mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
isofs: validate directory records in isofs_read_level3_size()
isofs_read_level3_size() walks the multi-extent directory records of a file and dereferences de->size and de->flags for each one without ever checking the record's length byte. A record with a short length placed near the end of a block makes those fixed-field reads run past the record, and for a record at the end of the last block of a page, past the buffer. readdir, lookup and the NFS get_parent path have validated every record with isofs_dir_record_valid() since commite2ee4078ec("isofs: validate directory records consistently"). Do the same here, after moving on to the next block when the previous record ended exactly at the end of the block or the rest of the block is zero padding, as commit 3c01d9263683 ("isofs: Fix handling of directories with tight blocks") does for the other two walkers. The check rejects a record that would run past its block, so the code that reassembled such a record from two blocks can no longer run. ECMA-119 does not allow directory records to straddle sector boundaries, which is what commitb2eb2e2886("isofs: Drop support of directory entries straddling blocks") relied on when it removed the same code from readdir and lookup. Remove it here too, along with its temporary record buffer. Found by fuzzing fs/isofs in a userspace harness with ASan (heap-buffer-overflow reads in de->flags). Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com> Link: https://patch.msgid.link/20260923153220.777907-1-matthias.goergens@gmail.com Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
parent
a4ed759939
commit
6e69419ca6
|
|
@ -1176,7 +1176,6 @@ static int isofs_read_level3_size(struct inode *inode)
|
|||
unsigned long block, offset, block_saved, offset_saved;
|
||||
int i = 0;
|
||||
int more_entries = 0;
|
||||
struct iso_directory_record *tmpde = NULL;
|
||||
struct iso_inode_info *ei = ISOFS_I(inode);
|
||||
|
||||
inode->i_size = 0;
|
||||
|
|
@ -1200,9 +1199,12 @@ static int isofs_read_level3_size(struct inode *inode)
|
|||
goto out_noread;
|
||||
}
|
||||
de = (struct iso_directory_record *) (bh->b_data + offset);
|
||||
de_len = *(unsigned char *) de;
|
||||
|
||||
if (de_len == 0) {
|
||||
/*
|
||||
* If we are at the end of a block (or at its zero-padded
|
||||
* tail), move on to the next block.
|
||||
*/
|
||||
if (offset >= bufsize || de->length[0] == 0) {
|
||||
brelse(bh);
|
||||
bh = NULL;
|
||||
++block;
|
||||
|
|
@ -1210,32 +1212,18 @@ static int isofs_read_level3_size(struct inode *inode)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!isofs_dir_record_valid(de, offset, bufsize)) {
|
||||
printk(KERN_NOTICE "iso9660: Corrupted directory entry in block %lu of inode %llu\n",
|
||||
block, inode->i_ino);
|
||||
brelse(bh);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
de_len = de->length[0];
|
||||
block_saved = block;
|
||||
offset_saved = offset;
|
||||
offset += de_len;
|
||||
|
||||
/* Make sure we have a full directory entry */
|
||||
if (offset >= bufsize) {
|
||||
int slop = bufsize - offset + de_len;
|
||||
if (!tmpde) {
|
||||
tmpde = kmalloc(256, GFP_KERNEL);
|
||||
if (!tmpde)
|
||||
goto out_nomem;
|
||||
}
|
||||
memcpy(tmpde, de, slop);
|
||||
offset &= bufsize - 1;
|
||||
block++;
|
||||
brelse(bh);
|
||||
bh = NULL;
|
||||
if (offset) {
|
||||
bh = sb_bread(inode->i_sb, block);
|
||||
if (!bh)
|
||||
goto out_noread;
|
||||
memcpy((void *)tmpde+slop, bh->b_data, offset);
|
||||
}
|
||||
de = tmpde;
|
||||
}
|
||||
|
||||
inode->i_size += isonum_733(de->size);
|
||||
if (i == 1) {
|
||||
ei->i_next_section_block = block_saved;
|
||||
|
|
@ -1249,17 +1237,11 @@ static int isofs_read_level3_size(struct inode *inode)
|
|||
goto out_toomany;
|
||||
} while (more_entries);
|
||||
out:
|
||||
kfree(tmpde);
|
||||
brelse(bh);
|
||||
return 0;
|
||||
|
||||
out_nomem:
|
||||
brelse(bh);
|
||||
return -ENOMEM;
|
||||
|
||||
out_noread:
|
||||
printk(KERN_INFO "ISOFS: unable to read i-node block %lu\n", block);
|
||||
kfree(tmpde);
|
||||
return -EIO;
|
||||
|
||||
out_toomany:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user