aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ioctl.c48
1 files changed, 33 insertions, 15 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 3d89fd888399..393a543a519e 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1958,7 +1958,7 @@ static noinline int copy_to_sk(struct btrfs_root *root,
1958 struct btrfs_key *key, 1958 struct btrfs_key *key,
1959 struct btrfs_ioctl_search_key *sk, 1959 struct btrfs_ioctl_search_key *sk,
1960 size_t *buf_size, 1960 size_t *buf_size,
1961 char *buf, 1961 char __user *ubuf,
1962 unsigned long *sk_offset, 1962 unsigned long *sk_offset,
1963 int *num_found) 1963 int *num_found)
1964{ 1964{
@@ -2018,14 +2018,22 @@ static noinline int copy_to_sk(struct btrfs_root *root,
2018 sh.transid = found_transid; 2018 sh.transid = found_transid;
2019 2019
2020 /* copy search result header */ 2020 /* copy search result header */
2021 memcpy(buf + *sk_offset, &sh, sizeof(sh)); 2021 if (copy_to_user(ubuf + *sk_offset, &sh, sizeof(sh))) {
2022 ret = -EFAULT;
2023 goto out;
2024 }
2025
2022 *sk_offset += sizeof(sh); 2026 *sk_offset += sizeof(sh);
2023 2027
2024 if (item_len) { 2028 if (item_len) {
2025 char *p = buf + *sk_offset; 2029 char __user *up = ubuf + *sk_offset;
2026 /* copy the item */ 2030 /* copy the item */
2027 read_extent_buffer(leaf, p, 2031 if (read_extent_buffer_to_user(leaf, up,
2028 item_off, item_len); 2032 item_off, item_len)) {
2033 ret = -EFAULT;
2034 goto out;
2035 }
2036
2029 *sk_offset += item_len; 2037 *sk_offset += item_len;
2030 } 2038 }
2031 (*num_found)++; 2039 (*num_found)++;
@@ -2052,13 +2060,22 @@ advance_key:
2052 } else 2060 } else
2053 ret = 1; 2061 ret = 1;
2054out: 2062out:
2063 /*
2064 * 0: all items from this leaf copied, continue with next
2065 * 1: * more items can be copied, but unused buffer is too small
2066 * * all items were found
2067 * Either way, it will stops the loop which iterates to the next
2068 * leaf
2069 * -EOVERFLOW: item was to large for buffer
2070 * -EFAULT: could not copy extent buffer back to userspace
2071 */
2055 return ret; 2072 return ret;
2056} 2073}
2057 2074
2058static noinline int search_ioctl(struct inode *inode, 2075static noinline int search_ioctl(struct inode *inode,
2059 struct btrfs_ioctl_search_key *sk, 2076 struct btrfs_ioctl_search_key *sk,
2060 size_t *buf_size, 2077 size_t *buf_size,
2061 char *buf) 2078 char __user *ubuf)
2062{ 2079{
2063 struct btrfs_root *root; 2080 struct btrfs_root *root;
2064 struct btrfs_key key; 2081 struct btrfs_key key;
@@ -2106,7 +2123,7 @@ static noinline int search_ioctl(struct inode *inode,
2106 ret = 0; 2123 ret = 0;
2107 goto err; 2124 goto err;
2108 } 2125 }
2109 ret = copy_to_sk(root, path, &key, sk, buf_size, buf, 2126 ret = copy_to_sk(root, path, &key, sk, buf_size, ubuf,
2110 &sk_offset, &num_found); 2127 &sk_offset, &num_found);
2111 btrfs_release_path(path); 2128 btrfs_release_path(path);
2112 if (ret) 2129 if (ret)
@@ -2124,7 +2141,8 @@ err:
2124static noinline int btrfs_ioctl_tree_search(struct file *file, 2141static noinline int btrfs_ioctl_tree_search(struct file *file,
2125 void __user *argp) 2142 void __user *argp)
2126{ 2143{
2127 struct btrfs_ioctl_search_args *args; 2144 struct btrfs_ioctl_search_args __user *uargs;
2145 struct btrfs_ioctl_search_key sk;
2128 struct inode *inode; 2146 struct inode *inode;
2129 int ret; 2147 int ret;
2130 size_t buf_size; 2148 size_t buf_size;
@@ -2132,14 +2150,15 @@ static noinline int btrfs_ioctl_tree_search(struct file *file,
2132 if (!capable(CAP_SYS_ADMIN)) 2150 if (!capable(CAP_SYS_ADMIN))
2133 return -EPERM; 2151 return -EPERM;
2134 2152
2135 args = memdup_user(argp, sizeof(*args)); 2153 uargs = (struct btrfs_ioctl_search_args __user *)argp;
2136 if (IS_ERR(args))
2137 return PTR_ERR(args);
2138 2154
2139 buf_size = sizeof(args->buf); 2155 if (copy_from_user(&sk, &uargs->key, sizeof(sk)))
2156 return -EFAULT;
2157
2158 buf_size = sizeof(uargs->buf);
2140 2159
2141 inode = file_inode(file); 2160 inode = file_inode(file);
2142 ret = search_ioctl(inode, &args->key, &buf_size, args->buf); 2161 ret = search_ioctl(inode, &sk, &buf_size, uargs->buf);
2143 2162
2144 /* 2163 /*
2145 * In the origin implementation an overflow is handled by returning a 2164 * In the origin implementation an overflow is handled by returning a
@@ -2148,9 +2167,8 @@ static noinline int btrfs_ioctl_tree_search(struct file *file,
2148 if (ret == -EOVERFLOW) 2167 if (ret == -EOVERFLOW)
2149 ret = 0; 2168 ret = 0;
2150 2169
2151 if (ret == 0 && copy_to_user(argp, args, sizeof(*args))) 2170 if (ret == 0 && copy_to_user(&uargs->key, &sk, sizeof(sk)))
2152 ret = -EFAULT; 2171 ret = -EFAULT;
2153 kfree(args);
2154 return ret; 2172 return ret;
2155} 2173}
2156 2174