Commit a1d47b262952a45aae62bd49cfaf33dd76c11a2c

Authored by Jan Kara
1 parent e159332b9a

udf: Verify symlink size before loading it

UDF specification allows arbitrarily large symlinks. However we support
only symlinks at most one block large. Check the length of the symlink
so that we don't access memory beyond end of the symlink block.

CC: stable@vger.kernel.org
Reported-by: Carl Henrik Lunde <chlunde@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>

Showing 1 changed file with 13 additions and 4 deletions Inline Diff

1 /* 1 /*
2 * symlink.c 2 * symlink.c
3 * 3 *
4 * PURPOSE 4 * PURPOSE
5 * Symlink handling routines for the OSTA-UDF(tm) filesystem. 5 * Symlink handling routines for the OSTA-UDF(tm) filesystem.
6 * 6 *
7 * COPYRIGHT 7 * COPYRIGHT
8 * This file is distributed under the terms of the GNU General Public 8 * This file is distributed under the terms of the GNU General Public
9 * License (GPL). Copies of the GPL can be obtained from: 9 * License (GPL). Copies of the GPL can be obtained from:
10 * ftp://prep.ai.mit.edu/pub/gnu/GPL 10 * ftp://prep.ai.mit.edu/pub/gnu/GPL
11 * Each contributing author retains all rights to their own work. 11 * Each contributing author retains all rights to their own work.
12 * 12 *
13 * (C) 1998-2001 Ben Fennema 13 * (C) 1998-2001 Ben Fennema
14 * (C) 1999 Stelias Computing Inc 14 * (C) 1999 Stelias Computing Inc
15 * 15 *
16 * HISTORY 16 * HISTORY
17 * 17 *
18 * 04/16/99 blf Created. 18 * 04/16/99 blf Created.
19 * 19 *
20 */ 20 */
21 21
22 #include "udfdecl.h" 22 #include "udfdecl.h"
23 #include <linux/uaccess.h> 23 #include <linux/uaccess.h>
24 #include <linux/errno.h> 24 #include <linux/errno.h>
25 #include <linux/fs.h> 25 #include <linux/fs.h>
26 #include <linux/time.h> 26 #include <linux/time.h>
27 #include <linux/mm.h> 27 #include <linux/mm.h>
28 #include <linux/stat.h> 28 #include <linux/stat.h>
29 #include <linux/pagemap.h> 29 #include <linux/pagemap.h>
30 #include <linux/buffer_head.h> 30 #include <linux/buffer_head.h>
31 #include "udf_i.h" 31 #include "udf_i.h"
32 32
33 static void udf_pc_to_char(struct super_block *sb, unsigned char *from, 33 static void udf_pc_to_char(struct super_block *sb, unsigned char *from,
34 int fromlen, unsigned char *to) 34 int fromlen, unsigned char *to)
35 { 35 {
36 struct pathComponent *pc; 36 struct pathComponent *pc;
37 int elen = 0; 37 int elen = 0;
38 unsigned char *p = to; 38 unsigned char *p = to;
39 39
40 while (elen < fromlen) { 40 while (elen < fromlen) {
41 pc = (struct pathComponent *)(from + elen); 41 pc = (struct pathComponent *)(from + elen);
42 switch (pc->componentType) { 42 switch (pc->componentType) {
43 case 1: 43 case 1:
44 /* 44 /*
45 * Symlink points to some place which should be agreed 45 * Symlink points to some place which should be agreed
46 * upon between originator and receiver of the media. Ignore. 46 * upon between originator and receiver of the media. Ignore.
47 */ 47 */
48 if (pc->lengthComponentIdent > 0) 48 if (pc->lengthComponentIdent > 0)
49 break; 49 break;
50 /* Fall through */ 50 /* Fall through */
51 case 2: 51 case 2:
52 p = to; 52 p = to;
53 *p++ = '/'; 53 *p++ = '/';
54 break; 54 break;
55 case 3: 55 case 3:
56 memcpy(p, "../", 3); 56 memcpy(p, "../", 3);
57 p += 3; 57 p += 3;
58 break; 58 break;
59 case 4: 59 case 4:
60 memcpy(p, "./", 2); 60 memcpy(p, "./", 2);
61 p += 2; 61 p += 2;
62 /* that would be . - just ignore */ 62 /* that would be . - just ignore */
63 break; 63 break;
64 case 5: 64 case 5:
65 p += udf_get_filename(sb, pc->componentIdent, p, 65 p += udf_get_filename(sb, pc->componentIdent, p,
66 pc->lengthComponentIdent); 66 pc->lengthComponentIdent);
67 *p++ = '/'; 67 *p++ = '/';
68 break; 68 break;
69 } 69 }
70 elen += sizeof(struct pathComponent) + pc->lengthComponentIdent; 70 elen += sizeof(struct pathComponent) + pc->lengthComponentIdent;
71 } 71 }
72 if (p > to + 1) 72 if (p > to + 1)
73 p[-1] = '\0'; 73 p[-1] = '\0';
74 else 74 else
75 p[0] = '\0'; 75 p[0] = '\0';
76 } 76 }
77 77
78 static int udf_symlink_filler(struct file *file, struct page *page) 78 static int udf_symlink_filler(struct file *file, struct page *page)
79 { 79 {
80 struct inode *inode = page->mapping->host; 80 struct inode *inode = page->mapping->host;
81 struct buffer_head *bh = NULL; 81 struct buffer_head *bh = NULL;
82 unsigned char *symlink; 82 unsigned char *symlink;
83 int err = -EIO; 83 int err;
84 unsigned char *p = kmap(page); 84 unsigned char *p = kmap(page);
85 struct udf_inode_info *iinfo; 85 struct udf_inode_info *iinfo;
86 uint32_t pos; 86 uint32_t pos;
87 87
88 /* We don't support symlinks longer than one block */
89 if (inode->i_size > inode->i_sb->s_blocksize) {
90 err = -ENAMETOOLONG;
91 goto out_unmap;
92 }
93
88 iinfo = UDF_I(inode); 94 iinfo = UDF_I(inode);
89 pos = udf_block_map(inode, 0); 95 pos = udf_block_map(inode, 0);
90 96
91 down_read(&iinfo->i_data_sem); 97 down_read(&iinfo->i_data_sem);
92 if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 98 if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
93 symlink = iinfo->i_ext.i_data + iinfo->i_lenEAttr; 99 symlink = iinfo->i_ext.i_data + iinfo->i_lenEAttr;
94 } else { 100 } else {
95 bh = sb_bread(inode->i_sb, pos); 101 bh = sb_bread(inode->i_sb, pos);
96 102
97 if (!bh) 103 if (!bh) {
98 goto out; 104 err = -EIO;
105 goto out_unlock_inode;
106 }
99 107
100 symlink = bh->b_data; 108 symlink = bh->b_data;
101 } 109 }
102 110
103 udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p); 111 udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p);
104 brelse(bh); 112 brelse(bh);
105 113
106 up_read(&iinfo->i_data_sem); 114 up_read(&iinfo->i_data_sem);
107 SetPageUptodate(page); 115 SetPageUptodate(page);
108 kunmap(page); 116 kunmap(page);
109 unlock_page(page); 117 unlock_page(page);
110 return 0; 118 return 0;
111 119
112 out: 120 out_unlock_inode:
113 up_read(&iinfo->i_data_sem); 121 up_read(&iinfo->i_data_sem);
114 SetPageError(page); 122 SetPageError(page);
123 out_unmap:
115 kunmap(page); 124 kunmap(page);
116 unlock_page(page); 125 unlock_page(page);
117 return err; 126 return err;
118 } 127 }
119 128
120 /* 129 /*
121 * symlinks can't do much... 130 * symlinks can't do much...
122 */ 131 */
123 const struct address_space_operations udf_symlink_aops = { 132 const struct address_space_operations udf_symlink_aops = {
124 .readpage = udf_symlink_filler, 133 .readpage = udf_symlink_filler,
125 }; 134 };
126 135