Re: [Discussion] systemd-run0 policy issue
Dominick Grift <[email protected]>
| Newsgroups | org.kernel.vger.selinux |
|---|---|
| Message-ID | <[email protected]> |
Jan Janasek <[email protected]> writes: > Hi everyone, > > (I originally posted this to the fedora selinux list, but was advised > that this is the proper ML for such architectural discussions.) > > We’ve been analyzing the integration of systemd-run0 with SELinux and > hit a fundamental architectural roadblock, related to bug > https://bugzilla.redhat.com/show_bug.cgi?id=2359828. Unlike sudo, > where the parent process is the user's shell (allowing PAM to easily > calculate and transition the context), run0 delegates execution via > D-Bus to PID 1 (init_t). This breaks standard SELinux PAM transitions > and creates a severe design challenge for maintaining user isolation. > (Currently, wrapping commands via run0 --via-shell acts as a temporary > workaround, but we are looking for a robust architectural fix.) > > When pam_selinux.so attempts to transition the user directly into > their target domain over a specific binary, it immediately triggers > strict policy conflicts. To demonstrate the exact mechanics of what > happens when PAM forces this transition, I wrote a Python reproducer > (labeled as bin_t and running in the unconfined_t domain) that uses > setexeccon to simulate a transition (e.g., to staff_t) and then calls > os.execl("/usr/bin/dnf5", ...). It triggers these distinct SELinux > denials: > > # 1. The Transition Denial: The kernel blocks the domain transition > type=AVC msg=audit(07/23/2026 09:23:00.584:636) : avc: denied { > transition } for pid=4945 comm=python3 path=/usr/bin/dnf5 > dev="nvme0n1p2" ino=146474 > scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 > tcontext=staff_u:staff_r:staff_t:s0-s0:c0.c1023 tclass=process > permissive=1 > > # 2. The Entrypoint Denial: The target domain lacks entrypoint > permissions on the binary > type=AVC msg=audit(07/23/2026 09:23:00.584:637) : avc: denied { > entrypoint } for pid=4945 comm=python3 path=/usr/bin/dnf5 > dev="nvme0n1p2" ino=146474 > scontext=staff_u:staff_r:staff_t:s0-s0:c0.c1023 > tcontext=system_u:object_r:rpm_exec_t:s0 tclass=file permissive=1 > > Fixing this purely in the Base Policy would require writing transition > and entrypoint rules for every single interactive tool a user might > run. This is unmaintainable, massively expands the attack surface, and > breaks the principle of least privilege. > > We explored a few potential ways to handle this and would like the > community's input: > > 1. SELinux-aware run0 (Upstream fix). Modify run0/systemd to be > natively SELinux-aware. Instead of relying blindly on pam_selinux.so > (which only sees init_t as the caller), run0 could dynamically > calculate the correct target context based on the originating user's > session and explicitly set it for the execution (e.g., via the > SELinuxContext= property of the transient unit). > 2. Leave pam_selinux.so commented out in /lib/pam.d/systemd-run0. If > we leave pam_selinux.so disabled in the run0 PAM stack, processes > simply inherit init_t. This means we would have to write static > type_transition rules into the base policy for every single > interactive binary users might run. (For example, run0 dnf only works > right now because an init_t -> rpm_exec_t transition historically > exists). > 3. Enable PAM + Explicit Default Contexts (A Flawed PoC). We tried > keeping pam_selinux.so enabled and explicitly defining the transition > path in /etc/selinux/targeted/contexts/users/unconfined_u: > system_r:init_t:s0 unconfined_r:systemd_run_t:s0 > unconfined_r:unconfined_t:s0 While this correctly routes run0 payloads > into an isolated domain (systemd_run_t) without polluting init_t, it > causes unacceptable collateral damage. The SELinux get_default_context > API only sees the caller (init_t) and the user (unconfined_u). Because > run0 sessions and systemd --user sessions share these exact same > inputs, this global mapping breaks systemd --user instances by > throwing them into systemd_run_t instead of unconfined_t. > > Given that we cannot safely rely on global policy rules (which expands > PID 1's attack surface) or PAM default contexts (which breaks user > sessions), we'd love to hear your thoughts. Are there other approaches > or configuration options we might have missed? Or is pushing for run0 > to become natively SELinux-aware the most viable path forward? > > Any thoughts or guidance would be greatly appreciated. I brought this up before too: https://github.com/SELinuxProject/selinux/issues/485 My idea was to extend pam_selinux context configuration with a optional "pamname" field. As far as I know that can be retrieved by libpam and then be associated with a context based on a combination of source, target and now also optionally pamname. system_u:system_r:init_t:s0 user_r:user_systemd_t:s0 "systemd-user" system_u:system_r:init_t:s0 user_r:user_t:s0 "systemd-run0" This could then also nicely work natively with systemd's PAMName= functionality. ... In theory at least and that is all that is. > > Best regards, > Jan Janasek > > -- gpg --auto-key-locate clear,nodefault,wkd --locate-external-keys [email protected] Key fingerprint = FCD2 3660 5D6B 9D27 7FC6 E0FF DA7E 521F 10F6 4098 Dominick Grift Mastodon: @[email protected]