<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://security.opensuse.org/feed.xml" rel="self" type="application/atom+xml" /><link href="https://security.opensuse.org/" rel="alternate" type="text/html" /><updated>2026-05-06T08:12:37+00:00</updated><id>https://security.opensuse.org/feed.xml</id><title type="html">SUSE Security Team Blog</title><subtitle>Open Source vulnerability reports and code review results.</subtitle><entry><title type="html">SELinux: Policy Packaging Migration to support Snapshots and Rollbacks</title><link href="https://security.opensuse.org/2026/04/29/selinux-modules-move-to-etc.html" rel="alternate" type="text/html" title="SELinux: Policy Packaging Migration to support Snapshots and Rollbacks" /><published>2026-04-29T00:00:00+00:00</published><updated>2026-04-29T00:00:00+00:00</updated><id>https://security.opensuse.org/2026/04/29/selinux-modules-move-to-etc</id><content type="html" xml:base="https://security.opensuse.org/2026/04/29/selinux-modules-move-to-etc.html"><![CDATA[<h1 class="no_toc" id="table-of-contents">Table of Contents</h1>

<ul id="markdown-toc">
  <li><a href="#0-tldr" id="markdown-toc-0-tldr">0) TL;DR</a></li>
  <li><a href="#1-introduction" id="markdown-toc-1-introduction">1) Introduction</a></li>
  <li><a href="#2-issues-with-current-selinux-policy-packaging" id="markdown-toc-2-issues-with-current-selinux-policy-packaging">2) Issues with current SELinux policy packaging</a></li>
  <li><a href="#3-solution-migration-from-var-to-etc" id="markdown-toc-3-solution-migration-from-var-to-etc">3) Solution: migration from /var to /etc</a>    <ul>
      <li><a href="#packages-involved-in-the-migration" id="markdown-toc-packages-involved-in-the-migration">Packages involved in the migration</a></li>
    </ul>
  </li>
  <li><a href="#4-troubleshooting" id="markdown-toc-4-troubleshooting">4) Troubleshooting</a></li>
  <li><a href="#5-closing-remarks" id="markdown-toc-5-closing-remarks">5) Closing Remarks</a></li>
  <li><a href="#6-references" id="markdown-toc-6-references">6) References</a></li>
</ul>

<h1 id="0-tldr">0) TL;DR</h1>

<ul>
  <li>The SELinux policy packaging had long-standing issues on systems using BTRFS
snapshots: files under <code class="language-plaintext highlighter-rouge">/var/lib/selinux</code> were not covered by snapshots and
could not be rolled back.</li>
  <li>These files have now been migrated to <code class="language-plaintext highlighter-rouge">/etc/selinux</code>, which allows the SELinux
policy to be fully covered by snapshots.</li>
  <li>The migration applies to openSUSE Tumbleweed and MicroOS systems using
SELinux.</li>
  <li>The migration is transparent to the user and automatic on default setups. If
you have a non-standard filesystem setup, or if you observe issues, read the
full post below.</li>
</ul>

<h1 id="1-introduction">1) Introduction</h1>

<p>SELinux has been the Mandatory Access Control mechanism on openSUSE
distributions such as MicroOS and Leap Micro since 2022, and most recently
openSUSE Tumbleweed <a href="https://news.opensuse.org/2025/02/13/tw-plans-to-adopt-selinux-as-default/">switched the default MAC to SELinux</a> in
February 2025.</p>

<p>The files installed on a system by the SELinux policy package have traditionally
been split between <code class="language-plaintext highlighter-rouge">/var/lib/selinux</code>, <code class="language-plaintext highlighter-rouge">/usr/share/selinux</code> and <code class="language-plaintext highlighter-rouge">/etc/selinux</code>
on most Linux distributions, including openSUSE. The separation across these
directory trees conflicts with the modern Linux concept of atomic/image-based
updates, which in openSUSE has been implemented as a <a href="https://en.opensuse.org/openSUSE:Packaging_Requirements_for_Atomic_and_Image_Update">snapshot and rollback
mechanism based on BTRFS</a>. This mechanism only snapshots
the <code class="language-plaintext highlighter-rouge">/usr</code> and <code class="language-plaintext highlighter-rouge">/etc</code> trees, intended for packages and configuration
respectively. Other directory trees are meant for user files or, as in the case
of <code class="language-plaintext highlighter-rouge">/var</code>, for mutable system state files, and as such are not covered by
snapshots.</p>

<p>Installing SELinux policy files under <code class="language-plaintext highlighter-rouge">/var</code> violates this requirement, and can
result in inconsistency in case of rollbacks: policy files under <code class="language-plaintext highlighter-rouge">/etc</code> and
<code class="language-plaintext highlighter-rouge">/usr</code> would be rolled back, but files under <code class="language-plaintext highlighter-rouge">/var</code> would not be touched.</p>

<p>To resolve this issue, we have migrated SELinux policy files under <code class="language-plaintext highlighter-rouge">/var</code> to
<code class="language-plaintext highlighter-rouge">/etc</code>. The migration is automatic and does not require any user interaction in
standard setups. This blog post explains the issue in more detail, documents the
steps taken to migrate the files, and describes known issues and how to resolve
them.</p>

<h1 id="2-issues-with-current-selinux-policy-packaging">2) Issues with current SELinux policy packaging</h1>

<p>Atomic/image-based update systems have become increasingly relevant in recent
years. In openSUSE, this concept has been realised as both fully transactional
systems (e.g. MicroOS, Leap Micro) and as regular distributions with automatic
snapshots and the possibility to rollback broken updates (e.g. Tumbleweed). In
both of these cases, the traditional SELinux policy packaging causes some
issues.</p>

<p>In case of a rollback of an update containing a change to the SELinux policy, if
there is a mismatch between what was rolled back (<code class="language-plaintext highlighter-rouge">/usr/share/selinux</code> and
<code class="language-plaintext highlighter-rouge">/etc/selinux</code>) and what could not (<code class="language-plaintext highlighter-rouge">/var/lib/selinux</code>), this could lead to
policy build issues, external module installation issues, and could bring the
SELinux policy and the whole system into a state which is difficult to recover
from automatically.</p>

<p>In practice, these issues are very rare, since they require a particular set of
circumstances:</p>
<ol>
  <li>installing a policy update which contains backwards-incompatible changes
(e.g. adding or removing SELinux types, attributes, modules …)</li>
  <li>rolling back this update</li>
  <li>performing some action which requires the SELinux policy items affected by
the rollback, such as rebuilding the policy or an affected external policy
module (either manually or e.g. via RPM package installation).</li>
</ol>

<p>As a matter of policy, these kinds of backwards-incompatible policy updates are
never performed on distributions such as Leap Micro (except possibly during
migration between major distribution versions), thus preventing the issue. On
Tumbleweed and MicroOS these updates can happen, albeit rarely, and when
combined with the probability of a rollback and the further triggering actions
they become exceedingly rare.</p>

<p>Manually reinstalling the SELinux policy package (and any affected external
policy modules) is sufficient to fix the issues, but this is still an
undesirable characteristic of this legacy packaging structure.</p>

<h1 id="3-solution-migration-from-var-to-etc">3) Solution: migration from /var to /etc</h1>

<p>To permanently address the aforementioned issues, we decided to migrate SELinux
policy files under <code class="language-plaintext highlighter-rouge">/var/lib/selinux</code> to <code class="language-plaintext highlighter-rouge">/etc/selinux</code>. As mentioned, this
location was already used for other SELinux policy files, and is covered by the
snapshot and rollback mechanism.</p>

<p>The migration was tracked in <a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1221342">bsc#1221342</a>. After a long
period of automated and manual testing over the past few months, the migration
will be performed in an upcoming Tumbleweed snapshot.</p>

<p>Some of the challenges encountered during the implementation of the migration
process were:</p>
<ul>
  <li>different rollback and update behaviour on classical and transactional systems
(also transactional-update before version 5 used overlayfs for /etc)</li>
  <li>preserving existing local modifications to the SELinux configuration</li>
  <li>migrating custom modules (installed by packages or manually created by the
user)</li>
  <li>packaging changes or rebuilds of some packages to properly reflect location
changes, including RPM SELinux macros</li>
  <li>cleanup of <code class="language-plaintext highlighter-rouge">/var/lib/selinux</code> once no snapshot is using the old path</li>
  <li>installation on a fresh system, without migrating an existing system</li>
  <li>observability of discrepancies between migrated modules in
<code class="language-plaintext highlighter-rouge">/etc/selinux</code> and last pre-migration state in <code class="language-plaintext highlighter-rouge">/var/lib/selinux</code></li>
</ul>

<p>The migration process is automatic and in most situations will not be visible
to the user, except for information printed in the <code class="language-plaintext highlighter-rouge">zypper</code> output during the
update. The process takes care not only of the migration of policy
modules provided by the system SELinux policy (e.g. <code class="language-plaintext highlighter-rouge">selinux-policy-targeted</code>),
but also of custom modules installed by other packages (see below) and local
modifications to SELinux configuration (booleans, users, ports, …).</p>

<p>To allow the migration to be fully reverted, the process temporarily preserves
the “old” <code class="language-plaintext highlighter-rouge">/var/lib/selinux/</code> directory tree even after the migration. Once no
snapshots are found which still refer to <code class="language-plaintext highlighter-rouge">/var/lib/selinux</code>, the whole directory
tree is safely deleted.</p>

<p>Most of the steps are done during package update, except for the final cleanup
step which is performed on the system after the migration has been completed.
During package update, the migration process will:</p>
<ul>
  <li>print information about the migration process and inform the user if the
system satisfies the migration requirements (root BTRFS subvolume present) or
if a non-standard setup was detected (e.g. <code class="language-plaintext highlighter-rouge">/etc</code> on different BTRFS subvolume
or no BTRFS at all), and what to do in this case.</li>
  <li>check if the system has already been migrated and skip migration in this case
(using marker files in <code class="language-plaintext highlighter-rouge">/etc/selinux/selinux_modules_migrated-*</code>)</li>
  <li>backup the old location (<code class="language-plaintext highlighter-rouge">/var/lib/selinux</code>) to preserve state (marker files
<code class="language-plaintext highlighter-rouge">selinux_modules_pending-*</code> and <code class="language-plaintext highlighter-rouge">temp_selinux_modules_dir_created</code>)</li>
  <li>install package (modules) into the new location (<code class="language-plaintext highlighter-rouge">/etc/selinux</code>)</li>
  <li>copy local changes and custom modules (<code class="language-plaintext highlighter-rouge">*.local</code> files, <code class="language-plaintext highlighter-rouge">200</code>, <code class="language-plaintext highlighter-rouge">400</code> and
<code class="language-plaintext highlighter-rouge">disabled</code> folders) from the old location to the new location, show diff in
case of missing custom modules from <code class="language-plaintext highlighter-rouge">/etc/selinux</code> (marker file
<code class="language-plaintext highlighter-rouge">selinux_modules_migrated-*</code>)</li>
  <li>install cleanup systemd service (<code class="language-plaintext highlighter-rouge">cleanoldsepoldir.service</code>) and
script(<code class="language-plaintext highlighter-rouge">/usr/libexec/selinux/cleanoldsepoldir.sh</code>) to remove the old
<code class="language-plaintext highlighter-rouge">/var/lib/selinux</code> location once no snapshot is using it</li>
</ul>

<p>After package update:</p>
<ul>
  <li>at boot, the <code class="language-plaintext highlighter-rouge">cleanoldsepoldir</code> service checks if any snapshot still requires
<code class="language-plaintext highlighter-rouge">/var/lib/selinux</code>. If not, it removes the directory, and creates marker file
<code class="language-plaintext highlighter-rouge">var_lib_selinux_deleted</code> to stop the <code class="language-plaintext highlighter-rouge">cleanoldsepoldir</code> service from running
again.</li>
  <li>the cleanup script also allows the user to check if there are some custom
SELinux modules missing in the new location, and has some heuristics to find
the RPM packages of non-migrated modules to reinstall them</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>/usr/libexec/selinux/cleanoldsepoldir.sh <span class="nt">-h</span>
This script checks <span class="k">if </span>it is safe to remove the old /var/lib/selinux directory.

Usage:
  /usr/libexec/selinux/cleanoldsepoldir.sh <span class="o">(</span>Checks snapshots and deletes /var/lib/selinux <span class="k">if </span>safe<span class="o">)</span>
  /usr/libexec/selinux/cleanoldsepoldir.sh <span class="nt">--check-custom-selinux-modules</span> <span class="o">(</span>Checks <span class="k">for </span>unmigrated custom modules<span class="o">)</span>
  /usr/libexec/selinux/cleanoldsepoldir.sh <span class="nt">-h</span>|--help <span class="o">(</span>Displays this <span class="nb">help </span>message<span class="o">)</span>
</code></pre></div></div>

<h2 id="packages-involved-in-the-migration">Packages involved in the migration</h2>

<p>These packages contain the SELinux policy packaging and were the main object of
the migration:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">libsemanage-conf</code> (store-root set to <code class="language-plaintext highlighter-rouge">/etc/selinux/semanage.conf</code>)</li>
  <li><code class="language-plaintext highlighter-rouge">selinux-policy</code> (service <code class="language-plaintext highlighter-rouge">cleanoldsepoldir.service</code> and script
<code class="language-plaintext highlighter-rouge">cleanoldsepoldir.sh</code>)</li>
  <li><code class="language-plaintext highlighter-rouge">selinux-policy-*</code> (actual migration and marker files in <code class="language-plaintext highlighter-rouge">/etc/selinux</code>)</li>
</ul>

<p>All packages which set SELinux booleans were rebuilt:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">selinux-policy-targeted-gaming</code></li>
  <li><code class="language-plaintext highlighter-rouge">selinux-policy-sapenablement</code></li>
  <li><code class="language-plaintext highlighter-rouge">container-selinux</code></li>
  <li><code class="language-plaintext highlighter-rouge">libvirt</code></li>
</ul>

<p>Packages which ship custom SELinux modules were also fixed and rebuilt:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">cockpit-ws-selinux</code></li>
  <li><code class="language-plaintext highlighter-rouge">drbd-selinux</code></li>
  <li><code class="language-plaintext highlighter-rouge">google-guest-oslogin-selinux</code></li>
  <li><code class="language-plaintext highlighter-rouge">swtpm-selinux</code></li>
  <li><code class="language-plaintext highlighter-rouge">tigervnc-selinux</code></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2.0-abrmd-selinux</code></li>
</ul>

<blockquote>
  <p>We tried to identify all packages affected by this migration, but if you
should find other packages in Tumbleweed which need to be migrated, please
report a <a href="https://en.opensuse.org/openSUSE:Bugreport_SELinux">bug</a>.</p>
</blockquote>

<h1 id="4-troubleshooting">4) Troubleshooting</h1>

<ul>
  <li>If you have a non-standard filesystem setup (e.g. using custom BTRFS
subvolumes, not using BTRFS at all, …) the migration may not work for you
fully. You can find out if the migration was successful by checking for the
presence of the directory <code class="language-plaintext highlighter-rouge">/etc/selinux/selinux_modules_migrated-*</code>
corresponding to your installed policy (e.g.
<code class="language-plaintext highlighter-rouge">/etc/selinux/selinux_modules_migrated-targeted</code>). If the directory exists,
the migration has been successful. If not, please open a <a href="https://en.opensuse.org/openSUSE:Bugreport_SELinux">bug</a>.</li>
  <li>If you observe any issues resembling those described in <a href="#2-issues-with-current-selinux-policy-packaging">Section
2</a>, you can resolve them by
reinstalling the <code class="language-plaintext highlighter-rouge">selinux-policy*</code> package and any affected external modules:
    <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>zypper <span class="k">in</span> <span class="nt">-f</span> selinux-policy selinux-policy-targeted
</code></pre></div>    </div>
  </li>
  <li>After the migration, only the last state of <code class="language-plaintext highlighter-rouge">/var/lib/selinux</code> is preserved,
which means that some older snapshots may still be inconsistent with it. If
rolling back to one of these older snapshots is necessary, you can fix the
issues after rolling back by reinstalling the policy and any affected external
modules as detailed above.</li>
</ul>

<h1 id="5-closing-remarks">5) Closing Remarks</h1>

<p>The openSUSE SELinux team is committed to keeping openSUSE users safe with
SELinux, and to fixing problems that SELinux may cause to the community. To
facilitate changes with SELinux we rely on users to work with us and provide
feedback, so that we understand what the current problematic areas are. If you
encounter problems with SELinux feel free to open a <a href="https://en.opensuse.org/openSUSE:Bugreport_SELinux">bug</a> or reach
out over the <a href="https://lists.opensuse.org/archives/list/selinux@lists.opensuse.org/">mailing list</a>.</p>

<h1 id="6-references">6) References</h1>

<ul>
  <li><a href="https://news.opensuse.org/2025/02/13/tw-plans-to-adopt-selinux-as-default/">Tumbleweed Adopts SELinux as Default</a></li>
  <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1221342">Policy migration tracker bug</a></li>
  <li><a href="https://en.opensuse.org/openSUSE:Bugreport_SELinux">openSUSE Bugreport SELinux</a></li>
  <li><a href="https://lists.opensuse.org/archives/list/selinux@lists.opensuse.org/">openSUSE SELinux Mailing List</a></li>
</ul>]]></content><author><name>Zdenek Kubala, &lt;a href=&apos;mailto:filippo.bonazzi@suse.com&apos;&gt;Filippo Bonazzi (editor)&lt;/a&gt;</name></author><category term="selinux" /><summary type="html"><![CDATA[The traditional SELinux policy location /var/lib/selinux is not supported by the openSUSE snapshot and rollback mechanism. openSUSE is now migrating the policy packaging to locations supported by this mechanism, which will allow for proper policy snapshots and rollbacks.]]></summary></entry><entry><title type="html">plasma-login-manager: Weaknesses in plasmaloginauthhelper (CVE-2026-25710)</title><link href="https://security.opensuse.org/2026/04/27/plasma-login-manager.html" rel="alternate" type="text/html" title="plasma-login-manager: Weaknesses in plasmaloginauthhelper (CVE-2026-25710)" /><published>2026-04-27T00:00:00+00:00</published><updated>2026-04-27T00:00:00+00:00</updated><id>https://security.opensuse.org/2026/04/27/plasma-login-manager</id><content type="html" xml:base="https://security.opensuse.org/2026/04/27/plasma-login-manager.html"><![CDATA[<h1 class="no_toc" id="table-of-contents">Table of Contents</h1>

<ul id="markdown-toc">
  <li><a href="#1-introduction" id="markdown-toc-1-introduction">1) Introduction</a></li>
  <li><a href="#2-helper-overview" id="markdown-toc-2-helper-overview">2) Helper Overview</a></li>
  <li><a href="#3-security-issues" id="markdown-toc-3-security-issues">3) Security Issues</a>    <ul>
      <li><a href="#3a-arbitrary-chown-via-symlink-attack-in-sync-method" id="markdown-toc-3a-arbitrary-chown-via-symlink-attack-in-sync-method">3.a) Arbitrary <code class="language-plaintext highlighter-rouge">chown()</code> via Symlink Attack in <code class="language-plaintext highlighter-rouge">sync()</code> Method</a></li>
      <li><a href="#3b-arbitrary-file-deletion-in-reset-method" id="markdown-toc-3b-arbitrary-file-deletion-in-reset-method">3.b) Arbitrary File Deletion in <code class="language-plaintext highlighter-rouge">reset()</code> Method</a></li>
      <li><a href="#3c-symlink-attack-via-varlibplasmaloginwallpapers-in-save-method" id="markdown-toc-3c-symlink-attack-via-varlibplasmaloginwallpapers-in-save-method">3.c) Symlink Attack via <code class="language-plaintext highlighter-rouge">/var/lib/plasmalogin/wallpapers</code> in <code class="language-plaintext highlighter-rouge">save()</code> Method</a></li>
      <li><a href="#3d-missing-integrity-check-of-configuration-data-in-save-method" id="markdown-toc-3d-missing-integrity-check-of-configuration-data-in-save-method">3.d) Missing Integrity Check of Configuration Data in <code class="language-plaintext highlighter-rouge">save()</code> Method</a></li>
      <li><a href="#3e-lack-of-file-descriptor-and-file-size-verification-in-save-method" id="markdown-toc-3e-lack-of-file-descriptor-and-file-size-verification-in-save-method">3.e) Lack of File Descriptor and File Size Verification in <code class="language-plaintext highlighter-rouge">save()</code> Method</a></li>
    </ul>
  </li>
  <li><a href="#4-suggested-fixes" id="markdown-toc-4-suggested-fixes">4) Suggested Fixes</a></li>
  <li><a href="#5-severity" id="markdown-toc-5-severity">5) Severity</a></li>
  <li><a href="#6-upstream-bugfix" id="markdown-toc-6-upstream-bugfix">6) Upstream Bugfix</a></li>
  <li><a href="#7-cve-assignment" id="markdown-toc-7-cve-assignment">7) CVE Assignment</a></li>
  <li><a href="#8-timeline" id="markdown-toc-8-timeline">8) Timeline</a></li>
  <li><a href="#9-references" id="markdown-toc-9-references">9) References</a></li>
</ul>

<h1 id="1-introduction">1) Introduction</h1>

<p>In recent releases of the KDE desktop environment a fork of the <a href="https://www.github.com/sddm/sddm">SDDM display
manager</a> called <a href="https://invent.kde.org/plasma/plasma-login-manager">plasma-login-manager</a> has been
integrated. As usual this led to <a href="https://bugzilla.suse.com/show_bug.cgi?id=1260039">a review</a> in our team for the
privileged D-Bus components contained in the package. While most of the code
<a href="https://bugzilla.suse.com/show_bug.cgi?id=1260402">remains the same</a>, the new upstream added a <a href="https://invent.kde.org/plasma/plasma-login-manager/-/blob/v6.6.2/src/frontend/kcm/auth/plasmaloginauthhelper.cpp?ref_type=tags">privileged D-Bus
helper</a> called <code class="language-plaintext highlighter-rouge">plasmaloginauthhelper</code>, which suffers from
<a href="https://bugzilla.suse.com/show_bug.cgi?id=1260930">defense-in-depth security issues</a>. The full details of the
issues will be discussed in the following sections.</p>

<p>For this review we looked into plasma-login-manager <a href="https://invent.kde.org/plasma/plasma-login-manager/-/tree/v6.6.2?ref_type=tags">version
6.6.2</a>.</p>

<h1 id="2-helper-overview">2) Helper Overview</h1>

<p><code class="language-plaintext highlighter-rouge">plasmaloginauthhelper</code> makes the D-Bus interface
“org.kde.kcontrol.kcmplasmalogin” accessible to all users in the system via
the D-Bus system bus. It offers three actions <code class="language-plaintext highlighter-rouge">sync()</code>, <code class="language-plaintext highlighter-rouge">reset()</code> and <code class="language-plaintext highlighter-rouge">save()</code>
which are all by default protected by Polkit’s <code class="language-plaintext highlighter-rouge">auth_admin</code> setting.</p>

<p>These methods allow to manage configuration data stored in the home directory
of the <code class="language-plaintext highlighter-rouge">plasmalogin</code> service user, which has a preset of <code class="language-plaintext highlighter-rouge">/var/lib/plasmalogin</code>.
The helper runs with full root privileges and interprets various
client-supplied data. The <code class="language-plaintext highlighter-rouge">plasmalogin</code> home directory has the following
permissions:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>drwxr-x--- 5 plasmalogin plasmalogin 4.0K Mar 24 13:25
</code></pre></div></div>

<p>Actually this helper is also a kind of fork of a helper found in the
<code class="language-plaintext highlighter-rouge">sddm-kcm</code> repository, which we covered <a href="/2024/04/02/kde6-dbus-polkit.html#problematic-file-system-operations-in-sddm-kcm6">in a previous
report</a>. It seems the codebase has not improved since then,
but rather additional attack surface has been added in the meantime.</p>

<h1 id="3-security-issues">3) Security Issues</h1>

<h2 id="3a-arbitrary-chown-via-symlink-attack-in-sync-method">3.a) Arbitrary <code class="language-plaintext highlighter-rouge">chown()</code> via Symlink Attack in <code class="language-plaintext highlighter-rouge">sync()</code> Method</h2>

<p>In the <a href="https://invent.kde.org/plasma/plasma-login-manager/-/blob/v6.6.2/src/frontend/kcm/auth/plasmaloginauthhelper.cpp?ref_type=tags#L61"><code class="language-plaintext highlighter-rouge">sync()</code> method</a> the helper service naively performs
<a href="https://invent.kde.org/plasma/plasma-login-manager/-/blob/v6.6.2/src/frontend/kcm/auth/plasmaloginauthhelper.cpp?ref_type=tags#L85"><code class="language-plaintext highlighter-rouge">chown()</code> calls</a> on files located in the service user’s home
directory (<code class="language-plaintext highlighter-rouge">/var/lib/plasmalogin</code>), allowing a <code class="language-plaintext highlighter-rouge">plasmalogin</code> to <code class="language-plaintext highlighter-rouge">root</code>
exploit.</p>

<p>The <code class="language-plaintext highlighter-rouge">chown()</code> is performed for the paths <code class="language-plaintext highlighter-rouge">$PLASMALOGIN_HOME/.config</code>,
<code class="language-plaintext highlighter-rouge">$PLASMALOGIN_HOME/.config/fontconfig</code> as well for a list of configuration
files like <code class="language-plaintext highlighter-rouge">plasmarc</code> placed into <code class="language-plaintext highlighter-rouge">$PLASMALOGIN_HOME/.config</code>.</p>

<p>A compromised <code class="language-plaintext highlighter-rouge">plasmalogin</code> service account can place symbolic links here to
direct the <code class="language-plaintext highlighter-rouge">chown()</code> to arbitrary files in the system. After the <code class="language-plaintext highlighter-rouge">chown()</code> the
helper writes client-supplied content into these files, which will also end up
in arbitrary files in case of a symlink attack.</p>

<p>This method’s logic would also allow deletion of certain files like <code class="language-plaintext highlighter-rouge">plasmarc</code>
in arbitrary directories, would the <a href="https://invent.kde.org/plasma/plasma-login-manager/-/blob/v6.6.2/src/frontend/kcm/auth/plasmaloginauthhelper.cpp?ref_type=tags#L99">relevant
statement</a> in the service implementation not lack the
final filename component in the path construction:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">QFile</span><span class="p">(</span><span class="n">homeDir</span> <span class="o">+</span> <span class="n">QStringLiteral</span><span class="p">(</span><span class="s">"/.config/"</span><span class="p">)).</span><span class="n">remove</span><span class="p">();</span>
</code></pre></div></div>

<p>Thus this removal logic doesn’t work at all at the moment, since it attempts
to remove the <code class="language-plaintext highlighter-rouge">.config</code> directory instead of the actual configuration files.</p>

<h2 id="3b-arbitrary-file-deletion-in-reset-method">3.b) Arbitrary File Deletion in <code class="language-plaintext highlighter-rouge">reset()</code> Method</h2>

<p>In the <a href="https://invent.kde.org/plasma/plasma-login-manager/-/blob/v6.6.2/src/frontend/kcm/auth/plasmaloginauthhelper.cpp?ref_type=tags#L125"><code class="language-plaintext highlighter-rouge">reset()</code> method</a> the paths <code class="language-plaintext highlighter-rouge">$PLASMALOGIN_HOME/.cache</code> and
<code class="language-plaintext highlighter-rouge">$PLASMALOGIN_HOME/.config/fontconfig</code> are recursively deleted. For this
purpose the Qt API <code class="language-plaintext highlighter-rouge">QDir::removeRecursively()</code> is used. <a href="https://github.com/qt/qtbase/blob/90b845d15ffb97693dba527385db83510ebd121a/src/corelib/io/qdir.cpp#L1666">The
implementation</a> of this function follows symbolic links even in the
final path component, which means that a compromised <code class="language-plaintext highlighter-rouge">plasmalogin</code> service
user can leverage this logic to achieve the deletion of arbitrary directory
trees in the system.</p>

<h2 id="3c-symlink-attack-via-varlibplasmaloginwallpapers-in-save-method">3.c) Symlink Attack via <code class="language-plaintext highlighter-rouge">/var/lib/plasmalogin/wallpapers</code> in <code class="language-plaintext highlighter-rouge">save()</code> Method</h2>

<p>In the <a href="https://invent.kde.org/plasma/plasma-login-manager/-/blob/v6.6.2/src/frontend/kcm/auth/plasmaloginauthhelper.cpp?ref_type=tags#L161"><code class="language-plaintext highlighter-rouge">save()</code> method</a> the path <code class="language-plaintext highlighter-rouge">/var/lib/plasmalogin/wallpapers</code>
is <a href="https://invent.kde.org/plasma/plasma-login-manager/-/blob/v6.6.2/src/frontend/kcm/auth/plasmaloginauthhelper.cpp?ref_type=tags#L195">created and opened by root</a>, using a system call
sequence affected by a race condition. A compromised <code class="language-plaintext highlighter-rouge">plasmalogin</code> user can
replace the directory by a symbolic link in time for the service to write
wallpaper files to arbitrary locations in the system, leading to local
Denial-of-Service (DoS) and integrity violation.</p>

