2020-05-12 19:45:42

by Shuah Khan

[permalink] [raw]
Subject: [PATCH v2 0/2] fs: avoid fdput() after failed fdget()

While debugging an unrelated problem, I noticed these two cases fdput()
is called after failed fdget() while reviewing at all the fdget() and
fdput() paths in the kernel.

Changes since v1:
Patch 1:
Changed to address review comments to refine the code for improved
readability in addition to the change to avoid fdput() on failed
fdget()
Patch 2:
No change to v1. Including it in the series to keep the patches
together.

Shuah Khan (2):
fs: avoid fdput() after failed fdget() in ksys_sync_file_range()
fs: avoid fdput() after failed fdget() in kernel_read_file_from_fd()

fs/exec.c | 2 +-
fs/sync.c | 12 ++++++------
2 files changed, 7 insertions(+), 7 deletions(-)

--
2.25.1


2020-05-12 19:45:42

by Shuah Khan

[permalink] [raw]
Subject: [PATCH v2 1/2] fs: avoid fdput() after failed fdget() in ksys_sync_file_range()

Fix ksys_sync_file_range() to avoid fdput() after a failed fdget().
fdput() doesn't do fput() on this file since FDPUT_FPUT isn't set
in fd.flags.

Change it anyway since failed fdget() doesn't require a fdput(). Refine
the code path a bit for it to read more clearly.
Reference: commit 22f96b3808c1 ("fs: add sync_file_range() helper")

Signed-off-by: Shuah Khan <[email protected]>
---
fs/sync.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/fs/sync.c b/fs/sync.c
index 4d1ff010bc5a..300ca73ec87c 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -364,15 +364,15 @@ int sync_file_range(struct file *file, loff_t offset, loff_t nbytes,
int ksys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
unsigned int flags)
{
- int ret;
- struct fd f;
+ int ret = -EBADF;
+ struct fd f = fdget(fd);

- ret = -EBADF;
- f = fdget(fd);
- if (f.file)
- ret = sync_file_range(f.file, offset, nbytes, flags);
+ if (!f.file)
+ goto out;

+ ret = sync_file_range(f.file, offset, nbytes, flags);
fdput(f);
+out:
return ret;
}

--
2.25.1

2020-05-12 19:48:11

by Shuah Khan

[permalink] [raw]
Subject: [PATCH v2 2/2] fs: avoid fdput() after failed fdget() in kernel_read_file_from_fd()

Fix kernel_read_file_from_fd() to avoid fdput() after a failed fdget().
fdput() doesn't do fput() on this file since FDPUT_FPUT isn't set
in fd.flags. Fix it anyway since failed fdget() doesn't require
a fdput().

This was introduced in a commit that added kernel_read_file_from_fd() as
a wrapper for the VFS common kernel_read_file().

Fixes: b844f0ecbc56 ("vfs: define kernel_copy_file_from_fd()")
Signed-off-by: Shuah Khan <[email protected]>
---
fs/exec.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/exec.c b/fs/exec.c
index 06b4c550af5d..ea24bdce939d 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1021,8 +1021,8 @@ int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size,
goto out;

ret = kernel_read_file(f.file, buf, size, max_size, id);
-out:
fdput(f);
+out:
return ret;
}
EXPORT_SYMBOL_GPL(kernel_read_file_from_fd);
--
2.25.1

2020-05-13 05:48:31

by Al Viro

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] fs: avoid fdput() after failed fdget() in ksys_sync_file_range()

On Tue, May 12, 2020 at 01:43:04PM -0600, Shuah Khan wrote:

> @@ -364,15 +364,15 @@ int sync_file_range(struct file *file, loff_t offset, loff_t nbytes,
> int ksys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
> unsigned int flags)
> {
> - int ret;
> - struct fd f;
> + int ret = -EBADF;
> + struct fd f = fdget(fd);
>
> - ret = -EBADF;
> - f = fdget(fd);
> - if (f.file)
> - ret = sync_file_range(f.file, offset, nbytes, flags);
> + if (!f.file)
> + goto out;
>
> + ret = sync_file_range(f.file, offset, nbytes, flags);
> fdput(f);
> +out:
> return ret;

IDGI... What's the point of that goto out, when it leads straight to return?

2020-05-13 05:52:41

by Al Viro

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] fs: avoid fdput() after failed fdget() in kernel_read_file_from_fd()

On Tue, May 12, 2020 at 01:43:05PM -0600, Shuah Khan wrote:
> Fix kernel_read_file_from_fd() to avoid fdput() after a failed fdget().
> fdput() doesn't do fput() on this file since FDPUT_FPUT isn't set
> in fd.flags. Fix it anyway since failed fdget() doesn't require
> a fdput().
>
> This was introduced in a commit that added kernel_read_file_from_fd() as
> a wrapper for the VFS common kernel_read_file().
>
> Fixes: b844f0ecbc56 ("vfs: define kernel_copy_file_from_fd()")
> Signed-off-by: Shuah Khan <[email protected]>
> ---
> fs/exec.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/exec.c b/fs/exec.c
> index 06b4c550af5d..ea24bdce939d 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -1021,8 +1021,8 @@ int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size,
> goto out;
>
> ret = kernel_read_file(f.file, buf, size, max_size, id);
> -out:
> fdput(f);
> +out:
> return ret;

