diff options
author | Ilya Dryomov <idryomov@gmail.com> | 2015-09-09 15:39:06 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-10 13:29:01 -0700 |
commit | 9a5bc726d559221a3394bb8ef97d0abc1ee94d00 (patch) | |
tree | 8d6bcc02409b4754e9641488b03599b28af8e6e4 /kernel/sysctl.c | |
parent | 1303a27c9c32020a3b6ac89be270d2ab1f28be24 (diff) | |
download | linux-9a5bc726d559221a3394bb8ef97d0abc1ee94d00.tar.gz linux-9a5bc726d559221a3394bb8ef97d0abc1ee94d00.tar.bz2 linux-9a5bc726d559221a3394bb8ef97d0abc1ee94d00.zip |
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>
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r-- | kernel/sysctl.c | 10 |
1 files changed, 5 insertions, 5 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 715cc57cc66a..e69201d8094e 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1995,7 +1995,7 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, int val = *valp; if (val < 0) { *negp = true; - *lvalp = (unsigned long)-val; + *lvalp = -(unsigned long)val; } else { *negp = false; *lvalp = (unsigned long)val; @@ -2201,7 +2201,7 @@ static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp, int val = *valp; if (val < 0) { *negp = true; - *lvalp = (unsigned long)-val; + *lvalp = -(unsigned long)val; } else { *negp = false; *lvalp = (unsigned long)val; @@ -2436,7 +2436,7 @@ static int do_proc_dointvec_jiffies_conv(bool *negp, unsigned long *lvalp, unsigned long lval; if (val < 0) { *negp = true; - lval = (unsigned long)-val; + lval = -(unsigned long)val; } else { *negp = false; lval = (unsigned long)val; @@ -2459,7 +2459,7 @@ static int do_proc_dointvec_userhz_jiffies_conv(bool *negp, unsigned long *lvalp unsigned long lval; if (val < 0) { *negp = true; - lval = (unsigned long)-val; + lval = -(unsigned long)val; } else { *negp = false; lval = (unsigned long)val; @@ -2484,7 +2484,7 @@ static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp, unsigned long lval; if (val < 0) { *negp = true; - lval = (unsigned long)-val; + lval = -(unsigned long)val; } else { *negp = false; lval = (unsigned long)val; |