<p>In this spot the helper employs a low-level <a href="https://invent.kde.org/plasma/plasma-login-manager/-/blob/v6.6.2/src/frontend/kcm/auth/plasmaloginauthhelper.cpp?ref_type=tags#L225"><code class="language-plaintext highlighter-rouge">openat2()</code> system
call</a> to avoid symbolic link resolution, but this only
applies to the actual files placed within the wallpaper directory, not to the
directory itself, which is naively opened before that.</p>

<h2 id="3d-missing-integrity-check-of-configuration-data-in-save-method">3.d) Missing Integrity Check of Configuration Data in <code class="language-plaintext highlighter-rouge">save()</code> Method</h2>

<p>In the <code class="language-plaintext highlighter-rouge">save()</code> method the contents of the file <code class="language-plaintext highlighter-rouge">/etc/plasmalogin.conf</code> can be
<a href="https://invent.kde.org/plasma/plasma-login-manager/-/blob/v6.6.2/src/frontend/kcm/auth/plasmaloginauthhelper.cpp?ref_type=tags#L169">completely controlled by the caller</a>. Since this
method is protected by <code class="language-plaintext highlighter-rouge">auth_admin</code> Polkit authentication this is basically
acceptable, but there is not even an integrity or syntax check of the data,
the method blindly forwards whatever the client passes to it into this file,
without a maximum size limit or any sanity checks. While this is not directly a
security issue it is a lack of robustness, because the D-Bus service is
responsible for maintaining a sane structure of the privileged configuration
file, preventing a broken system e.g. in case of buggy clients.</p>

<h2 id="3e-lack-of-file-descriptor-and-file-size-verification-in-save-method">3.e) Lack of File Descriptor and File Size Verification in <code class="language-plaintext highlighter-rouge">save()</code> Method</h2>

<p>For the actual wallpaper files, <a href="/2024/08/13/summer-spotlight.html#kde6-release-final-touches-and-improvements">file descriptor passing</a>
is employed, which is good. There is no upper limit enforced on the amount of
data placed into the wallpapers directory, however, which allows to exhaust
disk space in <code class="language-plaintext highlighter-rouge">/var/lib/plasmalogin</code>.</p>

<p>Even file descriptors passed from clients should be verified to check whether
they refer to regular files and have no unexpected file flags set. This
verification is missing.</p>

<h1 id="4-suggested-fixes">4) Suggested Fixes</h1>

<p>We suggested the following fixes to upstream:</p>

<ul>
  <li>Foremost the helper should drop privileges to the <code class="language-plaintext highlighter-rouge">plasmalogin</code> user before
performing any file system operations in <code class="language-plaintext highlighter-rouge">/var/lib/plasmalogin</code>, thereby
eliminating all symlink attack surface. There still remains
Denial-of-Service (DoS) attack surface if the service user places e.g. a named
FIFO pipe somewhere. Avoiding this requires careful inspection of each path
component by the service before opening it.</li>
  <li>The helper should verify the structure and size of data written to
<code class="language-plaintext highlighter-rouge">/etc/plasmalogin.conf</code>.</li>
  <li>The helper should place a limit on the maximum amount of space which
may be used for wallpapers in the <code class="language-plaintext highlighter-rouge">plasmalogin</code> user’s home directory.</li>
  <li>The helper should verify the type and flags of file descriptors passed
by the client. The descriptors should not have special file types and
they should not have any unexpected flags like <code class="language-plaintext highlighter-rouge">O_PATH</code> set.</li>
</ul>

<h1 id="5-severity">5) Severity</h1>

<p>None of the issues in this report is exploitable in a default installation of
<code class="language-plaintext highlighter-rouge">plasma-login-manager</code>. Most of the problems affect the situation when the
<code class="language-plaintext highlighter-rouge">plasmalogin</code> service user is compromised and thus affect defense-in-depth.</p>

<p>It is conceivable, however,  that some actions in the helper, like the
wallpaper management, could be reduced to lesser authentication requirements
like a Polkit <code class="language-plaintext highlighter-rouge">yes</code> setting for locally logged-in users in the future, be it
due to upstream changes or due to choices made by system integrators. Then
further problems like disk space exhaustion by other unprivileged users could
sneak in as well.</p>

<p>Based on the high severity of the defense-in-depth issues shown in this
report, our assessment is that there is effectively no separation between
<code class="language-plaintext highlighter-rouge">root</code> and the <code class="language-plaintext highlighter-rouge">plasmalogin</code> service user account.</p>

<h1 id="6-upstream-bugfix">6) Upstream Bugfix</h1>

<p>At this time there is no bugfix available by upstream, but a security fix
is planned for the next Plasma release on May 12. We have not been involved in
upstream’s bugfix process so far and have no knowledge about the approach that
will be taken to address the issues from this report.</p>

<h1 id="7-cve-assignment">7) CVE Assignment</h1>

<p>We suggested a single CVE assignment relating to the lack of privilege drop of
the D-Bus service, which is the root cause of most of the issues described in
this report. In coordination with upstream we assigned CVE-2026-25710 and
shared it with them to track these defects.</p>

<h1 id="8-timeline">8) Timeline</h1>

<table>
  <tbody>
    <tr>
      <td>2026-03-30</td>
      <td>We reached out to security@kde.org with a report of the problems, offering coordinated disclosure. We stated that in our eyes, due to the issues being restricted to defense-in-depth, an embargo would not be strictly necessary.</td>
    </tr>
    <tr>
      <td>2026-03-30</td>
      <td>Upstream provided a short reply, asking for a CVE assignment.</td>
    </tr>
    <tr>
      <td>2026-03-31</td>
      <td>We assigned CVE-2026-25710 and shared it with upstream.</td>
    </tr>
    <tr>
      <td>2026-04-13</td>
      <td>Lacking a more detailed response from upstream we asked once more whether they would like to perform coordinated disclosure and what the desired coordinated release date (CRD) would be in that case.</td>
    </tr>
    <tr>
      <td>2026-04-13</td>
      <td>We received a reply from upstream stating that no coordinated disclosure would be necessary and bugfixes would be published via public pull requests soon in expectation of a security release on May 12.</td>
    </tr>
    <tr>
      <td>2026-04-13</td>
      <td>To be sure we asked upstream once more whether they agreed to us publishing the report right away.</td>
    </tr>
    <tr>
      <td>2026-04-20</td>
      <td>Lacking a response and with no visible publication on upstream’s end we asked once more if publication on our end would be acceptable for them.</td>
    </tr>
    <tr>
      <td>2026-04-21</td>
      <td>We received a response confirming that we were allowed to publish right away.</td>
    </tr>
  </tbody>
</table>

<h1 id="9-references">9) References</h1>

<ul>
  <li><a href="/2024/04/02/kde6-dbus-polkit.html#problematic-file-system-operations-in-sddm-kcm6">blog post about issues in sddm-kcm6</a></li>
  <li><a href="/2024/08/13/summer-spotlight.html#kde6-release-final-touches-and-improvements">blog post about the introduction of file descriptor passing in kauth</a></li>
  <li><a href="https://bugzilla.suse.com/show_bug.cgi?id=1260930">openSUSE plasma-login-manager KCM helper review bug</a></li>
  <li><a href="https://invent.kde.org/plasma/plasma-login-manager/-/blob/v6.6.2/src/frontend/kcm/auth/plasmaloginauthhelper.cpp?ref_type=tags">plasmaloginauthhelper code</a></li>
  <li><a href="https://invent.kde.org/plasma/plasma-login-manager">plasma-login-manager repository</a></li>
</ul>]]></content><author><name>&lt;a href=&apos;mailto:matthias.gerstner@suse.de&apos;&gt;Matthias Gerstner&lt;/a&gt;, &lt;a href=&apos;mailto:filippo.bonazzi@suse.com&apos;&gt;Filippo Bonazzi (editor)&lt;/a&gt;</name></author><category term="CVE" /><category term="D-Bus" /><summary type="html"><![CDATA[plasma-login-manager, a new display manager component in KDE, contains a privileged D-Bus helper which suffers from defense-in-depth issues allowing the plasmalogin service user to escalate to root in various ways.]]></summary></entry><entry><title type="html">SUSE Security Team Spotlight Winter 2025/2026</title><link href="https://security.opensuse.org/2026/04/20/winter-spotlight.html" rel="alternate" type="text/html" title="SUSE Security Team Spotlight Winter 2025/2026" /><published>2026-04-20T00:00:00+00:00</published><updated>2026-04-20T00:00:00+00:00</updated><id>https://security.opensuse.org/2026/04/20/winter-spotlight</id><content type="html" xml:base="https://security.opensuse.org/2026/04/20/winter-spotlight.html"><![CDATA[<h1 class="no_toc" id="table-of-contents">Table of Contents</h1>

<ul id="markdown-toc">
  <li><a href="#1-introduction" id="markdown-toc-1-introduction">1) Introduction</a></li>
  <li><a href="#section-systemd" id="markdown-toc-section-systemd">2) systemd v258 - v260 Continued Reviews of D-Bus and Varlink Changes</a></li>
  <li><a href="#section-snap" id="markdown-toc-section-snap">3) snapd: Follow-up Audit for Transparent Inclusion of Snap Systemd Services</a></li>
  <li><a href="#section-bootkitd" id="markdown-toc-section-bootkitd">4) bootkitd: D-Bus Service for Manipulating Bootloader Configuration</a></li>
  <li><a href="#section-libpgpr" id="markdown-toc-section-libpgpr">5) libpgpr: RPM PGP Signature Parsing Library</a></li>
  <li><a href="#section-gdm" id="markdown-toc-section-gdm">6) GDM: Changes and Additions in Release 50</a></li>
  <li><a href="#section-rtkit" id="markdown-toc-section-rtkit">7) rtkit: D-Bus Service to Support Unprivileged Realtime Scheduling</a></li>
  <li><a href="#section-steamos" id="markdown-toc-section-steamos">8) SteamOS Package Additions</a>    <ul>
      <li><a href="#jupiter-fan-control" id="markdown-toc-jupiter-fan-control">jupiter-fan-control</a></li>
      <li><a href="#gamescope-session-steam-factory-reset" id="markdown-toc-gamescope-session-steam-factory-reset">gamescope-session-steam-factory-reset</a></li>
      <li><a href="#jupiter-hw-support" id="markdown-toc-jupiter-hw-support">jupiter-hw-support</a></li>
    </ul>
  </li>
  <li><a href="#section-deepin" id="markdown-toc-section-deepin">9) Revisit of Deepin Desktop D-Bus Services after Removal from openSUSE</a>    <ul>
      <li><a href="#backlight-helper" id="markdown-toc-backlight-helper">Backlight Helper</a></li>
      <li><a href="#accounts-service" id="markdown-toc-accounts-service">Accounts Service</a></li>
      <li><a href="#summary" id="markdown-toc-summary">Summary</a></li>
    </ul>
  </li>
  <li><a href="#10-conclusion" id="markdown-toc-10-conclusion">10) Conclusion</a></li>
</ul>

<h1 id="1-introduction">1) Introduction</h1>

<p>The winter months have passed for us and as usual we want to give you an
overview of what topics our team covered in the area of code reviews during
this time. We did not publish any dedicated security reports for a while, after
we had to deal with a little burst of publications at the beginning of the
year. Still we haven’t been idle during this time and looked into various
packages and components, which we will cover in this post.</p>

<p>The <a href="#section-systemd">next section</a> discusses continued review efforts
surrounding new systemd releases. <a href="#section-snap">Section 3</a> covers a follow-up
audit of changes in the Snap package manager. <a href="#section-bootkitd">Section 4</a>
looks at <code class="language-plaintext highlighter-rouge">bootkitd</code>, a D-Bus service for managing bootloader configuration.
<a href="#section-libpgpr">Section 5</a> deals with <code class="language-plaintext highlighter-rouge">libpgpr</code>, a signature parsing library
which was pulled out of the RPM package manager codebase. <a href="#section-gdm">Section
6</a> is about changes we reviewed in a new release of GNOME display
manager (GDM). <a href="#section-rtkit">Section 7</a> contains a review report about the
<code class="language-plaintext highlighter-rouge">rtkit</code> real-time scheduling D-Bus service. <a href="#section-steamos">Section 8</a>
provides an insight into efforts to package SteamOS components for openSUSE
Tumbleweed. <a href="#section-deepin">Section 9</a> looks into an attempt to get Deepin
desktop components back into openSUSE.</p>

<h1 id="section-systemd">2) systemd v258 - v260 Continued Reviews of D-Bus and Varlink Changes</h1>

<p>We already gave an insight into our efforts of reviewing changes in systemd
v258 in <a href="/2026/01/14/autumn-spotlight.html#section-systemd">our previous spotlight post</a>. Meanwhile systemd
upstream has established a new release model leading to more frequent releases
and backports of new features into existing stable branches. This has caused an
increase of review requests in our team, as can be seen by the following list
of review bugs we received since the v258 version release:</p>

<ul>
  <li><a href="https://bugzilla.suse.com/show_bug.cgi?id=1257388">bsc#1257388: follow-up review of backported code in systemd 258.3</a></li>
  <li><a href="https://bugzilla.suse.com/show_bug.cgi?id=1257943">bsc#1257943: follow-up review of backported code in systemd 258.4</a></li>
  <li><a href="https://bugzilla.suse.com/show_bug.cgi?id=1255368">bsc#1255368: review of changes introduced in systemd 259</a></li>
  <li><a href="https://bugzilla.suse.com/show_bug.cgi?id=1259318">bsc#1259318: review of changes introduced in systemd 260</a></li>
</ul>

<p>The review of changes in systemd 260 has just been finished and the new
version is about to become available in openSUSE Tumbleweed soon. The
backports into stable 258 branches have been easy to review so far, since they
are mostly clean cherry-pick merges of changes reviewed by us earlier already.</p>

<p>So far we did not find any issues in the continued changes in systemd, but it
remains a challenging review target especially in the area of virtual machine
and container APIs, as we have explained in earlier posts on the topic.</p>

<h1 id="section-snap">3) snapd: Follow-up Audit for Transparent Inclusion of Snap Systemd Services</h1>

<p>After we <a href="/2026/01/14/autumn-spotlight.html#section-snapd">accepted snap</a> into openSUSE Tumbleweed a while ago we
received a <a href="https://bugzilla.suse.com/show_bug.cgi?id=1256175">follow-up review request</a>, which revolves around a
feature to transparently make systemd services available which have been
installed via Snaps.</p>

<p>We have accepted the change, but asked the packagers to include a notice in
the package informing openSUSE users that systemd services installed via Snaps
are not covered by the security review processes of SUSE product security.</p>

<h1 id="section-bootkitd">4) bootkitd: D-Bus Service for Manipulating Bootloader Configuration</h1>

<p><a href="https://github.com/Nykseli/bootkitd">Bootkitd</a> is a D-Bus service for programmatically managing
bootloader configuration. We received <a href="https://bugzilla.suse.com/show_bug.cgi?id=1256421">a review request</a> for
its inclusion into openSUSE Tumbleweed. The service is implemented in the Rust
programming language and is a simple case regarding security, since it is only
accessible by <code class="language-plaintext highlighter-rouge">root</code>. Thus no privilege boundaries are crossed and privilege
escalation is not a concern.</p>

<h1 id="section-libpgpr">5) libpgpr: RPM PGP Signature Parsing Library</h1>

<p><a href="https://github.com/rpm-software-management/libpgpr"><code class="language-plaintext highlighter-rouge">libpgpr</code></a> is a library which has been recently separated from
the main RPM package manager codebase. Its purpose is the parsing and
verification of PGP signatures as they are found embedded in RPM files. Given
the sensitive nature of PGP cryptography and potentially crafted input data,
we have been asked <a href="https://bugzilla.suse.com/show_bug.cgi?id=1257996">to check the security</a> of this library.</p>

<p>The library consists of a legacy C codebase living up to the C90 standard.
The library API is not well documented and not very consistent at the moment.
At the same time the code is concerned with memory management and binary data
structure parsing of high complexity. These shortcomings notwithstanding, the
implementation seems to have matured over time and we believe there are
currently no major errors to be found when processing untrusted data.</p>

<p>In our opinion, the biggest danger regarding security in this codebase will
likely be future changes which might introduce regressions. Also users of the
library won’t easily know what to expect of the API, since requirements are
not clearly marked (e.g. which parameters are optional, when memory ownership
transfers happen and so on).</p>

<p>We provided <a href="https://github.com/rpm-software-management/libpgpr/pull/1/changes/0310a46f661ed9059eb0fb5ab8686ee6f761b2cc">comprehensive comments</a> on the
codebase to upstream, suggesting various refactoring, improvements and test
coverage to bring the project up to a more modern standard.</p>

<h1 id="section-gdm">6) GDM: Changes and Additions in Release 50</h1>

<p>In February our openSUSE Gnome Display Manager (GDM) maintainers started
preparing the upgrade for release 50, which was in Beta testing at the time,
but should be fully released by now. The new version triggered <a href="https://bugzilla.suse.com/show_bug.cgi?id=1258025">a follow-up
review</a> of D-Bus and Polkit related features in GDM.</p>

<p>GDM is tightly integrated with GNOME remote desktop (GRD) these days and the
changes we’ve seen here are related to this integration. The differences
compared to the previous version of GDM have been small in the area of D-Bus
and Polkit, though, and no problematic additional attack surface has been
added in this version.</p>

<h1 id="section-rtkit">7) rtkit: D-Bus Service to Support Unprivileged Realtime Scheduling</h1>

<p>The <a href="https://gitlab.freedesktop.org/pipewire/rtkit">rtkit daemon</a> has been around on Linux distributions for
a long time. Its purpose it to allow unprivileged programs in the system to
make use of real-time scheduling features in a controlled fashion. Linux
offers <a href="https://man7.org/linux/man-pages/man7/sched.7.html">two real-time scheduling policies</a> <code class="language-plaintext highlighter-rouge">SCHED_RR</code> and
<code class="language-plaintext highlighter-rouge">SCHED_FIFO</code>, which perform Round-robin or First-in First-out scheduling
respectively. Rogue processes running under one of these policies can easily
lock up the complete system due to no other userspace threads being scheduled
by the kernel anymore. For this reason, only tasks holding the <code class="language-plaintext highlighter-rouge">CAP_SYS_NICE</code>
capability (usually only <code class="language-plaintext highlighter-rouge">root</code>) are allowed to assign these scheduling
settings.</p>

<p>This is where <code class="language-plaintext highlighter-rouge">rtkit</code> comes in: it offers a D-Bus interface to allow
unprivileged processes to enjoy real-time scheduling features while being
under supervision of the <code class="language-plaintext highlighter-rouge">rtkit</code> daemon to prevent any negative side effects.</p>

<p>In a recent update of <code class="language-plaintext highlighter-rouge">rtkit</code> to version 0.14, changes in its D-Bus
configuration triggered a <a href="https://bugzilla.suse.com/show_bug.cgi?id=1258681">follow-up review</a> after over a decade
since our team last looked at it. <code class="language-plaintext highlighter-rouge">rtkit</code> is installed and running (or
activatable) by default on a number of Linux distributions like openSUSE,
Debian or Fedora. Due to this prevalence of <code class="language-plaintext highlighter-rouge">rtkit</code> in Linux systems, the
inherent danger of a local Denial-of-Service and in light of the amount of
time passed since the last full review, we thought it wise to have a fresh look
at the service’s implementation.</p>

<p>The <code class="language-plaintext highlighter-rouge">rtkit</code> D-Bus configuration follows a bit of an unusual approach by
maintaining <a href="https://gitlab.freedesktop.org/pipewire/rtkit/-/blob/v0.14/org.freedesktop.RealtimeKit1.conf?ref_type=tags#L15">a deny list</a> of methods which may not be
invoked by non-root users. This is not ideal, since additional methods will
automatically be accessible to all users in the system, should a developer
forget to update the deny list. At the moment no problems exist in this area,
however.</p>

<p>The blacklisted D-Bus methods which are only accessible to <code class="language-plaintext highlighter-rouge">root</code> affect the
global state of the daemon. The remaining D-Bus methods are used to request
real-time scheduling for caller-owned processes. These methods are
additionally protected by Polkit authentication; the related Polkit actions
are set to <code class="language-plaintext highlighter-rouge">yes</code> for local users in an active session, meaning that local
interactive users can invoke them without authentication.</p>

<p>The <a href="https://gitlab.freedesktop.org/pipewire/rtkit/-/blob/v0.14/rtkit-daemon.c?ref_type=tags#L1261">implementation of Polkit authentication</a> relies on
rather complex custom code based on the “unix-process” Polkit authentication
subject. This subject is often affected by race conditions and the D-Bus
“system-bus-name” subject should rather be used. In this case the use of
“unix-process” is acceptable, since the request includes not only the client’s
PID but also its process start time and UID, which is retrieved from the UNIX
domain socket D-Bus connection. Thus there should be no way that race
conditions can be exploited in a way that the client is mistaken for <code class="language-plaintext highlighter-rouge">root</code>,
for example.</p>

<p>The actual application of real-time scheduling to a client’s target
process is highly affected by race conditions, due to the retrieval of data
from <code class="language-plaintext highlighter-rouge">/proc/&lt;pid&gt;</code> and the fact that processes can disappear and/or be
repurposed at any time. The developers are obviously aware of the potential
issues, since they verify the target process’s properties <a href="https://gitlab.freedesktop.org/pipewire/rtkit/-/blob/v0.14/rtkit-daemon.c?ref_type=tags#L763">before and after
changing its scheduling properties</a>. Such detection
of a race condition after the fact is problematic when the risk is a lockup of
the whole system.</p>

<p>Due to this, the daemon also maintains <a href="https://gitlab.freedesktop.org/pipewire/rtkit/-/blob/v0.14/rtkit-daemon.c?ref_type=tags#L1973">a watchdog and a canary
thread</a> to counteract any unexpected effects of
unprivileged real-time scheduling. The watchdog runs at the highest real-time
scheduling priority and periodically monitors whether the canary thread, which
is running with low scheduling priority, is still being scheduled. If a stall
is detected, then the watchdog thread removes the real-time scheduling
settings from all registered client tasks to recover the system. Additionally
the daemon monitors the amount of requests individual users are sending,
and blocks them if a threshold is exceeded.</p>

<p>It is clear that the implementation of this service is confronted with various
uncertainties and it tries to make up for them. The overall result is not
ideal but should be good enough to prevent major security issues. An
improvement to the design could be to obtain a directory file descriptor for
<code class="language-plaintext highlighter-rouge">/proc/&lt;pid&gt;</code> of the target process, verify the process’s credentials and
further on only use the directory file descriptor anymore for accessing
process data. Explicit PID file descriptors might also help in some other
spots these days (they can also be used for authentication with Polkit now,
for example).</p>

<h1 id="section-steamos">8) SteamOS Package Additions</h1>

<p>There is continued effort by community packagers to bring SteamOS-related
components to openSUSE. We already covered <a href="/2025/10/01/summer-spotlight.html#10-steam-powerbuttond-insecure-operation-in-home-directories">one of these
components</a> in one of last year’s spotlight posts.
This winter we received three additional review requests in this area.
Packaging these components is often difficult, because the programs use
fixed non-standard paths and approaches that don’t fit well into a
general-purpose Linux distribution. We will look into the individual packages
in the following sub-sections.</p>

<h2 id="jupiter-fan-control">jupiter-fan-control</h2>

<p>This <a href="https://bugzilla.suse.com/show_bug.cgi?id=1256004">review</a> is about a fan control daemon which
regulates the speed of the Steam Deck fan. The daemon itself is acceptable, it
mostly deals with hardware information and controls found in <code class="language-plaintext highlighter-rouge">/sys</code> and
therefore it crosses no security boundaries. It also creates a world-readable
logfile in <code class="language-plaintext highlighter-rouge">/var/log</code>, which only contains fan data, however, thus not
resulting in a relevant information leak towards unprivileged users.</p>

<p>A Polkit action allows to start and stop the daemon by providing the
administrator password, which is also fine. A wrapper script which performs
these start/stop actions is placed into
<code class="language-plaintext highlighter-rouge">/usr/bin/steamos-polkit-helpers/jupiter-fan-control</code>, which is a non-standard
location, but according to the packager is hard-coded into SteamOS components
and cannot be changed.</p>

<h2 id="gamescope-session-steam-factory-reset">gamescope-session-steam-factory-reset</h2>

<p><a href="https://bugzilla.suse.com/show_bug.cgi?id=1257125">This review</a> is concerned with a set of scripts
which allow to perform a factory reset operation on SteamOS. On openSUSE there
is nothing sensible that can be done in terms of a factory reset, thus the
packager added scripts that are in effect no-ops. Still these scripts were
supposed to be invoked with root privileges via Polkit authentication.
After a longer discussion with the maintainer we decided to take a different
approach that does not require to run dummy scripts with root privileges, but
still allows system integrators to hook into the process and change the
behaviour.</p>

<h2 id="jupiter-hw-support">jupiter-hw-support</h2>

<p><a href="https://bugzilla.suse.com/show_bug.cgi?id=1257533">The third review</a> is concerned with a bunch of SteamOS
scripts that automatically perform actions like mounting removable devices
without requiring authentication, expecting a single “deck” interactive user
in the system. The community packager discussed some aspects of these
privileged operations with us and how to best integrate them into openSUSE.
The effort is still ongoing.</p>

<h1 id="section-deepin">9) Revisit of Deepin Desktop D-Bus Services after Removal from openSUSE</h1>

<p>A year ago we announced <a href="/2025/05/07/deepin-desktop-removal.html">the removal of Deepin desktop
components</a> from openSUSE because of policy violations and bad
security. Deepin upstream promised to improve the problematic components and
we offered to have a fresh look at things when they would have something new
to show. As a result <a href="https://bugzilla.suse.com/show_bug.cgi?id=1254493">a follow-up review bug</a> was created in
which the Deepin package maintainer claimed that all reported security issues
were fixed by upstream. The following sections discuss two of the D-Bus
components we revisited in this context.</p>

<h2 id="backlight-helper">Backlight Helper</h2>

<p>A small D-Bus helper for <a href="https://bugzilla.suse.com/show_bug.cgi?id=1257149">controlling laptop backlight</a>
seemed like a promising start; the code is clean and conservative. It is
lacking Polkit authentication, however, which means that any user in the
system can meddle with the backlight. Such settings are usually restricted to
local interactive users in an active session. We informed upstream about this
shortcoming and there is supposed to be a fix available by now, but we didn’t
look into it yet.</p>

<h2 id="accounts-service">Accounts Service</h2>

<p>The Deepin <a href="https://bugzilla.suse.com/show_bug.cgi?id=1257142">accounts service</a> offers a larger D-Bus
interface for managing user accounts in the system. We looked into version
6.1.66 of the project. Unfortunately we quickly discovered new security issues
in this component:</p>

<ul>
  <li><a href="https://github.com/linuxdeepin/dde-daemon/blob/6.1.66/accounts1/users/guest.go#L12">the <code class="language-plaintext highlighter-rouge">CreateGuestUser()</code></a> D-Bus method, which
requires admin authentication, creates a user account with an empty password
and a home directory in a random location in <code class="language-plaintext highlighter-rouge">/tmp</code>. The creation of this
directory is affected by a race condition, which could allow other users in
the system to pre-create the directory. A home directory in <code class="language-plaintext highlighter-rouge">/tmp</code> is highly
unusual and empty passwords, even for guest accounts, are bad practice.</li>
  <li><a href="https://github.com/linuxdeepin/dde-daemon/blob/6.1.66/accounts1/user_ifc.go#L81">the <code class="language-plaintext highlighter-rouge">SetHomeDir()</code></a> D-Bus method, which requires
only user-level self-authentication, allows to move the user’s home
directory into arbitrary new locations, even <code class="language-plaintext highlighter-rouge">/root</code>. This operation is
performed via the command line <code class="language-plaintext highlighter-rouge">usermod -m -d &lt;new-home-path&gt; &lt;username&gt;</code>. The
only aspect that prevents a simple local root exploit is that <code class="language-plaintext highlighter-rouge">usermod</code>
refuses to perform the operation if the calling user still has processes
running in the system.  How this API function could ever be used meaningfully
for self-administration, then, is puzzling. It might be possible for an
attacker to overcome this check, however, by quickly killing all of its
processes just in time for the <code class="language-plaintext highlighter-rouge">usermod</code> invocation to succeed.</li>
  <li><a href="https://github.com/linuxdeepin/dde-daemon/blob/6.1.66/accounts1/user_ifc.go#L147">the <code class="language-plaintext highlighter-rouge">SetPassword()</code></a> D-Bus method, again
accessible by providing the user password, is affected by multiple issues:
    <ul>
      <li>the new user password is leaked in the process command line constructed in
<a href="https://github.com/linuxdeepin/dde-daemon/blob/6.1.66/accounts1/users/prop.go#L178"><code class="language-plaintext highlighter-rouge">ModifyPasswd()</code></a>.</li>
      <li>the function <a href="https://github.com/linuxdeepin/dde-daemon/blob/6.1.66/accounts1/user_chpwd_union_id.go#L690"><code class="language-plaintext highlighter-rouge">removeLoginKeyring()</code></a>
