selinux-policy/m4-bad-data: add M4 bad-data tests for modular policy builds
Add beakerlib/TMT coverage and fixtures for M4 preprocessing of modular
policy builds: .if to all_interfaces.conf, .te + interfaces to .tmp
(then checkmodule), and .fc to .mod.fc, using live support macros from a
selinux-policy checkout and a snapshotted modular M4 recipe.
Each case is its own rlRun phase in runtest.sh. Covers interface path
validation (including duplicates and broken gen_require), .te arity
edge cases, post-M4 checkmodule failures from bad interface expansion,
.fc path edge cases, M4-to-semodule_package E2E, and .fc content where
labeling validation is deferred to sefcontext_compile.
When SELINUX_POLICY_SRC is unset, clones fedora-selinux/selinux-policy
using a host-detected branch (f$VERSION_ID on Fedora, c${major}s
otherwise), overridable with SELINUX_POLICY_BRANCH.
Signed-off-by: Akhil Kohli <akkohli@redhat.com>
This commit is contained in:
parent
d10bf3b3f9
commit
5cd19cd9d3
7 changed files with 338 additions and 810 deletions
|
|
@ -3,3 +3,8 @@ Author: Akhil Kohli <akkohli@redhat.com>
|
|||
|
||||
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).
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
/tmp gen_context(system_u:object_r:tmp_t,s0)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
interface(`test_good_iface',`
|
||||
gen_require(`type $1; class file { read };')
|
||||
allow $1 self:file read;
|
||||
')
|
||||
|
|
@ -8,9 +8,9 @@ component:
|
|||
require:
|
||||
- checkpolicy
|
||||
- m4
|
||||
- make
|
||||
- git
|
||||
- policycoreutils
|
||||
- selinux-policy-devel
|
||||
recommend:
|
||||
- selinux-policy
|
||||
- selinux-policy-targeted
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue