Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull UDF & isofs fixes from Jan Kara:
"A couple of UDF fixes of handling of corrupted media and one iso9660
fix of the same"

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
udf: Reduce repeated dereferences
udf: Check component length before reading it
udf: Check path length when reading symlink
udf: Verify symlink size before loading it
udf: Verify i_size when loading inode
isofs: Fix unchecked printing of ER records

+106 -47
+3
fs/isofs/rock.c
··· 362 362 rs.cont_size = isonum_733(rr->u.CE.size); 363 363 break; 364 364 case SIG('E', 'R'): 365 + /* Invalid length of ER tag id? */ 366 + if (rr->u.ER.len_id + offsetof(struct rock_ridge, u.ER.data) > rr->len) 367 + goto out; 365 368 ISOFS_SB(inode->i_sb)->s_rock = 1; 366 369 printk(KERN_DEBUG "ISO 9660 Extensions: "); 367 370 {
+16 -15
fs/udf/dir.c
··· 57 57 sector_t offset; 58 58 int i, num, ret = 0; 59 59 struct extent_position epos = { NULL, 0, {0, 0} }; 60 + struct super_block *sb = dir->i_sb; 60 61 61 62 if (ctx->pos == 0) { 62 63 if (!dir_emit_dot(file, ctx)) ··· 77 76 if (nf_pos == 0) 78 77 nf_pos = udf_ext0_offset(dir); 79 78 80 - fibh.soffset = fibh.eoffset = nf_pos & (dir->i_sb->s_blocksize - 1); 79 + fibh.soffset = fibh.eoffset = nf_pos & (sb->s_blocksize - 1); 81 80 if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { 82 - if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits, 81 + if (inode_bmap(dir, nf_pos >> sb->s_blocksize_bits, 83 82 &epos, &eloc, &elen, &offset) 84 83 != (EXT_RECORDED_ALLOCATED >> 30)) { 85 84 ret = -ENOENT; 86 85 goto out; 87 86 } 88 - block = udf_get_lb_pblock(dir->i_sb, &eloc, offset); 89 - if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { 87 + block = udf_get_lb_pblock(sb, &eloc, offset); 88 + if ((++offset << sb->s_blocksize_bits) < elen) { 90 89 if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 91 90 epos.offset -= sizeof(struct short_ad); 92 91 else if (iinfo->i_alloc_type == ··· 96 95 offset = 0; 97 96 } 98 97 99 - if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) { 98 + if (!(fibh.sbh = fibh.ebh = udf_tread(sb, block))) { 100 99 ret = -EIO; 101 100 goto out; 102 101 } 103 102 104 - if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) { 105 - i = 16 >> (dir->i_sb->s_blocksize_bits - 9); 106 - if (i + offset > (elen >> dir->i_sb->s_blocksize_bits)) 107 - i = (elen >> dir->i_sb->s_blocksize_bits) - offset; 103 + if (!(offset & ((16 >> (sb->s_blocksize_bits - 9)) - 1))) { 104 + i = 16 >> (sb->s_blocksize_bits - 9); 105 + if (i + offset > (elen >> sb->s_blocksize_bits)) 106 + i = (elen >> sb->s_blocksize_bits) - offset; 108 107 for (num = 0; i > 0; i--) { 109 - block = udf_get_lb_pblock(dir->i_sb, &eloc, offset + i); 110 - tmp = udf_tgetblk(dir->i_sb, block); 108 + block = udf_get_lb_pblock(sb, &eloc, offset + i); 109 + tmp = udf_tgetblk(sb, block); 111 110 if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp)) 112 111 bha[num++] = tmp; 113 112 else ··· 153 152 } 154 153 155 154 if ((cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) { 156 - if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE)) 155 + if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE)) 157 156 continue; 158 157 } 159 158 160 159 if ((cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) { 161 - if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE)) 160 + if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE)) 162 161 continue; 163 162 } 164 163 ··· 168 167 continue; 169 168 } 170 169 171 - flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); 170 + flen = udf_get_filename(sb, nameptr, lfi, fname, UDF_NAME_LEN); 172 171 if (!flen) 173 172 continue; 174 173 175 174 tloc = lelb_to_cpu(cfi.icb.extLocation); 176 - iblock = udf_get_lb_pblock(dir->i_sb, &tloc, 0); 175 + iblock = udf_get_lb_pblock(sb, &tloc, 0); 177 176 if (!dir_emit(ctx, fname, flen, iblock, DT_UNKNOWN)) 178 177 goto out; 179 178 } /* end while */
+14
fs/udf/inode.c
··· 1489 1489 } 1490 1490 inode->i_generation = iinfo->i_unique; 1491 1491 1492 + /* Sanity checks for files in ICB so that we don't get confused later */ 1493 + if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 1494 + /* 1495 + * For file in ICB data is stored in allocation descriptor 1496 + * so sizes should match 1497 + */ 1498 + if (iinfo->i_lenAlloc != inode->i_size) 1499 + goto out; 1500 + /* File in ICB has to fit in there... */ 1501 + if (inode->i_size > inode->i_sb->s_blocksize - 1502 + udf_file_entry_alloc_offset(inode)) 1503 + goto out; 1504 + } 1505 + 1492 1506 switch (fe->icbTag.fileType) { 1493 1507 case ICBTAG_FILE_TYPE_DIRECTORY: 1494 1508 inode->i_op = &udf_dir_inode_operations;
+9 -8
fs/udf/namei.c
··· 159 159 struct udf_inode_info *dinfo = UDF_I(dir); 160 160 int isdotdot = child->len == 2 && 161 161 child->name[0] == '.' && child->name[1] == '.'; 162 + struct super_block *sb = dir->i_sb; 162 163 163 164 size = udf_ext0_offset(dir) + dir->i_size; 164 165 f_pos = udf_ext0_offset(dir); 165 166 166 167 fibh->sbh = fibh->ebh = NULL; 167 - fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); 168 + fibh->soffset = fibh->eoffset = f_pos & (sb->s_blocksize - 1); 168 169 if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { 169 - if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos, 170 + if (inode_bmap(dir, f_pos >> sb->s_blocksize_bits, &epos, 170 171 &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) 171 172 goto out_err; 172 - block = udf_get_lb_pblock(dir->i_sb, &eloc, offset); 173 - if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { 173 + block = udf_get_lb_pblock(sb, &eloc, offset); 174 + if ((++offset << sb->s_blocksize_bits) < elen) { 174 175 if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 175 176 epos.offset -= sizeof(struct short_ad); 176 177 else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) ··· 179 178 } else 180 179 offset = 0; 181 180 182 - fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); 181 + fibh->sbh = fibh->ebh = udf_tread(sb, block); 183 182 if (!fibh->sbh) 184 183 goto out_err; 185 184 } ··· 218 217 } 219 218 220 219 if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) { 221 - if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE)) 220 + if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE)) 222 221 continue; 223 222 } 224 223 225 224 if ((cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) { 226 - if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE)) 225 + if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE)) 227 226 continue; 228 227 } 229 228 ··· 234 233 if (!lfi) 235 234 continue; 236 235 237 - flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); 236 + flen = udf_get_filename(sb, nameptr, lfi, fname, UDF_NAME_LEN); 238 237 if (flen && udf_match(flen, fname, child->len, child->name)) 239 238 goto out_ok; 240 239 }
+46 -11
fs/udf/symlink.c
··· 30 30 #include <linux/buffer_head.h> 31 31 #include "udf_i.h" 32 32 33 - static void udf_pc_to_char(struct super_block *sb, unsigned char *from, 34 - int fromlen, unsigned char *to) 33 + static int udf_pc_to_char(struct super_block *sb, unsigned char *from, 34 + int fromlen, unsigned char *to, int tolen) 35 35 { 36 36 struct pathComponent *pc; 37 37 int elen = 0; 38 + int comp_len; 38 39 unsigned char *p = to; 39 40 41 + /* Reserve one byte for terminating \0 */ 42 + tolen--; 40 43 while (elen < fromlen) { 41 44 pc = (struct pathComponent *)(from + elen); 45 + elen += sizeof(struct pathComponent); 42 46 switch (pc->componentType) { 43 47 case 1: 44 48 /* 45 49 * Symlink points to some place which should be agreed 46 50 * upon between originator and receiver of the media. Ignore. 47 51 */ 48 - if (pc->lengthComponentIdent > 0) 52 + if (pc->lengthComponentIdent > 0) { 53 + elen += pc->lengthComponentIdent; 49 54 break; 55 + } 50 56 /* Fall through */ 51 57 case 2: 58 + if (tolen == 0) 59 + return -ENAMETOOLONG; 52 60 p = to; 53 61 *p++ = '/'; 62 + tolen--; 54 63 break; 55 64 case 3: 65 + if (tolen < 3) 66 + return -ENAMETOOLONG; 56 67 memcpy(p, "../", 3); 57 68 p += 3; 69 + tolen -= 3; 58 70 break; 59 71 case 4: 72 + if (tolen < 2) 73 + return -ENAMETOOLONG; 60 74 memcpy(p, "./", 2); 61 75 p += 2; 76 + tolen -= 2; 62 77 /* that would be . - just ignore */ 63 78 break; 64 79 case 5: 65 - p += udf_get_filename(sb, pc->componentIdent, p, 66 - pc->lengthComponentIdent); 80 + elen += pc->lengthComponentIdent; 81 + if (elen > fromlen) 82 + return -EIO; 83 + comp_len = udf_get_filename(sb, pc->componentIdent, 84 + pc->lengthComponentIdent, 85 + p, tolen); 86 + p += comp_len; 87 + tolen -= comp_len; 88 + if (tolen == 0) 89 + return -ENAMETOOLONG; 67 90 *p++ = '/'; 91 + tolen--; 68 92 break; 69 93 } 70 - elen += sizeof(struct pathComponent) + pc->lengthComponentIdent; 71 94 } 72 95 if (p > to + 1) 73 96 p[-1] = '\0'; 74 97 else 75 98 p[0] = '\0'; 99 + return 0; 76 100 } 77 101 78 102 static int udf_symlink_filler(struct file *file, struct page *page) ··· 104 80 struct inode *inode = page->mapping->host; 105 81 struct buffer_head *bh = NULL; 106 82 unsigned char *symlink; 107 - int err = -EIO; 83 + int err; 108 84 unsigned char *p = kmap(page); 109 85 struct udf_inode_info *iinfo; 110 86 uint32_t pos; 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 + } 111 93 112 94 iinfo = UDF_I(inode); 113 95 pos = udf_block_map(inode, 0); ··· 124 94 } else { 125 95 bh = sb_bread(inode->i_sb, pos); 126 96 127 - if (!bh) 128 - goto out; 97 + if (!bh) { 98 + err = -EIO; 99 + goto out_unlock_inode; 100 + } 129 101 130 102 symlink = bh->b_data; 131 103 } 132 104 133 - udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p); 105 + err = udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p, PAGE_SIZE); 134 106 brelse(bh); 107 + if (err) 108 + goto out_unlock_inode; 135 109 136 110 up_read(&iinfo->i_data_sem); 137 111 SetPageUptodate(page); ··· 143 109 unlock_page(page); 144 110 return 0; 145 111 146 - out: 112 + out_unlock_inode: 147 113 up_read(&iinfo->i_data_sem); 148 114 SetPageError(page); 115 + out_unmap: 149 116 kunmap(page); 150 117 unlock_page(page); 151 118 return err;
+2 -1
fs/udf/udfdecl.h
··· 211 211 } 212 212 213 213 /* unicode.c */ 214 - extern int udf_get_filename(struct super_block *, uint8_t *, uint8_t *, int); 214 + extern int udf_get_filename(struct super_block *, uint8_t *, int, uint8_t *, 215 + int); 215 216 extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *, 216 217 int); 217 218 extern int udf_build_ustr(struct ustr *, dstring *, int);
+16 -12
fs/udf/unicode.c
··· 28 28 29 29 #include "udf_sb.h" 30 30 31 - static int udf_translate_to_linux(uint8_t *, uint8_t *, int, uint8_t *, int); 31 + static int udf_translate_to_linux(uint8_t *, int, uint8_t *, int, uint8_t *, 32 + int); 32 33 33 34 static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen) 34 35 { ··· 334 333 return u_len + 1; 335 334 } 336 335 337 - int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname, 338 - int flen) 336 + int udf_get_filename(struct super_block *sb, uint8_t *sname, int slen, 337 + uint8_t *dname, int dlen) 339 338 { 340 339 struct ustr *filename, *unifilename; 341 340 int len = 0; ··· 348 347 if (!unifilename) 349 348 goto out1; 350 349 351 - if (udf_build_ustr_exact(unifilename, sname, flen)) 350 + if (udf_build_ustr_exact(unifilename, sname, slen)) 352 351 goto out2; 353 352 354 353 if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) { ··· 367 366 } else 368 367 goto out2; 369 368 370 - len = udf_translate_to_linux(dname, filename->u_name, filename->u_len, 369 + len = udf_translate_to_linux(dname, dlen, 370 + filename->u_name, filename->u_len, 371 371 unifilename->u_name, unifilename->u_len); 372 372 out2: 373 373 kfree(unifilename); ··· 405 403 #define EXT_MARK '.' 406 404 #define CRC_MARK '#' 407 405 #define EXT_SIZE 5 406 + /* Number of chars we need to store generated CRC to make filename unique */ 407 + #define CRC_LEN 5 408 408 409 - static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, 410 - int udfLen, uint8_t *fidName, 411 - int fidNameLen) 409 + static int udf_translate_to_linux(uint8_t *newName, int newLen, 410 + uint8_t *udfName, int udfLen, 411 + uint8_t *fidName, int fidNameLen) 412 412 { 413 413 int index, newIndex = 0, needsCRC = 0; 414 414 int extIndex = 0, newExtIndex = 0, hasExt = 0; ··· 443 439 newExtIndex = newIndex; 444 440 } 445 441 } 446 - if (newIndex < 256) 442 + if (newIndex < newLen) 447 443 newName[newIndex++] = curr; 448 444 else 449 445 needsCRC = 1; ··· 471 467 } 472 468 ext[localExtIndex++] = curr; 473 469 } 474 - maxFilenameLen = 250 - localExtIndex; 470 + maxFilenameLen = newLen - CRC_LEN - localExtIndex; 475 471 if (newIndex > maxFilenameLen) 476 472 newIndex = maxFilenameLen; 477 473 else 478 474 newIndex = newExtIndex; 479 - } else if (newIndex > 250) 480 - newIndex = 250; 475 + } else if (newIndex > newLen - CRC_LEN) 476 + newIndex = newLen - CRC_LEN; 481 477 newName[newIndex++] = CRC_MARK; 482 478 valueCRC = crc_itu_t(0, fidName, fidNameLen); 483 479 newName[newIndex++] = hex_asc_upper_hi(valueCRC >> 8);