2010-06-03 10:04:21

by Dan Carpenter

[permalink] [raw]
Subject: [patch] fcntl: return -EFAULT if copy_to_user fails

copy_to_user() returns the number of bytes remaining, but we want to
return -EFAULT.

ret = fcntl(fd, F_SETOWN_EX, NULL);

With the original code ret would be 8 here.

Signed-off-by: Dan Carpenter <[email protected]>

diff --git a/fs/fcntl.c b/fs/fcntl.c
index f74d270..0ea7b0f 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -274,7 +274,7 @@ static int f_setown_ex(struct file *filp, unsigned long arg)

ret = copy_from_user(&owner, owner_p, sizeof(owner));
if (ret)
- return ret;
+ return -EFAULT;

switch (owner.type) {
case F_OWNER_TID:


2010-06-03 10:18:30

by Takuya Yoshikawa

[permalink] [raw]
Subject: Re: [patch] fcntl: return -EFAULT if copy_to_user fails

(2010/06/03 19:04), Dan Carpenter wrote:
> copy_to_user() returns the number of bytes remaining, but we want to
> return -EFAULT.
>
> ret = fcntl(fd, F_SETOWN_EX, NULL);
>
> With the original code ret would be 8 here.
>
> Signed-off-by: Dan Carpenter<[email protected]>

How about f_getown_ex() ?

if (!ret)
ret = copy_to_user(owner_p, &owner, sizeof(owner));
return ret;

Fixing this too would be better, I think.

Takuya

>
> diff --git a/fs/fcntl.c b/fs/fcntl.c
> index f74d270..0ea7b0f 100644
> --- a/fs/fcntl.c
> +++ b/fs/fcntl.c
> @@ -274,7 +274,7 @@ static int f_setown_ex(struct file *filp, unsigned long arg)
>
> ret = copy_from_user(&owner, owner_p, sizeof(owner));
> if (ret)
> - return ret;
> + return -EFAULT;
>
> switch (owner.type) {
> case F_OWNER_TID:
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

2010-06-03 10:36:10

by Dan Carpenter

[permalink] [raw]
Subject: [patch v2] fcntl: return -EFAULT if copy_to_user fails

copy_to_user() returns the number of bytes remaining, but we want to
return -EFAULT.
ret = fcntl(fd, F_SETOWN_EX, NULL);
With the original code ret would be 8 here.

V2: Takuya Yoshikawa pointed out a similar issue in f_getown_ex()

Signed-off-by: Dan Carpenter <[email protected]>

diff --git a/fs/fcntl.c b/fs/fcntl.c
index f74d270..51e11bf 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -274,7 +274,7 @@ static int f_setown_ex(struct file *filp, unsigned long arg)

ret = copy_from_user(&owner, owner_p, sizeof(owner));
if (ret)
- return ret;
+ return -EFAULT;

switch (owner.type) {
case F_OWNER_TID:
@@ -332,8 +332,11 @@ static int f_getown_ex(struct file *filp, unsigned long arg)
}
read_unlock(&filp->f_owner.lock);

- if (!ret)
+ if (!ret) {
ret = copy_to_user(owner_p, &owner, sizeof(owner));
+ if (ret)
+ ret = -EFAULT;
+ }
return ret;
}

2010-06-03 10:42:12

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [patch v2] fcntl: return -EFAULT if copy_to_user fails

On Thu, 2010-06-03 at 12:35 +0200, Dan Carpenter wrote:
> copy_to_user() returns the number of bytes remaining, but we want to
> return -EFAULT.
> ret = fcntl(fd, F_SETOWN_EX, NULL);
> With the original code ret would be 8 here.
>
> V2: Takuya Yoshikawa pointed out a similar issue in f_getown_ex()
>
> Signed-off-by: Dan Carpenter <[email protected]>

Acked-by: Peter Zijlstra <[email protected]>

> diff --git a/fs/fcntl.c b/fs/fcntl.c
> index f74d270..51e11bf 100644
> --- a/fs/fcntl.c
> +++ b/fs/fcntl.c
> @@ -274,7 +274,7 @@ static int f_setown_ex(struct file *filp, unsigned long arg)
>
> ret = copy_from_user(&owner, owner_p, sizeof(owner));
> if (ret)
> - return ret;
> + return -EFAULT;
>
> switch (owner.type) {
> case F_OWNER_TID:
> @@ -332,8 +332,11 @@ static int f_getown_ex(struct file *filp, unsigned long arg)
> }
> read_unlock(&filp->f_owner.lock);
>
> - if (!ret)
> + if (!ret) {
> ret = copy_to_user(owner_p, &owner, sizeof(owner));
> + if (ret)
> + ret = -EFAULT;
> + }
> return ret;
> }
>

