aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomohiro Misono <misono.tomohiro@jp.fujitsu.com>2018-05-20 21:09:43 -0400
committerDavid Sterba <dsterba@suse.com>2018-05-31 05:35:23 -0400
commit42e4b520c812daaf5e6177c2e4beec012ce1e2ce (patch)
tree84dd5c98cf91db85fc13c84bff3a688b996f35fa
parentb64ec075bded2b30bcd90af5aa5256d2237c885d (diff)
btrfs: Add unprivileged ioctl which returns subvolume's ROOT_REF
Add unprivileged ioctl BTRFS_IOC_GET_SUBVOL_ROOTREF which returns ROOT_REF information of the subvolume containing this inode except the subvolume name (this is because to prevent potential name leak). The subvolume name will be gained by user version of ino_lookup ioctl (BTRFS_IOC_INO_LOOKUP_USER) which also performs permission check. The min id of root ref's subvolume to be searched is specified by @min_id in struct btrfs_ioctl_get_subvol_rootref_args. After the search ends, @min_id is set to the last searched root ref's subvolid + 1. Also, if there are more root refs than BTRFS_MAX_ROOTREF_BUFFER_NUM, -EOVERFLOW is returned. Therefore the caller can just call this ioctl again without changing the argument to continue search. Reviewed-by: Qu Wenruo <wqu@suse.com> Reviewed-by: Gu Jinxiang <gujx@cn.fujitsu.com> Tested-by: Gu Jinxiang <gujx@cn.fujitsu.com> Signed-off-by: Tomohiro Misono <misono.tomohiro@jp.fujitsu.com> [ style fixes and struct item renames ] Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/ioctl.c99
-rw-r--r--include/uapi/linux/btrfs.h18
2 files changed, 117 insertions, 0 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 42ed752288e6..be9b3f39183c 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2502,6 +2502,103 @@ out:
2502 return ret; 2502 return ret;
2503} 2503}
2504 2504
2505/*
2506 * Return ROOT_REF information of the subvolume containing this inode
2507 * except the subvolume name.
2508 */
2509static int btrfs_ioctl_get_subvol_rootref(struct file *file, void __user *argp)
2510{
2511 struct btrfs_ioctl_get_subvol_rootref_args *rootrefs;
2512 struct btrfs_root_ref *rref;
2513 struct btrfs_root *root;
2514 struct btrfs_path *path;
2515 struct btrfs_key key;
2516 struct extent_buffer *leaf;
2517 struct inode *inode;
2518 u64 objectid;
2519 int slot;
2520 int ret;
2521 u8 found;
2522
2523 path = btrfs_alloc_path();
2524 if (!path)
2525 return -ENOMEM;
2526
2527 rootrefs = memdup_user(argp, sizeof(*rootrefs));
2528 if (IS_ERR(rootrefs)) {
2529 btrfs_free_path(path);
2530 return PTR_ERR(rootrefs);
2531 }
2532
2533 inode = file_inode(file);
2534 root = BTRFS_I(inode)->root->fs_info->tree_root;
2535 objectid = BTRFS_I(inode)->root->root_key.objectid;
2536
2537 key.objectid = objectid;
2538 key.type = BTRFS_ROOT_REF_KEY;
2539 key.offset = rootrefs->min_treeid;
2540 found = 0;
2541
2542 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
2543 if (ret < 0) {
2544 goto out;
2545 } else if (path->slots[0] >=
2546 btrfs_header_nritems(path->nodes[0])) {
2547 ret = btrfs_next_leaf(root, path);
2548 if (ret < 0) {
2549 goto out;
2550 } else if (ret > 0) {
2551 ret = -EUCLEAN;
2552 goto out;
2553 }
2554 }
2555 while (1) {
2556 leaf = path->nodes[0];
2557 slot = path->slots[0];
2558
2559 btrfs_item_key_to_cpu(leaf, &key, slot);
2560 if (key.objectid != objectid || key.type != BTRFS_ROOT_REF_KEY) {
2561 ret = 0;
2562 goto out;
2563 }
2564
2565 if (found == BTRFS_MAX_ROOTREF_BUFFER_NUM) {
2566 ret = -EOVERFLOW;
2567 goto out;
2568 }
2569
2570 rref = btrfs_item_ptr(leaf, slot, struct btrfs_root_ref);
2571 rootrefs->rootref[found].treeid = key.offset;
2572 rootrefs->rootref[found].dirid =
2573 btrfs_root_ref_dirid(leaf, rref);
2574 found++;
2575
2576 ret = btrfs_next_item(root, path);
2577 if (ret < 0) {
2578 goto out;
2579 } else if (ret > 0) {
2580 ret = -EUCLEAN;
2581 goto out;
2582 }
2583 }
2584
2585out:
2586 if (!ret || ret == -EOVERFLOW) {
2587 rootrefs->num_items = found;
2588 /* update min_treeid for next search */
2589 if (found)
2590 rootrefs->min_treeid =
2591 rootrefs->rootref[found - 1].treeid + 1;
2592 if (copy_to_user(argp, rootrefs, sizeof(*rootrefs)))
2593 ret = -EFAULT;
2594 }
2595
2596 kfree(rootrefs);
2597 btrfs_free_path(path);
2598
2599 return ret;
2600}
2601
2505static noinline int btrfs_ioctl_snap_destroy(struct file *file, 2602static noinline int btrfs_ioctl_snap_destroy(struct file *file,
2506 void __user *arg) 2603 void __user *arg)
2507{ 2604{
@@ -5666,6 +5763,8 @@ long btrfs_ioctl(struct file *file, unsigned int
5666 return btrfs_ioctl_fssetxattr(file, argp); 5763 return btrfs_ioctl_fssetxattr(file, argp);
5667 case BTRFS_IOC_GET_SUBVOL_INFO: 5764 case BTRFS_IOC_GET_SUBVOL_INFO:
5668 return btrfs_ioctl_get_subvol_info(file, argp); 5765 return btrfs_ioctl_get_subvol_info(file, argp);
5766 case BTRFS_IOC_GET_SUBVOL_ROOTREF:
5767 return btrfs_ioctl_get_subvol_rootref(file, argp);
5669 } 5768 }
5670 5769
5671 return -ENOTTY; 5770 return -ENOTTY;
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
index f8f20d72b852..f90d10478235 100644
--- a/include/uapi/linux/btrfs.h
+++ b/include/uapi/linux/btrfs.h
@@ -785,6 +785,22 @@ struct btrfs_ioctl_get_subvol_info_args {
785 __u64 reserved[8]; 785 __u64 reserved[8];
786}; 786};
787 787
788#define BTRFS_MAX_ROOTREF_BUFFER_NUM 255
789struct btrfs_ioctl_get_subvol_rootref_args {
790 /* in/out, minimum id of rootref's treeid to be searched */
791 __u64 min_treeid;
792
793 /* out */
794 struct {
795 __u64 treeid;
796 __u64 dirid;
797 } rootref[BTRFS_MAX_ROOTREF_BUFFER_NUM];
798
799 /* out, number of found items */
800 __u8 num_items;
801 __u8 align[7];
802};
803
788/* Error codes as returned by the kernel */ 804/* Error codes as returned by the kernel */
789enum btrfs_err_code { 805enum btrfs_err_code {
790 BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1, 806 BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1,
@@ -905,5 +921,7 @@ enum btrfs_err_code {
905 struct btrfs_ioctl_logical_ino_args) 921 struct btrfs_ioctl_logical_ino_args)
906#define BTRFS_IOC_GET_SUBVOL_INFO _IOR(BTRFS_IOCTL_MAGIC, 60, \ 922#define BTRFS_IOC_GET_SUBVOL_INFO _IOR(BTRFS_IOCTL_MAGIC, 60, \
907 struct btrfs_ioctl_get_subvol_info_args) 923 struct btrfs_ioctl_get_subvol_info_args)
924#define BTRFS_IOC_GET_SUBVOL_ROOTREF _IOWR(BTRFS_IOCTL_MAGIC, 61, \
925 struct btrfs_ioctl_get_subvol_rootref_args)
908 926
909#endif /* _UAPI_LINUX_BTRFS_H */ 927#endif /* _UAPI_LINUX_BTRFS_H */