which is invoked in this context operates as <code class="language-plaintext highlighter-rouge">root</code> in the user’s home
directory, offering local Denial-of-Service attack surface.</li>
      <li><a href="https://github.com/linuxdeepin/dde-daemon/blob/6.1.66/accounts1/user_chpwd_union_id.go#L119">an insufficient check</a> is made by the D-Bus
service, which tries to verify whether the client is running a trusted
password change application. The check is affected by a race condition and
can be circumvented by malicious clients.</li>
      <li>the function <a href="https://github.com/linuxdeepin/dde-daemon/blob/6.1.66/accounts1/user_chpwd_union_id.go#L530"><code class="language-plaintext highlighter-rouge">newPwdChangerX()</code></a> performs a
<code class="language-plaintext highlighter-rouge">chown()</code> on the client’s <code class="language-plaintext highlighter-rouge">.XAuthority</code> file placed into
<code class="language-plaintext highlighter-rouge">/run/user/&lt;uid&gt;/.XAuthority</code>, which is a local root exploit attack vector.</li>
    </ul>
  </li>
</ul>

<p>The openSUSE Deepin packager informed us that there are also fixes for these
issues available by now, but we did not get around to verify them yet.</p>

<h2 id="summary">Summary</h2>

<p>Due to the recurring number of security issues, the amount of time
required by upstream to address them and a lack of a formal security fix
workflow in the Deepin project we stopped assigning CVEs for the issues we
find in Deepin. We don’t see much value in further CVEs since the security
issues are often quickly replaced by other security issues, thus resulting
mostly in noise. Overall we don’t recommend to use Deepin components until
the security culture of Deepin upstream improves.</p>

<p>By now we are also treating Deepin review requests with lower priority, since
the efforts which went on for years still haven’t yielded acceptable results
and we would rather invest our resources into other, more promising packages.</p>

<h1 id="10-conclusion">10) Conclusion</h1>

<p>One of the fundamental goals of the SUSE Security Team is to keep a high
standard regarding software available in SUSE distributions. Not blindly
accepting new software releases is necessary to uphold this commitment, which
also means often revisiting software we already looked into before.</p>

<p>Keeping up with the fast pace of projects like systemd can be challenging in
this regard, but the security issues we continue to find e.g. in Deepin
software show that this work is still useful. The Spotlight series is one way
to highlight this continuous and not always necessarily glamorous work.</p>]]></content><author><name>&lt;a href=&apos;mailto:matthias.gerstner@suse.de&apos;&gt;Matthias Gerstner&lt;/a&gt;, &lt;a href=&apos;mailto:filippo.bonazzi@suse.com&apos;&gt;Filippo Bonazzi (editor)&lt;/a&gt;</name></author><category term="spotlight" /><summary type="html"><![CDATA[This is the winter 2025/2026 edition of our spotlight series. This time we will discuss, among others, a review of the libpgpr signature parsing library, the rtkit realtime scheduling service and an attempt at bringing Deepin desktop components back to openSUSE.]]></summary></entry><entry><title type="html">cosmic-greeter: Unsafe File System Operations in User Home Directories (CVE-2026-25704)</title><link href="https://security.opensuse.org/2026/04/16/cosmic-greeter.html" rel="alternate" type="text/html" title="cosmic-greeter: Unsafe File System Operations in User Home Directories (CVE-2026-25704)" /><published>2026-04-16T00:00:00+00:00</published><updated>2026-04-16T00:00:00+00:00</updated><id>https://security.opensuse.org/2026/04/16/cosmic-greeter</id><content type="html" xml:base="https://security.opensuse.org/2026/04/16/cosmic-greeter.html"><![CDATA[<h1 class="no_toc" id="table-of-contents">Table of Contents</h1>

<ul id="markdown-toc">
  <li><a href="#introduction" id="markdown-toc-introduction">Introduction</a></li>
  <li><a href="#overview" id="markdown-toc-overview">Overview</a></li>
  <li><a href="#security-issues" id="markdown-toc-security-issues">Security Issues</a></li>
  <li><a href="#suggested-fixes" id="markdown-toc-suggested-fixes">Suggested Fixes</a></li>
  <li><a href="#upstream-bugfix" id="markdown-toc-upstream-bugfix">Upstream Bugfix</a></li>
  <li><a href="#cve-assignment" id="markdown-toc-cve-assignment">CVE Assignment</a></li>
  <li><a href="#timeline" id="markdown-toc-timeline">Timeline</a></li>
  <li><a href="#references" id="markdown-toc-references">References</a></li>
</ul>

<h1 id="introduction">Introduction</h1>

<p>Cosmic is <a href="https://system76.com/cosmic">a Linux desktop environment</a> written in the Rust
programming language. There is an ongoing effort to package it for openSUSE
Tumbleweed; in this context we reviewed a number of Cosmic components, among
them <a href="https://bugzilla.suse.com/show_bug.cgi?id=1259401">a D-Bus service</a> found in
<a href="https://github.com/pop-os/cosmic-greeter">cosmic-greeter</a>.  We found issues when the service
accesses home directories of unprivileged users, which will be described
further below. This report is based on cosmic-greeter version 1.0.8.</p>

<h1 id="overview">Overview</h1>

<p><code class="language-plaintext highlighter-rouge">cosmic-greeter-daemon</code> is implemented in
<a href="https://github.com/pop-os/cosmic-greeter/blob/epoch-1.0.8/daemon/src/main.rs">daemon/src/main.rs</a>, runs with full root privileges
and offers a D-Bus interface “com.system76.CosmicGreeter” on the D-Bus system
bus. The interface only provides a single D-Bus method
“com.system76.CosmicGreeter.GetUserData”.</p>

<p>This D-Bus method is only allowed to be called by members of the
<code class="language-plaintext highlighter-rouge">cosmic-greeter</code> group, not by arbitrary other unprivileged users. What the
<a href="https://github.com/pop-os/cosmic-greeter/blob/epoch-1.0.8/daemon/src/main.rs#L62">method does</a> is basically looking up all
non-system user accounts in <code class="language-plaintext highlighter-rouge">/etc/passwd</code> and gathering Cosmic configuration
data from every user’s home directory.</p>

<h1 id="security-issues">Security Issues</h1>

<p>The code contains <a href="https://github.com/pop-os/cosmic-greeter/blob/epoch-1.0.8/daemon/src/main.rs#L9">a comment</a>, outlining that it
is important to drop privileges to the owner of the home directory
being processed, to prevent security issues. While this is a good starting
point, the actual implementation of this logic is still lacking in a number of
spots.</p>

<p>Following is an excerpt of an <code class="language-plaintext highlighter-rouge">strace</code> of the <code class="language-plaintext highlighter-rouge">cosmic-greeter-daemon</code> process
during invocation of the D-Bus method. The output will help illustrate some of
the issues in question:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>setresuid<span class="o">(</span><span class="nt">-1</span>, 1000, <span class="nt">-1</span><span class="o">)</span> <span class="o">=</span> 0
&lt;...&gt;
statx<span class="o">(</span>AT_FDCWD, <span class="s2">"/var/lib/AccountsService/icons/&lt;user&gt;"</span>, AT_STATX_SYNC_AS_STAT, STATX_ALL, 0x7feb5d5f8a50<span class="o">)</span> <span class="o">=</span> <span class="nt">-1</span> ENOENT <span class="o">(</span>No such file or directory<span class="o">)</span>
statx<span class="o">(</span>AT_FDCWD, <span class="s2">"/home/&lt;user&gt;/.local/share/cosmic/com.system76.CosmicTheme.Mode/v1"</span>, AT_STATX_SYNC_AS_STAT, STATX_ALL, 0x7feb5d5f8800<span class="o">)</span> <span class="o">=</span> <span class="nt">-1</span> ENOENT <span class="o">(</span>No such file or directory<span class="o">)</span>
<span class="nb">mkdir</span><span class="o">(</span><span class="s2">"/home/&lt;user&gt;/.config/cosmic/com.system76.CosmicTheme.Mode/v1"</span>, 0777<span class="o">)</span> <span class="o">=</span> <span class="nt">-1</span> EEXIST <span class="o">(</span>File exists<span class="o">)</span>
statx<span class="o">(</span>AT_FDCWD, <span class="s2">"/home/&lt;user&gt;/.config/cosmic/com.system76.CosmicTheme.Mode/v1"</span>, AT_STATX_SYNC_AS_STAT, STATX_ALL, <span class="o">{</span><span class="nv">stx_mask</span><span class="o">=</span>STATX_ALL|STATX_MNT_ID, <span class="nv">stx_attributes</span><span class="o">=</span>0, <span class="nv">stx_mode</span><span class="o">=</span>S_IFDIR|0755, <span class="nv">stx_size</span><span class="o">=</span>4096, ...<span class="o">})</span> <span class="o">=</span> 0
statx<span class="o">(</span>AT_FDCWD, <span class="s2">"/home/&lt;user&gt;/.config/cosmic/com.system76.CosmicTheme.Mode/v1/is_dark"</span>, AT_STATX_SYNC_AS_STAT, STATX_ALL, <span class="o">{</span><span class="nv">stx_mask</span><span class="o">=</span>STATX_ALL|STATX_MNT_ID, <span class="nv">stx_attributes</span><span class="o">=</span>0, <span class="nv">stx_mode</span><span class="o">=</span>S_IFCHR|0666, <span class="nv">stx_size</span><span class="o">=</span>0, ...<span class="o">})</span> <span class="o">=</span> 0
<span class="nb">mkdir</span><span class="o">(</span><span class="s2">"/home/&lt;user&gt;/.config/cosmic/com.system76.CosmicTheme.Dark/v1"</span>, 0777<span class="o">)</span> <span class="o">=</span> <span class="nt">-1</span> EEXIST <span class="o">(</span>File exists<span class="o">)</span>
openat<span class="o">(</span>AT_FDCWD, <span class="s2">"/home/&lt;user&gt;/.config/cosmic/com.system76.CosmicTheme.Dark/v1/palette"</span>, O_RDONLY|O_CLOEXEC<span class="o">)</span> <span class="o">=</span> 11
&lt;...&gt;
setresuid<span class="o">(</span><span class="nt">-1</span>, 0, <span class="nt">-1</span> &lt;unfinished ...&gt;
</code></pre></div></div>

<p>What we are seeing here is that the privilege drop only concerns the effective
user ID of the <code class="language-plaintext highlighter-rouge">cosmic-greeter-daemon</code> process. The root group credentials are
retained. This means any potential attacks by the owner of a home directory
can still try to leverage root group credentials to their advantage.</p>

<p>Given this, the file operations performed in the user’s home directory are
subject to a range of security issues:</p>

<ul>
  <li>
    <p>directory components within the path can be replaced by symbolic
links. E.g. if a user places a symlink like this:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$HOME/.config/cosmic → /root/.config/cosmic
</code></pre></div>    </div>

    <p>then the daemon would actually process root’s Cosmic configuration files,
provided that root’s home directory is accessible for members of the root
group.</p>
  </li>
  <li>since the daemon also attempts to create directories under some conditions,
these directories could be created in arbitrary locations where the root
group has write permission.</li>
  <li>the daemon checks the type of files via <code class="language-plaintext highlighter-rouge">stat()</code> before trying to open
configuration files, for example. This is a typical
Time-of-Check/Time-of-Use (TOCTOU) race condition, however, because the owner
of the home directory can attempt to replace a regular file by a symbolic link
or special file by the time the actual <code class="language-plaintext highlighter-rouge">open()</code> call is performed by the
daemon. This can lead to the following potential issues:
    <ul>
      <li>parsing of private files accessible to the root group.
Whether the data parsed from such files could ever leak into the
context of a local attacker is a matter that we did not investigate
more closely for the purpose of this report.</li>
      <li>by placing a symbolic link to e.g. <code class="language-plaintext highlighter-rouge">/dev/zero</code>, an out-of-memory situation
can be triggered in the daemon, causing it to be killed by the kernel,
leading to a local Denial-of-Service (DoS).</li>
      <li>by placing a FIFO named pipe in the location the daemon would block
on it forever, also leading to a local DoS.</li>
    </ul>
  </li>
  <li>the daemon considers accounts with user IDs ≥ 1000 <a href="https://github.com/pop-os/cosmic-greeter/blob/epoch-1.0.8/daemon/src/main.rs#L65">as regular user
accounts</a>. On many Linux distributions
this means that also the <code class="language-plaintext highlighter-rouge">nobody</code> user account is included (UID 65534). As a
result, the daemon also attempts to process Cosmic configuration in
        <code class="language-plaintext highlighter-rouge">/var/lib/nobody</code> on openSUSE.
This grants processes operating with <code class="language-plaintext highlighter-rouge">nobody</code> privileges the opportunity to
attempt to exploit the daemon’s logic.</li>
</ul>

<p>The severity of these issues is reduced by the fact that only members of the
<code class="language-plaintext highlighter-rouge">cosmic-greeter</code> group are allowed to invoke the <code class="language-plaintext highlighter-rouge">GetUserData</code> D-Bus method,
thus potential attackers have to wait for an authorized process to call the
function to attempt to exploit it. We don’t have enough insight into the
bigger picture of the Cosmic desktop environment, but it could be possible
that local users are able to indirectly trigger the execution of this D-Bus
method by using other APIs made available by Cosmic.</p>

<h1 id="suggested-fixes">Suggested Fixes</h1>

<p>We suggested the following improvements to upstream to deal with the issues:</p>

<ul>
  <li>the privileges should be fully dropped to the target user account, including
group ID and the supplementary group IDs.</li>
  <li>to prevent potential DoS attack surface, the daemon should carefully
open target paths element by element, passing <code class="language-plaintext highlighter-rouge">O_NOFOLLOW|O_NONBLOCK</code>
to prevent symlink attacks, then perform an <code class="language-plaintext highlighter-rouge">fstat()</code> on the open file
to determine its type in a race-free fashion.</li>
  <li>the <code class="language-plaintext highlighter-rouge">nobody</code> user account should be explicitly excluded based on its name
for distributions that set a valid shell for this account.</li>
  <li>as additional hardening, the systemd unit <code class="language-plaintext highlighter-rouge">cosmic-greeter-daemon.service</code> can
be extended with directives like <code class="language-plaintext highlighter-rouge">ProtectSystem=full</code>. This needs some tuning,
though, since the daemon still needs to be able to read files in home
directories of other users.</li>
</ul>

<h1 id="upstream-bugfix">Upstream Bugfix</h1>

<p>Upstream implemented <a href="https://github.com/pop-os/cosmic-greeter/commit/63cd93bddd01bf714e98553966d4da12eac0ee5b">commit 63cd93bddd0</a>
containing the following changes:</p>

<ul>
  <li>the daemon properly drops its group and supplementary group IDs to the
target user’s.</li>
  <li>only user IDs in the range defined by <code class="language-plaintext highlighter-rouge">UID_MIN</code> and <code class="language-plaintext highlighter-rouge">UID_MAX</code> as configured
in <code class="language-plaintext highlighter-rouge">/etc/login.defs</code> will be considered.</li>
  <li>icon files in <code class="language-plaintext highlighter-rouge">/var/lib/accountservice</code> will be opened with <code class="language-plaintext highlighter-rouge">O_NOFOLLOW</code>
(actually an unrelated change / security hardening).</li>
</ul>

<p>This bugfix is part of <a href="https://github.com/pop-os/cosmic-greeter/releases/tag/epoch-1.0.9">upstream release 1.0.9</a> and
newer.</p>

<p>What is still missing from our point of view is the prevention of local DoS
attack surface when accessing files in the user’s home directory. We informed
upstream about this but have not heard back about this topic for a while.</p>

<h1 id="cve-assignment">CVE Assignment</h1>

<p>Upstream has not expressed any wishes regarding CVE assignment, or whether one
should be assigned at all. We decided to assign a single CVE-2026-25704 from
our pool to track the main aspect of this report, the incomplete privilege
drop in the daemon.</p>

<h1 id="timeline">Timeline</h1>

<table>
  <tbody>
    <tr>
      <td>2026-03-11</td>
      <td>We forwarded this report to security@system76.com and the main developer of cosmic-greeter, offering coordinated disclosure.</td>
    </tr>
    <tr>
      <td>2026-03-11</td>
      <td>Upstream confirmed the issue and opted out of coordinated disclosure.</td>
    </tr>
    <tr>
      <td>2026-03-11</td>
      <td>We got a follow-up response asking us to keep the information private for while longer after all.</td>
    </tr>
    <tr>
      <td>2026-03-11</td>
      <td>We received a patch from upstream corresponding to <a href="https://github.com/pop-os/cosmic-greeter/commit/63cd93bddd01bf714e98553966d4da12eac0ee5b">commit 63cd93bddd0</a> and have been asked to review it.</td>
    </tr>
    <tr>
      <td>2026-03-12</td>
      <td>Upstream meanwhile created a public pull request based on this bugfix and informed us that the report no longer needed to be private.</td>
    </tr>
    <tr>
      <td>2026-03-13</td>
      <td>We assigned CVE-2026-25704 to track the main aspect of the vulnerability, an incomplete privilege drop.</td>
    </tr>
    <tr>
      <td>2026-03-13</td>
      <td>We shared the CVE with upstream and provided feedback on the bugfix, mainly pointing out that local Denial-of-Service (DoS) attack service still remains.</td>
    </tr>
    <tr>
      <td>2026-03-13</td>
      <td>Upstream informed us that they are going to address these remaining issues as well.</td>
    </tr>
    <tr>
      <td>2026-03-24</td>
      <td>We asked upstream about the status of the additional fixes, but received no response so far.</td>
    </tr>
    <tr>
      <td>2026-04-16</td>
      <td>Publication of this report.</td>
    </tr>
  </tbody>
</table>

<h1 id="references">References</h1>

<ul>
  <li><a href="https://system76.com/cosmic">Cosmic Website</a></li>
  <li><a href="https://bugzilla.suse.com/show_bug.cgi?id=1259401">openSUSE cosmic-greeter review bug</a></li>
  <li><a href="https://github.com/pop-os/cosmic-greeter/commit/63cd93bddd01bf714e98553966d4da12eac0ee5b">cosmic-greeter privilege drop bugfix</a></li>
  <li><a href="https://github.com/pop-os/cosmic-greeter/releases/tag/epoch-1.0.9">Upstream Release 1.0.9 containing the bugfix</a></li>
</ul>]]></content><author><name>&lt;a href=&apos;mailto:matthias.gerstner@suse.de&apos;&gt;Matthias Gerstner&lt;/a&gt;, &lt;a href=&apos;mailto:filippo.bonazzi@suse.com&apos;&gt;Filippo Bonazzi (editor)&lt;/a&gt;</name></author><category term="CVE" /><category term="D-Bus" /><summary type="html"><![CDATA[Cosmic is a modern Linux desktop environment implemented in Rust. One of its components, cosmic-greeter, contains a D-Bus service which operates in user home directories in an unsafe manner, leading to potential privilege escalation or local Denial-of-Service.]]></summary></entry><entry><title type="html">The Journey of auditing UYUNI</title><link href="https://security.opensuse.org/2026/01/16/the-journey-of-auditing-uyuni.html" rel="alternate" type="text/html" title="The Journey of auditing UYUNI" /><published>2026-01-16T00:00:00+00:00</published><updated>2026-01-16T00:00:00+00:00</updated><id>https://security.opensuse.org/2026/01/16/the-journey-of-auditing-uyuni</id><content type="html" xml:base="https://security.opensuse.org/2026/01/16/the-journey-of-auditing-uyuni.html"><![CDATA[<h1 class="no_toc" id="table-of-contents">Table of Contents</h1>

<ul id="markdown-toc">
  <li><a href="#1-introduction" id="markdown-toc-1-introduction">1) Introduction</a></li>
  <li><a href="#2-the-methodology" id="markdown-toc-2-the-methodology">2) The methodology</a>    <ul>
      <li><a href="#some-numbers-about-the-codebase" id="markdown-toc-some-numbers-about-the-codebase">Some numbers about the codebase</a></li>
      <li><a href="#the-activity-tracking" id="markdown-toc-the-activity-tracking">The activity tracking</a></li>
      <li><a href="#the-setup" id="markdown-toc-the-setup">The setup</a></li>
      <li><a href="#the-attackers-corner" id="markdown-toc-the-attackers-corner">The attacker’s corner</a></li>
      <li><a href="#the-reporting-method" id="markdown-toc-the-reporting-method">The reporting method</a></li>
    </ul>
  </li>
  <li><a href="#3-audit-results" id="markdown-toc-3-audit-results">3) Audit results</a>    <ul>
      <li><a href="#cve-2024-49502-spacewalk-web-reflected-xss-in-setup-wizard-http-proxy-credentials-pane" id="markdown-toc-cve-2024-49502-spacewalk-web-reflected-xss-in-setup-wizard-http-proxy-credentials-pane">CVE-2024-49502: spacewalk-web: Reflected XSS in Setup Wizard, HTTP Proxy credentials pane</a></li>
      <li><a href="#cve-2024-49503-spacewalk-web-reflected-xss-in-setup-wizard-organization-credentials" id="markdown-toc-cve-2024-49503-spacewalk-web-reflected-xss-in-setup-wizard-organization-credentials">CVE-2024-49503: spacewalk-web: Reflected XSS in Setup Wizard, Organization Credentials</a></li>
      <li><a href="#cve-2025-23392-spacewalk-java-reflected-xss-in-systemscontrollerjava" id="markdown-toc-cve-2025-23392-spacewalk-java-reflected-xss-in-systemscontrollerjava">CVE-2025-23392: spacewalk-java: reflected XSS in SystemsController.java</a></li>
      <li><a href="#cve-2025-46809-plain-text-http-proxy-userpassword-in-repolog-accessible-from-the-uyuni-5x-webui" id="markdown-toc-cve-2025-46809-plain-text-http-proxy-userpassword-in-repolog-accessible-from-the-uyuni-5x-webui">CVE-2025-46809: Plain text HTTP Proxy user:password in repolog accessible from the UYUNI 5.x webUI</a></li>
      <li><a href="#cve-2025-46811-unprotected-websocket-endpoint" id="markdown-toc-cve-2025-46811-unprotected-websocket-endpoint">CVE-2025-46811: Unprotected websocket endpoint</a></li>
      <li><a href="#cve-2025-53883-spacewalk-java-various-xss-found-on-search-page" id="markdown-toc-cve-2025-53883-spacewalk-java-various-xss-found-on-search-page">CVE-2025-53883: spacewalk-java: various XSS found on search page</a></li>
      <li><a href="#cve-2025-53880-susemanager-tftpsync-recv-arbitrary-file-creation-and-deletion-due-to-path-traversal" id="markdown-toc-cve-2025-53880-susemanager-tftpsync-recv-arbitrary-file-creation-and-deletion-due-to-path-traversal">CVE-2025-53880: susemanager-tftpsync-recv: arbitrary file creation and deletion due to path traversal</a></li>
      <li><a href="#other-minor-findings" id="markdown-toc-other-minor-findings">Other minor findings</a></li>
    </ul>
  </li>
  <li><a href="#4-conclusions" id="markdown-toc-4-conclusions">4) Conclusions</a></li>
  <li><a href="#5-whats-next" id="markdown-toc-5-whats-next">5) What’s next?</a></li>
  <li><a href="#6-links" id="markdown-toc-6-links">6) Links</a></li>
</ul>

<h1 id="1-introduction">1) Introduction</h1>

<p><a href="https://github.com/uyuni-project/uyuni">UYUNI</a> is an open source system management solution, forked from <a href="https://spacewalkproject.github.io/">Spacewalk</a> and upstream community project from which <a href="https://www.suse.com/products/multi-linux-manager/">SUSE Multi-Linux Manager</a> is derived.</p>

<p>The audit started in January 2024 with the perimeter definition. Since it’s not feasible to audit everything, a list of packages was chosen and submitted to UYUNI product owner.
The criteria for including a package in the perimeter were:</p>
<ul>
  <li>the package implementing UYUNI web UI</li>
  <li>the package implementing API or websocket layer</li>
  <li>the package implementing UYUNI backend</li>
  <li>the <code class="language-plaintext highlighter-rouge">salt</code> package (fundamental for UYUNI server and minions interaction)</li>
  <li>packages not included in previous UYUNI audits</li>
</ul>

<p>In March 2024 the code scanning activities effectively started.</p>

<p><a name="section-methodology"></a></p>

<h1 id="2-the-methodology">2) The methodology</h1>

<p>Auditing a complex codebase like UYUNI is not just running a static analysis tool and waiting for it to complete. It is a
complex and long-running journey that took one year and a half to complete.</p>

<h2 id="some-numbers-about-the-codebase">Some numbers about the codebase</h2>

<p>The codebase is big with a lot of sub-packages. Each sub-package was treated as a standalone audit with its own Bugzilla bug, its own list of affected vulnerabilities and its own report. 
The final report was produced by combining the reports of all sub-packages.</p>

<p>The audited codebase is more than 4.5 millions lines of code, with at least 7 different programming languages.</p>

<table>
  <thead>
    <tr>
      <th>Language</th>
      <th style="text-align: right">Files</th>
      <th style="text-align: right">Lines of code</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>JavaScript</td>
      <td style="text-align: right">2547</td>
      <td style="text-align: right">3805282</td>
    </tr>
    <tr>
      <td>Java</td>
      <td style="text-align: right">4052</td>
      <td style="text-align: right">369100</td>
    </tr>
    <tr>
      <td>Go</td>
      <td style="text-align: right">795</td>
      <td style="text-align: right">250684</td>
    </tr>
    <tr>
      <td>Python</td>
      <td style="text-align: right">407</td>
      <td style="text-align: right">103965</td>
    </tr>
    <tr>
      <td>JSP</td>
      <td style="text-align: right">641</td>
      <td style="text-align: right">36861</td>
    </tr>
    <tr>
      <td>Shell</td>
      <td style="text-align: right">86</td>
      <td style="text-align: right">6744</td>
    </tr>
    <tr>
      <td>Perl</td>
      <td style="text-align: right">65</td>
      <td style="text-align: right">6070</td>
    </tr>
  </tbody>
</table>

<p>As you may wonder, using a single catch-all tool to analyze such a heterogeneous codebase is not possible.</p>

<p>Every package in the scanning perimeter was audited looking at the source both using tools and by manual inspection. The running server was continuously inspected dynamically looking for low-hanging fruit like cross-site-scripting (XSS), SQL injection and similar, and for business logic flaws.</p>

<p>Each security issue was then triaged and if necessary a CVE identifier was assigned and the vulnerability put under EMBARGO. Using the
<a href="https://en.opensuse.org/openSUSE:Security_disclosure_policy">openSUSE coordinated disclosure policy</a>
as a framework, we coordinate with upstream and disclose the issue when solved.</p>

<h2 id="the-activity-tracking">The activity tracking</h2>

<p>We use Bugzilla as tracking authority for audits and vulnerabilities found during the activity. A master bug (<a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1218619">boo#1218619</a>) was created with the purpose of acting as a main container for all sub-packages audit bugs.</p>

<p>Each audit bug contains all affecting vulnerabilities and, of course, a vulnerability bug can be set as blocker to more sub-packages.</p>

<h2 id="the-setup">The setup</h2>

<p>For the activity, a set of
<a href="https://en.wikipedia.org/wiki/Kernel-based_Virtual_Machine">KVM</a>-powered machines were created:</p>

<ul>
  <li>a UYUNI server instance</li>
  <li>a UYUNI proxy instance</li>
  <li>a couple of minions, Linux workstations attached and managed centrally by the master.</li>
</ul>

<p>The server is the main UYUNI component orchestrating minions attestation and enabling system administrators to launch commands and interact with minions using the web interface.</p>

<p>A minion, in the UYUNI slang, is a Linux-powered machine (ideally it is a client in a local network), connected to the server.</p>

<p>A UYUNI proxy is a particular kind of server, used to fetch packages from software distribution channels and centrally store software packages for an efficient distribution to minions. Distribution channels are software repositories and a system administrator subscribes his own UYUNI instance to different repositories.</p>

<p>Each server was running <a href="https://microos.opensuse.org/">openSUSE MicroOS</a> as
underlying operating system and minions were running either
<a href="https://get.opensuse.org/tumbleweed/">openSUSE Tumbleweed</a> or
<a href="https://ubuntu.com/">Ubuntu</a> Linux distributions.</p>

<h2 id="the-attackers-corner">The attacker’s corner</h2>

<p>For the testing activities we used two different machines. A virtual machine running openSUSE Tumbleweed, used for source code inspection and a virtual machine running <a href="https://www.kali.org">Kali Linux</a> installed to help in penetration testing activities.</p>

<h3 id="the-tools">The tools</h3>

<p><a href="https://portswigger.net/burp/communitydownload">Burp Suite community</a> was the
main tool used trying to spot security issues in the running application.</p>

<p>To help, during the UYUNI application browsing, a custom tool was developed. While browsing the web UI trying to find business logic flaws, I felt the need for something running in the background spotting low-hanging fruit in web pages form, cookies and more.
The tool eventually became an OSS project named <a href="https://github.com/thesp0nge/nightcrawler-mitm">nightcrawler-mitm</a>. It’s a <a href="https://www.mitmproxy.org/">mitmproxy</a> extension implementing both an active and a passive scanner running several security controls in the background.</p>

<p>Also for auditing the source code, opensource tools were used.
Some of the tools used are famous OSS projects, like:</p>

<ul>
  <li><a href="https://github.com/PyCQA/bandit">bandit</a></li>
  <li><a href="https://semgrep.dev/">semgrep</a></li>
  <li><a href="https://docs.npmjs.com/cli/v8/commands/npm-audit">npm audit</a></li>
</ul>

<p>To help me during the activities, I also used some SAST tools previously written by myself, like:</p>

<ul>
  <li><a href="https://github.com/thesp0nge/dr_source">dr_source</a></li>
  <li><a href="https://github.com/thesp0nge/dawnscanner">dawnscanner</a></li>
</ul>

<h2 id="the-reporting-method">The reporting method</h2>

<p>As discussed before, every finding was tracked on a separate bugzilla bug. Each bug was linked, marking as a blocking bug, to any sub-package audit bug affected by the associated vulnerability.</p>

<p>Of course, every vulnerability was confirmed by a successful exploitation, before being added to our Bugzilla tracking system. Vulnerabilities were assigned to UYUNI developers and tracked until a fix was released. 
A CVE was also assigned if required by the issue severity.</p>

<p>The standard <a href="https://www.first.org/cvss/v4.0/">CVSS version 4</a> was used as a scoring system and to assign a severity. The rationale is that if a CVSS is lower than 5, then the severity is low, it is medium if CVSS is between 5 and 7 and high otherwise. 
The same approach was used to assign a triage score to each sub-package. The triage score will be used in the future to decide if the sub-package must be in future audit perimeter or not.</p>

<p>At the end of the audit, the list of issues and the triage score created a technical report sent to UYUNI developers.</p>

<p><a name="section-results"></a></p>

<h1 id="3-audit-results">3) Audit results</h1>

