tools/testing/selftests/sysctl/sysctl.sh: add tests for >32-bit values written to...
authorZev Weiss <zev@bewilderbeest.net>
Tue, 12 Mar 2019 06:27:58 +0000 (23:27 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 12 Mar 2019 17:04:00 +0000 (10:04 -0700)
Patch series "sysctl: fix range-checking in do_proc_dointvec_minmax_conv()", v2.

After being left with an unusable system after a typo executing
something like 'echo $((1<<24)) > /proc/sys/vm/max_map_count', I found
that do_proc_dointvec_minmax_conv() was missing a check to ensure that
the converted value actually fits in an int.

The first of the following patches enhances the sysctl selftest such
that it detects this problem; the second provides a minimal fix
(suitable for -stable) such that the selftest passes.  The third patch
then performs a more thorough refactoring to eliminate the code
duplication that led to the bug in the first place (maintaining the
passing status of the selftest).

This patch (of 3):

At present this exposes a bug in do_proc_dointvec_minmax_conv() (it
fails to check for values that are too wide to fit in an int).

Link: http://lkml.kernel.org/r/20190207123426.9202-2-zev@bewilderbeest.net
Signed-off-by: Zev Weiss <zev@bewilderbeest.net>
Cc: Luis Chamberlain <mcgrof@kernel.org>
Cc: Kees Cook <keescook@chromium.org>
Cc: Brendan Higgins <brendanhiggins@google.com>
Cc: Iurii Zaikin <yzaikin@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
tools/testing/selftests/sysctl/sysctl.sh

index 584eb8ea780a49220782d08e104756199fc19934..780ce71233743f4c3b9b36e9435f9eae2d676641 100755 (executable)
@@ -290,6 +290,58 @@ run_numerictests()
        test_rc
 }
 
+check_failure()
+{
+       echo -n "Testing that $1 fails as expected..."
+       reset_vals
+       TEST_STR="$1"
+       orig="$(cat $TARGET)"
+       echo -n "$TEST_STR" > $TARGET 2> /dev/null
+
+       # write should fail and $TARGET should retain its original value
+       if [ $? = 0 ] || [ "$(cat $TARGET)" != "$orig" ]; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+       test_rc
+}
+
+run_wideint_tests()
+{
+       # sysctl conversion functions receive a boolean sign and ulong
+       # magnitude; here we list the magnitudes we want to test (each of
+       # which will be tested in both positive and negative forms).  Since
+       # none of these values fit in 32 bits, writing them to an int- or
+       # uint-typed sysctl should fail.
+       local magnitudes=(
+               # common boundary-condition values (zero, +1, -1, INT_MIN,
+               # and INT_MAX respectively) if truncated to lower 32 bits
+               # (potential for being falsely deemed in range)
+               0x0000000100000000
+               0x0000000100000001
+               0x00000001ffffffff
+               0x0000000180000000
+               0x000000017fffffff
+
+               # these look like negatives, but without a leading '-' are
+               # actually large positives (should be rejected as above
+               # despite being zero/+1/-1/INT_MIN/INT_MAX in the lower 32)
+               0xffffffff00000000
+               0xffffffff00000001
+               0xffffffffffffffff
+               0xffffffff80000000
+               0xffffffff7fffffff
+       )
+
+       for sign in '' '-'; do
+               for mag in "${magnitudes[@]}"; do
+                       check_failure "${sign}${mag}"
+               done
+       done
+}
+
 # Your test must accept digits 3 and 4 to use this
 run_limit_digit()
 {
@@ -556,6 +608,7 @@ sysctl_test_0001()
        TEST_STR=$(( $ORIG + 1 ))
 
        run_numerictests
+       run_wideint_tests
        run_limit_digit
 }
 
@@ -580,6 +633,7 @@ sysctl_test_0003()
        TEST_STR=$(( $ORIG + 1 ))
 
        run_numerictests
+       run_wideint_tests
        run_limit_digit
        run_limit_digit_int
 }
@@ -592,6 +646,7 @@ sysctl_test_0004()
        TEST_STR=$(( $ORIG + 1 ))
 
        run_numerictests
+       run_wideint_tests
        run_limit_digit
        run_limit_digit_uint
 }