0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039 set -e
0040
0041 TEST_NAME="kmod"
0042 TEST_DRIVER="test_${TEST_NAME}"
0043 TEST_DIR=$(dirname $0)
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055 ALL_TESTS="0001:3:1"
0056 ALL_TESTS="$ALL_TESTS 0002:3:1"
0057 ALL_TESTS="$ALL_TESTS 0003:1:1"
0058 ALL_TESTS="$ALL_TESTS 0004:1:1"
0059 ALL_TESTS="$ALL_TESTS 0005:10:1"
0060 ALL_TESTS="$ALL_TESTS 0006:10:1"
0061 ALL_TESTS="$ALL_TESTS 0007:5:1"
0062 ALL_TESTS="$ALL_TESTS 0008:150:1"
0063 ALL_TESTS="$ALL_TESTS 0009:150:1"
0064 ALL_TESTS="$ALL_TESTS 0010:1:1"
0065 ALL_TESTS="$ALL_TESTS 0011:1:1"
0066 ALL_TESTS="$ALL_TESTS 0012:1:1"
0067 ALL_TESTS="$ALL_TESTS 0013:1:1"
0068
0069
0070 ksft_skip=4
0071
0072 test_modprobe()
0073 {
0074 if [ ! -d $DIR ]; then
0075 echo "$0: $DIR not present" >&2
0076 echo "You must have the following enabled in your kernel:" >&2
0077 cat $TEST_DIR/config >&2
0078 exit $ksft_skip
0079 fi
0080 }
0081
0082 function allow_user_defaults()
0083 {
0084 if [ -z $DEFAULT_KMOD_DRIVER ]; then
0085 DEFAULT_KMOD_DRIVER="test_module"
0086 fi
0087
0088 if [ -z $DEFAULT_KMOD_FS ]; then
0089 DEFAULT_KMOD_FS="xfs"
0090 fi
0091
0092 if [ -z $PROC_DIR ]; then
0093 PROC_DIR="/proc/sys/kernel/"
0094 fi
0095
0096 if [ -z $MODPROBE_LIMIT ]; then
0097 MODPROBE_LIMIT=50
0098 fi
0099
0100 if [ -z $DIR ]; then
0101 DIR="/sys/devices/virtual/misc/${TEST_DRIVER}0/"
0102 fi
0103
0104 if [ -z $DEFAULT_NUM_TESTS ]; then
0105 DEFAULT_NUM_TESTS=150
0106 fi
0107
0108 MODPROBE_LIMIT_FILE="${PROC_DIR}/kmod-limit"
0109 }
0110
0111 test_reqs()
0112 {
0113 if ! which modprobe 2> /dev/null > /dev/null; then
0114 echo "$0: You need modprobe installed" >&2
0115 exit $ksft_skip
0116 fi
0117
0118 if ! which kmod 2> /dev/null > /dev/null; then
0119 echo "$0: You need kmod installed" >&2
0120 exit $ksft_skip
0121 fi
0122
0123
0124
0125
0126
0127
0128
0129 KMOD_VERSION=$(kmod --version | awk '{print $3}')
0130 if [[ $KMOD_VERSION -le 19 ]]; then
0131 echo "$0: You need at least kmod 20" >&2
0132 echo "kmod <= 19 is buggy, for details see:" >&2
0133 echo "https://git.kernel.org/cgit/utils/kernel/kmod/kmod.git/commit/libkmod/libkmod-module.c?id=fd44a98ae2eb5eb32161088954ab21e58e19dfc4" >&2
0134 exit $ksft_skip
0135 fi
0136
0137 uid=$(id -u)
0138 if [ $uid -ne 0 ]; then
0139 echo $msg must be run as root >&2
0140 exit $ksft_skip
0141 fi
0142 }
0143
0144 function load_req_mod()
0145 {
0146 trap "test_modprobe" EXIT
0147
0148 if [ ! -d $DIR ]; then
0149
0150 modprobe $TEST_DRIVER
0151 fi
0152 }
0153
0154 test_finish()
0155 {
0156 echo "$MODPROBE" > /proc/sys/kernel/modprobe
0157 echo "Test completed"
0158 }
0159
0160 errno_name_to_val()
0161 {
0162 case "$1" in
0163
0164
0165
0166 MODULE_NOT_FOUND)
0167 echo 256;;
0168 SUCCESS)
0169 echo 0;;
0170 -EPERM)
0171 echo -1;;
0172 -ENOENT)
0173 echo -2;;
0174 -EINVAL)
0175 echo -22;;
0176 -ERR_ANY)
0177 echo -123456;;
0178 *)
0179 echo invalid;;
0180 esac
0181 }
0182
0183 errno_val_to_name()
0184 case "$1" in
0185 256)
0186 echo MODULE_NOT_FOUND;;
0187 0)
0188 echo SUCCESS;;
0189 -1)
0190 echo -EPERM;;
0191 -2)
0192 echo -ENOENT;;
0193 -22)
0194 echo -EINVAL;;
0195 -123456)
0196 echo -ERR_ANY;;
0197 *)
0198 echo invalid;;
0199 esac
0200
0201 config_set_test_case_driver()
0202 {
0203 if ! echo -n 1 >$DIR/config_test_case; then
0204 echo "$0: Unable to set to test case to driver" >&2
0205 exit 1
0206 fi
0207 }
0208
0209 config_set_test_case_fs()
0210 {
0211 if ! echo -n 2 >$DIR/config_test_case; then
0212 echo "$0: Unable to set to test case to fs" >&2
0213 exit 1
0214 fi
0215 }
0216
0217 config_num_threads()
0218 {
0219 if ! echo -n $1 >$DIR/config_num_threads; then
0220 echo "$0: Unable to set to number of threads" >&2
0221 exit 1
0222 fi
0223 }
0224
0225 config_get_modprobe_limit()
0226 {
0227 if [[ -f ${MODPROBE_LIMIT_FILE} ]] ; then
0228 MODPROBE_LIMIT=$(cat $MODPROBE_LIMIT_FILE)
0229 fi
0230 echo $MODPROBE_LIMIT
0231 }
0232
0233 config_num_thread_limit_extra()
0234 {
0235 MODPROBE_LIMIT=$(config_get_modprobe_limit)
0236 let EXTRA_LIMIT=$MODPROBE_LIMIT+$1
0237 config_num_threads $EXTRA_LIMIT
0238 }
0239
0240
0241
0242 config_set_driver()
0243 {
0244 if ! echo -n $1 >$DIR/config_test_driver; then
0245 echo "$0: Unable to set driver" >&2
0246 exit 1
0247 fi
0248 }
0249
0250 config_set_fs()
0251 {
0252 if ! echo -n $1 >$DIR/config_test_fs; then
0253 echo "$0: Unable to set driver" >&2
0254 exit 1
0255 fi
0256 }
0257
0258 config_get_driver()
0259 {
0260 cat $DIR/config_test_driver
0261 }
0262
0263 config_get_test_result()
0264 {
0265 cat $DIR/test_result
0266 }
0267
0268 config_reset()
0269 {
0270 if ! echo -n "1" >"$DIR"/reset; then
0271 echo "$0: reset should have worked" >&2
0272 exit 1
0273 fi
0274 }
0275
0276 config_show_config()
0277 {
0278 echo "----------------------------------------------------"
0279 cat "$DIR"/config
0280 echo "----------------------------------------------------"
0281 }
0282
0283 config_trigger()
0284 {
0285 if ! echo -n "1" >"$DIR"/trigger_config 2>/dev/null; then
0286 echo "$1: FAIL - loading should have worked"
0287 config_show_config
0288 exit 1
0289 fi
0290 echo "$1: OK! - loading kmod test"
0291 }
0292
0293 config_trigger_want_fail()
0294 {
0295 if echo "1" > $DIR/trigger_config 2>/dev/null; then
0296 echo "$1: FAIL - test case was expected to fail"
0297 config_show_config
0298 exit 1
0299 fi
0300 echo "$1: OK! - kmod test case failed as expected"
0301 }
0302
0303 config_expect_result()
0304 {
0305 RC=$(config_get_test_result)
0306 RC_NAME=$(errno_val_to_name $RC)
0307
0308 ERRNO_NAME=$2
0309 ERRNO=$(errno_name_to_val $ERRNO_NAME)
0310
0311 if [[ $ERRNO_NAME = "-ERR_ANY" ]]; then
0312 if [[ $RC -ge 0 ]]; then
0313 echo "$1: FAIL, test expects $ERRNO_NAME - got $RC_NAME ($RC)" >&2
0314 config_show_config
0315 exit 1
0316 fi
0317 elif [[ $RC != $ERRNO ]]; then
0318 echo "$1: FAIL, test expects $ERRNO_NAME ($ERRNO) - got $RC_NAME ($RC)" >&2
0319 config_show_config
0320 exit 1
0321 fi
0322 echo "$1: OK! - Return value: $RC ($RC_NAME), expected $ERRNO_NAME"
0323 }
0324
0325 kmod_defaults_driver()
0326 {
0327 config_reset
0328 modprobe -r $DEFAULT_KMOD_DRIVER
0329 config_set_driver $DEFAULT_KMOD_DRIVER
0330 }
0331
0332 kmod_defaults_fs()
0333 {
0334 config_reset
0335 modprobe -r $DEFAULT_KMOD_FS
0336 config_set_fs $DEFAULT_KMOD_FS
0337 config_set_test_case_fs
0338 }
0339
0340 kmod_test_0001_driver()
0341 {
0342 NAME='\000'
0343
0344 kmod_defaults_driver
0345 config_num_threads 1
0346 printf $NAME >"$DIR"/config_test_driver
0347 config_trigger ${FUNCNAME[0]}
0348 config_expect_result ${FUNCNAME[0]} MODULE_NOT_FOUND
0349 }
0350
0351 kmod_test_0001_fs()
0352 {
0353 NAME='\000'
0354
0355 kmod_defaults_fs
0356 config_num_threads 1
0357 printf $NAME >"$DIR"/config_test_fs
0358 config_trigger ${FUNCNAME[0]}
0359 config_expect_result ${FUNCNAME[0]} -EINVAL
0360 }
0361
0362 kmod_test_0001()
0363 {
0364 kmod_test_0001_driver
0365 kmod_test_0001_fs
0366 }
0367
0368 kmod_test_0002_driver()
0369 {
0370 NAME="nope-$DEFAULT_KMOD_DRIVER"
0371
0372 kmod_defaults_driver
0373 config_set_driver $NAME
0374 config_num_threads 1
0375 config_trigger ${FUNCNAME[0]}
0376 config_expect_result ${FUNCNAME[0]} MODULE_NOT_FOUND
0377 }
0378
0379 kmod_test_0002_fs()
0380 {
0381 NAME="nope-$DEFAULT_KMOD_FS"
0382
0383 kmod_defaults_fs
0384 config_set_fs $NAME
0385 config_trigger ${FUNCNAME[0]}
0386 config_expect_result ${FUNCNAME[0]} -EINVAL
0387 }
0388
0389 kmod_test_0002()
0390 {
0391 kmod_test_0002_driver
0392 kmod_test_0002_fs
0393 }
0394
0395 kmod_test_0003()
0396 {
0397 kmod_defaults_fs
0398 config_num_threads 1
0399 config_trigger ${FUNCNAME[0]}
0400 config_expect_result ${FUNCNAME[0]} SUCCESS
0401 }
0402
0403 kmod_test_0004()
0404 {
0405 kmod_defaults_fs
0406 config_num_threads 2
0407 config_trigger ${FUNCNAME[0]}
0408 config_expect_result ${FUNCNAME[0]} SUCCESS
0409 }
0410
0411 kmod_test_0005()
0412 {
0413 kmod_defaults_driver
0414 config_trigger ${FUNCNAME[0]}
0415 config_expect_result ${FUNCNAME[0]} SUCCESS
0416 }
0417
0418 kmod_test_0006()
0419 {
0420 kmod_defaults_fs
0421 config_trigger ${FUNCNAME[0]}
0422 config_expect_result ${FUNCNAME[0]} SUCCESS
0423 }
0424
0425 kmod_test_0007()
0426 {
0427 kmod_test_0005
0428 kmod_test_0006
0429 }
0430
0431 kmod_test_0008()
0432 {
0433 kmod_defaults_driver
0434 MODPROBE_LIMIT=$(config_get_modprobe_limit)
0435 let EXTRA=$MODPROBE_LIMIT/6
0436 config_num_thread_limit_extra $EXTRA
0437 config_trigger ${FUNCNAME[0]}
0438 config_expect_result ${FUNCNAME[0]} SUCCESS
0439 }
0440
0441 kmod_test_0009()
0442 {
0443 kmod_defaults_fs
0444 MODPROBE_LIMIT=$(config_get_modprobe_limit)
0445 let EXTRA=$MODPROBE_LIMIT/4
0446 config_num_thread_limit_extra $EXTRA
0447 config_trigger ${FUNCNAME[0]}
0448 config_expect_result ${FUNCNAME[0]} SUCCESS
0449 }
0450
0451 kmod_test_0010()
0452 {
0453 kmod_defaults_driver
0454 config_num_threads 1
0455 echo "/KMOD_TEST_NONEXISTENT" > /proc/sys/kernel/modprobe
0456 config_trigger ${FUNCNAME[0]}
0457 config_expect_result ${FUNCNAME[0]} -ENOENT
0458 echo "$MODPROBE" > /proc/sys/kernel/modprobe
0459 }
0460
0461 kmod_test_0011()
0462 {
0463 kmod_defaults_driver
0464 config_num_threads 1
0465
0466
0467
0468
0469 echo > /proc/sys/kernel/modprobe
0470 config_trigger ${FUNCNAME[0]}
0471 config_expect_result ${FUNCNAME[0]} -ENOENT
0472 echo "$MODPROBE" > /proc/sys/kernel/modprobe
0473 }
0474
0475 kmod_check_visibility()
0476 {
0477 local name="$1"
0478 local cmd="$2"
0479
0480 modprobe $DEFAULT_KMOD_DRIVER
0481
0482 local priv=$(eval $cmd)
0483 local unpriv=$(capsh --drop=CAP_SYSLOG -- -c "$cmd")
0484
0485 if [ "$priv" = "$unpriv" ] || \
0486 [ "${priv:0:3}" = "0x0" ] || \
0487 [ "${unpriv:0:3}" != "0x0" ] ; then
0488 echo "${FUNCNAME[0]}: FAIL, $name visible to unpriv: '$priv' vs '$unpriv'" >&2
0489 exit 1
0490 else
0491 echo "${FUNCNAME[0]}: OK!"
0492 fi
0493 }
0494
0495 kmod_test_0012()
0496 {
0497 kmod_check_visibility /proc/modules \
0498 "grep '^${DEFAULT_KMOD_DRIVER}\b' /proc/modules | awk '{print \$NF}'"
0499 }
0500
0501 kmod_test_0013()
0502 {
0503 kmod_check_visibility '/sys/module/*/sections/*' \
0504 "cat /sys/module/${DEFAULT_KMOD_DRIVER}/sections/.*text | head -n1"
0505 }
0506
0507 list_tests()
0508 {
0509 echo "Test ID list:"
0510 echo
0511 echo "TEST_ID x NUM_TEST"
0512 echo "TEST_ID: Test ID"
0513 echo "NUM_TESTS: Number of recommended times to run the test"
0514 echo
0515 echo "0001 x $(get_test_count 0001) - Simple test - 1 thread for empty string"
0516 echo "0002 x $(get_test_count 0002) - Simple test - 1 thread for modules/filesystems that do not exist"
0517 echo "0003 x $(get_test_count 0003) - Simple test - 1 thread for get_fs_type() only"
0518 echo "0004 x $(get_test_count 0004) - Simple test - 2 threads for get_fs_type() only"
0519 echo "0005 x $(get_test_count 0005) - multithreaded tests with default setup - request_module() only"
0520 echo "0006 x $(get_test_count 0006) - multithreaded tests with default setup - get_fs_type() only"
0521 echo "0007 x $(get_test_count 0007) - multithreaded tests with default setup test request_module() and get_fs_type()"
0522 echo "0008 x $(get_test_count 0008) - multithreaded - push kmod_concurrent over max_modprobes for request_module()"
0523 echo "0009 x $(get_test_count 0009) - multithreaded - push kmod_concurrent over max_modprobes for get_fs_type()"
0524 echo "0010 x $(get_test_count 0010) - test nonexistent modprobe path"
0525 echo "0011 x $(get_test_count 0011) - test completely disabling module autoloading"
0526 echo "0012 x $(get_test_count 0012) - test /proc/modules address visibility under CAP_SYSLOG"
0527 echo "0013 x $(get_test_count 0013) - test /sys/module/*/sections/* visibility under CAP_SYSLOG"
0528 }
0529
0530 usage()
0531 {
0532 NUM_TESTS=$(grep -o ' ' <<<"$ALL_TESTS" | grep -c .)
0533 let NUM_TESTS=$NUM_TESTS+1
0534 MAX_TEST=$(printf "%04d\n" $NUM_TESTS)
0535 echo "Usage: $0 [ -t <4-number-digit> ] | [ -w <4-number-digit> ] |"
0536 echo " [ -s <4-number-digit> ] | [ -c <4-number-digit> <test- count>"
0537 echo " [ all ] [ -h | --help ] [ -l ]"
0538 echo ""
0539 echo "Valid tests: 0001-$MAX_TEST"
0540 echo ""
0541 echo " all Runs all tests (default)"
0542 echo " -t Run test ID the number amount of times is recommended"
0543 echo " -w Watch test ID run until it runs into an error"
0544 echo " -s Run test ID once"
0545 echo " -c Run test ID x test-count number of times"
0546 echo " -l List all test ID list"
0547 echo " -h|--help Help"
0548 echo
0549 echo "If an error every occurs execution will immediately terminate."
0550 echo "If you are adding a new test try using -w <test-ID> first to"
0551 echo "make sure the test passes a series of tests."
0552 echo
0553 echo Example uses:
0554 echo
0555 echo "${TEST_NAME}.sh -- executes all tests"
0556 echo "${TEST_NAME}.sh -t 0008 -- Executes test ID 0008 number of times is recommended"
0557 echo "${TEST_NAME}.sh -w 0008 -- Watch test ID 0008 run until an error occurs"
0558 echo "${TEST_NAME}.sh -s 0008 -- Run test ID 0008 once"
0559 echo "${TEST_NAME}.sh -c 0008 3 -- Run test ID 0008 three times"
0560 echo
0561 list_tests
0562 exit 1
0563 }
0564
0565 function test_num()
0566 {
0567 re='^[0-9]+$'
0568 if ! [[ $1 =~ $re ]]; then
0569 usage
0570 fi
0571 }
0572
0573 function get_test_data()
0574 {
0575 test_num $1
0576 local field_num=$(echo $1 | sed 's/^0*//')
0577 echo $ALL_TESTS | awk '{print $'$field_num'}'
0578 }
0579
0580 function get_test_count()
0581 {
0582 TEST_DATA=$(get_test_data $1)
0583 LAST_TWO=${TEST_DATA
0584 echo ${LAST_TWO%:*}
0585 }
0586
0587 function get_test_enabled()
0588 {
0589 TEST_DATA=$(get_test_data $1)
0590 echo ${TEST_DATA
0591 }
0592
0593 function run_all_tests()
0594 {
0595 for i in $ALL_TESTS ; do
0596 TEST_ID=${i%:*:*}
0597 ENABLED=$(get_test_enabled $TEST_ID)
0598 TEST_COUNT=$(get_test_count $TEST_ID)
0599 if [[ $ENABLED -eq "1" ]]; then
0600 test_case $TEST_ID $TEST_COUNT
0601 fi
0602 done
0603 }
0604
0605 function watch_log()
0606 {
0607 if [ $
0608 clear
0609 fi
0610 date
0611 echo "Running test: $2 - run #$1"
0612 }
0613
0614 function watch_case()
0615 {
0616 i=0
0617 while [ 1 ]; do
0618
0619 if [ $
0620 test_num $1
0621 watch_log $i ${TEST_NAME}_test_$1
0622 ${TEST_NAME}_test_$1
0623 else
0624 watch_log $i all
0625 run_all_tests
0626 fi
0627 let i=$i+1
0628 done
0629 }
0630
0631 function test_case()
0632 {
0633 NUM_TESTS=$DEFAULT_NUM_TESTS
0634 if [ $
0635 NUM_TESTS=$2
0636 fi
0637
0638 i=0
0639 while [ $i -lt $NUM_TESTS ]; do
0640 test_num $1
0641 watch_log $i ${TEST_NAME}_test_$1 noclear
0642 RUN_TEST=${TEST_NAME}_test_$1
0643 $RUN_TEST
0644 let i=$i+1
0645 done
0646 }
0647
0648 function parse_args()
0649 {
0650 if [ $
0651 run_all_tests
0652 else
0653 if [[ "$1" = "all" ]]; then
0654 run_all_tests
0655 elif [[ "$1" = "-w" ]]; then
0656 shift
0657 watch_case $@
0658 elif [[ "$1" = "-t" ]]; then
0659 shift
0660 test_num $1
0661 test_case $1 $(get_test_count $1)
0662 elif [[ "$1" = "-c" ]]; then
0663 shift
0664 test_num $1
0665 test_num $2
0666 test_case $1 $2
0667 elif [[ "$1" = "-s" ]]; then
0668 shift
0669 test_case $1 1
0670 elif [[ "$1" = "-l" ]]; then
0671 list_tests
0672 elif [[ "$1" = "-h" || "$1" = "--help" ]]; then
0673 usage
0674 else
0675 usage
0676 fi
0677 fi
0678 }
0679
0680 test_reqs
0681 allow_user_defaults
0682 load_req_mod
0683
0684 MODPROBE=$(</proc/sys/kernel/modprobe)
0685 trap "test_finish" EXIT
0686
0687 parse_args $@
0688
0689 exit 0