Fwd: [Discussion] systemd-run0 policy issue

Jan Janasek via selinux <[email protected]>
Newsgroups gmane.linux.redhat.fedora.selinux
Message-ID <CABd7YBGJtyK-0zQgUzvxf__uYCNd-Ocv0gwauJkR4Swjdn5--Q@mail.gmail.com>
Hi all,

I am forwarding this to the upstream list for broader discussion.
---------- Forwarded message ---------
From: Jan Janasek <[email protected]>
Date: Tue, Aug 4, 2026 at 11:11 AM
Subject: [Discussion] systemd-run0 policy issue
To: selinux-internal-list <[email protected]>


Hi everyone,

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.

Best regards,
Jan Janasek

-- 
_______________________________________________
selinux mailing list -- [email protected]
To unsubscribe send an email to [email protected]
Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: https://lists.fedoraproject.org/archives/list/[email protected]
Do not reply to spam, report it: https://forge.fedoraproject.org/infra/tickets/issues/new
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.