<p>During the audit, seven CVEs were found and fixed, and numerous minor issues were addressed, improving the product’s reliability and overall security posture.</p>

<h2 id="cve-2024-49502-spacewalk-web-reflected-xss-in-setup-wizard-http-proxy-credentials-pane">CVE-2024-49502: spacewalk-web: Reflected XSS in Setup Wizard, HTTP Proxy credentials pane</h2>

<p>A reflected cross-site scripting has been found in the HTTP proxy pane of the setup wizard UI element. Tracked in
<a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1231852">boo#1231852</a></p>

<h2 id="cve-2024-49503-spacewalk-web-reflected-xss-in-setup-wizard-organization-credentials">CVE-2024-49503: spacewalk-web: Reflected XSS in Setup Wizard, Organization Credentials</h2>

<p>A reflected cross-site scripting has been found in the Organization Credentials pane of the setup wizard UI element. Tracked in
<a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1231922">boo#1231922</a></p>

<h2 id="cve-2025-23392-spacewalk-java-reflected-xss-in-systemscontrollerjava">CVE-2025-23392: spacewalk-java: reflected XSS in SystemsController.java</h2>

<p>Some URLs, served by the <code class="language-plaintext highlighter-rouge">SystemsController.java</code> class are vulnerable to a reflected XSS vulnerability. Some example of vulnerable URLs are listed in the Github advisory as well. The
<a href="https://github.com/uyuni-project/uyuni/security/advisories/GHSA-v588-pf3f-jfp9">advisory</a>
was filed by an external independent researcher following
<a href="https://en.opensuse.org/openSUSE:Security_disclosure_policy">our coordinated disclosure policy</a>.
Tracked in <a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1239826">boo#1239826</a></p>

<h2 id="cve-2025-46809-plain-text-http-proxy-userpassword-in-repolog-accessible-from-the-uyuni-5x-webui">CVE-2025-46809: Plain text HTTP Proxy user:password in repolog accessible from the UYUNI 5.x webUI</h2>

<p>Credentials to be used in UYUNI HTTP proxy are disclosed in the error log in case of wrong port number or misspelled
hostname. Tracked in
<a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1245005">boo#1245005</a></p>

<h2 id="cve-2025-46811-unprotected-websocket-endpoint">CVE-2025-46811: Unprotected websocket endpoint</h2>

<p>During an internal assessment, a customer found an issue with the remote-commands websocket endpoint (<code class="language-plaintext highlighter-rouge">/rhn/websocket/minion/remote-commands</code>).
Using websockets, anyone with the ability to connect to port 443 of SUSE Manager is able to run any command as root on any client with no authentication. The customer using our coordinated disclosure policy as a reference, reported the issue which was then fixed and publicly disclosed. Tracked in
<a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1246119">boo#1246119</a></p>

<h2 id="cve-2025-53883-spacewalk-java-various-xss-found-on-search-page">CVE-2025-53883: spacewalk-java: various XSS found on search page</h2>

<p>During an internal assessment, a customer found that some reflected cross-site scriptings were possible due to improper input validation. The issue was tracked in the private SUSE bugzilla instance, since some customer sensitive information was included. However the issue is described in the public
<a href="https://www.suse.com/security/cve/CVE-2025-53883.html">CVE-2025-53883 page.</a></p>

<h2 id="cve-2025-53880-susemanager-tftpsync-recv-arbitrary-file-creation-and-deletion-due-to-path-traversal">CVE-2025-53880: susemanager-tftpsync-recv: arbitrary file creation and deletion due to path traversal</h2>

<p>A Path Traversal vulnerability in the <code class="language-plaintext highlighter-rouge">tftpsync/add</code> and <code class="language-plaintext highlighter-rouge">tftpsync/delete</code> scripts allows a remote attacker on an adjacent network to write or delete files on the filesystem with the privileges of the unprivileged <code class="language-plaintext highlighter-rouge">wwwrun</code> user. Although the endpoint is unauthenticated, access is restricted to a list of allowed IP addresses. The unprivileged user has write access to a directory that controls the provisioning of other systems, leading to a full compromise of those subsequent systems. Tracked in
<a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1246277">boo#1246277</a></p>

<h2 id="other-minor-findings">Other minor findings</h2>

<p>Additional vulnerabilities were identified that, while valid, did not meet the criteria for CVE assignment:</p>

<ul>
  <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1231900">boo#1231900</a>: VUL-0: arbitrary log messages in API can lead to a disk space exhaustion (and so to a denial of service)</li>
  <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1245740">boo#1245740</a>: VUL-0: Default venv-salt-minion environment is activated on the different user accounts</li>
  <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1243679">boo#1243679</a>: VUL-0: Insecure communication in TFTP proxy sync.</li>
  <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1243768">boo#1243768</a>: VUL-0: Potential Command InjectionPattern in check_push Function. No activity: a follow-up was requested.</li>
  <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1239636">boo#1239636</a>: VUL-0: log pollution in class TraceBackEvent</li>
  <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1237368">boo#1237368</a>: VUL-0: unhandled exception when dealing with numeric request parameters</li>
  <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1243087">boo#1243087</a>: VUL-0: spacewalk-search: unexploitable XSS in XML RPC Server.</li>
  <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1227577">boo#1227577</a>: VUL-0: spacecmd and spacewalk-backend: usage of unsafe third party library for XML.</li>
</ul>

<p>Last but not least, during the audit also some codebase improvements were suggested to raise the security posture even further:</p>

<ul>
  <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1228945">boo#1228945</a>:
AUDIT-FIND: spacewalk-utils: Sensitive information disclosure in backup file</li>
  <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1223313">boo#1223313</a>:
AUDIT-FIND: Possible deserialization issue in spacewalk-client-tools
(affecting only SUMA 4.x)</li>
  <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1228116">boo#1228116</a>:
AUDIT-FIND: spacewalk-admin: mgr-monitoring-ctl doesn’t sanitize PILLAR
parameter</li>
  <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1231983">boo#1231983</a>:
AUDIT-FIND: spacewalk-web: generatePassword() improve namespace entropy</li>
  <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1246941">boo#1246941</a>:
AUDIT-FIND: saline: Hardening Against Insecure Deserialization</li>
  <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1247015">boo#1247015</a>:
AUDIT-FIND: saline: Race Condition in Service Startup Allows for IPC Hijacking
on Systems with a Permissive umask</li>
  <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1227579">boo#1227579</a>:
AUDIT-FIND: spacecmd: get rid of pickle to read and parse configuration files.</li>
</ul>

<p><a name="section-conclusions"></a></p>

<h1 id="4-conclusions">4) Conclusions</h1>

<p>The UYUNI audit was an intense and rewarding run. The good results in term of number of found vulnerabilities and the fast reaction to release the fixes, confirmed UYUNI as a solid and reliable product for the community.</p>

<p>As all software, of course it can be improved in terms of code quality by applying safe coding patterns, using secure and reliable third-party libraries and consolidating the usage of one or two programming languages. This is an important step, because it creates a common ground for engineers and a solid codebase for the community to entice contributions and pull requests.</p>

<p>A vibrant codebase, using a balanced mix between standard and cutting edge technologies can increase adoption of the product and it can attract developers and contributors.</p>

<p>It also helps in adopting safe coding best practices that are widely updated and developed for newer technologies rather than ancient and not actively used programming languages.</p>

<p>The low number of vulnerabilities found, and the reaction time in fixing the serious ones, indicate that the project is well-curated and actively maintained. The  security posture is good and it can be safely deployed in production.</p>

<p><a name="section-next"></a></p>

<h1 id="5-whats-next">5) What’s next?</h1>

<p>Like every journey, the final destination is not the reward itself. The UYUNI project is actively under development with a monthly (more or less) release cycle.</p>

<p>The next audit will start in the first quarter of 2026 and it will be another one year and a half rollercoaster ride, with rabbit holes, false positives, suspected CVEs turning out to be not exploitable and real <em>root dance</em> issues.</p>

<p>The fun part is to audit code written in multiple languages, with different stacks and libraries.</p>

<p>It’s not rewarding only from a security perspective, it’s
a real learning experience.</p>

<p><a name="section-links"></a></p>

<h1 id="6-links">6) Links</h1>

<ul>
  <li>The <a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1218619">master Bugzilla bug</a>.</li>
  <li>The <a href="https://www.uyuni-project.org/pages/stable-version.html">latest stable version 2025.10 of UYUNI</a> containing all the relevant fixes.</li>
  <li>The <a href="https://github.com/thesp0nge/nightcrawler-mitm">nightcrawler-mitm</a> tool, written to actively and passively scan the web application in the background.</li>
  <li>The <a href="https://github.com/thesp0nge/dr_source">dr_source</a> tool, written as a SAST companion tool mainly for Java but improved with support for other programming languages.</li>
  <li><a href="https://github.com/uyuni-project/uyuni">The UYUNI source code on Github</a></li>
  <li><a href="https://en.opensuse.org/openSUSE:Security_disclosure_policy">The openSUSE coordinated disclosure policy</a></li>
</ul>]]></content><author><name>&lt;a href=&apos;mailto:paolo.perego@suse.de&apos;&gt;Paolo Perego&lt;/a&gt;, &lt;a href=&apos;mailto:filippo.bonazzi@suse.com&apos;&gt;Filippo Bonazzi (editor)&lt;/a&gt;</name></author><category term="UYUNI" /><category term="audit" /><category term="pentest" /><category term="cve" /><category term="web-pentest" /><summary type="html"><![CDATA[UYUNI is software designed to help system administrators manage a heterogeneous data center full of Linux servers. Auditing such a large piece of software is a long-running journey with ups and downs. Let's explore the process that led us to discover a number of CVEs.]]></summary></entry><entry><title type="html">SUSE Security Team Spotlight Autumn 2025</title><link href="https://security.opensuse.org/2026/01/14/autumn-spotlight.html" rel="alternate" type="text/html" title="SUSE Security Team Spotlight Autumn 2025" /><published>2026-01-14T00:00:00+00:00</published><updated>2026-01-14T00:00:00+00:00</updated><id>https://security.opensuse.org/2026/01/14/autumn-spotlight</id><content type="html" xml:base="https://security.opensuse.org/2026/01/14/autumn-spotlight.html"><![CDATA[<h1 class="no_toc" id="table-of-contents">Table of Contents</h1>

<ul id="markdown-toc">
  <li><a href="#1-introduction" id="markdown-toc-1-introduction">1) Introduction</a></li>
  <li><a href="#section-systemd" id="markdown-toc-section-systemd">2) Completion of <code class="language-plaintext highlighter-rouge">systemd</code> v258 Code Review</a></li>
  <li><a href="#section-plasma-setup" id="markdown-toc-section-plasma-setup">3) D-Bus Issues in Unreleased <code class="language-plaintext highlighter-rouge">plasma-setup</code> KDE Package</a>    <ul>
      <li><a href="#sub-section-autostarthook" id="markdown-toc-sub-section-autostarthook">org.kde.initialsystemsetup.createnewuserautostarthook</a></li>
      <li><a href="#orgkdeinitialsystemsetupsetnewuserhomedirectoryownership" id="markdown-toc-orgkdeinitialsystemsetupsetnewuserhomedirectoryownership">org.kde.initialsystemsetup.setnewuserhomedirectoryownership</a></li>
      <li><a href="#orgkdeinitialsystemsetupsetnewusertempautologin" id="markdown-toc-orgkdeinitialsystemsetupsetnewusertempautologin">org.kde.initialsystemsetup.setnewusertempautologin</a></li>
      <li><a href="#upstream-fixes" id="markdown-toc-upstream-fixes">Upstream Fixes</a></li>
    </ul>
  </li>
  <li><a href="#section-plocate" id="markdown-toc-section-plocate">4) Discussion about Granting setgid Privileges to the <code class="language-plaintext highlighter-rouge">plocate</code> Binary</a></li>
  <li><a href="#section-virtualbmc" id="markdown-toc-section-virtualbmc">5) Local Root Exploit in OpenStack’s non-production <code class="language-plaintext highlighter-rouge">virtualbmc</code> Project</a>    <ul>
      <li><a href="#lack-of-authorization-and-input-validation-in-vbmcd" id="markdown-toc-lack-of-authorization-and-input-validation-in-vbmcd">Lack of Authorization and Input Validation in <code class="language-plaintext highlighter-rouge">vbmcd</code></a></li>
      <li><a href="#reproducer" id="markdown-toc-reproducer">Reproducer</a></li>
      <li><a href="#further-concerns" id="markdown-toc-further-concerns">Further Concerns</a></li>
    </ul>
  </li>
  <li><a href="#section-snapd" id="markdown-toc-section-snapd">6) Revisit of the <code class="language-plaintext highlighter-rouge">snapd</code> Package Manager</a></li>
  <li><a href="#7-conclusion" id="markdown-toc-7-conclusion">7) Conclusion</a></li>
</ul>

<h1 id="1-introduction">1) Introduction</h1>

<p>The winter season has already begun for most of the people in our team and
with the Christmas holidays behind us, which granted us some well-earned rest,
we want to take a look back at what happened in our team during the autumn
months. During this time we already published a few dedicated review reports:</p>

<ul>
  <li><a href="/2025/10/31/opensmtpd-local-DoS.html">trivial local Denial-of-Service</a> in the <code class="language-plaintext highlighter-rouge">OpenSMTPD</code> mail
transfer agent.</li>
  <li><a href="/2025/11/06/scx-unauthorized-dbus.html">unauthenticated D-Bus API</a> in the <code class="language-plaintext highlighter-rouge">scx</code> scheduler project allowing
for a major local Denial-of-Service.</li>
  <li><a href="/2025/11/13/lightdm-kde-greeter-auth-helper.html">minor privilege escalation</a> from <code class="language-plaintext highlighter-rouge">lightdm</code> to <code class="language-plaintext highlighter-rouge">root</code> in
<code class="language-plaintext highlighter-rouge">lightdm-kde-greeter</code> leading to major improvements of its D-Bus code.</li>
  <li><a href="/2025/12/10/smb4k-major-issues-in-kauth-helper.html">major local vulnerabilities</a> in the D-Bus
interface of <code class="language-plaintext highlighter-rouge">smb4k</code>, resulting in upstream fixing a series of
long-standing issues in the affected component.</li>
</ul>

<p>In this post, as usual in the spotlight series, we will look into some topics
that did not justify dedicated reports. First we will discuss our <a href="#section-systemd">continued
efforts</a> to review privileged components found in the
<code class="language-plaintext highlighter-rouge">systemd</code> v258 release, which involved diving deep into some low-level aspects
of the Linux kernel API. <a href="#section-plasma-setup">Section 3</a> looks at D-Bus
issues we found in <code class="language-plaintext highlighter-rouge">plasma-setup</code>, a new component for the KDE desktop.
<a href="#section-plocate">Section 4</a> covers recent discussions about granting special
setgid permissions to the <code class="language-plaintext highlighter-rouge">plocate</code> package. <a href="#section-virtualbmc">Section 5</a>
gives insight into security issues found in the <code class="language-plaintext highlighter-rouge">virtualbmc</code> OpenStack
project, which turned out to be for testing purposes only. <a href="#section-snapd">Section
6</a> discusses revived efforts to bring the Snap package manager
to openSUSE.</p>

<h1 id="section-systemd">2) Completion of <code class="language-plaintext highlighter-rouge">systemd</code> v258 Code Review</h1>

<p>We already discussed our <code class="language-plaintext highlighter-rouge">systemd</code> v258 review efforts <a href="/2025/10/01/summer-spotlight.html#2-systemd-v258-local-root-exploit-in-new-systemd-machined-api-found-in-release-candidates">in the previous
spotlight edition</a>. At the time we found a
local root exploit in the <code class="language-plaintext highlighter-rouge">systemd-machined</code> API, which could be fixed before
the final release of v258. For the addition of this new major version of
<code class="language-plaintext highlighter-rouge">systemd</code> to openSUSE Tumbleweed, we still needed to look more closely into a
number of other D-Bus and Varlink services that have been added.</p>

<p>During autumn we completed the review of changes in
<a href="https://bugzilla.suse.com/show_bug.cgi?id=1250898"><code class="language-plaintext highlighter-rouge">systemd-mountfsd</code></a> and
<a href="https://bugzilla.suse.com/show_bug.cgi?id=1250902"><code class="language-plaintext highlighter-rouge">systemd-nsresourced</code></a>. Some of the changes
introduced with these services allow unprivileged users to perform a number of
container-related operations without requiring special privileges.</p>

<p>The <a href="https://github.com/systemd/systemd/blob/781d9d0789379d1ea1f2ecefb804d41e9c8b6c38/src/mountfsd/mountwork.c#L726"><code class="language-plaintext highlighter-rouge">io.systemd.MountFileSystem.MountDirectory</code> API
call</a> in <code class="language-plaintext highlighter-rouge">mountfsd</code>, for example, allows to obtain
a mount file descriptor for a directory owned by the calling user, on which a
user and group ID mapping is applied corresponding to a user namespace file
descriptor also owned by the caller. Some newer, little-known Linux system
calls like <a href="https://manpages.debian.org/testing/manpages-dev/open_tree.2.en.html"><code class="language-plaintext highlighter-rouge">open_tree()</code></a> and
<a href="https://manpages.debian.org/testing/manpages-dev/mount_setattr.2.en.html"><code class="language-plaintext highlighter-rouge">mount_setattr()</code></a> are used to achieve this. This niche
topic and the low-level nature of the involved APIs result in quite complex
code which needed careful reviewing. We are happy to report that we could find
no issues in this area, however.</p>

<p>The <code class="language-plaintext highlighter-rouge">nsresourced</code> service, among other features, allows unprivileged users to
obtain a dynamic range of user and group IDs for use with user namespaces. The
tools <a href="https://man7.org/linux/man-pages/man1/newuidmap.1.html"><code class="language-plaintext highlighter-rouge">newuidmap</code></a> and <a href="https://man7.org/linux/man-pages/man1/newgidmap.1.html"><code class="language-plaintext highlighter-rouge">newgidmap</code></a> already
allowed this for a longer time based on static configuration files. The
<code class="language-plaintext highlighter-rouge">nsresourced</code> service applies <em>dynamic</em> limits and ID ranges to processes in
the system, however, which makes things quite more complicated. This even
includes <a href="https://github.com/systemd/systemd/blob/781d9d0789379d1ea1f2ecefb804d41e9c8b6c38/src/nsresourced/bpf/userns-restrict/userns-restrict.bpf.c">an EBPF program</a>, which keeps track
of the uses of the resulting user namespace file descriptors. Despite this
complexity we could not find any issues in this component either.</p>

<p>What kept us busy for a longer time was <a href="https://github.com/systemd/systemd/blob/781d9d0789379d1ea1f2ecefb804d41e9c8b6c38/src/mountfsd/mountwork.c#L852">logic
invoked</a> by <code class="language-plaintext highlighter-rouge">mountfsd</code> to obtain the
user and group ID mapping tied to the user namespace file descriptor passed by
the unprivileged client. To retrieve this information, the utility function
<a href="https://github.com/systemd/systemd/blob/781d9d0789379d1ea1f2ecefb804d41e9c8b6c38/src/basic/namespace-util.c#L600"><code class="language-plaintext highlighter-rouge">ns_enter_and_pin()</code></a> forks a short-lived
child process which joins the user namespace provided by the client.  The
parent process then reads the child’s <code class="language-plaintext highlighter-rouge">uid_map</code> and <code class="language-plaintext highlighter-rouge">gid_map</code> nodes from
<code class="language-plaintext highlighter-rouge">/proc/&lt;child-pid&gt;</code>.</p>

<p>The <code class="language-plaintext highlighter-rouge">mountfsd</code> daemon runs with <code class="language-plaintext highlighter-rouge">root</code> privileges (although some sandboxing is
applied to it as well), which will be inherited by the short-lived child
process. Once the child process joins the user namespace provided by the
unprivileged client, the security domain of this process changes, however,
because the client owning the namespace is supposed to have full control over
processes associated with it.</p>

<p>One consequence of this is that the owner of the user namespace can send
arbitrary signals to the short-lived <code class="language-plaintext highlighter-rouge">systemd</code> process, e.g. to kill it. This
would only result in a kind of Denial-of-Service against the client itself and
should not cause any security issues.</p>

<p>We expected another important ramification of this to be in the area of the
<a href="https://man7.org/linux/man-pages/man2/ptrace.2.html"><code class="language-plaintext highlighter-rouge">ptrace()</code> system call</a>. The following is stated in the “ptrace
access mode checking” section of the <code class="language-plaintext highlighter-rouge">ptrace(2)</code> man page:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(3)  Deny access if neither of the following is true:

            •  The real, effective, and saved-set user IDs of the target
               match the caller's user ID, and the real, effective, and
               saved-set group IDs of the target match the caller's group
               ID.

            •  The caller has the CAP_SYS_PTRACE capability in the user
               namespace of the target.
</code></pre></div></div>

<p>According to the second item, the unprivileged client, which owns all
capabilities in its user namespace, should be able to trace the short-lived
<code class="language-plaintext highlighter-rouge">systemd</code> process which joins the client-controlled user namespace. This
ability would have allowed for an interesting privilege escalation, because
tracing capabilities also include the ability to modify the target process,
e.g. to change its code and data. While trying to reproduce this, the kernel
always denied <code class="language-plaintext highlighter-rouge">ptrace()</code> access to this short-lived process, however, and we
were not sure why. Unclarity in such aspects is not a good thing when it
concerns security, thus we set out to get to the bottom of this.</p>

<p>After diving deep into the Linux kernel’s <code class="language-plaintext highlighter-rouge">ptrace()</code> code, we found <a href="https://github.com/torvalds/linux/commit/bfedb589252c01fa505ac9f6f2a3d5d68d707ef4">the
commit</a> which is responsible for the rejection of
tracing access in this scenario. The background of this commit actually is
to prevent owners of unprivileged user namespaces from accessing the
executable of processes created in the initial namespace. <code class="language-plaintext highlighter-rouge">ptrace()</code> access to
the target PID is now only allowed if the target process performed an
<code class="language-plaintext highlighter-rouge">execve()</code> while being a member of the newly joined user namespace. In summary
this means the following:</p>

<ul>
  <li>if a process only performs <code class="language-plaintext highlighter-rouge">fork()</code> and <code class="language-plaintext highlighter-rouge">setns()</code> to join a user namespace,
then <code class="language-plaintext highlighter-rouge">ptrace()</code> access to this process is denied to the owner of the user
namespace.</li>
  <li>if a process performs <code class="language-plaintext highlighter-rouge">fork()</code>, <code class="language-plaintext highlighter-rouge">setns()</code> and <code class="language-plaintext highlighter-rouge">execve()</code>, then <code class="language-plaintext highlighter-rouge">ptrace()</code>
access to this process is granted to the owner of the user namespace.</li>
</ul>

<p>This detail is not documented in the <a href="https://man7.org/linux/man-pages/man2/ptrace.2.html"><code class="language-plaintext highlighter-rouge">ptrace()</code> man page</a> and it
took us a while to fully understand what was going on. With this well
understood we could finally move on, knowing that the logic in <code class="language-plaintext highlighter-rouge">mountfsd</code> is
robust.</p>

<h1 id="section-plasma-setup">3) D-Bus Issues in Unreleased <code class="language-plaintext highlighter-rouge">plasma-setup</code> KDE Package</h1>

<p>This new KDE component was first named KISS (KDE initial system setup), but
meanwhile has been renamed to <a href="https://github.com/KDE/plasma-setup.git"><code class="language-plaintext highlighter-rouge">plasma-setup</code></a>.
Its purpose is to perform initial system configuration based on a graphical
wizard, when a Linux system has been freshly installed.</p>

<p>Our openSUSE KDE packagers <a href="https://bugzilla.suse.com/show_bug.cgi?id=1249520">asked for a review</a> of this new
component, expecting it to be part of a major KDE release in autumn. It turned
out that this had not been planned by upstream after all (or plans changed).
Still the review we performed turned out to be useful, since we identified
various security problems in the existing code which could be fixed by
upstream before the new component had seen production use.</p>

<p>The following report is based on the <code class="language-plaintext highlighter-rouge">plasma-setup</code> source code as of upstream
<a href="https://github.com/KDE/plasma-setup/tree/08ed810e0e7ba1642d6f2bd211e0ba43e85f8496">commit 08ed810e0e7</a>. While the graphical
components of <code class="language-plaintext highlighter-rouge">plasma-setup</code> run with low privileges, there exists a D-Bus
helper service running as <code class="language-plaintext highlighter-rouge">root</code>, <code class="language-plaintext highlighter-rouge">kde-initial-system-setup-auth-helper</code>,
which allows to perform a number of operations with elevated privileges. These
operations are guarded by Polkit authorization rules. The dedicated user
account <code class="language-plaintext highlighter-rouge">kde-initial-system-setup</code> is allowed to invoke any of these actions
without authentication. Beyond this, any locally logged-in users are also
allowed to invoke the operations without authentication. The latter is quite
problematic, as will be outlined below.</p>

<p>The implementation of the D-Bus callbacks for these actions is found in
<a href="https://github.com/KDE/plasma-setup/blob/08ed810e0e7ba1642d6f2bd211e0ba43e85f8496/src/auth/authhelper.cpp"><code class="language-plaintext highlighter-rouge">src/auth/authhelper.cpp</code></a>. The following
sub-sections discuss issues in a couple of these actions.</p>

<h2 id="sub-section-autostarthook">org.kde.initialsystemsetup.createnewuserautostarthook</h2>

<p>This action <a href="https://github.com/KDE/plasma-setup/blob/08ed810e0e7ba1642d6f2bd211e0ba43e85f8496/src/auth/authhelper.cpp#L28">receives a “username” parameter</a>
from the unprivileged D-Bus client. The username is not verified by the
privileged helper, it only needs to be convertible to <code class="language-plaintext highlighter-rouge">QString</code>. The helper
then creates all the directory components of
<code class="language-plaintext highlighter-rouge">/home/&lt;username&gt;/.config/autostart</code>. After this, the file
<code class="language-plaintext highlighter-rouge">/home/&lt;username&gt;/.config/autostart/remove-autologin.desktop</code> is created and
fixed data is written into it.</p>

<p>This action allows local users to create arbitrary world-readable directories
owned by <code class="language-plaintext highlighter-rouge">root</code>. This can be achieved by passing a string like
<code class="language-plaintext highlighter-rouge">../../my/desired/path</code> as “username”. Furthermore, by placing a symlink at
the expected location of <code class="language-plaintext highlighter-rouge">remove-autologin.desktop</code>, arbitrary files in the
system can be overwritten, leading to a local Denial-of-Service.</p>

<p>The implementation of the action also causes the created directories and files
to be owned by <code class="language-plaintext highlighter-rouge">root:root</code>, and not by the user that actually owns the home
directory, which is unclean.</p>

<h3 id="suggested-fixes">Suggested Fixes</h3>

<p>Apart from restricting access to the helper to the <code class="language-plaintext highlighter-rouge">kde-initial-system-setup</code>
user, the implementation of this action should verify whether the
passed-in username actually exists. Furthermore, the home directory of this
account should be obtained via the <a href="https://man7.org/linux/man-pages/man3/getpwent.3.html"><code class="language-plaintext highlighter-rouge">getpwent()</code></a> API, instead
of assuming that <code class="language-plaintext highlighter-rouge">/home/&lt;username&gt;</code> will always be the correct home directory.</p>

