aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-04-15 20:23:00 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-04-15 20:23:00 -0400
commit12e993b89464707398e4209bd99983e376454985 (patch)
tree1cf84a342cb63bf3c89c4b9a1f1d49a9f65f35ed
parentebfc5b802fa76baeb4371311ff9fc27a2258d90d (diff)
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 92ae03f2ef99 ("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: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/x86/lib/usercopy.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/arch/x86/lib/usercopy.c b/arch/x86/lib/usercopy.c
index 57252c928f56..d6ae30bbd7bb 100644
--- a/arch/x86/lib/usercopy.c
+++ b/arch/x86/lib/usercopy.c
@@ -57,7 +57,7 @@ static inline unsigned long count_bytes(unsigned long mask)
57 * hit it), 'max' is the address space maximum (and we return 57 * hit it), 'max' is the address space maximum (and we return
58 * -EFAULT if we hit it). 58 * -EFAULT if we hit it).
59 */ 59 */
60static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, long max) 60static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, unsigned long max)
61{ 61{
62 long res = 0; 62 long res = 0;
63 63
@@ -100,7 +100,7 @@ static inline long do_strncpy_from_user(char *dst, const char __user *src, long
100 * too? If so, that's ok - we got as much as the user asked for. 100 * too? If so, that's ok - we got as much as the user asked for.
101 */ 101 */
102 if (res >= count) 102 if (res >= count)
103 return count; 103 return res;
104 104
105 /* 105 /*
106 * Nope: we hit the address space limit, and we still had more 106 * Nope: we hit the address space limit, and we still had more