History

ext4: add bounds checking in get_max_inline_xattr_value_size()

Normally the extended attributes in the inode body would have been checked when the inode is first opened, but if someone is writing to the block device while the file system is mounted, it's possible for the inode table to get corrupted. Add bounds checking to avoid reading beyond the end of allocated memory if this happens.

Theodore Ts'o committed 3 years ago

Commit 2220eaf1 parent 6dcc98f1 file · +11 −1Browse files

Unified · Split

fs/ext4/inline.c+11−1
@@ -34,6 +34,7 @@ static int get_max_inline_xattr_value_size(struct inode *inode, · 33 unmodified lines
3434 struct ext4_xattr_ibody_header *header;
3535 struct ext4_xattr_entry *entry;
3636 struct ext4_inode *raw_inode;
37+ void *end;
3738 int free, min_offs;
3839
3940 if (!EXT4_INODE_HAS_XATTR_SPACE(inode))
@@ -57,14 +58,23 @@ static int get_max_inline_xattr_value_size(struct inode *inode, · 17 unmodified lines
5758 raw_inode = ext4_raw_inode(iloc);
5859 header = IHDR(inode, raw_inode);
5960 entry = IFIRST(header);
61+ end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
6062
6163 /* Compute min_offs. */
62− for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
64+ while (!IS_LAST_ENTRY(entry)) {
65+ void *next = EXT4_XATTR_NEXT(entry);
66+
67+ if (next >= end) {
68+ EXT4_ERROR_INODE(inode,
69+ "corrupt xattr in inline inode");
70+ return 0;
71+ }
6372 if (!entry->e_value_inum && entry->e_value_size) {
6473 size_t offs = le16_to_cpu(entry->e_value_offs);
6574 if (offs < min_offs)
6675 min_offs = offs;
6776 }
77+ entry = next;
6878 }
6979 free = min_offs -
7080 ((void *)entry - (void *)IFIRST(header)) - sizeof(__u32);