* [PATCH v2 0/3] btrfs: Add three new unprivileged ioctls to allow normal users to call "sub list/show" etc.
@ 2018-03-15 8:09 Misono, Tomohiro
2018-03-15 8:10 ` [PATCH v2 1/3] btrfs: Add unprivileged ioctl which returns subvolume information Misono, Tomohiro
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Misono, Tomohiro @ 2018-03-15 8:09 UTC (permalink / raw)
To: linux-btrfs
changelog:
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 peforms permission check.
They will be used to implement user version of "subvolume list/show" etc in user tools.
See each commit log for more details.
The rfc implementation of btrfs-progs can be found in the ML titled as follows:
[RFC PATCH v2 0/8] btrfs-progs: Allow normal user to call "subvolume list/show"
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 | 413 +++++++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/btrfs.h | 84 ++++++++++
2 files changed, 497 insertions(+)
--
2.14.3
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/3] btrfs: Add unprivileged ioctl which returns subvolume information
2018-03-15 8:09 [PATCH v2 0/3] btrfs: Add three new unprivileged ioctls to allow normal users to call "sub list/show" etc Misono, Tomohiro
@ 2018-03-15 8:10 ` Misono, Tomohiro
2018-03-18 4:16 ` kbuild test robot
2018-03-15 8:11 ` [PATCH v2 2/3] btrfs: Add unprivileged ioctl which returns subvolume's ROOT_REF Misono, Tomohiro
2018-03-15 8:11 ` [PATCH v2 3/3] btrfs: Add unprivileged version of ino_lookup ioctl Misono, Tomohiro
2 siblings, 1 reply; 7+ messages in thread
From: Misono, Tomohiro @ 2018-03-15 8:10 UTC (permalink / raw)
To: linux-btrfs
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.)
Signed-off-by: Tomohiro Misono <misono.tomohiro@jp.fujitsu.com>
---
fs/btrfs/ioctl.c | 118 +++++++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/btrfs.h | 51 ++++++++++++++++++++
2 files changed, 169 insertions(+)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 111ee282b777..852421ac81cd 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2309,6 +2309,122 @@ 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 __user *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) {
+ /* If the subvolume is a snapshot, offset is not zero */
+ u64 objectid = key.objectid;
+
+ 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;
+
+ 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)
{
@@ -5663,6 +5779,8 @@ long btrfs_ioctl(struct file *file, unsigned int
return 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;
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
index c8d99b9ca550..ed053852c71f 100644
--- a/include/uapi/linux/btrfs.h
+++ b/include/uapi/linux/btrfs.h
@@ -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, \
struct 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 */
--
2.14.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 2/3] btrfs: Add unprivileged ioctl which returns subvolume's ROOT_REF
2018-03-15 8:09 [PATCH v2 0/3] btrfs: Add three new unprivileged ioctls to allow normal users to call "sub list/show" etc Misono, Tomohiro
2018-03-15 8:10 ` [PATCH v2 1/3] btrfs: Add unprivileged ioctl which returns subvolume information Misono, Tomohiro
@ 2018-03-15 8:11 ` Misono, Tomohiro
2018-03-18 4:46 ` kbuild test robot
2018-03-15 8:11 ` [PATCH v2 3/3] btrfs: Add unprivileged version of ino_lookup ioctl Misono, Tomohiro
2 siblings, 1 reply; 7+ messages in thread
From: Misono, Tomohiro @ 2018-03-15 8:11 UTC (permalink / raw)
To: linux-btrfs
Add unprivileged ioctl BTRFS_IOC_GET_SUBVOL_ROOTREF which
returns ROOT_REF information of the subvolume containing this inode.
The min id of root ref's subvolume to be searched is specified by
min_id in struct btrfs_ioctl_get_subvol_rootref_args.
If there are more root refs than BTRFS_MAX_ROOTREF_BUFFER_NUM,
this ioctl sets min_id to the last searched root ref's subvolid + 1
and return -EOVERFLOW. Therefore the caller can just call this ioctl
again without changing the argument to continue search.
Signed-off-by: Tomohiro Misono <misono.tomohiro@jp.fujitsu.com>
---
fs/btrfs/ioctl.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/btrfs.h | 16 ++++++++
2 files changed, 107 insertions(+)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 852421ac81cd..816a3eb60020 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2425,6 +2425,95 @@ static noinline int btrfs_ioctl_get_subvol_info(struct file *file,
return ret;
}
+/* Returns ROOT_REF information of the subvolume contining this inode. */
+static noinline int btrfs_ioctl_get_subvol_rootref(struct file *file,
+ void __user *argp)
+{
+ struct btrfs_ioctl_get_subvol_rootref_args __user *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;
+
+ 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) {
+ /* update min_id for next search */
+ rootrefs->min_id = key.offset;
+ 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;
+ 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)
{
@@ -5781,6 +5870,8 @@ long btrfs_ioctl(struct file *file, unsigned int
return 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;
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
index ed053852c71f..82c88d52d6e6 100644
--- a/include/uapi/linux/btrfs.h
+++ b/include/uapi/linux/btrfs.h
@@ -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 */
--
2.14.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 3/3] btrfs: Add unprivileged version of ino_lookup ioctl
2018-03-15 8:09 [PATCH v2 0/3] btrfs: Add three new unprivileged ioctls to allow normal users to call "sub list/show" etc Misono, Tomohiro
2018-03-15 8:10 ` [PATCH v2 1/3] btrfs: Add unprivileged ioctl which returns subvolume information Misono, Tomohiro
2018-03-15 8:11 ` [PATCH v2 2/3] btrfs: Add unprivileged ioctl which returns subvolume's ROOT_REF Misono, Tomohiro
@ 2018-03-15 8:11 ` Misono, Tomohiro
2018-03-18 5:11 ` kbuild test robot
2 siblings, 1 reply; 7+ messages in thread
From: Misono, Tomohiro @ 2018-03-15 8:11 UTC (permalink / raw)
To: linux-btrfs
Add 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.
Signed-off-by: Tomohiro Misono <misono.tomohiro@jp.fujitsu.com>
---
fs/btrfs/ioctl.c | 204 +++++++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/btrfs.h | 17 ++++
2 files changed, 221 insertions(+)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 816a3eb60020..87534e1855f2 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2267,6 +2267,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 */
+ read_extent_buffer(l, &rref, item_off, sizeof(struct btrfs_root_ref));
+ if (rref.dirid != args->dirid) {
+ 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)
{
@@ -2309,6 +2469,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 && copy_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)
@@ -5872,6 +6074,8 @@ long btrfs_ioctl(struct file *file, unsigned int
return 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;
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
index 82c88d52d6e6..5f91de93dd5a 100644
--- a/include/uapi/linux/btrfs.h
+++ b/include/uapi/linux/btrfs.h
@@ -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 */
--
2.14.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/3] btrfs: Add unprivileged ioctl which returns subvolume information
2018-03-15 8:10 ` [PATCH v2 1/3] btrfs: Add unprivileged ioctl which returns subvolume information Misono, Tomohiro
@ 2018-03-18 4:16 ` kbuild test robot
0 siblings, 0 replies; 7+ messages in thread
From: kbuild test robot @ 2018-03-18 4:16 UTC (permalink / raw)
To: Misono, Tomohiro; +Cc: kbuild-all, linux-btrfs
Hi Tomohiro,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on linus/master]
[also build test WARNING on v4.16-rc5 next-20180316]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Misono-Tomohiro/btrfs-Add-three-new-unprivileged-ioctls-to-allow-normal-users-to-call-sub-list-show-etc/20180318-101013
reproduce:
# apt-get install sparse
make ARCH=x86_64 allmodconfig
make C=1 CF=-D__CHECK_ENDIAN__
sparse warnings: (new ones prefixed by >>)
fs/btrfs/ioctl.c:1561:9: sparse: incompatible types in comparison expression (different address spaces)
>> fs/btrfs/ioctl.c:2336:21: sparse: incorrect type in assignment (different address spaces) @@ expected struct btrfs_ioctl_get_subvol_info_args [noderef] <asn:1>*subvol_info @@ got sn:1>*subvol_info @@
fs/btrfs/ioctl.c:2336:21: expected struct btrfs_ioctl_get_subvol_info_args [noderef] <asn:1>*subvol_info
fs/btrfs/ioctl.c:2336:21: got void *
>> fs/btrfs/ioctl.c:2373:9: sparse: incorrect type in argument 1 (different address spaces) @@ expected void *to @@ got unsigned char [noderef] <avoid *to @@
fs/btrfs/ioctl.c:2373:9: expected void *to
fs/btrfs/ioctl.c:2373:9: got unsigned char [noderef] <asn:1>*<noident>
fs/btrfs/ioctl.c:2374:9: sparse: incorrect type in argument 1 (different address spaces) @@ expected void *to @@ got unsigned char [noderef] <avoid *to @@
fs/btrfs/ioctl.c:2374:9: expected void *to
fs/btrfs/ioctl.c:2374:9: got unsigned char [noderef] <asn:1>*<noident>
fs/btrfs/ioctl.c:2376:9: sparse: incorrect type in argument 1 (different address spaces) @@ expected void *to @@ got unsigned char [noderef] <avoid *to @@
fs/btrfs/ioctl.c:2376:9: expected void *to
fs/btrfs/ioctl.c:2376:9: got unsigned char [noderef] <asn:1>*<noident>
>> fs/btrfs/ioctl.c:2416:39: sparse: incorrect type in argument 2 (different address spaces) @@ expected void *dst @@ got char [noderef] <avoid *dst @@
fs/btrfs/ioctl.c:2416:39: expected void *dst
fs/btrfs/ioctl.c:2416:39: got char [noderef] <asn:1>*<noident>
>> fs/btrfs/ioctl.c:2419:32: sparse: incorrect type in argument 2 (different address spaces) @@ expected void const *from @@ got struct btrfs_ioctl_get_subvol_info_args [nodervoid const *from @@
fs/btrfs/ioctl.c:2419:32: expected void const *from
fs/btrfs/ioctl.c:2419:32: got struct btrfs_ioctl_get_subvol_info_args [noderef] <asn:1>*subvol_info
>> fs/btrfs/ioctl.c:2423:16: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *<noident> @@ got struct btrfs_ioctl_get_subvol_info_args [nodervoid const *<noident> @@
fs/btrfs/ioctl.c:2423:16: expected void const *<noident>
fs/btrfs/ioctl.c:2423:16: got struct btrfs_ioctl_get_subvol_info_args [noderef] <asn:1>*subvol_info
fs/btrfs/ioctl.c:2917:24: sparse: incompatible types in comparison expression (different address spaces)
>> fs/btrfs/ioctl.c:2368:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2370:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2371:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2379:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2380:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2381:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2383:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2384:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2385:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2387:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2388:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2389:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2391:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2392:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2393:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2405:29: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2407:17: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2410:17: sparse: dereference of noderef expression
vim +2336 fs/btrfs/ioctl.c
2311
2312 /* Get the subvolume information in BTRFS_ROOT_ITEM and BTRFS_ROOT_BACKREF */
2313 static noinline int btrfs_ioctl_get_subvol_info(struct file *file,
2314 void __user *argp)
2315 {
2316 struct btrfs_ioctl_get_subvol_info_args __user *subvol_info;
2317 struct btrfs_root *root;
2318 struct btrfs_path *path;
2319 struct btrfs_key key;
2320
2321 struct btrfs_root_item root_item;
2322 struct btrfs_root_ref *rref;
2323 struct extent_buffer *l;
2324 int slot;
2325
2326 unsigned long item_off;
2327 unsigned long item_len;
2328
2329 struct inode *inode;
2330 int ret;
2331
2332 path = btrfs_alloc_path();
2333 if (!path)
2334 return -ENOMEM;
2335
> 2336 subvol_info = kzalloc(sizeof(*subvol_info), GFP_KERNEL);
2337 if (!subvol_info) {
2338 btrfs_free_path(path);
2339 return -ENOMEM;
2340 }
2341 inode = file_inode(file);
2342
2343 root = BTRFS_I(inode)->root->fs_info->tree_root;
2344 key.objectid = BTRFS_I(inode)->root->root_key.objectid;
2345 key.type = BTRFS_ROOT_ITEM_KEY;
2346 key.offset = 0;
2347 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
2348 if (ret < 0) {
2349 goto out;
2350 } else if (ret > 0) {
2351 /* If the subvolume is a snapshot, offset is not zero */
2352 u64 objectid = key.objectid;
2353
2354 btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
2355 if (key.objectid != objectid ||
2356 key.type != BTRFS_ROOT_ITEM_KEY) {
2357 ret = -ENOENT;
2358 goto out;
2359 }
2360 }
2361
2362 l = path->nodes[0];
2363 slot = path->slots[0];
2364 item_off = btrfs_item_ptr_offset(l, slot);
2365 item_len = btrfs_item_size_nr(l, slot);
2366 read_extent_buffer(l, &root_item, item_off, item_len);
2367
> 2368 subvol_info->id = key.objectid;
2369
2370 subvol_info->generation = btrfs_root_generation(&root_item);
2371 subvol_info->flags = btrfs_root_flags(&root_item);
2372
> 2373 memcpy(subvol_info->uuid, root_item.uuid, BTRFS_UUID_SIZE);
> 2374 memcpy(subvol_info->parent_uuid, root_item.parent_uuid,
2375 BTRFS_UUID_SIZE);
> 2376 memcpy(subvol_info->received_uuid, root_item.received_uuid,
2377 BTRFS_UUID_SIZE);
2378
2379 subvol_info->ctransid = btrfs_root_ctransid(&root_item);
2380 subvol_info->ctime.sec = btrfs_stack_timespec_sec(&root_item.ctime);
2381 subvol_info->ctime.nsec = btrfs_stack_timespec_nsec(&root_item.ctime);
2382
2383 subvol_info->otransid = btrfs_root_otransid(&root_item);
2384 subvol_info->otime.sec = btrfs_stack_timespec_sec(&root_item.otime);
2385 subvol_info->otime.nsec = btrfs_stack_timespec_nsec(&root_item.otime);
2386
2387 subvol_info->stransid = btrfs_root_stransid(&root_item);
2388 subvol_info->stime.sec = btrfs_stack_timespec_sec(&root_item.stime);
2389 subvol_info->stime.nsec = btrfs_stack_timespec_nsec(&root_item.stime);
2390
2391 subvol_info->rtransid = btrfs_root_rtransid(&root_item);
2392 subvol_info->rtime.sec = btrfs_stack_timespec_sec(&root_item.rtime);
2393 subvol_info->rtime.nsec = btrfs_stack_timespec_nsec(&root_item.rtime);
2394
2395 btrfs_release_path(path);
2396 key.type = BTRFS_ROOT_BACKREF_KEY;
2397 key.offset = 0;
2398 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
2399 if (ret < 0)
2400 goto out;
2401
2402 l = path->nodes[0];
2403 slot = path->slots[0];
2404 btrfs_item_key_to_cpu(l, &key, slot);
2405 if (key.objectid == subvol_info->id &&
2406 key.type == BTRFS_ROOT_BACKREF_KEY){
2407 subvol_info->parent_id = key.offset;
2408
2409 rref = btrfs_item_ptr(l, slot, struct btrfs_root_ref);
2410 subvol_info->dirid = btrfs_root_ref_dirid(l, rref);
2411
2412 item_off = btrfs_item_ptr_offset(l, slot)
2413 + sizeof(struct btrfs_root_ref);
2414 item_len = btrfs_item_size_nr(l, slot)
2415 - sizeof(struct btrfs_root_ref);
> 2416 read_extent_buffer(l, subvol_info->name, item_off, item_len);
2417 }
2418
> 2419 if (copy_to_user(argp, subvol_info, sizeof(*subvol_info)))
2420 ret = -EFAULT;
2421
2422 out:
> 2423 kzfree(subvol_info);
2424 btrfs_free_path(path);
2425 return ret;
2426 }
2427
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 2/3] btrfs: Add unprivileged ioctl which returns subvolume's ROOT_REF
2018-03-15 8:11 ` [PATCH v2 2/3] btrfs: Add unprivileged ioctl which returns subvolume's ROOT_REF Misono, Tomohiro
@ 2018-03-18 4:46 ` kbuild test robot
0 siblings, 0 replies; 7+ messages in thread
From: kbuild test robot @ 2018-03-18 4:46 UTC (permalink / raw)
To: Misono, Tomohiro; +Cc: kbuild-all, linux-btrfs
Hi Tomohiro,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on linus/master]
[also build test WARNING on v4.16-rc5 next-20180316]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Misono-Tomohiro/btrfs-Add-three-new-unprivileged-ioctls-to-allow-normal-users-to-call-sub-list-show-etc/20180318-101013
reproduce:
# apt-get install sparse
make ARCH=x86_64 allmodconfig
make C=1 CF=-D__CHECK_ENDIAN__
sparse warnings: (new ones prefixed by >>)
fs/btrfs/ioctl.c:1561:9: sparse: incompatible types in comparison expression (different address spaces)
fs/btrfs/ioctl.c:2336:21: sparse: incorrect type in assignment (different address spaces) @@ expected struct btrfs_ioctl_get_subvol_info_args [noderef] <asn:1>*subvol_info @@ got sn:1>*subvol_info @@
fs/btrfs/ioctl.c:2336:21: expected struct btrfs_ioctl_get_subvol_info_args [noderef] <asn:1>*subvol_info
fs/btrfs/ioctl.c:2336:21: got void *
fs/btrfs/ioctl.c:2373:9: sparse: incorrect type in argument 1 (different address spaces) @@ expected void *to @@ got unsigned char [noderef] <avoid *to @@
fs/btrfs/ioctl.c:2373:9: expected void *to
fs/btrfs/ioctl.c:2373:9: got unsigned char [noderef] <asn:1>*<noident>
fs/btrfs/ioctl.c:2374:9: sparse: incorrect type in argument 1 (different address spaces) @@ expected void *to @@ got unsigned char [noderef] <avoid *to @@
fs/btrfs/ioctl.c:2374:9: expected void *to
fs/btrfs/ioctl.c:2374:9: got unsigned char [noderef] <asn:1>*<noident>
fs/btrfs/ioctl.c:2376:9: sparse: incorrect type in argument 1 (different address spaces) @@ expected void *to @@ got unsigned char [noderef] <avoid *to @@
fs/btrfs/ioctl.c:2376:9: expected void *to
fs/btrfs/ioctl.c:2376:9: got unsigned char [noderef] <asn:1>*<noident>
fs/btrfs/ioctl.c:2416:39: sparse: incorrect type in argument 2 (different address spaces) @@ expected void *dst @@ got char [noderef] <avoid *dst @@
fs/btrfs/ioctl.c:2416:39: expected void *dst
fs/btrfs/ioctl.c:2416:39: got char [noderef] <asn:1>*<noident>
fs/btrfs/ioctl.c:2419:32: sparse: incorrect type in argument 2 (different address spaces) @@ expected void const *from @@ got struct btrfs_ioctl_get_subvol_info_args [nodervoid const *from @@
fs/btrfs/ioctl.c:2419:32: expected void const *from
fs/btrfs/ioctl.c:2419:32: got struct btrfs_ioctl_get_subvol_info_args [noderef] <asn:1>*subvol_info
fs/btrfs/ioctl.c:2423:16: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *<noident> @@ got struct btrfs_ioctl_get_subvol_info_args [nodervoid const *<noident> @@
fs/btrfs/ioctl.c:2423:16: expected void const *<noident>
fs/btrfs/ioctl.c:2423:16: got struct btrfs_ioctl_get_subvol_info_args [noderef] <asn:1>*subvol_info
>> fs/btrfs/ioctl.c:2451:18: sparse: incorrect type in assignment (different address spaces) @@ expected struct btrfs_ioctl_get_subvol_rootref_args [noderef] <asn:1>*rootrefs @@ got sn:1>*rootrefs @@
fs/btrfs/ioctl.c:2451:18: expected struct btrfs_ioctl_get_subvol_rootref_args [noderef] <asn:1>*rootrefs
fs/btrfs/ioctl.c:2451:18: got void *
>> fs/btrfs/ioctl.c:2507:40: sparse: incorrect type in argument 2 (different address spaces) @@ expected void const *from @@ got struct btrfs_ioctl_get_subvol_rootref_args [nodervoid const *from @@
fs/btrfs/ioctl.c:2507:40: expected void const *from
fs/btrfs/ioctl.c:2507:40: got struct btrfs_ioctl_get_subvol_rootref_args [noderef] <asn:1>*rootrefs
>> fs/btrfs/ioctl.c:2512:15: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *<noident> @@ got struct btrfs_ioctl_get_subvol_rootref_args [nodervoid const *<noident> @@
fs/btrfs/ioctl.c:2512:15: expected void const *<noident>
fs/btrfs/ioctl.c:2512:15: got struct btrfs_ioctl_get_subvol_rootref_args [noderef] <asn:1>*rootrefs
fs/btrfs/ioctl.c:3006:24: sparse: incompatible types in comparison expression (different address spaces)
fs/btrfs/ioctl.c:2368:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2370:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2371:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2379:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2380:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2381:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2383:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2384:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2385:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2387:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2388:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2389:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2391:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2392:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2393:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2405:29: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2407:17: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2410:17: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2463:22: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2488:33: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2494:42: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2495:42: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2506:17: sparse: dereference of noderef expression
vim +2451 fs/btrfs/ioctl.c
2311
2312 /* Get the subvolume information in BTRFS_ROOT_ITEM and BTRFS_ROOT_BACKREF */
2313 static noinline int btrfs_ioctl_get_subvol_info(struct file *file,
2314 void __user *argp)
2315 {
2316 struct btrfs_ioctl_get_subvol_info_args __user *subvol_info;
2317 struct btrfs_root *root;
2318 struct btrfs_path *path;
2319 struct btrfs_key key;
2320
2321 struct btrfs_root_item root_item;
2322 struct btrfs_root_ref *rref;
2323 struct extent_buffer *l;
2324 int slot;
2325
2326 unsigned long item_off;
2327 unsigned long item_len;
2328
2329 struct inode *inode;
2330 int ret;
2331
2332 path = btrfs_alloc_path();
2333 if (!path)
2334 return -ENOMEM;
2335
2336 subvol_info = kzalloc(sizeof(*subvol_info), GFP_KERNEL);
2337 if (!subvol_info) {
2338 btrfs_free_path(path);
2339 return -ENOMEM;
2340 }
2341 inode = file_inode(file);
2342
2343 root = BTRFS_I(inode)->root->fs_info->tree_root;
2344 key.objectid = BTRFS_I(inode)->root->root_key.objectid;
2345 key.type = BTRFS_ROOT_ITEM_KEY;
2346 key.offset = 0;
2347 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
2348 if (ret < 0) {
2349 goto out;
2350 } else if (ret > 0) {
2351 /* If the subvolume is a snapshot, offset is not zero */
2352 u64 objectid = key.objectid;
2353
2354 btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
2355 if (key.objectid != objectid ||
2356 key.type != BTRFS_ROOT_ITEM_KEY) {
2357 ret = -ENOENT;
2358 goto out;
2359 }
2360 }
2361
2362 l = path->nodes[0];
2363 slot = path->slots[0];
2364 item_off = btrfs_item_ptr_offset(l, slot);
2365 item_len = btrfs_item_size_nr(l, slot);
2366 read_extent_buffer(l, &root_item, item_off, item_len);
2367
2368 subvol_info->id = key.objectid;
2369
2370 subvol_info->generation = btrfs_root_generation(&root_item);
2371 subvol_info->flags = btrfs_root_flags(&root_item);
2372
2373 memcpy(subvol_info->uuid, root_item.uuid, BTRFS_UUID_SIZE);
2374 memcpy(subvol_info->parent_uuid, root_item.parent_uuid,
2375 BTRFS_UUID_SIZE);
2376 memcpy(subvol_info->received_uuid, root_item.received_uuid,
2377 BTRFS_UUID_SIZE);
2378
2379 subvol_info->ctransid = btrfs_root_ctransid(&root_item);
2380 subvol_info->ctime.sec = btrfs_stack_timespec_sec(&root_item.ctime);
2381 subvol_info->ctime.nsec = btrfs_stack_timespec_nsec(&root_item.ctime);
2382
2383 subvol_info->otransid = btrfs_root_otransid(&root_item);
2384 subvol_info->otime.sec = btrfs_stack_timespec_sec(&root_item.otime);
2385 subvol_info->otime.nsec = btrfs_stack_timespec_nsec(&root_item.otime);
2386
2387 subvol_info->stransid = btrfs_root_stransid(&root_item);
2388 subvol_info->stime.sec = btrfs_stack_timespec_sec(&root_item.stime);
2389 subvol_info->stime.nsec = btrfs_stack_timespec_nsec(&root_item.stime);
2390
2391 subvol_info->rtransid = btrfs_root_rtransid(&root_item);
2392 subvol_info->rtime.sec = btrfs_stack_timespec_sec(&root_item.rtime);
2393 subvol_info->rtime.nsec = btrfs_stack_timespec_nsec(&root_item.rtime);
2394
2395 btrfs_release_path(path);
2396 key.type = BTRFS_ROOT_BACKREF_KEY;
2397 key.offset = 0;
2398 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
2399 if (ret < 0)
2400 goto out;
2401
2402 l = path->nodes[0];
2403 slot = path->slots[0];
2404 btrfs_item_key_to_cpu(l, &key, slot);
2405 if (key.objectid == subvol_info->id &&
2406 key.type == BTRFS_ROOT_BACKREF_KEY){
2407 subvol_info->parent_id = key.offset;
2408
2409 rref = btrfs_item_ptr(l, slot, struct btrfs_root_ref);
2410 subvol_info->dirid = btrfs_root_ref_dirid(l, rref);
2411
2412 item_off = btrfs_item_ptr_offset(l, slot)
2413 + sizeof(struct btrfs_root_ref);
2414 item_len = btrfs_item_size_nr(l, slot)
2415 - sizeof(struct btrfs_root_ref);
> 2416 read_extent_buffer(l, subvol_info->name, item_off, item_len);
2417 }
2418
> 2419 if (copy_to_user(argp, subvol_info, sizeof(*subvol_info)))
2420 ret = -EFAULT;
2421
2422 out:
> 2423 kzfree(subvol_info);
2424 btrfs_free_path(path);
2425 return ret;
2426 }
2427
2428 /* Returns ROOT_REF information of the subvolume contining this inode. */
2429 static noinline int btrfs_ioctl_get_subvol_rootref(struct file *file,
2430 void __user *argp)
2431 {
2432 struct btrfs_ioctl_get_subvol_rootref_args __user *rootrefs;
2433 struct btrfs_root_ref *rref;
2434 struct btrfs_root *root;
2435 struct btrfs_path *path;
2436 struct btrfs_key key;
2437
2438 struct extent_buffer *l;
2439 int slot;
2440
2441 struct inode *inode;
2442 int i, nritems;
2443 int ret;
2444 u64 objectid;
2445 u8 found;
2446
2447 path = btrfs_alloc_path();
2448 if (!path)
2449 return -ENOMEM;
2450
> 2451 rootrefs = memdup_user(argp, sizeof(*rootrefs));
2452 if (!rootrefs) {
2453 btrfs_free_path(path);
2454 return -ENOMEM;
2455 }
2456
2457 inode = file_inode(file);
2458 root = BTRFS_I(inode)->root->fs_info->tree_root;
2459 objectid = BTRFS_I(inode)->root->root_key.objectid;
2460
2461 key.objectid = objectid;
2462 key.type = BTRFS_ROOT_REF_KEY;
2463 key.offset = rootrefs->min_id;
2464 found = 0;
2465 while (1) {
2466 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
2467 if (ret < 0)
2468 goto out;
2469
2470 l = path->nodes[0];
2471 slot = path->slots[0];
2472 nritems = btrfs_header_nritems(l);
2473 if (nritems - slot == 0) {
2474 ret = 0;
2475 goto out;
2476 }
2477
2478 for (i = slot; i < nritems; i++) {
2479 btrfs_item_key_to_cpu(l, &key, i);
2480 if (key.objectid != objectid ||
2481 key.type != BTRFS_ROOT_REF_KEY) {
2482 ret = 0;
2483 goto out;
2484 }
2485
2486 if (found == BTRFS_MAX_ROOTREF_BUFFER_NUM) {
2487 /* update min_id for next search */
2488 rootrefs->min_id = key.offset;
2489 ret = -EOVERFLOW;
2490 goto out;
2491 }
2492
2493 rref = btrfs_item_ptr(l, i, struct btrfs_root_ref);
2494 rootrefs->rootref[found].subvolid = key.offset;
2495 rootrefs->rootref[found].dirid =
2496 btrfs_root_ref_dirid(l, rref);
2497 found++;
2498 }
2499
2500 btrfs_release_path(path);
2501 key.offset++;
2502 }
2503
2504 out:
2505 if (!ret || ret == -EOVERFLOW) {
2506 rootrefs->num_items = found;
> 2507 if (copy_to_user(argp, rootrefs, sizeof(*rootrefs)))
2508 ret = -EFAULT;
2509 }
2510
2511 btrfs_free_path(path);
> 2512 kfree(rootrefs);
2513
2514 return ret;
2515 }
2516
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 3/3] btrfs: Add unprivileged version of ino_lookup ioctl
2018-03-15 8:11 ` [PATCH v2 3/3] btrfs: Add unprivileged version of ino_lookup ioctl Misono, Tomohiro
@ 2018-03-18 5:11 ` kbuild test robot
0 siblings, 0 replies; 7+ messages in thread
From: kbuild test robot @ 2018-03-18 5:11 UTC (permalink / raw)
To: Misono, Tomohiro; +Cc: kbuild-all, linux-btrfs
Hi Tomohiro,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on linus/master]
[also build test WARNING on v4.16-rc5 next-20180316]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Misono-Tomohiro/btrfs-Add-three-new-unprivileged-ioctls-to-allow-normal-users-to-call-sub-list-show-etc/20180318-101013
reproduce:
# apt-get install sparse
make ARCH=x86_64 allmodconfig
make C=1 CF=-D__CHECK_ENDIAN__
sparse warnings: (new ones prefixed by >>)
fs/btrfs/ioctl.c:1561:9: sparse: incompatible types in comparison expression (different address spaces)
>> fs/btrfs/ioctl.c:2414:17: sparse: restricted __le64 degrades to integer
fs/btrfs/ioctl.c:2538:21: sparse: incorrect type in assignment (different address spaces) @@ expected struct btrfs_ioctl_get_subvol_info_args [noderef] <asn:1>*subvol_info @@ got sn:1>*subvol_info @@
fs/btrfs/ioctl.c:2538:21: expected struct btrfs_ioctl_get_subvol_info_args [noderef] <asn:1>*subvol_info
fs/btrfs/ioctl.c:2538:21: got void *
fs/btrfs/ioctl.c:2575:9: sparse: incorrect type in argument 1 (different address spaces) @@ expected void *to @@ got unsigned char [noderef] <avoid *to @@
fs/btrfs/ioctl.c:2575:9: expected void *to
fs/btrfs/ioctl.c:2575:9: got unsigned char [noderef] <asn:1>*<noident>
fs/btrfs/ioctl.c:2576:9: sparse: incorrect type in argument 1 (different address spaces) @@ expected void *to @@ got unsigned char [noderef] <avoid *to @@
fs/btrfs/ioctl.c:2576:9: expected void *to
fs/btrfs/ioctl.c:2576:9: got unsigned char [noderef] <asn:1>*<noident>
fs/btrfs/ioctl.c:2578:9: sparse: incorrect type in argument 1 (different address spaces) @@ expected void *to @@ got unsigned char [noderef] <avoid *to @@
fs/btrfs/ioctl.c:2578:9: expected void *to
fs/btrfs/ioctl.c:2578:9: got unsigned char [noderef] <asn:1>*<noident>
fs/btrfs/ioctl.c:2618:39: sparse: incorrect type in argument 2 (different address spaces) @@ expected void *dst @@ got char [noderef] <avoid *dst @@
fs/btrfs/ioctl.c:2618:39: expected void *dst
fs/btrfs/ioctl.c:2618:39: got char [noderef] <asn:1>*<noident>
fs/btrfs/ioctl.c:2621:32: sparse: incorrect type in argument 2 (different address spaces) @@ expected void const *from @@ got struct btrfs_ioctl_get_subvol_info_args [nodervoid const *from @@
fs/btrfs/ioctl.c:2621:32: expected void const *from
fs/btrfs/ioctl.c:2621:32: got struct btrfs_ioctl_get_subvol_info_args [noderef] <asn:1>*subvol_info
fs/btrfs/ioctl.c:2625:16: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *<noident> @@ got struct btrfs_ioctl_get_subvol_info_args [nodervoid const *<noident> @@
fs/btrfs/ioctl.c:2625:16: expected void const *<noident>
fs/btrfs/ioctl.c:2625:16: got struct btrfs_ioctl_get_subvol_info_args [noderef] <asn:1>*subvol_info
fs/btrfs/ioctl.c:2653:18: sparse: incorrect type in assignment (different address spaces) @@ expected struct btrfs_ioctl_get_subvol_rootref_args [noderef] <asn:1>*rootrefs @@ got sn:1>*rootrefs @@
fs/btrfs/ioctl.c:2653:18: expected struct btrfs_ioctl_get_subvol_rootref_args [noderef] <asn:1>*rootrefs
fs/btrfs/ioctl.c:2653:18: got void *
fs/btrfs/ioctl.c:2709:40: sparse: incorrect type in argument 2 (different address spaces) @@ expected void const *from @@ got struct btrfs_ioctl_get_subvol_rootref_args [nodervoid const *from @@
fs/btrfs/ioctl.c:2709:40: expected void const *from
fs/btrfs/ioctl.c:2709:40: got struct btrfs_ioctl_get_subvol_rootref_args [noderef] <asn:1>*rootrefs
fs/btrfs/ioctl.c:2714:15: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *<noident> @@ got struct btrfs_ioctl_get_subvol_rootref_args [nodervoid const *<noident> @@
fs/btrfs/ioctl.c:2714:15: expected void const *<noident>
fs/btrfs/ioctl.c:2714:15: got struct btrfs_ioctl_get_subvol_rootref_args [noderef] <asn:1>*rootrefs
fs/btrfs/ioctl.c:3208:24: sparse: incompatible types in comparison expression (different address spaces)
fs/btrfs/ioctl.c:2570:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2572:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2573:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2581:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2582:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2583:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2585:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2586:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2587:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2589:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2590:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2591:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2593:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2594:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2595:9: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2607:29: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2609:17: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2612:17: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2665:22: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2690:33: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2696:42: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2697:42: sparse: dereference of noderef expression
fs/btrfs/ioctl.c:2708:17: sparse: dereference of noderef expression
vim +2414 fs/btrfs/ioctl.c
2269
2270 static noinline int btrfs_search_path_in_tree_user(struct inode *inode,
2271 struct btrfs_ioctl_ino_lookup_user_args *args)
2272 {
2273 struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
2274 struct super_block *sb = inode->i_sb;
2275 struct btrfs_key upper_limit = BTRFS_I(inode)->location;
2276 u64 treeid = BTRFS_I(inode)->root->root_key.objectid;
2277 u64 dirid = args->dirid;
2278
2279 unsigned long item_off;
2280 unsigned long item_len;
2281 struct btrfs_inode_ref *iref;
2282 struct btrfs_root_ref rref;
2283 struct btrfs_root *root;
2284 struct btrfs_path *path;
2285 struct btrfs_key key, key2;
2286 struct extent_buffer *l;
2287 struct inode *temp_inode;
2288 char *ptr;
2289 int slot;
2290 int len;
2291 int total_len = 0;
2292 int ret = -1;
2293
2294 path = btrfs_alloc_path();
2295 if (!path)
2296 return -ENOMEM;
2297
2298 /*
2299 * If the bottom subvolume does not exist directly under upper_limit,
2300 * construct the path in bottomup way.
2301 */
2302 if (dirid != upper_limit.objectid) {
2303 ptr = &args->path[BTRFS_INO_LOOKUP_USER_PATH_MAX - 1];
2304
2305 key.objectid = treeid;
2306 key.type = BTRFS_ROOT_ITEM_KEY;
2307 key.offset = (u64)-1;
2308 root = btrfs_read_fs_root_no_name(fs_info, &key);
2309 if (IS_ERR(root)) {
2310 ret = -ENOENT;
2311 goto out;
2312 }
2313
2314 key.objectid = dirid;
2315 key.type = BTRFS_INODE_REF_KEY;
2316 key.offset = (u64)-1;
2317 while (1) {
2318 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
2319 if (ret < 0) {
2320 goto out;
2321 } else if (ret > 0) {
2322 ret = btrfs_previous_item(root, path, dirid,
2323 BTRFS_INODE_REF_KEY);
2324 if (ret < 0) {
2325 goto out;
2326 } else if (ret > 0) {
2327 ret = -ENOENT;
2328 goto out;
2329 }
2330 }
2331
2332 l = path->nodes[0];
2333 slot = path->slots[0];
2334 btrfs_item_key_to_cpu(l, &key, slot);
2335
2336 iref = btrfs_item_ptr(l, slot, struct btrfs_inode_ref);
2337 len = btrfs_inode_ref_name_len(l, iref);
2338 ptr -= len + 1;
2339 total_len += len + 1;
2340 if (ptr < args->path) {
2341 ret = -ENAMETOOLONG;
2342 goto out;
2343 }
2344
2345 *(ptr + len) = '/';
2346 read_extent_buffer(l, ptr,
2347 (unsigned long)(iref + 1), len);
2348
2349 /* Check the read+exec permission of this directory */
2350 ret = btrfs_previous_item(root, path, dirid,
2351 BTRFS_INODE_ITEM_KEY);
2352 if (ret < 0) {
2353 goto out;
2354 } else if (ret > 0) {
2355 ret = -ENOENT;
2356 goto out;
2357 }
2358
2359 l = path->nodes[0];
2360 slot = path->slots[0];
2361 btrfs_item_key_to_cpu(l, &key2, slot);
2362 if (key2.objectid != dirid) {
2363 ret = -ENOENT;
2364 goto out;
2365 }
2366
2367 temp_inode = btrfs_iget(sb, &key2, root, NULL);
2368 ret = inode_permission(temp_inode, MAY_READ | MAY_EXEC);
2369 iput(temp_inode);
2370 if (ret) {
2371 ret = -EACCES;
2372 goto out;
2373 }
2374
2375 if (key.offset == upper_limit.objectid)
2376 break;
2377 if (key.objectid == BTRFS_FIRST_FREE_OBJECTID) {
2378 ret = -EACCES;
2379 goto out;
2380 }
2381
2382 btrfs_release_path(path);
2383 key.objectid = key.offset;
2384 key.offset = (u64)-1;
2385 dirid = key.objectid;
2386 }
2387
2388 memmove(args->path, ptr, total_len);
2389 args->path[total_len] = '\0';
2390 btrfs_release_path(path);
2391 }
2392
2393 /* get the bottom subolume's name from ROOT_REF */
2394 root = fs_info->tree_root;
2395 key.objectid = treeid;
2396 key.type = BTRFS_ROOT_REF_KEY;
2397 key.offset = args->subvolid;
2398 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
2399 if (ret < 0) {
2400 goto out;
2401 } else if (ret > 0) {
2402 ret = -ENOENT;
2403 goto out;
2404 }
2405
2406 l = path->nodes[0];
2407 slot = path->slots[0];
2408 btrfs_item_key_to_cpu(l, &key, slot);
2409
2410 item_off = btrfs_item_ptr_offset(l, slot);
2411 item_len = btrfs_item_size_nr(l, slot);
2412 /* check if dirid in ROOT_REF corresponds to passed dirid */
2413 read_extent_buffer(l, &rref, item_off, sizeof(struct btrfs_root_ref));
> 2414 if (rref.dirid != args->dirid) {
2415 ret = -EINVAL;
2416 goto out;
2417 }
2418
2419 /* copy subvolume's name */
2420 item_off += sizeof(struct btrfs_root_ref);
2421 item_len -= sizeof(struct btrfs_root_ref);
2422 read_extent_buffer(l, args->name, item_off, item_len);
2423 args->name[item_len] = '\0';
2424
2425 out:
2426 btrfs_free_path(path);
2427 return ret;
2428 }
2429
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2018-03-18 5:11 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-03-15 8:09 [PATCH v2 0/3] btrfs: Add three new unprivileged ioctls to allow normal users to call "sub list/show" etc Misono, Tomohiro
2018-03-15 8:10 ` [PATCH v2 1/3] btrfs: Add unprivileged ioctl which returns subvolume information Misono, Tomohiro
2018-03-18 4:16 ` kbuild test robot
2018-03-15 8:11 ` [PATCH v2 2/3] btrfs: Add unprivileged ioctl which returns subvolume's ROOT_REF Misono, Tomohiro
2018-03-18 4:46 ` kbuild test robot
2018-03-15 8:11 ` [PATCH v2 3/3] btrfs: Add unprivileged version of ino_lookup ioctl Misono, Tomohiro
2018-03-18 5:11 ` kbuild test robot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).