<p>When the execution of this helper is actually limited to the initial setup
context, it could be technically acceptable to operate as <code class="language-plaintext highlighter-rouge">root</code> in the newly
created user’s home directory. For reasons of prudence and giving a good
example, we still recommend to drop privileges to the target user account
before actually writing the <code class="language-plaintext highlighter-rouge">.desktop</code> file in the user’s home directory.</p>

<h2 id="orgkdeinitialsystemsetupsetnewuserhomedirectoryownership">org.kde.initialsystemsetup.setnewuserhomedirectoryownership</h2>

<p>The method call associated with this action <a href="https://github.com/KDE/plasma-setup/blob/08ed810e0e7ba1642d6f2bd211e0ba43e85f8496/src/auth/authhelper.cpp#L125">also receives a “username”
parameter</a> which is not verified. The
following command line is invoked based on the “username” parameter:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">chown</span> <span class="nt">-R</span> &lt;username&gt;:&lt;username&gt; /home/&lt;username&gt;
</code></pre></div></div>

<p>This is on the verge of a local root exploit, save for the fact that <code class="language-plaintext highlighter-rouge">chown</code>
expects a valid user and group account to give the ownership to, which at the
same time needs to result in the proper path to operate on.  A username
containing path elements will fail, because the necessary characters like <code class="language-plaintext highlighter-rouge">/</code>
are by default denied in usernames.</p>

<p>This action still allows to potentially change ownership of all files of
arbitrary other users’ home directories. Fortunately the recursive <code class="language-plaintext highlighter-rouge">chown</code>
algorithm is not subject to symlink attacks these days. If somebody would be
able to place a symlink in place of their home directory in
<code class="language-plaintext highlighter-rouge">/home/&lt;username&gt;</code>, then the symlink would still be followed, however.</p>

<p>The username could also be interpreted as an arbitrary command line argument
to <code class="language-plaintext highlighter-rouge">chown</code>, thwarted only by the fact that the <code class="language-plaintext highlighter-rouge">&lt;username&gt;:&lt;username&gt;</code>
argument is constructed here instead of just passing <code class="language-plaintext highlighter-rouge">&lt;username&gt;</code>, which will
prevent proper command line arguments from being passed.</p>

<h3 id="suggested-fixes-1">Suggested Fixes</h3>

<p>As for the previous action, the implementation should verify if the username
is valid and determine the proper home directory and group via <code class="language-plaintext highlighter-rouge">getpwent()</code>.
The assumption that username and group are equivalent is also problematic
here.</p>

<p>Why this operation would be needed at all for a newly created home directory
is questionable. When new user accounts are created, file ownership should
already be correct. If this action is supposed to fix the ownership of files
created by other <code class="language-plaintext highlighter-rouge">plasma-setup</code> actions in the home directory as <code class="language-plaintext highlighter-rouge">root</code> (as is
seen in the <a href="#sub-section-autostarthook"><code class="language-plaintext highlighter-rouge">createnewuserautostarthook</code> action</a>),
then this is only a hack which should be removed in favor of not creating
files as <code class="language-plaintext highlighter-rouge">root</code> in unprivileged users’ home directories in the first place.</p>

<h2 id="orgkdeinitialsystemsetupsetnewusertempautologin">org.kde.initialsystemsetup.setnewusertempautologin</h2>

<p>Again this method <a href="https://github.com/KDE/plasma-setup/blob/08ed810e0e7ba1642d6f2bd211e0ba43e85f8496/src/auth/authhelper.cpp#L150">receives a “username”
parameter</a> which is not verified. The
implementation writes the following content to the file
<code class="language-plaintext highlighter-rouge">/etc/sddm.conf.d/99-kde-initial-system-setup.conf</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Autologin]
User=&lt;username&gt;
Session=plasma
Relogin=true
</code></pre></div></div>

<p>This SDDM configuration snippet is supposed to automatically login the
given user account. For some reason that we did not investigate more deeply,
the configuration was not effective during our tests on openSUSE
Tumbleweed. We could verify that the configuration file created this way was
parsed and evaluated in SDDM, however, so something else must have been amiss.</p>

<p>The automatic login is supposed to work, though, and if it does, then any
local user account can call this action with <code class="language-plaintext highlighter-rouge">root</code> as username, which should
cause an automatic login of the <code class="language-plaintext highlighter-rouge">root</code> user the next time SDDM runs.</p>

<p>By passing crafted strings for “username”, the content of the drop-in
configuration file can even be fully controlled by local users. The following
“username” would create a General section with a crafted “RebootCommand”, for
example:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>user\n[General]\nRebootCommand=/home/myuser/evil
</code></pre></div></div>

<p>Provided the configuration snippet is actually in effect in SDDM, this action
allows for a local root exploit.</p>

<h3 id="suggested-fixes-2">Suggested Fixes</h3>

<p>As for the other actions, the implementation should verify whether the passed
“username” is valid and does not equal <code class="language-plaintext highlighter-rouge">root</code>.</p>

<h2 id="upstream-fixes">Upstream Fixes</h2>

<p>We privately approached KDE security on 2025-09-22 with a detailed report
about these findings. As a result we established contact with the
<code class="language-plaintext highlighter-rouge">plasma-setup</code> developer and discussed fixes for the issues. It was decided to
perform the bugfix in the open, since the component was not yet part of a
stable release of KDE. We reviewed an <a href="https://invent.kde.org/plasma/plasma-setup/-/merge_requests/48">upstream merge
request</a> during the course of two weeks and upstream
managed to arrive at a much improved version of the KAuth helper component.</p>

<p>As of <a href="https://github.com/KDE/plasma-setup/blob/e6eb1cd9a8d4094ff2771d25ee6f761ea9f05c6c/src/auth/authhelper.cpp">commit e6eb1cd9a8d</a> the privileged
helper carefully scrutinizes the input parameters received via D-Bus, and it
also drops privileges to the calling user before operating in the unprivileged
user’s home directory. Also the KAuth actions provided by the helper are now
restricted to the <code class="language-plaintext highlighter-rouge">plasma-setup</code> service user and no longer accessible to
all locally logged-in users. The latter would still be problematic, since it
would allow to setup automatic login for arbitrary other users in the system,
for example.</p>

<h1 id="section-plocate">4) Discussion about Granting setgid Privileges to the <code class="language-plaintext highlighter-rouge">plocate</code> Binary</h1>

<p>An openSUSE community member approached us about <a href="https://bugzilla.suse.com/show_bug.cgi?id=1254549">granting special setgid
privileges to the <code class="language-plaintext highlighter-rouge">plocate</code></a> binary. <code class="language-plaintext highlighter-rouge">plocate</code> is a modern and
fast replacement for the classic <code class="language-plaintext highlighter-rouge">locate</code> program. Upstream supports operation
of the <code class="language-plaintext highlighter-rouge">plocate</code> program with the <code class="language-plaintext highlighter-rouge">setgid</code> bit assigned to the <code class="language-plaintext highlighter-rouge">plocate</code>
group. This means that the program is granted <code class="language-plaintext highlighter-rouge">plocate</code> group privileges
during execution.</p>

<p>When <code class="language-plaintext highlighter-rouge">updatedb</code>, locate’s utility for indexing files, would be invoked with
full root privileges, then the database in <code class="language-plaintext highlighter-rouge">/var/lib/plocate</code> would contain
information about all files in the file system. This way <code class="language-plaintext highlighter-rouge">locate</code> would grant
all users in the system read access to this information, resulting in an
information leak, because users can see paths that they would not normally be
allowed to list, like all the files stored in the <code class="language-plaintext highlighter-rouge">/root</code> home directory. For
this reason the <code class="language-plaintext highlighter-rouge">plocate-updatedb</code> system service on openSUSE Tumbleweed runs
as <code class="language-plaintext highlighter-rouge">nobody:nobody</code>, resulting in a system-wide <code class="language-plaintext highlighter-rouge">plocate</code> database which only
contains information about publicly accessible paths in the system. For being
able to locate their own private files, users need to create their own
user-specific databases instead.</p>

<p>The purpose of the setgid privilege is to address this <code class="language-plaintext highlighter-rouge">locate</code> database
access issue. <code class="language-plaintext highlighter-rouge">plocate</code> supports a mode in which <code class="language-plaintext highlighter-rouge">updatedb</code> is invoked with
full root privileges, but the ownership of the central database is changed to
<code class="language-plaintext highlighter-rouge">root:plocate</code> and file mode <code class="language-plaintext highlighter-rouge">0640</code>. When <code class="language-plaintext highlighter-rouge">plocate</code> is installed as
setgid-plocate then it is still allowed to access the central database. The
program drops the special group credentials quickly again, right after opening
the database. The program then ensures that the calling user will only be able
to retrieve information about files that it is allowed to access based on its
real credentials.</p>

<p>There is a minor security issue found in this approach. Since the <code class="language-plaintext highlighter-rouge">plocate</code>
database does not contain metadata about the files it indexed, the <code class="language-plaintext highlighter-rouge">plocate</code>
program needs to check the ownership of files in the file system at the time
the search query runs. This is a sort of a TOCTOU (time-of-check time-of-use)
race condition. There can be situations when the verification in <code class="language-plaintext highlighter-rouge">plocate</code>
yields wrong results:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root# <span class="nb">mkdir</span> <span class="nt">--mode</span><span class="o">=</span>1777 /shared
root# <span class="nb">mkdir</span> <span class="nt">--mode</span><span class="o">=</span>0700 /shared/secret-dir
root# <span class="nb">touch</span> /shared/secret-dir/secret-file
root# updatedb

<span class="c"># root will be able to locate any files in secret-dir</span>
root# locate /shared/se
/shared/secret-dir
/shared/secret-dir/secret-file

<span class="c"># non-root cannot locate the secret-file</span>
user<span class="nv">$ </span>locate /shared/se
/shared/secret-dir

<span class="c"># now consider root deletes the secret-dir again</span>
root# <span class="nb">rm</span> <span class="nt">-rf</span> /shared/secret-dir

<span class="c"># now the unprivileged user takes ownership of this path</span>
user<span class="nv">$ </span><span class="nb">mkdir</span> <span class="nt">--mode</span><span class="o">=</span>0755 /shared/secret-dir

<span class="c"># this only works before `updatedb` is called again, because then it will</span>
<span class="c"># notice that secret-file no longer exists and delete it from the database.</span>
<span class="c">#</span>
<span class="c"># when the unprivileged user calls locate this time, the secret-file will show</span>
<span class="c"># up, since the "secret-dir" is now controlled by the unprivileged caller.</span>
user<span class="nv">$ </span>locate /shared/se
/shared/secret-dir
/shared/secret-dir/secret-file
</code></pre></div></div>

<p>This problem likely cannot be easily fixed in the <code class="language-plaintext highlighter-rouge">plocate</code> code, since it
would require changing the database format radically, increasing database size
as a result, only to fix an unlikely problem.</p>

<p>The information leak is minor and should rarely be exploitable. For this
reason we left it up to the openSUSE <code class="language-plaintext highlighter-rouge">plocate</code> package maintainer whether the
setgid-plocate approach should be used, or not.</p>

<h1 id="section-virtualbmc">5) Local Root Exploit in OpenStack’s non-production <code class="language-plaintext highlighter-rouge">virtualbmc</code> Project</h1>

<p>By way of our efforts to monitor newly introduced <code class="language-plaintext highlighter-rouge">systemd</code> services in
openSUSE Tumbleweed, the <a href="https://github.com/openstack/virtualbmc"><code class="language-plaintext highlighter-rouge">python-virtualbmc</code></a>
package caught our attention. The program allows to emulate a board management
controller (BMC) interface for use with libvirt.</p>

<p>Part of the package is a daemon running with full root privileges, listening
for ZeroMQ API requests on <code class="language-plaintext highlighter-rouge">localhost</code>. A number of unauthenticated API calls
in this context raised our suspicions, which is why we scheduled a <a href="https://bugzilla.suse.com/show_bug.cgi?id=1253677">full
review of this package</a>. A closer look showed that the
unauthenticated API calls were indeed problematic, even allowing for a full
local root exploit.</p>

<p>We filed a detailed private bug report on
<a href="https://bugs.launchpad.net/virtualbmc/+bug/2133163">LaunchPad</a> for the OpenStack project, but had
difficulties getting a response. After some weeks we reached out to an
individual member of the OpenStack security team and learned from the reply
that the virtualbmc project was not intended for production use at all, but is
rather a utility intended for use in testing environments. This is also
documented in the repository’s <a href="https://github.com/openstack/virtualbmc/blob/master/README.rst">README</a>, which was
overlooked by us. As a result we filed a delete request for the
<code class="language-plaintext highlighter-rouge">python-virtualbmc</code> package in openSUSE Tumbleweed, and the package has
already been removed.</p>

<p>For completeness, a detailed report of the security issues in the virtualbmc
daemon follows below.</p>

<h2 id="lack-of-authorization-and-input-validation-in-vbmcd">Lack of Authorization and Input Validation in <code class="language-plaintext highlighter-rouge">vbmcd</code></h2>

<p>When the <code class="language-plaintext highlighter-rouge">virtualbmc</code> <code class="language-plaintext highlighter-rouge">systemd</code> service is started, then <code class="language-plaintext highlighter-rouge">/usr/bin/vbmcd</code> runs
with full root privileges. It offers a ZeroMQ-based network API, listening on
localhost port 50891 by default. Any local user in the system can talk to the
daemon this way.</p>

<p>A simple request which can be sent to the daemon (in JSON format) is the
following stop command, for example:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
        </span><span class="nl">"command"</span><span class="p">:</span><span class="w"> </span><span class="s2">"stop"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"port"</span><span class="p">:</span><span class="w"> </span><span class="mi">1234</span><span class="p">,</span><span class="w">
        </span><span class="nl">"domain_names"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"../../home/myaccount/mydomain"</span><span class="p">],</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">domain_name</code> passed here will be used by the daemon to lookup a
supposedly trusted per-domain configuration file, which is by default located
in <code class="language-plaintext highlighter-rouge">/root/.vbmc/&lt;domain&gt;/config</code>. Since the daemon does not scrutinize the
input <code class="language-plaintext highlighter-rouge">domain_name</code>, a local attacker can include directory components in the
name, to trick the daemon into accessing an attacker-controlled configuration
file.</p>

<p>In the context of the <code class="language-plaintext highlighter-rouge">stop</code> command used here, the daemon will try to update
the domain’s configuration file in case a change of domain state is detected.
The path for writing out the updated configuration file will be constructed
using the <code class="language-plaintext highlighter-rouge">domain_name</code> found in the input configuration file. Thus the local
attacker can place data like this into <code class="language-plaintext highlighter-rouge">/home/myaccount/mydomain/config</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[VirtualBMC]
domain_name = ../../etc/sudoers.d
port = 1234
active = true
address = some
  evil stuff
  myaccount ALL=(ALL:ALL) NOPASSWD: ALL
</code></pre></div></div>

<p>The daemon will now believe that the domain’s state changed, because the input
configuration file contains <code class="language-plaintext highlighter-rouge">active = true</code>, while the daemon was asked to
stop the domain. This will trigger logic to write out an updated configuration
file with the new state of the domain configuration. The logic for this is
found in the <a href="https://github.com/openstack/virtualbmc/blob/6e14e8bdb8cc022d843bfb98377bfc89d99fc9c5/virtualbmc/manager.py#L90"><code class="language-plaintext highlighter-rouge">_vbmc_enabled()</code></a> member
function.</p>

<p>Since the <code class="language-plaintext highlighter-rouge">domain_name</code> found in the crafted configuration file is set to
<code class="language-plaintext highlighter-rouge">../../etc/sudoers.d</code>, the daemon will write the new configuration file into
<code class="language-plaintext highlighter-rouge">/root/.vbmcd/../../etc/sudoers.d/config</code>. To get an advantage from this, the
attacker must get the daemon to write out at least one valid <code class="language-plaintext highlighter-rouge">sudoers</code>
configuration line into the new configuration file.</p>

<p>The attacker has only a limited degree of freedom at this stage, because
the daemon will write out the new configuration file via the Python
<code class="language-plaintext highlighter-rouge">configparser</code> module and will only consider the <code class="language-plaintext highlighter-rouge">[VirtualBMC]</code> section as
well as any of the configuration keys listed in the <a href="https://github.com/openstack/virtualbmc/blob/6e14e8bdb8cc022d843bfb98377bfc89d99fc9c5/virtualbmc/manager.py#L40"><code class="language-plaintext highlighter-rouge">VBMC_OPTIONS</code>
list</a> defined in the daemon’s code.</p>

<p>To help with the exploit, the
<a href="https://docs.python.org/3/library/configparser.html"><code class="language-plaintext highlighter-rouge">configparser</code></a>
multiline syntax comes to the rescue: any lines following an assignment which
are indented will be accepted as part of the configuration value. When writing
the settings out to a new configuration file, these multiline settings will be
preserved.  This is put to use in the example above, which contains a final
line <code class="language-plaintext highlighter-rouge">myaccount ALL=...</code>. This line will now appear along with the rest of the
configuration data in <code class="language-plaintext highlighter-rouge">/etc/sudoers.d/config</code>.</p>

<p>As a result, when the attacker now invokes <code class="language-plaintext highlighter-rouge">sudo su -</code>, a couple of sudoers
parsing errors will appear, but in the end, access is granted and a root shell
will be obtained by the attacker.</p>

<p>This approach of using a sudoers drop-in configuration file is just one of the
more obvious approaches that came to mind. There’s a lot of different ways
to exploit this, however, for example by overwriting shell scripts or script
snippets in <code class="language-plaintext highlighter-rouge">/etc</code> or <code class="language-plaintext highlighter-rouge">/usr/bin</code> and then waiting for a privileged process to
run them. This would be even easier, because shell scripts have less
strict syntax requirements compared to the sudoers configuration file. The
effect would not be immediate, however, like in the sudoers approach.</p>

<h2 id="reproducer">Reproducer</h2>

<p>We offer a <a href="/download/virtualbmc-exploit.py">Python script for download</a>, which
is a Proof-of-Concept (PoC) to reproduce the local root exploit in the context
of an arbitrary unprivileged user on the system, when <code class="language-plaintext highlighter-rouge">vbmcd</code> is running with
its default configuration.  <code class="language-plaintext highlighter-rouge">sudo</code> needs to be installed, naturally, for the
exploit to work.</p>

<h2 id="further-concerns">Further Concerns</h2>

<p>In general, the API offered by <code class="language-plaintext highlighter-rouge">vbmcd</code> on localhost is missing input
sanitization and authorization. Authorization seems only to be performed
indirectly via libvirt. In this context clients can also pass crafted
<code class="language-plaintext highlighter-rouge">libvirt_uri</code> parameters, for example, which seem to make it possible to let
the daemon connect to arbitrary URLs via SSH. There also is no isolation
between different users’ domain configurations, e.g. the “stop” command used
above can be issued for any domain configured by another user in the system.</p>

<p>To make this API safe, we believe there needs to be an ownership model for
each domain’s configuration, a verification of the client’s credentials in
some form (a UNIX domain socket would allow this more easily) and sanitization
of all input parameters to avoid any unexpected side effects.</p>

<p>Since the daemon listens on an unprivileged port on localhost, other
unprivileged users can try to bind to this port first and provide a fake
<code class="language-plaintext highlighter-rouge">vbmcd</code> service. Since the API requests can also contain secret credentials,
this would pose a major local information leak. For safe operation, the API
would need to bind to a privileged port on localhost instead.</p>

<h1 id="section-snapd">6) Revisit of the <code class="language-plaintext highlighter-rouge">snapd</code> Package Manager</h1>

<p>In 2019 we received <a href="https://bugzilla.suse.com/show_bug.cgi?id=1127366">a request</a> to add the <a href="https://snapcraft.io"><code class="language-plaintext highlighter-rouge">snapd</code> package
manager</a> to openSUSE, which involved a <a href="https://bugzilla.suse.com/show_bug.cgi?id=1127368">review of the
setuid-root program</a> <code class="language-plaintext highlighter-rouge">snap-confine</code>. At the time we were
generally satisfied with the code quality and design of the program, but still
<a href="https://bugzilla.suse.com/show_bug.cgi?id=1127368#c3">found a few low to medium severity security issues</a>
and gave recommendations on how to improve the code in some spots. The
packagers have meanwhile been busy with other topics and we never saw
an updated openSUSE package containing the necessary changes, which is why we
closed the related bugs after a period of inactivity.</p>

<p>In August we received <a href="https://bugzilla.suse.com/show_bug.cgi?id=1248682">a follow-up request</a> for addition of an
updated <code class="language-plaintext highlighter-rouge">snapd</code> package. We revisited the privileged components and again
<a href="https://bugzilla.suse.com/show_bug.cgi?id=1248682#c5">provided feedback</a> to upstream. This time
all remaining issues could be resolved and the new package has been allowed to
become part of openSUSE Tumbleweed. We are happy to see these old efforts not
going completely to waste, and welcome the possibility to use Snap packages on
openSUSE Tumbleweed in the future.</p>

<h1 id="7-conclusion">7) Conclusion</h1>

<p>Again we hope we’ve been able to give you some additional insight into our
efforts to maintain the security of SUSE distributions and open source
software. We are looking forward to the next edition of the spotlight series,
which will be published in about three months from now.</p>]]></content><author><name>&lt;a href=&apos;mailto:matthias.gerstner@suse.de&apos;&gt;Matthias Gerstner&lt;/a&gt;, &lt;a href=&apos;mailto:filippo.bonazzi@suse.com&apos;&gt;Filippo Bonazzi (editor)&lt;/a&gt;</name></author><category term="spotlight" /><summary type="html"><![CDATA[This is the autumn 2025 edition of our spotlight series. Once again it has been a very busy three months for us in the SUSE security team. Some of the topics we will cover this time are the final outcome of our systemd v258 code review efforts, improvements we helped with in KDE's new plasma-setup utility and security issues in the virtualbmc OpenStack component, which turned out to be intended for testing purposes only.]]></summary></entry><entry><title type="html">InputPlumber: Lack of D-Bus Authorization and Input Verification allows UI Input Injection and Denial-of-Service (CVE-2025-66005, CVE-2025-14338)</title><link href="https://security.opensuse.org/2026/01/09/inputplumber-lack-of-dbus-auth.html" rel="alternate" type="text/html" title="InputPlumber: Lack of D-Bus Authorization and Input Verification allows UI Input Injection and Denial-of-Service (CVE-2025-66005, CVE-2025-14338)" /><published>2026-01-09T00:00:00+00:00</published><updated>2026-01-09T00:00:00+00:00</updated><id>https://security.opensuse.org/2026/01/09/inputplumber-lack-of-dbus-auth</id><content type="html" xml:base="https://security.opensuse.org/2026/01/09/inputplumber-lack-of-dbus-auth.html"><![CDATA[<h1 class="no_toc" id="table-of-contents">Table of Contents</h1>

<ul id="markdown-toc">
  <li><a href="#1-introduction" id="markdown-toc-1-introduction">1) Introduction</a></li>
  <li><a href="#section-overview" id="markdown-toc-section-overview">2) Overview of the D-Bus Service</a></li>
  <li><a href="#section-issues" id="markdown-toc-section-issues">3) Security Issues</a>    <ul>
      <li><a href="#31-lack-of-authentication--polkit-authentication-bypass" id="markdown-toc-31-lack-of-authentication--polkit-authentication-bypass">3.1) Lack of Authentication / Polkit Authentication Bypass</a></li>
      <li><a href="#32-d-bus-methods-allowing-privilege-escalation" id="markdown-toc-32-d-bus-methods-allowing-privilege-escalation">3.2) D-Bus Methods Allowing Privilege Escalation</a></li>
    </ul>
  </li>
  <li><a href="#section-suggested-fixes" id="markdown-toc-section-suggested-fixes">4) Suggested Fixes</a></li>
  <li><a href="#section-bugfixes" id="markdown-toc-section-bugfixes">5) Upstream Bugfixes</a></li>
  <li><a href="#section-cves" id="markdown-toc-section-cves">6) CVE Assignment</a></li>
  <li><a href="#section-disclosure" id="markdown-toc-section-disclosure">7) Coordinated Disclosure</a></li>
  <li><a href="#8-timeline" id="markdown-toc-8-timeline">8) Timeline</a></li>
  <li><a href="#9-references" id="markdown-toc-9-references">9) References</a></li>
</ul>

<h1 id="1-introduction">1) Introduction</h1>

<p><a href="https://github.com/ShadowBlip/InputPlumber">InputPlumber</a> is a utility for combining Linux input
devices into virtual input devices. It is mostly used in the context of Linux
gaming and is part of <a href="https://store.steampowered.com/steamos">SteamOS</a>.</p>

<p>An openSUSE community member packaged InputPlumber which <a href="https://bugzilla.suse.com/show_bug.cgi?id=1249149">required a
review</a> by the SUSE security team, as it contains a D-Bus
system service. The first version of InputPlumber we reviewed was completely
lacking client authentication, causing us to reject it. A follow-up version
contained Polkit authentication, which turned out to be lacking in multiple
regards. At this point we approached upstream with a detailed report and
established coordinated disclosure. Starting with <a href="https://github.com/ShadowBlip/InputPlumber/releases/tag/v0.69.0">version
v0.69.0</a> of InputPlumber most (but not all) of the
issues in this report have been addressed. SteamOS also <a href="https://steamcommunity.com/games/1675200/announcements/detail/500594947381003216">published new
images</a> for version 3.7.20 containing the fixes.</p>

<p>This report is based on <a href="https://github.com/ShadowBlip/InputPlumber/releases/tag/v0.67.0">InputPlumber release v0.67.0</a>.
The <a href="#section-overview">next section</a> provides an overview of
InputPlumber’s D-Bus service. <a href="#section-issues">Section 3</a> looks into the
security issues in detail. <a href="#section-suggested-fixes">Section 4</a> discusses the
fixes we suggested to upstream. <a href="#section-bugfixes">Section 5</a> looks into the
upstream bugfixes to address the issues and aspects that remain unfixed.
<a href="#section-cves">Section 6</a> covers the CVE assignments we did for the issues we
found. <a href="#section-disclosure">Section 7</a> provides a summary of the coordinated
disclosure process we followed for this report.</p>

<h1 id="section-overview">2) Overview of the D-Bus Service</h1>

<p>InputPlumber is implemented in Rust and the size of the code base is surprisingly
high for this type of project, adding up to about 50,000 lines of code
overall (not counting vendor code) and about 3,000 lines dedicated to the
D-Bus API specifically.</p>

<p>The InputPlumber D-Bus service runs with full root privileges, offering the
<a href="https://github.com/ShadowBlip/InputPlumber/blob/v0.67.0/src/dbus/interface/manager.rs#L38">“org.shadowblip.InputManager” interface</a> on the D-Bus
system bus. Additionally various interfaces representing Linux input devices
are provided by the daemon, like a <a href="https://github.com/ShadowBlip/InputPlumber/blob/v0.67.0/src/dbus/interface/target/keyboard.rs#L27">keyboard interface</a>.
In summary the service provides around 90 different D-Bus properties and about
10 different interfaces on various objects exported by it. The <a href="https://github.com/ShadowBlip/InputPlumber/blob/v0.67.0/rootfs/usr/share/polkit-1/actions/org.shadowblip.InputPlumber.policy">Polkit
policy</a> lists over 100 different actions, controlling
every aspect of the D-Bus API including read/write access to individual
properties.</p>

<h1 id="section-issues">3) Security Issues</h1>

<h2 id="31-lack-of-authentication--polkit-authentication-bypass">3.1) Lack of Authentication / Polkit Authentication Bypass</h2>

<p>Initially we looked into InputPlumber <a href="https://github.com/ShadowBlip/InputPlumber/releases/tag/v0.62.2">version
v0.62.2</a>. In this version there is no Polkit
authorization at all for the D-Bus interfaces. There are also no
restrictions in the configuration of the D-Bus service, allowing all users in
the system to connect to it, even low privilege user accounts like <code class="language-plaintext highlighter-rouge">nobody</code>.</p>

<p>We thought about reaching out to upstream already at this point, when we
noticed that in InputPlumber <a href="https://github.com/ShadowBlip/InputPlumber/releases/tag/v0.63.0">version v0.63.0</a> (which
was meanwhile published on GitHub) Polkit authentication had been added via
<a href="https://github.com/ShadowBlip/InputPlumber/commit/0a80f3d85741195af3d5501beacd363933c56b1b">commit 0a80f3d85</a>. Thus we asked our community
maintainer to update the package to at least that version for us to have
another look.</p>

<p>Due to other priorities we only got around to taking a fresh look at the
package at a later time, when the package had already been updated to <a href="https://github.com/ShadowBlip/InputPlumber/releases/tag/v0.67.0">version
v0.67.0</a>, on which this report is based.</p>

<p>Looking into this version we first discovered that the Polkit authentication
was still not effective in the package build provided to us. The reason for
this was that Polkit support was only a compile-time feature on Rust Cargo
configuration level - which was <a href="https://github.com/ShadowBlip/InputPlumber/commit/8a201ec27e898ca07868ba9adc27191fca030969">disabled by
default</a>. We believe that in this version there
is also no canonical way to enable the feature when using the
<a href="https://github.com/ShadowBlip/InputPlumber/blob/v0.67.0/Makefile">Makefile</a> found in the repository. For this reason we created
our own build of InputPlumber and applied a patch to hard-enable the Polkit
feature for testing.</p>

