Re: [Discussion] systemd-run0 policy issue
Dominick Grift <[email protected]>
| Newsgroups | org.kernel.vger.selinux |
|---|---|
| Message-ID | <[email protected]> |
Stephen Smalley <[email protected]> writes: > On Thu, Aug 13, 2026 at 9:35 AM Dominick Grift > <[email protected]> wrote: >> >> Stephen Smalley <[email protected]> writes: >> >> > On Thu, Aug 13, 2026 at 9:11 AM Jan Janasek <[email protected]> wrote: >> >> >> >> 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. >> > >> > Option 1 seems best to me, but this issue might also be related: >> > https://github.com/SELinuxProject/selinux/issues/485 >> >> Disagree because this functionality is not that much more than some >> abstraction/wrapper around systemd's PAMName= functionality. In my view it would >> be more robust to make any solution to this issue also work for the >> underlying PAMName= technology it is built on. > > I'm perfectly willing to stand corrected by those who may know more > about this particular area. > I was merely basing my opinion on what the original poster provided as > context, so feel free to > ignore me ;) The discussion has to start somewhere and this is a good opportunity to clarify why this might be better fixed on a pam_selinux level. The above argument is one but if we address this on a pam_selinux level then that might also work out nicely for systemd-stdio-bridge. I don't know if its technically feasible (Cow was looking into it but went AWOL although he is still on the chat so I will ask him about it) but otherwise it might be implemented similarly to name-based transitions. These are pam-name-based transitions, optional too. -- 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]