2010-06-03 11:59:21

by Jens Axboe

[permalink] [raw]
Subject: Re: [patch v2] fcntl: return -EFAULT if copy_to_user fails

On 2010-06-03 12:35, Dan Carpenter wrote:
> copy_to_user() returns the number of bytes remaining, but we want to
> return -EFAULT.
> ret = fcntl(fd, F_SETOWN_EX, NULL);
> With the original code ret would be 8 here.
>
> V2: Takuya Yoshikawa pointed out a similar issue in f_getown_ex()

Pretty basic bug, how long has this been there?

Acked-by: Jens Axboe <[email protected]>

--
Jens Axboe

2010-06-03 12:12:44

by Takuya Yoshikawa

[permalink] [raw]
Subject: Re: [patch v2] fcntl: return -EFAULT if copy_to_user fails

(2010/06/03 20:59), Jens Axboe wrote:
> On 2010-06-03 12:35, Dan Carpenter wrote:
>> copy_to_user() returns the number of bytes remaining, but we want to
>> return -EFAULT.
>> ret = fcntl(fd, F_SETOWN_EX, NULL);
>> With the original code ret would be 8 here.
>>
>> V2: Takuya Yoshikawa pointed out a similar issue in f_getown_ex()
>
> Pretty basic bug, how long has this been there?

IIUC, from the beginning, when these were introduced.

And I recently sent similar bug fixes for other parts.

Ah, I also saw somebody sent cleanup patches using memdup_user() which does
not reside in uaccess.h.

Though I'm personally using private *_user documentation,
are there any good official doc for these?

Takuya



>
> Acked-by: Jens Axboe<[email protected]>
>

2010-06-03 12:38:12

by Eric Dumazet

[permalink] [raw]
Subject: Re: [patch v2] fcntl: return -EFAULT if copy_to_user fails

Le jeudi 03 juin 2010 à 21:16 +0900, Takuya Yoshikawa a écrit :
> (2010/06/03 20:59), Jens Axboe wrote:
> > On 2010-06-03 12:35, Dan Carpenter wrote:
> >> copy_to_user() returns the number of bytes remaining, but we want to
> >> return -EFAULT.
> >> ret = fcntl(fd, F_SETOWN_EX, NULL);
> >> With the original code ret would be 8 here.
> >>
> >> V2: Takuya Yoshikawa pointed out a similar issue in f_getown_ex()
> >
> > Pretty basic bug, how long has this been there?
>
> IIUC, from the beginning, when these were introduced.

Maybe copy_to_user() was changed sometime to return a partial count
instead of EFAULT ?

I do think we should have a set of helper functions, instead of
spreading special EFAULT cases in one housand places...

This is really ugly.

static inline int sec_copy_to_user(arg1, arg2, arg3)
{
int res = copy_to_user(arg1, arg2, arg3);

return (res > 0) ? -EFAULT : res;
}


2010-06-03 12:45:58

by Dan Carpenter

[permalink] [raw]
Subject: Re: [patch v2] fcntl: return -EFAULT if copy_to_user fails

