diff options
-rw-r--r-- | fs/btrfs/ioctl.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 6e09fc1c1c18..3d89fd888399 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -1957,7 +1957,7 @@ static noinline int copy_to_sk(struct btrfs_root *root, | |||
1957 | struct btrfs_path *path, | 1957 | struct btrfs_path *path, |
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 *buf, |
1962 | unsigned long *sk_offset, | 1962 | unsigned long *sk_offset, |
1963 | int *num_found) | 1963 | int *num_found) |
@@ -1990,7 +1990,7 @@ static noinline int copy_to_sk(struct btrfs_root *root, | |||
1990 | if (!key_in_sk(key, sk)) | 1990 | if (!key_in_sk(key, sk)) |
1991 | continue; | 1991 | continue; |
1992 | 1992 | ||
1993 | if (sizeof(sh) + item_len > buf_size) { | 1993 | if (sizeof(sh) + item_len > *buf_size) { |
1994 | if (*num_found) { | 1994 | if (*num_found) { |
1995 | ret = 1; | 1995 | ret = 1; |
1996 | goto out; | 1996 | goto out; |
@@ -2001,11 +2001,12 @@ static noinline int copy_to_sk(struct btrfs_root *root, | |||
2001 | * handle -EOVERFLOW | 2001 | * handle -EOVERFLOW |
2002 | */ | 2002 | */ |
2003 | 2003 | ||
2004 | *buf_size = sizeof(sh) + item_len; | ||
2004 | item_len = 0; | 2005 | item_len = 0; |
2005 | ret = -EOVERFLOW; | 2006 | ret = -EOVERFLOW; |
2006 | } | 2007 | } |
2007 | 2008 | ||
2008 | if (sizeof(sh) + item_len + *sk_offset > buf_size) { | 2009 | if (sizeof(sh) + item_len + *sk_offset > *buf_size) { |
2009 | ret = 1; | 2010 | ret = 1; |
2010 | goto out; | 2011 | goto out; |
2011 | } | 2012 | } |
@@ -2056,7 +2057,7 @@ out: | |||
2056 | 2057 | ||
2057 | static noinline int search_ioctl(struct inode *inode, | 2058 | static noinline int search_ioctl(struct inode *inode, |
2058 | struct btrfs_ioctl_search_key *sk, | 2059 | struct btrfs_ioctl_search_key *sk, |
2059 | size_t buf_size, | 2060 | size_t *buf_size, |
2060 | char *buf) | 2061 | char *buf) |
2061 | { | 2062 | { |
2062 | struct btrfs_root *root; | 2063 | struct btrfs_root *root; |
@@ -2067,8 +2068,10 @@ static noinline int search_ioctl(struct inode *inode, | |||
2067 | int num_found = 0; | 2068 | int num_found = 0; |
2068 | unsigned long sk_offset = 0; | 2069 | unsigned long sk_offset = 0; |
2069 | 2070 | ||
2070 | if (buf_size < sizeof(struct btrfs_ioctl_search_header)) | 2071 | if (*buf_size < sizeof(struct btrfs_ioctl_search_header)) { |
2072 | *buf_size = sizeof(struct btrfs_ioctl_search_header); | ||
2071 | return -EOVERFLOW; | 2073 | return -EOVERFLOW; |
2074 | } | ||
2072 | 2075 | ||
2073 | path = btrfs_alloc_path(); | 2076 | path = btrfs_alloc_path(); |
2074 | if (!path) | 2077 | if (!path) |
@@ -2121,9 +2124,10 @@ err: | |||
2121 | static noinline int btrfs_ioctl_tree_search(struct file *file, | 2124 | static noinline int btrfs_ioctl_tree_search(struct file *file, |
2122 | void __user *argp) | 2125 | void __user *argp) |
2123 | { | 2126 | { |
2124 | struct btrfs_ioctl_search_args *args; | 2127 | struct btrfs_ioctl_search_args *args; |
2125 | struct inode *inode; | 2128 | struct inode *inode; |
2126 | int ret; | 2129 | int ret; |
2130 | size_t buf_size; | ||
2127 | 2131 | ||
2128 | if (!capable(CAP_SYS_ADMIN)) | 2132 | if (!capable(CAP_SYS_ADMIN)) |
2129 | return -EPERM; | 2133 | return -EPERM; |
@@ -2132,8 +2136,10 @@ static noinline int btrfs_ioctl_tree_search(struct file *file, | |||
2132 | if (IS_ERR(args)) | 2136 | if (IS_ERR(args)) |
2133 | return PTR_ERR(args); | 2137 | return PTR_ERR(args); |
2134 | 2138 | ||
2139 | buf_size = sizeof(args->buf); | ||
2140 | |||
2135 | inode = file_inode(file); | 2141 | inode = file_inode(file); |
2136 | ret = search_ioctl(inode, &args->key, sizeof(args->buf), args->buf); | 2142 | ret = search_ioctl(inode, &args->key, &buf_size, args->buf); |
2137 | 2143 | ||
2138 | /* | 2144 | /* |
2139 | * In the origin implementation an overflow is handled by returning a | 2145 | * In the origin implementation an overflow is handled by returning a |