Again, that goto is a pointless obfuscation; just return -EBADF
and be done with that.

Incidentally, why is that thing exported?

2020-05-13 13:17:11

by Luis Chamberlain

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] fs: avoid fdput() after failed fdget() in kernel_read_file_from_fd()

On Wed, May 13, 2020 at 06:49:50AM +0100, Al Viro wrote:
> On Tue, May 12, 2020 at 01:43:05PM -0600, Shuah Khan wrote:
> > diff --git a/fs/exec.c b/fs/exec.c
> > index 06b4c550af5d..ea24bdce939d 100644
> > --- a/fs/exec.c
> > +++ b/fs/exec.c
> > @@ -1021,8 +1021,8 @@ int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size,
> > goto out;
> >
> > ret = kernel_read_file(f.file, buf, size, max_size, id);
> > -out:
> > fdput(f);
> > +out:
> > return ret;
>
> Incidentally, why is that thing exported?

Both kernel_read_file_from_fd() and kernel_read_file() are exported
because they have users, however kernel_read_file() only has security
stuff as a user. Do we want to get rid of the lsm hook for it?

I also have some non-posted patches which tucks away these kernel_read*()
exports under a symbol namespace, to avoid wide-spread use / abuse on
areas in the kernel, so I'd be happy to take this on if we want to
remove it export / lsm hook as part of my series. I did this as there
is another series of patches for a new driver which extend these family
of functions with a now pread() variant....

Luis

2020-05-13 14:22:25

by Luis Chamberlain

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] fs: avoid fdput() after failed fdget() in kernel_read_file_from_fd()

On Wed, May 13, 2020 at 7:13 AM Luis Chamberlain <[email protected]> wrote:
>
> On Wed, May 13, 2020 at 06:49:50AM +0100, Al Viro wrote:
> > On Tue, May 12, 2020 at 01:43:05PM -0600, Shuah Khan wrote:
> > > diff --git a/fs/exec.c b/fs/exec.c
> > > index 06b4c550af5d..ea24bdce939d 100644
> > > --- a/fs/exec.c
> > > +++ b/fs/exec.c
> > > @@ -1021,8 +1021,8 @@ int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size,
> > > goto out;
> > >
> > > ret = kernel_read_file(f.file, buf, size, max_size, id);
> > > -out:
> > > fdput(f);
> > > +out:
> > > return ret;
> >
> > Incidentally, why is that thing exported?
>
> Both kernel_read_file_from_fd() and kernel_read_file() are exported
> because they have users, however kernel_read_file() only has security
> stuff as a user. Do we want to get rid of the lsm hook for it?

Alright, yeah just the export needs to be removed. I have a patch
series dealing with these callers so will add it to my queue.

Luis

2020-05-13 18:00:59

by Shuah Khan

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] fs: avoid fdput() after failed fdget() in kernel_read_file_from_fd()

On 5/12/20 11:49 PM, Al Viro wrote:
> On Tue, May 12, 2020 at 01:43:05PM -0600, Shuah Khan wrote:
>> Fix kernel_read_file_from_fd() to avoid fdput() after a failed fdget().
>> fdput() doesn't do fput() on this file since FDPUT_FPUT isn't set
>> in fd.flags. Fix it anyway since failed fdget() doesn't require
>> a fdput().
>>
>> This was introduced in a commit that added kernel_read_file_from_fd() as
>> a wrapper for the VFS common kernel_read_file().
>>
>> Fixes: b844f0ecbc56 ("vfs: define kernel_copy_file_from_fd()")
>> Signed-off-by: Shuah Khan <[email protected]>
>> ---
>> fs/exec.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/fs/exec.c b/fs/exec.c
>> index 06b4c550af5d..ea24bdce939d 100644
>> --- a/fs/exec.c
>> +++ b/fs/exec.c
>> @@ -1021,8 +1021,8 @@ int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size,
>> goto out;
>>
>> ret = kernel_read_file(f.file, buf, size, max_size, id);
>> -out:
>> fdput(f);
>> +out:
>> return ret;
>
> Again, that goto is a pointless obfuscation; just return -EBADF
> and be done with that.
>

My reasoning is if this routine ends up growing it might be useful
to handle the return this way.

In any case, I will send v3 for both of these patches.

thanks,
-- Shuah

2020-05-22 22:02:12

by Scott Branden

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] fs: avoid fdput() after failed fdget() in kernel_read_file_from_fd()

Hi Luis,

