btrfs: Add three new unprivileged ioctls to allow normal users to call "sub list/show" etc.
v4 cover btrfs: Add three new unprivileged ioctls to allow normal users to call "sub list/show" etc.
changelog:
v3 -> v4
- call btrfs_next_leaf() after btrfs_search_slot() when the slot position exceeds the number of items
- rebased to current misc-next
v2 -> v3
- fix kbuild test bot warning
v1 -> v2
- completely reimplement 1st/2nd ioctl to have user friendly api
- various cleanup, remove unnecessary goto
===
This adds three new unprivileged ioctls:
1st patch:
ioctl which returns subvolume information of ROOT_ITEM and ROOT_BACKREF
2nd patch:
ioctl which returns subvolume information of ROOT_REF (without subvolume name)
3rd patch:
user version of ino_lookup ioctl which also performs permission check.
They will be used to implement user version of "subvolume list/show" etc. in user tools.
See each commit log for more detals.
The implementation of btrfs-progs can be found in the ML titled as follows:
[PATCH 0/11] btrfs-progs: Rework of "subvolume list/show" and relax the root privileges of them
Tomohiro Misono (3):
btrfs: Add unprivileged ioctl which returns subvolume information
btrfs: Add unprivileged ioctl which returns subvolume's ROOT_REF
btrfs: Add unprivileged version of ino_lookup ioctl
fs/btrfs/ioctl.c | 435 +++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/btrfs.h | 84 +++++++++ 2 files changed, 519 insertions(+)
Signature · 1 line
2.14.3
PATCH v4 1/3 btrfs: Add unprivileged ioctl which returns subvolume information
Add new unprivileged ioctl BTRFS_IOC_GET_SUBVOL_INFO which returns the information of subvolume containing this inode. (i.e. returns the information in ROOT_ITEM and ROOT_BACKREF.)
--- fs/btrfs/ioctl.c | 129 +++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/btrfs.h | 51 ++++++++++++++++++ 2 files changed, 180 insertions(+)
fs/btrfs/ioctl.c +129 -0
@@ -2242,6 +2242,133 @@ static noinline int btrfs_ioctl_ino_lookup(struct file *file,return ret; } +/* Get the subvolume information in BTRFS_ROOT_ITEM and BTRFS_ROOT_BACKREF */ +static noinline int btrfs_ioctl_get_subvol_info(struct file *file, +void __user *argp) +{ +struct btrfs_ioctl_get_subvol_info_args *subvol_info; +struct btrfs_root *root; +struct btrfs_path *path; +struct btrfs_key key; + +struct btrfs_root_item root_item; +struct btrfs_root_ref *rref; +struct extent_buffer *l; +int slot; + +unsigned long item_off; +unsigned long item_len; + +struct inode *inode; +int ret; + + path =btrfs_alloc_path (); +if (!path) +return -ENOMEM ; + + subvol_info =kzalloc (sizeof (*subvol_info),GFP_KERNEL ); +if (!subvol_info) { +btrfs_free_path (path); +return -ENOMEM ; + } + inode =file_inode (file); + + root =BTRFS_I (inode)->root->fs_info->tree_root; + key.objectid =BTRFS_I (inode)->root->root_key.objectid; + key.type =BTRFS_ROOT_ITEM_KEY ; + key.offset =0 ; + ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); +if (ret <0 ) { + goto out; + }else if (ret >0 ) { +u64 objectid = key.objectid; + +if (path->slots[0 ] >=btrfs_header_nritems (path->nodes[0 ])) { + ret =btrfs_next_leaf (root, path); +if (ret <0 ) +return ret; + } + +/* If the subvolume is a snapshot, offset is not zero */ +btrfs_item_key_to_cpu (path->nodes[0 ], &key, path->slots[0 ]); +if (key.objectid != objectid || + key.type !=BTRFS_ROOT_ITEM_KEY ) { + ret = -ENOENT ; + goto out; + } + } + + l = path->nodes[0 ]; + slot = path->slots[0 ]; + item_off =btrfs_item_ptr_offset (l, slot); + item_len =btrfs_item_size_nr (l, slot); +read_extent_buffer (l, &root_item, item_off, item_len); + + subvol_info->id = key.objectid; + + subvol_info->generation =btrfs_root_generation (&root_item); + subvol_info->flags =btrfs_root_flags (&root_item); + +memcpy (subvol_info->uuid, root_item.uuid,BTRFS_UUID_SIZE ); +memcpy (subvol_info->parent_uuid, root_item.parent_uuid, +BTRFS_UUID_SIZE ); +memcpy (subvol_info->received_uuid, root_item.received_uuid, +BTRFS_UUID_SIZE ); + + subvol_info->ctransid =btrfs_root_ctransid (&root_item); + subvol_info->ctime.sec =btrfs_stack_timespec_sec (&root_item.ctime); + subvol_info->ctime.nsec =btrfs_stack_timespec_nsec (&root_item.ctime); + + subvol_info->otransid =btrfs_root_otransid (&root_item); + subvol_info->otime.sec =btrfs_stack_timespec_sec (&root_item.otime); + subvol_info->otime.nsec =btrfs_stack_timespec_nsec (&root_item.otime); + + subvol_info->stransid =btrfs_root_stransid (&root_item); + subvol_info->stime.sec =btrfs_stack_timespec_sec (&root_item.stime); + subvol_info->stime.nsec =btrfs_stack_timespec_nsec (&root_item.stime); + + subvol_info->rtransid =btrfs_root_rtransid (&root_item); + subvol_info->rtime.sec =btrfs_stack_timespec_sec (&root_item.rtime); + subvol_info->rtime.nsec =btrfs_stack_timespec_nsec (&root_item.rtime); + +btrfs_release_path (path); + key.type =BTRFS_ROOT_BACKREF_KEY ; + key.offset =0 ; + ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); +if (ret <0 ) { + goto out; + }else if (path->slots[0 ] >=btrfs_header_nritems (path->nodes[0 ])) { + ret =btrfs_next_leaf (root, path); +if (ret <0 ) +return ret; + } + + l = path->nodes[0 ]; + slot = path->slots[0 ]; +btrfs_item_key_to_cpu (l, &key, slot); +if (key.objectid == subvol_info->id && + key.type ==BTRFS_ROOT_BACKREF_KEY ){ + subvol_info->parent_id = key.offset; + + rref = btrfs_item_ptr(l, slot, struct btrfs_root_ref); + subvol_info->dirid =btrfs_root_ref_dirid (l, rref); + + item_off =btrfs_item_ptr_offset (l, slot) + +sizeof (struct btrfs_root_ref ); + item_len =btrfs_item_size_nr (l, slot) + -sizeof (struct btrfs_root_ref ); +read_extent_buffer (l, subvol_info->name, item_off, item_len); + } + +if (copy_to_user (argp, subvol_info,sizeof (*subvol_info))) + ret = -EFAULT ; + +out: +kzfree (subvol_info); +btrfs_free_path (path); +return ret; +} + static noinline int btrfs_ioctl_snap_destroy(struct file *file,void __user *arg) {
@@ -5374,6 +5501,8 @@ long btrfs_ioctl(struct file *file, unsigned intreturn btrfs_ioctl_get_features (file, argp);case BTRFS_IOC_SET_FEATURES :return btrfs_ioctl_set_features (file, argp); +case BTRFS_IOC_GET_SUBVOL_INFO : +return btrfs_ioctl_get_subvol_info (file, argp); }return -ENOTTY ;
include/uapi/linux/btrfs.h +51 -0
62 lines not on this page · raw message
Signature · 1 line
2.14.3
RE: [PATCH v4 1/3] btrfs: Add unprivileged ioctl which returns subvolume information
Hi,
Quoted 57 lines
-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Tomohiro Misono
Sent: Friday, May 11, 2018 3:26 PM
To: [email protected]
Subject: [PATCH v4 1/3] btrfs: Add unprivileged ioctl which returns subvolume informationAdd new unprivileged ioctl
BTRFS_IOC_GET_SUBVOL_INFOwhich returns the information of subvolume containing this inode. (i.e. returns the information inROOT_ITEMandROOT_BACKREF.)Signed-off-by Tomohiro Misono <[email protected]>--- fs/btrfs/ioctl.c | 129 +++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/btrfs.h | 51 ++++++++++++++++++ 2 files changed, 180 insertions(+)fs/btrfs/ioctl.c +35
-0@@ -2242,6 +2242,133 @@ static noinline int btrfs_ioctl_ino_lookup(struct file *file,return ret; } +/* Get the subvolume information in BTRFS_ROOT_ITEM and +BTRFS_ROOT_BACKREF */ static noinline int btrfs_ioctl_get_subvol_info(struct file *file, +void __user *argp) +{ +struct btrfs_ioctl_get_subvol_info_args *subvol_info; +struct btrfs_root *root; +struct btrfs_path *path; +struct btrfs_key key; + +struct btrfs_root_item root_item; +struct btrfs_root_ref *rref; +struct extent_buffer *l; +int slot; + +unsigned long item_off; +unsigned long item_len; + +struct inode *inode; +int ret; + + path =btrfs_alloc_path (); +if (!path) +return -ENOMEM ; + + subvol_info =kzalloc (sizeof (*subvol_info),GFP_KERNEL ); +if (!subvol_info) { +btrfs_free_path (path); +return -ENOMEM ; + } + inode =file_inode (file); + + root =BTRFS_I (inode)->root->fs_info->tree_root; + key.objectid =BTRFS_I (inode)->root->root_key.objectid; + key.type =BTRFS_ROOT_ITEM_KEY ; + key.offset =0 ;
fs/btrfs/ioctl.c static noinline int btrfs_ioctl_ino_lookup(struct file *file, · line 2289
Quoted 10 lines
fs/btrfs/ioctl.c +10
-0+ ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); +if (ret <0 ) { + goto out; + }else if (ret >0 ) { +u64 objectid = key.objectid; + +if (path->slots[0 ] >=btrfs_header_nritems (path->nodes[0 ])) { + ret =btrfs_next_leaf (root, path); +if (ret <0 ) +return ret;
Should goto out; to free subvol_info and path.
Quoted 44 lines
fs/btrfs/ioctl.c +44
-0+ } + +/* If the subvolume is a snapshot, offset is not zero */ +btrfs_item_key_to_cpu (path->nodes[0 ], &key, path->slots[0 ]); +if (key.objectid != objectid || + key.type !=BTRFS_ROOT_ITEM_KEY ) { + ret = -ENOENT ; + goto out; + } + } + + l = path->nodes[0 ]; + slot = path->slots[0 ]; + item_off =btrfs_item_ptr_offset (l, slot); + item_len =btrfs_item_size_nr (l, slot); +read_extent_buffer (l, &root_item, item_off, item_len); + + subvol_info->id = key.objectid; + + subvol_info->generation =btrfs_root_generation (&root_item); + subvol_info->flags =btrfs_root_flags (&root_item); + +memcpy (subvol_info->uuid, root_item.uuid,BTRFS_UUID_SIZE ); +memcpy (subvol_info->parent_uuid, root_item.parent_uuid, +BTRFS_UUID_SIZE ); +memcpy (subvol_info->received_uuid, root_item.received_uuid, +BTRFS_UUID_SIZE ); + + subvol_info->ctransid =btrfs_root_ctransid (&root_item); + subvol_info->ctime.sec =btrfs_stack_timespec_sec (&root_item.ctime); + subvol_info->ctime.nsec =btrfs_stack_timespec_nsec (&root_item.ctime); + + subvol_info->otransid =btrfs_root_otransid (&root_item); + subvol_info->otime.sec =btrfs_stack_timespec_sec (&root_item.otime); + subvol_info->otime.nsec =btrfs_stack_timespec_nsec (&root_item.otime); + + subvol_info->stransid =btrfs_root_stransid (&root_item); + subvol_info->stime.sec =btrfs_stack_timespec_sec (&root_item.stime); + subvol_info->stime.nsec =btrfs_stack_timespec_nsec (&root_item.stime); + + subvol_info->rtransid =btrfs_root_rtransid (&root_item); + subvol_info->rtime.sec =btrfs_stack_timespec_sec (&root_item.rtime); + subvol_info->rtime.nsec =btrfs_stack_timespec_nsec (&root_item.rtime); +
fs/btrfs/ioctl.c static noinline int btrfs_ioctl_ino_lookup(struct file *file, · line 2343
Quoted 10 lines
fs/btrfs/ioctl.c +10
-0+btrfs_release_path (path); + key.type =BTRFS_ROOT_BACKREF_KEY ; + key.offset =0 ; + ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); +if (ret <0 ) { + goto out; + }else if (path->slots[0 ] >=btrfs_header_nritems (path->nodes[0 ])) { + ret =btrfs_next_leaf (root, path); +if (ret <0 ) +return ret;
Should goto out; to free subvol_info and path.
Quoted 8 lines
fs/btrfs/ioctl.c +8
-0+ } + + l = path->nodes[0 ]; + slot = path->slots[0 ]; +btrfs_item_key_to_cpu (l, &key, slot); +if (key.objectid == subvol_info->id && + key.type ==BTRFS_ROOT_BACKREF_KEY ){ + subvol_info->parent_id = key.offset;
fs/btrfs/ioctl.c static noinline int btrfs_ioctl_ino_lookup(struct file *file, · line 2361
Quoted 10 lines
fs/btrfs/ioctl.c +10
-0+ + rref = btrfs_item_ptr(l, slot, struct btrfs_root_ref); + subvol_info->dirid =btrfs_root_ref_dirid (l, rref); + + item_off =btrfs_item_ptr_offset (l, slot) + +sizeof (struct btrfs_root_ref ); + item_len =btrfs_item_size_nr (l, slot) + -sizeof (struct btrfs_root_ref ); +read_extent_buffer (l, subvol_info->name, item_off, item_len); + }
If this if is not correct(ex. corrupt filesystem without backref), should it return -ENOENT, or its be ok without parent_id, dirid and name. Suggest to add logic of else.
Quoted 88 lines
fs/btrfs/ioctl.c +12
-0+ +if (copy_to_user (argp, subvol_info,sizeof (*subvol_info))) + ret = -EFAULT ; + +out: +kzfree (subvol_info); +btrfs_free_path (path); +return ret; +} + static noinline int btrfs_ioctl_snap_destroy(struct file *file,void __user *arg) {@@ -5374,6 +5501,8 @@ long btrfs_ioctl(struct file *file, unsigned intreturn btrfs_ioctl_get_features (file, argp);case BTRFS_IOC_SET_FEATURES :return btrfs_ioctl_set_features (file, argp); +case BTRFS_IOC_GET_SUBVOL_INFO : +return btrfs_ioctl_get_subvol_info (file, argp); }return -ENOTTY ;include/uapi/linux/btrfs.h +49
-0@@ -725,6 +725,55 @@ struct btrfs_ioctl_send_args {__u64 reserved[4 ];/* in */ }; +struct btrfs_ioctl_get_subvol_info_args { +/* All filed is out */ +/* Id of this subvolume */ +__u64 id; +/* Name of this subvolume, used to get the real name at mount point */ +char name[BTRFS_VOL_NAME_MAX +1 ]; +/* +* Id of the subvolume which contains this subvolume. +* Zero for top-level subvolume or deleted subvolume +*/ +__u64 parent_id; +/* +* Inode number of the directory which contains this subvolume. +* Zero for top-level subvolume or deleted subvolume +*/ +__u64 dirid; + +/* Latest transaction id of this subvolume */ +__u64 generation; +/* Flags of this subvolume */ +__u64 flags; + +/* uuid of this subvolume */ +__u8 uuid[BTRFS_UUID_SIZE ]; +/* +* uuid of the subvolume of which this subvolume is a snapshot. +* All zero for non-snapshot subvolume +*/ +__u8 parent_uuid[BTRFS_UUID_SIZE ]; +/* +* uuid of the subvolume from which this subvolume is received. +* All zero for non-received subvolume +*/ +__u8 received_uuid[BTRFS_UUID_SIZE ]; + +/* Transaction id indicates when change/create/send/receive happens */ +__u64 ctransid; +__u64 otransid; +__u64 stransid; +__u64 rtransid; +/* Time corresponds to c/o/s/rtransid */ +struct btrfs_ioctl_timespec ctime; +struct btrfs_ioctl_timespec otime; +struct btrfs_ioctl_timespec stime; +struct btrfs_ioctl_timespec rtime; + +__u64 reserved[8 ]; +}; + /* Error codes as returned by the kernel */ enum btrfs_err_code { BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1, @@ -843,5 +892,7 @@ enum btrfs_err_code { struct btrfs_ioctl_vol_args_v2)#define
BTRFS_IOC_LOGICAL_INO_V2_IOWR(BTRFS_IOCTL_MAGIC, 59, \include/uapi/linux/btrfs.h +2
-1struct btrfs_ioctl_logical_ino_args) +#define BTRFS_IOC_GET_SUBVOL_INFO _IOR(BTRFS_IOCTL_MAGIC, 60, \ + struct btrfs_ioctl_get_subvol_info_args)#endif /* _UAPI_LINUX_BTRFS_H */ --
Quoted 2 lines
2.14.3
Quoted 6 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
�翳簕.n�+壏煯壄�+%娝�遍荻w�簕.n�+壏{饼籯~镶炟^n噐■�侂h櫒璀�&{鄗夸z罐楘+€�+zf"穐殘啳嗃i��飦�戧鐉_璁鎗:+v墾�)撸鴐
Re: [PATCH v4 1/3] btrfs: Add unprivileged ioctl which returns subvolume information
Quoted 62 lines · Jinxiang/顾 金香
Hi,
Quoted 60 lines
-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Tomohiro Misono
Sent: Friday, May 11, 2018 3:26 PM
To: [email protected]
Subject: [PATCH v4 1/3] btrfs: Add unprivileged ioctl which returns subvolume informationAdd new unprivileged ioctl
BTRFS_IOC_GET_SUBVOL_INFOwhich returns the information of subvolume containing this inode. (i.e. returns the information inROOT_ITEMandROOT_BACKREF.)Signed-off-by Tomohiro Misono <[email protected]>--- fs/btrfs/ioctl.c | 129 +++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/btrfs.h | 51 ++++++++++++++++++ 2 files changed, 180 insertions(+)fs/btrfs/ioctl.c +38
-0@@ -2242,6 +2242,133 @@ static noinline int btrfs_ioctl_ino_lookup(struct file *file,return ret; } +/* Get the subvolume information in BTRFS_ROOT_ITEM and +BTRFS_ROOT_BACKREF */ static noinline int btrfs_ioctl_get_subvol_info(struct file *file, +void __user *argp) +{ +struct btrfs_ioctl_get_subvol_info_args *subvol_info; +struct btrfs_root *root; +struct btrfs_path *path; +struct btrfs_key key; + +struct btrfs_root_item root_item; +struct btrfs_root_ref *rref; +struct extent_buffer *l; +int slot; + +unsigned long item_off; +unsigned long item_len; + +struct inode *inode; +int ret; + + path =btrfs_alloc_path (); +if (!path) +return -ENOMEM ; + + subvol_info =kzalloc (sizeof (*subvol_info),GFP_KERNEL ); +if (!subvol_info) { +btrfs_free_path (path); +return -ENOMEM ; + } + inode =file_inode (file); + + root =BTRFS_I (inode)->root->fs_info->tree_root; + key.objectid =BTRFS_I (inode)->root->root_key.objectid; + key.type =BTRFS_ROOT_ITEM_KEY ; + key.offset =0 ; + ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); +if (ret <0 ) { + goto out;
Quoted 8 lines
fs/btrfs/ioctl.c static noinline int btrfs_ioctl_ino_lookup(struct file *file, · line 2289
Quoted 7 lines
fs/btrfs/ioctl.c +7
-0+ }else if (ret >0 ) { +u64 objectid = key.objectid; + +if (path->slots[0 ] >=btrfs_header_nritems (path->nodes[0 ])) { + ret =btrfs_next_leaf (root, path); +if (ret <0 ) +return ret;Should goto out; to free
subvol_infoand path.
Thanks, will update both.
Quoted 68 lines
Quoted 44 lines
fs/btrfs/ioctl.c +44
-0+ } + +/* If the subvolume is a snapshot, offset is not zero */ +btrfs_item_key_to_cpu (path->nodes[0 ], &key, path->slots[0 ]); +if (key.objectid != objectid || + key.type !=BTRFS_ROOT_ITEM_KEY ) { + ret = -ENOENT ; + goto out; + } + } + + l = path->nodes[0 ]; + slot = path->slots[0 ]; + item_off =btrfs_item_ptr_offset (l, slot); + item_len =btrfs_item_size_nr (l, slot); +read_extent_buffer (l, &root_item, item_off, item_len); + + subvol_info->id = key.objectid; + + subvol_info->generation =btrfs_root_generation (&root_item); + subvol_info->flags =btrfs_root_flags (&root_item); + +memcpy (subvol_info->uuid, root_item.uuid,BTRFS_UUID_SIZE ); +memcpy (subvol_info->parent_uuid, root_item.parent_uuid, +BTRFS_UUID_SIZE ); +memcpy (subvol_info->received_uuid, root_item.received_uuid, +BTRFS_UUID_SIZE ); + + subvol_info->ctransid =btrfs_root_ctransid (&root_item); + subvol_info->ctime.sec =btrfs_stack_timespec_sec (&root_item.ctime); + subvol_info->ctime.nsec =btrfs_stack_timespec_nsec (&root_item.ctime); + + subvol_info->otransid =btrfs_root_otransid (&root_item); + subvol_info->otime.sec =btrfs_stack_timespec_sec (&root_item.otime); + subvol_info->otime.nsec =btrfs_stack_timespec_nsec (&root_item.otime); + + subvol_info->stransid =btrfs_root_stransid (&root_item); + subvol_info->stime.sec =btrfs_stack_timespec_sec (&root_item.stime); + subvol_info->stime.nsec =btrfs_stack_timespec_nsec (&root_item.stime); + + subvol_info->rtransid =btrfs_root_rtransid (&root_item); + subvol_info->rtime.sec =btrfs_stack_timespec_sec (&root_item.rtime); + subvol_info->rtime.nsec =btrfs_stack_timespec_nsec (&root_item.rtime); +fs/btrfs/ioctl.c static noinline int btrfs_ioctl_ino_lookup(struct file *file, · line 2343
Quoted 10 lines
fs/btrfs/ioctl.c +10
-0+btrfs_release_path (path); + key.type =BTRFS_ROOT_BACKREF_KEY ; + key.offset =0 ; + ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); +if (ret <0 ) { + goto out; + }else if (path->slots[0 ] >=btrfs_header_nritems (path->nodes[0 ])) { + ret =btrfs_next_leaf (root, path); +if (ret <0 ) +return ret;Should goto out; to free
subvol_infoand path.Quoted 13 lines
fs/btrfs/ioctl.c +13
-0+ } + + l = path->nodes[0 ]; + slot = path->slots[0 ]; +btrfs_item_key_to_cpu (l, &key, slot); +if (key.objectid == subvol_info->id && + key.type ==BTRFS_ROOT_BACKREF_KEY ){ + subvol_info->parent_id = key.offset; + + rref = btrfs_item_ptr(l, slot, struct btrfs_root_ref); + subvol_info->dirid =btrfs_root_ref_dirid (l, rref); + + item_off =btrfs_item_ptr_offset (l, slot)
Quoted 8 lines
fs/btrfs/ioctl.c static noinline int btrfs_ioctl_ino_lookup(struct file *file, · line 2361
Quoted 5 lines
fs/btrfs/ioctl.c +5
-0+ +sizeof (struct btrfs_root_ref ); + item_len =btrfs_item_size_nr (l, slot) + -sizeof (struct btrfs_root_ref ); +read_extent_buffer (l, subvol_info->name, item_off, item_len); + }If this if is not correct(ex. corrupt filesystem without backref), should it return
-ENOENT, or its be ok withoutparent_id, dirid and name. Suggest to add logic of else.
If backref does not exist (except top-level subvolume), it means filesystem corruption. So, I'd like to return -EUCLEAN here.
Thanks,
Tomohiro Misono
Quoted 100 lines
Quoted 89 lines
fs/btrfs/ioctl.c +12
-0+ +if (copy_to_user (argp, subvol_info,sizeof (*subvol_info))) + ret = -EFAULT ; + +out: +kzfree (subvol_info); +btrfs_free_path (path); +return ret; +} + static noinline int btrfs_ioctl_snap_destroy(struct file *file,void __user *arg) {@@ -5374,6 +5501,8 @@ long btrfs_ioctl(struct file *file, unsigned intreturn btrfs_ioctl_get_features (file, argp);case BTRFS_IOC_SET_FEATURES :return btrfs_ioctl_set_features (file, argp); +case BTRFS_IOC_GET_SUBVOL_INFO : +return btrfs_ioctl_get_subvol_info (file, argp); }return -ENOTTY ;include/uapi/linux/btrfs.h +49
-0@@ -725,6 +725,55 @@ struct btrfs_ioctl_send_args {__u64 reserved[4 ];/* in */ }; +struct btrfs_ioctl_get_subvol_info_args { +/* All filed is out */ +/* Id of this subvolume */ +__u64 id; +/* Name of this subvolume, used to get the real name at mount point */ +char name[BTRFS_VOL_NAME_MAX +1 ]; +/* +* Id of the subvolume which contains this subvolume. +* Zero for top-level subvolume or deleted subvolume +*/ +__u64 parent_id; +/* +* Inode number of the directory which contains this subvolume. +* Zero for top-level subvolume or deleted subvolume +*/ +__u64 dirid; + +/* Latest transaction id of this subvolume */ +__u64 generation; +/* Flags of this subvolume */ +__u64 flags; + +/* uuid of this subvolume */ +__u8 uuid[BTRFS_UUID_SIZE ]; +/* +* uuid of the subvolume of which this subvolume is a snapshot. +* All zero for non-snapshot subvolume +*/ +__u8 parent_uuid[BTRFS_UUID_SIZE ]; +/* +* uuid of the subvolume from which this subvolume is received. +* All zero for non-received subvolume +*/ +__u8 received_uuid[BTRFS_UUID_SIZE ]; + +/* Transaction id indicates when change/create/send/receive happens */ +__u64 ctransid; +__u64 otransid; +__u64 stransid; +__u64 rtransid; +/* Time corresponds to c/o/s/rtransid */ +struct btrfs_ioctl_timespec ctime; +struct btrfs_ioctl_timespec otime; +struct btrfs_ioctl_timespec stime; +struct btrfs_ioctl_timespec rtime; + +__u64 reserved[8 ]; +}; + /* Error codes as returned by the kernel */ enum btrfs_err_code { BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1, @@ -843,5 +892,7 @@ enum btrfs_err_code { struct btrfs_ioctl_vol_args_v2)#define
BTRFS_IOC_LOGICAL_INO_V2_IOWR(BTRFS_IOCTL_MAGIC, 59, \include/uapi/linux/btrfs.h +2
-1struct btrfs_ioctl_logical_ino_args) +#define BTRFS_IOC_GET_SUBVOL_INFO _IOR(BTRFS_IOCTL_MAGIC, 60, \ + struct btrfs_ioctl_get_subvol_info_args)#endif /* _UAPI_LINUX_BTRFS_H */ --Quoted 2 lines
2.14.3
Reviewed-by Gu Jinxiang <[email protected]>Quoted 6 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
RE: [PATCH v4 1/3] btrfs: Add unprivileged ioctl which returns subvolume information
Hi, add a missed a comment.
Quoted 81 lines
-----Original Message-----
From: Misono Tomohiro [mailto:[email protected]]
Sent: Tuesday, May 15, 2018 3:04 PM
To: Gu, Jinxiang/顾 金香 <[email protected]>; [email protected]
Subject: Re: [PATCH v4 1/3] btrfs: Add unprivileged ioctl which returns subvolume informationQuoted 66 lines · Jinxiang/顾 金香
Hi,
Quoted 64 lines
-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Tomohiro Misono
Sent: Friday, May 11, 2018 3:26 PM
To: [email protected]
Subject: [PATCH v4 1/3] btrfs: Add unprivileged ioctl which returns subvolume informationAdd new unprivileged ioctl
BTRFS_IOC_GET_SUBVOL_INFOwhich returns the information of subvolume containing this inode. (i.e. returns the information inROOT_ITEMandROOT_BACKREF.)Signed-off-by Tomohiro Misono <[email protected]>--- fs/btrfs/ioctl.c | 129 +++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/btrfs.h | 51 ++++++++++++++++++ 2 files changed, 180 insertions(+)fs/btrfs/ioctl.c index renamed from fs/btrfs/ioctl.c +0
-0
48e2ddff32bd..64b23e22852f100644fs/btrfs/ioctl.c +38
-0@@ -2242,6 +2242,133 @@ static noinline int btrfs_ioctl_ino_lookup(struct file *file,return ret; } +/* Get the subvolume information in BTRFS_ROOT_ITEM and +BTRFS_ROOT_BACKREF */ static noinline int btrfs_ioctl_get_subvol_info(struct file *file, +void __user *argp) +{ +struct btrfs_ioctl_get_subvol_info_args *subvol_info; +struct btrfs_root *root; +struct btrfs_path *path; +struct btrfs_key key; + +struct btrfs_root_item root_item; +struct btrfs_root_ref *rref; +struct extent_buffer *l; +int slot; + +unsigned long item_off; +unsigned long item_len; + +struct inode *inode; +int ret; + + path =btrfs_alloc_path (); +if (!path) +return -ENOMEM ; + + subvol_info =kzalloc (sizeof (*subvol_info),GFP_KERNEL ); +if (!subvol_info) { +btrfs_free_path (path); +return -ENOMEM ; + } + inode =file_inode (file); + + root =BTRFS_I (inode)->root->fs_info->tree_root; + key.objectid =BTRFS_I (inode)->root->root_key.objectid; + key.type =BTRFS_ROOT_ITEM_KEY ; + key.offset =0 ; + ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); +if (ret <0 ) { + goto out;Quoted 8 lines
fs/btrfs/ioctl.c static noinline int btrfs_ioctl_ino_lookup(struct file *file, · line 2289
Quoted 7 lines
fs/btrfs/ioctl.c +7
-0+ }else if (ret >0 ) { +u64 objectid = key.objectid; + +if (path->slots[0 ] >=btrfs_header_nritems (path->nodes[0 ])) { + ret =btrfs_next_leaf (root, path); +if (ret <0 ) +return ret;Should goto out; to free
subvol_infoand path.
Quoted 2 lines
Thanks, will update both.
Since btrfs_next_leaf may return 1 when nritems of next leaf is 0, So, btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); may goes wrong. And I think it should add a judge before btrfs_item_key_to_cpu.
Quoted 81 lines
Quoted 72 lines
Quoted 48 lines
fs/btrfs/ioctl.c +48
-0+ } + +/* If the subvolume is a snapshot, offset is not zero */ +btrfs_item_key_to_cpu (path->nodes[0 ], &key, path->slots[0 ]); +if (key.objectid != objectid || + key.type !=BTRFS_ROOT_ITEM_KEY ) { + ret = -ENOENT ; + goto out; + } + } + + l = path->nodes[0 ]; + slot = path->slots[0 ]; + item_off =btrfs_item_ptr_offset (l, slot); + item_len =btrfs_item_size_nr (l, slot); +read_extent_buffer (l, &root_item, item_off, item_len); + + subvol_info->id = key.objectid; + + subvol_info->generation =btrfs_root_generation (&root_item); + subvol_info->flags =btrfs_root_flags (&root_item); + +memcpy (subvol_info->uuid, root_item.uuid,BTRFS_UUID_SIZE ); +memcpy (subvol_info->parent_uuid, root_item.parent_uuid, +BTRFS_UUID_SIZE ); +memcpy (subvol_info->received_uuid, root_item.received_uuid, +BTRFS_UUID_SIZE ); + + subvol_info->ctransid =btrfs_root_ctransid (&root_item); + subvol_info->ctime.sec =btrfs_stack_timespec_sec (&root_item.ctime); + subvol_info->ctime.nsec = +btrfs_stack_timespec_nsec (&root_item.ctime); + + subvol_info->otransid =btrfs_root_otransid (&root_item); + subvol_info->otime.sec =btrfs_stack_timespec_sec (&root_item.otime); + subvol_info->otime.nsec = +btrfs_stack_timespec_nsec (&root_item.otime); + + subvol_info->stransid =btrfs_root_stransid (&root_item); + subvol_info->stime.sec =btrfs_stack_timespec_sec (&root_item.stime); + subvol_info->stime.nsec = +btrfs_stack_timespec_nsec (&root_item.stime); + + subvol_info->rtransid =btrfs_root_rtransid (&root_item); + subvol_info->rtime.sec =btrfs_stack_timespec_sec (&root_item.rtime); + subvol_info->rtime.nsec = +btrfs_stack_timespec_nsec (&root_item.rtime); +fs/btrfs/ioctl.c static noinline int btrfs_ioctl_ino_lookup(struct file *file, · line 2343
Quoted 10 lines
fs/btrfs/ioctl.c +10
-0+btrfs_release_path (path); + key.type =BTRFS_ROOT_BACKREF_KEY ; + key.offset =0 ; + ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); +if (ret <0 ) { + goto out; + }else if (path->slots[0 ] >=btrfs_header_nritems (path->nodes[0 ])) { + ret =btrfs_next_leaf (root, path); +if (ret <0 ) +return ret;Should goto out; to free
subvol_infoand path.Quoted 13 lines
fs/btrfs/ioctl.c +13
-0+ } + + l = path->nodes[0 ]; + slot = path->slots[0 ]; +btrfs_item_key_to_cpu (l, &key, slot); +if (key.objectid == subvol_info->id && + key.type ==BTRFS_ROOT_BACKREF_KEY ){ + subvol_info->parent_id = key.offset; + + rref = btrfs_item_ptr(l, slot, struct btrfs_root_ref); + subvol_info->dirid =btrfs_root_ref_dirid (l, rref); + + item_off =btrfs_item_ptr_offset (l, slot)Quoted 8 lines
fs/btrfs/ioctl.c static noinline int btrfs_ioctl_ino_lookup(struct file *file, · line 2361
Quoted 5 lines
fs/btrfs/ioctl.c +5
-0+ +sizeof (struct btrfs_root_ref ); + item_len =btrfs_item_size_nr (l, slot) + -sizeof (struct btrfs_root_ref ); +read_extent_buffer (l, subvol_info->name, item_off, item_len); + }If this if is not correct(ex. corrupt filesystem without backref), should it return
-ENOENT, or its be ok withoutparent_id, dirid and name. Suggest to add logic of else.
Quoted 107 lines
If backref does not exist (except top-level subvolume), it means filesystem corruption. So, I'd like to return
-EUCLEANhere.Thanks,
Tomohiro MisonoQuoted 101 lines
Quoted 90 lines
fs/btrfs/ioctl.c +12
-0+ +if (copy_to_user (argp, subvol_info,sizeof (*subvol_info))) + ret = -EFAULT ; + +out: +kzfree (subvol_info); +btrfs_free_path (path); +return ret; +} + static noinline int btrfs_ioctl_snap_destroy(struct file *file,void __user *arg) {@@ -5374,6 +5501,8 @@ long btrfs_ioctl(struct file *file, unsigned intreturn btrfs_ioctl_get_features (file, argp);case BTRFS_IOC_SET_FEATURES :return btrfs_ioctl_set_features (file, argp); +case BTRFS_IOC_GET_SUBVOL_INFO : +return btrfs_ioctl_get_subvol_info (file, argp); }return -ENOTTY ;include/uapi/linux/btrfs.h +49
-0@@ -725,6 +725,55 @@ struct btrfs_ioctl_send_args {__u64 reserved[4 ];/* in */ }; +struct btrfs_ioctl_get_subvol_info_args { +/* All filed is out */ +/* Id of this subvolume */ +__u64 id; +/* Name of this subvolume, used to get the real name at mount point */ +char name[BTRFS_VOL_NAME_MAX +1 ]; +/* +* Id of the subvolume which contains this subvolume. +* Zero for top-level subvolume or deleted subvolume +*/ +__u64 parent_id; +/* +* Inode number of the directory which contains this subvolume. +* Zero for top-level subvolume or deleted subvolume +*/ +__u64 dirid; + +/* Latest transaction id of this subvolume */ +__u64 generation; +/* Flags of this subvolume */ +__u64 flags; + +/* uuid of this subvolume */ +__u8 uuid[BTRFS_UUID_SIZE ]; +/* +* uuid of the subvolume of which this subvolume is a snapshot. +* All zero for non-snapshot subvolume +*/ +__u8 parent_uuid[BTRFS_UUID_SIZE ]; +/* +* uuid of the subvolume from which this subvolume is received. +* All zero for non-received subvolume +*/ +__u8 received_uuid[BTRFS_UUID_SIZE ]; + +/* Transaction id indicates when change/create/send/receive happens */ +__u64 ctransid; +__u64 otransid; +__u64 stransid; +__u64 rtransid; +/* Time corresponds to c/o/s/rtransid */ +struct btrfs_ioctl_timespec ctime; +struct btrfs_ioctl_timespec otime; +struct btrfs_ioctl_timespec stime; +struct btrfs_ioctl_timespec rtime; + +__u64 reserved[8 ]; +}; + /* Error codes as returned by the kernel */ enum btrfs_err_code { BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1, @@ -843,5 +892,7 @@ enum btrfs_err_code { struct btrfs_ioctl_vol_args_v2) #define
BTRFS_IOC_LOGICAL_INO_V2_IOWR(BTRFS_IOCTL_MAGIC, 59, \include/uapi/linux/btrfs.h +2
-1struct btrfs_ioctl_logical_ino_args) +#define BTRFS_IOC_GET_SUBVOL_INFO _IOR(BTRFS_IOCTL_MAGIC, 60, \ + struct btrfs_ioctl_get_subvol_info_args)#endif /* _UAPI_LINUX_BTRFS_H */ --Quoted 2 lines
2.14.3
Reviewed-by Gu Jinxiang <[email protected]>Quoted 6 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
�翳簕.n�+壏煯壄�+%娝�遍荻w�簕.n�+壏{饼籯~镶炟^n噐■�侂h櫒璀�&{鄗夸z罐楘+€�+zf"穐殘啳嗃i��飦�戧鐉_璁鎗:+v墾�)撸鴐
Re: [PATCH v4 1/3] btrfs: Add unprivileged ioctl which returns subvolume information
Quoted 83 lines · Jinxiang/顾 金香
Hi, add a missed a comment.
Quoted 81 lines
-----Original Message-----
From: Misono Tomohiro [mailto:[email protected]]
Sent: Tuesday, May 15, 2018 3:04 PM
To: Gu, Jinxiang/顾 金香 <[email protected]>; [email protected]
Subject: Re: [PATCH v4 1/3] btrfs: Add unprivileged ioctl which returns subvolume informationQuoted 74 lines · Jinxiang/顾 金香
Hi,
Quoted 61 lines
-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Tomohiro Misono
Sent: Friday, May 11, 2018 3:26 PM
To: [email protected]
Subject: [PATCH v4 1/3] btrfs: Add unprivileged ioctl which returns subvolume informationAdd new unprivileged ioctl
BTRFS_IOC_GET_SUBVOL_INFOwhich returns the information of subvolume containing this inode. (i.e. returns the information inROOT_ITEMandROOT_BACKREF.)Signed-off-by Tomohiro Misono <[email protected]>--- fs/btrfs/ioctl.c | 129 +++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/btrfs.h | 51 ++++++++++++++++++ 2 files changed, 180 insertions(+)fs/btrfs/ioctl.c index renamed from fs/btrfs/ioctl.c +0
-0
48e2ddff32bd..64b23e22852f100644fs/btrfs/ioctl.c +35
-0@@ -2242,6 +2242,133 @@ static noinline int btrfs_ioctl_ino_lookup(struct file *file,return ret; } +/* Get the subvolume information in BTRFS_ROOT_ITEM and +BTRFS_ROOT_BACKREF */ static noinline int btrfs_ioctl_get_subvol_info(struct file *file, +void __user *argp) +{ +struct btrfs_ioctl_get_subvol_info_args *subvol_info; +struct btrfs_root *root; +struct btrfs_path *path; +struct btrfs_key key; + +struct btrfs_root_item root_item; +struct btrfs_root_ref *rref; +struct extent_buffer *l; +int slot; + +unsigned long item_off; +unsigned long item_len; + +struct inode *inode; +int ret; + + path =btrfs_alloc_path (); +if (!path) +return -ENOMEM ; + + subvol_info =kzalloc (sizeof (*subvol_info),GFP_KERNEL ); +if (!subvol_info) { +btrfs_free_path (path); +return -ENOMEM ; + } + inode =file_inode (file); + + root =BTRFS_I (inode)->root->fs_info->tree_root; + key.objectid =BTRFS_I (inode)->root->root_key.objectid; + key.type =BTRFS_ROOT_ITEM_KEY ; + key.offset =0 ;fs/btrfs/ioctl.c static noinline int btrfs_ioctl_ino_lookup(struct file *file, · line 2289
Quoted 10 lines
fs/btrfs/ioctl.c +10
-0+ ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); +if (ret <0 ) { + goto out; + }else if (ret >0 ) { +u64 objectid = key.objectid; + +if (path->slots[0 ] >=btrfs_header_nritems (path->nodes[0 ])) { + ret =btrfs_next_leaf (root, path); +if (ret <0 ) +return ret;Should goto out; to free
subvol_infoand path.
Quoted 6 lines
Quoted 2 lines
Thanks, will update both.
Since
btrfs_next_leafmay return 1 when nritems of next leaf is 0, So,btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); may goes wrong. And I think it should add a judge beforebtrfs_item_key_to_cpu.
Ok, I will update to handle all cases.
[snip]>>>> + l = path->nodes[0];
Quoted 19 lines
Quoted 19 lines
Quoted 18 lines
Quoted 5 lines
fs/btrfs/ioctl.c +5
-0+ slot = path->slots[0 ]; +btrfs_item_key_to_cpu (l, &key, slot); +if (key.objectid == subvol_info->id && + key.type ==BTRFS_ROOT_BACKREF_KEY ){ + subvol_info->parent_id = key.offset;fs/btrfs/ioctl.c static noinline int btrfs_ioctl_ino_lookup(struct file *file, · line 2361
Quoted 10 lines
fs/btrfs/ioctl.c +10
-0+ + rref = btrfs_item_ptr(l, slot, struct btrfs_root_ref); + subvol_info->dirid =btrfs_root_ref_dirid (l, rref); + + item_off =btrfs_item_ptr_offset (l, slot) + +sizeof (struct btrfs_root_ref ); + item_len =btrfs_item_size_nr (l, slot) + -sizeof (struct btrfs_root_ref ); +read_extent_buffer (l, subvol_info->name, item_off, item_len); + }If this if is not correct(ex. corrupt filesystem without backref), should it return
-ENOENT, or its be ok withoutparent_id, dirid and name. Suggest to add logic of else.
Quoted 2 lines
Quoted 2 lines
If backref does not exist (except top-level subvolume), it means filesystem corruption. So, I'd like to return
-EUCLEANhere.
On second thought, I notice if this ioctl is called after containing subvolume is deleted, the entry may not exist. So, -ENOENT is fine.
Thanks,
Tomohiro Misono
Quoted 105 lines
Quoted 105 lines
Thanks,
Tomohiro MisonoQuoted 101 lines
Quoted 90 lines
fs/btrfs/ioctl.c +12
-0+ +if (copy_to_user (argp, subvol_info,sizeof (*subvol_info))) + ret = -EFAULT ; + +out: +kzfree (subvol_info); +btrfs_free_path (path); +return ret; +} + static noinline int btrfs_ioctl_snap_destroy(struct file *file,void __user *arg) {@@ -5374,6 +5501,8 @@ long btrfs_ioctl(struct file *file, unsigned intreturn btrfs_ioctl_get_features (file, argp);case BTRFS_IOC_SET_FEATURES :return btrfs_ioctl_set_features (file, argp); +case BTRFS_IOC_GET_SUBVOL_INFO : +return btrfs_ioctl_get_subvol_info (file, argp); }return -ENOTTY ;include/uapi/linux/btrfs.h +49
-0@@ -725,6 +725,55 @@ struct btrfs_ioctl_send_args {__u64 reserved[4 ];/* in */ }; +struct btrfs_ioctl_get_subvol_info_args { +/* All filed is out */ +/* Id of this subvolume */ +__u64 id; +/* Name of this subvolume, used to get the real name at mount point */ +char name[BTRFS_VOL_NAME_MAX +1 ]; +/* +* Id of the subvolume which contains this subvolume. +* Zero for top-level subvolume or deleted subvolume +*/ +__u64 parent_id; +/* +* Inode number of the directory which contains this subvolume. +* Zero for top-level subvolume or deleted subvolume +*/ +__u64 dirid; + +/* Latest transaction id of this subvolume */ +__u64 generation; +/* Flags of this subvolume */ +__u64 flags; + +/* uuid of this subvolume */ +__u8 uuid[BTRFS_UUID_SIZE ]; +/* +* uuid of the subvolume of which this subvolume is a snapshot. +* All zero for non-snapshot subvolume +*/ +__u8 parent_uuid[BTRFS_UUID_SIZE ]; +/* +* uuid of the subvolume from which this subvolume is received. +* All zero for non-received subvolume +*/ +__u8 received_uuid[BTRFS_UUID_SIZE ]; + +/* Transaction id indicates when change/create/send/receive happens */ +__u64 ctransid; +__u64 otransid; +__u64 stransid; +__u64 rtransid; +/* Time corresponds to c/o/s/rtransid */ +struct btrfs_ioctl_timespec ctime; +struct btrfs_ioctl_timespec otime; +struct btrfs_ioctl_timespec stime; +struct btrfs_ioctl_timespec rtime; + +__u64 reserved[8 ]; +}; + /* Error codes as returned by the kernel */ enum btrfs_err_code { BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1, @@ -843,5 +892,7 @@ enum btrfs_err_code { struct btrfs_ioctl_vol_args_v2) #define
BTRFS_IOC_LOGICAL_INO_V2_IOWR(BTRFS_IOCTL_MAGIC, 59, \include/uapi/linux/btrfs.h +2
-1struct btrfs_ioctl_logical_ino_args) +#define BTRFS_IOC_GET_SUBVOL_INFO _IOR(BTRFS_IOCTL_MAGIC, 60, \ + struct btrfs_ioctl_get_subvol_info_args)#endif /* _UAPI_LINUX_BTRFS_H */ --Quoted 2 lines
2.14.3
Reviewed-by Gu Jinxiang <[email protected]>Quoted 6 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v4 2/3 btrfs: Add unprivileged ioctl which returns subvolume's ROOT_REF
In reply to Tomohiro MisonoAdd 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.
--- fs/btrfs/ioctl.c | 102 +++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/btrfs.h | 16 +++++++ 2 files changed, 118 insertions(+)
fs/btrfs/ioctl.c +102 -0
@@ -2369,6 +2369,106 @@ static noinline int btrfs_ioctl_get_subvol_info(struct file *file,return ret; } +/* +* Return ROOT_REF information of the subvolume contining this inode +* except the subvolume name. +*/ +static noinline int btrfs_ioctl_get_subvol_rootref(struct file *file, +void __user *argp) +{ +struct btrfs_ioctl_get_subvol_rootref_args *rootrefs; +struct btrfs_root_ref *rref; +struct btrfs_root *root; +struct btrfs_path *path; +struct btrfs_key key; + +struct extent_buffer *l; +int slot; + +struct inode *inode; +int i, nritems; +int ret; +u64 objectid; +u8 found; + + path =btrfs_alloc_path (); +if (!path) +return -ENOMEM ; + + rootrefs =memdup_user (argp,sizeof (*rootrefs)); +if (!rootrefs) { +btrfs_free_path (path); +return -ENOMEM ; + } + + inode =file_inode (file); + root =BTRFS_I (inode)->root->fs_info->tree_root; + objectid =BTRFS_I (inode)->root->root_key.objectid; + + key.objectid = objectid; + key.type =BTRFS_ROOT_REF_KEY ; + key.offset = rootrefs->min_id; + found =0 ; +while (1 ) { + ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); +if (ret <0 ) { + goto out; + }else if (path->slots[0 ] >= +btrfs_header_nritems (path->nodes[0 ])) { + ret =btrfs_next_leaf (root, path); +if (ret <0 ) +return ret; + } + + l = path->nodes[0 ]; + slot = path->slots[0 ]; + nritems =btrfs_header_nritems (l); +if (nritems - slot ==0 ) { + ret =0 ; + goto out; + } + +for (i = slot; i < nritems; i++) { +btrfs_item_key_to_cpu (l, &key, i); +if (key.objectid != objectid || + key.type !=BTRFS_ROOT_REF_KEY ) { + ret =0 ; + goto out; + } + +if (found ==BTRFS_MAX_ROOTREF_BUFFER_NUM ) { + ret = -EOVERFLOW ; + goto out; + } + + rref = btrfs_item_ptr(l, i, struct btrfs_root_ref); + rootrefs->rootref[found].subvolid = key.offset; + rootrefs->rootref[found].dirid = +btrfs_root_ref_dirid (l, rref); + found++; + } + +btrfs_release_path (path); + key.offset++; + } + +out: +if (!ret || ret == -EOVERFLOW ) { + rootrefs->num_items = found; +/* update min_id for next search */ +if (found) + rootrefs->min_id = + rootrefs->rootref[found -1 ].subvolid +1 ; +if (copy_to_user (argp, rootrefs,sizeof (*rootrefs))) + ret = -EFAULT ; + } + +btrfs_free_path (path); +kfree (rootrefs); + +return ret; +} + static noinline int btrfs_ioctl_snap_destroy(struct file *file,void __user *arg) {
@@ -5503,6 +5603,8 @@ long btrfs_ioctl(struct file *file, unsigned intreturn btrfs_ioctl_set_features (file, argp);case BTRFS_IOC_GET_SUBVOL_INFO :return btrfs_ioctl_get_subvol_info (file, argp); +case BTRFS_IOC_GET_SUBVOL_ROOTREF : +return btrfs_ioctl_get_subvol_rootref (file, argp); }return -ENOTTY ;
include/uapi/linux/btrfs.h +16 -0
@@ -774,6 +774,20 @@ struct btrfs_ioctl_get_subvol_info_args {__u64 reserved[8 ]; }; +#define BTRFS_MAX_ROOTREF_BUFFER_NUM 255 +struct btrfs_ioctl_get_subvol_rootref_args { +/* in/out, min id of rootref's subvolid to be searched */ +__u64 min_id; +/* out */ +struct { +__u64 subvolid; +__u64 dirid; + } rootref[BTRFS_MAX_ROOTREF_BUFFER_NUM ]; +/* out, number of found items */ +__u8 num_items; +__u8 align[7 ]; +}; +/* Error codes as returned by the kernel */ enum btrfs_err_code {BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET =1 ,
@@ -894,5 +908,7 @@ enum btrfs_err_code { struct btrfs_ioctl_logical_ino_args)#define BTRFS_IOC_GET_SUBVOL_INFO _IOR(BTRFS_IOCTL_MAGIC, 60, \ struct btrfs_ioctl_get_subvol_info_args) +#define BTRFS_IOC_GET_SUBVOL_ROOTREF _IOWR(BTRFS_IOCTL_MAGIC, 61, \ + struct btrfs_ioctl_get_subvol_rootref_args)#endif /* _UAPI_LINUX_BTRFS_H */
Signature · 1 line
2.14.3
RE: [PATCH v4 2/3] btrfs: Add unprivileged ioctl which returns subvolume's ROOT_REF
Quoted 27 lines
-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Tomohiro Misono
Sent: Friday, May 11, 2018 3:26 PM
To: [email protected]
Subject: [PATCH v4 2/3] btrfs: Add unprivileged ioctl which returns subvolume'sROOT_REFAdd unprivileged ioctl
BTRFS_IOC_GET_SUBVOL_ROOTREFwhich returnsROOT_REFinformation 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 ofino_lookupioctl (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 thanBTRFS_MAX_ROOTREF_BUFFER_NUM,-EOVERFLOWis returned. Therefore the caller can just call this ioctl again without changing the argument to continue search.Signed-off-by Tomohiro Misono <[email protected]>--- fs/btrfs/ioctl.c | 102 +++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/btrfs.h | 16 +++++++ 2 files changed, 118 insertions(+)
fs/btrfs/ioctl.c static noinline int btrfs_ioctl_get_subvol_info(struct file *file, · line 2373
Quoted 5 lines
fs/btrfs/ioctl.c +2
-0@@ -2369,6 +2369,106 @@ static noinline int btrfs_ioctl_get_subvol_info(struct file *file,return ret; } +/* +* Return ROOT_REF information of the subvolume contining this inode
s/contining/containing
Quoted 37 lines
fs/btrfs/ioctl.c +37
-0+* except the subvolume name. +*/ +static noinline int btrfs_ioctl_get_subvol_rootref(struct file *file, +void __user *argp) +{ +struct btrfs_ioctl_get_subvol_rootref_args *rootrefs; +struct btrfs_root_ref *rref; +struct btrfs_root *root; +struct btrfs_path *path; +struct btrfs_key key; + +struct extent_buffer *l; +int slot; + +struct inode *inode; +int i, nritems; +int ret; +u64 objectid; +u8 found; + + path =btrfs_alloc_path (); +if (!path) +return -ENOMEM ; + + rootrefs =memdup_user (argp,sizeof (*rootrefs)); +if (!rootrefs) { +btrfs_free_path (path); +return -ENOMEM ; + } + + inode =file_inode (file); + root =BTRFS_I (inode)->root->fs_info->tree_root; + objectid =BTRFS_I (inode)->root->root_key.objectid; + + key.objectid = objectid; + key.type =BTRFS_ROOT_REF_KEY ; + key.offset = rootrefs->min_id;
fs/btrfs/ioctl.c static noinline int btrfs_ioctl_get_subvol_info(struct file *file, · line 2420
Quoted 10 lines
fs/btrfs/ioctl.c +10
-0+ found =0 ; +while (1 ) { + ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); +if (ret <0 ) { + goto out; + }else if (path->slots[0 ] >= +btrfs_header_nritems (path->nodes[0 ])) { + ret =btrfs_next_leaf (root, path); +if (ret <0 ) +return ret;
Should goto out; to do free work.
Quoted 23 lines
fs/btrfs/ioctl.c +23
-0+ } + + l = path->nodes[0 ]; + slot = path->slots[0 ]; + nritems =btrfs_header_nritems (l); +if (nritems - slot ==0 ) { + ret =0 ; + goto out; + } + +for (i = slot; i < nritems; i++) { +btrfs_item_key_to_cpu (l, &key, i); +if (key.objectid != objectid || + key.type !=BTRFS_ROOT_REF_KEY ) { + ret =0 ; + goto out; + } + +if (found ==BTRFS_MAX_ROOTREF_BUFFER_NUM ) { + ret = -EOVERFLOW ; + goto out; + } +
fs/btrfs/ioctl.c static noinline int btrfs_ioctl_get_subvol_info(struct file *file, · line 2453
Quoted 10 lines
fs/btrfs/ioctl.c +10
-0+ rref = btrfs_item_ptr(l, i, struct btrfs_root_ref); + rootrefs->rootref[found].subvolid = key.offset; + rootrefs->rootref[found].dirid = +btrfs_root_ref_dirid (l, rref); + found++; + } + +btrfs_release_path (path); + key.offset++; + }
Suggest to use btrfs_search_slot and btrfs_next_item to reduce counts of btrfs_search_slot.
Quoted 64 lines
fs/btrfs/ioctl.c +20
-0+ +out: +if (!ret || ret == -EOVERFLOW ) { + rootrefs->num_items = found; +/* update min_id for next search */ +if (found) + rootrefs->min_id = + rootrefs->rootref[found -1 ].subvolid +1 ; +if (copy_to_user (argp, rootrefs,sizeof (*rootrefs))) + ret = -EFAULT ; + } + +btrfs_free_path (path); +kfree (rootrefs); + +return ret; +} + static noinline int btrfs_ioctl_snap_destroy(struct file *file,void __user *arg) {@@ -5503,6 +5603,8 @@ long btrfs_ioctl(struct file *file, unsigned intreturn btrfs_ioctl_set_features (file, argp);case BTRFS_IOC_GET_SUBVOL_INFO :return btrfs_ioctl_get_subvol_info (file, argp); +case BTRFS_IOC_GET_SUBVOL_ROOTREF : +return btrfs_ioctl_get_subvol_rootref (file, argp); }return -ENOTTY ;include/uapi/linux/btrfs.h +14
-0@@ -774,6 +774,20 @@ struct btrfs_ioctl_get_subvol_info_args {__u64 reserved[8 ]; }; +#define BTRFS_MAX_ROOTREF_BUFFER_NUM 255 struct +btrfs_ioctl_get_subvol_rootref_args { +/* in/out, min id of rootref's subvolid to be searched */ +__u64 min_id; +/* out */ +struct { +__u64 subvolid; +__u64 dirid; + } rootref[BTRFS_MAX_ROOTREF_BUFFER_NUM ]; +/* out, number of found items */ +__u8 num_items; +__u8 align[7 ]; +}; + /* Error codes as returned by the kernel */ enum btrfs_err_code { BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1, @@ -894,5 +908,7 @@ enum btrfs_err_code { struct btrfs_ioctl_logical_ino_args) #define BTRFS_IOC_GET_SUBVOL_INFO_IOR(BTRFS_IOCTL_MAGIC, 60, \
include/uapi/linux/btrfs.h +2
-1struct btrfs_ioctl_get_subvol_info_args) +#define BTRFS_IOC_GET_SUBVOL_ROOTREF _IOWR(BTRFS_IOCTL_MAGIC, 61, \ + struct btrfs_ioctl_get_subvol_rootref_args)#endif /* _UAPI_LINUX_BTRFS_H */ --2.14.3
Quoted 5 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
�翳簕.n�+壏煯壄�+%娝�遍荻w�簕.n�+壏{饼籯~镶炟^n噐■�侂h櫒璀�&{鄗夸z罐楘+€�+zf"穐殘啳嗃i��飦�戧鐉_璁鎗:+v墾�)撸鴐
PATCH v4 3/3 btrfs: Add unprivileged version of ino_lookup ioctl
In reply to Tomohiro MisonoAdd unprivileged version of ino_lookup ioctl BTRFS_IOC_INO_LOOKUP_USER to allow normal users to call "btrfs subvololume list/show" etc. in combination with BTRFS_IOC_GET_SUBVOL_INFO/BTRFS_IOC_GET_SUBVOL_ROOTREF.
This can be used like BTRFS_IOC_INO_LOOKUP but the argument is different. This is because it always searches the fs/file tree correspoinding to the fd with which this ioctl is called and also returns the name of bottom subvolume.
The main differences from original ino_lookup ioctl are:
1. Read + Exec permission will be checked using inode_permission() during path construction. -EACCES will be returned in case of failure.
2. Path construction will be stopped at the inode number which corresponds to the fd with which this ioctl is called. If constructed path does not exist under fd's inode, -EACCES will be returned.
3. The name of bottom subvolume is also searched and filled.
Note that the maximum length of path is shorter 256 (BTRFS_VOL_NAME_MAX+1) bytes than ino_lookup ioctl because of space of subvolume's name.
--- fs/btrfs/ioctl.c | 204 +++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/btrfs.h | 17 ++++ 2 files changed, 221 insertions(+)
fs/btrfs/ioctl.c +204 -0
@@ -2200,6 +2200,166 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,return ret; } +static noinline int btrfs_search_path_in_tree_user(struct inode *inode, +struct btrfs_ioctl_ino_lookup_user_args *args) +{ +struct btrfs_fs_info *fs_info =BTRFS_I (inode)->root->fs_info; +struct super_block *sb = inode->i_sb; +struct btrfs_key upper_limit =BTRFS_I (inode)->location; +u64 treeid =BTRFS_I (inode)->root->root_key.objectid; +u64 dirid = args->dirid; + +unsigned long item_off; +unsigned long item_len; +struct btrfs_inode_ref *iref; +struct btrfs_root_ref *rref; +struct btrfs_root *root; +struct btrfs_path *path; +struct btrfs_key key, key2; +struct extent_buffer *l; +struct inode *temp_inode; +char *ptr; +int slot; +int len; +int total_len =0 ; +int ret =-1 ; + + path =btrfs_alloc_path (); +if (!path) +return -ENOMEM ; + +/* +* If the bottom subvolume does not exist directly under upper_limit, +* construct the path in bottomup way. +*/ +if (dirid != upper_limit.objectid) { + ptr = &args->path[BTRFS_INO_LOOKUP_USER_PATH_MAX -1 ]; + + key.objectid = treeid; + key.type =BTRFS_ROOT_ITEM_KEY ; + key.offset = (u64)-1 ; + root =btrfs_read_fs_root_no_name (fs_info, &key); +if (IS_ERR (root)) { + ret = -ENOENT ; + goto out; + } + + key.objectid = dirid; + key.type =BTRFS_INODE_REF_KEY ; + key.offset = (u64)-1 ; +while (1 ) { + ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); +if (ret <0 ) { + goto out; + }else if (ret >0 ) { + ret =btrfs_previous_item (root, path, dirid, +BTRFS_INODE_REF_KEY ); +if (ret <0 ) { + goto out; + }else if (ret >0 ) { + ret = -ENOENT ; + goto out; + } + } + + l = path->nodes[0 ]; + slot = path->slots[0 ]; +btrfs_item_key_to_cpu (l, &key, slot); + + iref = btrfs_item_ptr(l, slot, struct btrfs_inode_ref); + len =btrfs_inode_ref_name_len (l, iref); + ptr -= len +1 ; + total_len += len +1 ; +if (ptr < args->path) { + ret = -ENAMETOOLONG ; + goto out; + } + + *(ptr + len) ='/' ; +read_extent_buffer (l, ptr, + (unsigned long )(iref +1 ), len); + +/* Check the read+exec permission of this directory */ + ret =btrfs_previous_item (root, path, dirid, +BTRFS_INODE_ITEM_KEY ); +if (ret <0 ) { + goto out; + }else if (ret >0 ) { + ret = -ENOENT ; + goto out; + } + + l = path->nodes[0 ]; + slot = path->slots[0 ]; +btrfs_item_key_to_cpu (l, &key2, slot); +if (key2.objectid != dirid) { + ret = -ENOENT ; + goto out; + } + + temp_inode =btrfs_iget (sb, &key2, root,NULL ); + ret =inode_permission (temp_inode,MAY_READ |MAY_EXEC ); +iput (temp_inode); +if (ret) { + ret = -EACCES ; + goto out; + } + +if (key.offset == upper_limit.objectid) +break ; +if (key.objectid ==BTRFS_FIRST_FREE_OBJECTID ) { + ret = -EACCES ; + goto out; + } + +btrfs_release_path (path); + key.objectid = key.offset; + key.offset = (u64)-1 ; + dirid = key.objectid; + } + +memmove (args->path, ptr, total_len); + args->path[total_len] ='\0' ; +btrfs_release_path (path); + } + +/* get the bottom subolume's name from ROOT_REF */ + root = fs_info->tree_root; + key.objectid = treeid; + key.type =BTRFS_ROOT_REF_KEY ; + key.offset = args->subvolid; + ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); +if (ret <0 ) { + goto out; + }else if (ret >0 ) { + ret = -ENOENT ; + goto out; + } + + l = path->nodes[0 ]; + slot = path->slots[0 ]; +btrfs_item_key_to_cpu (l, &key, slot); + + item_off =btrfs_item_ptr_offset (l, slot); + item_len =btrfs_item_size_nr (l, slot); +/* check if dirid in ROOT_REF corresponds to passed dirid */ + rref = btrfs_item_ptr(l, slot, struct btrfs_root_ref); +if (args->dirid !=btrfs_root_ref_dirid (l, rref)) { + ret = -EINVAL ; + goto out; + } + +/* copy subvolume's name */ + item_off +=sizeof (struct btrfs_root_ref ); + item_len -=sizeof (struct btrfs_root_ref ); +read_extent_buffer (l, args->name, item_off, item_len); + args->name[item_len] ='\0' ; + +out: +btrfs_free_path (path); +return ret; +} + static noinline int btrfs_ioctl_ino_lookup(struct file *file,void __user *argp) {
@@ -2242,6 +2402,48 @@ static noinline int btrfs_ioctl_ino_lookup(struct file *file,return ret; } +/* +* User version of ino_lookup ioctl (unprivileged) +* +* The main differences from original ino_lookup ioctl are: +* 1. Read + Exec permission will be checked using inode_permission() +* during path construction. -EACCES will be returned in case +* of failure. +* 2. Path construction will be stopped at the inode number which +* corresponds to the fd with which this ioctl is called. If +* constructed path does not exist under fd's inode, -EACCES +* will be returned. +* 3. The name of bottom subvolume is also searched and filled. +*/ +static noinline int btrfs_ioctl_ino_lookup_user(struct file *file, +void __user *argp) +{ +struct btrfs_ioctl_ino_lookup_user_args *args; +struct inode *inode; +int ret =0 ; + + args =memdup_user (argp,sizeof (*args)); +if (IS_ERR (args)) +return PTR_ERR (args); + + inode =file_inode (file); + +if (args->dirid ==BTRFS_FIRST_FREE_OBJECTID && +BTRFS_I (inode)->location.objectid !=BTRFS_FIRST_FREE_OBJECTID ) { +/* The subvolume does not exist under fd with which this is called */ +kfree (args); +return -EACCES ; + } + + ret =btrfs_search_path_in_tree_user (inode, args); + +if (ret ==0 &©_to_user (argp, args,sizeof (*args))) + ret = -EFAULT ; + +kfree (args); +return ret; +} +/* Get the subvolume information in BTRFS_ROOT_ITEM and BTRFS_ROOT_BACKREF */ static noinline int btrfs_ioctl_get_subvol_info(struct file *file,void __user *argp)
@@ -5605,6 +5807,8 @@ long btrfs_ioctl(struct file *file, unsigned intreturn btrfs_ioctl_get_subvol_info (file, argp);case BTRFS_IOC_GET_SUBVOL_ROOTREF :return btrfs_ioctl_get_subvol_rootref (file, argp); +case BTRFS_IOC_INO_LOOKUP_USER : +return btrfs_ioctl_ino_lookup_user (file, argp); }return -ENOTTY ;
include/uapi/linux/btrfs.h +17 -0
@@ -422,6 +422,21 @@ struct btrfs_ioctl_ino_lookup_args {char name[BTRFS_INO_LOOKUP_PATH_MAX ]; }; +#define BTRFS_INO_LOOKUP_USER_PATH_MAX (4080-BTRFS_VOL_NAME_MAX-1) +struct btrfs_ioctl_ino_lookup_user_args { +/* in, inode number containing the subvolume of 'subvolid' */ +__u64 dirid; +/* in */ +__u64 subvolid; +/* out, name of the subvolume of 'subvolid' */ +char name[BTRFS_VOL_NAME_MAX +1 ]; +/* +* out, constructed path from the directory with which +* the ioctl is called to dirid +*/ +char path[BTRFS_INO_LOOKUP_USER_PATH_MAX ]; +}; +/* Search criteria for the btrfs SEARCH ioctl family. */ struct btrfs_ioctl_search_key {/*
@@ -910,5 +925,7 @@ enum btrfs_err_code { struct btrfs_ioctl_get_subvol_info_args)#define BTRFS_IOC_GET_SUBVOL_ROOTREF _IOWR(BTRFS_IOCTL_MAGIC, 61, \ struct btrfs_ioctl_get_subvol_rootref_args) +#define BTRFS_IOC_INO_LOOKUP_USER _IOWR(BTRFS_IOCTL_MAGIC, 62, \ + struct btrfs_ioctl_ino_lookup_user_args)#endif /* _UAPI_LINUX_BTRFS_H */
Signature · 1 line
2.14.3
RE: [PATCH v4 3/3] btrfs: Add unprivileged version of ino_lookup ioctl
Hi
Quoted 7 lines
-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Tomohiro Misono
Sent: Friday, May 11, 2018 3:26 PM
To: [email protected]
Subject: [PATCH v4 3/3] btrfs: Add unprivileged version ofino_lookupioctlAdd unprivileged version of
ino_lookupioctlBTRFS_IOC_INO_LOOKUP_USERto allow normal users to call "btrfs subvololume list/show"
s/subvololume/subvolume
Quoted 276 lines
etc. in combination with BTRFS_IOC_GET_SUBVOL_INFO/BTRFS_IOC_GET_SUBVOL_ROOTREF.
This can be used like
BTRFS_IOC_INO_LOOKUPbut the argument is different. This is because it always searches the fs/file tree correspoinding to the fd with which this ioctl is called and also returns the name of bottom subvolume.The main differences from original
ino_lookupioctl are:
1. Read + Exec permission will be checked usinginode_permission()during path construction.-EACCESwill be returned in case of failure.
2. Path construction will be stopped at the inode number which corresponds to the fd with which this ioctl is called. If constructed path does not exist under fd's inode,-EACCESwill be returned.
3. The name of bottom subvolume is also searched and filled.Note that the maximum length of path is shorter 256 (BTRFS_VOL_NAME_MAX+1) bytes than
ino_lookupioctl because of space of subvolume's name.Signed-off-by Tomohiro Misono <[email protected]>--- fs/btrfs/ioctl.c | 204 +++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/btrfs.h | 17 ++++ 2 files changed, 221 insertions(+)fs/btrfs/ioctl.c +203
-0@@ -2200,6 +2200,166 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,return ret; } +static noinline int btrfs_search_path_in_tree_user(struct inode *inode, +struct btrfs_ioctl_ino_lookup_user_args *args) { +struct btrfs_fs_info *fs_info =BTRFS_I (inode)->root->fs_info; +struct super_block *sb = inode->i_sb; +struct btrfs_key upper_limit =BTRFS_I (inode)->location; +u64 treeid =BTRFS_I (inode)->root->root_key.objectid; +u64 dirid = args->dirid; + +unsigned long item_off; +unsigned long item_len; +struct btrfs_inode_ref *iref; +struct btrfs_root_ref *rref; +struct btrfs_root *root; +struct btrfs_path *path; +struct btrfs_key key, key2; +struct extent_buffer *l; +struct inode *temp_inode; +char *ptr; +int slot; +int len; +int total_len =0 ; +int ret =-1 ; + + path =btrfs_alloc_path (); +if (!path) +return -ENOMEM ; + +/* +* If the bottom subvolume does not exist directly under upper_limit, +* construct the path in bottomup way. +*/ +if (dirid != upper_limit.objectid) { + ptr = &args->path[BTRFS_INO_LOOKUP_USER_PATH_MAX -1 ]; + + key.objectid = treeid; + key.type =BTRFS_ROOT_ITEM_KEY ; + key.offset = (u64)-1 ; + root =btrfs_read_fs_root_no_name (fs_info, &key); +if (IS_ERR (root)) { + ret = -ENOENT ; + goto out; + } + + key.objectid = dirid; + key.type =BTRFS_INODE_REF_KEY ; + key.offset = (u64)-1 ; +while (1 ) { + ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); +if (ret <0 ) { + goto out; + }else if (ret >0 ) { + ret =btrfs_previous_item (root, path, dirid, +BTRFS_INODE_REF_KEY ); +if (ret <0 ) { + goto out; + }else if (ret >0 ) { + ret = -ENOENT ; + goto out; + } + } + + l = path->nodes[0 ]; + slot = path->slots[0 ]; +btrfs_item_key_to_cpu (l, &key, slot); + + iref = btrfs_item_ptr(l, slot, struct btrfs_inode_ref); + len =btrfs_inode_ref_name_len (l, iref); + ptr -= len +1 ; + total_len += len +1 ; +if (ptr < args->path) { + ret = -ENAMETOOLONG ; + goto out; + } + + *(ptr + len) ='/' ; +read_extent_buffer (l, ptr, + (unsigned long )(iref +1 ), len); + +/* Check the read+exec permission of this directory */ + ret =btrfs_previous_item (root, path, dirid, +BTRFS_INODE_ITEM_KEY ); +if (ret <0 ) { + goto out; + }else if (ret >0 ) { + ret = -ENOENT ; + goto out; + } + + l = path->nodes[0 ]; + slot = path->slots[0 ]; +btrfs_item_key_to_cpu (l, &key2, slot); +if (key2.objectid != dirid) { + ret = -ENOENT ; + goto out; + } + + temp_inode =btrfs_iget (sb, &key2, root,NULL ); + ret =inode_permission (temp_inode,MAY_READ |MAY_EXEC ); +iput (temp_inode); +if (ret) { + ret = -EACCES ; + goto out; + } + +if (key.offset == upper_limit.objectid) +break ; +if (key.objectid ==BTRFS_FIRST_FREE_OBJECTID ) { + ret = -EACCES ; + goto out; + } + +btrfs_release_path (path); + key.objectid = key.offset; + key.offset = (u64)-1 ; + dirid = key.objectid; + } + +memmove (args->path, ptr, total_len); + args->path[total_len] ='\0' ; +btrfs_release_path (path); + } + +/* get the bottom subolume's name from ROOT_REF */ + root = fs_info->tree_root; + key.objectid = treeid; + key.type =BTRFS_ROOT_REF_KEY ; + key.offset = args->subvolid; + ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); +if (ret <0 ) { + goto out; + }else if (ret >0 ) { + ret = -ENOENT ; + goto out; + } + + l = path->nodes[0 ]; + slot = path->slots[0 ]; +btrfs_item_key_to_cpu (l, &key, slot); + + item_off =btrfs_item_ptr_offset (l, slot); + item_len =btrfs_item_size_nr (l, slot); +/* check if dirid in ROOT_REF corresponds to passed dirid */ + rref = btrfs_item_ptr(l, slot, struct btrfs_root_ref); +if (args->dirid !=btrfs_root_ref_dirid (l, rref)) { + ret = -EINVAL ; + goto out; + } + +/* copy subvolume's name */ + item_off +=sizeof (struct btrfs_root_ref ); + item_len -=sizeof (struct btrfs_root_ref ); +read_extent_buffer (l, args->name, item_off, item_len); + args->name[item_len] ='\0' ; + +out: +btrfs_free_path (path); +return ret; +} + static noinline int btrfs_ioctl_ino_lookup(struct file *file,void __user *argp) {@@ -2242,6 +2402,48 @@ static noinline int btrfs_ioctl_ino_lookup(struct file *file,return ret; } +/* +* User version of ino_lookup ioctl (unprivileged) +* +* The main differences from original ino_lookup ioctl are: +* 1. Read + Exec permission will be checked using inode_permission() +* during path construction. -EACCES will be returned in case +* of failure. +* 2. Path construction will be stopped at the inode number which +* corresponds to the fd with which this ioctl is called. If +* constructed path does not exist under fd's inode, -EACCES +* will be returned. +* 3. The name of bottom subvolume is also searched and filled. +*/ +static noinline int btrfs_ioctl_ino_lookup_user(struct file *file, +void __user *argp) +{ +struct btrfs_ioctl_ino_lookup_user_args *args; +struct inode *inode; +int ret =0 ; + + args =memdup_user (argp,sizeof (*args)); +if (IS_ERR (args)) +return PTR_ERR (args); + + inode =file_inode (file); + +if (args->dirid ==BTRFS_FIRST_FREE_OBJECTID && +BTRFS_I (inode)->location.objectid !=BTRFS_FIRST_FREE_OBJECTID ) { +/* The subvolume does not exist under fd with which this is called */ +kfree (args); +return -EACCES ; + } + + ret =btrfs_search_path_in_tree_user (inode, args); + +if (ret ==0 &©_to_user (argp, args,sizeof (*args))) + ret = -EFAULT ; + +kfree (args); +return ret; +} + /* Get the subvolume information in BTRFS_ROOT_ITEM and BTRFS_ROOT_BACKREF */ static noinline intbtrfs_ioctl_get_subvol_info (struct file *file,void __user *argp)@@ -5605,6 +5807,8 @@ long btrfs_ioctl(struct file *file, unsigned intreturn btrfs_ioctl_get_subvol_info (file, argp);case BTRFS_IOC_GET_SUBVOL_ROOTREF :return btrfs_ioctl_get_subvol_rootref (file, argp); +case BTRFS_IOC_INO_LOOKUP_USER : +return btrfs_ioctl_ino_lookup_user (file, argp); }return -ENOTTY ;include/uapi/linux/btrfs.h +15
-0@@ -422,6 +422,21 @@ struct btrfs_ioctl_ino_lookup_args {char name[BTRFS_INO_LOOKUP_PATH_MAX ]; }; +#define BTRFS_INO_LOOKUP_USER_PATH_MAX (4080-BTRFS_VOL_NAME_MAX-1) +struct btrfs_ioctl_ino_lookup_user_args { +/* in, inode number containing the subvolume of 'subvolid' */ +__u64 dirid; +/* in */ +__u64 subvolid; +/* out, name of the subvolume of 'subvolid' */ +char name[BTRFS_VOL_NAME_MAX +1 ]; +/* +* out, constructed path from the directory with which +* the ioctl is called to dirid +*/ +char path[BTRFS_INO_LOOKUP_USER_PATH_MAX ]; +}; +/* Search criteria for the btrfs SEARCH ioctl family. */ struct btrfs_ioctl_search_key {/*
include/uapi/linux/btrfs.h enum btrfs_err_code {
Quoted 8 lines
include/uapi/linux/btrfs.h +2
-1@@ -910,5 +925,7 @@ enum btrfs_err_code { struct btrfs_ioctl_get_subvol_info_args) #define BTRFS_IOC_GET_SUBVOL_ROOTREF_IOWR (BTRFS_IOCTL_MAGIC ,61 , \ struct btrfs_ioctl_get_subvol_rootref_args) +#define BTRFS_IOC_INO_LOOKUP_USER _IOWR(BTRFS_IOCTL_MAGIC, 62, \ + struct btrfs_ioctl_ino_lookup_user_args)#endif /* _UAPI_LINUX_BTRFS_H */ --
Seems good to me.
Quoted 8 lines
2.14.3
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
�翳簕.n�+壏煯壄�+%娝�遍荻w�簕.n�+壏{饼籯~镶炟^n噐■�侂h櫒璀�&{鄗夸z罐楘+€�+zf"穐殘啳嗃i��飦�戧鐉_璁鎗:+v墾�)撸鴐