public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Akhil Kohli <akkohli@redhat.com>
To: git-commits@fedoraproject.org
Subject: [tests/selinux] pr775-checkpolicy-revdeps: selinux-policy/m4-bad-data: add M4 bad-data tests for modular policy builds
Date: Fri, 11 Sep 2026 13:23:55 GMT	[thread overview]
Message-ID: <178913303556.1.14525113001861399424.tests-selinux-6ed096cf7f92@fedoraproject.org> (raw)

            A new commit has been pushed.

            Repo   : tests/selinux
            Branch : pr775-checkpolicy-revdeps
            Commit : 6ed096cf7f92ee789974f23f209c07348039cea3
            Author : Akhil Kohli <akkohli@redhat.com>
            Date   : 2026-08-13T10:26:03+02:00
            Stats  : +529/-0 in 31 file(s)
            URL    : https://src.fedoraproject.org/tests/selinux/c/6ed096cf7f92ee789974f23f209c07348039cea3?branch=pr775-checkpolicy-revdeps

            Log:
            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.

33 test cases (42 harness pass steps) with minimal standalone fixtures.

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>

---
diff --git a/selinux-policy/m4-bad-data/PURPOSE b/selinux-policy/m4-bad-data/PURPOSE
new file mode 100644
index 0000000..ea14daa
--- /dev/null
+++ b/selinux-policy/m4-bad-data/PURPOSE
@@ -0,0 +1,10 @@
+PURPOSE of /CoreOS/selinux-policy/Sanity/m4-bad-data
+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).

diff --git a/selinux-policy/m4-bad-data/fixtures/file_contexts/bad_context.fc b/selinux-policy/m4-bad-data/fixtures/file_contexts/bad_context.fc
new file mode 100644
index 0000000..06aec43
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/file_contexts/bad_context.fc
@@ -0,0 +1 @@
+/usr/bin/bad	not_a_valid_selinux_context

diff --git a/selinux-policy/m4-bad-data/fixtures/file_contexts/bad_fields.fc b/selinux-policy/m4-bad-data/fixtures/file_contexts/bad_fields.fc
new file mode 100644
index 0000000..13821d6
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/file_contexts/bad_fields.fc
@@ -0,0 +1 @@
+only_one_field_on_this_line