On Thu, Jun 03, 2010 at 09:16:52PM +0900, Takuya Yoshikawa wrote:
> (2010/06/03 20:59), Jens Axboe wrote:
>> On 2010-06-03 12:35, Dan Carpenter wrote:
>>> copy_to_user() returns the number of bytes remaining, but we want to
>>> return -EFAULT.
>>> ret = fcntl(fd, F_SETOWN_EX, NULL);
>>> With the original code ret would be 8 here.
>>>
>>> V2: Takuya Yoshikawa pointed out a similar issue in f_getown_ex()
>>
>> Pretty basic bug, how long has this been there?
>
> IIUC, from the beginning, when these were introduced.
>
> And I recently sent similar bug fixes for other parts.
>

It was your clear_user() patch which inspired me. I wrote a smatch
check to find these. I've pushed the code to the smatch repo.
http://repo.or.cz/r/smatch.git

The heuristic I use is that if we return a variable which is the
return value of copy_to_user() and it's non-zero then complain. It
didn't find the f_getown_ex() because that return value could come from
copy_to_user() or it could be -EINVAL.

I'll mess with it a bit and see if I can make it catch the f_getown_ex()
bug.

regards,
dan carpenter

2010-06-03 12:46:05

by Al Viro

[permalink] [raw]
Subject: Re: [patch] fcntl: return -EFAULT if copy_to_user fails

On Thu, Jun 03, 2010 at 07:22:34PM +0900, Takuya Yoshikawa wrote:
> (2010/06/03 19:04), Dan Carpenter wrote:
> >copy_to_user() returns the number of bytes remaining, but we want to
> >return -EFAULT.
> >
> > ret = fcntl(fd, F_SETOWN_EX, NULL);
> >
> >With the original code ret would be 8 here.
> >
> >Signed-off-by: Dan Carpenter<[email protected]>
>
> How about f_getown_ex() ?
>
> if (!ret)
> ret = copy_to_user(owner_p, &owner, sizeof(owner));
> return ret;
>
> Fixing this too would be better, I think.
>
> Takuya

Applied, will push today.

2010-06-03 13:10:54

by Nick Piggin

[permalink] [raw]
Subject: Re: [patch v2] fcntl: return -EFAULT if copy_to_user fails

On Thu, Jun 03, 2010 at 02:38:03PM +0200, Eric Dumazet wrote:
> Le jeudi 03 juin 2010 ? 21:16 +0900, Takuya Yoshikawa a ?crit :
> > (2010/06/03 20:59), Jens Axboe wrote:
> > > On 2010-06-03 12:35, Dan Carpenter wrote:
> > >> copy_to_user() returns the number of bytes remaining, but we want to
> > >> return -EFAULT.
> > >> ret = fcntl(fd, F_SETOWN_EX, NULL);
> > >> With the original code ret would be 8 here.
> > >>
> > >> V2: Takuya Yoshikawa pointed out a similar issue in f_getown_ex()
> > >
> > > Pretty basic bug, how long has this been there?
> >
> > IIUC, from the beginning, when these were introduced.
>
> Maybe copy_to_user() was changed sometime to return a partial count
> instead of EFAULT ?

I think it's been like that since first introduced. Some functions
do need to know in order to do partial copies.


> I do think we should have a set of helper functions, instead of
> spreading special EFAULT cases in one housand places...
>
> This is really ugly.
>
> static inline int sec_copy_to_user(arg1, arg2, arg3)
> {
> int res = copy_to_user(arg1, arg2, arg3);
>
> return (res > 0) ? -EFAULT : res;
> }

It would be unfortunate if it adds more confusion. I'd prefer to have
a sufficiently different name. memcpy_to_user/memcpy_from_user
perhaps?

2010-06-03 13:20:18

by Takuya Yoshikawa

[permalink] [raw]
Subject: Re: [patch v2] fcntl: return -EFAULT if copy_to_user fails

