[PATCH] checkpolicy: add bad data protection tests
Akhil Kohli <[email protected]>
| Newsgroups | org.kernel.vger.selinux |
|---|---|
| Message-ID | <[email protected]> |
Add test_checkmodule_negative.sh and .te fixtures for bad-data protection (missing/bad-path and corrupted .te inputs). Signed-off-by: Akhil Kohli <[email protected]> --- checkpolicy/Makefile | 3 +- checkpolicy/tests/negative/bad_module_line.te | 5 + checkpolicy/tests/negative/bad_require.te | 5 + checkpolicy/tests/negative/bad_syntax.te | 8 + checkpolicy/tests/negative/dup_module.te | 6 + checkpolicy/tests/negative/good_module.te | 8 + .../tests/negative/invalid_module_version.te | 5 + checkpolicy/tests/negative/unknown_class.te | 7 + checkpolicy/tests/negative/unknown_perm.te | 8 + checkpolicy/tests/negative/unknown_type.te | 8 + .../tests/test_checkmodule_negative.sh | 178 ++++++++++++++++++ 11 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 checkpolicy/tests/negative/bad_module_line.te create mode 100644 checkpolicy/tests/negative/bad_require.te create mode 100644 checkpolicy/tests/negative/bad_syntax.te create mode 100644 checkpolicy/tests/negative/dup_module.te create mode 100644 checkpolicy/tests/negative/good_module.te create mode 100644 checkpolicy/tests/negative/invalid_module_version.te create mode 100644 checkpolicy/tests/negative/unknown_class.te create mode 100644 checkpolicy/tests/negative/unknown_perm.te create mode 100644 checkpolicy/tests/negative/unknown_type.te create mode 100755 checkpolicy/tests/test_checkmodule_negative.sh diff --git a/checkpolicy/Makefile b/checkpolicy/Makefile index 0055f495..e59ad63a 100644 --- a/checkpolicy/Makefile +++ b/checkpolicy/Makefile @@ -51,8 +51,9 @@ lex.yy.c: policy_scan.l y.tab.c $(LEX) policy_scan.l .PHONY: test -test: checkpolicy +test: checkpolicy checkmodule ./tests/test_roundtrip.sh + ./tests/test_checkmodule_negative.sh # helper target for fuzzing checkobjects: $(CHECKOBJS) diff --git a/checkpolicy/tests/negative/bad_module_line.te b/checkpolicy/tests/negative/bad_module_line.te new file mode 100644 index 00000000..587df2e1 --- /dev/null +++ b/checkpolicy/tests/negative/bad_module_line.te @@ -0,0 +1,5 @@ +module bad module name 1.0 garbage; + +require { + type foo_t; +} diff --git a/checkpolicy/tests/negative/bad_require.te b/checkpolicy/tests/negative/bad_require.te new file mode 100644 index 00000000..a45df4f4 --- /dev/null +++ b/checkpolicy/tests/negative/bad_require.te @@ -0,0 +1,5 @@ +module bad_require 1.0; + +require { + garbage_token foo_t; +} diff --git a/checkpolicy/tests/negative/bad_syntax.te b/checkpolicy/tests/negative/bad_syntax.te new file mode 100644 index 00000000..20605201 --- /dev/null +++ b/checkpolicy/tests/negative/bad_syntax.te @@ -0,0 +1,8 @@ +module bad_syntax 1.0; + +require { + type foo_t; + class file { read }; +} + +allow foo_t foo_t:file { diff --git a/checkpolicy/tests/negative/dup_module.te b/checkpolicy/tests/negative/dup_module.te new file mode 100644 index 00000000..beefff72 --- /dev/null +++ b/checkpolicy/tests/negative/dup_module.te @@ -0,0 +1,6 @@ +module dup_module 1.0; +module dup_module 1.0; + +require { + type foo_t; +} diff --git a/checkpolicy/tests/negative/good_module.te b/checkpolicy/tests/negative/good_module.te new file mode 100644 index 00000000..b9c9982f --- /dev/null +++ b/checkpolicy/tests/negative/good_module.te @@ -0,0 +1,8 @@ +module good_module 1.0; + +require { + type foo_t, bar_t; + class file { read write }; +} + +allow foo_t bar_t:file read; diff --git a/checkpolicy/tests/negative/invalid_module_version.te b/checkpolicy/tests/negative/invalid_module_version.te new file mode 100644 index 00000000..d18b7639 --- /dev/null +++ b/checkpolicy/tests/negative/invalid_module_version.te @@ -0,0 +1,5 @@ +module invalid_module_version; + +require { + type foo_t; +} diff --git a/checkpolicy/tests/negative/unknown_class.te b/checkpolicy/tests/negative/unknown_class.te new file mode 100644 index 00000000..825e0413 --- /dev/null +++ b/checkpolicy/tests/negative/unknown_class.te @@ -0,0 +1,7 @@ +module unknown_class 1.0; + +require { + type foo_t; +} + +allow foo_t self:not_a_class read; diff --git a/checkpolicy/tests/negative/unknown_perm.te b/checkpolicy/tests/negative/unknown_perm.te new file mode 100644 index 00000000..f4efbb54 --- /dev/null +++ b/checkpolicy/tests/negative/unknown_perm.te @@ -0,0 +1,8 @@ +module unknown_perm 1.0; + +require { + type foo_t, bar_t; + class file { read }; +} + +allow foo_t bar_t:file circular_ref; diff --git a/checkpolicy/tests/negative/unknown_type.te b/checkpolicy/tests/negative/unknown_type.te new file mode 100644 index 00000000..62360e04 --- /dev/null +++ b/checkpolicy/tests/negative/unknown_type.te @@ -0,0 +1,8 @@ +module unknown_type 1.0; + +require { + type foo_t; + class file { read }; +} + +allow foo_t undeclared_t:file read; diff --git a/checkpolicy/tests/test_checkmodule_negative.sh b/checkpolicy/tests/test_checkmodule_negative.sh new file mode 100755 index 00000000..a5f49f3b --- /dev/null +++ b/checkpolicy/tests/test_checkmodule_negative.sh @@ -0,0 +1,178 @@ +#!/bin/sh +# +# Negative / bad-data tests for checkmodule on module (.te) inputs. +# Matches the modular policy compile path: checkmodule -M -m <input> -o <module>.mod +# + +set -eu + +BASEDIR=$(CDPATH= cd -- "$(dirname "$0")" && pwd) +NEGDIR="${BASEDIR}/negative" +CHECKMODULE="${BASEDIR}/../checkmodule" +OUTDIR=$(mktemp -d "${TMPDIR:-/tmp}/checkmodule-negative.XXXXXX") +PASS=0 +FAIL=0 + +cleanup() { + rm -rf "${OUTDIR}" +} +trap cleanup EXIT + +mod_name_from_fixture() { + basename "$1" .te +} + +expect_pass() { + desc="$1" + fixture="$2" + modname=$(mod_name_from_fixture "${fixture}") + outmod="${OUTDIR}/${modname}.mod" + stderr="${OUTDIR}/${modname}.err" + + echo "==== POSITIVE (expect checkmodule success): ${desc}" + rm -f "${outmod}" + + set +e + "${CHECKMODULE}" -M -m -o "${outmod}" "${NEGDIR}/${fixture}" 2>"${stderr}" + rc=$? + set -e + + if [ "${rc}" -ne 0 ]; then + echo "FAIL: expected success (rc=0), got rc=${rc}" >&2 + cat "${stderr}" >&2 + FAIL=$((FAIL + 1)) + return 1 + fi + if [ ! -s "${outmod}" ]; then + echo "FAIL: expected non-empty ${outmod}" >&2 + FAIL=$((FAIL + 1)) + return 1 + fi + + echo "==== ${desc} success" + PASS=$((PASS + 1)) + echo "" +} + +expect_fail() { + desc="$1" + pattern="$2" + outname="${3:-fail}" + shift 3 + + outmod="${OUTDIR}/${outname}.mod" + stderr="${OUTDIR}/${outname}.err" + + echo "==== NEGATIVE (expect checkmodule error): ${desc}" + rm -f "${outmod}" + + set +e + "${CHECKMODULE}" -M -m "$@" -o "${outmod}" 2>"${stderr}" + rc=$? + set -e + + if [ "${rc}" -eq 0 ]; then + echo "FAIL: expected non-zero exit, got rc=0" >&2 + FAIL=$((FAIL + 1)) + return 1 + fi + if [ -f "${outmod}" ]; then + echo "FAIL: did not expect output module ${outmod}" >&2 + FAIL=$((FAIL + 1)) + return 1 + fi + if ! grep -Eq "${pattern}" "${stderr}"; then + echo "FAIL: stderr did not match /${pattern}/" >&2 + cat "${stderr}" >&2 + FAIL=$((FAIL + 1)) + return 1 + fi + + echo "==== ${desc}: rejected as expected" + PASS=$((PASS + 1)) + echo "" +} + +expect_fail_unreadable() { + desc="unreadable .te file" + fixture="${OUTDIR}/unreadable.te" + outmod="${OUTDIR}/unreadable.mod" + stderr="${OUTDIR}/unreadable.err" + + echo "==== NEGATIVE (expect checkmodule error): ${desc}" + if [ "$(id -u)" -eq 0 ]; then + echo "SKIP: root can read mode 000 files; unreadable check is non-root only" + PASS=$((PASS + 1)) + echo "" + return 0 + fi + + rm -f "${outmod}" + + set +e + "${CHECKMODULE}" -M -m -o "${outmod}" "${fixture}" 2>"${stderr}" + rc=$? + set -e + + if [ "${rc}" -eq 0 ]; then + echo "FAIL: expected non-zero exit, got rc=0" >&2 + FAIL=$((FAIL + 1)) + return 1 + fi + if [ -f "${outmod}" ]; then + echo "FAIL: did not expect output module ${outmod}" >&2 + FAIL=$((FAIL + 1)) + return 1 + fi + if ! grep -Eq 'unable to open|Permission denied' "${stderr}"; then + echo "FAIL: stderr did not mention unable to open or Permission denied" >&2 + cat "${stderr}" >&2 + FAIL=$((FAIL + 1)) + return 1 + fi + + echo "==== ${desc}: rejected as expected" + PASS=$((PASS + 1)) + echo "" +} + +# Ephemeral fixtures for path-based cases. +ln -sf /nonexistent/path "${OUTDIR}/broken_symlink.te" +cat > "${OUTDIR}/unreadable.te" <<'EOF' +module unreadable 1.0; + +require { + type foo_t; +} +EOF +chmod 000 "${OUTDIR}/unreadable.te" + +# Control fixture: valid module compiles and produces .mod output. +expect_pass "good_module.te" "good_module.te" + +# Corrupted .te sections (PDF #2). +expect_fail "bad_syntax.te" "syntax error" "bad_syntax" "${NEGDIR}/bad_syntax.te" +expect_fail "unknown_perm.te" "permission circular_ref is not defined" "unknown_perm" "${NEGDIR}/unknown_perm.te" +expect_fail "unknown_type.te" "unknown type undeclared_t" "unknown_type" "${NEGDIR}/unknown_type.te" +expect_fail "unknown_class.te" "unknown class not_a_class" "unknown_class" "${NEGDIR}/unknown_class.te" +expect_fail "bad_module_line.te" "syntax error" "bad_module_line" "${NEGDIR}/bad_module_line.te" +expect_fail "bad_require.te" "syntax error" "bad_require" "${NEGDIR}/bad_require.te" +expect_fail "invalid_module_version.te" "syntax error" "invalid_module_version" "${NEGDIR}/invalid_module_version.te" +expect_fail "dup_module.te" "syntax error" "dup_module" "${NEGDIR}/dup_module.te" + +# Missing / bad-path .te inputs (PDF #1). +expect_fail "missing .te path" "unable to open" "missing_path" "${OUTDIR}/does_not_exist.te" +expect_fail "directory instead of .te file" "input in flex scanner failed" "directory_input" "${NEGDIR}" +expect_fail "broken symlink to .te" "unable to open" "broken_symlink" "${OUTDIR}/broken_symlink.te" +expect_fail_unreadable +expect_fail "empty .te path argument" "unable to open" "empty_path" "" + +# CLI edge cases. +expect_fail "checkmodule with no input file" "unable to open policy.conf" "no_input" +expect_fail "checkmodule -o name mismatch" "Module name good_module is different" "name_mismatch" \ + -o "${OUTDIR}/wrong_name.mod" "${NEGDIR}/good_module.te" + +echo "checkmodule negative tests: ${PASS} passed, ${FAIL} failed" +if [ "${FAIL}" -ne 0 ]; then + exit 1 +fi -- 2.55.0