On 2020-05-13 7:19 a.m., Luis Chamberlain wrote:
> On Wed, May 13, 2020 at 7:13 AM Luis Chamberlain <[email protected]> wrote:
>> On Wed, May 13, 2020 at 06:49:50AM +0100, Al Viro wrote:
>>> On Tue, May 12, 2020 at 01:43:05PM -0600, Shuah Khan wrote:
>>>> diff --git a/fs/exec.c b/fs/exec.c
>>>> index 06b4c550af5d..ea24bdce939d 100644
>>>> --- a/fs/exec.c
>>>> +++ b/fs/exec.c
>>>> @@ -1021,8 +1021,8 @@ int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size,
>>>> goto out;
>>>>
>>>> ret = kernel_read_file(f.file, buf, size, max_size, id);
>>>> -out:
>>>> fdput(f);
>>>> +out:
>>>> return ret;
>>> Incidentally, why is that thing exported?
>> Both kernel_read_file_from_fd() and kernel_read_file() are exported
>> because they have users, however kernel_read_file() only has security
>> stuff as a user. Do we want to get rid of the lsm hook for it?
> Alright, yeah just the export needs to be removed. I have a patch
> series dealing with these callers so will add it to my queue.
When will these changes make it into linux-next?
It is difficult for me to complete my patch series without these other
misc. changes in place.
>
> Luis
Regards,
 Scott

2020-05-22 22:17:03

by Scott Branden

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] fs: avoid fdput() after failed fdget() in kernel_read_file_from_fd()



On 2020-05-22 2:59 p.m., Scott Branden wrote:
> Hi Luis,
>
> On 2020-05-13 7:19 a.m., Luis Chamberlain wrote:
>> On Wed, May 13, 2020 at 7:13 AM Luis Chamberlain <[email protected]>
>> wrote:
>>> On Wed, May 13, 2020 at 06:49:50AM +0100, Al Viro wrote:
>>>> On Tue, May 12, 2020 at 01:43:05PM -0600, Shuah Khan wrote:
>>>>> diff --git a/fs/exec.c b/fs/exec.c
>>>>> index 06b4c550af5d..ea24bdce939d 100644
>>>>> --- a/fs/exec.c
>>>>> +++ b/fs/exec.c
>>>>> @@ -1021,8 +1021,8 @@ int kernel_read_file_from_fd(int fd, void
>>>>> **buf, loff_t *size, loff_t max_size,
>>>>>              goto out;
>>>>>
>>>>>      ret = kernel_read_file(f.file, buf, size, max_size, id);
>>>>> -out:
>>>>>      fdput(f);
>>>>> +out:
>>>>>      return ret;
>>>> Incidentally, why is that thing exported?
>>> Both kernel_read_file_from_fd() and kernel_read_file() are exported
>>> because they have users, however kernel_read_file() only has security
>>> stuff as a user. Do we want to get rid of the lsm hook for it?
>> Alright, yeah just the export needs to be removed. I have a patch
>> series dealing with these callers so will add it to my queue.
> When will these changes make it into linux-next?
> It is difficult for me to complete my patch series without these other
> misc. changes in place.
Sorry, I see the patch series is still being worked on (missing
changelog, comments, etc).
Hopefully the patches stabilize so I can apply my changes on top fairly
soon.
>>
>>    Luis
> Regards,
>  Scott

2020-05-22 22:50:50

by Luis Chamberlain

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] fs: avoid fdput() after failed fdget() in kernel_read_file_from_fd()

On Fri, May 22, 2020 at 03:14:59PM -0700, Scott Branden wrote:
>
>
> On 2020-05-22 2:59 p.m., Scott Branden wrote:
> > Hi Luis,
> >
> > On 2020-05-13 7:19 a.m., Luis Chamberlain wrote:
> > > On Wed, May 13, 2020 at 7:13 AM Luis Chamberlain <[email protected]>
> > > wrote:
> > > > On Wed, May 13, 2020 at 06:49:50AM +0100, Al Viro wrote:
> > > > > On Tue, May 12, 2020 at 01:43:05PM -0600, Shuah Khan wrote:
> > > > > > diff --git a/fs/exec.c b/fs/exec.c
> > > > > > index 06b4c550af5d..ea24bdce939d 100644
> > > > > > --- a/fs/exec.c
> > > > > > +++ b/fs/exec.c
> > > > > > @@ -1021,8 +1021,8 @@ int kernel_read_file_from_fd(int
> > > > > > fd, void **buf, loff_t *size, loff_t max_size,
> > > > > > ???????????? goto out;
> > > > > >
> > > > > > ???? ret = kernel_read_file(f.file, buf, size, max_size, id);
> > > > > > -out:
> > > > > > ???? fdput(f);
> > > > > > +out:
> > > > > > ???? return ret;
> > > > > Incidentally, why is that thing exported?
> > > > Both kernel_read_file_from_fd() and kernel_read_file() are exported
> > > > because they have users, however kernel_read_file() only has security
> > > > stuff as a user. Do we want to get rid of the lsm hook for it?
> > > Alright, yeah just the export needs to be removed. I have a patch
> > > series dealing with these callers so will add it to my queue.
> > When will these changes make it into linux-next?
> > It is difficult for me to complete my patch series without these other
> > misc. changes in place.
> Sorry, I see the patch series is still being worked on (missing changelog,
> comments, etc).
> Hopefully the patches stabilize so I can apply my changes on top fairly
> soon.

Yeah I have to redo that series to take into account feedback. I'll be
sure cc you on that. I have a few other series to attend to before that,
so I think this will take a week.

Luis