Commit fec52486 authored by Zev Weiss's avatar Zev Weiss Committed by Linus Torvalds
Browse files

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: default avatarZev 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent a089e4fe
Loading
Loading
Loading
Loading
+55 −0
Original line number Diff line number Diff line
@@ -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
}