fix: polkit org.ublue.privileged.user.setup defaults no/no/auth_admin — system_files/shared/usr/share/polkit-1/actions/org.ublue.privileged.user.setup.policy - #1108
Conversation
allow_any/allow_inactive/allow_active=yes made the wheel-only gate in 20-privileged-user-setup.rules a dead letter: NOT_HANDLED falls through to the implicit authorizations, so any local user in any session state could pkexec /usr/bin/ublue-privileged-setup as root with no auth. Set defaults to no/no/auth_admin. Wheel keeps passwordless access via the existing rules.d rule; everyone else is denied unless an admin authenticates. Matches the sibling org.frostyard.ChairLift.bootc.policy hardening shipped in the same directory. Closes #1107 Signed-off-by: sec-check[bot] <sec-check[bot]@users.noreply.github.com>
Danathar
left a comment
There was a problem hiding this comment.
The finding in #1107 is real — today any local user can run ublue-privileged-setup as root without authenticating — but this change would ship a login regression to every image, so it can't land as-is.
Who calls this, and when. system_files/shared/usr/share/ublue-os/user-setup.hooks.d/99-privileged.sh in bluefin, utah and bluefin-lts is:
pkexec /usr/bin/ublue-privileged-setupand ublue-user-setup.service is a user unit WantedBy=graphical-session.target, so that pkexec runs for every user at every graphical login.
The wheel rule never matches — not just for non-wheel users. 20-privileged-user-setup.rules checks
action.id == "org.freedesktop.policykit.exec" && action.lookup("program") == "/usr/bin/ublue-privileged-setup"But the policy annotates org.freedesktop.policykit.exec.path, and when pkexec finds an action whose exec.path matches the program it authorizes against that action id — org.ublue.policykit.privileged.user.setup — not org.freedesktop.policykit.exec. So the rule returns NOT_HANDLED for everyone, wheel members included, and the <defaults> decide. Today the defaults are yes, which is why nobody has noticed.
What this PR does on a real system. With allow_active = auth_admin and a rule that never says YES, every graphical login — including the admin's — pops a polkit authentication dialog for ublue-privileged-setup. Dismiss it and the hook fails (harmless, hookrunner.sh keeps going), but the dialog comes back next login. That's the "auth prompt at every login" class of bug.
What it should be (still one small PR, but three files):
- Fix the rule so it can actually match:
action.id == "org.ublue.policykit.privileged.user.setup"(keep theprogramcheck as belt-and-braces), returningYESfor wheel. - Then tighten the defaults — but to
no/no/no, notauth_admin. Non-wheel users have no business being prompted for an admin password at login; they should be denied silently and the hook should skip. - Make
99-privileged.sh(in the consuming repos — it's a hook, not in common) checkid -nG | grep -qw wheelbefore calling pkexec, so non-admin users don't even hit polkit.
And please verify on a VM login, wheel and non-wheel, before merging — this is exactly the kind of change the composed E2E doesn't exercise.
The XML change itself is well-formed; it's the surrounding mechanism that's wrong.
Security Fix
Ground claimed (hold-gated coordination):
system_files/shared/usr/share/polkit-1/actions/org.ublue.privileged.user.setup.policyonly. Disjoint from common#932 (etc/sudoers.d/001-bootc), chairlift#37 (chairlift Go internal/helperexec), and all other open PRs.The action's implicit authorizations were
allow_any/allow_inactive/allow_active = yes. Because20-privileged-user-setup.rulesreturnsNOT_HANDLEDfor non-wheel subjects, polkit falls through to those defaults — so any local user, in any session state, could run/usr/bin/ublue-privileged-setupas root with no authentication. The wheel-only restriction was never effective.Change: defaults become
no/no/auth_admin. Wheel members keep passwordless access via the unchanged rules.d rule; all other subjects are denied unless an admin authenticates. Matches the hardening already used by the siblingorg.frostyard.ChairLift.bootc.policyin the same directory. XML well-formedness verified.Closes #1107
Filed by sec-check agent (ACMM L4/L5 — hold-gated mode). Hold-gated: human review required.
— hive: agent=sec-check backend=copilot model=kimi-k3 copilot=1.0.78