aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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. */