diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.h | 3 | ||||
-rw-r--r-- | fs/btrfs/dir-item.c | 35 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 3 | ||||
-rw-r--r-- | fs/btrfs/tree-log.c | 7 | ||||
-rw-r--r-- | fs/btrfs/xattr.c | 2 |
5 files changed, 50 insertions, 0 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 841330f3d68d..6036fdb88c53 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -2393,6 +2393,9 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, | |||
2393 | struct btrfs_path *path, u64 dir, | 2393 | struct btrfs_path *path, u64 dir, |
2394 | const char *name, u16 name_len, | 2394 | const char *name, u16 name_len, |
2395 | int mod); | 2395 | int mod); |
2396 | int verify_dir_item(struct btrfs_root *root, | ||
2397 | struct extent_buffer *leaf, | ||
2398 | struct btrfs_dir_item *dir_item); | ||
2396 | 2399 | ||
2397 | /* orphan.c */ | 2400 | /* orphan.c */ |
2398 | int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, | 2401 | int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, |
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index f0cad5ae5be7..02c97ad61b6d 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c | |||
@@ -377,6 +377,9 @@ struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, | |||
377 | 377 | ||
378 | leaf = path->nodes[0]; | 378 | leaf = path->nodes[0]; |
379 | dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item); | 379 | dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item); |
380 | if (verify_dir_item(root, leaf, dir_item)) | ||
381 | return NULL; | ||
382 | |||
380 | total_len = btrfs_item_size_nr(leaf, path->slots[0]); | 383 | total_len = btrfs_item_size_nr(leaf, path->slots[0]); |
381 | while (cur < total_len) { | 384 | while (cur < total_len) { |
382 | this_len = sizeof(*dir_item) + | 385 | this_len = sizeof(*dir_item) + |
@@ -429,3 +432,35 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, | |||
429 | } | 432 | } |
430 | return ret; | 433 | return ret; |
431 | } | 434 | } |
435 | |||
436 | int verify_dir_item(struct btrfs_root *root, | ||
437 | struct extent_buffer *leaf, | ||
438 | struct btrfs_dir_item *dir_item) | ||
439 | { | ||
440 | u16 namelen = BTRFS_NAME_LEN; | ||
441 | u8 type = btrfs_dir_type(leaf, dir_item); | ||
442 | |||
443 | if (type >= BTRFS_FT_MAX) { | ||
444 | printk(KERN_CRIT "btrfs: invalid dir item type: %d\n", | ||
445 | (int)type); | ||
446 | return 1; | ||
447 | } | ||
448 | |||
449 | if (type == BTRFS_FT_XATTR) | ||
450 | namelen = XATTR_NAME_MAX; | ||
451 | |||
452 | if (btrfs_dir_name_len(leaf, dir_item) > namelen) { | ||
453 | printk(KERN_CRIT "btrfS: invalid dir item name len: %u\n", | ||
454 | (unsigned)btrfs_dir_data_len(leaf, dir_item)); | ||
455 | return 1; | ||
456 | } | ||
457 | |||
458 | /* BTRFS_MAX_XATTR_SIZE is the same for all dir items */ | ||
459 | if (btrfs_dir_data_len(leaf, dir_item) > BTRFS_MAX_XATTR_SIZE(root)) { | ||
460 | printk(KERN_CRIT "btrfs: invalid dir item data len: %u\n", | ||
461 | (unsigned)btrfs_dir_data_len(leaf, dir_item)); | ||
462 | return 1; | ||
463 | } | ||
464 | |||
465 | return 0; | ||
466 | } | ||
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 888dbdb3b128..e010000d4bc9 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -4272,6 +4272,9 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
4272 | while (di_cur < di_total) { | 4272 | while (di_cur < di_total) { |
4273 | struct btrfs_key location; | 4273 | struct btrfs_key location; |
4274 | 4274 | ||
4275 | if (verify_dir_item(root, leaf, di)) | ||
4276 | break; | ||
4277 | |||
4275 | name_len = btrfs_dir_name_len(leaf, di); | 4278 | name_len = btrfs_dir_name_len(leaf, di); |
4276 | if (name_len <= sizeof(tmp_name)) { | 4279 | if (name_len <= sizeof(tmp_name)) { |
4277 | name_ptr = tmp_name; | 4280 | name_ptr = tmp_name; |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index a4bbb854dfd2..429cfcfadf90 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -1286,6 +1286,8 @@ static noinline int replay_one_dir_item(struct btrfs_trans_handle *trans, | |||
1286 | ptr_end = ptr + item_size; | 1286 | ptr_end = ptr + item_size; |
1287 | while (ptr < ptr_end) { | 1287 | while (ptr < ptr_end) { |
1288 | di = (struct btrfs_dir_item *)ptr; | 1288 | di = (struct btrfs_dir_item *)ptr; |
1289 | if (verify_dir_item(root, eb, di)) | ||
1290 | return -EIO; | ||
1289 | name_len = btrfs_dir_name_len(eb, di); | 1291 | name_len = btrfs_dir_name_len(eb, di); |
1290 | ret = replay_one_name(trans, root, path, eb, di, key); | 1292 | ret = replay_one_name(trans, root, path, eb, di, key); |
1291 | BUG_ON(ret); | 1293 | BUG_ON(ret); |
@@ -1412,6 +1414,11 @@ again: | |||
1412 | ptr_end = ptr + item_size; | 1414 | ptr_end = ptr + item_size; |
1413 | while (ptr < ptr_end) { | 1415 | while (ptr < ptr_end) { |
1414 | di = (struct btrfs_dir_item *)ptr; | 1416 | di = (struct btrfs_dir_item *)ptr; |
1417 | if (verify_dir_item(root, eb, di)) { | ||
1418 | ret = -EIO; | ||
1419 | goto out; | ||
1420 | } | ||
1421 | |||
1415 | name_len = btrfs_dir_name_len(eb, di); | 1422 | name_len = btrfs_dir_name_len(eb, di); |
1416 | name = kmalloc(name_len, GFP_NOFS); | 1423 | name = kmalloc(name_len, GFP_NOFS); |
1417 | if (!name) { | 1424 | if (!name) { |
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c index a5776531dc2b..e5d22f280956 100644 --- a/fs/btrfs/xattr.c +++ b/fs/btrfs/xattr.c | |||
@@ -242,6 +242,8 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) | |||
242 | break; | 242 | break; |
243 | 243 | ||
244 | di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); | 244 | di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); |
245 | if (verify_dir_item(root, leaf, di)) | ||
246 | continue; | ||
245 | 247 | ||
246 | name_len = btrfs_dir_name_len(leaf, di); | 248 | name_len = btrfs_dir_name_len(leaf, di); |
247 | total_size += name_len + 1; | 249 | total_size += name_len + 1; |