From 70236f85f268357f2d0cdc92bdbc4ab977fcfdba Mon Sep 17 00:00:00 2001 From: Christopher Dryden Date: Sun, 28 Dec 2025 14:31:21 +0000 Subject: [PATCH 1/2] CI: Add SMACK test runner for GNU tests --- .github/workflows/GnuTests.yml | 59 +++++++++++++- util/run-gnu-tests-smack-ci.sh | 143 +++++++++++++++++++++++++++++++++ 2 files changed, 198 insertions(+), 4 deletions(-) create mode 100755 util/run-gnu-tests-smack-ci.sh diff --git a/.github/workflows/GnuTests.yml b/.github/workflows/GnuTests.yml index dd11f926f0a..363abf9123f 100644 --- a/.github/workflows/GnuTests.yml +++ b/.github/workflows/GnuTests.yml @@ -2,7 +2,7 @@ name: GnuTests # spell-checker:ignore (abbrev/names) CodeCov gnulib GnuTests Swatinem # spell-checker:ignore (jargon) submodules devel -# spell-checker:ignore (libs/utils) autopoint chksum dpkg getenforce getlimits gperf lcov libexpect limactl pyinotify setenforce shopt texinfo valgrind libattr libcap taiki-e +# spell-checker:ignore (libs/utils) autopoint chksum dpkg getenforce getlimits gperf lcov libexpect limactl pyinotify setenforce shopt texinfo valgrind libattr libcap taiki-e zstd cpio # spell-checker:ignore (options) Ccodegen Coverflow Cpanic Zpanic # spell-checker:ignore (people) Dawid Dziurla * dawidd dtolnay # spell-checker:ignore (vars) FILESET SUBDIRS XPASS @@ -31,6 +31,7 @@ env: TEST_STTY_FULL_SUMMARY_FILE: 'gnu-stty-full-result.json' TEST_SELINUX_FULL_SUMMARY_FILE: 'selinux-gnu-full-result.json' TEST_SELINUX_ROOT_FULL_SUMMARY_FILE: 'selinux-root-gnu-full-result.json' + TEST_SMACK_FULL_SUMMARY_FILE: 'smack-gnu-full-result.json' jobs: native: @@ -318,8 +319,52 @@ jobs: gnu/tests-selinux/*.log gnu/tests-selinux/*/*.log.gz + smack: + name: Run GNU tests (SMACK) + runs-on: ubuntu-24.04 + steps: + - name: Checkout code (uutils) + uses: actions/checkout@v6 + with: + path: 'uutils' + persist-credentials: false + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + components: rustfmt + - uses: Swatinem/rust-cache@v2 + with: + workspaces: "./uutils -> target" + - name: Checkout code (GNU coreutils) + run: (mkdir -p gnu && cd gnu && bash ../uutils/util/fetch-gnu.sh) + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y qemu-system-x86 zstd cpio + - name: Run GNU SMACK tests + run: | + cd uutils + bash util/run-gnu-tests-smack-ci.sh "$GITHUB_WORKSPACE/gnu" "$GITHUB_WORKSPACE/gnu/tests-smack" + - name: Extract testing info into JSON + run: | + python3 uutils/util/gnu-json-result.py gnu/tests-smack > ${{ env.TEST_SMACK_FULL_SUMMARY_FILE }} + - name: Upload SMACK json results + uses: actions/upload-artifact@v5 + with: + name: smack-gnu-full-result + path: ${{ env.TEST_SMACK_FULL_SUMMARY_FILE }} + - name: Compress SMACK test logs + run: gzip gnu/tests-smack/*/*.log 2>/dev/null || true + - name: Upload SMACK test logs + uses: actions/upload-artifact@v5 + with: + name: smack-test-logs + path: | + gnu/tests-smack/*.log + gnu/tests-smack/*/*.log.gz + aggregate: - needs: [native, selinux] + needs: [native, selinux, smack] permissions: actions: read # for dawidd6/action-download-artifact to query and download artifacts contents: read # for actions/checkout to fetch code @@ -384,6 +429,12 @@ jobs: name: selinux-root-gnu-full-result path: results merge-multiple: true + - name: Download smack json results + uses: actions/download-artifact@v7 + with: + name: smack-gnu-full-result + path: results + merge-multiple: true - name: Extract/summarize testing info id: summary shell: bash @@ -394,8 +445,8 @@ jobs: path_UUTILS='uutils' json_count=$(ls -l results/*.json | wc -l) - if [[ "$json_count" -ne 5 ]]; then - echo "::error ::Failed to download all results json files (expected 4 files, found $json_count); failing early" + if [[ "$json_count" -ne 6 ]]; then + echo "::error ::Failed to download all results json files (expected 6 files, found $json_count); failing early" ls -lR results || true exit 1 fi diff --git a/util/run-gnu-tests-smack-ci.sh b/util/run-gnu-tests-smack-ci.sh new file mode 100755 index 00000000000..2f4ac37d203 --- /dev/null +++ b/util/run-gnu-tests-smack-ci.sh @@ -0,0 +1,143 @@ +#!/bin/bash +# Run GNU SMACK tests in QEMU with SMACK-enabled kernel +# Usage: run-gnu-tests-smack-ci.sh [GNU_DIR] [OUTPUT_DIR] +# spell-checker:ignore rootfs zstd unzstd cpio newc nographic smackfs devtmpfs tmpfs poweroff libm libgcc libpthread libdl librt sysfs rwxat +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_DIR="$(dirname "$SCRIPT_DIR")" +GNU_DIR="${1:-$REPO_DIR/../gnu}" +OUTPUT_DIR="${2:-$REPO_DIR/target/smack-test-results}" +SMACK_DIR="$REPO_DIR/target/smack-test" + +echo "Setting up SMACK test environment..." +rm -rf "$SMACK_DIR" +mkdir -p "$SMACK_DIR"/{rootfs/{bin,lib64,proc,sys,dev,tmp,etc,gnu},kernel} + +# Download Arch Linux kernel (has SMACK built-in) +if [ ! -f /tmp/arch-vmlinuz ]; then + echo "Downloading Arch Linux kernel..." + MIRROR="https://geo.mirror.pkgbuild.com/core/os/x86_64" + KERNEL_PKG=$(curl -sL "$MIRROR/" | grep -oP 'linux-[0-9][^"]*-x86_64\.pkg\.tar\.zst' | grep -v headers | sort -V | tail -1) + [ -z "$KERNEL_PKG" ] && { echo "Error: Could not find kernel package"; exit 1; } + curl -sL -o /tmp/arch-kernel.pkg.tar.zst "$MIRROR/$KERNEL_PKG" + zstd -d /tmp/arch-kernel.pkg.tar.zst -o /tmp/arch-kernel.pkg.tar 2>/dev/null || unzstd /tmp/arch-kernel.pkg.tar.zst -o /tmp/arch-kernel.pkg.tar + VMLINUZ_PATH=$(tar -tf /tmp/arch-kernel.pkg.tar | grep 'vmlinuz$' | head -1) + tar -xf /tmp/arch-kernel.pkg.tar -C /tmp "$VMLINUZ_PATH" + mv "/tmp/$VMLINUZ_PATH" /tmp/arch-vmlinuz + rm -rf /tmp/usr /tmp/arch-kernel.pkg.tar /tmp/arch-kernel.pkg.tar.zst +fi +cp /tmp/arch-vmlinuz "$SMACK_DIR/kernel/vmlinuz" + +# Setup busybox +BUSYBOX=/tmp/busybox +[ -f "$BUSYBOX" ] || curl -sL -o "$BUSYBOX" https://busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox +chmod +x "$BUSYBOX" +cp "$BUSYBOX" "$SMACK_DIR/rootfs/bin/" +(cd "$SMACK_DIR/rootfs/bin" && "$BUSYBOX" --list | xargs -I{} ln -sf busybox {} 2>/dev/null) + +# Copy required libraries +for lib in ld-linux-x86-64.so.2 libc.so.6 libm.so.6 libgcc_s.so.1 libpthread.so.0 libdl.so.2 librt.so.1; do + path=$(ldconfig -p | grep "$lib" | head -1 | awk '{print $NF}') + [ -n "$path" ] && [ -f "$path" ] && cp -L "$path" "$SMACK_DIR/rootfs/lib64/" 2>/dev/null || true +done + +# Create minimal config files +echo -e "root:x:0:0:root:/root:/bin/sh\nnobody:x:65534:65534:nobody:/nonexistent:/bin/sh" > "$SMACK_DIR/rootfs/etc/passwd" +echo -e "root:x:0:\nnobody:x:65534:" > "$SMACK_DIR/rootfs/etc/group" +touch "$SMACK_DIR/rootfs/etc/mtab" + +# Copy GNU tests +cp -r "$GNU_DIR/tests" "$SMACK_DIR/rootfs/gnu/" + +# Create init script +cat > "$SMACK_DIR/rootfs/init" << 'INIT' +#!/bin/sh +mount -t proc proc /proc +mount -t sysfs sys /sys +mount -t smackfs smackfs /sys/fs/smackfs 2>/dev/null || true +if [ -d /sys/fs/smackfs ]; then + echo "_" > /proc/self/attr/current 2>/dev/null || true + echo "_ _ rwxat" > /sys/fs/smackfs/load 2>/dev/null || true +fi +mount -t devtmpfs devtmpfs /dev 2>/dev/null || true +ln -sf /proc/mounts /etc/mtab +mkdir -p /tmp && mount -t tmpfs tmpfs /tmp +chmod 1777 /tmp +export PATH="/bin:$PATH" srcdir="/gnu" LD_LIBRARY_PATH="/lib64" +cd /gnu/tests +sh "$TEST_SCRIPT" +echo "EXIT:$?" +poweroff -f +INIT +chmod +x "$SMACK_DIR/rootfs/init" + +# Build utilities with SMACK support +echo "Building utilities with SMACK support..." +UTILS="ls id mkdir mknod mkfifo" +for U in $UTILS; do + cargo build --release --manifest-path="$REPO_DIR/Cargo.toml" --package "uu_$U" --bin "$U" --features "uu_$U/smack" 2>/dev/null +done + +# Find SMACK tests +SMACK_TESTS=$(grep -l 'require_smack_' -r "$GNU_DIR/tests/" 2>/dev/null || true) +[ -z "$SMACK_TESTS" ] && { echo "No SMACK tests found"; exit 0; } + +echo "Found $(echo "$SMACK_TESTS" | wc -l) SMACK tests" + +# Create output directory +rm -rf "$OUTPUT_DIR" +mkdir -p "$OUTPUT_DIR" + +# Run each test +for TEST_PATH in $SMACK_TESTS; do + TEST_REL="${TEST_PATH#"$GNU_DIR"/tests/}" + TEST_DIR=$(dirname "$TEST_REL") + TEST_NAME=$(basename "$TEST_REL" .sh) + + echo "Running: $TEST_REL" + + # Create working copy + WORK="/tmp/smack-test-$$" + rm -rf "$WORK" "$WORK.gz" + cp -a "$SMACK_DIR/rootfs" "$WORK" + + # Copy built utilities + for U in $UTILS; do + rm -f "$WORK/bin/$U" + cp "$REPO_DIR/target/release/$U" "$WORK/bin/$U" + done + + # Set test script path + sed -i "s|\$TEST_SCRIPT|$TEST_REL|g" "$WORK/init" + + # Build initramfs and run + (cd "$WORK" && find . | cpio -o -H newc 2>/dev/null | gzip > "$WORK.gz") + + OUTPUT=$(timeout 120 qemu-system-x86_64 \ + -kernel "$SMACK_DIR/kernel/vmlinuz" \ + -initrd "$WORK.gz" \ + -append "console=ttyS0 quiet panic=-1 security=smack lsm=smack" \ + -nographic -m 256M -no-reboot 2>&1) || true + + # Determine result + if echo "$OUTPUT" | grep -q "EXIT:0"; then + RESULT="PASS"; EXIT_STATUS=0 + elif echo "$OUTPUT" | grep -q "EXIT:77"; then + RESULT="SKIP"; EXIT_STATUS=77 + else + RESULT="FAIL"; EXIT_STATUS=1 + fi + + echo " $RESULT: $TEST_REL" + + # Create log file for gnu-json-result.py + mkdir -p "$OUTPUT_DIR/$TEST_DIR" + echo "$OUTPUT" > "$OUTPUT_DIR/$TEST_DIR/$TEST_NAME.log" + echo "" >> "$OUTPUT_DIR/$TEST_DIR/$TEST_NAME.log" + echo "$RESULT $TEST_NAME.sh (exit status: $EXIT_STATUS)" >> "$OUTPUT_DIR/$TEST_DIR/$TEST_NAME.log" + + rm -rf "$WORK" "$WORK.gz" +done + +echo "Done. Results in $OUTPUT_DIR" From 14e2cf20869289bd5ebb89d336d9aaeca3e99062 Mon Sep 17 00:00:00 2001 From: Christopher Dryden Date: Sun, 28 Dec 2025 14:41:24 +0000 Subject: [PATCH 2/2] Fix SMACK CI to only build ls (only utility with SMACK support) --- util/run-gnu-tests-smack-ci.sh | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/util/run-gnu-tests-smack-ci.sh b/util/run-gnu-tests-smack-ci.sh index 2f4ac37d203..37a4631a594 100755 --- a/util/run-gnu-tests-smack-ci.sh +++ b/util/run-gnu-tests-smack-ci.sh @@ -72,12 +72,10 @@ poweroff -f INIT chmod +x "$SMACK_DIR/rootfs/init" -# Build utilities with SMACK support +# Build utilities with SMACK support (only ls has SMACK support for now) +# TODO: When other utilities have SMACK support, build: ls id mkdir mknod mkfifo echo "Building utilities with SMACK support..." -UTILS="ls id mkdir mknod mkfifo" -for U in $UTILS; do - cargo build --release --manifest-path="$REPO_DIR/Cargo.toml" --package "uu_$U" --bin "$U" --features "uu_$U/smack" 2>/dev/null -done +cargo build --release --manifest-path="$REPO_DIR/Cargo.toml" --package uu_ls --bin ls --features uu_ls/smack # Find SMACK tests SMACK_TESTS=$(grep -l 'require_smack_' -r "$GNU_DIR/tests/" 2>/dev/null || true) @@ -102,11 +100,11 @@ for TEST_PATH in $SMACK_TESTS; do rm -rf "$WORK" "$WORK.gz" cp -a "$SMACK_DIR/rootfs" "$WORK" - # Copy built utilities - for U in $UTILS; do - rm -f "$WORK/bin/$U" - cp "$REPO_DIR/target/release/$U" "$WORK/bin/$U" - done + # Copy built utilities (only ls has SMACK support for now) + # TODO: When other utilities have SMACK support, use: + # for U in ls id mkdir mknod mkfifo; do cp "$REPO_DIR/target/release/$U" "$WORK/bin/$U"; done + rm -f "$WORK/bin/ls" + cp "$REPO_DIR/target/release/ls" "$WORK/bin/ls" # Set test script path sed -i "s|\$TEST_SCRIPT|$TEST_REL|g" "$WORK/init"