aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2014-09-16 14:34:59 -0400
committerTheodore Ts'o <tytso@mit.edu>2014-09-16 14:34:59 -0400
commita0626e75954078cfacddb00a4545dde821170bc5 (patch)
tree61aeb6747c5fc7016ac54cc704fb6d9b1833674d /fs/ext4
parent684de5748660e16e185754697ac0afa9e18297f6 (diff)
ext4: check EA value offset when loading
When loading extended attributes, check each entry's value offset to make sure it doesn't collide with the entries. Without this check it is easy to crash the kernel by mounting a malicious FS containing a file with an EA wherein e_value_offs = 0 and e_value_size > 0 and then deleting the EA, which corrupts the name list. (See the f_ea_value_crash test's FS image in e2fsprogs for an example.) Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Cc: stable@vger.kernel.org
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/xattr.c32
1 files changed, 24 insertions, 8 deletions
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index da4df703c211..42823ab3718c 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -190,14 +190,28 @@ ext4_listxattr(struct dentry *dentry, char *buffer, size_t size)
190} 190}
191 191
192static int 192static int
193ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end) 193ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end,
194 void *value_start)
194{ 195{
195 while (!IS_LAST_ENTRY(entry)) { 196 struct ext4_xattr_entry *e = entry;
196 struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(entry); 197
198 while (!IS_LAST_ENTRY(e)) {
199 struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(e);
197 if ((void *)next >= end) 200 if ((void *)next >= end)
198 return -EIO; 201 return -EIO;
199 entry = next; 202 e = next;
200 } 203 }
204
205 while (!IS_LAST_ENTRY(entry)) {
206 if (entry->e_value_size != 0 &&
207 (value_start + le16_to_cpu(entry->e_value_offs) <
208 (void *)e + sizeof(__u32) ||
209 value_start + le16_to_cpu(entry->e_value_offs) +
210 le32_to_cpu(entry->e_value_size) > end))
211 return -EIO;
212 entry = EXT4_XATTR_NEXT(entry);
213 }
214
201 return 0; 215 return 0;
202} 216}
203 217
@@ -214,7 +228,8 @@ ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh)
214 return -EIO; 228 return -EIO;
215 if (!ext4_xattr_block_csum_verify(inode, bh->b_blocknr, BHDR(bh))) 229 if (!ext4_xattr_block_csum_verify(inode, bh->b_blocknr, BHDR(bh)))
216 return -EIO; 230 return -EIO;
217 error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size); 231 error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size,
232 bh->b_data);
218 if (!error) 233 if (!error)
219 set_buffer_verified(bh); 234 set_buffer_verified(bh);
220 return error; 235 return error;
@@ -331,7 +346,7 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
331 header = IHDR(inode, raw_inode); 346 header = IHDR(inode, raw_inode);
332 entry = IFIRST(header); 347 entry = IFIRST(header);
333 end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; 348 end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
334 error = ext4_xattr_check_names(entry, end); 349 error = ext4_xattr_check_names(entry, end, entry);
335 if (error) 350 if (error)
336 goto cleanup; 351 goto cleanup;
337 error = ext4_xattr_find_entry(&entry, name_index, name, 352 error = ext4_xattr_find_entry(&entry, name_index, name,
@@ -463,7 +478,7 @@ ext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size)
463 raw_inode = ext4_raw_inode(&iloc); 478 raw_inode = ext4_raw_inode(&iloc);
464 header = IHDR(inode, raw_inode); 479 header = IHDR(inode, raw_inode);
465 end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; 480 end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
466 error = ext4_xattr_check_names(IFIRST(header), end); 481 error = ext4_xattr_check_names(IFIRST(header), end, IFIRST(header));
467 if (error) 482 if (error)
468 goto cleanup; 483 goto cleanup;
469 error = ext4_xattr_list_entries(dentry, IFIRST(header), 484 error = ext4_xattr_list_entries(dentry, IFIRST(header),
@@ -980,7 +995,8 @@ int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i,
980 is->s.here = is->s.first; 995 is->s.here = is->s.first;
981 is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; 996 is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
982 if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) { 997 if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) {
983 error = ext4_xattr_check_names(IFIRST(header), is->s.end); 998 error = ext4_xattr_check_names(IFIRST(header), is->s.end,
999 IFIRST(header));
984 if (error) 1000 if (error)
985 return error; 1001 return error;
986 /* Find the named attribute. */ 1002 /* Find the named attribute. */