Fix pacman whitelist matching for yay's -U package-file installs

is_blocked_package_name compared raw pacman -U <file>.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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015yfDYbaw1D1WhVMqWhsSDA
This commit is contained in:
Krzysztof Rudnicki 2026-08-12 22:43:30 +02:00
parent a97ad66e1f
commit 0c28f9988f
4 changed files with 135 additions and 1 deletions

View File

@ -0,0 +1,34 @@
{
"intent": "Fix pacman_wrapper.sh so whitelist/blocklist matching works for `pacman -U <file>.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 <file>.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"
]
}

View File

@ -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

View File

@ -346,14 +346,34 @@ function display_operation() {
esac
}
# Helper: strip a pacman package-file suffix (-<pkgver>-<pkgrel>-<arch>.pkg.tar.<ext>)
# down to the bare package name, if present. `pacman -U <path>` (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

View File

@ -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 <path>.pkg.tar.zst`
# argument. Regression test for the 2026-08-12 bug: `yay` always installs a
# package it just built via `pacman -U <path>/<pkg>-<ver>-<rel>-<arch>.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 ""