| From 1c78544eaa4660096aeb6a57ec82b42cdb3bfe5a Mon Sep 17 00:00:00 2001 |
| From: Filipe Manana <fdmanana@suse.com> |
| Date: Mon, 14 Sep 2020 09:01:04 +0100 |
| Subject: btrfs: fix wrong address when faulting in pages in the search ioctl |
| |
| From: Filipe Manana <fdmanana@suse.com> |
| |
| commit 1c78544eaa4660096aeb6a57ec82b42cdb3bfe5a upstream. |
| |
| When faulting in the pages for the user supplied buffer for the search |
| ioctl, we are passing only the base address of the buffer to the function |
| fault_in_pages_writeable(). This means that after the first iteration of |
| the while loop that searches for leaves, when we have a non-zero offset, |
| stored in 'sk_offset', we try to fault in a wrong page range. |
| |
| So fix this by adding the offset in 'sk_offset' to the base address of the |
| user supplied buffer when calling fault_in_pages_writeable(). |
| |
| Several users have reported that the applications compsize and bees have |
| started to operate incorrectly since commit a48b73eca4ceb9 ("btrfs: fix |
| potential deadlock in the search ioctl") was added to stable trees, and |
| these applications make heavy use of the search ioctls. This fixes their |
| issues. |
| |
| Link: https://lore.kernel.org/linux-btrfs/632b888d-a3c3-b085-cdf5-f9bb61017d92@lechevalier.se/ |
| Link: https://github.com/kilobyte/compsize/issues/34 |
| Fixes: a48b73eca4ceb9 ("btrfs: fix potential deadlock in the search ioctl") |
| CC: stable@vger.kernel.org # 4.4+ |
| Tested-by: A L <mail@lechevalier.se> |
| Reviewed-by: Josef Bacik <josef@toxicpanda.com> |
| Signed-off-by: Filipe Manana <fdmanana@suse.com> |
| Reviewed-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/btrfs/ioctl.c | 3 ++- |
| 1 file changed, 2 insertions(+), 1 deletion(-) |
| |
| --- a/fs/btrfs/ioctl.c |
| +++ b/fs/btrfs/ioctl.c |
| @@ -2129,7 +2129,8 @@ static noinline int search_ioctl(struct |
| key.offset = sk->min_offset; |
| |
| while (1) { |
| - ret = fault_in_pages_writeable(ubuf, *buf_size - sk_offset); |
| + ret = fault_in_pages_writeable(ubuf + sk_offset, |
| + *buf_size - sk_offset); |
| if (ret) |
| break; |
| |