Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sysctl: fix int -> unsigned long assignments in INT_MIN case

The following

if (val < 0)
*lvalp = (unsigned long)-val;

is incorrect because the compiler is free to assume -val to be positive
and use a sign-extend instruction for extending the bit pattern. This is
a problem if val == INT_MIN:

# echo -2147483648 >/proc/sys/dev/scsi/logging_level
# cat /proc/sys/dev/scsi/logging_level
-18446744071562067968

Cast to unsigned long before negation - that way we first sign-extend and
then negate an unsigned, which is well defined. With this:

# cat /proc/sys/dev/scsi/logging_level
-2147483648

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Cc: Mikulas Patocka <mikulas@twibright.com>
Cc: Robert Xiao <nneonneo@gmail.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Kees Cook <keescook@chromium.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Ilya Dryomov and committed by
Linus Torvalds
9a5bc726 1303a27c

+5 -5
+5 -5
kernel/sysctl.c
··· 1995 1995 int val = *valp; 1996 1996 if (val < 0) { 1997 1997 *negp = true; 1998 - *lvalp = (unsigned long)-val; 1998 + *lvalp = -(unsigned long)val; 1999 1999 } else { 2000 2000 *negp = false; 2001 2001 *lvalp = (unsigned long)val; ··· 2201 2201 int val = *valp; 2202 2202 if (val < 0) { 2203 2203 *negp = true; 2204 - *lvalp = (unsigned long)-val; 2204 + *lvalp = -(unsigned long)val; 2205 2205 } else { 2206 2206 *negp = false; 2207 2207 *lvalp = (unsigned long)val; ··· 2436 2436 unsigned long lval; 2437 2437 if (val < 0) { 2438 2438 *negp = true; 2439 - lval = (unsigned long)-val; 2439 + lval = -(unsigned long)val; 2440 2440 } else { 2441 2441 *negp = false; 2442 2442 lval = (unsigned long)val; ··· 2459 2459 unsigned long lval; 2460 2460 if (val < 0) { 2461 2461 *negp = true; 2462 - lval = (unsigned long)-val; 2462 + lval = -(unsigned long)val; 2463 2463 } else { 2464 2464 *negp = false; 2465 2465 lval = (unsigned long)val; ··· 2484 2484 unsigned long lval; 2485 2485 if (val < 0) { 2486 2486 *negp = true; 2487 - lval = (unsigned long)-val; 2487 + lval = -(unsigned long)val; 2488 2488 } else { 2489 2489 *negp = false; 2490 2490 lval = (unsigned long)val;