Commit 12e993b8 authored by Linus Torvalds's avatar Linus Torvalds

x86-32: fix up strncpy_from_user() sign error

The 'max' range needs to be unsigned, since the size of the user address
space is bigger than 2GB.

We know that 'count' is positive in 'long' (that is checked in the
caller), so we will truncate 'max' down to something that fits in a
signed long, but before we actually do that, that comparison needs to be
done in unsigned.

Bug introduced in commit 92ae03f2 ("x86: merge 32/64-bit versions of
'strncpy_from_user()' and speed it up").  On x86-64 you can't trigger
this, since the user address space is much smaller than 63 bits, and on
x86-32 it works in practice, since you would seldom hit the strncpy
limits anyway.

I had actually tested the corner-cases, I had only tested them on
x86-64.  Besides, I had only worried about the case of a pointer *close*
to the end of the address space, rather than really far away from it ;)

This also changes the "we hit the user-specified maximum" to return
'res', for the trivial reason that gcc seems to generate better code
that way.  'res' and 'count' are the same in that case, so it really
doesn't matter which one we return.
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent ebfc5b80
...@@ -57,7 +57,7 @@ static inline unsigned long count_bytes(unsigned long mask) ...@@ -57,7 +57,7 @@ static inline unsigned long count_bytes(unsigned long mask)
* hit it), 'max' is the address space maximum (and we return * hit it), 'max' is the address space maximum (and we return
* -EFAULT if we hit it). * -EFAULT if we hit it).
*/ */
static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, long max) static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, unsigned long max)
{ {
long res = 0; long res = 0;
...@@ -100,7 +100,7 @@ static inline long do_strncpy_from_user(char *dst, const char __user *src, long ...@@ -100,7 +100,7 @@ static inline long do_strncpy_from_user(char *dst, const char __user *src, long
* too? If so, that's ok - we got as much as the user asked for. * too? If so, that's ok - we got as much as the user asked for.
*/ */
if (res >= count) if (res >= count)
return count; return res;
/* /*
* Nope: we hit the address space limit, and we still had more * Nope: we hit the address space limit, and we still had more
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment