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
34 struct ext4_xattr_ibody_header *header;34 struct ext4_xattr_ibody_header *header;
35 struct ext4_xattr_entry *entry;35 struct ext4_xattr_entry *entry;
36 struct ext4_inode *raw_inode;36 struct ext4_inode *raw_inode;
37 void *end;
37 int free, min_offs;38 int free, min_offs;
38 39
39 if (!EXT4_INODE_HAS_XATTR_SPACE(inode))40 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
57 raw_inode = ext4_raw_inode(iloc);58 raw_inode = ext4_raw_inode(iloc);
58 header = IHDR(inode, raw_inode);59 header = IHDR(inode, raw_inode);
59 entry = IFIRST(header);60 entry = IFIRST(header);
61 end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
60 62
61 /* Compute min_offs. */63 /* 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 }
63 if (!entry->e_value_inum && entry->e_value_size) {72 if (!entry->e_value_inum && entry->e_value_size) {
64 size_t offs = le16_to_cpu(entry->e_value_offs);73 size_t offs = le16_to_cpu(entry->e_value_offs);
65 if (offs < min_offs)74 if (offs < min_offs)
66 min_offs = offs;75 min_offs = offs;
67 }76 }
77 entry = next;
68 }78 }
69 free = min_offs -79 free = min_offs -
70 ((void *)entry - (void *)IFIRST(header)) - sizeof(__u32);80 ((void *)entry - (void *)IFIRST(header)) - sizeof(__u32);