tools/testing/selftests/sysctl/sysctl.sh: add tests for >32-bit values written to 32-bit integers

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>
This commit is contained in:
Zev Weiss 2019-03-11 23:27:58 -07:00 committed by Linus Torvalds
parent a089e4fed5
commit fec5248668
1 changed files with 55 additions and 0 deletions

View File

@ -290,6 +290,58 @@ run_numerictests()
test_rc 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 # Your test must accept digits 3 and 4 to use this
run_limit_digit() run_limit_digit()
{ {
@ -556,6 +608,7 @@ sysctl_test_0001()
TEST_STR=$(( $ORIG + 1 )) TEST_STR=$(( $ORIG + 1 ))
run_numerictests run_numerictests
run_wideint_tests
run_limit_digit run_limit_digit
} }
@ -580,6 +633,7 @@ sysctl_test_0003()
TEST_STR=$(( $ORIG + 1 )) TEST_STR=$(( $ORIG + 1 ))
run_numerictests run_numerictests
run_wideint_tests
run_limit_digit run_limit_digit
run_limit_digit_int run_limit_digit_int
} }
@ -592,6 +646,7 @@ sysctl_test_0004()
TEST_STR=$(( $ORIG + 1 )) TEST_STR=$(( $ORIG + 1 ))
run_numerictests run_numerictests
run_wideint_tests
run_limit_digit run_limit_digit
run_limit_digit_uint run_limit_digit_uint
} }