From be8ce8b9759bfcd78143ec6dd77293dce68b0472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Thu, 8 Oct 2026 20:31:22 -0300 Subject: [PATCH 1/3] fix(probe): preserve Debian library directory permissions The Debian package set the xCAT helper directory to 0644, preventing unprivileged users from loading the probe modules. Set library directories to 0755 and regular files to 0644. Repair the old helper-directory mode during configuration because dpkg preserves existing modes. Leave administrator overrides, other modes, and symlinks unchanged. --- xCAT-probe/debian/postinst | 6 ++++++ xCAT-probe/debian/rules | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/xCAT-probe/debian/postinst b/xCAT-probe/debian/postinst index 5ced18096..19af47964 100644 --- a/xCAT-probe/debian/postinst +++ b/xCAT-probe/debian/postinst @@ -20,6 +20,12 @@ set -e case "$1" in configure) + probe_lib=/opt/xcat/probe/lib/perl/xCAT + if [ -d "$probe_lib" ] && [ ! -L "$probe_lib" ] && + [ "$(stat -c %a "$probe_lib")" = 644 ] && + ! dpkg-statoverride --list "$probe_lib" >/dev/null; then + chmod 755 "$probe_lib" + fi ;; abort-upgrade|abort-remove|abort-deconfigure) diff --git a/xCAT-probe/debian/rules b/xCAT-probe/debian/rules index bb1842ebe..7f1a3c4ba 100755 --- a/xCAT-probe/debian/rules +++ b/xCAT-probe/debian/rules @@ -42,8 +42,8 @@ binary-arch: dh_install -X".svn" chmod 755 `pwd`/debian/xcat-probe/opt/xcat/bin/* chmod 755 `pwd`/debian/xcat-probe/opt/xcat/probe/subcmds/* - chmod 644 `pwd`/debian/xcat-probe/opt/xcat/probe/lib/perl/* - chmod 644 `pwd`/debian/xcat-probe/opt/xcat/probe/lib/perl/xCAT/* + find `pwd`/debian/xcat-probe/opt/xcat/probe/lib -type d -exec chmod 755 {} + + find `pwd`/debian/xcat-probe/opt/xcat/probe/lib -type f -exec chmod 644 {} + # dh_installmenu # dh_installdebconf # dh_installlogrotate From 957c52fe533db54a0d409cf4d1a3c1811585858f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Thu, 8 Oct 2026 20:43:03 -0300 Subject: [PATCH 2/3] test(probe): exercise Debian package permissions --- .github/workflows/xcat_test.yml | 3 + .../native/probe_debian_permissions.bats | 140 ++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 xCAT-test/native/probe_debian_permissions.bats diff --git a/.github/workflows/xcat_test.yml b/.github/workflows/xcat_test.yml index fc30f70a8..385ed7a9e 100644 --- a/.github/workflows/xcat_test.yml +++ b/.github/workflows/xcat_test.yml @@ -26,6 +26,9 @@ jobs: - name: Exercise image package policy if: ${{ !cancelled() }} run: prove xCAT-test/native/el10_image_package_policy.t + - name: Check Debian probe payload permissions + if: ${{ !cancelled() }} + run: bats xCAT-test/native/probe_debian_permissions.bats - name: Prepare xCAT syslog directory if: ${{ !cancelled() }} run: sudo install -d -o syslog -g adm -m 0750 /var/log/xcat diff --git a/xCAT-test/native/probe_debian_permissions.bats b/xCAT-test/native/probe_debian_permissions.bats new file mode 100644 index 000000000..846030036 --- /dev/null +++ b/xCAT-test/native/probe_debian_permissions.bats @@ -0,0 +1,140 @@ +#!/usr/bin/env bats + +load '../bats/helpers/shell_source' + +setup() +{ + if [ "$(uname -s)" != Linux ] || [ ! -f /etc/debian_version ]; then + skip 'requires Debian package tools' + fi + if [ "$(id -u)" -eq 0 ]; then + echo 'Run this test as an unprivileged user' >&2 + return 1 + fi + for tool in perl dpkg-buildpackage dpkg-deb fakeroot reprepro bwrap; do + command -v "$tool" >/dev/null || { + echo "Required utility is unavailable: $tool" >&2 + return 1 + } + done + fixture="$(mktemp -d "${BATS_TMPDIR:-${TMPDIR:-/tmp}}/probe-permissions.XXXXXX")" + checkout="$fixture/checkout" + destination="$fixture/repository" + payload="$fixture/payload" + mkdir -p "$checkout" "$payload" "$fixture/home" + for entry in builddebs.pl build-utils Version Release xCAT-probe perl-xCAT; do + cp -a "$(repo_path "$entry")" "$checkout/" + done + mkdir -p "$checkout/xCAT-probe/lib/perl/xCAT" + chmod 700 "$checkout/xCAT-probe/lib" "$checkout/xCAT-probe/lib/perl" \ + "$checkout/xCAT-probe/lib/perl/xCAT" + chmod 600 "$checkout/xCAT-probe/lib/perl/"*.pm + printf '1600000000\n' > "$checkout/Gitepoch" + printf '%040d\n' 0 > "$checkout/Gitinfo" +} + +teardown() +{ + if [ -n "${fixture:-}" ] && [ -d "$fixture" ]; then + chmod -R u+rwX "$fixture" + rm -rf "$fixture" + fi +} + +build_probe() +{ + cd "$checkout" || return 1 + run env -i HOME="$fixture/home" PATH=/usr/bin:/bin LC_ALL=C \ + perl builddebs.pl --package xCAT-probe --dist noble --release permissiontest \ + --dest "$destination" + [ "$status" -eq 0 ] || { echo "$output"; return 1; } + + packages=("$destination"/debs/xcat-probe_*_all.deb) + [ "${#packages[@]}" -eq 1 ] + [ -f "${packages[0]}" ] + run dpkg-deb -x "${packages[0]}" "$payload" + [ "$status" -eq 0 ] || { echo "$output"; return 1; } + + prefix="$payload/opt/xcat" + library_root="$prefix/probe/lib" + library="$library_root/perl" +} + +prepare_postinst() +{ + mkdir -p "$fixture/control" "$fixture/dpkg" + run dpkg-deb -e "${packages[0]}" "$fixture/control" + [ "$status" -eq 0 ] || { echo "$output"; return 1; } + sandbox=(env -i PATH=/usr/bin:/bin LC_ALL=C bwrap + --unshare-all --die-with-parent --new-session --ro-bind / / + --dev /dev + --tmpfs /opt --bind "$prefix" /opt/xcat + --bind "$fixture/dpkg" /var/lib/dpkg) +} + +run_postinst() +{ + run "${sandbox[@]}" /bin/sh "$fixture/control/postinst" "$@" + [ "$status" -eq 0 ] || { echo "$output"; return 1; } +} + +@test "the Debian probe payload preserves library modes and contents" { + build_probe + [ "$(stat -c %a "$library_root")" = 755 ] + [ "$(stat -c %a "$library")" = 755 ] + [ "$(stat -c %a "$library/xCAT")" = 755 ] + run find "$library_root" -type d ! -perm 0755 -print + [ "$status" -eq 0 ] + [ -z "$output" ] + run find "$library_root" -type f ! -perm 0644 -print + [ "$status" -eq 0 ] + [ -z "$output" ] + for helper in CommandUtils GlobalDef NetworkUtils PacketCapture ServiceNodeUtils; do + cmp "$(repo_path "perl-xCAT/xCAT/$helper.pm")" "$library/xCAT/$helper.pm" + done + cmp "$(repo_path xCAT-probe/lib/perl/probe_utils.pm)" "$library/probe_utils.pm" +} + +@test "packaged probe commands load their helpers without root privileges" { + build_probe + for subcommand in code_template detect_dhcpd discovery osdeploy xcatmn; do + [ "$(stat -c %a "$prefix/probe/subcmds/$subcommand")" = 755 ] + run env -i PATH=/usr/bin:/bin XCATROOT="$prefix" \ + "$prefix/probe/subcmds/$subcommand" -T + [ "$status" -eq 0 ] || { echo "$output"; return 1; } + [[ "$output" =~ ^\[ok\][[:space:]]*: ]] || { echo "$output"; return 1; } + done +} + +@test "package configuration repairs the old directory mode idempotently" { + build_probe + prepare_postinst + chmod 644 "$library/xCAT" + run_postinst configure 2.19.0 + [ "$(stat -c %a "$library/xCAT")" = 755 ] + run_postinst configure 2.19.0 + [ "$(stat -c %a "$library/xCAT")" = 755 ] +} + +@test "package configuration preserves overrides and unrelated modes" { + build_probe + prepare_postinst + chmod 644 "$library/xCAT" + run "${sandbox[@]}" dpkg-statoverride --add root root 644 /opt/xcat/probe/lib/perl/xCAT + [ "$status" -eq 0 ] || { echo "$output"; return 1; } + run "${sandbox[@]}" dpkg-statoverride --list /opt/xcat/probe/lib/perl/xCAT + [ "$status" -eq 0 ] || { echo "$output"; return 1; } + [ "$output" = 'root root 644 /opt/xcat/probe/lib/perl/xCAT' ] + run_postinst configure 2.19.0 + [ "$(stat -c %a "$library/xCAT")" = 644 ] + run "${sandbox[@]}" dpkg-statoverride --remove /opt/xcat/probe/lib/perl/xCAT + [ "$status" -eq 0 ] || { echo "$output"; return 1; } + chmod 700 "$library/xCAT" + run_postinst configure 2.19.0 + [ "$(stat -c %a "$library/xCAT")" = 700 ] + mv "$library/xCAT" "$library/private" + chmod 644 "$library/private" + ln -s private "$library/xCAT" + run_postinst configure 2.19.0 + [ "$(stat -c %a "$library/private")" = 644 ] +} From b7adfccad374419503acc969e3966b4ac35bc6fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Thu, 8 Oct 2026 20:43:03 -0300 Subject: [PATCH 3/3] docs(test): describe the Debian probe permission check --- xCAT-test/README.md | 2 +- xCAT-test/native/README.md | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/xCAT-test/README.md b/xCAT-test/README.md index 115fe5553..8582d7d73 100644 --- a/xCAT-test/README.md +++ b/xCAT-test/README.md @@ -8,7 +8,7 @@ language: | Perl unit tests | `xCAT-test/unit/*.t` | `prove -r xCAT-test/unit` | | Shell unit tests | `xCAT-test/bats/*.bats` | `bats -r xCAT-test/bats` | | Black-box service tests | `xCAT-test/blackboxtest/` | `python3 -m unittest discover -s tests`, then `blackboxtest run ` on a management node | -| Native host tests | `xCAT-test/native/*.t` | Explicit lab runs; see [native/README.md](native/README.md) | +| Native host tests | `xCAT-test/native/*.t`, `xCAT-test/native/*.bats` | Explicit lab runs; see [native/README.md](native/README.md) | | CLI functional tests | `xCAT-test/autotest/testcase/` and `xCAT-test/autotest/bundle/` | `xcattest -f -t ` or `xcattest -f -b ` | Use Perl `.t` tests for Perl modules, Perl scripts, templates, and repository diff --git a/xCAT-test/native/README.md b/xCAT-test/native/README.md index 58d3240c4..677dad2be 100644 --- a/xCAT-test/native/README.md +++ b/xCAT-test/native/README.md @@ -61,6 +61,15 @@ agent. These checks inspect real packages and repository output; they do not qualify package installation on every target architecture. On EL8, install both `python36` and `python3-rpm` to provide the interpreter and its RPM bindings. +The Debian probe permission test has a separate pull-request CI step. It needs +Debian build tools, BATS, bubblewrap, fakeroot, reprepro and +libfile-slurper-perl. Run it as an ordinary user on a Debian or Ubuntu host +with unprivileged namespaces enabled: + +``` +bats xCAT-test/native/probe_debian_permissions.bats +``` + Run the package and unprivileged namespace cases as an ordinary user: ```