<p>In this custom package build of InputPlumber the Polkit authentication
triggered as expected. While looking into the implementation of the <a href="https://github.com/ShadowBlip/InputPlumber/blob/413c37c85e89d04fffcf53bd62312256e7324a86/src/dbus/polkit.rs#L31">Polkit
authentication wrapper</a>, however, we noticed that the Polkit
authentication logic uses the “unix-process” Polkit subject in an unsafe way.
It retrieves the caller’s PID from the D-Bus connection and passes this
information on to the Polkit daemon. This suffers from a race condition,
because the client can attempt to have its PID replaced by a privileged
process by the time <code class="language-plaintext highlighter-rouge">polkitd</code> gets around to actually look at the credentials
of the process.</p>

<p>This is a well-known issue when using the “unix-process” Polkit subject which
was assigned <a href="https://nvd.nist.gov/vuln/detail/CVE-2013-4288">CVE-2013-4288</a> in the past. For this reason the
subject has been marked as deprecated in Polkit. The “unix-process” subject
<a href="https://github.com/polkit-org/polkit/commit/9295e289cdb1b6cf2747ecf07054230e15edb385">is seeing new use</a> these days, however, when
combined with the use of Linux PID file descriptors, which are not affected by
the race condition.</p>

<p>In summary none of the versions of InputPlumber we looked into provided
sufficient authentication, even if integrators would have managed to actually
enable the Polkit layer in versions v0.63.0 and later. Thus all InputPlumber
D-Bus methods can be considered accessible by all users in the system without
authentication.</p>

<h2 id="32-d-bus-methods-allowing-privilege-escalation">3.2) D-Bus Methods Allowing Privilege Escalation</h2>

<p>Considering the unprivileged access to the D-Bus methods provided by
InputPlumber, the following two methods quickly caught our attention as being
problematic:</p>

<h3 id="createcompositedevicein--s-config_path"><strong><code class="language-plaintext highlighter-rouge">CreateCompositeDevice(in  s config_path)</code></strong></h3>

<p><a href="https://github.com/ShadowBlip/InputPlumber/blob/v0.67.0/src/dbus/interface/manager.rs#L141">This method</a> parses the provided input path as YAML to
create a CompositeDevice configuration and suffers from the following issues:</p>

<ul>
  <li>The method allows to perform file existence tests, by passing paths usually
not accessible to the caller.</li>
  <li>The method allows for a local Denial-of-Service (e.g. by passing <code class="language-plaintext highlighter-rouge">/dev/zero</code>
as input file, leading to memory exhaustion in InputPlumber).</li>
  <li>The method allows for an information leak, e.g. from <code class="language-plaintext highlighter-rouge">/root/.bash_history</code>:
    <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>user <span class="nv">$ </span>gdbus call <span class="nt">-y</span> <span class="nt">-d</span> org.shadowblip.InputPlumber <span class="nt">-o</span> /org/shadowblip/InputPlumber/Manager <span class="se">\</span>
    <span class="nt">-m</span> org.shadowblip.InputManager.CreateCompositeDevice /root/.bash_history
Error: GDBus.Error:org.freedesktop.DBus.Error.Failed: Unable to deserialize: invalid <span class="nb">type</span>: string <span class="s2">"cd /etc/polkit-1/rules.d/"</span>, expected struct CompositeDeviceConfig at line 2 column 1
</code></pre></div>    </div>
    <p>The string <code class="language-plaintext highlighter-rouge">cd /etc/polkit-1/rules.d</code> is an entry from <code class="language-plaintext highlighter-rouge">root</code>’s history file
in this case.</p>
  </li>
</ul>

<h3 id="createtargetdevicein-s-kind"><strong><code class="language-plaintext highlighter-rouge">CreateTargetDevice(in s kind)</code></strong></h3>

<p><a href="https://github.com/ShadowBlip/InputPlumber/blob/v0.67.0/src/dbus/interface/manager.rs#L165">This method</a> allows to create a virtual keyboard input
device like this:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>user <span class="nv">$ </span>gdbus call <span class="nt">-y</span> <span class="nt">-d</span> org.shadowblip.InputPlumber <span class="nt">-o</span> /org/shadowblip/InputPlumber/Manager <span class="se">\</span>
   <span class="nt">-m</span> org.shadowblip.InputManager.CreateTargetDevice keyboard
</code></pre></div></div>

<p>Once the virtual keyboard has been created, key presses can be injected into
the active user session (login terminal or graphical desktop) like this:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>user <span class="nv">$ </span>gdbus call <span class="nt">-y</span> <span class="nt">-d</span> org.shadowblip.InputPlumber <span class="nt">-o</span> /org/shadowblip/InputPlumber/devices/target/keyboard0 <span class="se">\</span>
    <span class="nt">-m</span> org.shadowblip.Input.Keyboard.SendKey KEY_R <span class="nb">true</span>
</code></pre></div></div>

<p>All supported key symbols are found in <a href="https://github.com/ShadowBlip/InputPlumber/blob/v0.67.0/src/dbus/interface/target/keyboard.rs#L64"><code class="language-plaintext highlighter-rouge">keyboard.rs</code></a>.
Using this ability, any user in the system can inject input to an active
desktop session or the active login terminal screen, possibly leading to
arbitrary code execution in the context of the currently logged in user, if
any.</p>

<h1 id="section-suggested-fixes">4) Suggested Fixes</h1>

<p>We suggested the following action items to upstream to improve the security of
the InputPlumber D-Bus API:</p>

<ul>
  <li>Use of the “system bus name” Polkit subject to fix the authentication code.</li>
  <li>Enabling of Polkit authorization by default in the build process.</li>
  <li>Passing of file descriptors instead of path names to D-Bus methods. This way
the complexity of safely accessing client-provided paths is avoided and
various attack scenarios in this area are no longer relevant.</li>
  <li>Addition of documentation pointing out that unauthorized access to the D-Bus
service has security implications.</li>
  <li>Addition of hardening to the <code class="language-plaintext highlighter-rouge">inputplumber</code> systemd service. By using settings
like <code class="language-plaintext highlighter-rouge">ProtectSystem=full</code> the service can be tightened to avoid any unexpected
side effects when things go wrong at the first line of defense.</li>
</ul>

<h1 id="section-bugfixes">5) Upstream Bugfixes</h1>

<p>Upstream mostly followed our suggestions and fixed the issues as follows:</p>

<ul>
  <li>in <a href="https://github.com/ShadowBlip/InputPlumber/commit/4db3b20ad9f5f21a7cbc54a9144443c9c4899249">commit 4db3b20</a> the Polkit subject used for
authentication has been switched to “system bus name”, therefore fixing the
Polkit authentication bypass.</li>
  <li>in <a href="https://github.com/ShadowBlip/InputPlumber/commit/f3854be20099cff564aa9699632f71074f5c96ee">commit f3854be</a> the “Polkit” Cargo feature is
enabled by default.</li>
  <li>in <a href="https://github.com/ShadowBlip/InputPlumber/commit/79f0745b61b588a0ff1d29c8f45d05054ea5f138">commit 79f0745</a> systemd hardening is applied
to the InputPlumber service.</li>
</ul>

<p>All of these fixes are contained in InputPlumber version
<a href="https://github.com/ShadowBlip/InputPlumber/releases/tag/v0.69.0">v0.69.0</a> and later.</p>

<p>Upstream initially wanted to avoid breaking the D-Bus API by switching to file
descriptors instead of path names, as we suggested. We strongly recommended to
do this, however, to avoid various issues that can occur when clients pass
malicious file paths. An upstream developer then <a href="https://github.com/ShadowBlip/InputPlumber/pull/477">created a pull
request</a> which introduces file descriptors in the API.
We provided feedback that this is going in the right direction, but suggested to
also perform checks on the file descriptors passed by clients to make sure they
refer to regular files and have no unusual open flags like <code class="language-plaintext highlighter-rouge">O_PATH</code> set.</p>

<p id="marker-missing-fixes">At the time of publication of this report we noticed that the improvements of
the D-Bus API to use file descriptors have not been merged yet and are not
available in a release. Thus some aspects of the issues described in this
report remain unaddressed, although they are now at least protected by proper
Polkit authentication. Sensitive methods like <code class="language-plaintext highlighter-rouge">CreateCompositeDevice</code> also
require <a href="https://github.com/ShadowBlip/InputPlumber/blob/v0.67.0/rootfs/usr/share/polkit-1/actions/org.shadowblip.InputPlumber.policy#L206">admin privileges to be called</a>, thus
these are mostly defense-in-depth issues, or only relevant when integrators
or admins relax Polkit authentication requirements.</p>

<h1 id="section-cves">6) CVE Assignment</h1>

<p>In agreement with upstream we performed the following CVE assignments
corresponding to this report:</p>

<ul>
  <li>
    <p>CVE-2025-66005: lack of authorization of the InputManager D-Bus interface in
InputPlumber versions before v0.63.0 can lead to local Denial-of-Service,
information leak or even privilege escalation in the context of the
currently active user session.</p>
  </li>
  <li>
    <p>CVE-2025-14338: Polkit authentication disabled by default and a race
condition in the Polkit authorization check in versions before v0.69.0 can
lead to the same issues as in CVE-2025-66005.</p>
  </li>
</ul>

<h1 id="section-disclosure">7) Coordinated Disclosure</h1>

<p>We informed upstream about the security issues on 2025-11-25 and offered
coordinated disclosure. Upstream quickly confirmed the issues and agreed to
follow coordinated disclosure. The developers discussed bugfixes with us, which
they provided in public GitHub pull requests. This way the information about
the issues was not fully private anymore, but we agreed to keep the full
report private for a longer time, until new SteamOS images would be published,
containing a fixed InputPlumber.</p>

<p>We found out only at the time of publication that <a href="#marker-missing-fixes">not all aspects of the
issues have been addressed</a> in the bugfix release.</p>

<p>We want to thank the InputPlumber developers for their cooperation regarding
this report.</p>

<h1 id="8-timeline">8) Timeline</h1>

<table>
  <tbody>
    <tr>
      <td>2025-11-21</td>
      <td>We contacted one of the developers of InputPlumber, asking for the proper security contact for the project.</td>
    </tr>
    <tr>
      <td>2025-11-21</td>
      <td>We got a swift reply and learned that we reached the correct person for security reports already.</td>
    </tr>
    <tr>
      <td>2025-11-25</td>
      <td>We forwarded a detailed report outlining the issues in InputPlumber to upstream, offering coordinated disclosure.</td>
    </tr>
    <tr>
      <td>2025-11-25</td>
      <td>Upstream confirmed the issues and opted for coordinated disclosure.</td>
    </tr>
    <tr>
      <td>2025-12-08</td>
      <td>Upstream pointed us to a couple of public pull requests which should address the issues and asked us to review them.</td>
    </tr>
    <tr>
      <td>2025-12-10</td>
      <td>We provided feedback on the pull requests. The D-Bus API still used client-controlled paths at this point, and we suggested to turn them into file descriptors. We also pointed out that the issues were no longer fully private in light of the public pull requests, but suggested to keep the full report private for longer until an agreed upon date.</td>
    </tr>
    <tr>
      <td>2025-12-10</td>
      <td>We <a href="#section-cves">assigned CVEs</a> for the issues and communicated them to upstream.</td>
    </tr>
    <tr>
      <td>2025-12-12</td>
      <td>Upstream informed us that they wanted to keep the original D-Bus API stable, but agreed to add an additional fix to use file descriptors anyway.</td>
    </tr>
    <tr>
      <td>2025-12-16</td>
      <td>We asked upstream whether they were able to agree on a general publication date for the report by now.</td>
    </tr>
    <tr>
      <td>2025-12-22</td>
      <td>Upstream pointed us to <a href="https://github.com/ShadowBlip/InputPlumber/pull/477">another public GitHub pull request</a> introducing file descriptors in the D-Bus API.</td>
    </tr>
    <tr>
      <td>2025-12-22</td>
      <td>Upstream informed us that the publication date still needed further internal discussions and that they would get back to us.</td>
    </tr>
    <tr>
      <td>2025-12-23</td>
      <td>We provided feedback to upstream about the additional pull request. We generally agreed with the change but suggested to also check file descriptor type and flags on the service side, to avoid unexpected file descriptors being passed by clients.</td>
    </tr>
    <tr>
      <td>2025-12-27</td>
      <td>Upstream informed us that Valve was planning to publish new SteamOS images containing the InputPlumber fixes on January 9, which was agreed upon for general publication date of the full report.</td>
    </tr>
    <tr>
      <td>2025-01-09</td>
      <td>Upstream informed us about publication of the <a href="https://steamcommunity.com/games/1675200/announcements/detail/500594947381003216">new SteamOS images</a>, thanking us for our support.</td>
    </tr>
    <tr>
      <td>2025-01-09</td>
      <td>Publication of this report.</td>
    </tr>
  </tbody>
</table>

<h1 id="9-references">9) References</h1>

<ul>
  <li><a href="https://github.com/ShadowBlip/InputPlumber">InputPlumber GitHub project</a></li>
  <li><a href="https://github.com/ShadowBlip/InputPlumber/releases/tag/v0.69.0">InputPlumber Bugfix Release v0.69.0</a></li>
  <li><a href="https://steamcommunity.com/games/1675200/announcements/detail/500594947381003216">SteamOS Images 3.7.20 Beta</a> containing a fixed InputPlumber</li>
</ul>]]></content><author><name>&lt;a href=&apos;mailto:matthias.gerstner@suse.de&apos;&gt;Matthias Gerstner&lt;/a&gt;, &lt;a href=&apos;mailto:filippo.bonazzi@suse.com&apos;&gt;Filippo Bonazzi (editor)&lt;/a&gt;</name></author><category term="CVE" /><category term="D-Bus" /><category term="Polkit" /><summary type="html"><![CDATA[InputPlumber is a utility for combining Linux input devices into virtual input devices. It includes a D-Bus daemon offering an interface to all users in the system. A lack of D-Bus client authorization in versions before v0.69.0 allows arbitrary local users to inject key presses into active sessions or to perform local Denial-of-Service attacks against InputPlumber.]]></summary></entry><entry><title type="html">Foomuuri: Lack of Client Authorization and Input Verification allow Control over Firewall Configuration (CVE-2025-67603, CVE-2025-67858)</title><link href="https://security.opensuse.org/2026/01/07/foomuuri-lack-of-dbus-authorization.html" rel="alternate" type="text/html" title="Foomuuri: Lack of Client Authorization and Input Verification allow Control over Firewall Configuration (CVE-2025-67603, CVE-2025-67858)" /><published>2026-01-07T00:00:00+00:00</published><updated>2026-01-07T00:00:00+00:00</updated><id>https://security.opensuse.org/2026/01/07/foomuuri-lack-of-dbus-authorization</id><content type="html" xml:base="https://security.opensuse.org/2026/01/07/foomuuri-lack-of-dbus-authorization.html"><![CDATA[<h1 class="no_toc" id="table-of-contents">Table of Contents</h1>

<ul id="markdown-toc">
  <li><a href="#1-introduction" id="markdown-toc-1-introduction">1) Introduction</a></li>
  <li><a href="#section-overview" id="markdown-toc-section-overview">2) Overview of the D-Bus Service</a></li>
  <li><a href="#section-issues" id="markdown-toc-section-issues">3) Security Issues</a>    <ul>
      <li><a href="#section-auth-issue" id="markdown-toc-section-auth-issue">3.1) Lack of Client Authorization</a></li>
      <li><a href="#section-input-verification" id="markdown-toc-section-input-verification">3.2 Missing Input Parameter Verification</a></li>
      <li><a href="#section-umask-issue" id="markdown-toc-section-umask-issue">3.3) Unsafe <code class="language-plaintext highlighter-rouge">umask</code> used in Daemonize Code</a></li>
    </ul>
  </li>
  <li><a href="#section-bugfixes" id="markdown-toc-section-bugfixes">4) Upstream Bugfixes</a></li>
  <li><a href="#section-cves" id="markdown-toc-section-cves">5) CVE Assignment</a></li>
  <li><a href="#section-disclosure" id="markdown-toc-section-disclosure">6) Coordinated Disclosure</a></li>
  <li><a href="#7-timeline" id="markdown-toc-7-timeline">7) Timeline</a></li>
  <li><a href="#8-references" id="markdown-toc-8-references">8) References</a></li>
</ul>

<h1 id="1-introduction">1) Introduction</h1>

<p><a href="https://github.com/FoobarOy/foomuuri">Foomuuri</a> is an nftables-based firewall manager for Linux.
The project includes a D-Bus daemon which offers an API similar to
firewalld. In early December an openSUSE community member <a href="https://bugzilla.suse.com/show_bug.cgi?id=1254385">asked us to review
Foomuuri</a> for addition to openSUSE Tumbleweed.</p>

<p>During the review we quickly noticed a lack of client authorization and input
validation in the implementation of Foomuuri’s D-Bus service. We reported the
issues to upstream and performed coordinated disclosure. Upstream published
<a href="https://github.com/FoobarOy/foomuuri/releases/tag/v0.31">version 0.31</a> of Foomuuri on 2026-01-07 which
contains bugfixes for the security issues.</p>

<p>The <a href="#section-overview">next section</a> provides an overview of the Foomuuri
D-Bus service. <a href="#section-issues">Section 3)</a> discusses the security issues in
detail. <a href="#section-bugfixes">Section 4)</a> provides an overview of the upstream
bugfixes to address the issues. <a href="#section-cves">Section 5)</a> looks into the CVEs
which were assigned. <a href="#section-disclosure">Section 6)</a> gives insight into the
coordinated disclosure process which was established for these findings.</p>

<p>This report is based on <a href="https://github.com/FoobarOy/foomuuri/releases/tag/v0.29">Foomuuri release v0.29</a>.</p>

<h1 id="section-overview">2) Overview of the D-Bus Service</h1>

<p>Foomuuri runs with full root privileges and <a href="https://github.com/FoobarOy/foomuuri/blob/c532cc902a402bbaf88e90a972d078649425f34b/src/foomuuri#L2856">registers a D-Bus
interface</a> under the name”fi.foobar.Foomuuri1”. Optionally a
firewalld drop-in replacement interface is also registered under
“org.fedoraproject.FirewallD1”. Both interfaces hook into the same logic,
however, and there is no need to look at them separately.</p>

<p>There are <a href="https://github.com/FoobarOy/foomuuri/blob/c532cc902a402bbaf88e90a972d078649425f34b/src/foomuuri#L2763">only a few methods</a> provided by the D-Bus
interface: getting the list of available zones and managing the assignment of
network interfaces to zones.</p>

<h1 id="section-issues">3) Security Issues</h1>

<h2 id="section-auth-issue">3.1) Lack of Client Authorization</h2>

<p>There is no authentication layer like Polkit present in the Foomuuri D-Bus
service, and there are also no restrictions <a href="https://github.com/FoobarOy/foomuuri/blob/c532cc902a402bbaf88e90a972d078649425f34b/firewalld/fi.foobar.Foomuuri-FirewallD.conf#L20">on D-Bus configuration
level</a> as to who is allowed to connect to the D-Bus
interfaces provided.</p>

<p>As a result any local user, including low privilege service user accounts or
even <code class="language-plaintext highlighter-rouge">nobody</code>, can invoke the D-Bus interface and change the firewall
configuration. The only state which can be modified this way is the assignment
of interfaces to zones, but this is enough to weaken the firewall
configuration or to perform a limited Denial-of-Service.</p>

<h2 id="section-input-verification">3.2 Missing Input Parameter Verification</h2>

<p>Apart from the lack of access restrictions pointed out above, the input
parameters to the D-Bus methods are not carefully scrutinized. While the <code class="language-plaintext highlighter-rouge">zone</code>
input parameter is at least checked <a href="https://github.com/FoobarOy/foomuuri/blob/c532cc902a402bbaf88e90a972d078649425f34b/src/foomuuri#L2698">against currently configured
zones</a>, no further checks are performed on the
<code class="language-plaintext highlighter-rouge">interface</code> parameter. This means that, e.g. via the “addInterface” D-Bus
method, arbitrary strings can be passed as interface name. There is also
intentionally no check if the specified name corresponds to an existing
network device in the system (to allow seamless coverage of network devices
even before they are added to the system).</p>

<p>One result from this can be log spoofing, since the <code class="language-plaintext highlighter-rouge">interface</code> name is
passed to logging functions unmodified. The string could contain control
characters or newlines, which can manipulate the log.</p>

<p>In <a href="https://github.com/FoobarOy/foomuuri/blob/c532cc902a402bbaf88e90a972d078649425f34b/src/foomuuri#L2692"><code class="language-plaintext highlighter-rouge">DbusCommon.add_interface()</code></a> the possibly
crafted interface name is added to the to-be-generated JSON configuration via
the <code class="language-plaintext highlighter-rouge">out()</code> method. While we did not verify whether this works in practice, a
local attacker could attempt to largely control the JSON configuration passed
to <code class="language-plaintext highlighter-rouge">nftables</code>, by skillfully embedding additional JSON configuration in the
<code class="language-plaintext highlighter-rouge">interface</code> parameter.</p>

<p>We were worried that this could even lead to arbitrary code execution by
abusing features of <code class="language-plaintext highlighter-rouge">nftables</code> like loading external files or plugin code, but
it turned out that there are no such features available in the <code class="language-plaintext highlighter-rouge">nftables</code>
configuration format.</p>

<h2 id="section-umask-issue">3.3) Unsafe <code class="language-plaintext highlighter-rouge">umask</code> used in Daemonize Code</h2>

<p>Foomuuri contains optional support to daemonize itself. Normally this is done
by systemd and the code in question is not invoked. It <a href="https://github.com/FoobarOy/foomuuri/blob/c532cc902a402bbaf88e90a972d078649425f34b/src/foomuuri#L244">contains
logic</a> to set the daemon’s <code class="language-plaintext highlighter-rouge">umask</code> to 0, however, which is a bad
default, since applications or libraries which intend to foster user control of
the file mode of newly created files can pass modes like <code class="language-plaintext highlighter-rouge">0666</code> to <code class="language-plaintext highlighter-rouge">open()</code>,
rendering them world-writable.</p>

<p>Foomuuri does not contain any code paths that create new files, but the <code class="language-plaintext highlighter-rouge">umask</code>
setting is also inherited by child processes, for example. While we did not
think this was a tangible security issue in this form, we suggested to choose a
more conservative value here to prevent future issues.</p>

<h1 id="section-bugfixes">4) Upstream Bugfixes</h1>

<p>We suggested the following fixes to upstream:</p>

<ul>
  <li>restrict access to the D-Bus interfaces to <code class="language-plaintext highlighter-rouge">root</code> only, maybe also to
members of a dedicated opt-in group. Alternatively Polkit could be used for
authentication of callers, which is more effort and complex, however.</li>
  <li>the <code class="language-plaintext highlighter-rouge">interface</code> input parameter should be verified right from the
beginning of each D-Bus method to make sure that it does not contain
any whitespace or special characters and is not longer than <code class="language-plaintext highlighter-rouge">IFNAMSIZ</code> bytes
(which is currently 16 bytes on Linux).</li>
  <li>as an additional hardening measure we also suggested to apply systemd
directives like <code class="language-plaintext highlighter-rouge">ProtectSystem=full</code> to Foomuuri’s systemd services,
to prevent possible privilege escalation should anything go wrong at
the first line of defense.</li>
</ul>

<p>Upstream decided to implement Polkit authentication for Foomuuri’s D-Bus
service and otherwise followed closely our suggestions:</p>

<ul>
  <li>commit <a href="https://github.com/FoobarOy/foomuuri/commit/5944a428f53a132fc343ff6792b1b7539f1c990e">5944a42</a> adds Polkit authentication to the D-Bus
service. Changing firewall settings now requires admin authorization.
The use of Polkit can be disabled in Foomuuri, in which case only clients
with UID 0 are allowed to perform the operations.</li>
  <li>commit <a href="https://github.com/FoobarOy/foomuuri/commit/d1961f420600d133e5f1d3125deb17445e7745ac">d1961f4</a> adds verification of the
<code class="language-plaintext highlighter-rouge">interface</code> parameter to prevent manipulation of the JSON configuration
data.</li>
  <li>commit <a href="https://github.com/FoobarOy/foomuuri/commit/806e11d59c1e582452668cec3b68397e4cbf71b3">806e11d</a> sets the <code class="language-plaintext highlighter-rouge">umask</code> used in the daemonize code
to a more conservative <code class="language-plaintext highlighter-rouge">0o022</code> setting, preventing world- or group-writable
files from coming into existence.</li>
  <li>commit <a href="https://github.com/FoobarOy/foomuuri/commit/5fcf1254537604b0b609047519efedeb7a2fd2cb">5fcf125</a> adds the <code class="language-plaintext highlighter-rouge">ProtectSystem=full</code>
directive to all Foomuuri systemd service units.</li>
</ul>

<p>All of the bugfixes are contained in <a href="https://github.com/FoobarOy/foomuuri/releases/tag/v0.31">version 0.31</a>
of Foomuuri.</p>

<h1 id="section-cves">5) CVE Assignment</h1>

<p>In agreement with upstream we assigned the following two CVEs corresponding to
this report:</p>

<ul>
  <li>
    <p>CVE-2025-67603: lack of client authorization allows arbitrary users to
influence the firewall configuration (<a href="#section-auth-issue">issue 3.1</a>).</p>
  </li>
  <li>
    <p>CVE-2025-67858: a crafted <code class="language-plaintext highlighter-rouge">interface</code> input parameter to D-Bus methods can
lead to integrity loss of the firewall configuration or further unspecified
impact by manipulating the JSON configuration passed to <code class="language-plaintext highlighter-rouge">nft</code>
(<a href="#section-input-verification">issue 3.2</a>).</p>
  </li>
</ul>

<h1 id="section-disclosure">6) Coordinated Disclosure</h1>

<p>We reported these issues to the upstream developer on 2025-12-11, offering
coordinated disclosure. We soon got a reply and discussed the details of the
non-disclosure process. Upstream quickly shared patches with us for review and
we agreed on the final patches already on 2025-12-19. In light of the
approaching Christmas season we agreed on a publication date of 2026-01-07
for general disclosure.</p>

<p>We want to thank the upstream author for the prompt reaction and cooperation
in fixing the issues.</p>

<h1 id="7-timeline">7) Timeline</h1>

<table>
  <tbody>
    <tr>
      <td>2025-12-11</td>
      <td>We contacted the Foomuuri developer by email providing a detailed report about the D-Bus related findings and offered coordinated disclosure.</td>
    </tr>
    <tr>
      <td>2025-12-12</td>
      <td>The upstream author confirmed the issues, agreed to coordinated disclosure and asked us to assign CVEs the way we suggested them. 2026-01-07 was suggested for publication date.</td>
    </tr>
    <tr>
      <td>2025-12-15</td>
      <td>We discussed some additional technical details like the <a href="#section-umask-issue">umask issue</a> and the question of whether arbitrary code execution could result from the ability to control the JSON configuration passed to <code class="language-plaintext highlighter-rouge">nft</code>.</td>
    </tr>
    <tr>
      <td>2025-12-18</td>
      <td>Upstream shared with us a first version of patches for the issues we reported. The patches for minor issues and hardening were already published on GitHub at this point.</td>
    </tr>
    <tr>
      <td>2025-12-19</td>
      <td>We provided feedback on the patches, suggesting minor improvements.</td>
    </tr>
    <tr>
      <td>2025-12-19</td>
      <td>With the fixes ready we discussed whether earlier publication would make sense, but we agreed to stick to the date of 2026-01-07 to accommodate the Christmas holiday season.</td>
    </tr>
    <tr>
      <td>2026-01-07</td>
      <td>Upstream <a href="https://github.com/FoobarOy/foomuuri/releases/tag/v0.31">release v0.31</a> was published.</td>
    </tr>
    <tr>
      <td>2026-01-07</td>
      <td>Publication of this report.</td>
    </tr>
  </tbody>
</table>

<h1 id="8-references">8) References</h1>

<ul>
  <li><a href="https://github.com/FoobarOy/foomuuri">Foomuuri GitHub project</a></li>
  <li><a href="https://github.com/FoobarOy/foomuuri/releases/tag/v0.31">Foomuuri v0.31 Bugfix Release</a></li>
</ul>]]></content><author><name>&lt;a href=&apos;mailto:matthias.gerstner@suse.de&apos;&gt;Matthias Gerstner&lt;/a&gt;, &lt;a href=&apos;mailto:filippo.bonazzi@suse.com&apos;&gt;Filippo Bonazzi (editor)&lt;/a&gt;</name></author><category term="CVE" /><category term="D-Bus" /><summary type="html"><![CDATA[Foomuuri is an nftables-based firewall manager for Linux. It contains a privileged D-Bus service which allows to change the firewall configuration. A lack of D-Bus client authorization and input data verification allow arbitrary local users to completely control the system's firewall configuration in Foomuuri before version 0.31.]]></summary></entry><entry><title type="html">TLP: Polkit Authentication Bypass in Profiles Daemon in Version 1.9.0 (CVE-2025-67859)</title><link href="https://security.opensuse.org/2026/01/07/tlp-polkit-authentication-bypass.html" rel="alternate" type="text/html" title="TLP: Polkit Authentication Bypass in Profiles Daemon in Version 1.9.0 (CVE-2025-67859)" /><published>2026-01-07T00:00:00+00:00</published><updated>2026-01-07T00:00:00+00:00</updated><id>https://security.opensuse.org/2026/01/07/tlp-polkit-authentication-bypass</id><content type="html" xml:base="https://security.opensuse.org/2026/01/07/tlp-polkit-authentication-bypass.html"><![CDATA[<h1 class="no_toc" id="table-of-contents">Table of Contents</h1>

<ul id="markdown-toc">
  <li><a href="#1-introduction" id="markdown-toc-1-introduction">1) Introduction</a></li>
  <li><a href="#section-overview" id="markdown-toc-section-overview">2) Overview of the TLP Daemon</a></li>
  <li><a href="#section-issues" id="markdown-toc-section-issues">3) Security Issues</a>    <ul>
      <li><a href="#subsection-polkit-bypass" id="markdown-toc-subsection-polkit-bypass">3.1 Polkit Authorization Check can be Bypassed</a></li>
      <li><a href="#subsection-predictable-cookies" id="markdown-toc-subsection-predictable-cookies">3.2 Predictable Cookie Values in HoldProfile Method Allow to Release Holds</a></li>
      <li><a href="#33-non-integer-cookie-parameter-in-releaseprofile-method-leads-to-unhandled-exception" id="markdown-toc-33-non-integer-cookie-parameter-in-releaseprofile-method-leads-to-unhandled-exception">3.3 Non-Integer <code class="language-plaintext highlighter-rouge">cookie</code> Parameter in “ReleaseProfile” Method Leads to Unhandled Exception</a></li>
      <li><a href="#subsection-unlimited-holds" id="markdown-toc-subsection-unlimited-holds">3.4 Unlimited Number of Profile Holds Provides DoS Attack Surface</a></li>
    </ul>
  </li>
  <li><a href="#section-cves" id="markdown-toc-section-cves">4) CVE Assignment</a></li>
  <li><a href="#section-disclosure" id="markdown-toc-section-disclosure">5) Coordinated Disclosure</a></li>
  <li><a href="#6-timeline" id="markdown-toc-6-timeline">6) Timeline</a></li>
  <li><a href="#7-references" id="markdown-toc-7-references">7) References</a></li>
</ul>

<h1 id="1-introduction">1) Introduction</h1>

<p><a href="https://linrunner.de/tlp">TLP</a> is a utility for saving laptop battery power when
running Linux (note: the TLP acronym has <a href="https://linrunner.de/tlp/faq/misc.html#what-does-tlp-stand-for">no special
meaning</a>). In version 1.9.0 of TLP a profiles daemon
similar to <a href="https://gitlab.gnome.org/Infrastructure/Mirrors/lorry-mirrors/gitlab_freedesktop_org/hadess/power-profiles-daemon">GNOME’s power profiles daemon</a> has been added to the
project, providing a D-Bus API for controlling some of TLP’s settings.</p>

<p>Our SUSE TLP package maintainer <a href="https://bugzilla.suse.com/show_bug.cgi?id=1254768">asked us for a review</a>
of the changes contained in the new TLP release, leading us to discover
issues in the Polkit authentication logic used in TLP’s profiles daemon, which
allow a complete authentication bypass. While looking into the daemon we also
found some additional security problems in the area of local Denial-of-Service
(DoS).</p>

<p>We reported the issues to upstream in December and performed coordinated
disclosure. <a href="https://github.com/linrunner/TLP/releases/tag/1.9.1">TLP release 1.9.1</a> contains fixes
for the issues described below. This report is based on <a href="https://linrunner.de/tlp/news.html#tlp-1-9-released">TLP
1.9.0</a>.</p>

<p>The <a href="#section-overview">next section</a> provides a quick overview of the TLP
power daemon. <a href="#section-issues">Section 3</a> discusses the security issues we
discovered in detail. <a href="#section-cves">Section 4</a> looks into the CVEs we
assigned. <a href="#section-disclosure">Section 5</a> provides a summary of the
coordinated disclosure process we followed for these findings.</p>

<h1 id="section-overview">2) Overview of the TLP Daemon</h1>

<p>The new TLP power daemon is implemented in <a href="https://github.com/linrunner/TLP/blob/1.9.0/tlp-pd.in">a Python script of moderate
size</a>. The daemon runs with full root privileges and accepts
D-Bus client connections from arbitrary users. For authorization of clients a
<a href="https://github.com/linrunner/TLP/blob/main/tlp-pd.policy">Polkit policy</a> defines a couple of actions which are
checked in the daemon’s <a href="https://github.com/linrunner/TLP/blob/1.9.0/tlp-pd.in#L675"><code class="language-plaintext highlighter-rouge">_check_polkit_auth() function</code></a>.
Some of these actions are allowed for local users in an active session without
providing further credentials, others require admin credentials.</p>

<h1 id="section-issues">3) Security Issues</h1>

<h2 id="subsection-polkit-bypass">3.1 Polkit Authorization Check can be Bypassed</h2>

<p>The <a href="https://github.com/linrunner/TLP/blob/1.9.0/tlp-pd.in#L675"><code class="language-plaintext highlighter-rouge">check_polkit_auth()</code> function</a> relies on Polkit’s
“unix-process” subject in an unsafe way. The function obtains the caller’s PID
and passes this information to the Polkit daemon for authorization, which is
inherently subject to a race condition: at the time the Polkit daemon looks up
the provided PID, the process can already have been replaced by a different
one with higher privileges than the D-Bus client actually has.</p>

<p>As a result of this, the Polkit authorization check in the TLP power daemon
can be bypassed by local users, allowing them to arbitrarily control the power
profile in use as well as the daemon’s log settings.</p>

<p>This is a well-known issue when using the “unix-process” Polkit subject which
was assigned <a href="https://nvd.nist.gov/vuln/detail/CVE-2013-4288">CVE-2013-4288</a> in the past. For this reason the
subject has been marked as deprecated in Polkit. The “unix-process” subject
<a href="https://github.com/polkit-org/polkit/commit/9295e289cdb1b6cf2747ecf07054230e15edb385">is seeing new use</a> these days, however, when
combined with the use of Linux PID file descriptors, which are not affected by
the race condition.</p>

<h3 id="upstream-bugfix">Upstream Bugfix</h3>

<p>We suggested to upstream to switch to Polkit’s D-Bus “system bus name” subject
instead, which is a robust way to authenticate D-Bus clients based on the UNIX
domain socket the client uses to connect to the bus. This is what upstream did
in commit <a href="https://github.com/linrunner/TLP/commit/08aa9cdb135b3563b2fb6eb4e0ecb638df5e7c09">08aa9cd</a>.</p>

<h2 id="subsection-predictable-cookies">3.2 Predictable Cookie Values in HoldProfile Method Allow to Release Holds</h2>

<p>The D-Bus methods “HoldProfile” and “ReleaseProfile” can be used by locally
logged-in users without admin authentication and allow to establish a
“profile hold”, preventing the profile from being automatically switched until
it is released again.</p>

<p>The “HoldProfile” method returns a cookie value to the caller which needs to
be presented to the “ReleaseProfile” method again to release it. This
cookie value is a simple integer which starts counting at zero and <a href="https://github.com/linrunner/TLP/blob/1.9.0/tlp-pd.in#L187">is
incremented</a> for each call to “HoldProfile”. This makes
the cookie value predictable and allows other, unrelated users or applications
to release an active profile hold by trying to guess the cookie value in use.</p>

<h3 id="upstream-bugfix-1">Upstream Bugfix</h3>

<p>We suggested to upstream to make the cookie value unpredictable by generating
a random number. This is what upstream did in commit
<a href="https://github.com/linrunner/TLP/commit/a88002ef26f58a2caec88d09a3f70e8b5b2f8585">a88002e</a>.</p>

<h2 id="33-non-integer-cookie-parameter-in-releaseprofile-method-leads-to-unhandled-exception">3.3 Non-Integer <code class="language-plaintext highlighter-rouge">cookie</code> Parameter in “ReleaseProfile” Method Leads to Unhandled Exception</h2>

<p>As described in the previous section, the <a href="https://github.com/linrunner/TLP/blob/1.9.0/tlp-pd.in#L223">“ReleaseProfile” D-Bus
method</a> expects an integer <code class="language-plaintext highlighter-rouge">cookie</code> parameter as input.
The Python D-Bus framework used to implement the method allows clients to pass
non-integer types as <code class="language-plaintext highlighter-rouge">cookie</code>, however, which causes an exception to be thrown
in the daemon. This does not lead to the daemon exiting, however, since the
framework catches the exception.</p>

<p>The issue can be reproduced via the following command line:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>user<span class="nv">$ </span>dbus-send <span class="nt">--system</span> <span class="nt">--dest</span><span class="o">=</span>org.freedesktop.UPower.PowerProfiles <span class="se">\</span>
      <span class="nt">--type</span><span class="o">=</span>method_call <span class="nt">--print-reply</span> /org/freedesktop/UPower/PowerProfiles <span class="se">\</span>
      org.freedesktop.UPower.PowerProfiles.ReleaseProfile string:test
Error org.freedesktop.DBus.Python.ValueError: Traceback <span class="o">(</span>most recent call
last<span class="o">)</span>:
  File <span class="s2">"/usr/lib/python3.13/site-packages/dbus/service.py"</span>, line 712, <span class="k">in
</span>_message_cb
    retval <span class="o">=</span> candidate_method<span class="o">(</span>self, <span class="k">*</span>args, <span class="k">**</span>keywords<span class="o">)</span>
  File <span class="s2">"/usr/sbin/tlp-pd"</span>, line 223, <span class="k">in </span>ReleaseProfile
    cookie <span class="o">=</span> int<span class="o">(</span>cookie<span class="o">)</span>
ValueError: invalid literal <span class="k">for </span>int<span class="o">()</span> with base 10: dbus.String<span class="o">(</span><span class="s1">'test'</span><span class="o">)</span>
</code></pre></div></div>

<h3 id="upstream-bugfix-2">Upstream Bugfix</h3>

<p>While this is not strictly a security issue, we still suggested to make the
daemon more robust by actively catching type mismatch issues for the <code class="language-plaintext highlighter-rouge">cookie</code>
input parameter. Upstream followed this suggestion and implemented it in the
<a href="https://github.com/linrunner/TLP/commit/a88002ef26f58a2caec88d09a3f70e8b5b2f8585">same commit</a> as above which introduces unpredictable
cookie values.</p>

<h2 id="subsection-unlimited-holds">3.4 Unlimited Number of Profile Holds Provides DoS Attack Surface</h2>

<p>The profile hold mechanism described in <a href="#subsection-predictable-cookies">section
3.2</a> allows local users in an active session
to create an unlimited number of profile holds without admin authentication.
This can lead to resource exhaustion in the TLP power daemon, since an integer
is entered into a Python dictionary along with arbitrary strings <code class="language-plaintext highlighter-rouge">reason</code> and
<code class="language-plaintext highlighter-rouge">application_id</code> which are also supplied by the client. This API thus
offers Denial-of-Service attack surface.</p>

<p>We found a <a href="https://gitlab.freedesktop.org/upower/power-profiles-daemon/-/issues/47#note_1088794">similar issue</a> in <a href="https://gitlab.gnome.org/Infrastructure/Mirrors/lorry-mirrors/gitlab_freedesktop_org/hadess/power-profiles-daemon">GNOME’s power profile
daemon</a> some years ago, but GNOME upstream disagreed with our
analysis at the time, which is why SUSE distributions are applying <a href="https://build.opensuse.org/projects/GNOME:Next/packages/power-profiles-daemon/files/hold-profile-hardening.patch?expand=1">a custom
patch</a> to limit the number parallel profile holds.</p>

<h3 id="upstream-bugfix-3">Upstream Bugfix</h3>

<p>We asked upstream whether there are any valid use cases for supporting a large
number of profile holds in parallel, and it turns out that the typical use
case is only to support a single profile hold at any given time. Thus upstream
agreed to restrict the number of profile holds to a maximum of 16, which is
implemented in <a href="https://github.com/linrunner/TLP/commit/6a637c9b32fbcbe5080ccd4af0d3d3ec388959c3">commit 6a637c9</a>.</p>

<h1 id="section-cves">4) CVE Assignment</h1>

<p>We assigned CVE-2025-67859 to track <a href="#subsection-polkit-bypass">issue
3.1 (Polkit authentication bypass)</a>. Issues <a href="#subsection-predictable-cookies">3.2
(predictable cookie values)</a> and <a href="#subsection-unlimited-holds">3.4
(unlimited number of profile holds)</a> would
formally also justify CVE assignments; their severity is low, however, and we
agreed with upstream to focus on the main aspect of the Polkit authentication
bypass.</p>

<h1 id="section-disclosure">5) Coordinated Disclosure</h1>

<p>We reached out to the upstream author on December 16 with details about the
issues and offered coordinated disclosure. Upstream confirmed the issues and
accepted coordinated disclosure. We discussed patches and further details over
the course of the following two weeks. Due to the approaching Christmas
holiday season we decided to set the general publication date to January 7.</p>

<p>We want to express our thanks to the TLP upstream author for the smooth
cooperation in handling these issues.</p>

<h1 id="6-timeline">6) Timeline</h1>

<table>
  <tbody>
    <tr>
      <td>2025-12-16</td>
      <td>We reached out to the upstream developer by email providing a detailed report and offered coordinated disclosure.</td>
    </tr>
    <tr>
      <td>2025-12-17</td>
      <td>We received a reply discussing details of the report. Coordinated disclosure was established with a preliminary publication date set to 2026-01-27.</td>
    </tr>
    <tr>
      <td>2025-12-20</td>
      <td>We received a set of patches from upstream for review. 2026-01-07 was suggested as new publication date.</td>
    </tr>
    <tr>
      <td>2025-12-23</td>
      <td>We provided positive feedback on the patches and agreed to the new publication date. We also pointed out the additional problem of the unlimited number of profile holds (<a href="#subsection-unlimited-holds">issue 3.4</a>).</td>
    </tr>
    <tr>
      <td>2025-12-25</td>
      <td>We received a follow-up patch from upstream limiting the number of profile holds.</td>
    </tr>
    <tr>
      <td>2025-12-29</td>
      <td>We reviewed the follow-up patch and provided positive feedback to upstream.</td>
    </tr>
    <tr>
      <td>2025-01-07</td>
      <td>Upstream published <a href="https://github.com/linrunner/TLP/releases/tag/1.9.1">bugfix release 1.9.1</a> as planned.</td>
    </tr>
    <tr>
      <td>2025-01-07</td>
      <td>Publication of this report.</td>
    </tr>
  </tbody>
</table>

<h1 id="7-references">7) References</h1>

<ul>
  <li><a href="https://linrunner.de/tlp">TLP Website</a></li>
  <li><a href="https://github.com/linrunner/TLP.git">TLP GitHub project</a></li>
  <li><a href="https://github.com/linrunner/TLP/releases/tag/1.9.1">TLP Bugfix Release 1.9.1</a></li>
  <li><a href="https://bugzilla.suse.com/show_bug.cgi?id=1254768">openSUSE Bugzilla review bug for TLP 1.9.1</a></li>
</ul>]]></content><author><name>&lt;a href=&apos;mailto:matthias.gerstner@suse.de&apos;&gt;Matthias Gerstner&lt;/a&gt;, &lt;a href=&apos;mailto:filippo.bonazzi@suse.com&apos;&gt;Filippo Bonazzi (editor)&lt;/a&gt;</name></author><category term="CVE" /><category term="D-Bus" /><category term="Polkit" /><summary type="html"><![CDATA[TLP is a utility for saving laptop battery power when running Linux. In version 1.9.0 of TLP a profiles daemon has been added to the project, which provides a D-Bus interface for controlling different power profiles. An unsafe use of the Polkit authentication API in this daemon allows local users to bypass authorization and gain arbitrary control over power profiles and log level settings of TLP. While looking into the new daemon we also found a few other security issues in the area of local Denial-of-Service.]]></summary></entry><entry><title type="html">smb4k: Major Vulnerabilities in KAuth Helper (CVE-2025-66002, CVE-2025-66003)</title><link href="https://security.opensuse.org/2025/12/10/smb4k-major-issues-in-kauth-helper.html" rel="alternate" type="text/html" title="smb4k: Major Vulnerabilities in KAuth Helper (CVE-2025-66002, CVE-2025-66003)" /><published>2025-12-10T00:00:00+00:00</published><updated>2025-12-10T00:00:00+00:00</updated><id>https://security.opensuse.org/2025/12/10/smb4k-major-issues-in-kauth-helper</id><content type="html" xml:base="https://security.opensuse.org/2025/12/10/smb4k-major-issues-in-kauth-helper.html"><![CDATA[<h1 class="no_toc" id="table-of-contents">Table of Contents</h1>

<ul id="markdown-toc">
  <li><a href="#1-introduction" id="markdown-toc-1-introduction">1) Introduction</a></li>
  <li><a href="#section-overview" id="markdown-toc-section-overview">2) Overview of the Privileged Mount Helper</a></li>
  <li><a href="#section-mount-problems" id="markdown-toc-section-mount-problems">3) Problems in <code class="language-plaintext highlighter-rouge">Smb4KMountHelper::mount()</code></a>    <ul>
      <li><a href="#subsection-mount-arbitrary-dir" id="markdown-toc-subsection-mount-arbitrary-dir">3.1) Arbitrary Target Directories can be used for Mounting Network Shares</a></li>
      <li><a href="#subsection-mount-arbitrary-args" id="markdown-toc-subsection-mount-arbitrary-args">3.2) Arbitrary Command Line Arguments can be Passed to <code class="language-plaintext highlighter-rouge">mount.cifs</code></a></li>
      <li><a href="#33-clients-can-control-the-krb5ccname-environment-variable-passed-to-mountcifs" id="markdown-toc-33-clients-can-control-the-krb5ccname-environment-variable-passed-to-mountcifs">3.3) Clients can Control the <code class="language-plaintext highlighter-rouge">KRB5CCNAME</code> Environment Variable Passed To <code class="language-plaintext highlighter-rouge">mount.cifs</code></a></li>
    </ul>
  </li>
  <li><a href="#section-unmount-problems" id="markdown-toc-section-unmount-problems">4) Problems in <code class="language-plaintext highlighter-rouge">Smb4KMountHelper::unmount()</code></a>    <ul>
      <li><a href="#subsection-umount-arbitrary-dir" id="markdown-toc-subsection-umount-arbitrary-dir">4.1) Missing <code class="language-plaintext highlighter-rouge">return</code> Statement on Mount Path Verification Failure</a></li>
      <li><a href="#subsection-umount-arbitrary-args" id="markdown-toc-subsection-umount-arbitrary-args">4.2) Arbitrary Command Line Parameters can be Passed to <code class="language-plaintext highlighter-rouge">umount</code></a></li>
      <li><a href="#subsection-kmountpoint" id="markdown-toc-subsection-kmountpoint">4.3) Race Conditions Affecting <code class="language-plaintext highlighter-rouge">KMountPoint::currentMountPoints()</code></a></li>
      <li><a href="#44-arbitrary-network-share-mounts-can-be-unmounted" id="markdown-toc-44-arbitrary-network-share-mounts-can-be-unmounted">4.4) Arbitrary Network Share Mounts can be Unmounted</a></li>
    </ul>
  </li>
  <li><a href="#section-remarks" id="markdown-toc-section-remarks">5) Other Remarks</a>    <ul>
      <li><a href="#51-superfluous-mh_command-client-parameter" id="markdown-toc-51-superfluous-mh_command-client-parameter">5.1) Superfluous <code class="language-plaintext highlighter-rouge">mh_command</code> Client Parameter</a></li>
      <li><a href="#52-redundant-online-check-code" id="markdown-toc-52-redundant-online-check-code">5.2) Redundant “online check” Code</a></li>
      <li><a href="#53-mountcifs-and-umount-follow-symbolic-links" id="markdown-toc-53-mountcifs-and-umount-follow-symbolic-links">5.3) <code class="language-plaintext highlighter-rouge">mount.cifs</code> and <code class="language-plaintext highlighter-rouge">umount</code> Follow Symbolic Links</a></li>
    </ul>
  </li>
  <li><a href="#section-suggested-fixes" id="markdown-toc-section-suggested-fixes">6) Suggested Fixes</a></li>
  <li><a href="#section-bugfix" id="markdown-toc-section-bugfix">7) Upstream Bugfix</a></li>
  <li><a href="#section-workarounds" id="markdown-toc-section-workarounds">8) Possible Workarounds</a></li>
  <li><a href="#section-reproducers" id="markdown-toc-section-reproducers">9) Reproducers</a></li>
  <li><a href="#section-cves" id="markdown-toc-section-cves">10) CVE Assignment</a></li>
  <li><a href="#section-disclosure" id="markdown-toc-section-disclosure">11) Coordinated Disclosure</a></li>
  <li><a href="#12-timeline" id="markdown-toc-12-timeline">12) Timeline</a></li>
  <li><a href="#13-references" id="markdown-toc-13-references">13) References</a></li>
</ul>

<h1 id="1-introduction">1) Introduction</h1>

<p><a href="https://invent.kde.org/network/smb4k.git">smb4k</a> is a KDE desktop related utility which allows
unprivileged mounting of Samba/CIFS network shares. The SUSE security team
reviewed its privileged KAuth helper component <a href="https://bugzilla.suse.com/show_bug.cgi?id=1033300">already in
2017</a> which led to <a href="https://bugzilla.suse.com/show_bug.cgi?id=1036244">the discovery of
CVE-2017-8422</a> (general KAuth authentication bypass)
<a href="https://bugzilla.suse.com/show_bug.cgi?id=1036245">and CVE-2017-8849</a> (local root exploit via smb4k mount
helper).</p>

<p>This September <a href="https://bugzilla.suse.com/show_bug.cgi?id=1249004">we were asked to reconsider</a> smb4k
for inclusion in openSUSE Tumbleweed. The resulting review showed that the
mount helper still lacks input validation, is affected by race conditions and
has a bug in its existing verification logic. This leads to local attack
vectors which allow Denial-of-Service or even a local root exploit.</p>

<p>Many Linux distributions and also some BSDs are potentially affected by the
issues described in this report. We offered coordinated disclosure to upstream
and the maximum 90 days non-disclosure period was fully spent to arrive at a
patch which addresses all the issues. This patch is found in <a href="https://invent.kde.org/network/smb4k/-/commit/0dea60194ab6eb8f6e34ca2e6cb0f97b90c46f1e">commit
0dea60194a</a>, which is part of the <a href="https://sourceforge.net/p/smb4k/blog/2025/12/smb4k-405-security-bug-fix-release">4.0.5 bugfix
release</a> of smb4k.</p>

<p>The <a href="#section-overview">following section</a> provides a short overview of the
privileged mount helper. <a href="#section-mount-problems">Section 3</a> looks into the
problems found in the helper’s mount method. <a href="#section-unmount-problems">Section
4</a> in turn looks into the issues found in the
helper’s unmount method. <a href="#section-remarks">Section 5</a> contains further
remarks on the helper’s code quality and security concerns. <a href="#section-suggested-fixes">Section
6</a> discusses the fixes we suggested to upstream to
address the issues. <a href="#section-bugfix">Section 7</a> gives details about the bugfix
which was finally implemented by upstream. <a href="#section-workarounds">Section 8</a>
suggests possible workarounds that can be applied to avoid the issues found in
this report.  <a href="#section-reproducers">Section 9</a> provides reproducers for the
issues.</p>

<p>This report is based on <a href="https://invent.kde.org/network/smb4k/-/tags/4.0.4">smb4k release 4.0.4</a>.</p>

<h1 id="section-overview">2) Overview of the Privileged Mount Helper</h1>

<p>The problematic privileged mount helper component of smb4k is relatively small
and can be found in the file <a href="https://invent.kde.org/network/smb4k/-/blob/4.0.4/helpers/smb4kmounthelper.cpp?ref_type=tags">smb4kmounthelper.cpp</a>. The
helper runs with full root privileges and implements two KAuth actions
accessible via D-Bus: mounting and unmounting a network share. Both actions
are allowed for local users in active sessions without authentication, based
on the Polkit <code class="language-plaintext highlighter-rouge">yes</code> setting.</p>

<h1 id="section-mount-problems">3) Problems in <code class="language-plaintext highlighter-rouge">Smb4KMountHelper::mount()</code></h1>

<h2 id="subsection-mount-arbitrary-dir">3.1) Arbitrary Target Directories can be used for Mounting Network Shares</h2>

<p>The helper does not impose any restrictions on the target directory
where the desired Samba share will be mounted. This means the share can
also be mounted over <code class="language-plaintext highlighter-rouge">/bin</code>, for example. Should the client have control
over the contents of the network share, then this allows for a local root
exploit by placing crafted binaries e.g. for <code class="language-plaintext highlighter-rouge">/bin/bash</code> on the share, which
are bound to be executed by privileged processes at some point.</p>

<p>If the share’s content cannot be controlled by the attacker, then this serves
as a local Denial-of-Service attack vector, as vital system programs will
become inaccessible.</p>

<p>To fix this, we suggest to only allow mounting of network shares in a
pre-defined location which is not controlled by unprivileged users.</p>

<h2 id="subsection-mount-arbitrary-args">3.2) Arbitrary Command Line Arguments can be Passed to <code class="language-plaintext highlighter-rouge">mount.cifs</code></h2>

<p>The client can specify arbitrary additional command line arguments in the
<code class="language-plaintext highlighter-rouge">mh_options</code> parameter, which <a href="https://invent.kde.org/network/smb4k/-/blob/4.0.4/helpers/smb4kmounthelper.cpp?ref_type=tags#L73">will be passed to the <code class="language-plaintext highlighter-rouge">mount.cifs</code>
program</a>. The command line constructed by the mount helper
looks like this:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/sbin/mount.cifs &lt;URL&gt; &lt;mountpoint&gt; &lt;options&gt;...
</code></pre></div></div>

<p>All of these arguments, except for the path to the <code class="language-plaintext highlighter-rouge">mount.cifs</code> program
itself, are actually controlled by the client. It is not the generic <code class="language-plaintext highlighter-rouge">mount</code>
program which is invoked here, otherwise the client could already perform
arbitrary mounts in the system. Instead the attacker is restricted to what the
special-purpose <code class="language-plaintext highlighter-rouge">mount.cifs</code> binary provides.</p>

<p>The <code class="language-plaintext highlighter-rouge">mount.cifs</code> program supports <a href="https://man7.org/linux//man-pages/man8/mount.cifs.8.html">a plethora of mount
options</a>. Investigating the effect of each one would go
beyond the scope of this report. There is one simple privilege escalation
vector, however: passing <code class="language-plaintext highlighter-rouge">filemode=04777,uid=0</code> to the command line results in
every file on the network share mount receiving setuid-root permissions. If
the content of the network share is controlled by the attacker, then this can
easily be used to introduce an attacker-controlled setuid-root program into
the system. This would then allow for a local root exploit even if <a href="#subsection-mount-arbitrary-dir">issue
3.1)</a> would be fixed.</p>

<p>Other <code class="language-plaintext highlighter-rouge">mount.cifs</code> options like <code class="language-plaintext highlighter-rouge">port=&lt;port&gt;</code> could be used to direct the
kernel to a CIFS server controlled by the attacker itself, listening on an
unprivileged port on localhost. This way a local attacker could provide the
necessary crafted network share for executing the exploits described in this
report on its own, without relying on external network resources.</p>

<p>To fix this, we suggest to restrict the <code class="language-plaintext highlighter-rouge">mh_options</code> to a whitelist of allowed
parameters, and also verify the options’ values in case they can contain
problematic settings.</p>

<h2 id="33-clients-can-control-the-krb5ccname-environment-variable-passed-to-mountcifs">3.3) Clients can Control the <code class="language-plaintext highlighter-rouge">KRB5CCNAME</code> Environment Variable Passed To <code class="language-plaintext highlighter-rouge">mount.cifs</code></h2>

<p>The client can provide an arbitrary path in the <code class="language-plaintext highlighter-rouge">mh_krb5ticket</code> parameter;
the mount helper <a href="https://invent.kde.org/network/smb4k/-/blob/4.0.4/helpers/smb4kmounthelper.cpp?ref_type=tags#L97">will place this path into the <code class="language-plaintext highlighter-rouge">KRB5CCNAME</code> environment
variable</a> for the <code class="language-plaintext highlighter-rouge">mount.cifs</code> child process. This is
to allow use of the client’s Kerberos credentials for mounting the network
share.</p>

<p>The client can pass a path pointing to file system locations normally not
accessible to it. In a multi-user scenario this would allow, for
example, to hijack another user’s Kerberos credentials, by passing a path to
the credentials cache of the other user. It might also lead to information
leaks of files like <code class="language-plaintext highlighter-rouge">/etc/shadow</code>, should <code class="language-plaintext highlighter-rouge">mount.cifs</code> output file content to
the system logs or on stderr (the output of which is returned to the client
via D-Bus).</p>

<p>Furthermore, this path could be used for file existence tests or for a local
Denial-of-Service attack (by pointing to special files like <code class="language-plaintext highlighter-rouge">/dev/zero</code> or a
named FIFO pipe).</p>