(2010/06/03 22:10), Nick Piggin wrote:
> On Thu, Jun 03, 2010 at 02:38:03PM +0200, Eric Dumazet wrote:
>> Le jeudi 03 juin 2010 ? 21:16 +0900, Takuya Yoshikawa a ?crit :
>>> (2010/06/03 20:59), Jens Axboe wrote:
>>>> On 2010-06-03 12:35, Dan Carpenter wrote:
>>>>> copy_to_user() returns the number of bytes remaining, but we want to
>>>>> return -EFAULT.
>>>>> ret = fcntl(fd, F_SETOWN_EX, NULL);
>>>>> With the original code ret would be 8 here.
>>>>>
>>>>> V2: Takuya Yoshikawa pointed out a similar issue in f_getown_ex()
>>>>
>>>> Pretty basic bug, how long has this been there?
>>>
>>> IIUC, from the beginning, when these were introduced.
>>
>> Maybe copy_to_user() was changed sometime to return a partial count
>> instead of EFAULT ?
>
> I think it's been like that since first introduced. Some functions
> do need to know in order to do partial copies.
>
>
>> I do think we should have a set of helper functions, instead of
>> spreading special EFAULT cases in one housand places...
>>
>> This is really ugly.
>>
>> static inline int sec_copy_to_user(arg1, arg2, arg3)
>> {
>> int res = copy_to_user(arg1, arg2, arg3);
>>
>> return (res> 0) ? -EFAULT : res;
>> }
>
> It would be unfortunate if it adds more confusion. I'd prefer to have
> a sufficiently different name. memcpy_to_user/memcpy_from_user
> perhaps?

Then, and memclear_user() ?

>

2010-06-03 13:42:57

by Eric Dumazet

[permalink] [raw]
Subject: Re: [patch v2] fcntl: return -EFAULT if copy_to_user fails

Le jeudi 03 juin 2010 à 22:24 +0900, Takuya Yoshikawa a écrit :
> (2010/06/03 22:10), Nick Piggin wrote:
> > On Thu, Jun 03, 2010 at 02:38:03PM +0200, Eric Dumazet wrote:

> >> This is really ugly.
> >>
> >> static inline int sec_copy_to_user(arg1, arg2, arg3)
> >> {
> >> int res = copy_to_user(arg1, arg2, arg3);
> >>
> >> return (res> 0) ? -EFAULT : res;
> >> }
> >
> > It would be unfortunate if it adds more confusion. I'd prefer to have
> > a sufficiently different name. memcpy_to_user/memcpy_from_user
> > perhaps?
>
> Then, and memclear_user() ?
>
> >
>

We are interested by the fact that full copy is done, so maybe use the
'full' prefix ?

fullcopy_to_user() , fullclear_user() ?


2010-06-04 11:14:46

by Dan Carpenter

[permalink] [raw]
Subject: Re: [patch v2] fcntl: return -EFAULT if copy_to_user fails

On Thu, Jun 03, 2010 at 02:45:36PM +0200, Dan Carpenter wrote:
> The heuristic I use is that if we return a variable which is the
> return value of copy_to_user() and it's non-zero then complain. It
> didn't find the f_getown_ex() because that return value could come from
> copy_to_user() or it could be -EINVAL.
>
> I'll mess with it a bit and see if I can make it catch the f_getown_ex()
> bug.
>

I changed the heuristic to complain if we return a non-zero return from
copy_to_user() and the minimum possible value of the return is not zero.

ret = copy_to_user();
if (ret)
return ret; // <- Complain. The minimum value is 1.

Or:

if (!foo)
ret = -ENOMEM;
if (!ret)
ret = copy_to_user();
return ret; // <- Complain. The minimum value is -ENOMEM.

This seems to work pretty well. I've fixed all the bugs this found and
I've pushed the check to the smatch repo.

regards,
dan carpenter