Sentinel v0.12.0
Sentinel 0.12.0
A security-architecture release: the "remember" decision and its grant
store move out of the root PAM module into a sandboxed, unprivileged
broker; the remember window is reworked so every grant is bound to the
exact command; and the root unsafe surface is locked down.
If you remember one thing: a remembered grant now covers only the exact
command you approved — sudo pacman -Syu can never wave through
sudo pacman -U /tmp/evil, and pkexec id never covers pkexec rm.
Highlights
- Per-command remember, on both the polkit and sudo/su paths. Grants
are keyed by the whole elevated command, not the program name. - Privilege-separation broker. The root PAM module no longer holds any
grant state; it relays to an unprivileged, in-memory, root-only daemon. - sudo's own credential cache is disabled by the installer, so
Sentinel's per-command window is the single source of truth for sudo. pam-sentinelis now#![deny(unsafe_code)]apart from two
documented, narrowly-scoped sites.
Remember window
- Shown by default on the polkit/GUI dialog (
[general].remember_seconds
defaults to300). The box defaults unchecked — nothing is auto-allowed
unless you tick it on that prompt. (#22) - Grants bind to the full command. This fixes a real bug: the polkit
path previously keyed grants on(action, exe), command-blind, so one
tickedpkexeccould silently auto-allow any later pkexec command. The
key is now the whole command on both paths, andpkexecis remembered
per command like everything else (no blanket carve-out). - Per-service window.
[services.<name>].remember_secondsis the knob;
the compiled default is300forpolkit-1and0for terminal
services, but the shipped config optssudo/sudo-i/suinto300.
Set a service to0to require confirmation every time. Unknown
[services.*]keys are now a hard parse error. - Arbitrary-code gateways never qualify (both paths): shells,
interpreters, and shell-escapers (editors, pagers,find, …) as the
elevated command, plus bare-elevation root shells (sudo -s/-i/-v,
su) on the terminal path, always re-prompt.
Privilege-separation broker
Following the pam_sss / OpenSSH-monitor model, the remember decision and
grant store now live in sentinel-broker — a long-lived, unprivileged
daemon (systemd DynamicUser=) that serves only root peers over a Unix
socket (SO_PEERCRED uid-0 gate) and holds grants in memory. There is
no on-disk artifact to forge or roll back, and grants evaporate when the
daemon stops. pam_sentinel relays over a typed, length-bounded postcard
protocol (sentinel-broker-proto), and is fail-closed: an unreachable
broker means "show the dialog", never "let in". The old root
/run/sentinel/ts timestamp store is removed. Both broker crates are
#![forbid(unsafe_code)]; the unit is hardened (seccomp @system-service,
no capabilities, ProtectSystem=strict, AF_UNIX-only).
Hardening
- Root
unsafesurface locked down.pam-sentinelis
#![deny(unsafe_code)]; hand-rolledextern "C"syscall shims are
replaced with safenixwrappers, leaving onlyfork(2)and post-fork
set_varbehindSAFETY-documented#[allow(unsafe_code)]. - Fuzz harnesses (
cargo-fuzz) for the untrusted inputs that cross
into the auth path —Verdict::from_str,strip_elevation_prefix,
format_message, and the broker wire protocol — smoke-fuzzed in CI.
Installer
- Ships and enables the broker (KDE installer), tearing it down on
uninstall. - Disables sudo's own credential cache.
sudo'stimestamp_timeout
(~5 min) let a back-to-backsudoskip the PAM stack entirely, bypassing
Sentinel. The installer drops aDefaults timestamp_timeout=0snippet so
everysudoruns PAM and Sentinel's per-command window is the only
cache (honored by classic sudo and sudo-rs). Detection covers
/etc/sudoers, openSUSE's/usr/etc/sudoers, and sudo-rs's
/etc/sudoers-rs, writing only into a drop-in dir that config actually
includes (visudo-validated, recorded for uninstall, never a vendor
dir). Skipped with a warning where there's no safe drop-in (e.g. NixOS);
--no-sudoopts out.
Upgrading
- Reinstall to pick up the broker and the updated config. The KDE
installer's reinstall is in-place and reversible. - Terminal
sudo/sunow remember per command out of the box (shipped
config). Set[services.<name>].remember_seconds = 0to keep the strict
"confirm every time" behavior for a service. sudo's built-in 5-minute grace is turned off so Sentinel is the
only sudo cache. Remove/etc/sudoers.d/sentinel-timestamp(or
uninstall) to restore it.- polkit's own
auth_admin_keep/auth_self_keepcaching is unchanged —
Sentinel does not override it.pkexecdoes not usekeep, so it is
re-confirmed every time.