#!/bin/bash
# vim: dict=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# runtest.sh of /CoreOS/selinux-policy/Sanity/serge-testsuite
# Description: functional test suite for the LSM-based SELinux security module
# Author: Milos Malik <mmalik@redhat.com>
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Copyright (c) 2014 Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing
# to use, modify, copy, or redistribute it subject to the terms
# and conditions of the GNU General Public License version 2.
#
# This program is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this program; if not, write to the Free
# Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Include Beakerlib environment
. /usr/share/beakerlib/beakerlib.sh || exit 1
PACKAGE="selinux-policy"
# Default commit to checkout from the repo.
# This should be updated as needed after verifying that the new version
# doesn't break testing and after applying all necessary tweaks in the TC.
# Run with GIT_BRANCH=master to run the latest upstream version.
DEFAULT_COMMIT="58eaa31c9e0e0a0567990336ae355b4cd309e6e3"
# Default pull requests to merge before running the test.
# If non-empty, then after checking out GIT_BRANCH the listed upstream pull
# requests (by number) are merged, creating a new temporary local branch.
DEFAULT_PULLS=""
# Default SELinux Patchwork series to apply before running the test.
DEFAULT_PATCHES=""
# Optional test parameter - location of testuite git.
GIT_URL=${GIT_URL:-"git://github.com/SELinuxProject/selinux-testsuite"}
# Optional test parameter - timeout for detecting lost packets
NETWORK_TIMEOUT=${NETWORK_TIMEOUT:-4}
# Optional test parameter - branch containing tests.
if [ -z "$GIT_BRANCH" ]; then
GIT_BRANCH="$DEFAULT_COMMIT"
# Use default cherries only if branch is default and they are not overriden
GIT_PULLS="${GIT_PULLS:-"$DEFAULT_PULLS"}"
GIT_PATCHES="${GIT_PATCHES:-"$DEFAULT_PATCHES"}"
fi
# DISTRO unset needed for policy devel Makefile... (Beaker sets it to "RHEL-...")
TS_ENV="env -u ARCH -u DISTRO LANG=C"
# Check if pipefail is enabled to restore original setting.
# See: https://unix.stackexchange.com/a/73180
if false | true; then
PIPEFAIL_ENABLE="set -o pipefail"
PIPEFAIL_DISABLE="set +o pipefail"
else
PIPEFAIL_ENABLE=""
PIPEFAIL_DISABLE=""
fi
if rlIsRHEL 5 ; then
# On RHEL-5 sort -V doesn't work, so just pretend we have the oldest kernel
function kver_ge() { false; }
function kver_lt() { true; }
function kver_le() { true; }
function kver_gt() { false; }
else
function version_le() {
{ echo "$1"; echo "$2"; } | sort -V | tail -n 1 | grep -qx "$2"
}
function kver_ge() { version_le "$1" "$(uname -r)"; }
function kver_lt() { ! kver_ge "$1"; }
function kver_le() { version_le "$(uname -r)" "$1"; }
function kver_gt() { ! kver_le "$1"; }
fi
function installDepsYum() {
local yum="$1"; shift
if "$yum" --help | grep -q -- --skip-broken; then
"$yum" install -y --skip-broken $*
else
for req in $*; do
if ! rpm -q --quiet --whatprovides "$req"; then
"$yum" install -y "$req" || true
fi
done
fi
}
function installDeps() {
if type yum >/dev/null; then
installDepsYum yum "$@"
elif type dnf >/dev/null; then
installDepsYum dnf "$@"
fi
}
function boolGet() {
getsebool "$1" | cut -d ' ' -f 3
}
function boolSet() {
getsebool "$1" &>/dev/null || return 0
setsebool "$1" "$2" || return 1
[ "$(boolGet "$1")" == "$2" ]
}
rlJournalStart
rlPhaseStartSetup "Install"
# We need to install the kernel-* packages by ourselves, since we need
# the same versions as the running kernel. And since we already need a
# reliable package install function, let's just install all the
# dependencies here. Thus we don't need to maintain duplicate lists of
# package requirements in many places (RH repo, Fedora kernel dist-git,
# CKI).
PKG_SUFFIX=""
KERNEL_VERSION="$(uname -r)"
PKG_VERSION="${KERNEL_VERSION%+debug}"
if [ "$PKG_VERSION" != "$KERNEL_VERSION" ]; then
rlLog "Detected debug kernel running."
PKG_SUFFIX="-debug"
fi
REQUIRES="
kernel$PKG_SUFFIX-modules-extra-$PKG_VERSION
kernel-rt$PKG_SUFFIX-modules-extra-$PKG_VERSION
kernel$PKG_SUFFIX-devel-$PKG_VERSION
kernel-rt$PKG_SUFFIX-devel-$PKG_VERSION
/usr/bin/unbuffer
attr
audit
checkpolicy
curl
dosfstools
e2fsprogs
elfutils-libelf-devel
expect
gcc
git
grep
iptables
jfsutils
keyutils-libs-devel
libbpf-devel
libibverbs-devel
libselinux-devel
libselinux-utils
libsepol-devel
libuuid-devel
lksctp-tools-devel
mktemp
nc
netlabel_tools
net-tools
nftables
nmap-ncat
perl-Test
perl-Test-Harness
perl-Test-Simple
policycoreutils
policycoreutils-devel
policycoreutils-python
python2-lxml
python3-lxml
quota
rdma-core-devel
selinux-policy-devel
setools-console
xfsprogs-devel
"
rlRun "installDeps \$REQUIRES" 0 "Install requires"
# The CRB repo with libbpf-devel might not be enabled on RHEL
if rlIsRHEL '>=8'; then
for repo in "rhel-CRB" "beaker-CRB"; do
rpm -q libbpf-devel &>/dev/null && break
rlRun "dnf install --enablerepo $repo -y libbpf-devel" 0-255
done
fi
rlPhaseEnd
rlPhaseStartSetup
rlAssertRpm ${PACKAGE}
rlAssertRpm audit
rlFileBackup /etc/selinux/semanage.conf
# running the testsuite in /tmp causes permission denied messages
# rlRun "TmpDir=\$(mktemp -d)" 0 "Creating tmp directory"
# rlRun "pushd $TmpDir"
if ! rlIsRHEL 5 ; then
# version_le() sanity check:
rlRun "version_le 4.10 4.10"
rlRun "version_le 4.10 4.10.0"
rlRun "version_le 4.10 4.10.1"
rlRun "! version_le 4.10 4.9"
rlRun "! version_le 4.10.0 4.10"
fi
if [ -d /sys/fs/selinux ]; then
selinuxfs=/sys/fs/selinux
else
selinuxfs=/selinux
fi
if rlIsRHEL '<7.3'; then
use_cil=n
else
use_cil=y
fi
make_vars="SELINUXFS=$selinuxfs SUPPORTS_CIL=$use_cil"
# test turns this boolean off
rlRun "BACKUP_allow_domain_fd_use=\$(boolGet allow_domain_fd_use)"
rlRun "BACKUP_domain_can_mmap_files=\$(boolGet domain_can_mmap_files)"
# test expects that domains cannot map files by default
rlRun "boolSet domain_can_mmap_files off"
rlRun "setenforce 1"
rlRun "sestatus"
if grep 'expand-check' /etc/selinux/semanage.conf; then
rlRun "sed -i 's/^expand-check[ ]*=.*$/expand-check = 0/' /etc/selinux/semanage.conf"
else
rlRun "echo 'expand-check = 0' >>/etc/selinux/semanage.conf"
fi
if [ ! -d selinux-testsuite ]; then
if ! rlRun "git clone $GIT_URL selinux-testsuite" 0; then
rlLogFatal "Unable to clone the testsuite repo!"
rlPhaseEnd
exit 127
fi
rlRun "pushd selinux-testsuite"
if ! rlRun "git checkout $GIT_BRANCH" 0; then
rlLogFatal "Unable to checkout the requested branch!"
rlPhaseEnd
exit 127
fi
for _ in $GIT_PULLS $GIT_PATCHES; do
rlRun "git config --global user.email nobody@redhat.com"
rlRun "git config --global user.name 'Nemo Nobody'"
rlRun "git checkout -b testing-cherry-picks" 0
break
done
for pull in $GIT_PULLS; do
ref="refs/pull/$pull/head"
if ! rlRun "git fetch origin $ref:$ref" 0; then
rlRun "git checkout $GIT_BRANCH" 0
rlLogWarning "PR merge failed, falling back to GIT_BRANCH"
break
fi
if ! rlRun "git merge --no-edit $ref" 0; then
rlRun "git merge --abort" 0
rlRun "git checkout $GIT_BRANCH" 0
rlLogWarning "PR merge failed, falling back to GIT_BRANCH"
break
fi
done
$PIPEFAIL_ENABLE
for pwseries in $GIT_PATCHES; do
url="https://patchwork.kernel.org/series/$pwseries/mbox/"
if ! rlRun "curl $url | git am -"; then
rlRun "git checkout $GIT_BRANCH" 0
rlLogWarning "Applying patch failed, falling back to GIT_BRANCH"
break
fi
done
$PIPEFAIL_DISABLE
rlRun "popd"
fi
rlRun "pushd selinux-testsuite"
# backup code before making tweaks
rlFileBackup "."
if [ "$VERBOSE" = "1" ]; then
rlRun "sed -i 's/\(use Test::Harness;\)/\1 \$Test::Harness::verbose = TRUE;/' tests/runtests.pl" 0 \
"Enable verbose output"
fi
{
echo "#ifndef IFF_NAPI"
echo "#define IFF_NAPI 0x0010"
echo "#endif"
echo "#ifndef IFF_NAPI_FRAGS"
echo "#define IFF_NAPI_FRAGS 0x0020"
echo "#endif"
echo "#ifndef IFF_NO_PI"
echo "#define IFF_NO_PI 0x1000"
echo "#endif"
} | rlRun "tee -a tests/tun_tap/tun_common.h" 0 \
"Harden tun_tap test against missing defs"
exclude_tests=""
force_tests=""
for file in ./tests/nnp*/execnnp.c; do
rlRun "sed -i 's/3.18/3.9/' $file" 0 \
"Fix up kernel version in nnp test"
done
if rlIsRHEL 5 ; then
rlRun "sed -i '/unconfined_devpts_t/d' policy/test_policy.if" 0
rlRun "sed -i 's/read_file_perms/r_file_perms/' policy/*.te" 0
rlRun "sed -i 's/mmap_file_perms/rx_file_perms/' policy/*.te" 0
rlRun "sed -i 's/list_dir_perms/r_dir_perms/' policy/*.te" 0
rlRun "sed -i 's/ open / /' policy/*.te" 0
rlRun "sed -i 's/^sysadm_bin_spec_domtrans_to/userdom_sysadm_bin_spec_domtrans_to/' policy/*.te" 0
rlRun "sed -i 's/^corecmd_exec_bin(\(.*\))$/corecmd_exec_bin(\1)\ncorecmd_exec_sbin(\1)/' policy/*.te" 0
rlRun "sed -i 's/^corecmd_bin_entry_type(\(.*\))$/corecmd_bin_entry_type(\1)\ncorecmd_sbin_entry_type(\1)/' policy/*.te" 0
rlRun "sed -i 's/^userdom_search_user_home_dirs(\(.*\))$/userdom_search_user_home_dirs(user, \1)/' policy/*.te" 0
fi
if rlIsRHEL 8; then
# CONFIG_KEY_DH_OPERATIONS not enabled on RHEL-8 :(
exclude_tests+=" keys"
fi
if rlIsRHEL "<8.2"; then
rlRun "sed -i '/SUBDIRS += bpf/d;/export CFLAGS += -DHAVE_BPF/d' tests/Makefile" 0 \
"RHEL < 8.2 doesn't ship libbpf => disable BPF subtests"
fi
rlRun "sed -i 's/tm\.tv_sec = [0-9]*;/tm.tv_sec = $NETWORK_TIMEOUT;/' ./tests/*/*.c" 0 \
"Tweak timeout in networking tests" # 2 secs is too little for SCTP test
if rlIsRHEL; then
if kver_lt "3.10.0-349"; then
# c4684bbdac07 [security] selinux: Permit bounded transitions under NO_NEW_PRIVS or NOSUID
# da74590f6501 [security] selinux: reject setexeccon() on MNT_NOSUID applications with -EACCES
exclude_tests+=" nnp_nosuid"
fi
if kver_lt "3.10.0-693"; then
# I don't know when exactly these tests start passing, so I'm just
# disabling them for anything below the RHEL-7.4 kernel...
exclude_tests+=" inet_socket"
exclude_tests+=" filesystem/ext4 filesystem/xfs filesystem/jfs filesystem/vfat"
fi
if kver_lt "3.10.0-875"; then
rlLog "No xperms support => disable xperms testing"
rlRun "sed -i '/TARGETS += test_ioctl_xperms\.te/d' policy/Makefile"
rlRun "sed -i 's/\$kernver >= 30/\$kernver >= 999999/' tests/ioctl/test"
fi
# workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1613056
# (if running kernel version sorts inside the known-bug window, then
# we need to apply the workaround)
if kver_ge "3.10.0-875" && kver_lt "3.10.0-972"; then
rlLog "Applying workaround for BZ 1613056..."
rlRun "cat >>policy/test_ipc.te <<<'allow_map(ipcdomain, tmpfs_t, file)'"
rlRun "cat >>policy/test_mmap.te <<<'allow_map(test_execmem_t, tmpfs_t, file)'"
rlRun "cat >>policy/test_mmap.te <<<'allow_map(test_no_execmem_t, tmpfs_t, file)'"
fi
if kver_ge 4.18; then
force_tests+=" sctp"
fi
if kver_ge 4.18.0-80.19; then
force_tests+=" cgroupfs_label"
fi
if kver_lt 4.18.0-152; then
# 2839e8ee09517 [net] sctp: add SCTP_ADDR_MADE_PRIM event
rlRun "sed -i 's/\\\$test_asconf = 1;/\$test_count -= 3;/g' tests/sctp/test" 0 \
"Disable SCTP ASCONF test (not testable on this kernel)"
# 3add2b6b02518 [net] sctp: add SCTP_SEND_FAILED_EVENT event
rlRun "sed -i 's/SCTP_SEND_FAILED_EVENT/SCTP_STREAM_CHANGE_EVENT + 1/g' tests/sctp/*.c" 0 \
"Fix SCTP test compilation on old RHEL kernels"
fi
# Needs:
# e4cfa05e9bfe ("selinux: Add xfs quota command types")
# (not backported to any RHEL at this point - TODO update the check once it is)
script1='s/\$test_count += 62;/$test_count = 55;/g'
script2='s/\$quota_checks += 1;/$quota_checks = 0;/g'
# for some reason this is needed for older RHEL 7 versions...
script3='s/\$test_count += 69;/$test_count = 55;/g'
rlRun "sed -i -E -e '$script1' -e '$script2' -e '$script3' tests/filesystem/test" 0 \
"Apply workaround for missing XFS quota checks"
fi
# CKI mainline kernels don't ship with module build infrastructure
# just yet. Also, RHEL-8 CKI kernel-devel programs are
# cross-compiled badly for alt arches, so try executing one of them.
if ! "/lib/modules/$(uname -r)/build/scripts/basic/fixdep" 2>&1 | grep -q "Usage"; then
exclude_tests+=" module_load"
fi
# CKI kernels are cross-compiled and generate invalid BTF for s390x
if [ "$(rlGetPrimaryArch)" = s390x ] && [ -r /sys/kernel/btf/vmlinux ]; then
# Check whether the magic number is stored big-endian
btf_head="$(head -c 2 /sys/kernel/btf/vmlinux | hexdump -e '/1 "%02x"')"
if [ "$btf_head" != eb9f ]; then
exclude_tests+=" bpf"
fi
fi
if [ -n "$exclude_tests" ] ; then
rlRun "sed -i '/^[^[:space:]]*:\(\| .*\)\$/i SUBDIRS:=\$(filter-out $exclude_tests, \$(SUBDIRS))' tests/Makefile" 0 \
"Exclude not applicable tests: $exclude_tests"
fi
if [ -n "$force_tests" ] ; then
rlRun "sed -i '/^[^[:space:]]*:\(\| .*\)\$/i SUBDIRS:=\$(filter-out $force_tests, \$(SUBDIRS))\nSUBDIRS += $force_tests' tests/Makefile" 0 \
"Force applicable tests: $force_tests"
fi
if ! modprobe sctp 2>/dev/null; then
script1='s/runcon -t test_sctp_socket_t/true/g'
script2='s/runcon -t test_no_sctp_socket_t/false/g'
rlRun "sed -i -e '$script1' -e '$script2' ./tests/extended_socket_class/test" 0 \
"No SCTP support => fix up extended_socket_class test"
fi
# on aarch64 and s390x the kernel support for Bluetooth is turned
# off so we disable the Bluetooth socket tests there
case "$(rlGetPrimaryArch)" in
aarch64|s390x)
script1='s/runcon -t test_bluetooth_socket_t/true/g'
script2='s/runcon -t test_no_bluetooth_socket_t/false/g'
rlRun "sed -i -e '$script1' -e '$script2' ./tests/extended_socket_class/test" 0 \
"No Bluetooth support => fix up extended_socket_class test"
;;
esac
# Initialize report.
rlRun "echo 'Remote: $GIT_URL' >results.log" 0
rlRun "echo 'Branch: $GIT_BRANCH' >>results.log" 0
rlRun "echo 'Commit: $(git rev-parse $GIT_BRANCH)' >>results.log" 0
rlRun "echo 'GH PRs: ${GIT_PULLS:-"(none)"}' >>results.log" 0
rlRun "echo 'Series: ${GIT_PATCHES:-"(none)"}' >>results.log" 0
rlRun "echo 'Kernel: $(uname -r)' >>results.log" 0
rlRun "echo 'Policy: $(rpm -q selinux-policy)' >>results.log" 0
rlRun "echo ' $(rpm -q checkpolicy)' >>results.log" 0
rlRun "echo ' $(rpm -q libselinux)' >>results.log" 0
rlRun "echo ' $(rpm -q libsemanage)' >>results.log" 0
rlRun "echo ' $(rpm -q libsepol)' >>results.log" 0
rlRun "echo ' $(rpm -q policycoreutils)' >>results.log" 0
rlRun "echo '' >>results.log" 0
rlRun "popd"
rlRun "AUDIT_FILE=\"\$(mktemp)\""
rlRun "auditctl -w \"\$AUDIT_FILE\" -p w" 0 \
"Enable creation of PATH audit records"
rlPhaseEnd
rlPhaseStartTest
rlRun "pushd selinux-testsuite"
rlRun "$TS_ENV make $make_vars" 0
rlRun "cat results.log" 0
$PIPEFAIL_ENABLE
rlRun "$TS_ENV unbuffer make -s test $make_vars 2>&1 | tee -a results.log" 0
$PIPEFAIL_DISABLE
rlRun "popd"
rlPhaseEnd
rlPhaseStartCleanup
rlRun "auditctl -W \"\$AUDIT_FILE\" -p w" 0 \
"Remove rule for creation of PATH audit records"
rlRun "rm -f \"\$AUDIT_FILE\""
# rlSEBooleanRestore
# rlSEBooleanRestore allow_domain_fd_use
# none of above-mentioned commands is able to correctly restore the value in the boolean
rlRun "boolSet domain_can_mmap_files $BACKUP_domain_can_mmap_files"
rlRun "boolSet allow_domain_fd_use $BACKUP_allow_domain_fd_use"
rlRun "pushd selinux-testsuite"
# Submit report to beaker.
rlFileSubmit "results.log" "selinux-testsuite.results.$(uname -r).txt"
rlRun "$TS_ENV make -s -C policy unload $make_vars" 0-2
rlRun "$TS_ENV make -s clean $make_vars" 0-2
rlRun "popd"
rlRun "sleep 5" 0
rlRun "dmesg | grep -i \"rcu_sched detected stalls\"" 1
rlFileRestore
rlPhaseEnd
rlJournalPrintText
rlJournalEnd