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

tools/testing/selftests/sysctl: validate sysctl_writes_strict

This adds several behavioral tests to sysctl string and number writing
to detect unexpected cases that behaved differently when the sysctl
kernel.sysctl_writes_strict != 1.

[ original ]
root@localhost:~# make test_num
== Testing sysctl behavior against /proc/sys/kernel/domainname ==
Writing test file ... ok
Checking sysctl is not set to test value ... ok
Writing sysctl from shell ... ok
Resetting sysctl to original value ... ok
Writing entire sysctl in single write ... ok
Writing middle of sysctl after synchronized seek ... FAIL
Writing beyond end of sysctl ... FAIL
Writing sysctl with multiple long writes ... FAIL
Writing entire sysctl in short writes ... FAIL
Writing middle of sysctl after unsynchronized seek ... ok
Checking sysctl maxlen is at least 65 ... ok
Checking sysctl keeps original string on overflow append ... FAIL
Checking sysctl stays NULL terminated on write ... ok
Checking sysctl stays NULL terminated on overwrite ... ok
make: *** [test_num] Error 1
root@localhost:~# make test_string
== Testing sysctl behavior against /proc/sys/vm/swappiness ==
Writing test file ... ok
Checking sysctl is not set to test value ... ok
Writing sysctl from shell ... ok
Resetting sysctl to original value ... ok
Writing entire sysctl in single write ... ok
Writing middle of sysctl after synchronized seek ... FAIL
Writing beyond end of sysctl ... FAIL
Writing sysctl with multiple long writes ... ok
make: *** [test_string] Error 1

[ with CONFIG_PROC_SYSCTL_STRICT_WRITES ]
root@localhost:~# make run_tests
== Testing sysctl behavior against /proc/sys/kernel/domainname ==
Writing test file ... ok
Checking sysctl is not set to test value ... ok
Writing sysctl from shell ... ok
Resetting sysctl to original value ... ok
Writing entire sysctl in single write ... ok
Writing middle of sysctl after synchronized seek ... ok
Writing beyond end of sysctl ... ok
Writing sysctl with multiple long writes ... ok
Writing entire sysctl in short writes ... ok
Writing middle of sysctl after unsynchronized seek ... ok
Checking sysctl maxlen is at least 65 ... ok
Checking sysctl keeps original string on overflow append ... ok
Checking sysctl stays NULL terminated on write ... ok
Checking sysctl stays NULL terminated on overwrite ... ok
== Testing sysctl behavior against /proc/sys/vm/swappiness ==
Writing test file ... ok
Checking sysctl is not set to test value ... ok
Writing sysctl from shell ... ok
Resetting sysctl to original value ... ok
Writing entire sysctl in single write ... ok
Writing middle of sysctl after synchronized seek ... ok
Writing beyond end of sysctl ... ok
Writing sysctl with multiple long writes ... ok

Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Kees Cook and committed by
Linus Torvalds
24fe831c f4aacea2

+216
+1
tools/testing/selftests/Makefile
··· 10 10 TARGETS += vm 11 11 TARGETS += powerpc 12 12 TARGETS += user 13 + TARGETS += sysctl 13 14 14 15 all: 15 16 for TARGET in $(TARGETS); do \
+19
tools/testing/selftests/sysctl/Makefile
··· 1 + # Makefile for sysctl selftests. 2 + # Expects kernel.sysctl_writes_strict=1. 3 + 4 + # No binaries, but make sure arg-less "make" doesn't trigger "run_tests". 5 + all: 6 + 7 + # Allow specific tests to be selected. 8 + test_num: 9 + @/bin/sh ./run_numerictests 10 + 11 + test_string: 12 + @/bin/sh ./run_stringtests 13 + 14 + run_tests: all test_num test_string 15 + 16 + # Nothing to clean up. 17 + clean: 18 + 19 + .PHONY: all run_tests clean test_num test_string
+109
tools/testing/selftests/sysctl/common_tests
··· 1 + #!/bin/sh 2 + 3 + TEST_FILE=$(mktemp) 4 + 5 + echo "== Testing sysctl behavior against ${TARGET} ==" 6 + 7 + set_orig() 8 + { 9 + echo "${ORIG}" > "${TARGET}" 10 + } 11 + 12 + set_test() 13 + { 14 + echo "${TEST_STR}" > "${TARGET}" 15 + } 16 + 17 + verify() 18 + { 19 + local seen 20 + seen=$(cat "$1") 21 + if [ "${seen}" != "${TEST_STR}" ]; then 22 + return 1 23 + fi 24 + return 0 25 + } 26 + 27 + trap 'set_orig; rm -f "${TEST_FILE}"' EXIT 28 + 29 + rc=0 30 + 31 + echo -n "Writing test file ... " 32 + echo "${TEST_STR}" > "${TEST_FILE}" 33 + if ! verify "${TEST_FILE}"; then 34 + echo "FAIL" >&2 35 + exit 1 36 + else 37 + echo "ok" 38 + fi 39 + 40 + echo -n "Checking sysctl is not set to test value ... " 41 + if verify "${TARGET}"; then 42 + echo "FAIL" >&2 43 + exit 1 44 + else 45 + echo "ok" 46 + fi 47 + 48 + echo -n "Writing sysctl from shell ... " 49 + set_test 50 + if ! verify "${TARGET}"; then 51 + echo "FAIL" >&2 52 + exit 1 53 + else 54 + echo "ok" 55 + fi 56 + 57 + echo -n "Resetting sysctl to original value ... " 58 + set_orig 59 + if verify "${TARGET}"; then 60 + echo "FAIL" >&2 61 + exit 1 62 + else 63 + echo "ok" 64 + fi 65 + 66 + # Now that we've validated the sanity of "set_test" and "set_orig", 67 + # we can use those functions to set starting states before running 68 + # specific behavioral tests. 69 + 70 + echo -n "Writing entire sysctl in single write ... " 71 + set_orig 72 + dd if="${TEST_FILE}" of="${TARGET}" bs=4096 2>/dev/null 73 + if ! verify "${TARGET}"; then 74 + echo "FAIL" >&2 75 + rc=1 76 + else 77 + echo "ok" 78 + fi 79 + 80 + echo -n "Writing middle of sysctl after synchronized seek ... " 81 + set_test 82 + dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 skip=1 2>/dev/null 83 + if ! verify "${TARGET}"; then 84 + echo "FAIL" >&2 85 + rc=1 86 + else 87 + echo "ok" 88 + fi 89 + 90 + echo -n "Writing beyond end of sysctl ... " 91 + set_orig 92 + dd if="${TEST_FILE}" of="${TARGET}" bs=20 seek=2 2>/dev/null 93 + if verify "${TARGET}"; then 94 + echo "FAIL" >&2 95 + rc=1 96 + else 97 + echo "ok" 98 + fi 99 + 100 + echo -n "Writing sysctl with multiple long writes ... " 101 + set_orig 102 + (perl -e 'print "A" x 50;'; echo "${TEST_STR}") | \ 103 + dd of="${TARGET}" bs=50 2>/dev/null 104 + if verify "${TARGET}"; then 105 + echo "FAIL" >&2 106 + rc=1 107 + else 108 + echo "ok" 109 + fi
+10
tools/testing/selftests/sysctl/run_numerictests
··· 1 + #!/bin/sh 2 + 3 + SYSCTL="/proc/sys" 4 + TARGET="${SYSCTL}/vm/swappiness" 5 + ORIG=$(cat "${TARGET}") 6 + TEST_STR=$(( $ORIG + 1 )) 7 + 8 + . ./common_tests 9 + 10 + exit $rc
+77
tools/testing/selftests/sysctl/run_stringtests
··· 1 + #!/bin/sh 2 + 3 + SYSCTL="/proc/sys" 4 + TARGET="${SYSCTL}/kernel/domainname" 5 + ORIG=$(cat "${TARGET}") 6 + TEST_STR="Testing sysctl" 7 + 8 + . ./common_tests 9 + 10 + # Only string sysctls support seeking/appending. 11 + MAXLEN=65 12 + 13 + echo -n "Writing entire sysctl in short writes ... " 14 + set_orig 15 + dd if="${TEST_FILE}" of="${TARGET}" bs=1 2>/dev/null 16 + if ! verify "${TARGET}"; then 17 + echo "FAIL" >&2 18 + rc=1 19 + else 20 + echo "ok" 21 + fi 22 + 23 + echo -n "Writing middle of sysctl after unsynchronized seek ... " 24 + set_test 25 + dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 2>/dev/null 26 + if verify "${TARGET}"; then 27 + echo "FAIL" >&2 28 + rc=1 29 + else 30 + echo "ok" 31 + fi 32 + 33 + echo -n "Checking sysctl maxlen is at least $MAXLEN ... " 34 + set_orig 35 + perl -e 'print "A" x ('"${MAXLEN}"'-2), "B";' | \ 36 + dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null 37 + if ! grep -q B "${TARGET}"; then 38 + echo "FAIL" >&2 39 + rc=1 40 + else 41 + echo "ok" 42 + fi 43 + 44 + echo -n "Checking sysctl keeps original string on overflow append ... " 45 + set_orig 46 + perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \ 47 + dd of="${TARGET}" bs=$(( MAXLEN - 1 )) 2>/dev/null 48 + if grep -q B "${TARGET}"; then 49 + echo "FAIL" >&2 50 + rc=1 51 + else 52 + echo "ok" 53 + fi 54 + 55 + echo -n "Checking sysctl stays NULL terminated on write ... " 56 + set_orig 57 + perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \ 58 + dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null 59 + if grep -q B "${TARGET}"; then 60 + echo "FAIL" >&2 61 + rc=1 62 + else 63 + echo "ok" 64 + fi 65 + 66 + echo -n "Checking sysctl stays NULL terminated on overwrite ... " 67 + set_orig 68 + perl -e 'print "A" x ('"${MAXLEN}"'-1), "BB";' | \ 69 + dd of="${TARGET}" bs=$(( $MAXLEN + 1 )) 2>/dev/null 70 + if grep -q B "${TARGET}"; then 71 + echo "FAIL" >&2 72 + rc=1 73 + else 74 + echo "ok" 75 + fi 76 + 77 + exit $rc