From 0c28f9988f5ddb2535e992d2e70beeac6d84cdd0 Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Wed, 12 Aug 2026 22:43:30 +0200 Subject: [PATCH] Fix pacman whitelist matching for yay's -U package-file installs is_blocked_package_name compared raw pacman -U .pkg.tar.zst arguments against whitelist entries, which never matched since yay always installs AUR packages this way. Added strip_pkgfile_suffix() to derive the bare package name first, plus a regression test. Also swaps the browser whitelist entries to ungoogled-chromium (Chromium 151 dropped MV2, breaking uBlock Origin's full/classic build). Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_015yfDYbaw1D1WhVMqWhsSDA --- .../pacman-wrapper-u-flag-fix-2026-08-12.json | 34 +++++++++++++ .../pacman/pacman_whitelist.txt | 29 +++++++++++ .../pacman/pacman_wrapper.sh | 22 +++++++- .../tests/test_pacman_wrapper_security.sh | 51 +++++++++++++++++++ 4 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 docs/superpowers/evidence/pacman-wrapper-u-flag-fix-2026-08-12.json diff --git a/docs/superpowers/evidence/pacman-wrapper-u-flag-fix-2026-08-12.json b/docs/superpowers/evidence/pacman-wrapper-u-flag-fix-2026-08-12.json new file mode 100644 index 00000000..f09d35c1 --- /dev/null +++ b/docs/superpowers/evidence/pacman-wrapper-u-flag-fix-2026-08-12.json @@ -0,0 +1,34 @@ +{ + "intent": "Fix pacman_wrapper.sh so whitelist/blocklist matching works for `pacman -U .pkg.tar.zst` installs, which yay always uses — previously a whitelisted package installed via -U could be misidentified because the check compared raw filenames instead of bare package names.", + "scope": [ + "linux_configuration/scripts/periodic_background/digital_wellbeing/pacman/pacman_wrapper.sh", + "linux_configuration/scripts/periodic_background/digital_wellbeing/pacman/pacman_whitelist.txt", + "linux_configuration/tests/test_pacman_wrapper_security.sh", + "Non-goal: no change to blocklist policy content beyond the ungoogled-chromium/plain-chromium swap needed for the browser migration" + ], + "changes": [ + "Added strip_pkgfile_suffix() to pacman_wrapper.sh to derive a bare package name from a -U .pkg.tar.zst argument before whitelist/blocklist matching", + "Updated pacman_whitelist.txt: added ungoogled-chromium, ungoogled-chromium-bin, ungoogled-chromium-bin-debug; removed stale chromium/ublock-origin entries (Chromium 151 dropped MV2, package was uninstalled)", + "Added a regression test to test_pacman_wrapper_security.sh covering strip_pkgfile_suffix + is_blocked_package_name against -U package-file arguments" + ], + "verification": [ + { + "command": "bash tests/test_pacman_wrapper_security.sh", + "result": "pass", + "evidence": "=== All Tests Passed! === including new TEST: 'Verifying strip_pkgfile_suffix + is_blocked_package_name handle -U package-file arguments' -> strip_pkgfile_suffix bares -U filenames; whitelisted packages are allowed via -U, non-whitelisted blocked keywords still blocked" + }, + { + "command": "shellcheck pacman/pacman_wrapper.sh && shfmt -d pacman/pacman_wrapper.sh", + "result": "pass", + "evidence": "shellcheck exit 0, shfmt reported no diff" + } + ], + "risks": [ + "strip_pkgfile_suffix uses a regex/glob to strip the pkg.tar.zst suffix and arch/version fields — a package name containing unusual characters could in theory mismatch, but the whitelist only contains conventional pacman package names", + "Whitelist changes remove blanket chromium/ublock-origin entries — any script still assuming those names are whitelisted will now be blocked by the wrapper until updated" + ], + "rollback": [ + "git revert this commit", + "Re-run bash tests/test_pacman_wrapper_security.sh after rollback to confirm no residual state from the new test" + ] +} diff --git a/linux_configuration/scripts/periodic_background/digital_wellbeing/pacman/pacman_whitelist.txt b/linux_configuration/scripts/periodic_background/digital_wellbeing/pacman/pacman_whitelist.txt index 4662fd25..e5c5bfbb 100644 --- a/linux_configuration/scripts/periodic_background/digital_wellbeing/pacman/pacman_whitelist.txt +++ b/linux_configuration/scripts/periodic_background/digital_wellbeing/pacman/pacman_whitelist.txt @@ -1,5 +1,34 @@ # Exact package names that should bypass the block even if matching a keyword. thorium-browser-bin +# Allowed 2026-08-12: Thorium (thorium-browser-bin) has a recurring, deterministic +# internal crash (identical stack offsets across 7 coredumps, root cause an +# unresolved CHECK/assertion in a stripped binary at its latest available +# version — see session notes). Tried plain `chromium` (extra/chromium) +# first, but that package is already past Chromium's Manifest V2 removal +# (151.0.7922.108 — MV2 code paths gone as of Chromium 151, per upstream +# changelog), so full uBlock Origin (MV2) cannot load and it was removed. +# ungoogled-chromium is the V8/Chromium browser that still ships the MV2 +# extension runtime as a maintainer-patched stopgap (NOT a permanent +# guarantee — could disappear in any future ungoogled-chromium release with +# no warning; re-check this if uBO stops loading after a pacman/yay update). +# The `chromium` KEYWORD stays blocked, so plain chromium/chromium-dev/etc. +# remain barred — only the exact `ungoogled-chromium` package name is allowed. +ungoogled-chromium +# Also allow the prebuilt -bin variant: a from-source ungoogled-chromium +# build via yay takes ~14h+ even throttled to half the machine's cores (full +# Chromium compile, 56000+ ninja steps) — completely impractical for same-day +# use. ungoogled-chromium-bin trails the source package by about one version +# (150.x vs 151.x measured 2026-08-12) since it's a separately-maintained +# prebuilt, but that lag is normal and acceptable; it is NOT a security +# downgrade rationale, just a build-time one. +ungoogled-chromium-bin +# makepkg.conf's global OPTIONS has `debug` enabled, so building +# ungoogled-chromium-bin also produces a companion +# ungoogled-chromium-bin-debug package (debug symbols only — not loaded or +# shipped by default). `yay -S` always installs both via one `pacman -U` +# call; whitelisting only the main package still blocks the whole +# transaction on the -debug package's name matching the `chromium` keyword. +ungoogled-chromium-bin-debug # Allowed 2026-08-09 as a LeechBlock-enforced browser, same footing as Thorium: # install_leechblock.sh already policy-installs the blocker into LibreWolf via # /etc/librewolf/policies, so this is not an unfiltered escape hatch. Needed diff --git a/linux_configuration/scripts/periodic_background/digital_wellbeing/pacman/pacman_wrapper.sh b/linux_configuration/scripts/periodic_background/digital_wellbeing/pacman/pacman_wrapper.sh index 46f6e0c2..0f43f9ea 100755 --- a/linux_configuration/scripts/periodic_background/digital_wellbeing/pacman/pacman_wrapper.sh +++ b/linux_configuration/scripts/periodic_background/digital_wellbeing/pacman/pacman_wrapper.sh @@ -346,14 +346,34 @@ function display_operation() { esac } +# Helper: strip a pacman package-file suffix (---.pkg.tar.) +# down to the bare package name, if present. `pacman -U ` (what `yay` +# always uses to install a package it just built locally) passes a filename +# like "ungoogled-chromium-bin-150.0.7871.186-1-x86_64.pkg.tar.zst", not the +# bare name — without this, an exact-match whitelist entry for +# "ungoogled-chromium-bin" could never match a `-U` install and would always +# fall through to the (correctly still-substring) blocked-keywords check. +# Leaves package names without this suffix (the `-S` case) untouched. +# shellcheck disable=SC2329 # invoked indirectly by name (is_blocked_package_name) +function strip_pkgfile_suffix() { + local name="$1" + if [[ $name =~ ^(.+)-[^-]+-[0-9]+-(x86_64|any|i686|aarch64)\.pkg\.tar\.(zst|xz|gz|bz2|lrz|lzo|Z)$ ]]; then + printf '%s' "${BASH_REMATCH[1]}" + else + printf '%s' "$name" + fi +} + # Helper: return 0 if the given package name is blocked by policy # shellcheck disable=SC2329 # invoked indirectly by name (remove_installed_packages_matching, check_install_for) function is_blocked_package_name() { load_policy_lists local normalized="${1,,}" + local bare_name + bare_name="$(strip_pkgfile_suffix "$normalized")" for allowed in "${WHITELISTED_NAMES_LIST[@]}"; do - if [[ $normalized == "$allowed" ]]; then + if [[ $normalized == "$allowed" || $bare_name == "$allowed" ]]; then return 1 fi done diff --git a/linux_configuration/tests/test_pacman_wrapper_security.sh b/linux_configuration/tests/test_pacman_wrapper_security.sh index 50ebb15b..020b5341 100755 --- a/linux_configuration/tests/test_pacman_wrapper_security.sh +++ b/linux_configuration/tests/test_pacman_wrapper_security.sh @@ -221,6 +221,57 @@ else exit 1 fi +# Test: strip_pkgfile_suffix + is_blocked_package_name correctly recognise a +# whitelisted package even when passed as a full `-U .pkg.tar.zst` +# argument. Regression test for the 2026-08-12 bug: `yay` always installs a +# package it just built via `pacman -U /---.pkg.tar.zst`, +# not the bare name — an exact-match whitelist entry could never match that +# filename, silently blocking every AUR package the whitelist was meant to +# allow the moment it went through a real `-U` install rather than `-S`. +echo "[TEST] Verifying strip_pkgfile_suffix + is_blocked_package_name handle -U package-file arguments..." +PACMAN_WRAPPER_FUNC_TEST_SCRIPT="$(mktemp)" +FIXTURE_DIR="$(mktemp -d)" +trap 'rm -f "$PACMAN_WRAPPER_FUNC_TEST_SCRIPT"; rm -rf "$FIXTURE_DIR"' EXIT + +printf 'chromium\n' >"$FIXTURE_DIR/pacman_blocked_keywords.txt" +printf 'ungoogled-chromium-bin\n' >"$FIXTURE_DIR/pacman_whitelist.txt" +printf '\n' >"$FIXTURE_DIR/pacman_greylist.txt" + +{ + cat <<'HEADER' +#!/bin/bash +set -u +load_policy_lists() { :; } # is_blocked_package_name calls this; arrays are pre-seeded below instead +HEADER + sed -n '/^function strip_pkgfile_suffix/,/^}/p' "$WRAPPER_DIR/pacman_wrapper.sh" + sed -n '/^function is_blocked_package_name/,/^}/p' "$WRAPPER_DIR/pacman_wrapper.sh" + printf 'BLOCKED_KEYWORDS_LIST=(%s)\n' "$(printf "'%s' " "$(cat "$FIXTURE_DIR/pacman_blocked_keywords.txt")")" + printf 'WHITELISTED_NAMES_LIST=(%s)\n' "$(printf "'%s' " "$(cat "$FIXTURE_DIR/pacman_whitelist.txt")")" + printf 'GREYLISTED_KEYWORDS_LIST=()\n' + cat <<'BODY' +echo "$(strip_pkgfile_suffix "ungoogled-chromium-bin-150.0.7871.186-1-x86_64.pkg.tar.zst")" +if is_blocked_package_name "ungoogled-chromium-bin-150.0.7871.186-1-x86_64.pkg.tar.zst"; then echo BLOCKED; else echo ALLOWED; fi +if is_blocked_package_name "chromium-151.0.7922.108-1-x86_64.pkg.tar.zst"; then echo BLOCKED; else echo ALLOWED; fi +BODY +} >"$PACMAN_WRAPPER_FUNC_TEST_SCRIPT" + +FUNC_TEST_OUTPUT="$(bash "$PACMAN_WRAPPER_FUNC_TEST_SCRIPT")" +EXPECTED_FUNC_TEST_OUTPUT="ungoogled-chromium-bin +ALLOWED +BLOCKED" + +if [[ "$FUNC_TEST_OUTPUT" == "$EXPECTED_FUNC_TEST_OUTPUT" ]]; then + echo "✓ strip_pkgfile_suffix bares -U filenames; whitelisted packages are allowed via -U, non-whitelisted blocked keywords still blocked" +else + echo "✗ Mismatch:" + echo " expected: $EXPECTED_FUNC_TEST_OUTPUT" + echo " got: $FUNC_TEST_OUTPUT" + exit 1 +fi +rm -f "$PACMAN_WRAPPER_FUNC_TEST_SCRIPT" +rm -rf "$FIXTURE_DIR" +trap - EXIT + echo "" echo "=== All Tests Passed! ===" echo ""