diff --git a/selinux-policy/m4-bad-data/PURPOSE b/selinux-policy/m4-bad-data/PURPOSE index 687731b..ea14daa 100644 --- a/selinux-policy/m4-bad-data/PURPOSE +++ b/selinux-policy/m4-bad-data/PURPOSE @@ -3,3 +3,8 @@ Author: Akhil Kohli Description: Negative bad-data tests for the M4 preprocessing stage of modular SELinux policy builds (.if, .te, and .fc inputs before checkmodule). + +Execution is via FMF/TMT (main.fmf -> runtest.sh) using beakerlib rlRun +phases. Support macros prefer SELINUX_POLICY_SRC, else installed +selinux-policy-devel (/usr/share/selinux/devel/include/support), else a +git clone (Fedora falls back to rawhide when f$N is missing). diff --git a/selinux-policy/m4-bad-data/fixtures/make_primary/bad_missing_te.fc b/selinux-policy/m4-bad-data/fixtures/make_primary/bad_missing_te.fc deleted file mode 100644 index e8be832..0000000 --- a/selinux-policy/m4-bad-data/fixtures/make_primary/bad_missing_te.fc +++ /dev/null @@ -1 +0,0 @@ -/tmp gen_context(system_u:object_r:tmp_t,s0) diff --git a/selinux-policy/m4-bad-data/fixtures/make_primary/bad_missing_te.if b/selinux-policy/m4-bad-data/fixtures/make_primary/bad_missing_te.if deleted file mode 100644 index bc5261d..0000000 --- a/selinux-policy/m4-bad-data/fixtures/make_primary/bad_missing_te.if +++ /dev/null @@ -1,4 +0,0 @@ -interface(`test_good_iface',` - gen_require(`type $1; class file { read };') - allow $1 self:file read; -') diff --git a/selinux-policy/m4-bad-data/main.fmf b/selinux-policy/m4-bad-data/main.fmf index 2536ed4..7ecf218 100644 --- a/selinux-policy/m4-bad-data/main.fmf +++ b/selinux-policy/m4-bad-data/main.fmf @@ -8,9 +8,9 @@ component: require: - checkpolicy - m4 - - make - git - policycoreutils + - selinux-policy-devel recommend: - selinux-policy - selinux-policy-targeted diff --git a/selinux-policy/m4-bad-data/make-primary/Makefile b/selinux-policy/m4-bad-data/make-primary/Makefile deleted file mode 100644 index bc8c1a5..0000000 --- a/selinux-policy/m4-bad-data/make-primary/Makefile +++ /dev/null @@ -1,57 +0,0 @@ -# Test harness Makefile (not the standard selinux-policy build / Rules.modular). -# Mirrors the modular primary dependency from Rules.modular (~lines 73-86): -# .mod/.pp require the module .te. Used only by m4-bad-data/run.sh for the -# missing-.te negative case. Real M4 support files still come from POLICY_ROOT. - -POLICY_ROOT ?= ../../.. -MODDIR ?= -OUTDIR ?= $(MODDIR)/out -MOD ?= bad_missing_te - -M4 ?= m4 -CHECKMODULE ?= checkmodule -CHECKMODULE_OPTS ?= -M -m -SEMOD_PKG ?= semodule_package -SED ?= sed - -M4SUPPORT = $(POLICY_ROOT)/support/divert.m4 \ - $(POLICY_ROOT)/policy/support/misc_macros.spt \ - $(POLICY_ROOT)/policy/support/mls_mcs_macros.spt \ - $(POLICY_ROOT)/policy/support/loadable_module.spt \ - $(POLICY_ROOT)/policy/support/obj_perm_sets.spt \ - $(POLICY_ROOT)/support/undivert.m4 - -M4PARAM = -D enable_mcs -D distro_redhat -D hide_broken_symptoms \ - -D mls_num_sens=16 -D mls_num_cats=1024 -D mcs_num_cats=1024 - -IFERROR = $(POLICY_ROOT)/support/iferror.m4 -EMPTY_GEN_DEF = /dev/null - -$(OUTDIR)/generated_definitions.conf: - @mkdir -p $(OUTDIR) - @touch $@ - -$(OUTDIR)/all_interfaces.conf: $(M4SUPPORT) $(MODDIR)/$(MOD).if $(IFERROR) - @mkdir -p $(OUTDIR) - @echo 'divert(-1)' > $@ - $(M4) $(M4PARAM) $(M4SUPPORT) $(MODDIR)/$(MOD).if $(IFERROR) >> $(OUTDIR)/all_interfaces.tmp - $(SED) -e 's/dollarsstar/$$*/g' $(OUTDIR)/all_interfaces.tmp >> $@ - @echo 'divert' >> $@ - -$(OUTDIR)/$(MOD).mod: $(M4SUPPORT) $(OUTDIR)/generated_definitions.conf \ - $(OUTDIR)/all_interfaces.conf $(MODDIR)/$(MOD).te - @mkdir -p $(OUTDIR) - $(M4) $(M4PARAM) -s $(M4SUPPORT) $(EMPTY_GEN_DEF) \ - $(OUTDIR)/all_interfaces.conf $(MODDIR)/$(MOD).te > $(OUTDIR)/$(MOD).tmp - $(CHECKMODULE) $(CHECKMODULE_OPTS) -o $@ $(OUTDIR)/$(MOD).tmp - -$(OUTDIR)/$(MOD).mod.fc: $(M4SUPPORT) $(MODDIR)/$(MOD).fc - @mkdir -p $(OUTDIR) - $(M4) $(M4PARAM) $(M4SUPPORT) $(MODDIR)/$(MOD).fc > $@ - -$(OUTDIR)/$(MOD).pp: $(OUTDIR)/$(MOD).mod $(OUTDIR)/$(MOD).mod.fc - @mkdir -p $(OUTDIR) - $(SEMOD_PKG) -o $@ -m $(OUTDIR)/$(MOD).mod -f $(OUTDIR)/$(MOD).mod.fc - -.PHONY: all -all: $(OUTDIR)/$(MOD).pp diff --git a/selinux-policy/m4-bad-data/run.sh b/selinux-policy/m4-bad-data/run.sh deleted file mode 100755 index 8e448dc..0000000 --- a/selinux-policy/m4-bad-data/run.sh +++ /dev/null @@ -1,733 +0,0 @@ -#!/bin/sh -# -# Bad-data tests for the M4 preprocessing stage of modular policy builds: -# .if -> all_interfaces.conf, .te + interfaces -> .tmp, .fc -> .mod.fc -# -# Mirrors Rules.modular invocations; uses plain "module name 1.0;" fixtures so tests -# do not depend on generated_definitions.conf. -# - -set -u - -BASEDIR=$(CDPATH= cd -- "$(dirname "$0")" && pwd) -POLICY_ROOT=${SELINUX_POLICY_SRC:-} -if [ -z "${POLICY_ROOT}" ] || [ ! -f "${POLICY_ROOT}/Rules.modular" ]; then - echo "SELINUX_POLICY_SRC must point to a selinux-policy source checkout" >&2 - exit 1 -fi -FIXTURES="${BASEDIR}/fixtures" -OUTDIR=$(mktemp -d "${TMPDIR:-/tmp}/selinux-policy-bad-data.XXXXXX") -PASS=0 -FAIL=0 - -M4=${M4:-m4} -CHECKMODULE=${CHECKMODULE:-checkmodule} -MAKE=${MAKE:-make} -SEMODULE_PACKAGE=${SEMODULE_PACKAGE:-semodule_package} - -M4SUPPORT="${POLICY_ROOT}/support/divert.m4 \ - ${POLICY_ROOT}/policy/support/misc_macros.spt \ - ${POLICY_ROOT}/policy/support/mls_mcs_macros.spt \ - ${POLICY_ROOT}/policy/support/loadable_module.spt \ - ${POLICY_ROOT}/policy/support/obj_perm_sets.spt \ - ${POLICY_ROOT}/support/undivert.m4" - -M4PARAM="-D enable_mcs -D distro_redhat -D hide_broken_symptoms -D mls_num_sens=16 -D mls_num_cats=1024 -D mcs_num_cats=1024" - -IFERROR="${POLICY_ROOT}/support/iferror.m4" -EMPTY_GEN_DEF=/dev/null - -cleanup() { - rm -rf "${OUTDIR}" -} -trap cleanup EXIT - -die() { - echo "FAIL: $*" >&2 - FAIL=$((FAIL + 1)) -} - -pass() { - echo "==== $*" - PASS=$((PASS + 1)) - echo "" -} - -# Build all_interfaces.conf from one or more .if files (Rules.modular lines 138-143). -build_all_interfaces() { - out="$1" - shift - - echo 'divert(-1)' >"${out}" - # shellcheck disable=SC2086 - ${M4} ${M4PARAM} ${M4SUPPORT} "$@" "${IFERROR}" >"${out}.tmp" 2>"${out}.err" - rc=$? - sed -e 's/dollarsstar/$*/g' "${out}.tmp" >>"${out}" - echo 'divert' >>"${out}" - return "${rc}" -} - -# Expand a module .te with interfaces (Rules.modular line 73-76; /dev/null for gen defs). -expand_module_te() { - interfaces="$1" - te="$2" - out="$3" - - # shellcheck disable=SC2086 - ${M4} ${M4PARAM} -s ${M4SUPPORT} "${EMPTY_GEN_DEF}" "${interfaces}" "${te}" \ - >"${out}" 2>"${out}.err" - rc=$? - return "${rc}" -} - -# Expand file_contexts (Rules.modular line 79-81). -expand_fc() { - fc="$1" - out="$2" - - # shellcheck disable=SC2086 - ${M4} ${M4PARAM} ${M4SUPPORT} "${fc}" >"${out}" 2>"${out}.err" - rc=$? - return "${rc}" -} - -mod_name_from_te() { - sed -n 's/^module[[:space:]]\+\([^[:space:]]\+\).*/\1/p' "$1" | head -1 -} - -expect_m4_interfaces_fail() { - desc="$1" - name="$2" - shift 2 - - echo "==== NEGATIVE (expect M4 interface build failure): ${desc}" - out="${OUTDIR}/${name}.interfaces" - rm -f "${out}" "${out}.tmp" "${out}.err" - - build_all_interfaces "${out}" "$@" - rc=$? - - if [ "${rc}" -eq 0 ]; then - die "${desc}: expected non-zero M4 exit, got rc=0" - return 0 - fi - - pass "${desc} (M4 failed as expected, rc=${rc})" -} - -expect_m4_interfaces_fail_unreadable() { - desc="unreadable .if file" - name="unreadable_if" - if_path="${OUTDIR}/unreadable.if" - out="${OUTDIR}/${name}.interfaces" - - echo "==== NEGATIVE (expect M4 interface build failure): ${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 "${out}" "${out}.tmp" "${out}.err" - cp "${FIXTURES}/interfaces/good.if" "${if_path}" - chmod 000 "${if_path}" - - build_all_interfaces "${out}" "${if_path}" - rc=$? - - if [ "${rc}" -eq 0 ]; then - die "${desc}: expected non-zero M4 exit, got rc=0" - return 0 - fi - - pass "${desc} (M4 failed as expected, rc=${rc})" -} - -expect_m4_interfaces_pass() { - desc="$1" - name="$2" - shift 2 - - echo "==== POSITIVE (expect M4 interface build success): ${desc}" - out="${OUTDIR}/${name}.interfaces" - rm -f "${out}" "${out}.tmp" "${out}.err" - - build_all_interfaces "${out}" "$@" - rc=$? - - if [ "${rc}" -ne 0 ]; then - echo "stderr:" >&2 - cat "${out}.err" >&2 - die "${desc}: expected M4 success, got rc=${rc}" - return 1 - fi - if [ ! -s "${out}" ]; then - die "${desc}: expected non-empty ${out}" - return 1 - fi - - pass "${desc} (M4 succeeded)" -} - -expect_expand_pass() { - desc="$1" - name="$2" - interfaces="$3" - te="$4" - - echo "==== POSITIVE (expect module M4 expand success): ${desc}" - tmp="${OUTDIR}/${name}.tmp" - rm -f "${tmp}" "${tmp}.err" - - expand_module_te "${interfaces}" "${te}" "${tmp}" - rc=$? - - if [ "${rc}" -ne 0 ]; then - cat "${tmp}.err" >&2 - die "${desc}: expected M4 success, got rc=${rc}" - return 1 - fi - if [ ! -s "${tmp}" ]; then - die "${desc}: expected non-empty ${tmp}" - return 1 - fi - - pass "${desc} (M4 expand succeeded)" -} - -expect_expand_fail() { - desc="$1" - name="$2" - interfaces="$3" - te="$4" - - echo "==== NEGATIVE (expect module M4 expand failure): ${desc}" - tmp="${OUTDIR}/${name}.tmp" - rm -f "${tmp}" "${tmp}.err" - - expand_module_te "${interfaces}" "${te}" "${tmp}" - rc=$? - - if [ "${rc}" -eq 0 ]; then - die "${desc}: expected M4 failure, got rc=0" - return 1 - fi - - pass "${desc} (M4 expand failed as expected, rc=${rc})" -} - -# Missing-.te check via make-primary/Makefile (harness mirror of Rules.modular -# .te→.mod dependency), not the standard selinux-policy build / Rules.modular. -expect_make_missing_te_fail() { - desc="Make fails when module .te is missing (harness Makefile, modular-style deps)" - name="b31_missing_te" - mod="bad_missing_te" - moddir="${OUTDIR}/${name}_mod" - makedir="${BASEDIR}/make-primary" - out="${moddir}/out" - log="${OUTDIR}/${name}.log" - - echo "==== NEGATIVE (expect Makefile failure): ${desc}" - rm -rf "${moddir}" - mkdir -p "${moddir}" - cp "${FIXTURES}/make_primary/${mod}.if" "${moddir}/${mod}.if" - cp "${FIXTURES}/make_primary/${mod}.fc" "${moddir}/${mod}.fc" - - rm -f "${log}" - ${MAKE} -f "${makedir}/Makefile" \ - POLICY_ROOT="${POLICY_ROOT}" \ - MODDIR="${moddir}" \ - OUTDIR="${out}" \ - MOD="${mod}" \ - "${out}/${mod}.pp" >"${log}" 2>&1 - rc=$? - - if [ "${rc}" -eq 0 ]; then - cat "${log}" >&2 - die "${desc}: expected non-zero make exit, got rc=0" - return 1 - fi - if [ -f "${out}/${mod}.mod" ] || [ -f "${out}/${mod}.pp" ]; then - die "${desc}: did not expect ${out}/${mod}.mod or .pp" - return 1 - fi - if ! grep -Eq "${mod}\\.te|No rule to make target|No such file" "${log}"; then - echo "FAIL: make log did not mention missing ${mod}.te" >&2 - cat "${log}" >&2 - FAIL=$((FAIL + 1)) - return 0 - fi - - pass "${desc} (make failed as expected, rc=${rc})" -} - -expect_m4_package_e2e_deferred() { - desc="$1" - name="$2" - fc="$3" - interfaces="$4" - te="$5" - - modfc="${OUTDIR}/${name}.mod.fc" - pp="${OUTDIR}/${name}.pp" - tmp="${OUTDIR}/${name}.tmp" - modname=$(mod_name_from_te "${te}") - e2e_dir="${OUTDIR}/${name}_build" - goodmod="${e2e_dir}/${modname}.mod" - stderr="${OUTDIR}/${name}.err" - - echo "==== DOCUMENT (M4 to semodule_package E2E; validate in sefcontext_compile): ${desc}" - if ! command -v "${SEMODULE_PACKAGE}" >/dev/null 2>&1; then - die "${desc}: ${SEMODULE_PACKAGE} not found on PATH" - return 1 - fi - - rm -rf "${e2e_dir}" - mkdir -p "${e2e_dir}" - rm -f "${modfc}" "${modfc}.err" "${pp}" "${stderr}" "${tmp}" "${tmp}.err" - - expand_module_te "${interfaces}" "${te}" "${tmp}" - rc=$? - if [ "${rc}" -ne 0 ]; then - cat "${tmp}.err" >&2 - die "${desc}: expected M4 success for good .te, got rc=${rc}" - return 1 - fi - - "${CHECKMODULE}" -M -m -o "${goodmod}" "${tmp}" 2>"${stderr}" - rc=$? - if [ "${rc}" -ne 0 ]; then - cat "${stderr}" >&2 - die "${desc}: expected checkmodule success for good .mod, got rc=${rc}" - return 1 - fi - - expand_fc "${fc}" "${modfc}" - rc=$? - if [ "${rc}" -ne 0 ]; then - cat "${modfc}.err" >&2 - die "${desc}: expected M4 success for bad .fc, got rc=${rc}" - return 1 - fi - - rm -f "${pp}" - "${SEMODULE_PACKAGE}" -o "${pp}" -m "${goodmod}" -f "${modfc}" 2>"${stderr}" - rc=$? - - if [ "${rc}" -ne 0 ]; then - cat "${stderr}" >&2 - die "${desc}: expected semodule_package exit 0 at packaging stage, got rc=${rc}" - return 1 - fi - if [ ! -s "${pp}" ]; then - die "${desc}: expected non-empty ${pp}" - return 1 - fi - - pass "${desc} (M4 to package exit 0; labeling validation deferred to sefcontext_compile)" -} - -expect_expand_then_checkmodule_pass() { - desc="$1" - name="$2" - interfaces="$3" - te="$4" - - expect_expand_pass "${desc}" "${name}" "${interfaces}" "${te}" || return 1 - - tmp="${OUTDIR}/${name}.tmp" - modname=$(mod_name_from_te "${te}") - outmod="${OUTDIR}/${modname}.mod" - stderr="${OUTDIR}/${modname}.err" - - echo "==== POSITIVE (expect checkmodule success after M4): ${desc}" - rm -f "${outmod}" - - "${CHECKMODULE}" -M -m -o "${outmod}" "${tmp}" 2>"${stderr}" - rc=$? - - if [ "${rc}" -ne 0 ]; then - cat "${stderr}" >&2 - die "${desc}: expected checkmodule success, got rc=${rc}" - return 1 - fi - if [ ! -s "${outmod}" ]; then - die "${desc}: expected non-empty ${outmod}" - return 1 - fi - - pass "${desc} (checkmodule succeeded)" -} - -expect_expand_then_checkmodule_fail() { - desc="$1" - name="$2" - interfaces="$3" - te="$4" - - expect_expand_pass "${desc} (M4 stage)" "${name}" "${interfaces}" "${te}" || return 1 - - tmp="${OUTDIR}/${name}.tmp" - modname=$(mod_name_from_te "${te}") - outmod="${OUTDIR}/${modname}.mod" - stderr="${OUTDIR}/${modname}.err" - - echo "==== NEGATIVE (expect checkmodule failure after M4): ${desc}" - rm -f "${outmod}" - - "${CHECKMODULE}" -M -m -o "${outmod}" "${tmp}" 2>"${stderr}" - rc=$? - - if [ "${rc}" -eq 0 ]; then - die "${desc}: expected checkmodule failure, got rc=0" - return 1 - fi - - pass "${desc} (checkmodule failed as expected, rc=${rc})" -} - -expect_expand_then_checkmodule_pass_document() { - desc="$1" - name="$2" - interfaces="$3" - te="$4" - note="$5" - - expect_expand_pass "${desc}" "${name}" "${interfaces}" "${te}" || return 1 - - tmp="${OUTDIR}/${name}.tmp" - modname=$(mod_name_from_te "${te}") - outmod="${OUTDIR}/${modname}.mod" - stderr="${OUTDIR}/${modname}.err" - - echo "==== DOCUMENT (${note}): ${desc}" - rm -f "${outmod}" - - "${CHECKMODULE}" -M -m -o "${outmod}" "${tmp}" 2>"${stderr}" - rc=$? - - if [ "${rc}" -ne 0 ]; then - cat "${stderr}" >&2 - die "${desc}: expected checkmodule success, got rc=${rc}" - return 1 - fi - if [ ! -s "${outmod}" ]; then - die "${desc}: expected non-empty ${outmod}" - return 1 - fi - - pass "${desc} (M4 and checkmodule succeeded; ${note})" -} - -expect_fc_m4_pass() { - desc="$1" - name="$2" - fc="$3" - - echo "==== POSITIVE (expect .fc M4 pass): ${desc}" - out="${OUTDIR}/${name}.mod.fc" - rm -f "${out}" "${out}.err" - - expand_fc "${fc}" "${out}" - rc=$? - - if [ "${rc}" -ne 0 ]; then - cat "${out}.err" >&2 - die "${desc}: expected M4 success, got rc=${rc}" - return 1 - fi - if [ ! -s "${out}" ]; then - die "${desc}: expected non-empty ${out}" - return 1 - fi - - pass "${desc} (M4 produced output; labeling validation is post-.mod)" -} - -expect_fc_m4_pass_deferred() { - desc="$1" - name="$2" - fc="$3" - allow_empty="${4:-0}" - - echo "==== DOCUMENT (M4 accepts input; validate in sefcontext_compile): ${desc}" - out="${OUTDIR}/${name}.mod.fc" - rm -f "${out}" "${out}.err" - - expand_fc "${fc}" "${out}" - rc=$? - - if [ "${rc}" -ne 0 ]; then - cat "${out}.err" >&2 - die "${desc}: expected M4 success at preprocessing stage, got rc=${rc}" - return 1 - fi - if [ "${allow_empty}" -eq 0 ] && [ ! -s "${out}" ]; then - die "${desc}: expected non-empty ${out} at preprocessing stage" - return 1 - fi - - pass "${desc} (M4 exit 0; labeling validation deferred to sefcontext_compile)" -} - -expect_fc_m4_fail() { - desc="$1" - name="$2" - fc="$3" - - echo "==== NEGATIVE (expect .fc M4 failure): ${desc}" - out="${OUTDIR}/${name}.mod.fc" - rm -f "${out}" "${out}.err" - - expand_fc "${fc}" "${out}" - rc=$? - - if [ "${rc}" -eq 0 ]; then - die "${desc}: expected M4 failure, got rc=0" - return 1 - fi - - pass "${desc} (M4 failed as expected, rc=${rc})" -} - -expect_fc_m4_fail_unreadable() { - desc="unreadable .fc file" - fc="${OUTDIR}/unreadable.fc" - out="${OUTDIR}/unreadable_fc.mod.fc" - - echo "==== NEGATIVE (expect .fc M4 failure): ${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 "${out}" "${out}.err" - cp "${FIXTURES}/file_contexts/good.fc" "${fc}" - chmod 000 "${fc}" - - expand_fc "${fc}" "${out}" - rc=$? - - if [ "${rc}" -eq 0 ]; then - die "${desc}: expected non-zero M4 exit, got rc=0" - return 0 - fi - - pass "${desc} (M4 failed as expected, rc=${rc})" -} - -# Ephemeral path fixtures for interface and file_context tests. -ln -sf /nonexistent/test_good.if "${OUTDIR}/broken_symlink.if" -ln -sf /nonexistent/test_good.mod.fc "${OUTDIR}/broken_symlink.fc" -printf '' > "${OUTDIR}/empty.fc" - -# --- .if -> all_interfaces.conf --- -expect_m4_interfaces_fail \ - "unclosed interface definition" \ - b1_unclosed \ - "${FIXTURES}/interfaces/bad_unclosed.if" - -expect_m4_interfaces_fail \ - "broken M4 syntax in interface file" \ - b1_m4_syntax \ - "${FIXTURES}/interfaces/bad_m4_syntax.if" - -expect_m4_interfaces_fail \ - "duplicate interface definition" \ - b1_duplicate \ - "${FIXTURES}/interfaces/bad_duplicate.if" - -expect_m4_interfaces_fail \ - "broken gen_require block in interface file" \ - b1_bad_gen_if \ - "${FIXTURES}/interfaces/bad_gen_if_build.if" - -expect_m4_interfaces_fail \ - "empty interface template name" \ - b1_empty_ifname \ - "${FIXTURES}/interfaces/bad_empty_ifname.if" - -expect_m4_interfaces_fail \ - "missing .if path" \ - b1_missing \ - "${OUTDIR}/does_not_exist.if" - -expect_m4_interfaces_fail \ - "directory instead of .if file" \ - b1_directory \ - "${BASEDIR}" - -expect_m4_interfaces_fail \ - "broken symlink for .if" \ - b1_symlink \ - "${OUTDIR}/broken_symlink.if" - -expect_m4_interfaces_fail_unreadable - -expect_m4_interfaces_pass \ - "control good interface" \ - b1_good \ - "${FIXTURES}/interfaces/good.if" - -# --- .te + M4 with interfaces --- -GOOD_IF="${OUTDIR}/b1_good.interfaces" - -expect_expand_then_checkmodule_pass \ - "control good .if + .te through M4 and checkmodule" \ - b2_good \ - "${GOOD_IF}" \ - "${FIXTURES}/modules/te_good.te" - -expect_expand_fail \ - "missing .te path at M4 expand" \ - b2_missing_te \ - "${GOOD_IF}" \ - "${OUTDIR}/does_not_exist.te" - -expect_make_missing_te_fail - -NEEDS_ARG_IF="${OUTDIR}/needs_arg.interfaces" -build_all_interfaces "${NEEDS_ARG_IF}" "${FIXTURES}/interfaces/needs_arg.if" - -expect_expand_then_checkmodule_fail \ - "interface called with too few arguments" \ - b2_few_args \ - "${NEEDS_ARG_IF}" \ - "${FIXTURES}/modules/te_few_args.te" - -expect_expand_then_checkmodule_pass_document \ - "interface called with too many arguments" \ - b2_many_args \ - "${NEEDS_ARG_IF}" \ - "${FIXTURES}/modules/te_many_args.te" \ - "extra interface args are ignored by M4" - -# --- M4 OK, bad expanded TE -> checkmodule fails --- -TRUNC_IF="${OUTDIR}/bad_trunc.interfaces" -build_all_interfaces "${TRUNC_IF}" "${FIXTURES}/interfaces/bad_trunc.if" - -expect_expand_then_checkmodule_fail \ - "truncated allow from interface expansion" \ - b5_trunc \ - "${TRUNC_IF}" \ - "${FIXTURES}/modules/te_trunc.te" - -GEN_REQ_IF="${OUTDIR}/bad_gen_require.interfaces" -build_all_interfaces "${GEN_REQ_IF}" "${FIXTURES}/interfaces/bad_gen_require.if" - -expect_expand_then_checkmodule_fail \ - "broken gen_require expanded from interface" \ - b5_gen_require \ - "${GEN_REQ_IF}" \ - "${FIXTURES}/modules/te_gen_require.te" - -UNKNOWN_TYPE_IF="${OUTDIR}/bad_unknown_type.interfaces" -build_all_interfaces "${UNKNOWN_TYPE_IF}" \ - "${FIXTURES}/interfaces/bad_unknown_type.if" - -expect_expand_then_checkmodule_fail \ - "unknown type from interface expansion" \ - b5_unknown_type \ - "${UNKNOWN_TYPE_IF}" \ - "${FIXTURES}/modules/te_unknown_type.te" - -UNKNOWN_PERM_IF="${OUTDIR}/bad_unknown_perm.interfaces" -build_all_interfaces "${UNKNOWN_PERM_IF}" \ - "${FIXTURES}/interfaces/bad_unknown_perm.if" - -expect_expand_then_checkmodule_fail \ - "unknown permission from interface expansion" \ - b5_unknown_perm \ - "${UNKNOWN_PERM_IF}" \ - "${FIXTURES}/modules/te_unknown_perm.te" - -GARBAGE_IF="${OUTDIR}/bad_garbage.interfaces" -build_all_interfaces "${GARBAGE_IF}" "${FIXTURES}/interfaces/bad_garbage.if" - -expect_expand_then_checkmodule_fail \ - "garbage token from interface expansion" \ - b5_garbage \ - "${GARBAGE_IF}" \ - "${FIXTURES}/modules/te_garbage.te" - -MODULE_LINE_IF="${OUTDIR}/bad_module_line.interfaces" -build_all_interfaces "${MODULE_LINE_IF}" \ - "${FIXTURES}/interfaces/bad_module_line.if" - -expect_expand_then_checkmodule_fail \ - "invalid module line from interface expansion" \ - b5_module_line \ - "${MODULE_LINE_IF}" \ - "${FIXTURES}/modules/te_bad_module_line.te" - -# --- .fc -> M4 -> .mod.fc --- -expect_fc_m4_pass \ - "control good .fc through M4" \ - b3_good \ - "${FIXTURES}/file_contexts/good.fc" - -expect_fc_m4_pass_deferred \ - "invalid context survives M4" \ - b3_bad_context \ - "${FIXTURES}/file_contexts/bad_context.fc" - -expect_fc_m4_pass_deferred \ - "wrong field count in .fc" \ - b3_bad_fields \ - "${FIXTURES}/file_contexts/bad_fields.fc" - -expect_fc_m4_pass_deferred \ - "empty .fc file" \ - b3_empty_fc \ - "${OUTDIR}/empty.fc" \ - 1 - -expect_fc_m4_pass_deferred \ - "path-only line without context in .fc" \ - b3_no_context \ - "${FIXTURES}/file_contexts/bad_no_context.fc" - -expect_fc_m4_pass_deferred \ - "invalid regex metacharacters in .fc path" \ - b3_bad_regex \ - "${FIXTURES}/file_contexts/bad_regex.fc" - -expect_fc_m4_fail \ - "missing .fc path" \ - b3_missing \ - "${OUTDIR}/does_not_exist.fc" - -expect_fc_m4_fail \ - "directory instead of .fc file" \ - b3_directory \ - "${BASEDIR}" - -expect_fc_m4_fail \ - "broken symlink for .fc" \ - b3_symlink \ - "${OUTDIR}/broken_symlink.fc" - -expect_fc_m4_fail_unreadable - -expect_fc_m4_fail \ - "broken M4 syntax in .fc" \ - b3_bad_m4 \ - "${FIXTURES}/file_contexts/bad_m4_syntax.fc" - -# --- M4-expanded .mod.fc through semodule_package (E2E; labeling deferred) --- -expect_m4_package_e2e_deferred \ - "bad M4-expanded .mod.fc packaged with good .mod (M4 to package E2E)" \ - b6_e2e \ - "${FIXTURES}/file_contexts/bad_context.fc" \ - "${GOOD_IF}" \ - "${FIXTURES}/modules/te_good.te" - -echo "========================================" -echo "Results: ${PASS} passed, ${FAIL} failed" -if [ "${FAIL}" -ne 0 ]; then - exit 1 -fi -exit 0 diff --git a/selinux-policy/m4-bad-data/runtest.sh b/selinux-policy/m4-bad-data/runtest.sh index 8bf4a7e..8a3ee22 100755 --- a/selinux-policy/m4-bad-data/runtest.sh +++ b/selinux-policy/m4-bad-data/runtest.sh @@ -14,7 +14,16 @@ PACKAGE="selinux-policy" POLICY_GIT="${SELINUX_POLICY_GIT:-https://github.com/fedora-selinux/selinux-policy.git}" POLICY_DIR="${SELINUX_POLICY_SRC:-}" -# Prefer explicit override; otherwise pick the host's default selinux-policy branch. +BASEDIR="$(cd "$(dirname "$0")" && pwd)" +FIXTURES="${BASEDIR}/fixtures" + +M4=${M4:-m4} +CHECKMODULE=${CHECKMODULE:-checkmodule} +SEMODULE_PACKAGE=${SEMODULE_PACKAGE:-semodule_package} + +# Prefer explicit override; otherwise pick a clone branch for local/fallback use. +# Fedora Rawhide may report VERSION_ID=rawhide or a numeric ID ahead of any fN +# branch (e.g. 45 while only rawhide/f44 exist). Clone falls back to rawhide. if [ -n "${SELINUX_POLICY_BRANCH:-}" ]; then POLICY_BRANCH="${SELINUX_POLICY_BRANCH}" else @@ -22,39 +31,348 @@ else # shellcheck disable=SC1090 . "${os_release}" if rlIsOSLike fedora; then - # e.g. Fedora 43 -> f43 (matches fedora-selinux/selinux-policy branches) - POLICY_BRANCH="f${VERSION_ID}" + fedora_rel="" + if [[ "${VERSION_ID}" =~ ^[0-9]+$ ]]; then + fedora_rel="${VERSION_ID}" + elif [[ "${REDHAT_BUGZILLA_PRODUCT_VERSION:-}" =~ ^[0-9]+$ ]]; then + fedora_rel="${REDHAT_BUGZILLA_PRODUCT_VERSION}" + elif [[ "${REDHAT_SUPPORT_PRODUCT_VERSION:-}" =~ ^[0-9]+$ ]]; then + fedora_rel="${REDHAT_SUPPORT_PRODUCT_VERSION}" + fi + if [ -n "${fedora_rel}" ]; then + POLICY_BRANCH="f${fedora_rel}" + else + POLICY_BRANCH="rawhide" + fi else - # e.g. CentOS Stream / RHEL 10.x -> c10s VERSION="${VERSION_ID%.*}" POLICY_BRANCH="c${VERSION}s" fi fi +DEVEL_SUPPORT="/usr/share/selinux/devel/include/support" + +# Configure M4SUPPORT/IFERROR from a selinux-policy git checkout layout. +setup_m4_from_git_tree() { + local root="$1" + M4SUPPORT="${root}/support/divert.m4 \ + ${root}/policy/support/misc_macros.spt \ + ${root}/policy/support/mls_mcs_macros.spt \ + ${root}/policy/support/loadable_module.spt \ + ${root}/policy/support/obj_perm_sets.spt \ + ${root}/support/undivert.m4" + IFERROR="${root}/support/iferror.m4" + POLICY_ROOT="${root}" +} + +# Configure M4SUPPORT from installed selinux-policy-devel (flat support/). +setup_m4_from_devel() { + local support="$1" + M4SUPPORT="${support}/divert.m4 \ + ${support}/misc_macros.spt \ + ${support}/mls_mcs_macros.spt \ + ${support}/loadable_module.spt \ + ${support}/obj_perm_sets.spt \ + ${support}/undivert.m4" + # iferror.m4 is build-tree only; recreate the upstream one-liner when absent. + if [ -f "${support}/iferror.m4" ]; then + IFERROR="${support}/iferror.m4" + else + IFERROR="${OUTDIR}/iferror.m4" + cat >"${IFERROR}" <<'EOF' +ifdef(`__if_error',`m4exit(1)') +EOF + fi + POLICY_ROOT="${support}" +} + +# Build all_interfaces.conf from one or more .if files (usual modular M4 recipe). +build_all_interfaces() { + local out="$1" + shift + + echo 'divert(-1)' >"${out}" + # shellcheck disable=SC2086 + ${M4} ${M4PARAM} ${M4SUPPORT} "$@" "${IFERROR}" >"${out}.tmp" 2>"${out}.err" + local rc=$? + sed -e 's/dollarsstar/$*/g' "${out}.tmp" >>"${out}" + echo 'divert' >>"${out}" + return "${rc}" +} + +# Expand a module .te with interfaces (usual modular M4 recipe; /dev/null for gen defs). +expand_module_te() { + local interfaces="$1" + local te="$2" + local out="$3" + + # shellcheck disable=SC2086 + ${M4} ${M4PARAM} -s ${M4SUPPORT} "${EMPTY_GEN_DEF}" "${interfaces}" "${te}" \ + >"${out}" 2>"${out}.err" + return $? +} + +# Expand file_contexts (usual modular M4 recipe for .fc -> .mod.fc). +expand_fc() { + local fc="$1" + local out="$2" + + # shellcheck disable=SC2086 + ${M4} ${M4PARAM} ${M4SUPPORT} "${fc}" >"${out}" 2>"${out}.err" + return $? +} + rlJournalStart rlPhaseStartSetup rlAssertRpm checkpolicy rlRun "command -v m4" rlRun "command -v checkmodule" - rlRun "command -v make" rlRun "command -v semodule_package" - if [ -z "${POLICY_DIR}" ]; then + OUTDIR=$(mktemp -d "${TMPDIR:-/var/tmp}/selinux-policy-m4-bad-data.XXXXXX") + rlRun "test -d ${OUTDIR}" + CLONED_POLICY_DIR="" + + # Macro source priority (Petr): explicit checkout > installed devel > git clone. + if [ -n "${POLICY_DIR}" ]; then + rlAssertExists "${POLICY_DIR}/Rules.modular" + setup_m4_from_git_tree "${POLICY_DIR}" + rlLog "Using SELINUX_POLICY_SRC=${POLICY_DIR}" + elif [ -f "${DEVEL_SUPPORT}/loadable_module.spt" ]; then + rlAssertRpm selinux-policy-devel + setup_m4_from_devel "${DEVEL_SUPPORT}" + rlLog "Using selinux-policy-devel support macros from ${DEVEL_SUPPORT}" + else + CLONED_POLICY_DIR="$(mktemp -d /var/tmp/selinux-policy-src.XXXXXX)" rlLog "Cloning ${POLICY_GIT} branch ${POLICY_BRANCH}" - POLICY_DIR="$(mktemp -d /var/tmp/selinux-policy-src.XXXXXX)" - rlRun "git clone --depth=1 -b ${POLICY_BRANCH} ${POLICY_GIT} ${POLICY_DIR}" + if rlIsOSLike fedora && [ "${POLICY_BRANCH}" != "rawhide" ]; then + # fN may not exist yet on Rawhide (e.g. f45); allow failure then retry. + rlRun "git clone --depth=1 -b ${POLICY_BRANCH} ${POLICY_GIT} ${CLONED_POLICY_DIR}" 0-255 + if [ ! -f "${CLONED_POLICY_DIR}/Rules.modular" ]; then + rlLog "Branch ${POLICY_BRANCH} unavailable; falling back to rawhide" + rlRun "rm -rf ${CLONED_POLICY_DIR}" + CLONED_POLICY_DIR="$(mktemp -d /var/tmp/selinux-policy-src.XXXXXX)" + rlRun "git clone --depth=1 -b rawhide ${POLICY_GIT} ${CLONED_POLICY_DIR}" + fi + else + rlRun "git clone --depth=1 -b ${POLICY_BRANCH} ${POLICY_GIT} ${CLONED_POLICY_DIR}" + fi + rlAssertExists "${CLONED_POLICY_DIR}/Rules.modular" + setup_m4_from_git_tree "${CLONED_POLICY_DIR}" fi - rlAssertExists "${POLICY_DIR}/Rules.modular" - rlRun "chmod +x run.sh" + + # shellcheck disable=SC2086 + rlRun "test -f $(echo ${M4SUPPORT} | awk '{print $1}')" + rlRun "test -f ${IFERROR}" + + M4PARAM="-D enable_mcs -D distro_redhat -D hide_broken_symptoms -D mls_num_sens=16 -D mls_num_cats=1024 -D mcs_num_cats=1024" + EMPTY_GEN_DEF=/dev/null + + rlRun "ln -sf /nonexistent/test_good.if ${OUTDIR}/broken_symlink.if" + rlRun "ln -sf /nonexistent/test_good.mod.fc ${OUTDIR}/broken_symlink.fc" + rlRun "printf '' > ${OUTDIR}/empty.fc" rlPhaseEnd - rlPhaseStartTest "M4 bad-data preprocessing" - rlRun "SELINUX_POLICY_SRC=${POLICY_DIR} ./run.sh" + # --- .if -> all_interfaces.conf --- + rlPhaseStartTest "unclosed interface definition" + rlRun "build_all_interfaces ${OUTDIR}/b1_unclosed.interfaces ${FIXTURES}/interfaces/bad_unclosed.if" 1-255 + rlPhaseEnd + + rlPhaseStartTest "broken M4 syntax in interface file" + rlRun "build_all_interfaces ${OUTDIR}/b1_m4_syntax.interfaces ${FIXTURES}/interfaces/bad_m4_syntax.if" 1-255 + rlPhaseEnd + + rlPhaseStartTest "duplicate interface definition" + rlRun "build_all_interfaces ${OUTDIR}/b1_duplicate.interfaces ${FIXTURES}/interfaces/bad_duplicate.if" 1-255 + rlPhaseEnd + + rlPhaseStartTest "broken gen_require block in interface file" + rlRun "build_all_interfaces ${OUTDIR}/b1_bad_gen_if.interfaces ${FIXTURES}/interfaces/bad_gen_if_build.if" 1-255 + rlPhaseEnd + + rlPhaseStartTest "empty interface template name" + rlRun "build_all_interfaces ${OUTDIR}/b1_empty_ifname.interfaces ${FIXTURES}/interfaces/bad_empty_ifname.if" 1-255 + rlPhaseEnd + + rlPhaseStartTest "missing .if path" + rlRun "build_all_interfaces ${OUTDIR}/b1_missing.interfaces ${OUTDIR}/does_not_exist.if" 1-255 + rlPhaseEnd + + rlPhaseStartTest "directory instead of .if file" + rlRun "build_all_interfaces ${OUTDIR}/b1_directory.interfaces ${BASEDIR}" 1-255 + rlPhaseEnd + + rlPhaseStartTest "broken symlink for .if" + rlRun "build_all_interfaces ${OUTDIR}/b1_symlink.interfaces ${OUTDIR}/broken_symlink.if" 1-255 + rlPhaseEnd + + rlPhaseStartTest "unreadable .if file" + if [ "$(id -u)" -eq 0 ]; then + rlLog "SKIP: root can read mode 000 files; unreadable check is non-root only" + else + rlRun "cp ${FIXTURES}/interfaces/good.if ${OUTDIR}/unreadable.if" + rlRun "chmod 000 ${OUTDIR}/unreadable.if" + rlRun "build_all_interfaces ${OUTDIR}/unreadable_if.interfaces ${OUTDIR}/unreadable.if" 1-255 + fi + rlPhaseEnd + + rlPhaseStartTest "control good interface" + rlRun "build_all_interfaces ${OUTDIR}/b1_good.interfaces ${FIXTURES}/interfaces/good.if" + rlRun "test -s ${OUTDIR}/b1_good.interfaces" + rlPhaseEnd + + GOOD_IF="${OUTDIR}/b1_good.interfaces" + + # --- .te + M4 with interfaces --- + rlPhaseStartTest "control good .if + .te through M4 and checkmodule" + rlRun "expand_module_te ${GOOD_IF} ${FIXTURES}/modules/te_good.te ${OUTDIR}/b2_good.tmp" + rlRun "test -s ${OUTDIR}/b2_good.tmp" + rlRun "${CHECKMODULE} -M -m -o ${OUTDIR}/te_good.mod ${OUTDIR}/b2_good.tmp" + rlRun "test -s ${OUTDIR}/te_good.mod" + rlPhaseEnd + + rlPhaseStartTest "missing .te path at M4 expand" + rlRun "expand_module_te ${GOOD_IF} ${OUTDIR}/does_not_exist.te ${OUTDIR}/b2_missing_te.tmp" 1-255 + rlPhaseEnd + + NEEDS_ARG_IF="${OUTDIR}/needs_arg.interfaces" + + rlPhaseStartTest "interface called with too few arguments" + rlRun "build_all_interfaces ${NEEDS_ARG_IF} ${FIXTURES}/interfaces/needs_arg.if" + rlRun "expand_module_te ${NEEDS_ARG_IF} ${FIXTURES}/modules/te_few_args.te ${OUTDIR}/b2_few_args.tmp" + rlRun "test -s ${OUTDIR}/b2_few_args.tmp" + rlRun "${CHECKMODULE} -M -m -o ${OUTDIR}/te_few.mod ${OUTDIR}/b2_few_args.tmp" 1-255 + rlPhaseEnd + + rlPhaseStartTest "interface called with too many arguments" + rlLog "DOCUMENT: extra interface args are ignored by M4" + rlRun "test -s ${NEEDS_ARG_IF}" + rlRun "expand_module_te ${NEEDS_ARG_IF} ${FIXTURES}/modules/te_many_args.te ${OUTDIR}/b2_many_args.tmp" + rlRun "test -s ${OUTDIR}/b2_many_args.tmp" + rlRun "${CHECKMODULE} -M -m -o ${OUTDIR}/te_many.mod ${OUTDIR}/b2_many_args.tmp" + rlRun "test -s ${OUTDIR}/te_many.mod" + rlPhaseEnd + + # --- M4 OK, bad expanded TE -> checkmodule fails --- + # bad_trunc.if is unclosed at the M4 interface stage (EOF in string), so it is + # rejected before module expand — same class of failure as other broken .if files. + rlPhaseStartTest "truncated allow from interface expansion" + rlRun "build_all_interfaces ${OUTDIR}/bad_trunc.interfaces ${FIXTURES}/interfaces/bad_trunc.if" 1-255 + rlPhaseEnd + + rlPhaseStartTest "broken gen_require expanded from interface" + rlRun "build_all_interfaces ${OUTDIR}/bad_gen_require.interfaces ${FIXTURES}/interfaces/bad_gen_require.if" + rlRun "expand_module_te ${OUTDIR}/bad_gen_require.interfaces ${FIXTURES}/modules/te_gen_require.te ${OUTDIR}/b5_gen_require.tmp" + rlRun "test -s ${OUTDIR}/b5_gen_require.tmp" + rlRun "${CHECKMODULE} -M -m -o ${OUTDIR}/te_gen_require.mod ${OUTDIR}/b5_gen_require.tmp" 1-255 + rlPhaseEnd + + rlPhaseStartTest "unknown type from interface expansion" + rlRun "build_all_interfaces ${OUTDIR}/bad_unknown_type.interfaces ${FIXTURES}/interfaces/bad_unknown_type.if" + rlRun "expand_module_te ${OUTDIR}/bad_unknown_type.interfaces ${FIXTURES}/modules/te_unknown_type.te ${OUTDIR}/b5_unknown_type.tmp" + rlRun "test -s ${OUTDIR}/b5_unknown_type.tmp" + rlRun "${CHECKMODULE} -M -m -o ${OUTDIR}/te_unknown_type.mod ${OUTDIR}/b5_unknown_type.tmp" 1-255 + rlPhaseEnd + + rlPhaseStartTest "unknown permission from interface expansion" + rlRun "build_all_interfaces ${OUTDIR}/bad_unknown_perm.interfaces ${FIXTURES}/interfaces/bad_unknown_perm.if" + rlRun "expand_module_te ${OUTDIR}/bad_unknown_perm.interfaces ${FIXTURES}/modules/te_unknown_perm.te ${OUTDIR}/b5_unknown_perm.tmp" + rlRun "test -s ${OUTDIR}/b5_unknown_perm.tmp" + rlRun "${CHECKMODULE} -M -m -o ${OUTDIR}/te_unknown_perm.mod ${OUTDIR}/b5_unknown_perm.tmp" 1-255 + rlPhaseEnd + + rlPhaseStartTest "garbage token from interface expansion" + rlRun "build_all_interfaces ${OUTDIR}/bad_garbage.interfaces ${FIXTURES}/interfaces/bad_garbage.if" + rlRun "expand_module_te ${OUTDIR}/bad_garbage.interfaces ${FIXTURES}/modules/te_garbage.te ${OUTDIR}/b5_garbage.tmp" + rlRun "test -s ${OUTDIR}/b5_garbage.tmp" + rlRun "${CHECKMODULE} -M -m -o ${OUTDIR}/te_garbage.mod ${OUTDIR}/b5_garbage.tmp" 1-255 + rlPhaseEnd + + rlPhaseStartTest "invalid module line from interface expansion" + rlRun "build_all_interfaces ${OUTDIR}/bad_module_line.interfaces ${FIXTURES}/interfaces/bad_module_line.if" + rlRun "expand_module_te ${OUTDIR}/bad_module_line.interfaces ${FIXTURES}/modules/te_bad_module_line.te ${OUTDIR}/b5_module_line.tmp" + rlRun "test -s ${OUTDIR}/b5_module_line.tmp" + rlRun "${CHECKMODULE} -M -m -o ${OUTDIR}/te_bad_mod.mod ${OUTDIR}/b5_module_line.tmp" 1-255 + rlPhaseEnd + + # --- .fc -> M4 -> .mod.fc --- + rlPhaseStartTest "control good .fc through M4" + rlRun "expand_fc ${FIXTURES}/file_contexts/good.fc ${OUTDIR}/b3_good.mod.fc" + rlRun "test -s ${OUTDIR}/b3_good.mod.fc" + rlPhaseEnd + + rlPhaseStartTest "invalid context survives M4" + rlLog "DOCUMENT: labeling validation deferred to sefcontext_compile" + rlRun "expand_fc ${FIXTURES}/file_contexts/bad_context.fc ${OUTDIR}/b3_bad_context.mod.fc" + rlRun "test -s ${OUTDIR}/b3_bad_context.mod.fc" + rlPhaseEnd + + rlPhaseStartTest "wrong field count in .fc" + rlLog "DOCUMENT: labeling validation deferred to sefcontext_compile" + rlRun "expand_fc ${FIXTURES}/file_contexts/bad_fields.fc ${OUTDIR}/b3_bad_fields.mod.fc" + rlRun "test -s ${OUTDIR}/b3_bad_fields.mod.fc" + rlPhaseEnd + + rlPhaseStartTest "empty .fc file" + rlLog "DOCUMENT: labeling validation deferred to sefcontext_compile" + rlRun "expand_fc ${OUTDIR}/empty.fc ${OUTDIR}/b3_empty_fc.mod.fc" + rlPhaseEnd + + rlPhaseStartTest "path-only line without context in .fc" + rlLog "DOCUMENT: labeling validation deferred to sefcontext_compile" + rlRun "expand_fc ${FIXTURES}/file_contexts/bad_no_context.fc ${OUTDIR}/b3_no_context.mod.fc" + rlRun "test -s ${OUTDIR}/b3_no_context.mod.fc" + rlPhaseEnd + + rlPhaseStartTest "invalid regex metacharacters in .fc path" + rlLog "DOCUMENT: labeling validation deferred to sefcontext_compile" + rlRun "expand_fc ${FIXTURES}/file_contexts/bad_regex.fc ${OUTDIR}/b3_bad_regex.mod.fc" + rlRun "test -s ${OUTDIR}/b3_bad_regex.mod.fc" + rlPhaseEnd + + rlPhaseStartTest "missing .fc path" + rlRun "expand_fc ${OUTDIR}/does_not_exist.fc ${OUTDIR}/b3_missing.mod.fc" 1-255 + rlPhaseEnd + + rlPhaseStartTest "directory instead of .fc file" + rlRun "expand_fc ${BASEDIR} ${OUTDIR}/b3_directory.mod.fc" 1-255 + rlPhaseEnd + + rlPhaseStartTest "broken symlink for .fc" + rlRun "expand_fc ${OUTDIR}/broken_symlink.fc ${OUTDIR}/b3_symlink.mod.fc" 1-255 + rlPhaseEnd + + rlPhaseStartTest "unreadable .fc file" + if [ "$(id -u)" -eq 0 ]; then + rlLog "SKIP: root can read mode 000 files; unreadable check is non-root only" + else + rlRun "cp ${FIXTURES}/file_contexts/good.fc ${OUTDIR}/unreadable.fc" + rlRun "chmod 000 ${OUTDIR}/unreadable.fc" + rlRun "expand_fc ${OUTDIR}/unreadable.fc ${OUTDIR}/unreadable_fc.mod.fc" 1-255 + fi + rlPhaseEnd + + rlPhaseStartTest "broken M4 syntax in .fc" + rlRun "expand_fc ${FIXTURES}/file_contexts/bad_m4_syntax.fc ${OUTDIR}/b3_bad_m4.mod.fc" 1-255 + rlPhaseEnd + + # --- M4-expanded .mod.fc through semodule_package (E2E; labeling deferred) --- + rlPhaseStartTest "bad M4-expanded .mod.fc packaged with good .mod" + rlLog "DOCUMENT: M4 to package E2E; labeling validation deferred to sefcontext_compile" + rlRun "mkdir -p ${OUTDIR}/b6_e2e_build" + rlRun "expand_module_te ${GOOD_IF} ${FIXTURES}/modules/te_good.te ${OUTDIR}/b6_e2e.tmp" + rlRun "${CHECKMODULE} -M -m -o ${OUTDIR}/b6_e2e_build/te_good.mod ${OUTDIR}/b6_e2e.tmp" + rlRun "expand_fc ${FIXTURES}/file_contexts/bad_context.fc ${OUTDIR}/b6_e2e.mod.fc" + rlRun "${SEMODULE_PACKAGE} -o ${OUTDIR}/b6_e2e.pp -m ${OUTDIR}/b6_e2e_build/te_good.mod -f ${OUTDIR}/b6_e2e.mod.fc" + rlRun "test -s ${OUTDIR}/b6_e2e.pp" rlPhaseEnd rlPhaseStartCleanup - if [[ "${POLICY_DIR}" == /var/tmp/selinux-policy-src.* ]]; then - rlRun "rm -rf ${POLICY_DIR}" + if [ -n "${OUTDIR:-}" ] && [ -d "${OUTDIR}" ]; then + rlRun "rm -rf ${OUTDIR}" + fi + if [ -n "${CLONED_POLICY_DIR:-}" ] && [ -d "${CLONED_POLICY_DIR}" ]; then + rlRun "rm -rf ${CLONED_POLICY_DIR}" fi rlPhaseEnd rlJournalPrintText