Re: SELinux Userspace Utilities: Local Denial-of-Service Attack Vectors in seunshare in release 3.10

Stephen Smalley <[email protected]> Mon, 27 Jul 2026 10:07:05 -0400
Newsgroups org.kernel.vger.selinux
Message-ID <CAEjxPJ64pR8QqO-+iBbUfFFajZoPz1buUsJ3ZUDnraU=rjouqg@mail.gmail.com>
FYI, we have published upstream security advisories for these issues
on GitHub at:
https://github.com/SELinuxProject/selinux/security/advisories?state=published

Thanks again for reporting them.

On Mon, Jul 20, 2026 at 4:56 AM Johannes Segitz <[email protected]> wrote:
>
> In case you missed it on OSS
>
> ----- Forwarded message from Matthias Gerstner <[email protected]> -----
>
> Date: Wed, 15 Jul 2026 12:48:22 +0200
> From: Matthias Gerstner <[email protected]>
> To: [email protected]
> Reply-To: [email protected]
> Subject: [oss-security] SELinux Userspace Utilities: Local Denial-of-Service Attack Vectors in seunshare in release 3.10
>
> Hello list,
>
> this is a report about Denial-of-Service issues in the `seunshare`
> setuid-root program. We also offer a rendered HTML version of this
> report on our blog [1].
>
> Summary: seunshare is a setuid-root utility used for sandboxing
> untrusted applications based on Linux namespaces and SELinux policies.
> During a code review we identified two local Denial-of-Service attack
> vectors in version 3.10 of the utility.
>
> 1) Introduction
> ===============
>
> The `seunshare` program [2] is part of the SELinux [3] "sandbox"
> feature, which is used to confine untrusted programs using Linux mount
> namespaces and restrictive SELinux policies. The program is designed to
> be installed with setuid-root privileges, accessible to all users in the
> system.
>
> We have been asked to review the program's security [4] with the
> intention of assigning the setuid bit to it on SUSE distributions in the
> future. Fedora Linux already ships this program with setuid-root
> enabled; other SELinux-enabled Linux distributions may do so as well.
>
> During our review of the utility's code [5] in version 3.10 [6] of the
> SELinux userspace utilities we identified two local Denial-of-Service
> attack vectors, which will be described in detail in the following
> sections. Upstream independently fixed these issues in version 3.11 [7],
> without clearly marking them as security issues, however.
>
> The rest of this report is based on version 3.10 of the codebase of
> `seunshare`.
>
> 2) Design Overview
> ==================
>
> The `seunshare` program is relatively small, consisting of about 1,000
> lines of C code. The elevated `root` privileges are primarily needed to
> setup a custom mount namespace for the sandbox environment.
>
> The program accepts a range of command line arguments which, among
> others, allow to request dedicated directories to be used for the
> following paths inside the sandbox:
>
> - the user's home directory.
> - the `/tmp` directory.
> - the `/run/user/<uid>` directory.
>
> For the `/run` and `/tmp` directories, the source paths specified by the
> user are copied into a random temporary directory in the initial mount
> namespace under `/tmp/.sandbox-<label>-XXXXXX` using the `rsync`
> program. These directories are then bind-mounted into the sandbox's
> mount namespace to appear at the expected locations.
>
> A lot of code in `seunshare` is concerned with securely maintaining
> these temporary directories. To allow the sandbox environment to modify
> the directory contents, `seunshare` assigns group write permissions for
> the real group ID of the calling user, as shown in this example:
>
>     drwxrwx--T. 2 root user 80 Jul  8 16:11 /tmp/.sandbox-user-OaxmUp/
>
> To safely access user-provided paths, the program flips its filesystem
> UID [8] to the real UID of the calling user and back to `root`, as
> needed.
>
> 3) Security Issues
> ==================
>
> Since `seunshare` is supposed to run on SELinux-enabled systems, it is
> important to understand what kind of privilege escalation can be
> achieved when vulnerabilities are exploited in a setuid-root binary like
> this. Many SELinux-enabled systems, such as Fedora and openSUSE, ship
> with the "targeted" SELinux policy by default. This policy is focused on
> confining well-known system services, but assigns an unconfined SELinux
> context to interactive users by default to achieve a balance between
> security and usability.
>
> There is currently no domain transition from the unconfined domain to
> the more restricted `seunshare_t` defined in the SELinux policy for
> `seunshare`. This means the execution of `seunshare` continues in the
> unconfined domain. Thus in the context of attacks carried out by
> interactive users, the impact of the vulnerabilities below will be a
> root-like privilege escalation despite the system running in SELinux
> enforced mode.
>
> 3.1) Local File Deletion Attack Vector in `rm_rf()`
> ---------------------------------------------------
>
> The function `rm_rf()` [9] is called at the end of the utility's
> execution to recursively remove temporary directory trees. While a
> comment in the function suggests that no symbolic links would be
> followed by this routine, the reality is that the `openat()` [10] system
> call is lacking the `O_NOFOLLOW` flag. This creates a race condition
> during the recursion of the `rm_rf()` function:
>
> - first an `fstatat()` is performed for directory contents obtained from
>   `readdir()` to safely determine whether an entry refers to a
>   sub-directory.
> - when a directory is encountered the unsafe `openat()` happens,
>   allowing the unprivileged user to replace the directory entry by a
>   symbolic link in the meantime. While the `O_DIRECTORY` flag is passed
>   to `openat()`, symbolic links in the target are still followed, as
>   long as they point to a directory.
>
> When the user calling `seunshare` is running in the unconfined SELinux
> domain, arbitrary `root`-owned files can be deleted this way. The
> vulnerability does not allow to delete arbitrary files of other users,
> however, because `seunshare` drops all capabilities [11] before calling
> `rm_rf()`.  This leaves the process in a somewhat strange state of
> privilege: it can no longer override discretionary access control (DAC)
> but it is still allowed to operate on files owned by the filesystem-uid
> of the privileged process, which is 0 during the invocation of
> `rm_rf()`.
>
> We developed a reproducer for this issue (attached to this email), which
> succeeds in executing the exploit quickly after some fine tuning of the
> timing for the target system. We verified that the reproducer works on
> current openSUSE Tumbleweed with policycoreutils 3.10 and the
> setuid-root bit enabled on `seunshare`. It does not work on current
> Fedora 44, as it seems Fedora backported a patch to fix this issue (it
> passes `O_NOFOLLOW` to the `openat()` call in question).
>
> Upstream fixed this issue in commit 38f0a4d9a [12] which is part of of
> the 3.11 upstream release.
>
> 3.2) Process Kill Attack Vector in `killall()`
> ----------------------------------------------
>
> `seunshare` offers `--kill` and `-Z` switches as documented in its man
> page:
>
>     -k --kill
>            Kill all processes with matching MCS level
>
>     -Z context
>            Use alternate SELinux context while running the executable
>
> Both switches combined cause the `killall()` [13] function to kill all
> processes running with the user-provided SELinux context. This does not
> fully work for arbitrary target processes due to SELinux access control;
> however, if the calling user is running in unconfined context (as
> explained previously) it allows to kill e.g. `root`-owned processes
> running also in unconfined context.  Once the algorithm reaches its own
> PID (if the context matches), it kills itself, thus it is possible that
> only a certain range of PIDs can be killed this way depending on the PID
> selection order of the algorithm in `killall()`.
>
> We have been able to reproduce the issue both on openSUSE and on Fedora
> 44 using a command line like this:
>
>     seunshare --kill -Z unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 \
>         -t ~/some-dir/ -- /usr/bin/true
>
> Upstream fixed this issue by dropping the `--kill` switch and the
> `killall()` function in commit 572db2fa [14].
>
> 4) Remaining Concerns
> =====================
>
> The code of `seunshare` has seen major changes between version 3.10 and
> 3.11 of the SELinux userspace utilities. The new version of the program
> improves on various aspects of the code; generally the code shows
> awareness of various filesystem-related security concerns that are
> relevant for setuid-root binaries. Still a number of concerns remain:
>
> - Data which is modified in temporary directories within the sandbox is
>   transparently copied back [15] into the calling user's source
>   directory via `rsync`. Since the program is untrusted it can
>   potentially create all kinds of dangerous files, which will now reside
>   e.g. in the user's regular home directory and could lead to security
>   issues at a later time when accessed without care.
> - The code flips the filesystem UID a lot to temporarily drop root
>   privileges for file operations. This logic is hard to follow in parts
>   and leaves the process in an unusual state of privilege, as the
>   effective UID is still 0; during the first stages of the program it
>   also still has all capabilities. Due to the filesystem UID being set
>   to the real user's UID, file operations are carried out using the
>   calling user's lower privileges, however. From a design point of view
>   it would be preferable to let the process operate in an unprivileged
>   state by default (effective UID and GID set to the real UID and GID).
>   Privileges could then be raised for the few operations that actually
>   need `root` privileges.
> - The code currently lacks some common security precautions for
>   setuid-root programs:
>   - while a new environment variable block is set up to execute the
>     untrusted target program, the privileged parent process keeps the
>     untrusted environment variables of the calling user in place. These
>     are also inherited to tools like `rsync` that are invoked for the
>     purposes of setting up the sandbox. While this is not an issue at
>     the moment, it could turn into a security issue at a later time when
>     the code changes.
>   - the `umask()` of the process is also kept unchanged, inheriting
>     whatever the unprivileged parent process configured. This can cause
>     files to receive world-readable or world-writable bits leading to
>     unexpected attack vectors.
>
> 5) CVE Assignments
> ==================
>
> We approached the upstream SELinux userspace utilities developers and
> suggested to assign CVEs for the two issues discussed above. Upstream
> informed us that they don't take care of CVE assignment themselves,
> however. Since Red Hat developers are also involved with upstream
> development, we are currently waiting for an agreement on who will
> assign CVEs to avoid duplicates.
>
> 6) Timeline
> ===========
>
> 2026-07-03: We (mistakenly) approached the SELinux kernel code maintainer,
>     asking for CVE assignments for these issues which have meanwhile been
>     fixed in the 3.11 upstream release.
>
> 2026-07-03: The SELinux kernel code maintainer forwarded our report to the
>     maintainers of the userspace utilities.
>
> 2026-07-06: An SELinux userspace developer informed us that the project
>     is not actively assigning CVEs.
>
> 2026-07-07: We responded that we would be able to assign CVEs on our
>     end, but would like to avoid a clash with any CVE assignment plans on
>     the end of Red Hat developers working on SELinux. We thus asked for
>     clarification of who will take care of it.
>
> 2026-07-15: Publication of this report.
>
> 7) References
> =============
>
> [1]: https://security.opensuse.org/2026/07/15/selinux-seunshare.html
> [2]: https://man7.org/linux/man-pages/man8/seunshare.8.html
> [3]: https://github.com/SELinuxProject/selinux
> [4]: https://bugzilla.suse.com/show_bug.cgi?id=1268256
> [5]: https://github.com/SELinuxProject/selinux/blob/3.10/sandbox/seunshare.c
> [6]: https://github.com/SELinuxProject/selinux/releases/tag/3.10
> [7]: https://github.com/SELinuxProject/selinux/releases/tag/3.11
> [8]: https://man7.org/linux/man-pages/man2/setfsuid.2.html
> [9]: https://github.com/SELinuxProject/selinux/blob/ca10fc4204ed60540d41d2499127c18ad0643f9e/sandbox/seunshare.c#L419
> [10]: https://github.com/SELinuxProject/selinux/blob/ca10fc4204ed60540d41d2499127c18ad0643f9e/sandbox/seunshare.c#L431
> [11]: https://github.com/SELinuxProject/selinux/blob/ca10fc4204ed60540d41d2499127c18ad0643f9e/sandbox/seunshare.c#L1069
> [12]: https://github.com/SELinuxProject/selinux/commit/38f0a4d9a683f2cd2472d4502842df5d5b8255a8
> [13]: https://github.com/SELinuxProject/selinux/blob/ca10fc4204ed60540d41d2499127c18ad0643f9e/sandbox/seunshare.c#L662
> [14]: https://github.com/SELinuxProject/selinux/commit/572db2fae9157ae620160e0d7b2c3f8b75fe6c1a
> [15]: https://github.com/SELinuxProject/selinux/blob/ca10fc4204ed60540d41d2499127c18ad0643f9e/sandbox/seunshare.c#L484
>
> Best Regards
>
> Matthias
>
> --
> Matthias Gerstner <[email protected]>
> Security Engineer
> https://www.suse.com/security
> GPG Key ID: 0x14C405C971923553
>
> SUSE Software Solutions Germany GmbH
> HRB 36809, AG Nürnberg
> Geschäftsführer: Jochen Jaser, Andrew McDonald
>
>
>
>
>
> ----- End forwarded message -----
>
> Johannes
> --
> GPG Key                EE16 6BCE AD56 E034 BFB3  3ADD 7BF7 29D5 E7C8 1FA0
> Subkey fingerprint:    250F 43F5 F7CE 6F1E 9C59  4F95 BC27 DD9D 2CC4 FD66
> SUSE Software Solutions Germany GmbH, Frankenstr. 146, 90461 Nürnberg, Germany
> www.suse.com, Geschäftsführer: Jochen Jaser, Andrew McDonald, Abhinav Puri, (HRB 36809, AG Nürnberg)
>