diff --git a/selinux-policy/m4-bad-data/fixtures/file_contexts/bad_m4_syntax.fc b/selinux-policy/m4-bad-data/fixtures/file_contexts/bad_m4_syntax.fc
new file mode 100644
index 0000000..7f4dca9
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/file_contexts/bad_m4_syntax.fc
@@ -0,0 +1 @@
+divert(-1

diff --git a/selinux-policy/m4-bad-data/fixtures/file_contexts/bad_no_context.fc b/selinux-policy/m4-bad-data/fixtures/file_contexts/bad_no_context.fc
new file mode 100644
index 0000000..7c14f2e
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/file_contexts/bad_no_context.fc
@@ -0,0 +1 @@
+/usr/bin/foo_only_path_no_context

diff --git a/selinux-policy/m4-bad-data/fixtures/file_contexts/bad_regex.fc b/selinux-policy/m4-bad-data/fixtures/file_contexts/bad_regex.fc
new file mode 100644
index 0000000..7c122e4
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/file_contexts/bad_regex.fc
@@ -0,0 +1 @@
+/usr/bin/[unclosed(regex	--	system_u:object_r:test_good_exec_t:s0

diff --git a/selinux-policy/m4-bad-data/fixtures/file_contexts/good.fc b/selinux-policy/m4-bad-data/fixtures/file_contexts/good.fc
new file mode 100644
index 0000000..12b26ca
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/file_contexts/good.fc
@@ -0,0 +1 @@
+/usr/bin/test_good	--	system_u:object_r:test_good_exec_t:s0

diff --git a/selinux-policy/m4-bad-data/fixtures/interfaces/bad_duplicate.if b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_duplicate.if
new file mode 100644
index 0000000..1e887a5
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_duplicate.if
@@ -0,0 +1,6 @@
+interface(`dup_iface',`
+	type dup_t;
+')
+interface(`dup_iface',`
+	type dup2_t;
+')

diff --git a/selinux-policy/m4-bad-data/fixtures/interfaces/bad_empty_ifname.if b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_empty_ifname.if
new file mode 100644
index 0000000..536347f
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_empty_ifname.if
@@ -0,0 +1,3 @@
+interface(``,`
+	type empty_name_t;
+')

diff --git a/selinux-policy/m4-bad-data/fixtures/interfaces/bad_garbage.if b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_garbage.if
new file mode 100644
index 0000000..bbfd2f6
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_garbage.if
@@ -0,0 +1,3 @@
+interface(`bad_garbage',`
+	@@@not_valid_selinux_or_m4@@@
+')

diff --git a/selinux-policy/m4-bad-data/fixtures/interfaces/bad_gen_if_build.if b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_gen_if_build.if
new file mode 100644
index 0000000..02c4e15
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_gen_if_build.if
@@ -0,0 +1,3 @@
+interface(`bad_gen_if_build',`
+	gen_require(`type $1
+')

diff --git a/selinux-policy/m4-bad-data/fixtures/interfaces/bad_gen_require.if b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_gen_require.if
new file mode 100644
index 0000000..bbfa3a8
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_gen_require.if
@@ -0,0 +1,4 @@
+interface(`bad_gen_require',`
+	gen_require(`type $1 class file { read };')
+	allow $1 self:file read;
+')

diff --git a/selinux-policy/m4-bad-data/fixtures/interfaces/bad_m4_syntax.if b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_m4_syntax.if
new file mode 100644
index 0000000..1d9bc85
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_m4_syntax.if
@@ -0,0 +1 @@
+define(`broken_define'

diff --git a/selinux-policy/m4-bad-data/fixtures/interfaces/bad_module_line.if b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_module_line.if
new file mode 100644
index 0000000..0111414
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_module_line.if
@@ -0,0 +1,3 @@
+interface(`bad_module_line',`
+	module duplicate_module_line 1.0;
+')

diff --git a/selinux-policy/m4-bad-data/fixtures/interfaces/bad_trunc.if b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_trunc.if
new file mode 100644
index 0000000..8f5ed17
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_trunc.if
@@ -0,0 +1,3 @@
+interface(`bad_trunc',`
+	gen_require(`type $1; class file { read };')
+	allow $1 self:file {

diff --git a/selinux-policy/m4-bad-data/fixtures/interfaces/bad_unclosed.if b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_unclosed.if
new file mode 100644
index 0000000..7c377dd
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_unclosed.if
@@ -0,0 +1,3 @@
+interface(`bad_unclosed',`
+	gen_require(`type $1;')
+	allow $1 self:file read;

diff --git a/selinux-policy/m4-bad-data/fixtures/interfaces/bad_unknown_perm.if b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_unknown_perm.if
new file mode 100644
index 0000000..94b83de
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_unknown_perm.if
@@ -0,0 +1,4 @@
+interface(`bad_unknown_perm',`
+	gen_require(`type $1; class file { read };')
+	allow $1 self:file circular_ref;
+')

diff --git a/selinux-policy/m4-bad-data/fixtures/interfaces/bad_unknown_type.if b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_unknown_type.if
new file mode 100644
index 0000000..710f141
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/interfaces/bad_unknown_type.if
@@ -0,0 +1,3 @@
+interface(`bad_unknown_type',`
+	allow undeclared_type_t self:file read;
+')

diff --git a/selinux-policy/m4-bad-data/fixtures/interfaces/good.if b/selinux-policy/m4-bad-data/fixtures/interfaces/good.if
new file mode 100644
index 0000000..bc5261d
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/interfaces/good.if
@@ -0,0 +1,4 @@
+interface(`test_good_iface',`
+	gen_require(`type $1; class file { read };')
+	allow $1 self:file read;
+')

diff --git a/selinux-policy/m4-bad-data/fixtures/interfaces/needs_arg.if b/selinux-policy/m4-bad-data/fixtures/interfaces/needs_arg.if
new file mode 100644
index 0000000..00b619e
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/interfaces/needs_arg.if
@@ -0,0 +1,4 @@
+interface(`needs_arg',`
+	gen_require(`type $1; class file { read };')
+	allow $1 self:file read;
+')

diff --git a/selinux-policy/m4-bad-data/fixtures/modules/te_bad_module_line.te b/selinux-policy/m4-bad-data/fixtures/modules/te_bad_module_line.te
new file mode 100644
index 0000000..c33368a
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/modules/te_bad_module_line.te
@@ -0,0 +1,8 @@
+module te_bad_mod 1.0;
+
+require {
+	type foo_t;
+	class file { read };
+}
+
+bad_module_line()

diff --git a/selinux-policy/m4-bad-data/fixtures/modules/te_few_args.te b/selinux-policy/m4-bad-data/fixtures/modules/te_few_args.te
new file mode 100644
index 0000000..7ac9436
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/modules/te_few_args.te
@@ -0,0 +1,8 @@
+module te_few 1.0;
+
+require {
+	type foo_t;
+	class file { read };
+}
+
+needs_arg()

diff --git a/selinux-policy/m4-bad-data/fixtures/modules/te_garbage.te b/selinux-policy/m4-bad-data/fixtures/modules/te_garbage.te
new file mode 100644
index 0000000..cb7daf4
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/modules/te_garbage.te
@@ -0,0 +1,8 @@
+module te_garbage 1.0;
+
+require {
+	type foo_t;
+	class file { read };
+}
+
+bad_garbage()

diff --git a/selinux-policy/m4-bad-data/fixtures/modules/te_gen_require.te b/selinux-policy/m4-bad-data/fixtures/modules/te_gen_require.te
new file mode 100644
index 0000000..8c84961
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/modules/te_gen_require.te
@@ -0,0 +1,8 @@
+module te_gen_require 1.0;
+
+require {
+	type foo_t;
+	class file { read };
+}
+
+bad_gen_require(foo_t)

diff --git a/selinux-policy/m4-bad-data/fixtures/modules/te_good.te b/selinux-policy/m4-bad-data/fixtures/modules/te_good.te
new file mode 100644
index 0000000..753237a
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/modules/te_good.te
@@ -0,0 +1,8 @@
+module te_good 1.0;
+
+require {
+	type foo_t;
+	class file { read };
+}
+
+test_good_iface(foo_t)

diff --git a/selinux-policy/m4-bad-data/fixtures/modules/te_many_args.te b/selinux-policy/m4-bad-data/fixtures/modules/te_many_args.te
new file mode 100644
index 0000000..e481b8a
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/modules/te_many_args.te
@@ -0,0 +1,8 @@
+module te_many 1.0;
+
+require {
+	type foo_t;
+	class file { read };
+}
+
+needs_arg(foo_t, extra_unused)

diff --git a/selinux-policy/m4-bad-data/fixtures/modules/te_trunc.te b/selinux-policy/m4-bad-data/fixtures/modules/te_trunc.te
new file mode 100644
index 0000000..4f56f72
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/modules/te_trunc.te
@@ -0,0 +1,8 @@
+module te_trunc 1.0;
+
+require {
+	type foo_t;
+	class file { read };
+}
+
+bad_trunc(foo_t)

diff --git a/selinux-policy/m4-bad-data/fixtures/modules/te_unknown_perm.te b/selinux-policy/m4-bad-data/fixtures/modules/te_unknown_perm.te
new file mode 100644
index 0000000..03dd324
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/modules/te_unknown_perm.te
@@ -0,0 +1,8 @@
+module te_unknown_perm 1.0;
+
+require {
+	type foo_t;
+	class file { read };
+}
+
+bad_unknown_perm(foo_t)

diff --git a/selinux-policy/m4-bad-data/fixtures/modules/te_unknown_type.te b/selinux-policy/m4-bad-data/fixtures/modules/te_unknown_type.te
new file mode 100644
index 0000000..ea4724c
--- /dev/null
+++ b/selinux-policy/m4-bad-data/fixtures/modules/te_unknown_type.te
@@ -0,0 +1,8 @@
+module te_unknown_type 1.0;
+
+require {
+	type foo_t;
+	class file { read };
+}
+
+bad_unknown_type()

diff --git a/selinux-policy/m4-bad-data/main.fmf b/selinux-policy/m4-bad-data/main.fmf
new file mode 100644
index 0000000..7ecf218
--- /dev/null
+++ b/selinux-policy/m4-bad-data/main.fmf
@@ -0,0 +1,18 @@
+summary: M4 bad-data tests for modular policy preprocessing
+contact: Akhil Kohli <akkohli@redhat.com>
+test: ./runtest.sh
+framework: beakerlib
+component:
+  - selinux-policy
+  - checkpolicy
+require:
+  - checkpolicy
+  - m4
+  - git
+  - policycoreutils
+  - selinux-policy-devel
+recommend:
+  - selinux-policy
+  - selinux-policy-targeted
+duration: 15m
+enabled: true

diff --git a/selinux-policy/m4-bad-data/runtest.sh b/selinux-policy/m4-bad-data/runtest.sh
new file mode 100755
index 0000000..8a3ee22
--- /dev/null
+++ b/selinux-policy/m4-bad-data/runtest.sh
@@ -0,0 +1,379 @@
+#!/bin/bash
+# vim: dict=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+#   runtest.sh of /CoreOS/selinux-policy/Sanity/m4-bad-data
+#   Description: M4 bad-data tests for modular policy preprocessing
+#   Author: Akhil Kohli <akkohli@redhat.com>
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+. /usr/share/beakerlib/beakerlib.sh || exit 1
+
+PACKAGE="selinux-policy"
+POLICY_GIT="${SELINUX_POLICY_GIT:-https://github.com/fedora-selinux/selinux-policy.git}"
+POLICY_DIR="${SELINUX_POLICY_SRC:-}"
+
+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
+    test -e /etc/os-release && os_release='/etc/os-release' || os_release='/usr/lib/os-release'
+    # shellcheck disable=SC1090
+    . "${os_release}"
+    if rlIsOSLike fedora; then
+        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
+        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 semodule_package"
+
+        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}"
+            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
+
+        # 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
+
+    # --- .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 [ -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
+rlJournalEnd

                 reply	other threads:[~2026-09-11 13:23 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=178913303556.1.14525113001861399424.tests-selinux-6ed096cf7f92@fedoraproject.org \
    --to=akkohli@redhat.com \
    --cc=git-commits@fedoraproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox