diff mbox series

btrfs: fix wrong address when faulting in pages in the search ioctl

Message ID 78bf853ef63f2dbd62587bb02bb723fbaa77c198.1600070418.git.fdmanana@suse.com (mailing list archive)
State New, archived
Headers show
Series btrfs: fix wrong address when faulting in pages in the search ioctl | expand

Commit Message

Filipe Manana Sept. 14, 2020, 8:01 a.m. UTC
From: Filipe Manana <fdmanana@suse.com>

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
Tested-by: A L <mail@lechevalier.se>
Fixes: a48b73eca4ceb9 ("btrfs: fix potential deadlock in the search ioctl")
Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ioctl.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Comments

Johannes Thumshirn Sept. 14, 2020, 12:06 p.m. UTC | #1
Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Josef Bacik Sept. 14, 2020, 3:23 p.m. UTC | #2
On 9/14/20 4:01 AM, fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
> 
> 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
> Tested-by: A L <mail@lechevalier.se>
> Fixes: a48b73eca4ceb9 ("btrfs: fix potential deadlock in the search ioctl")
> Signed-off-by: Filipe Manana <fdmanana@suse.com>
> ---
>   fs/btrfs/ioctl.c | 3 ++-
>   1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> index 5f06aeb71823..b91444e810a5 100644
> --- a/fs/btrfs/ioctl.c
> +++ b/fs/btrfs/ioctl.c
> @@ -2194,7 +2194,8 @@ static noinline int search_ioctl(struct inode *inode,
>   	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;
>   
> 

Eesh, can we get an xfstest for this?

Reviewed-by: Josef Bacik <josef@toxicpanda.com>

Thanks,

Josef
Filipe Manana Sept. 14, 2020, 3:47 p.m. UTC | #3
On Mon, Sep 14, 2020 at 4:23 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> On 9/14/20 4:01 AM, fdmanana@kernel.org wrote:
> > From: Filipe Manana <fdmanana@suse.com>
> >
> > 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
> > Tested-by: A L <mail@lechevalier.se>
> > Fixes: a48b73eca4ceb9 ("btrfs: fix potential deadlock in the search ioctl")
> > Signed-off-by: Filipe Manana <fdmanana@suse.com>
> > ---
> >   fs/btrfs/ioctl.c | 3 ++-
> >   1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> > index 5f06aeb71823..b91444e810a5 100644
> > --- a/fs/btrfs/ioctl.c
> > +++ b/fs/btrfs/ioctl.c
> > @@ -2194,7 +2194,8 @@ static noinline int search_ioctl(struct inode *inode,
> >       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;
> >
> >
>
> Eesh, can we get an xfstest for this?

I would have written one if it were simple to trigger.
I don't think it's easy to trigger it deterministically or close
enough to deterministic.

How do you guarantee that a call to the ioctl will cause the pages to
fault in at any iteration of the loop?
That the pages aren't already faulted in, and then if you need to
fault them in, that happens on an iteration other than the first one?

Thanks.

>
> Reviewed-by: Josef Bacik <josef@toxicpanda.com>
>
> Thanks,
>
> Josef
Josef Bacik Sept. 14, 2020, 3:58 p.m. UTC | #4
On 9/14/20 11:47 AM, Filipe Manana wrote:
> On Mon, Sep 14, 2020 at 4:23 PM Josef Bacik <josef@toxicpanda.com> wrote:
>>
>> On 9/14/20 4:01 AM, fdmanana@kernel.org wrote:
>>> From: Filipe Manana <fdmanana@suse.com>
>>>
>>> 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
>>> Tested-by: A L <mail@lechevalier.se>
>>> Fixes: a48b73eca4ceb9 ("btrfs: fix potential deadlock in the search ioctl")
>>> Signed-off-by: Filipe Manana <fdmanana@suse.com>
>>> ---
>>>    fs/btrfs/ioctl.c | 3 ++-
>>>    1 file changed, 2 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
>>> index 5f06aeb71823..b91444e810a5 100644
>>> --- a/fs/btrfs/ioctl.c
>>> +++ b/fs/btrfs/ioctl.c
>>> @@ -2194,7 +2194,8 @@ static noinline int search_ioctl(struct inode *inode,
>>>        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;
>>>
>>>
>>
>> Eesh, can we get an xfstest for this?
> 
> I would have written one if it were simple to trigger.
> I don't think it's easy to trigger it deterministically or close
> enough to deterministic.
> 
> How do you guarantee that a call to the ioctl will cause the pages to
> fault in at any iteration of the loop?
> That the pages aren't already faulted in, and then if you need to
> fault them in, that happens on an iteration other than the first one?
> 

Yeah I was thinking about it after I wrote it.  I guess mmap a few pages worth, 
and stick the first entry at the end of the first page?  A stress test is 
probably in order for this stuff so we don't have this sort of problem again. 
Thanks,

Josef
David Sterba Sept. 14, 2020, 6:02 p.m. UTC | #5
On Mon, Sep 14, 2020 at 09:01:04AM +0100, fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
> 
> 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
> Tested-by: A L <mail@lechevalier.se>
> Fixes: a48b73eca4ceb9 ("btrfs: fix potential deadlock in the search ioctl")
> Signed-off-by: Filipe Manana <fdmanana@suse.com>

Thanks, it's on the way to mainline and stable trees.
diff mbox series

Patch

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 5f06aeb71823..b91444e810a5 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2194,7 +2194,8 @@  static noinline int search_ioctl(struct inode *inode,
 	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;