<p>To fix this, we recommend not to pass a path, but an already open file
descriptor from the client to the helper, to avoid the opening of arbitrary
files with root privileges.</p>

<h1 id="section-unmount-problems">4) Problems in <code class="language-plaintext highlighter-rouge">Smb4KMountHelper::unmount()</code></h1>

<h2 id="subsection-umount-arbitrary-dir">4.1) Missing <code class="language-plaintext highlighter-rouge">return</code> Statement on Mount Path Verification Failure</h2>

<p>This is similar to <a href="#subsection-mount-arbitrary-dir">issue 3.1)</a> above
regarding mounting. In <a href="https://invent.kde.org/network/smb4k/-/blob/4.0.4/helpers/smb4kmounthelper.cpp?ref_type=tags#L177">smb4kmounthelper.cpp line
177</a> there is an <code class="language-plaintext highlighter-rouge">if</code> block that acts on the
situation when the <code class="language-plaintext highlighter-rouge">mh_mountpoint</code> path supplied by the client does not match
any of the available Samba mounts returned from
<code class="language-plaintext highlighter-rouge">KMountPoint::currentMountPoints()</code>.</p>

<p>The problem is that this <code class="language-plaintext highlighter-rouge">if</code> block only sets an error message, but does not
actually terminate the function execution with <code class="language-plaintext highlighter-rouge">return</code>. This means the
verification is ineffective and local users can unmount arbitrary file systems
despite the check.</p>

<p>This is a major local Denial-of-Service attack vector, which can lead to a
complete system outage. In some special contexts it might even allow
information leaks or privilege escalation, when file system locations have been
made inaccessible by mounting other file systems on top (we can imagine
something like this e.g. in the context of container setups).</p>

<h2 id="subsection-umount-arbitrary-args">4.2) Arbitrary Command Line Parameters can be Passed to <code class="language-plaintext highlighter-rouge">umount</code></h2>

<p>Similar to <a href="#subsection-mount-arbitrary-args">issue 3.2)</a> above, the privileged
helper forwards arbitrary command line parameters provided by the client in
<code class="language-plaintext highlighter-rouge">mh_options</code> to the command line of the <code class="language-plaintext highlighter-rouge">umount</code> program. This happens in
<a href="https://invent.kde.org/network/smb4k/-/blob/4.0.4/helpers/smb4kmounthelper.cpp?ref_type=tags#L187">smb4kmounthelper.cpp line 187</a>. Basically the <code class="language-plaintext highlighter-rouge">umount</code>
program will be invoked like this:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/sbin/umount &lt;options&gt;... &lt;mount-point&gt;
</code></pre></div></div>

<p>Assuming <a href="#subsection-umount-arbitrary-dir">issue 4.1)</a> would be fixed, the
<code class="language-plaintext highlighter-rouge">&lt;mount-point&gt;</code> parameter cannot be chosen arbitrarily by the client, but must
match an existing “cifs”, “smbfs” or “smb3” type mount path. As long as such a
mount path exists, the client can pass arbitrary additional mount points as
“options”, which will then be unmounted as well. This is a lighter variant of
issue 4.1), leading to local Denial-of-Service if the described pre-condition
is fulfilled.</p>

<p>Apart from this, <code class="language-plaintext highlighter-rouge">umount</code> offers <a href="https://man7.org/linux/man-pages/man8/umount.8.html">various options</a> that
can influence the way it operates. One option that sticks out is <code class="language-plaintext highlighter-rouge">-N
--namespace ns</code>, which causes the program to unmount the file system in an
arbitrary mount namespace. This could impact privileged processes, other
users’ containers or jailed processes.</p>

<p>To fix this, we suggest to restrict the <code class="language-plaintext highlighter-rouge">mh_options</code> to a whitelist of allowed
parameters.</p>

<h2 id="subsection-kmountpoint">4.3) Race Conditions Affecting <code class="language-plaintext highlighter-rouge">KMountPoint::currentMountPoints()</code></h2>

<p>This is not directly an issue in smb4k itself, but an issue in the <a href="https://invent.kde.org/frameworks/kio">KIO
library</a> which implements the <code class="language-plaintext highlighter-rouge">KMountPoint</code> API. During our
tests we used version <a href="https://invent.kde.org/frameworks/kio/-/tree/v6.17.0?ref_type=tags">v6.17.0</a> of this library.</p>

<p>The mount helper’s <code class="language-plaintext highlighter-rouge">umount()</code> function <a href="https://invent.kde.org/network/smb4k/-/blob/4.0.4/helpers/smb4kmounthelper.cpp?ref_type=tags#L163">attempts to verify</a>
the input path provided by the client by comparing it against current mounts
in the system as reported by the kernel. Only active “cifs”, “smbfs” and
“smb3” file system mounts are supposed to be unmounted. To this end the
current list of mounted file systems is obtained from</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="n">KMountPoint</span><span class="o">::</span><span class="n">currentMountPoints</span><span class="p">(</span><span class="n">KMountPoint</span><span class="o">::</span><span class="n">BasicInfoNeeded</span> <span class="o">|</span> <span class="n">KMountPoint</span><span class="o">::</span><span class="n">NeedMountOptions</span><span class="p">);</span>
</code></pre></div></div>

<p>The implementation of <code class="language-plaintext highlighter-rouge">currentMountPoints()</code> relies on the libmount
library <a href="https://invent.kde.org/frameworks/kio/-/blob/v6.17.0/src/core/kmountpoint.cpp?ref_type=tags#L341">to retrieve a list of mount points</a>. The
libmount library provides a proven implementation for safely parsing
files like <code class="language-plaintext highlighter-rouge">/proc/self/mountinfo</code>, which we reviewed ourselves a few years
ago and deemed robust. After safely obtaining the information from
libmount, the KIO library performs some actions on top, however, which
can lead to security relevant issues.</p>

<p>One minor issue is found in <a href="https://invent.kde.org/frameworks/kio/-/blob/v6.17.0/src/core/kmountpoint.cpp?ref_type=tags#L365">kmountpoint.cpp line 365</a>, where
<code class="language-plaintext highlighter-rouge">stat()</code> is called on the target mount directory of each mount entry. This
potentially accesses untrusted paths, also from FUSE file systems, which could
in some cases cause a local Denial-of-Service if <code class="language-plaintext highlighter-rouge">stat()</code> blocks. Also, the
supposed mount point could be unmounted by the time the <code class="language-plaintext highlighter-rouge">stat()</code> call is
performed, allowing the path to point to an arbitrary file (also following
symbolic links), which would lead to incorrect information in the <code class="language-plaintext highlighter-rouge">m_deviceID</code>
field of the information returned by <code class="language-plaintext highlighter-rouge">currentMountPoints()</code>.</p>

<p>Later on the code tries to <a href="https://invent.kde.org/frameworks/kio/-/blob/v6.17.0/src/core/kmountpoint.cpp?ref_type=tags#L382">“resolve GVFS mount points” in line
382</a>.  The <a href="https://invent.kde.org/frameworks/kio/-/blob/v6.17.0/src/core/kmountpoint.cpp?ref_type=tags#L267"><code class="language-plaintext highlighter-rouge">resolveGvfsMountPoints()</code>
function</a> that implements this logic looks for mount
entries with “gvfsd-fuse” as source device name. For each of these mount
points the function will list the mount’s directory contents and look for
directory entries of the form <code class="language-plaintext highlighter-rouge">&lt;type&gt;:&lt;label&gt;</code>, where <code class="language-plaintext highlighter-rouge">type</code> refers to the
file system type that is expected to be found there. The function then
synthesizes additional mount entries from this information which will be
returned to the caller, appearing as fully-fledged regular mounts.</p>

<p>There are two problems with this. For one, these operations are all subject to
race conditions; the mount table entries can change at any time. Secondly,
there exists a common way for unprivileged users in Linux systems to create
mount points with arbitrary source device names. This is the <code class="language-plaintext highlighter-rouge">fusermount</code>
setuid-root utility, which is used for mounting FUSE file systems. Local users
can create a fake <code class="language-plaintext highlighter-rouge">gvfsd-fuse</code> mount point like this:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="nv">$ </span><span class="nb">export </span><span class="nv">_FUSE_COMMFD</span><span class="o">=</span>0
    <span class="nv">$ </span><span class="nb">mkdir</span> <span class="nv">$HOME</span>/mnt
    <span class="nv">$ </span>fusermount <span class="nv">$HOME</span>/mnt <span class="nt">-ononempty</span>,fsname<span class="o">=</span>gvfsd-fuse
    <span class="nv">$ </span>mount | <span class="nb">tail</span> <span class="nt">-n1</span>
    gvfsd-fuse on /home/<span class="nv">$USER</span>/mnt <span class="nb">type </span>fuse <span class="o">(</span>rw,nosuid,nodev,relatime,user_id<span class="o">=</span>1000,group_id<span class="o">=</span>100<span class="o">)</span>
</code></pre></div></div>

<p>The default FUSE configuration prevents the <code class="language-plaintext highlighter-rouge">root</code> user from accessing
non-root controlled FUSE file systems. To overcome this limitation, an
attacker can perform the following steps:</p>

<ul>
  <li>create a fake <code class="language-plaintext highlighter-rouge">gvfsd-fuse</code> mount like shown above.</li>
  <li>trigger the <code class="language-plaintext highlighter-rouge">unmount()</code> logic in smb4k’s mount helper.</li>
  <li>attempt to unmount <code class="language-plaintext highlighter-rouge">$HOME/mnt</code> after <code class="language-plaintext highlighter-rouge">currentMountPoints()</code> obtained the
mount information from libmount, but before it calls
<code class="language-plaintext highlighter-rouge">resolveGvfsMountPoints()</code>.</li>
  <li>place directories in this location that match the expected format e.g.
something like <code class="language-plaintext highlighter-rouge">cifs:mymount</code>. These directories can already be placed
there in advance, of course.</li>
  <li>on success, the <code class="language-plaintext highlighter-rouge">currentMountPoints()</code> function will return a
synthesized entry to the mount helper which lists a CIFS mount in the
unprivileged user’s <code class="language-plaintext highlighter-rouge">$HOME/mnt/cifs:mymount</code>.</li>
</ul>

<p>Using this approach, the verification step in the mount helper’s
<code class="language-plaintext highlighter-rouge">unmount()</code> function can be bypassed even if issues
<a href="#subsection-umount-arbitrary-dir">4.1)</a> and
<a href="#subsection-umount-arbitrary-args">4.2)</a> would be fixed.</p>

<p>There are further potential issues in the <code class="language-plaintext highlighter-rouge">KMountPoint</code> logic, e.g. in
<code class="language-plaintext highlighter-rouge">finalizeCurrentMountPoint()</code> the source device name is resolved if the
<code class="language-plaintext highlighter-rouge">KMountPoint::NeedRealDeviceName</code> flag is passed by the caller. This
provides another opportunity for unprivileged FUSE mounts with fake
source device names to influence the outcome, e.g. to perform
file existence tests or otherwise trick the caller of the KIO library.</p>

<p>Due to these problems, the information obtained from
<code class="language-plaintext highlighter-rouge">currentMountPoints()</code> currently cannot be used to base security related
decisions on. Generally <code class="language-plaintext highlighter-rouge">root</code> should not perform these additional
queries at all. The library could check for <code class="language-plaintext highlighter-rouge">geteuid() == 0</code> to prevent
the execution of this dangerous logic in privileged contexts.</p>

<p>For unprivileged applications we could imagine the addition of a flag like
<code class="language-plaintext highlighter-rouge">KMountPoint::AllowUnsafe</code>, which opts in to the problematic behaviour. Only
applications that are aware of the potential problems would then pass this
flag.</p>

<p>When we reported this, KDE security at first stated that the problems
described in this section would only affect smb4k and no other users of the
KMountPoint API. We found it questionable to consider a library’s API secure
only based on its supposed current users. Beyond that, even unprivileged
processes using this API might fall victim to other users in the system
crafting gvfsd mount information. One could argue that there is an issue in
the <code class="language-plaintext highlighter-rouge">fusermount</code> utility to begin with. The <code class="language-plaintext highlighter-rouge">KMountPoint</code> API is explicitly
processing a FUSE-based file system, however, and thus it should be prepared
to deal with the peculiarities this entails.</p>

<p>When we pointed out our continued concern to KDE security, it was suggested
that we create an upstream issue, or ideally provide a bugfix ourselves. While
we are happy to help where we can, the issue at hand is a larger API design
topic, and we believe it should be dealt with carefully by the responsible
upstream developers, allowing them also to learn from this experience. For
this reason we only created the <a href="https://bugs.kde.org/show_bug.cgi?id=513176">upstream issue</a>, as
was suggested to us.</p>

<h2 id="44-arbitrary-network-share-mounts-can-be-unmounted">4.4) Arbitrary Network Share Mounts can be Unmounted</h2>

<p>Even if all the other issues discussed in this section would be fixed, the
current mount helper code allows to unmount arbitrary Samba shares, no matter
if they have been originally mounted by smb4k itself (for the same user or a
different one), or by other components in the system (e.g. via a fixed entry
in <code class="language-plaintext highlighter-rouge">/etc/fstab</code>).</p>

<p>Similarly to <a href="#subsection-mount-arbitrary-dir">issue 3.1)</a> above, we suggest to
restrict smb4k mounts to a pre-defined location not controlled by unprivileged
users to address this issue.</p>

<h1 id="section-remarks">5) Other Remarks</h1>

<h2 id="51-superfluous-mh_command-client-parameter">5.1) Superfluous <code class="language-plaintext highlighter-rouge">mh_command</code> Client Parameter</h2>

<p>Both helper actions compare an arbitrary path supplied by the client in
<code class="language-plaintext highlighter-rouge">mh_command</code> to the trusted “mount” or “unmount” program path returned
from <code class="language-plaintext highlighter-rouge">findMountExecutable()</code> or <code class="language-plaintext highlighter-rouge">findUmountExecutable()</code>, respectively. This
is odd. It seems this comparison is a remnant from the attempted fix of
CVE-2017-8849. This is superfluous logic that increases the complexity of both
client and helper unnecessarily and can cause confusion, at best.</p>

<p>The helper should choose the trusted mount program on its own and stop
considering the <code class="language-plaintext highlighter-rouge">mh_command</code> parameter at all.</p>

<h2 id="52-redundant-online-check-code">5.2) Redundant “online check” Code</h2>

<p>There is a redundant check for online network interfaces in
<a href="https://invent.kde.org/network/smb4k/-/blob/4.0.4/helpers/smb4kmounthelper.cpp?ref_type=tags#L205">smb4kmounthelper.cpp line 38</a> and <a href="https://invent.kde.org/network/smb4k/-/blob/4.0.4/helpers/smb4kmounthelper.cpp?ref_type=tags#L38">line
205</a>. This code should be placed into a separate function
instead, to avoid code duplication and to increase readability.</p>

<p>This online check is also highly heuristic, and it might be possible for
unprivileged users to influence its outcome e.g. by creating
unprivileged pseudo network devices that appear to be online.</p>

<h2 id="53-mountcifs-and-umount-follow-symbolic-links">5.3) <code class="language-plaintext highlighter-rouge">mount.cifs</code> and <code class="language-plaintext highlighter-rouge">umount</code> Follow Symbolic Links</h2>

<p>Both <code class="language-plaintext highlighter-rouge">mount.cifs</code> and <code class="language-plaintext highlighter-rouge">umount</code> follow symbolic links in path arguments. This
means that even if the mount helper would try to verify a path pointing to a
client-controlled location, this could be replaced with a symbolic link
by the time the actual <code class="language-plaintext highlighter-rouge">mount.cifs</code> or <code class="language-plaintext highlighter-rouge">umount</code> utility runs, and the mount
logic would then operate on a completely different location than expected by
the helper.</p>

<h1 id="section-suggested-fixes">6) Suggested Fixes</h1>

<p>Apart from the individual suggestions mentioned in the context of the
issues above, we believe the range and severity of the issues uncovered shows
that a major redesign of the mount helper utility is necessary to address all
the problems in a robust way.</p>

<p>Here are some suggestions regarding a larger redesign:</p>

<ul>
  <li>the helper should not allow mounting or unmounting of user provided
paths at all. A dedicated directory like <code class="language-plaintext highlighter-rouge">/mounts/smb4k</code>, only controlled by
<code class="language-plaintext highlighter-rouge">root</code>, should be used for these purposes. Some form of tracking which mount
belongs to which user would be needed (e.g.  giving ownership of the mount to
the client that requested it).  This is more like <a href="https://github.com/storaged-project/udisks">udisks</a>
solves the problem of mounting devices on user request.</li>
  <li>passing through arbitrary parameters from unprivileged clients to
<code class="language-plaintext highlighter-rouge">mount.cifs</code> or <code class="language-plaintext highlighter-rouge">umount</code> won’t work securely. A more abstract interface with
well-defined settings for mounting or unmounting would help to restrict the
degrees of freedom that a client has. This would also improve the decoupling
of the helper’s interface from the concrete implementation, this way the
helper could e.g. change the implementation to call the <code class="language-plaintext highlighter-rouge">mount()</code> and
<code class="language-plaintext highlighter-rouge">umount()</code> system calls directly, instead of going through the mount
utilities.</li>
</ul>

<h1 id="section-bugfix">7) Upstream Bugfix</h1>

<p>During the course of a month we discussed various versions of patches with the
smb4k upstream developer, until we arrived at <a href="https://invent.kde.org/network/smb4k/-/commit/0dea60194ab6eb8f6e34ca2e6cb0f97b90c46f1e">a workable
patch</a> just in time for publication of this report
after the 90 days maximum embargo period we offered. The main aspects of the
bugfix are as follows:</p>

<ul>
  <li>For <code class="language-plaintext highlighter-rouge">mount</code> and <code class="language-plaintext highlighter-rouge">unmount</code> the options passed by the client are now more
closely scrutinized, and only settings present in a whitelist of options are
allowed anymore.</li>
  <li>The <code class="language-plaintext highlighter-rouge">filemode</code> mount option, which is still basically supported, is now
checked to make sure no special file bits are present.</li>
  <li>The <code class="language-plaintext highlighter-rouge">uid</code> and <code class="language-plaintext highlighter-rouge">gid</code> mount options can only be set to the UID/GID of the
caller, not to arbitrary IDs anymore.</li>
  <li>Network share mounts are now restricted to a directory hierarchy rooted in
<code class="language-plaintext highlighter-rouge">/run/smb4k</code>. This way, unprivileged users can no longer place symlinks in
the mount destination paths. Mounts are placed in per-UID subdirectories
such that different clients cannot influence each other’s mounts anymore.</li>
  <li>For passing Kerberos credentials, clients now pass already open file
descriptors to the mount helper, thereby avoiding any issues with regards to
operating on untrusted paths.</li>
  <li>The problematic <code class="language-plaintext highlighter-rouge">KMountPoint</code> API is no longer used and has been replaced by
Qt’s <code class="language-plaintext highlighter-rouge">QStorageInfo</code> API. Formally the investigation of existing mount points
would no longer be necessary at all with the trusted mount tree location,
but the upstream developer preferred to keep this extra verification step
for the time being.</li>
</ul>

<p>We want to express our thanks to Alexander Reinholdt, the smb4k upstream
developer, for cooperating with us and finishing the patch in time for
publication. This way a series of long-standing issues in smb4k could finally
be addressed.</p>

<h1 id="section-workarounds">8) Possible Workarounds</h1>

<p>If the upstream bugfix cannot be used right away, the following suggestions
can be considered to remove the attack surface described in this report:</p>

<ul>
  <li>Raise the Polkit authentication requirements for the mount and unmount
helper actions to <code class="language-plaintext highlighter-rouge">auth_admin</code>. This way the problematic logic can only be
reached by already privileged users. This contradicts the original purpose of
smb4k, however, to allow unprivileged mounts and unmounts of network shares.</li>
  <li>Restrict D-Bus access to the mount helper utility to members of an opt-in
group like <code class="language-plaintext highlighter-rouge">smb4k</code>. Coupled with a security disclaimer, this would allow
users that really want to use this feature to opt-in.</li>
</ul>

<h1 id="section-reproducers">9) Reproducers</h1>

<p>The KAuth D-Bus interface cannot easily be invoked via utilities like <code class="language-plaintext highlighter-rouge">gdbus</code>,
because it expects a serialized <code class="language-plaintext highlighter-rouge">QVariantMap</code> as input. We offer two C++
programs which can be used to perform standalone tests of smb4k’s mount helper
API for the purposes of reproducing the attack vectors described in this
report, <a href="/download/smb4k_mount.cpp"><code class="language-plaintext highlighter-rouge">smb4k_mount.cpp</code></a> and
<a href="/download/smb4k_unmount.cpp"><code class="language-plaintext highlighter-rouge">smb4k_unmount.cpp</code></a>. There are comments in the
source code of the reproducers that explain how to compile and use them.</p>

<h1 id="section-cves">10) CVE Assignment</h1>

<p>Formally the findings in this report could justify a large count of CVEs, but
we decided to condense them into the two main aspects that result from the
issues:</p>

<ul>
  <li>CVE-2025-66002: local users can perform arbitrary unmounts via the smb4k
mount helper due to lack of input validation.</li>
  <li>CVE-2025-66003: local users can perform a local root exploit via the smb4k
mount helper if they can access and control the contents of a Samba network
share.</li>
</ul>

<p>When the end of the 90 days maximum non-disclosure period we offered upstream
approached, due to lack of feedback from KDE Security, we assigned these CVEs
as we originally suggested them to upstream.</p>

<h1 id="section-disclosure">11) Coordinated Disclosure</h1>

<p>We reached out to KDE security on September 11 and shared the full details
about the issues described in this report, offering coordinated disclosure.
For nearly the first two months of the maximum 90 days non-disclosure period,
we had difficulties getting clear answers from KDE security about the expected
publication date, whether they acknowledged the findings or even whether they
wanted to practice coordinated disclosure at all.</p>

<p>We only saw some visible progress at the beginning of November, when the
smb4k upstream developer joined the discussion and started developing
bugfixes. The progress remained slow, however, due to limited resources on the
end of the developer. Still, from this point onwards the discussion turned out
helpful and cooperative, and we could finally see that the non-disclosure time
was actually being put to use. We managed to agree on a bugfix that addresses
all the issues only less than a week before the 90 days maximum embargo period
would be reached.</p>

<p>In summary, we are not completely happy about how the coordinated disclosure
developed in this case. We perceived an unwillingness on the end of KDE security
to communicate and to help in coordinating the disclosure. We believe the
issue could have been fixed faster by suggesting a workaround to users and
by developing a bugfix in the open, with the help of the rest of the
community.</p>

<h1 id="12-timeline">12) Timeline</h1>

<table>
  <tbody>
    <tr>
      <td>2025-09-11</td>
      <td>We forwarded our report to security@kde.org, offering coordinated disclosure.</td>
    </tr>
    <tr>
      <td>2025-09-17</td>
      <td>We received acknowledgement of receipt from KDE security.</td>
    </tr>
    <tr>
      <td>2025-09-29</td>
      <td>Not having heard anything else from upstream, we asked at least for a confirmation of the issues described in the report and a formal decision whether coordinated disclosure was desired. We asked to get feedback until October 2, lest we would publish the information on our end.</td>
    </tr>
    <tr>
      <td>2025-10-01</td>
      <td>We got a reply from KDE security that they were working on the issue, without answering our questions. We replied again and tried to clarify that we did not intend to put time pressure on upstream, but would like to clearly setup the coordinated disclosure process.</td>
    </tr>
    <tr>
      <td>2025-10-02</td>
      <td>We got a short reply that they could not give us an expected publication date, repeating again that they were working on the issue. Our questions pertaining the process still remained unanswered. We once more explained that we would like to be involved in reviewing potential bugfixes where we could offer our help, and that we would like to avoid non-disclosure time passing without any visible progress.</td>
    </tr>
    <tr>
      <td>2025-10-07</td>
      <td>KDE security informed us that the fix was moving forward without giving further details.</td>
    </tr>
    <tr>
      <td>2025-11-07</td>
      <td>The smb4k developer, Alexander Reinholdt, contacted us directly sharing a first batch of suggested bugfixes.</td>
    </tr>
    <tr>
      <td>2025-11-12</td>
      <td>We provided detailed feedback on the security relevant part of the patch, pointing out various problems that remained, and new problems that got introduced.</td>
    </tr>
    <tr>
      <td>2025-11-12</td>
      <td>KDE security chimed in about the <a href="#subsection-kmountpoint">KMountPoint</a> topic, stating that smb4k would be the only privileged component using this API.</td>
    </tr>
    <tr>
      <td>2025-11-13</td>
      <td>We replied to KDE security explaining in more detail the remaining concerns we had regarding the KMountPoint API.</td>
    </tr>
    <tr>
      <td>2025-11-16</td>
      <td>The smb4k developer thanked us for the review of the patch, and sent back detailed comments on our input. He told us he would be working on a follow-up patch set.</td>
    </tr>
    <tr>
      <td>2025-11-26</td>
      <td>The smb4k developer informed us that it would take still more time for him to provide the improved version of the patch.</td>
    </tr>
    <tr>
      <td>2025-11-26</td>
      <td>We thanked the developer for his continued effort, but also reminded all participants that the end of the 90 days maximum non-disclosure period we offered was approaching in two weeks. We suggested the alternative of publishing a temporary workaround instead (like increasing authentication requirements), should a full bugfix be out of reach within the remaining time. We also suggested to involve the <a href="https://oss-security.openwall.org/wiki/mailing-lists/distros">distros mailing list</a> at this time, to give other Linux and BSD distributions a chance to prepare before general publication of the report.</td>
    </tr>
    <tr>
      <td>2025-11-27</td>
      <td>On the topic of the KMountPoint API, KDE security clarified that they ideally would like a merge request from us addressing our concerns.</td>
    </tr>
    <tr>
      <td>2025-11-28</td>
      <td>We assigned <a href="#section-cves">the CVEs</a> the way we initially suggested them to upstream, to provide them as additional information to the distros mailing list. We also shared the CVEs with upstream.</td>
    </tr>
    <tr>
      <td>2025-11-30</td>
      <td>The upstream developer shared an improved patch set with us.</td>
    </tr>
    <tr>
      <td>2025-12-01</td>
      <td>We sent another round of comments back to the upstream developer. The new patch was still lacking in a number of areas.</td>
    </tr>
    <tr>
      <td>2025-12-01</td>
      <td>We forwarded a draft of this report to the distros mailing list, announcing publication of the issues on 2025-12-10. We pointed out that no proper bugfix was available for sharing at this time.</td>
    </tr>
    <tr>
      <td>2025-12-03</td>
      <td>We received yet another version of the suggested patch from the upstream developer.</td>
    </tr>
    <tr>
      <td>2025-12-04</td>
      <td>This time we found no remaining security issues, agreed on the patch, but still commented on a couple of quality and style aspects.</td>
    </tr>
    <tr>
      <td>2025-12-04</td>
      <td>We forwarded the bugfix from the upstream developer to the distros mailing list.</td>
    </tr>
    <tr>
      <td>2025-12-05</td>
      <td>We asked the upstream developer to publish a bugfix release on 2025-12-10, which he agreed upon.</td>
    </tr>
    <tr>
      <td>2025-12-10</td>
      <td>Upstream published the <a href="https://sourceforge.net/p/smb4k/blog/2025/12/smb4k-405-security-bug-fix-release">bugfix release 4.0.5</a> as planned.</td>
    </tr>
    <tr>
      <td>2025-12-10</td>
      <td>Publication of this report.</td>
    </tr>
  </tbody>
</table>

<h1 id="13-references">13) References</h1>

<ul>
  <li><a href="https://invent.kde.org/network/smb4k.git">smb4k KDE Project</a></li>
  <li><a href="https://sourceforge.net/p/smb4k/blog/2025/12/smb4k-405-security-bug-fix-release">smb4k 4.05 bugfix release</a></li>
  <li><a href="https://invent.kde.org/network/smb4k/-/commit/0dea60194ab6eb8f6e34ca2e6cb0f97b90c46f1e">upstream bugfix for the issues in this report</a></li>
  <li><a href="https://bugzilla.suse.com/show_bug.cgi?id=1249004">SUSE Bugzilla review bug for smb4k</a></li>
  <li><a href="https://bugs.kde.org/show_bug.cgi?id=513176">Bug report against the KIO library regarding KMountPoint API issues</a></li>
</ul>]]></content><author><name>&lt;a href=&apos;mailto:matthias.gerstner@suse.de&apos;&gt;Matthias Gerstner&lt;/a&gt;, &lt;a href=&apos;mailto:filippo.bonazzi@suse.com&apos;&gt;Filippo Bonazzi (editor)&lt;/a&gt;</name></author><category term="CVE" /><category term="KDE" /><category term="D-Bus" /><summary type="html"><![CDATA[smb4k is a KDE desktop related utility which allows unprivileged mounts of Samba/CIFS network shares. The utility was already rejected from entering openSUSE in 2017 due to severe security issues. A revisit of the tool showed that it still suffered from major vulnerabilities leading to local Denial-of-Service or even a local root exploit. After a long coordinated disclosure, upstream arrived at a working bugfix in version 4.0.5.]]></summary></entry></feed>