aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ctree.h3
-rw-r--r--fs/btrfs/dir-item.c35
-rw-r--r--fs/btrfs/inode.c3
-rw-r--r--fs/btrfs/tree-log.c7
-rw-r--r--fs/btrfs/xattr.c2
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);
2396int 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 */
2398int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, 2401int 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
436int 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;