aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2011-03-16 16:47:17 -0400
committerJosef Bacik <josef@redhat.com>2011-03-17 14:21:41 -0400
commit22a94d44bd6876a90630338229da6c0436d46593 (patch)
tree50e5c7dd52ccf9292240de995e5b42b1619bcd82 /fs
parent41415730a1050499fbd63b3f7dd59b3a4c3bb91a (diff)
Btrfs: add checks to verify dir items are correct
We need to make sure the dir items we get are valid dir items. So any time we try and read one check it with verify_dir_item, which will do various sanity checks to make sure it looks sane. Thanks, Signed-off-by: Josef Bacik <josef@redhat.com>
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;