<?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-04-14T01:10:42+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">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><entry><title type="html">lightdm-kde-greeter: Privilege Escalation from lightdm Service User to root in KAuth Helper Service (CVE-2025-62876)</title><link href="https://security.opensuse.org/2025/11/13/lightdm-kde-greeter-auth-helper.html" rel="alternate" type="text/html" title="lightdm-kde-greeter: Privilege Escalation from lightdm Service User to root in KAuth Helper Service (CVE-2025-62876)" /><published>2025-11-13T00:00:00+00:00</published><updated>2025-11-13T00:00:00+00:00</updated><id>https://security.opensuse.org/2025/11/13/lightdm-kde-greeter-auth-helper</id><content type="html" xml:base="https://security.opensuse.org/2025/11/13/lightdm-kde-greeter-auth-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 D-Bus Helper</a></li>
  <li><a href="#section-problems" id="markdown-toc-section-problems">3) Problems in the D-Bus Helper</a></li>
  <li><a href="#section-bugfix" id="markdown-toc-section-bugfix">4) Upstream Bugfix</a></li>
  <li><a href="#5-cve-assignment" id="markdown-toc-5-cve-assignment">5) CVE Assignment</a></li>
  <li><a href="#6-coordinated-disclosure" id="markdown-toc-6-coordinated-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://invent.kde.org/plasma/lightdm-kde-greeter">lightdm-kde-greeter</a> is a KDE-themed greeter application
for the <a href="https://github.com/canonical/lightdm">lightdm display manager</a>. At the beginning of
September one of our community packagers <a href="https://bugzilla.suse.com/show_bug.cgi?id=1249146">asked us</a> to
review a D-Bus service contained in lightdm-kde-greeter for addition to
openSUSE Tumbleweed.</p>

<p>In the course of the review we found a potential privilege escalation from the
<code class="language-plaintext highlighter-rouge">lightdm</code> service user to <code class="language-plaintext highlighter-rouge">root</code> which is facilitated by this D-Bus service,
among some other shortcomings in its implementation.</p>

<p>The <a href="#section-overview">next section</a> provides a general overview of the D-Bus
service.  <a href="#section-problems">Section 3</a> discusses the security problems in the
service’s implementation. <a href="#section-bugfix">Section 4</a> takes a look at the
bugfix upstream arrived at.</p>

<p>This report is based on lightdm-kde-greeter <a href="https://invent.kde.org/plasma/lightdm-kde-greeter/-/tags/v6.0.3">release
6.0.3</a>.</p>

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

<p>lightdm-kde-greeter includes a D-Bus service which enables regular users to
configure custom themes to be used by the greeter application. The D-Bus
service is implemented as a <a href="/2024/04/02/kde6-dbus-polkit.html#the-kde-kauth-framework">KDE KAuth helper service</a>, running
with full root privileges.</p>

<p>The helper implements a <a href="https://invent.kde.org/plasma/lightdm-kde-greeter/-/blob/v6.0.3/kcm/helper.cpp#L48">single API method</a>, protected by
Polkit action <code class="language-plaintext highlighter-rouge">org.kde.kcontrol.kcmlightdm.save</code>, which requires
<code class="language-plaintext highlighter-rouge">auth_admin_keep</code> by default, i.e. users need to provide root credentials to
perform this action. The method takes a map of key/value pairs which allow to
fully control the contents of <code class="language-plaintext highlighter-rouge">lightdm.conf</code> and <code class="language-plaintext highlighter-rouge">lightdm-kde-greeter.conf</code>.</p>

<p>From a security point of view such a generic interface is sub-optimal, since
the scope of the operation is not restricted to changing theme settings, but
also allows to change all the rest of lightdm’s configuration, providing less
control over who may do what in the system. From an application’s point of
view this approach is understandable, however, as this makes it easy to
support any future features.</p>

<p>Another Polkit action <code class="language-plaintext highlighter-rouge">org.kde.kcontrol.kcmlightdm.savethemedetails</code> is
declared in <a href="https://invent.kde.org/plasma/lightdm-kde-greeter/-/blob/v6.0.3/kcm/kcm_lightdm.actions?ref_type=tags#L39"><code class="language-plaintext highlighter-rouge">kcm_lightdm.actions</code></a>, which is unused, maybe
a remnant of former versions of the project.</p>

<h1 id="section-problems">3) Problems in the D-Bus Helper</h1>

<p>The problems in the D-Bus service start in <a href="https://invent.kde.org/plasma/lightdm-kde-greeter/-/blob/v6.0.3/kcm/helper.cpp?ref_type=tags#L87">helper.cc line
87</a>, where we can find this comment:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// keys starting with "copy_" are handled in a special way, in fact,
// this is an instruction to copy the file to the greeter's home
// directory, because the greeter will not be able to read the image
// from the user's home folder
</code></pre></div></div>

<p>To start with it is rather bad API design to abuse the key/value map, which is
supposed to contain configuration file entries, for carrying “secret” copy
instructions. Even worse, in the resulting copy operation three different
security contexts are mixed:</p>

<ul>
  <li>the helper, which runs with full root privileges.</li>
  <li>the unprivileged D-Bus client, which specifies a path to be opened by the
helper.</li>
  <li>the <code class="language-plaintext highlighter-rouge">lightdm</code> service user; the helper will copy the user-specified file
into a directory controlled by it.</li>
</ul>

<p>The helper performs this copy operation with full <code class="language-plaintext highlighter-rouge">root</code> privileges without
taking precautions, reading input data from one unprivileged context and
writing it into another unprivileged context. This is done naively using
the Qt framework’s <code class="language-plaintext highlighter-rouge">QFile::copy()</code> and similar APIs, leading to a range of
potential local attack vectors:</p>

<ul>
  <li>Denial-of-Service (e.g. passing a named FIFO pipe as source file path,
causing the D-Bus helper to block indefinitely).</li>
  <li>information leak (e.g. passing a path to private data as source file like
<code class="language-plaintext highlighter-rouge">/etc/shadow</code>, which will then become public in <code class="language-plaintext highlighter-rouge">/var/lib/lightdm</code>).</li>
  <li>creation of directories in unexpected locations (the helper attempts to
create <code class="language-plaintext highlighter-rouge">/var/lib/lightdm/.../&lt;theme&gt;</code>, thus the lightdm user can place
symlinks there which will be followed).</li>
  <li>overwrite of unexpected files (similar as before, symlinks can be
placed as destination file name, which will be followed and overwritten
with client data).</li>
</ul>

<p>If this action would ever be set to <code class="language-plaintext highlighter-rouge">yes</code> Polkit authentication requirements,
then this would be close to a local root exploit. Even in its existing form it
allows the <code class="language-plaintext highlighter-rouge">lightdm</code> service user to escalate privileges to <code class="language-plaintext highlighter-rouge">root</code>.</p>

<p>Interestingly these problems are quite similar to issues in <code class="language-plaintext highlighter-rouge">sddm-kcm6</code>, which
we covered <a href="/2024/04/02/kde6-dbus-polkit.html#problematic-file-system-operations-in-sddm-kcm6">in a previous blog post</a>.</p>

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

<p>We suggested the following changes to upstream to address the problems:</p>

<ul>
  <li>the copy operation should be implemented using D-Bus file descriptor
passing, this way opening client-controlled paths as <code class="language-plaintext highlighter-rouge">root</code> is already avoided.</li>
  <li>for creating the file in the target directory of <code class="language-plaintext highlighter-rouge">lightdm</code>, a privilege drop to
the <code class="language-plaintext highlighter-rouge">lightdm</code> service user should be performed to avoid any symlink attack
surface.</li>
</ul>

<p>We are happy to share that the upstream maintainer of lightdm-kde-greeter
followed our suggestions closely and coordinated the changes with us before
the publication of the bugfix. With these changes, this KAuth helper is now
kind of a model implementation which can serve as a positive example for other
KDE components. Upstream also performed some general cleanup, like the removal
of the unused <code class="language-plaintext highlighter-rouge">savethemedetails</code> Polkit action from the repository.</p>

<p>Upstream released <a href="https://invent.kde.org/plasma/lightdm-kde-greeter/-/tags/v6.0.4">version 6.0.4</a> of
lightdm-kde-greeter which contains the fixes.</p>

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

<p>In agreement with upstream, we assigned CVE-2025-62876 to track the <code class="language-plaintext highlighter-rouge">lightdm</code>
service user to <code class="language-plaintext highlighter-rouge">root</code> privilege escalation aspect described in this report.
The severity of the issue is low, since it only affects defense-in-depth (if
the <code class="language-plaintext highlighter-rouge">lightdm</code> service user were compromised) and the problematic logic can
only be reached and exploited if triggered interactively by a privileged user.</p>

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

<p>We reported these issues to KDE security on 2025-09-04 offering coordinated
disclosure, but we initially had difficulties setting up the process with
them. Upstream did not clearly express the desire to practice coordinated
disclosure, no (preliminary) publication date could be set and no
confirmation of the issues was received.</p>

<p>Things took a turn for the better when a lightdm-kde-greeter developer
contacted us directly on 2025-10-16 and the publication date and fixes were
discussed. The ensuing review process for the bugfixes was very helpful in our
opinion, leading to a major improvement of the KAuth helper implementation in
lightdm-kde-greeter.</p>

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

<table>
  <tbody>
    <tr>
      <td>2025-09-04</td>
      <td>We received the <a href="https://bugzilla.suse.com/show_bug.cgi?id=1249146">review request</a> for the lightdm-kde-greeter D-Bus service.</td>
    </tr>
    <tr>
      <td>2025-09-10</td>
      <td>We privately reported the findings to KDE security.</td>
    </tr>
    <tr>
      <td>2025-09-17</td>
      <td>We received an initial reply from KDE security stating that they would get back to us.</td>
    </tr>
    <tr>
      <td>2025-09-29</td>
      <td>We asked for at least a confirmation of the report and a rough disclosure date, but upstream was not able to provide this.</td>
    </tr>
    <tr>
      <td>2025-10-01</td>
      <td>KDE security informed us that an upstream developer planned to release fixes by mid-November.</td>
    </tr>
    <tr>
      <td>2025-10-16</td>
      <td>An upstream developer contacted us to discuss the publication date, since the bugfixes were ready.</td>
    </tr>
    <tr>
      <td>2025-10-20</td>
      <td>We asked the developer to share the bugfixes for review.</td>
    </tr>
    <tr>
      <td>2025-10-21</td>
      <td>The developer shared a patch set with us.</td>
    </tr>
    <tr>
      <td>2025-10-24</td>
      <td>We agreed on 2025-10-31 for coordinated disclosure date.</td>
    </tr>
    <tr>
      <td>2025-10-28</td>
      <td>After a couple of email exchanges discussing the patches, upstream arrived at an improved patch set. We suggested to assign a CVE for the <code class="language-plaintext highlighter-rouge">ligthdm</code> to <code class="language-plaintext highlighter-rouge">root</code> attack surface.</td>
    </tr>
    <tr>
      <td>2025-10-29</td>
      <td>We assigned CVE-2025-62876.</td>
    </tr>
    <tr>
      <td>2025-11-03</td>
      <td>We asked when the bugfix release would be published, with the disclosure date already passed.</td>
    </tr>
    <tr>
      <td>2025-11-03</td>
      <td>Upstream agreed to publish on the same day.</td>
    </tr>
    <tr>
      <td>2025-11-03</td>
      <td>Upstream released <a href="https://invent.kde.org/plasma/lightdm-kde-greeter/-/tags/v6.0.4">version 6.0.4</a> containing the bugfixes. We published our <a href="https://bugzilla.suse.com/show_bug.cgi?id=1249146">Bugzilla bug</a> on the topic.</td>
    </tr>
    <tr>
      <td>2025-11-13</td>
      <td>Publication of this report.</td>
    </tr>
  </tbody>
</table>

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

<ul>
  <li><a href="https://bugzilla.suse.com/show_bug.cgi?id=1249146">lightdm-kde-greeter review bug in openSUSE Bugzilla</a></li>
  <li><a href="https://invent.kde.org/plasma/lightdm-kde-greeter/-/tags/v6.0.4">lightdm-kde-greeter version 6.0.4 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="KDE" /><category term="D-Bus" /><summary type="html"><![CDATA[lightdm-kde-greeter is a KDE-themed greeter application for the lightdm display manager. It contains a KAuth-based D-Bus helper application for performing privileged operations, which suffers from a `lightdm` to `root` privilege escalation and some other shortcomings in versions up to 6.0.3. In discussions with upstream we managed to arrive at a much improved version of the affected code.]]></summary></entry><entry><title type="html">scx: Unauthenticated scx_loader D-Bus Service can lead to major Denial-of-Service</title><link href="https://security.opensuse.org/2025/11/06/scx-unauthorized-dbus.html" rel="alternate" type="text/html" title="scx: Unauthenticated scx_loader D-Bus Service can lead to major Denial-of-Service" /><published>2025-11-06T00:00:00+00:00</published><updated>2025-11-06T00:00:00+00:00</updated><id>https://security.opensuse.org/2025/11/06/scx-unauthorized-dbus</id><content type="html" xml:base="https://security.opensuse.org/2025/11/06/scx-unauthorized-dbus.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 Unauthenticated <code class="language-plaintext highlighter-rouge">scx_loader</code> D-Bus Service</a></li>
  <li><a href="#section-parameters" id="markdown-toc-section-parameters">3) Passing Arbitrary Parameters to Schedulers</a>    <ul>
      <li><a href="#the---pin-root-path-option" id="markdown-toc-the---pin-root-path-option">The <code class="language-plaintext highlighter-rouge">--pin-root-path</code> Option</a></li>
      <li><a href="#the---kconfig-option" id="markdown-toc-the---kconfig-option">The <code class="language-plaintext highlighter-rouge">--kconfig</code> Option</a></li>
      <li><a href="#the---btf-custom-path-option" id="markdown-toc-the---btf-custom-path-option">The <code class="language-plaintext highlighter-rouge">--btf-custom-path</code> Option</a></li>
      <li><a href="#the---bpf-token-path-option" id="markdown-toc-the---bpf-token-path-option">The <code class="language-plaintext highlighter-rouge">--bpf-token-path</code> Option</a></li>
    </ul>
  </li>
  <li><a href="#section-root-exploit" id="markdown-toc-section-root-exploit">4) On the Verge of a Local Root Exploit</a></li>
  <li><a href="#section-affected" id="markdown-toc-section-affected">5) Affected Linux Distributions</a></li>
  <li><a href="#section-suggested-fixes" id="markdown-toc-section-suggested-fixes">6) Suggested Fixes</a>    <ul>
      <li><a href="#restrict-access-to-a-group-on-d-bus-level" id="markdown-toc-restrict-access-to-a-group-on-d-bus-level">Restrict Access to a Group on D-Bus Level</a></li>
      <li><a href="#use-polkit-for-authentication" id="markdown-toc-use-polkit-for-authentication">Use Polkit for Authentication</a></li>
      <li><a href="#making-the-api-more-robust" id="markdown-toc-making-the-api-more-robust">Making the API more Robust</a></li>
      <li><a href="#use-systemd-sandboxing" id="markdown-toc-use-systemd-sandboxing">Use systemd Sandboxing</a></li>
    </ul>
  </li>
  <li><a href="#section-bugfix" id="markdown-toc-section-bugfix">7) Missing Upstream Bugfix</a></li>
  <li><a href="#8-cve-assignment" id="markdown-toc-8-cve-assignment">8) CVE Assignment</a></li>
  <li><a href="#section-timeline" id="markdown-toc-section-timeline">9) Timeline</a></li>
  <li><a href="#10-links" id="markdown-toc-10-links">10) Links</a></li>
</ul>

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

<p>The <a href="https://github.com/sched-ext/scx">scx project</a> offers a range of dynamically loadable
custom schedulers implemented in Rust and C, which make use of the Linux
kernel’s <code class="language-plaintext highlighter-rouge">sched_ext</code> feature. An optional D-Bus service called <code class="language-plaintext highlighter-rouge">scx_loader</code>
provides an interface accessible to all users in the system, which allows to
load and configure the schedulers provided by scx. This D-Bus service is
present in scx up to version v1.0.17. As a response to this report,
<code class="language-plaintext highlighter-rouge">scx_loader</code> has been moved into a <a href="https://github.com/sched-ext/scx-loader">dedicated repository</a>.</p>

<p>A SUSE colleague packaged scx for addition to openSUSE Tumbleweed, and the
D-Bus service it contained <a href="https://bugzilla.suse.com/show_bug.cgi?id=1250449">required a review</a> by our team.
The review showed that the D-Bus service runs with full root privileges and
is missing an authentication layer, thus allowing any user to nearly
arbitrarily change the scheduling properties of the system, leading to
Denial-of-Service and other attack vectors.</p>

<p><a href="#section-timeline">Upstream declined coordinated disclosure</a> for this report
and asked us to handle it in the open right away. In the discussion that
followed, upstream rejected parts of our report and presented no clear path
forward to fix the issues, which is why there is no bugfix available at the
moment.</p>

<p><a href="#section-overview">Section 2</a> provides an overview of the <code class="language-plaintext highlighter-rouge">scx_loader</code> D-Bus
service and its lack of authentication. <a href="#section-parameters">Section 3</a> takes
a look into problematic command line parameters which can be influenced by
unprivileged clients. <a href="#section-root-exploit">Section 4</a> looks into attempts to
achieve a local root exploit using the <code class="language-plaintext highlighter-rouge">scx_loader</code> API. <a href="#section-affected">Section
5</a> lists affected Linux distributions. <a href="#section-suggested-fixes">Section
6</a> discusses possible approaches to fix the issues
found in this report. <a href="#section-bugfix">Section 7</a> takes a look at the upstream
efforts to fix the issues.</p>

<p>This report is based on <a href="https://github.com/sched-ext/scx/releases/tag/v1.0.16">version 1.0.16</a> of scx.</p>

<h1 id="section-overview">2) Overview of the Unauthenticated <code class="language-plaintext highlighter-rouge">scx_loader</code> D-Bus Service</h1>

<p>The <a href="https://github.com/sched-ext/scx/tree/v1.0.16/tools/scx_loader"><code class="language-plaintext highlighter-rouge">scx_loader</code> D-Bus service</a> is implemented in Rust
and offers a completely unauthenticated D-Bus interface on the system bus. The
upstream repository contains configuration files and documentation
<a href="https://github.com/sched-ext/scx/blob/v1.0.16/tools/scx_loader/README.md?plain=1#L76">advertising this service as suitable to be automatically
started</a> via D-Bus requests. Thus arbitrary users in
the system (including low privilege service users or even <code class="language-plaintext highlighter-rouge">nobody</code>) are
allowed to make unrestricted use of the service.</p>

<p>The <a href="https://github.com/sched-ext/scx/blob/v1.0.16/tools/scx_loader/src/dbus.rs#L16">service’s interface</a> offers functions to start, stop or
switch between a number of scx schedulers. The start and switch methods also
offer to specify an arbitrary list of parameters which will be directly passed
to the binary implementing the scheduler.</p>

<p>Every scheduler is implemented in a dedicated binary and found e.g. in
<code class="language-plaintext highlighter-rouge">/usr/bin/scx_bpfland</code> for the bpfland scheduler. Not all schedulers that are
part of scx are accessible via this interface. The list of schedulers
supported by <code class="language-plaintext highlighter-rouge">scx_loader</code> in the reviewed version is:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>scx_bpfland scx_cosmos scx_flash scx_lavd
scx_p2dq scx_tickless scx_rustland scx_rusty
</code></pre></div></div>

<p>We believe the ability to more or less arbitrarily tune the scheduling
behaviour of the system already poses a local Denial-of-Service (DoS) attack
vector that might even make it possible to lock up the complete system. We did
not look into a concrete set of parameters that might achieve that, but it
seems likely, given the range of schedulers and their parameters made
available via the D-Bus interface.</p>

<h1 id="section-parameters">3) Passing Arbitrary Parameters to Schedulers</h1>

<p>The ability to pass arbitrary command line parameters to any of the supported
scheduler binaries increases the attack surface of the D-Bus interface
considerably. This makes a couple of concrete attacks possible, especially
when the scheduler in question accepts file paths as input. Apart from
parameters that influence scheduler behaviour, all schedulers offer the
generic “Libbpf Options”, of which the following four options stick out in
this context:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>--pin-root-path &lt;PIN_ROOT_PATH&gt;      Maps that set the 'pinning' attribute in their definition will have
                                     their pin_path attribute set to a file in this directory, and be
                                     auto-pinned to that path on load; defaults to "/sys/fs/bpf"
--kconfig &lt;KCONFIG&gt;                  Additional kernel config content that augments and overrides system
                                     Kconfig for CONFIG_xxx externs
--btf-custom-path &lt;BTF_CUSTOM_PATH&gt;  Path to the custom BTF to be used for BPF CO-RE relocations. This custom
                                     BTF completely replaces the use of vmlinux BTF for the purpose of CO-RE
                                     relocations. NOTE: any other BPF feature (e.g., fentry/fexit programs,
                                     struct_ops, etc) will need actual kernel BTF at /sys/kernel/btf/vmlinux
--bpf-token-path &lt;BPF_TOKEN_PATH&gt;    Path to BPF FS mount point to derive BPF token from. Created BPF token
                                     will be used for all bpf() syscall operations that accept BPF token
                                     (e.g., map creation, BTF and program loads, etc) automatically within
                                     instantiated BPF object. If bpf_token_path is not specified, libbpf will
                                     consult LIBBPF_BPF_TOKEN_PATH environment variable. If set, it will be
                                     taken as a value of bpf_token_path option and will force libbpf to
                                     either create BPF token from provided custom BPF FS path, or will
                                     disable implicit BPF token creation, if envvar value is an empty string.
                                     bpf_token_path overrides LIBBPF_BPF_TOKEN_PATH, if both are set at the
                                     same time. Setting bpf_token_path option to empty string disables
                                     libbpf's automatic attempt to create BPF token from default BPF FS mount
                                     point (/sys/fs/bpf), in case this default behavior is undesirable
</code></pre></div></div>

<p>libbpf is a userspace support library for BPF programs <a href="https://github.com/torvalds/linux/tree/c9cfc122f03711a5124b4aafab3211cf4d35a2ac/tools/lib/bpf">found in the Linux
source tree</a>. The following sub-sections take a look at each of
the attacker-controlled paths passed to this library in detail.</p>

<h2 id="the---pin-root-path-option">The <code class="language-plaintext highlighter-rouge">--pin-root-path</code> Option</h2>

<p>The <code class="language-plaintext highlighter-rouge">--pin-root-path</code> option potentially causes libbpf to create the
parent directory of this path in
<a href="https://github.com/torvalds/linux/blob/6146a0f1dfae5d37442a9ddcba012add260bceb0/tools/lib/bpf/libbpf.c#L8801"><code class="language-plaintext highlighter-rouge">bfp_object__pin_programs()</code></a>. We are not entirely
sure under which conditions the logic is triggered, however, and if these
conditions are controlled by an unprivileged caller in the context of the
<code class="language-plaintext highlighter-rouge">scx_loader</code> D-Bus API.</p>

<h2 id="the---kconfig-option">The <code class="language-plaintext highlighter-rouge">--kconfig</code> Option</h2>

<p>The file found in the <code class="language-plaintext highlighter-rouge">--kconfig</code> path is completely read into memory in
<a href="https://github.com/sched-ext/scx/blob/e25cc6e5920f33d5bbe2bd62b2e7a5854de88a19/rust/scx_utils/src/libbpf_clap_opts.rs#L91"><code class="language-plaintext highlighter-rouge">libbpf_clap_opts.rs</code> line 91</a>. This makes
a number of attack vectors possible:</p>

<ul>
  <li>pointing to a device file like <code class="language-plaintext highlighter-rouge">/dev/zero</code> leads to an out of memory
situation in the selected scheduler binary.</li>
  <li>pointing to a private file like <code class="language-plaintext highlighter-rouge">/etc/shadow</code> causes the scheduler binary to
read in the private data. We did not find a way for this data to leak out
into the context of an unprivileged D-Bus caller, however. This technique
still allows to perform file existence tests in locations that are normally
not accessible to unprivileged users.</li>
  <li>pointing to a FIFO named pipe will block the scheduler binary indefinitely,
breaking the D-Bus service. Also, by feeding data to such a PIPE, <em>nearly</em>
all memory can be used up, keeping the system in a low-memory situation
and possibly leading to the kernel’s OOM killer targeting unrelated
processes.</li>
  <li>by pointing to a regular file controlled by the caller, crafted KConfig
information can be passed into libbpf. The impact of this appears to be
minimal, however.</li>
</ul>

<p>The following command line is an example reproducer which will cause the
<code class="language-plaintext highlighter-rouge">scx_bpfland</code> process to consume all system memory until it is killed by
the kernel:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>user$ gdbus call -y -d org.scx.Loader -o /org/scx/Loader \
    -m org.scx.Loader.SwitchSchedulerWithArgs scx_bpfland \
    '["--kconfig", "/dev/zero"]'
</code></pre></div></div>

<h2 id="the---btf-custom-path-option">The <code class="language-plaintext highlighter-rouge">--btf-custom-path</code> Option</h2>

<p>The <code class="language-plaintext highlighter-rouge">--btf-custom-path</code> option offers similar attack vectors as the
<code class="language-plaintext highlighter-rouge">--kconfig</code> option discussed above. Additionally, crafted binary symbol
information can be fed to the scheduler via this path, which will be processed
either by <a href="https://github.com/torvalds/linux/blob/6146a0f1dfae5d37442a9ddcba012add260bceb0/tools/lib/bpf/btf.c#L1304"><code class="language-plaintext highlighter-rouge">btf_parse_raw()</code></a> or
<a href="https://github.com/torvalds/linux/blob/6146a0f1dfae5d37442a9ddcba012add260bceb0/tools/lib/bpf/btf.c#L1192"><code class="language-plaintext highlighter-rouge">btf_parse_elf()</code></a> found in libbpf. This can lead to
integrity violation of the scheduler / the kernel, the impact of which we
cannot fully judge as we lack expertise in this low level area and did not
want to invest more time than necessary for the analysis.</p>

<h2 id="the---bpf-token-path-option">The <code class="language-plaintext highlighter-rouge">--bpf-token-path</code> Option</h2>

<p>The <code class="language-plaintext highlighter-rouge">--bpf-token-path</code>, if it refers to a directory, <a href="https://github.com/torvalds/linux/blob/6146a0f1dfae5d37442a9ddcba012add260bceb0/tools/lib/bpf/libbpf.c#L5030">will be opened by
libbpf</a> and the file descriptor will be passed to the
bpf system call like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bpf(BPF_TOKEN_CREATE, {token_create={flags=0, bpffs_fd=20}}, 8) = -1 EINVAL (Invalid argument)
</code></pre></div></div>

<p>This does not seem to achieve anything, however, because the kernel code
rejects the caller if it lives in the initial user namespace (which the
privileged D-Bus service always does). The path could maybe serve as an
information leak to test file existence and type, if the behaviour of the
scheduler “start” operation shows observable differences depending on the
input.</p>

<h1 id="section-root-exploit">4) On the Verge of a Local Root Exploit</h1>

<p>With this much control over the command line parameters of many different
scheduler binaries, which offer a wide range of options, we initially assumed
that a full local root exploit would not be difficult to achieve. We tried
hard, however, and did not find any working attack vector so far. It could be
that we overlooked something in the area of the low level BPF handling
regarding the attacker-controlled input files discussed in the previous
section, however.</p>

<p><code class="language-plaintext highlighter-rouge">scx_loader</code> is saved from a trivial local root exploit merely by the fact
that only a subset of the available scx scheduler binaries is accessible via
its interface. The <code class="language-plaintext highlighter-rouge">scx_chaos</code> scheduler, which is not among the schedulers
offered by the D-Bus service, supports <a href="https://github.com/sched-ext/scx/blob/e25cc6e5920f33d5bbe2bd62b2e7a5854de88a19/scheds/rust/scx_chaos/src/lib.rs#L711">a positional command line
argument</a> referring to a “Program to run under the chaos
scheduler”. Would this scheduler be accessible via D-Bus, then unprivileged
users could cause user controlled programs to be executed with full root
privileges, leading to arbitrary code execution.</p>

<p>From discussions with upstream it sounds like the exclusion of schedulers like
<code class="language-plaintext highlighter-rouge">scx_chaos</code> from the D-Bus interface does not stem from security concerns, but
rather from functional restrictions, because some schedulers are not supported
in all contexts, or are not stable yet.</p>

<h1 id="section-affected">5) Affected Linux Distributions</h1>

<p>From our investigations and communication with upstream it seems that only
Arch Linux is affected by the problem in its default installation of scx.
Gentoo Linux comes with an ebuild for scx, but for some reason there is no
integration of <code class="language-plaintext highlighter-rouge">scx_loader</code> into the init system and also the D-Bus autostart
configuration file is missing. Thus it will only be affected if an admin
manually invokes the service.</p>

<p>Otherwise we did not find a packaging of <code class="language-plaintext highlighter-rouge">scx_loader</code> on current Fedora Linux,
Ubuntu LTS or Debian Linux. Due to the outcome of this review we never allowed
the D-Bus service into openSUSE, which is therefore also not affected.</p>

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

<h2 id="restrict-access-to-a-group-on-d-bus-level">Restrict Access to a Group on D-Bus Level</h2>

<p>A quick fix for the worst aspects of the issue would be to restrict the
<a href="https://github.com/sched-ext/scx/blob/e25cc6e5920f33d5bbe2bd62b2e7a5854de88a19/tools/scx_loader/org.scx.Loader.conf">D-Bus configuration in <code class="language-plaintext highlighter-rouge">org.scx.Loader.conf</code></a> to allow
access to the interface only for members of a dedicated group like <code class="language-plaintext highlighter-rouge">scx</code>. This
at least prevents random unprivileged users from abusing the API.</p>

<p>We offer a <a href="/download/0001-scx_loader-D-Bus-configuration-restrict-access-to-me.patch">patch for download</a> which does
exactly this.</p>

<h2 id="use-polkit-for-authentication">Use Polkit for Authentication</h2>

<p>By integrating Polkit authentication, the use of this interface can be
restricted to physically present interactive users. Even in this case we
suggest to restrict full API access to users that can authenticate as admin,
via Polkit’s <code class="language-plaintext highlighter-rouge">auth_admin_keep</code> setting. Read-only operations can still be
allowed without authentication.</p>

<h2 id="making-the-api-more-robust">Making the API more Robust</h2>

<p>The individual methods offered by the scx.Loader D-Bus service should not
allow to perform actions beyond the intended scope, even if a caller
would have authenticated in some form as outlined in the previous sections.</p>

<p>To this end, dangerous parameters for schedulers should either be rejected
(e.g. by enforcing a whitelist of allowed parameters) or verified (e.g. by
determining whether a provided path is only under control of root and similar
checks).</p>

<p>Regarding input files, the client ideally should not pass path names at all,
but send file descriptors instead, to avoid unexpected surprises and the
burden of verifying input paths in the privileged D-Bus service.</p>

<h2 id="use-systemd-sandboxing">Use systemd Sandboxing</h2>

<p>The systemd service for <code class="language-plaintext highlighter-rouge">scx_loader</code> could make use of various hardening
options that systemd offers (like <code class="language-plaintext highlighter-rouge">ProtectSystem=full</code>), as long as these
do not interfere with the functionality of the service. This would
prevent more dangerous attack vectors from succeeding if the first line of
defense fails.</p>

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

<p>Upstream showed <a href="https://github.com/sched-ext/scx/issues/2847#issuecomment-3365496251">a reluctant reaction</a> to the report
we provided <a href="https://github.com/sched-ext/scx/issues/2847">in a GitHub issue</a>, rejecting parts of our
assessment. An attempt to <a href="https://github.com/sched-ext/scx/pull/2970">introduce a Polkit authentication
layer</a> based on AI-generated code was abandoned quickly,
and upstream instead split off the <code class="language-plaintext highlighter-rouge">scx_loader</code> service into a <a href="https://github.com/sched-ext/scx-loader">new
repository</a> to separate it from the <code class="language-plaintext highlighter-rouge">scx</code> core project. Our
original GitHub issue has been closed, and we <a href="https://github.com/sched-ext/scx-loader/issues/12">cloned it</a>
in the new repository to keep track of the issue.</p>

<p>Downstream integrators of <code class="language-plaintext highlighter-rouge">scx_loader</code> can can limit access to the D-Bus
service to members of an <code class="language-plaintext highlighter-rouge">scx</code> group by applying the patch we offer in the
<a href="#section-suggested-fixes">Suggested Fixes</a> section. This way access to the
problematic API becomes opt-in, and is restricted to more privileged users
that actually intend to use this service.</p>

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

<p>We suggested to upstream to assign at least one cumulative CVE to generally
cover the unauthenticated D-Bus interface aspect leading to local DoS,
potential information disclosure and integrity violation. We offered to assign
a CVE from the SUSE pool to simplify the process.</p>

<p>Upstream did not respond to this and did not clearly confirm the issues we
raised, but rather rejected certain elements of our report. For this reason
there is currently no CVE assignment available.</p>

<h1 id="section-timeline">9) Timeline</h1>

<table id="section-timeline">
  <tbody>
    <tr>
      <td>2025-09-30</td>
      <td>We contacted one of the upstream developers by email and asked for a security contact of the project, since none was documented in the repository.</td>
    </tr>
    <tr>
      <td>2025-09-30</td>
      <td>The upstream developer agreed to handle the report together with a fellow developer of the project.</td>
    </tr>
    <tr>
      <td>2025-09-30</td>
      <td>We shared a detailed report with the two developers.</td>
    </tr>
    <tr>
      <td>2025-10-02</td>
      <td>After analysis of the report, the upstream developer suggested to create a public GitHub issue, <a href="https://github.com/sched-ext/scx/issues/2847">which we did</a>.</td>
    </tr>
    <tr>
      <td>2025-10-03</td>
      <td>An upstream developer <a href="https://github.com/sched-ext/scx/issues/2847#issuecomment-3365496251">responded to the issue</a> rejecting various parts of our report.</td>
    </tr>
    <tr>
      <td>2025-10-28</td>
      <td>With some delay we provided <a href="https://github.com/sched-ext/scx/issues/2847#issuecomment-3455392651">a short reply</a>, pointing out that the rejections seem to miss the central point of the change of privilege which is taking place.</td>
    </tr>
    <tr>
      <td>2025-10-28</td>
      <td>Upstream <a href="https://github.com/sched-ext/scx/pull/2970">created a pull request</a> based on AI-generated code to add an authentication layer to the D-Bus service.</td>
    </tr>
    <tr>
      <td>2025-10-28</td>
      <td>Upstream closed the unmerged pull request shortly after. The discussion sounded like upstream no longer intends to support the <code class="language-plaintext highlighter-rouge">scx_loader</code> D-Bus service in this repository.</td>
    </tr>
    <tr>
      <td>2025-11-03</td>
      <td>We provided a <a href="https://github.com/sched-ext/scx/issues/2847#issuecomment-3480324604">more detailed reply</a> to the issue discussion.</td>
    </tr>
    <tr>
      <td>2025-11-04</td>
      <td>Upstream closed the GitHub issue and split off <a href="https://github.com/sched-ext/scx-loader">a dedicated repository</a> for <code class="language-plaintext highlighter-rouge">scx_loader</code></td>
    </tr>
    <tr>
      <td>2025-11-06</td>
      <td>We <a href="https://github.com/sched-ext/scx-loader/issues/12">cloned the original issue</a> in the new repository</td>
    </tr>
    <tr>
      <td>2025-11-06</td>
      <td>Publication of this report.</td>
    </tr>
  </tbody>
</table>

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

<ul>
  <li><a href="https://github.com/sched-ext/scx">scx GitHub repository</a></li>
  <li><a href="https://github.com/sched-ext/scx/issues/2847">scx GitHub issue for this report</a></li>
  <li><a href="https://github.com/sched-ext/scx-loader">newly created <code class="language-plaintext highlighter-rouge">scx_loader</code> GitHub repository</a></li>
  <li><a href="https://github.com/sched-ext/scx-loader/issues/12">cloned GitHub issue in the new <code class="language-plaintext highlighter-rouge">scx_loader</code> repository</a></li>
  <li><a href="https://bugzilla.suse.com/show_bug.cgi?id=1250449">openSUSE Bugzilla review bug</a></li>
  <li><a href="/download/0001-scx_loader-D-Bus-configuration-restrict-access-to-me.patch">suggested patch to restrict access to the D-Bus service</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="local" /><category term="DoS" /><category term="D-Bus" /><summary type="html"><![CDATA[The scx project offers a range of dynamically loadable custom schedulers which make use of the Linux kernel's `sched_ext` feature. An optional D-Bus service `scx_loader` provides an interface accessible to all users, allowing them to nearly arbitrarily change the scheduling properties of the system, leading to Denial-of-Service and other attack vectors. Upstream rejected parts of our report, moved the `scx_loader` component into a separate repository and no bugfix is available as of now.]]></summary></entry><entry><title type="html">OpenSMTPD: Trivial Local Denial-of-Service via UNIX Domain Socket (CVE-2025-62875)</title><link href="https://security.opensuse.org/2025/10/31/opensmtpd-local-DoS.html" rel="alternate" type="text/html" title="OpenSMTPD: Trivial Local Denial-of-Service via UNIX Domain Socket (CVE-2025-62875)" /><published>2025-10-31T00:00:00+00:00</published><updated>2025-10-31T00:00:00+00:00</updated><id>https://security.opensuse.org/2025/10/31/opensmtpd-local-DoS</id><content type="html" xml:base="https://security.opensuse.org/2025/10/31/opensmtpd-local-DoS.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-local-dos" id="markdown-toc-section-local-dos">2) Local DoS Issue via UNIX Domain Socket (CVE-2025-62875)</a>    <ul>
      <li><a href="#section-memory-leak" id="markdown-toc-section-memory-leak">Memory Leak on Regular Connection Close</a></li>
      <li><a href="#section-dos-workaround" id="markdown-toc-section-dos-workaround">Workaround by Adjusting Socket Permissions</a></li>
      <li><a href="#reproducer" id="markdown-toc-reproducer">Reproducer</a></li>
      <li><a href="#affected-versions" id="markdown-toc-affected-versions">Affected Versions</a></li>
      <li><a href="#affected-systems" id="markdown-toc-affected-systems">Affected Systems</a></li>
      <li><a href="#cve-assignment" id="markdown-toc-cve-assignment">CVE Assignment</a></li>
      <li><a href="#upstream-bugfix" id="markdown-toc-upstream-bugfix">Upstream Bugfix</a></li>
    </ul>
  </li>
  <li><a href="#section-setuid" id="markdown-toc-section-setuid">3) Notes on setuid and setgid Binaries</a>    <ul>
      <li><a href="#lockspool" id="markdown-toc-lockspool">lockspool</a></li>
      <li><a href="#smtpctl" id="markdown-toc-smtpctl">smtpctl</a></li>
    </ul>
  </li>
  <li><a href="#section-network-code" id="markdown-toc-section-network-code">4) Notes on the Network-Facing OpenSMTPD Code</a></li>
  <li><a href="#5-timeline" id="markdown-toc-5-timeline">5) Timeline</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://www.opensmtpd.org/">OpenSMTPD</a> is an implementation of the server-side SMTP
protocol offered by the OpenBSD project. A few months ago a SUSE colleague
started packaging it for openSUSE Tumbleweed, which led to <a href="https://bugzilla.suse.com/show_bug.cgi?id=1247781">a code review of
the package</a>.</p>

<p>While looking into a local API offered by OpenSMTPD we discovered a trivial
local Denial-of-Service (DoS) attack vector which allows unprivileged users to
cause the shutdown of all smtpd services. The full details about the issue
follow in <a href="#section-local-dos">section 2</a>. Some additional remarks about
setuid-root and setgid utilities contained in OpenSMTPD are found in <a href="#section-setuid">section
3</a>. A quick survey of the network-facing code of OpenSMTPD is
provided in <a href="#section-network-code">section 4</a>.</p>

<p>Note that two source code repositories for OpenSMTPD exist. The most
up-to-date code is found in the <a href="https://cvsweb.openbsd.org/src/usr.sbin/smtpd">OpenBSD CVS repository</a>,
while the portable version <a href="https://github.com/OpenSMTPD/OpenSMTPD">is found on GitHub</a>. The
portable version offers cross platform support for various kinds of UNIX
systems, including Linux and the other BSDs. This report is based on the
portable <a href="https://github.com/OpenSMTPD/OpenSMTPD/releases/tag/7.7.0p0">OpenSMTPD version 7.7.0p0</a>.</p>

<p>We reported the local DoS issue to upstream but <a href="#section-timeline">did not get a
response</a> until two days before publication, due to
communication issues. By now an <a href="https://github.com/OpenSMTPD/OpenSMTPD/commit/653abf00f5283a2d3247eb9aabf8987d1b2f0510">upstream bugfix</a> is
available which will be part of a pending 7.8.0 release, but it seems an
independent <a href="#section-memory-leak">memory leak</a> issue remains unaddressed.</p>

<h1 id="section-local-dos">2) Local DoS Issue via UNIX Domain Socket (CVE-2025-62875)</h1>

<p>OpenSMTPD contains the <code class="language-plaintext highlighter-rouge">smtpctl</code> program, which communicates with the <code class="language-plaintext highlighter-rouge">smtpd:
control</code> daemon instance via a UNIX domain socket in <code class="language-plaintext highlighter-rouge">/var/run/smtpd.sock</code>.
While looking into the protocol used for this purpose, we noticed a trivial
local Denial-of-Service attack vector affecting all of OpenSMTPD.</p>

<p>The UNIX domain socket <code class="language-plaintext highlighter-rouge">smtpd.sock</code> has file mode <code class="language-plaintext highlighter-rouge">0666</code> and is thus writable
for all users in the system, allowing anybody to create local connections
towards <code class="language-plaintext highlighter-rouge">smtpd</code>.</p>

<p>In the daemon’s code in <a href="https://github.com/OpenSMTPD/OpenSMTPD/blob/8c07e2a4b3d61d01483bd0f61031cb93ed46c9cf/usr.sbin/smtpd/mproc.c#L159"><code class="language-plaintext highlighter-rouge">mproc_dispatch()</code></a> the
process exits via <code class="language-plaintext highlighter-rouge">fatal()</code> in case anything goes wrong while handling such a
UNIX domain socket connection. Two common error situations leading to this are
bad returns from <code class="language-plaintext highlighter-rouge">readv()</code> in <a href="https://github.com/OpenSMTPD/OpenSMTPD/blob/8c07e2a4b3d61d01483bd0f61031cb93ed46c9cf/openbsd-compat/imsg-buffer.c#L826"><code class="language-plaintext highlighter-rouge">ibuf_read()</code></a> or a bad message
length value in the message header, which is detected in
<a href="https://github.com/OpenSMTPD/OpenSMTPD/blob/8c07e2a4b3d61d01483bd0f61031cb93ed46c9cf/openbsd-compat/imsg.c#L369"><code class="language-plaintext highlighter-rouge">imsg_parse_hdr()</code></a>.  Similar error conditions exist in
the <a href="https://github.com/OpenSMTPD/OpenSMTPD/blob/8c07e2a4b3d61d01483bd0f61031cb93ed46c9cf/openbsd-compat/imsg-buffer.c#L878"><code class="language-plaintext highlighter-rouge">msgbuf_read()</code></a> call path which is used when file
descriptor passing is enabled on the connection (see
<a href="https://github.com/OpenSMTPD/OpenSMTPD/blob/8c07e2a4b3d61d01483bd0f61031cb93ed46c9cf/openbsd-compat/imsg.c#L74"><code class="language-plaintext highlighter-rouge">imsgbuf_read()</code></a>).</p>

<p>As a result, sending a malformed message with a bad header length is enough
for a client to provoke the invocation of <code class="language-plaintext highlighter-rouge">fatal()</code> on the daemon side.  Once
<code class="language-plaintext highlighter-rouge">fatal()</code> is called, the <code class="language-plaintext highlighter-rouge">smtpd: control</code> instance ends execution and causes
the whole smtpd instance to be shut down along with it.</p>

<p>We learned from upstream that the reason for the call to <code class="language-plaintext highlighter-rouge">fatal()</code> is that
<code class="language-plaintext highlighter-rouge">smtpd.sock</code> is used for two different purposes at the same time:</p>

<ul>
  <li>connections from other, trusted <code class="language-plaintext highlighter-rouge">smtpd</code> daemon instances.</li>
  <li>connections from arbitrary other clients using the <code class="language-plaintext highlighter-rouge">smtpctl</code> program.</li>
</ul>

<p>The call to <code class="language-plaintext highlighter-rouge">fatal()</code> is made with the first kind of connections in mind.
These connections are established during startup, and if anything goes wrong
while processing data from other <code class="language-plaintext highlighter-rouge">smtpd</code> daemon instances, then a bug in
OpenSMTPD itself is assumed, and a shutdown of all daemon processes is a
viable course of action.</p>

<p>The second kind of connections was left unconsidered in this logic, thus
allowing unprivileged clients to trigger this code path which leads to the
local DoS. The <a href="https://github.com/OpenSMTPD/OpenSMTPD/commit/653abf00f5283a2d3247eb9aabf8987d1b2f0510">upstream bugfix</a> consequently consists
of an added <code class="language-plaintext highlighter-rouge">if</code> clause which excludes the second type of connections from the
call to <code class="language-plaintext highlighter-rouge">fatal()</code>.</p>

<h2 id="section-memory-leak">Memory Leak on Regular Connection Close</h2>

<p>While looking into a possible bugfix for the DoS issue, we noticed
<a href="https://github.com/OpenSMTPD/OpenSMTPD/blob/8c07e2a4b3d61d01483bd0f61031cb93ed46c9cf/openbsd-compat/imsg-buffer.c#L799">a comment in the code</a>, which points to unsolved
cleanup issues, when processing a connection fails:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ibuf_read_process</span><span class="p">(</span><span class="k">struct</span> <span class="n">msgbuf</span> <span class="o">*</span><span class="n">msgbuf</span><span class="p">,</span> <span class="kt">int</span> <span class="n">fd</span><span class="p">)</span>
<span class="p">{</span>
    <span class="cm">/* &lt;&lt;&lt; SNIP &gt;&gt;&gt; */</span>
<span class="nl">fail:</span>
    <span class="cm">/* XXX how to properly clean up is unclear */</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">fd</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
        <span class="n">close</span><span class="p">(</span><span class="n">fd</span><span class="p">);</span>
    <span class="k">return</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This made us wonder, if the cleanup is unclear in error conditions, is it
maybe also unclear during regular operation? After all, proper cleanup will be
needed regardless of whether a connection ends gracefully or not. As it
happens, the cleanup logic for a regular connection close and for an erroneous
connection close indeed is equivalent in OpenSMTPD.</p>

<p>To this end, we tested what happens when a lot of UNIX domain socket
connections towards <code class="language-plaintext highlighter-rouge">smtpd</code> are created and closed in succession. The outcome
indeed is that the memory used by the <code class="language-plaintext highlighter-rouge">smtpd: control</code> instance
continuously grows. Thus it seems there is a memory leak present here as
well independently of the main issue described above. We did not analyze this
in more detail, but upstream is aware of the issue and is analyzing it on
their end.</p>

<p>This independent issue means that unprivileged clients can trigger the memory
leak in the <code class="language-plaintext highlighter-rouge">smtpd: control</code> daemon, even after applying the <a href="https://github.com/OpenSMTPD/OpenSMTPD/commit/653abf00f5283a2d3247eb9aabf8987d1b2f0510">upstream
bugfix</a> to fix the main issue in this report. The
impact will also be a local DoS, it will take a much longer time to execute
it, however, because the memory leak is small and in our tests only consumes
about 100 megabytes within half an hour. The next section describes a possible
temporary workaround to avoid this issue, as well.</p>

<h2 id="section-dos-workaround">Workaround by Adjusting Socket Permissions</h2>

<p>We initially suggested <a href="/download/0001-control_create_socket-prevent-world-access-to-UNIX-d.patch">a different patch</a> to
address the local DoS issue, tightening the permissions of the
<code class="language-plaintext highlighter-rouge">smtpd.sock</code> UNIX domain socket. We wrongly assumed that there were no valid
use cases for non-root users connecting to this socket. Shortly before
publication we learned from upstream that there actually is a valid use case
for this scenario: non-root users can enqueue mail using the <code class="language-plaintext highlighter-rouge">sendmail</code>
interface, which makes use of this socket.</p>

<p>Even though our suggested patch causes a regression in this case, it reduces
attack surface and provides protection against the memory leak described in
the previous section. For some users of OpenSMTPD it can thus be a sensible
option to use this patch if the described use case is not needed, at least
until upstream provides a fix for the memory leak issue, as well.</p>

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

<p>We offer a <a href="/download/talk_smtpd.py">simple Python script</a> to reproduce the issue.
The script creates a connection towards <code class="language-plaintext highlighter-rouge">smtpd.sock</code> and sends an excessive
header length. If the reproducer works, the <code class="language-plaintext highlighter-rouge">smtpd</code> daemon processes will all
exit immediately.</p>

<h2 id="affected-versions">Affected Versions</h2>

<p>In <a href="https://github.com/OpenSMTPD/OpenSMTPD/commit/3270e23a6eb">commit 3270e23a6eb</a>, which first made its way into
version 7.7.0, major changes to the message parsing code have been introduced,
including the call to <code class="language-plaintext highlighter-rouge">fatal()</code>. Triggering the issue was easily possible in
our tests for all packages based on this version.</p>

<p>It is unclear if older versions might be affected by some variant of this
issue as well. We only verified that the trivial reproducer does not work
against version 7.6.0 of OpenSMTPD.</p>

<h2 id="affected-systems">Affected Systems</h2>

<p>We verified that the issue affects the following systems, which all offer
OpenSMTPD version 7.7.0:</p>

<ul>
  <li>Arch Linux (fully updated on 2025-09-29)</li>
  <li>Debian 13</li>
  <li>Fedora 42</li>
  <li>Gentoo Linux using the 7.7.0p0 ebuild</li>
  <li>OpenBSD 7.7</li>
  <li>NetBSD 10.1 (using the package available from <a href="https://pkgsrc.org">pkgsrc</a>)</li>
</ul>

<p>On FreeBSD 14.2, where only the older version 7.6.0 of OpenSMTPD is available,
we could not reproduce the issue.</p>

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

<p>Without a formal confirmation from upstream we were reluctant to assign a
CVE for the issue. The case seemed clear-cut, however, and when we were
asked to provide a CVE on the <a href="https://oss-security.openwall.org/wiki/mailing-lists/distros">distros mailing list</a>, we
assigned CVE-2025-62875 and also communicated this to upstream.</p>

<p>When contact to upstream was established shortly before the publication of
this report, upstream picked up this CVE and used it to document their bugfix.</p>

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

<p>Upstream already published the <a href="https://github.com/OpenSMTPD/OpenSMTPD/commit/653abf00f5283a2d3247eb9aabf8987d1b2f0510">bugfix commit</a> for the
main issue in this report. The release of OpenSMTPD version 7.8.0 containing
this bugfix is expected soon, and <a href="https://www.mail-archive.com/misc@opensmtpd.org/msg06634.html">was already
announced</a> on the upstream mailing list.</p>

<h1 id="section-setuid">3) Notes on setuid and setgid Binaries</h1>

<p>The original reason for reviewing OpenSMTPD in the first place was the
<a href="https://bugzilla.suse.com/show_bug.cgi?id=1247781#c1">presence of setuid and setgid binaries</a> in the
package. The following sub-sections give a short summary of the outcome of the
review.</p>

<h2 id="lockspool">lockspool</h2>

<p><code class="language-plaintext highlighter-rouge">/usr/libexec/opensmtpd/lockspool</code> is a world-accessible setuid-root binary
which is used to synchronize parallel access to a user’s spool.</p>

<p>The <a href="https://github.com/OpenSMTPD/OpenSMTPD/blob/8c07e2a4b3d61d01483bd0f61031cb93ed46c9cf/contrib/libexec/lockspool/locking.c#L60">lockspool code</a> found in the OpenSMTPD portable
release is quite complex and <a href="https://bugzilla.suse.com/show_bug.cgi?id=1247781#c3">is based on some
assumptions</a> that might not hold true. This code
can allow for a minor local DoS in multi-user scenarios. The <a href="https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/libexec/mail.local/locking.c?rev=1.15&amp;content-type=text/plain">OpenBSD CVS
repository</a> already contains a simplified locking
algorithm which is not affected by this.</p>

<p>We reached out to upstream about this separately from the UNIX domain socket
DoS issue. In this instance we quickly got a reply and upstream <a href="https://github.com/OpenSMTPD/OpenSMTPD/commit/91be977454d422af71700aeec247464e313320de">merged the
change</a> from the CVS repository into the OpenBSD
portable repository. This change will be part of the OpenSMTPD 7.8.0 release.
We <a href="https://build.opensuse.org/projects/openSUSE:Factory/packages/OpenSMTPD/files/OpenSMTPD-simplified-world-writable-spoolers-handling.patch?expand=1">backported the change</a> into the openSUSE packaging of
OpenSMTPD as well.</p>

<h2 id="smtpctl">smtpctl</h2>

<p><code class="language-plaintext highlighter-rouge">/usr/sbin/smtpctl</code> is a world-accessible setgid binary operating in <code class="language-plaintext highlighter-rouge">_smtpq</code>
group context. The program uses these special group privileges to store mail
in the directory <br /><code class="language-plaintext highlighter-rouge">/var/spool/smtpd/offline</code>, when the smtpd services are not
running.</p>

<p>The <code class="language-plaintext highlighter-rouge">_smtpq</code> group privileges are only used for this well defined purpose and
the extra privileges are also dropped as soon as they are no longer needed. We
found no issues in this aspect of the program.</p>

<h1 id="section-network-code">4) Notes on the Network-Facing OpenSMTPD Code</h1>

<p>After we found the local security issues described in this report, we thought
it a good idea to also have at least <a href="https://bugzilla.suse.com/show_bug.cgi?id=1247781#c18">a cursory look at the actual
network-facing SMTP protocol parsing code</a> found in
OpenSMTPD. We could not find any tangible security issues in these parts,
still here is a short summary of our impression of the code:</p>

<ul>
  <li>the protocol parsing is implemented in plain C and thus error prone. The
implementation does have this under control, however, even though there is
some redundancy in handling the various message types.</li>
  <li>a lot of parsing is done manually without the help of third party libraries,
including things like domain name end email address verification.</li>
  <li>transmission of plaintext passwords is rejected on unencrypted connections,
which is a good security stance.</li>
  <li>the daemon processing network data is running with limited service user
credentials and is also placed into a <code class="language-plaintext highlighter-rouge">chroot</code> jail, which reduces attack
surface.</li>
  <li>the daemon logs every bad SMTP protocol message by default, including
attacker controlled data, which is a bit peculiar. The logging systems on
the BSDs and Linux systems we looked into are able to deal with this in safe
ways, however (e.g. terminal escape sequences are escaped or stripped).</li>
</ul>

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

<table id="section-timeline">
  <tbody>
    <tr>
      <td>2025-09-15</td>
      <td>We reported the issue to <a href="mailto:security@openbsd.org">security@openbsd.org</a>, offering coordinated disclosure. We quickly got a short reply that the topic had been forwarded to the relevant people.</td>
    </tr>
    <tr>
      <td>2025-09-29</td>
      <td>After two weeks without a more detailed response, we sent a follow-up email asking for confirmation of the issue and if coordinated disclosure was desired, or not. We asked for a response until 2025-10-02, otherwise we would publish the finding on our own terms.</td>
    </tr>
    <tr>
      <td>2025-10-02</td>
      <td>Still without response, we decided to  partially publish the issue by adding <a href="https://build.opensuse.org/projects/openSUSE:Factory/packages/OpenSMTPD/files/OpenSMTPD-reduced-permissions-on-SMTPD_SOCKET.patch?expand=1">a patch</a> to our packaging, which secures the UNIX domain socket permissions.</td>
    </tr>
    <tr>
      <td>2025-10-23</td>
      <td>We approached the <a href="https://oss-security.openwall.org/wiki/mailing-lists/distros">distros mailing list</a> to give a heads-up to other distributions about the issue. We suggested an embargo until 2025-10-31.</td>
    </tr>
    <tr>
      <td>2025-10-24</td>
      <td>A member of the distros mailing list asked for a CVE, so we decided to assign CVE-2025-62875 and also informed upstream about this and the ongoing embargo on the distros mailing list.</td>
    </tr>
    <tr>
      <td>2025-10-27</td>
      <td>We shared the <a href="/download/0001-control_create_socket-prevent-world-access-to-UNIX-d.patch">suggested patch</a> with the distros mailing list, which we initially had forgotten to do.</td>
    </tr>
    <tr>
      <td>2025-10-29</td>
      <td>An OpenSMTPD developer finally replied to our report, explaining that the information had been lost internally until now. Upstream confirmed the issue and informed us that a bugfix release was being prepared for 2025-11-03 at the latest.</td>
    </tr>
    <tr>
      <td>2025-10-30</td>
      <td>From further discussions with upstream we learned about the real intentions of the call to <code class="language-plaintext highlighter-rouge">fatal()</code> and about the regression caused by our <a href="/download/0001-control_create_socket-prevent-world-access-to-UNIX-d.patch">suggested patch</a>. We on the other hand informed upstream about the additional <a href="#section-memory-leak">memory leak</a> issue we stumbled upon.</td>
    </tr>
    <tr>
      <td>2025-10-31</td>
      <td>Upstream published its <a href="https://github.com/OpenSMTPD/OpenSMTPD/commit/653abf00f5283a2d3247eb9aabf8987d1b2f0510">bugfix for the main issue</a>.</td>
    </tr>
    <tr>
      <td>2025-10-31</td>
      <td>We updated our report with the latest information from upstream and published it.</td>
    </tr>
  </tbody>
</table>

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

<ul>
  <li><a href="https://www.opensmtpd.org/">OpenSMTPD website</a></li>
  <li><a href="https://github.com/OpenSMTPD/OpenSMTPD">OpenSMTPD portable Git repository</a></li>
  <li><a href="/download/0001-control_create_socket-prevent-world-access-to-UNIX-d.patch">Suggested patch to work around the issue (includes a possible regression!)</a></li>
  <li><a href="https://github.com/OpenSMTPD/OpenSMTPD/commit/653abf00f5283a2d3247eb9aabf8987d1b2f0510">Upstream bugfix of the issue (leaves a memory leak issue unaddressed)</a></li>
  <li><a href="/download/talk_smtpd.py">Python script to reproduce the issue</a></li>
  <li><a href="https://bugzilla.suse.com/show_bug.cgi?id=1247781">openSUSE Bugzilla review bug for OpenSMTPD</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="local" /><category term="CVE" /><category term="DoS" /><summary type="html"><![CDATA[A world-writable `smtpd.sock` allows arbitrary local users to crash an OpenSMTPD instance in version 7.7.0. Upstream provided a bugfix after a longer time of silence, but there might still linger a memory leak issue in the socket handling code, which remains unaddressed.]]></summary></entry><entry><title type="html">SUSE Security Team Spotlight Summer 2025</title><link href="https://security.opensuse.org/2025/10/01/summer-spotlight.html" rel="alternate" type="text/html" title="SUSE Security Team Spotlight Summer 2025" /><published>2025-10-01T00:00:00+00:00</published><updated>2025-10-01T00:00:00+00:00</updated><id>https://security.opensuse.org/2025/10/01/summer-spotlight</id><content type="html" xml:base="https://security.opensuse.org/2025/10/01/summer-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="#2-systemd-v258-local-root-exploit-in-new-systemd-machined-api-found-in-release-candidates" id="markdown-toc-2-systemd-v258-local-root-exploit-in-new-systemd-machined-api-found-in-release-candidates">2) systemd v258: Local Root Exploit in new systemd-machined API found in Release Candidates</a>    <ul>
      <li><a href="#the-bugfix" id="markdown-toc-the-bugfix">The Bugfix</a></li>
      <li><a href="#increase-in-complexity-in-systemd" id="markdown-toc-increase-in-complexity-in-systemd">Increase in Complexity in systemd</a></li>
    </ul>
  </li>
  <li><a href="#3-logrotate-issues-in-drop-in-configuration-files" id="markdown-toc-3-logrotate-issues-in-drop-in-configuration-files">3) logrotate: Issues in drop-in Configuration Files</a>    <ul>
      <li><a href="#missing-su-user-group-directives" id="markdown-toc-missing-su-user-group-directives">Missing <code class="language-plaintext highlighter-rouge">su &lt;user&gt; &lt;group&gt;</code> Directives</a></li>
      <li><a href="#problems-with-scripts-embedded-in-configuration" id="markdown-toc-problems-with-scripts-embedded-in-configuration">Problems with Scripts Embedded in Configuration</a></li>
      <li><a href="#possible-improvements-in-logrotate" id="markdown-toc-possible-improvements-in-logrotate">Possible Improvements in logrotate</a></li>
    </ul>
  </li>
  <li><a href="#4-gnome-49-d-bus-and-polkit-changes-in-new-major-version-release" id="markdown-toc-4-gnome-49-d-bus-and-polkit-changes-in-new-major-version-release">4) GNOME 49: D-Bus and Polkit Changes in new Major Version Release</a></li>
  <li><a href="#5-kea-dhcp-follow-up-review-of-network-attack-surface" id="markdown-toc-5-kea-dhcp-follow-up-review-of-network-attack-surface">5) Kea DHCP: Follow-Up Review of Network Attack Surface</a></li>
  <li><a href="#6-chrony-issues-in-chronyc-socket-creation" id="markdown-toc-6-chrony-issues-in-chronyc-socket-creation">6) chrony: Issues in chronyc Socket Creation</a></li>
  <li><a href="#7-pwaccessd-new-varlink-service-for-reading-user-account-information" id="markdown-toc-7-pwaccessd-new-varlink-service-for-reading-user-account-information">7) pwaccessd: New Varlink Service for Reading User Account Information</a></li>
  <li><a href="#8-sysextmgr-new-varlink-service-for-managing-systemd-sysext-images" id="markdown-toc-8-sysextmgr-new-varlink-service-for-managing-systemd-sysext-images">8) sysextmgr: New Varlink Service for Managing systemd-sysext Images</a></li>
  <li><a href="#9-bash-git-prompt-predictable-temporary-file-name-offers-local-attack-surface-cve-2025-61659" id="markdown-toc-9-bash-git-prompt-predictable-temporary-file-name-offers-local-attack-surface-cve-2025-61659">9) bash-git-prompt: Predictable Temporary File Name Offers Local Attack Surface (CVE-2025-61659)</a></li>
  <li><a href="#10-steam-powerbuttond-insecure-operation-in-home-directories" id="markdown-toc-10-steam-powerbuttond-insecure-operation-in-home-directories">10) steam-powerbuttond: Insecure Operation in Home Directories</a></li>
  <li><a href="#11-conclusion" id="markdown-toc-11-conclusion">11) Conclusion</a></li>
  <li><a href="#change-history" id="markdown-toc-change-history">Change History</a></li>
</ul>

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

<p>Autumn is already palpable for many of us these days and this means it is time
to take a look back at what happened in our team during the summer months. We
have not published any dedicated security reports during that time; instead
we have all the more to cover in this edition of the spotlight series which
discusses code review efforts that did not lead to major findings or otherwise
did not qualify for a dedicated report.</p>

<p>This is also the first anniversary of the spotlight series, which we started
in August 2024 with the first summer spotlight edition. We are happy to
provide our readers with interesting content about the daily work in our team
and are looking forward to more anniversaries to come.</p>

<p>In this issue we will cover <a href="#section-systemd">a local root exploit we discovered in systemd
v258-rc4</a> before it became part of a stable release, problems
found in <a href="#section-logrotate">logrotate drop-in configuration files</a>, <a href="#section-gnome">changes
in D-Bus configuration files</a> related to the GNOME version 49
release, and a follow-up <a href="#section-kea">code review of the Kea DHCP server
suite</a>. Furthermore we found a <a href="#section-chrony">symlink attack issue in
<code class="language-plaintext highlighter-rouge">chronyc</code></a>, proactively reviewed <a href="#section-varlink">new Varlink
services</a> developed by fellow SUSE engineers and discovered a
local privilege escalation issue in <a href="#section-bgp">bash-git-prompt</a>. Finally we
will talk about a <a href="#section-powerbuttond">problematic script used on Steam Deck
devices</a>.</p>

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

<h1 id="2-systemd-v258-local-root-exploit-in-new-systemd-machined-api-found-in-release-candidates">2) systemd v258: Local Root Exploit in new systemd-machined API found in Release Candidates</h1>

<p>At the beginning of August one of our systemd maintainers <a href="https://bugzilla.suse.com/show_bug.cgi?id=1247556">asked us to review
D-Bus and Polkit API changes</a> in a release candidate of
systemd 258.  This major version update of systemd contains many API additions
e.g. in <code class="language-plaintext highlighter-rouge">systemd-resolved</code>, <code class="language-plaintext highlighter-rouge">systemd-homed</code>, <code class="language-plaintext highlighter-rouge">systemd-machined</code> and
<code class="language-plaintext highlighter-rouge">systemd-nsresourced</code>.</p>

<p>While looking into these changes we found an issue in <code class="language-plaintext highlighter-rouge">systemd-machined</code>. This
daemon can be used to manage virtual machines and containers alike.
In upstream <a href="https://github.com/systemd/systemd/commit/adaff8eb35d">commit adaff8eb35d</a> a new Polkit
action “org.freedesktop.machine1.register-machine” has been added, which was
accessible to locally logged in users without authentication (Polkit <code class="language-plaintext highlighter-rouge">yes</code>
setting). The purpose of this new API is to allow users to register existing
containers with <code class="language-plaintext highlighter-rouge">systemd-machined</code>, that have been created by other means.</p>

<p>There exist two D-Bus methods which employ this Polkit action:
“RegisterMachine” and “RegisterMachineWithNetwork”. Both accept <a href="https://github.com/systemd/systemd/blob/v258-rc4/src/machine/machined-dbus.c#L969">a
rather long list of parameters</a> to describe the
container which is supposed to be registered with the daemon. The following
command line performs an example registration of a fake container:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gdbus call <span class="nt">-y</span> <span class="nt">-d</span> org.freedesktop.machine1 <span class="nt">-o</span> /org/freedesktop/machine1 <span class="se">\</span>
    <span class="nt">-m</span> org.freedesktop.machine1.Manager.RegisterMachineWithNetwork <span class="se">\</span>
    mymachine <span class="s1">'[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]'</span> myservice container <span class="se">\</span>
    <span class="nv">$$</span> <span class="nv">$PWD</span> <span class="s1">'[1, 2, 3]'</span>
</code></pre></div></div>

<p>Among these parameters is the process ID (PID) of the leader process of the
container. In this example <code class="language-plaintext highlighter-rouge">$$</code>, i.e. the shell’s own PID, is passed as leader
PID. The release candidate implementation of <code class="language-plaintext highlighter-rouge">systemd-machined</code> failed to
verify whether this process is owned by the caller and an actual member of an
unprivileged <a href="https://man7.org/linux/man-pages/man7/user_namespaces.7.html">user namespace</a> belonging to a container.</p>

<p>The first problematic aspect we noticed about this was that <code class="language-plaintext highlighter-rouge">systemd-machined</code>
can send <code class="language-plaintext highlighter-rouge">SIGTERM</code> to the process group the given leader PID belongs to (e.g.
when registering a new container using the same name), allowing a trivial
local Denial-of-Service against arbitrary other processes. Far more
problematic was something else that we noticed: the unprivileged user was able
to enter a shell in such a crafted container, like this:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>user<span class="nv">$ </span>machinectl shell mymachine
<span class="c"># full root privileges, this happens in the actual host's file system</span>
container-root# <span class="nb">touch</span> /evil
</code></pre></div></div>

<p>Since the leader PID in this case is a process belonging to the host’s initial
namespaces, the root shell for the “container” is actually a root shell in
the host itself, giving full root privileges over the system.</p>

<p>This problem is found in all release candidates of systemd v258. We reported
the problem privately to systemd security, and upstream developed bugfixes
right away while still in the RC phase.
The local root exploit was never present in any stable release version and
thus end users are not affected by the problem, which is also why no CVE was
assigned.</p>

<h2 id="the-bugfix">The Bugfix</h2>

<p>To address the issue, <code class="language-plaintext highlighter-rouge">systemd-machined</code> now verifies that the leader PID
specified by the client is actually owned by the caller. Furthermore the
authentication requirements for Polkit action “register-machine” have been
raised to <code class="language-plaintext highlighter-rouge">auth_admin_keep</code> even for local users.</p>

<p>While writing this very summary we noticed that one aspect of the issue had
been overlooked and was not fixed for the stable release: the verification of
the user namespace membership of the target process. Thus it is still possible
to gain a root shell this way, but only after authenticating as admin, which
means the caller already needs admin privileges to trigger the exploit. This
aspect <a href="https://github.com/systemd/systemd/pull/39102">has now been addressed for future releases </a> by
upstream, which is important, because upstream intends to relax the
authentication requirements for this action to <code class="language-plaintext highlighter-rouge">yes</code> again at a later time.</p>

<h2 id="increase-in-complexity-in-systemd">Increase in Complexity in systemd</h2>

<p>With this version of systemd we are seeing a noticeable increase in complexity
in the implementation of a number of systemd components. In the area of
container management the complexity is pretty much by design, given the
intricacy of the different namespace mechanisms playing together, partly
under the control of unprivileged users. There is also the addition of
<a href="https://varlink.org">Varlink</a> for Inter-Process-Communication, however, which
means that two different interfaces for D-Bus and Varlink now exist in parallel
for some services. This is also the case for <code class="language-plaintext highlighter-rouge">systemd-machined</code>.</p>

<p>While the D-Bus and Varlink interfaces usually call into shared functions for
most of the business logic and share the same Polkit actions, there is
necessarily a certain amount of redundancy in parsing and evaluation of
input parameters. As a result this also increases the burden on code reviewers
which now need to keep track of two different entry paths to the same logic.</p>

<p>We are not yet completely finished with reviewing all notable changes in
systemd v258 but intend to complete the effort within the next couple of weeks.
We are happy that our review efforts already prevented a local root exploit in
software as widespread as systemd from ending up in production environments.</p>

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

<h1 id="3-logrotate-issues-in-drop-in-configuration-files">3) logrotate: Issues in drop-in Configuration Files</h1>

<h2 id="missing-su-user-group-directives">Missing <code class="language-plaintext highlighter-rouge">su &lt;user&gt; &lt;group&gt;</code> Directives</h2>

<p>Recently we noticed that there exist <a href="https://bugzilla.suse.com/show_bug.cgi?id=1245961">a number of packages in openSUSE
Tumbleweed</a> which trigger <a href="https://github.com/rpm-software-management/rpmlint/blob/1bb96561b5b715ee1e32b4b3949fd8c8d94940d9/rpmlint/checks/LogrotateCheck.py#L35">a
“logrotate-user-writable-log-dir” rpmlint
diagnostic</a>. This diagnostic is emitted when a
package contains a logrotate drop-in configuration file (e.g. in
<code class="language-plaintext highlighter-rouge">/etc/logrotate.d</code>) which points the logrotate daemon to a log directory which
is controlled by non-root accounts, where it will operate with full root
privileges.</p>

<p>Operating as <code class="language-plaintext highlighter-rouge">root</code> in locations controlled by other users is generally very
difficult to get right and can easily lead to privilege escalation from a
service user to <code class="language-plaintext highlighter-rouge">root</code> e.g. via symlink attacks. logrotate
offers a <a href="https://github.com/logrotate/logrotate/blob/4c4023aef1824c03e5be0ffee503fef6a6c2668d/logrotate.8.in#L253"><code class="language-plaintext highlighter-rouge">su &lt;user&gt; &lt;group&gt;</code> syntax</a> to
instruct the daemon to perform a privilege drop to the user owning the
directory to avoid any security implications.</p>

<p>To start with, we had a look at the implementation of the logrotate daemon, to
judge what the impact would be, when a rogue service user account tries to
perform an attack against logrotate when it starts rotating logs in a
directory controlled by the compromised user. The results are as follows:</p>

<ul>
  <li>the daemon performs <a href="https://github.com/logrotate/logrotate/blob/4c4023aef1824c03e5be0ffee503fef6a6c2668d/logrotate.c#L1448">a sanity check</a> on the
directory to operate on and rejects any log directories which are writable
by world or a non-root group. This does not include the case where the
log directory is owned by a non-root user, however.</li>
  <li><a href="https://bugzilla.suse.com/show_bug.cgi?id=1245961#c2">the system calls used by logrotate</a>
always include safe flags for opening log files which will prevent trivial
symlink attacks by service users from succeeding. There could still be more
intricate attacks when a parent directory of the log directory is also owned
by a non-root user account. This is not a common setup, however, and we could
not find any package where this is the case.</li>
</ul>

<p>In summary we believe that there are no overly dangerous situations that can
result from a missing <code class="language-plaintext highlighter-rouge">su &lt;user&gt; &lt;group&gt;</code> directive in affected logrotate
configuration files. Still we decided that it will be better to fix existing
packages and enforce that packages emitting this rpmlint diagnostic are not
allowed into openSUSE in the future. To this end we fixed a couple of
openSUSE-specific logrotate drop-in configuration files as well as an <a href="https://github.com/dun/munge/pull/157">upstream
configuration file in Munge</a>.</p>

<h2 id="problems-with-scripts-embedded-in-configuration">Problems with Scripts Embedded in Configuration</h2>

<p>While looking into the credentials mismatch issue we noticed that logrotate
can end up in even more complex usage scenarios. The configuration file format
allows shell scripts to be embedded that will be executed after rotating
logfiles, for example. These scripts always run with full <code class="language-plaintext highlighter-rouge">root</code> privileges,
independently of an existing <code class="language-plaintext highlighter-rouge">su &lt;user&gt; &lt;group&gt;</code> directive. The likeliness of
security issues is higher in this case and issues are harder to detect, since
this is package-specific code possibly running as <code class="language-plaintext highlighter-rouge">root</code> in untrusted
directories.</p>

<p>While exploring all embedded scripts found in logrotate drop-in configuration
files in openSUSE Tumbleweed we found out that in most cases such scripts are
only used to restart a systemd service or to send a signal to a daemon running
in the background. In a few cases the scripts have been problematic, as is
described in the following sub-sections.</p>

<h3 id="python-mailman-cve-2025-53882">python-mailman (CVE-2025-53882)</h3>

<p>In the <a href="https://bugzilla.suse.com/show_bug.cgi?id=1246467">python-mailman</a> package we found two
problems in <a href="https://build.opensuse.org/projects/openSUSE:Factory/packages/python-mailman/files/mailman.logrotate?expand=1&amp;rev=f52eeb756d292f335b10d5e8a2ed822e">the embedded shell script</a>, which consisted
of these two lines:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/bin/kill <span class="nt">-HUP</span> <span class="si">$(</span>&lt;/run/mailman/master.pid<span class="si">)</span> 2&gt;/dev/null <span class="o">||</span> <span class="nb">true</span>
@BINDIR@/mailman reopen <span class="o">&gt;</span>/dev/null 2&gt;&amp;1 <span class="o">||</span> <span class="nb">true</span>
</code></pre></div></div>

<p>For one, <code class="language-plaintext highlighter-rouge">SIGHUP</code> was sent to a PID obtained from <code class="language-plaintext highlighter-rouge">/run/mailman/master.pid</code>,
which is under the control of the <code class="language-plaintext highlighter-rouge">mailman</code> service user. This would allow a
compromised <code class="language-plaintext highlighter-rouge">mailman</code> user to direct <code class="language-plaintext highlighter-rouge">SIGHUP</code> to arbitrary processes in the
system.</p>

<p>Furthermore the command line <code class="language-plaintext highlighter-rouge">/usr/bin/mailman reopen</code> was executed with full
root privileges, which results in output like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Usage: mailman [OPTIONS] COMMAND [ARGS]...
Try 'mailman -h' for help.

Error: If you are sure you want to run as root, specify --run-as-root.
</code></pre></div></div>

<p>This shows that the intended reopen of logfiles doesn’t work as expected.
Otherwise one might think that nothing harmful happens. This is not true,
however. This invocation of <code class="language-plaintext highlighter-rouge">mailman</code> still leads to the full initialization
of the logging system and all the logfiles in <br /><code class="language-plaintext highlighter-rouge">/var/log/mailman</code> are
created, if not already existing, with full root privileges. Symbolic links
are followed, if necessary.</p>

<p>This means a compromised <code class="language-plaintext highlighter-rouge">mailman</code> user can e.g. create a symlink
<code class="language-plaintext highlighter-rouge">/var/log/mailman/bounce.log</code> → <code class="language-plaintext highlighter-rouge">/etc/evil-file</code>. After the logrotate script
runs <code class="language-plaintext highlighter-rouge">/etc/evil-file</code> will be created. The files will be created with
root-ownership, so the only impact of this should be the creation of new empty
files owned by <code class="language-plaintext highlighter-rouge">root</code> in the system. This can still have security impact when
such empty state files control sensitive settings of other programs in the
system.</p>

<p>To fix this issue the sending of <code class="language-plaintext highlighter-rouge">SIGHUP</code> was completely dropped and the
reopen command is invoked via <code class="language-plaintext highlighter-rouge">sudo</code> as the dedicated <code class="language-plaintext highlighter-rouge">mailman</code> service user
and group. The logrotate drop-in configuration file containing the
problematic script is specific to openSUSE, thus we assigned a CVE for this
issue to make our users aware.</p>

<h3 id="sssd">sssd</h3>

<p>The sssd package has <a href="https://bugzilla.suse.com/show_bug.cgi?id=1246537">a very similar issue</a> in its
<a href="https://github.com/SSSD/sssd/blob/2d6ef923e1309ca3bef2b6093b91f736c81d608b/src/examples/logrotate.in">example logrotate configuration</a>, where a <code class="language-plaintext highlighter-rouge">SIGHUP</code>
signal is sent to a PID controlled by the <code class="language-plaintext highlighter-rouge">sssd</code> service user:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/bin/kill <span class="nt">-HUP</span> <span class="sb">`</span><span class="nb">cat</span> @pidpath@/sssd.pid 2&gt;/dev/null<span class="sb">`</span> 2&gt; /dev/null <span class="o">||</span> <span class="nb">true</span>
</code></pre></div></div>

<p>We created a public <a href="https://github.com/SSSD/sssd/issues/8041">upstream GitHub issue</a> to make the
developers aware of the problem. There is no fix available yet for the issue.</p>

<p><a name="section-icinga-cve"></a></p>

<h3 id="icinga2-cve-2025-61909">Icinga2 (CVE-2025-61909)</h3>

<p>In our icinga2 package there is yet another instance of sending a signal
(<code class="language-plaintext highlighter-rouge">SIGUSR1</code>) to a PID controlled by the unprivileged <code class="language-plaintext highlighter-rouge">icinga</code> service user:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/bin/kill <span class="nt">-USR1</span> <span class="si">$(</span><span class="nb">cat</span> /run/icinga2/icinga2.pid 2&gt; /dev/null<span class="si">)</span> 2&gt;/dev/null <span class="o">||</span> <span class="nb">true</span>
</code></pre></div></div>

<p>We wanted to change that into a <code class="language-plaintext highlighter-rouge">systemctl reload icinga2.service</code> instead,
only to find out that upstream’s reload script is <a href="https://github.com/Icinga/icinga2/issues/10527">affected by the same
issue</a>. We reported the problem to upstream and they
<a href="https://icinga.com/blog/releasing-icinga-2-v2-15-1-2-14-7-and-2-13-13-and-icinga-db-web-v1-2-3-and-1-1-4">fixed it and assigned a CVE</a> by now.</p>

<h3 id="exim-cve-2025-53881">exim (CVE-2025-53881)</h3>

<p>Our exim package contained a problematic <code class="language-plaintext highlighter-rouge">prerotate</code> shell script in its
<a href="https://build.opensuse.org/projects/openSUSE:Factory/packages/exim/files/exim.logrotate?expand=1">logrotate configuration</a> which allows <a href="https://bugzilla.suse.com/show_bug.cgi?id=1246457">escalation from
the <code class="language-plaintext highlighter-rouge">mail</code> user/group to <code class="language-plaintext highlighter-rouge">root</code></a>, when it runs. The
shell script is rather complex and tries to generate a statistics report
creating temporary files as <code class="language-plaintext highlighter-rouge">root</code> in the log directory owned by the
unprivileged <code class="language-plaintext highlighter-rouge">mail</code> user.</p>

<p>To fix this, the script has been adjusted to use a private temporary directory
for the report, instead. An update containing the fix will soon be available
for openSUSE Tumbleweed.</p>

<p>This again is an openSUSE specific logrotate configuration file, thus we
assigned a CVE to mark the problem.</p>

<h2 id="possible-improvements-in-logrotate">Possible Improvements in logrotate</h2>

<p>The issues we uncovered show also room for improvement in logrotate itself to
prevent such situations in the first place. For one, the daemon could refuse
to work on directories owned by non-root users, like it does for
world-writable directories. Furthermore scripts could be executed using the
same <code class="language-plaintext highlighter-rouge">su &lt;user&gt; &lt;group&gt;</code> credentials that are used for rotating the logs.</p>

<p>We did not reach out to upstream about these suggestions yet, but will keep
you informed about any developments in this area.</p>

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

<h1 id="4-gnome-49-d-bus-and-polkit-changes-in-new-major-version-release">4) GNOME 49: D-Bus and Polkit Changes in new Major Version Release</h1>

<p>GNOME 49 was recently released and our GNOME maintainers asked us to look into
a number of D-Bus and Polkit changes that appeared in related packages. We
encountered nothing too exciting this time:</p>

<ul>
  <li><a href="https://bugzilla.suse.com/show_bug.cgi?id=1248881">GDM</a>: Two changes appeared in GNOME’s display manager:
    <ul>
      <li>Some polkit actions are now tied to the <code class="language-plaintext highlighter-rouge">gdm</code> group instead of to the <code class="language-plaintext highlighter-rouge">gdm</code>
user. This is related to the display manager now using dynamic user
accounts.</li>
      <li>The <code class="language-plaintext highlighter-rouge">gdm</code> group is now allowed to access smart cards managed by
<code class="language-plaintext highlighter-rouge">pcscd</code>. This is supposed to fix <a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1061444#15">a bug report</a> where
smart cards could not be accessed by GDM. Why this bug never occurred
before is not completely clear, the Polkit settings are acceptable in any
case.</li>
    </ul>
  </li>
  <li><a href="https://bugzilla.suse.com/show_bug.cgi?id=1249067">gnome-initial-setup</a>: This package received the same
change as GDM, Polkit actions are now tied to the <code class="language-plaintext highlighter-rouge">gdm</code> group, not the
user.</li>
  <li><a href="https://bugzilla.suse.com/show_bug.cgi?id=1248979">gnome-remote-desktop</a>: This is the same as in
gnome-initial-setup, Polkit actions are now tied to the <code class="language-plaintext highlighter-rouge">gdm</code> group instead
of the user.</li>
  <li><a href="https://bugzilla.suse.com/show_bug.cgi?id=1248851">mutter</a>: This part of GNOME (a Wayland compositor
and X11 window manager) now contains a <code class="language-plaintext highlighter-rouge">backlight-helper</code>. Locally logged in
regular users are allowed to execute this program with <code class="language-plaintext highlighter-rouge">root</code> privileges to
control the backlight of mobile devices. We have seen this helper program
before in the <code class="language-plaintext highlighter-rouge">gnome-settings-daemon</code> package. It is a minimal C program
consisting of 200 lines of code and we could not find any issues in it.</li>
</ul>

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

<h1 id="5-kea-dhcp-follow-up-review-of-network-attack-surface">5) Kea DHCP: Follow-Up Review of Network Attack Surface</h1>

<p>Earlier this year we <a href="/2025/05/28/kea-dhcp-security-issues.html">reported a number of local security issues</a>
pertaining to the REST API in Kea DHCP. In a follow-up review we focused on
the network attack surface, which usually is the more interesting part when
dealing with a DHCP server suite. Alas, while looking at the network logic we
stumbled over <a href="https://gitlab.isc.org/isc-projects/kea/-/issues/4037">another minor local security issue</a> regarding
a temporary change to the process’s umask. Upstream addressed the problem in
the meantime.</p>

<p>Following the actual network processing logic in Kea’s code base is no easy
task. The C++ coding style uses a high level of abstraction which leads to many
indirections. Untrusted data received from network peers travels far in the
code without clear logical boundaries where data is verified before further
processing takes place. The code base contains a lot of comments, which
usually is a good thing, but in this instance it felt nearly too verbose
to us, making it hard to find the relevant bits.</p>

<p>On the positive side of things Kea is already a matured project and there were
no easy pickings to be found. Upstream also integrated AFL fuzzing into their
testing infrastructure, which should allow them to find network security
issues proactively. Consequently we have been unable to find any security
issues in the network processing in Kea.</p>

<p>Kea offers advanced features like configuring custom behaviour depending on
specific DHCP header fields. This naturally comes with quite some additional
complexity. In this light we believe Kea is well suited for large
organizations, but we would recommend a simpler DHCP server implementation for
small environments where such features are not needed, to reduce attack
surface.</p>

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

<h1 id="6-chrony-issues-in-chronyc-socket-creation">6) chrony: Issues in chronyc Socket Creation</h1>

<p><a href="https://bugzilla.suse.com/show_bug.cgi?id=1246544">This finding</a> resulted from our <a href="#section-logrotate">logrotate configuration
file</a> investigation discussed above. chrony is the
default NTP time synchronization program used in openSUSE and a number of
other Linux distributions. It ships a logrotate drop-in configuration
file that contains this <code class="language-plaintext highlighter-rouge">postrotate</code> shell code:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>postrotate
    /usr/bin/chronyc cyclelogs <span class="o">&gt;</span> /dev/null 2&gt;&amp;1 <span class="o">||</span> <span class="nb">true
</span>endscript
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">chronyc</code> is the client utility used to talk to the <code class="language-plaintext highlighter-rouge">chronyd</code> daemon
component. The communication mechanism used for this is a UNIX domain socket
placed in <code class="language-plaintext highlighter-rouge">/run/chrony/chronyd.sock</code>. <code class="language-plaintext highlighter-rouge">chronyc</code> is invoked as <code class="language-plaintext highlighter-rouge">root</code> in the
logrotate context above. At first we believed this should not be a problem,
since any privileged process should be allowed to talk to <code class="language-plaintext highlighter-rouge">chronyd</code>. While
looking at the <code class="language-plaintext highlighter-rouge">strace</code> output of the command line above the following system
call caught our attention, however:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">chmod</span><span class="o">(</span><span class="s2">"/run/chrony/chronyc.6588.sock"</span>, 0666<span class="o">)</span> <span class="o">=</span> 0
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">/run/chrony</code> directory is owned by the <code class="language-plaintext highlighter-rouge">chrony</code> service user:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>drwxr-x--- 3 chrony chrony 100 Sep 25 09:45 .
</code></pre></div></div>

<p>These are the same credentials used by the <code class="language-plaintext highlighter-rouge">chronyd</code> daemon. When <code class="language-plaintext highlighter-rouge">root</code>
performs the <code class="language-plaintext highlighter-rouge">chmod</code> call above, then a compromised <code class="language-plaintext highlighter-rouge">chrony</code> service user has
an opportunity to perform a symlink attack, directing the <code class="language-plaintext highlighter-rouge">chmod()</code> operation
to arbitrary files on the system, making them world-writable, thus making
possible a <code class="language-plaintext highlighter-rouge">chrony</code> to <code class="language-plaintext highlighter-rouge">root</code> privilege escalation. A couple of years ago we
found <a href="https://www.openwall.com/lists/oss-security/2020/08/21/1">a somewhat similar symlink attack</a> in the area
of the pidfile creation performed by the daemon.</p>

<p>We approached upstream about the issue on July 15 by creating <a href="https://gitlab.com/chrony/chrony/-/issues/28">a private
issue</a> in their GitLab project. The <a href="https://gitlab.com/chrony/chrony/-/commit/90d808ed28977ff79aaf3913ba477466c19d4695">bugfix</a>
turned out rather complex. The problem here is that the UNIX domain socket
used by chrony is datagram-oriented (<code class="language-plaintext highlighter-rouge">SOCK_DGRAM</code>). This means there is no
connection established between client and server. For the server being able to
send back data to the client, the client needs to bind its socket into the
file system as well and grant the server-side access to it. On Linux an
autobind feature exists for Unix domain sockets, which will automatically
assign an abstract address to the client socket, which is not visible in the
file system. This feature is not available on other UNIX systems, however,
that chrony also intends to support.</p>

<p>For these reasons the upstream approach to fix this involves the creation of
an unpredictably named sub-directory in <code class="language-plaintext highlighter-rouge">/run/chrony</code> to place the client-end
socket into. The directory is only writable for the client and the
unpredictable directory name is not known in advance, thus no symlinks can be
placed into the path anymore.</p>

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

<h1 id="7-pwaccessd-new-varlink-service-for-reading-user-account-information">7) pwaccessd: New Varlink Service for Reading User Account Information</h1>

<p>A fellow SUSE engineer recently finished development on
<a href="https://github.com/thkukuk/pwaccess"><code class="language-plaintext highlighter-rouge">pwaccessd</code></a>, a daemon providing user account information
via Varlink. This novel approach to providing account information allows, for
example, to grant regular users access to their own shadow entry, which would
otherwise only be accessible to <code class="language-plaintext highlighter-rouge">root</code>.</p>

<p>At the end of June we have been asked to <a href="https://bugzilla.suse.com/show_bug.cgi?id=1245261">review the new
daemon</a> for its security. We had a couple of hardening
recommendations and found an instance of possible log spoofing, but have
otherwise been satisfied with the implementation. Bugfixes and improvements
have been incorporated and the new service is now ready to be used in
production.</p>

<h1 id="8-sysextmgr-new-varlink-service-for-managing-systemd-sysext-images">8) sysextmgr: New Varlink Service for Managing systemd-sysext Images</h1>

<p>sysextmgr is <a href="https://github.com/thkukuk/sysextmgr">another new Varlink service</a> developed by
SUSE, which this time helps with the management of systemd-sysext images on
<a href="https://microos.opensuse.org">openSUSE MicroOS</a>. We noticed the addition of this service to
openSUSE via our monitoring of newly added systemd services in the
distribution. While looking into the Varlink API we <a href="https://bugzilla.suse.com/show_bug.cgi?id=1247107">discovered a number of
issues</a> in the service like Denial-of-Service attack
surface and some minor symlink issues. The issues could be resolved quickly
and we are now happy with the state of the service.</p>

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

<h1 id="9-bash-git-prompt-predictable-temporary-file-name-offers-local-attack-surface-cve-2025-61659">9) bash-git-prompt: Predictable Temporary File Name Offers Local Attack Surface (CVE-2025-61659)</h1>

<p>Our team is currently undertaking an effort to have a look at all kinds of
shell related drop-in code like command-specific shell completion support and
files installed into <code class="language-plaintext highlighter-rouge">/etc/profile.d</code> to manipulate the shell environment.
Any packages can install such files and they can easily lead to security
problems when things are not done right.</p>

<p>The amount of such files in a complete Linux distribution is huge, naturally,
thus this is a long-term task that will require time to produce a complete
list of findings. A <a href="https://bugzilla.suse.com/show_bug.cgi?id=1247489">first finding</a> in the
<a href="https://github.com/magicmonty/bash-git-prompt"><code class="language-plaintext highlighter-rouge">bash-git-prompt</code></a> package already resulted from this, however.
This package installs shell code into <code class="language-plaintext highlighter-rouge">/etc/profile.d/bash-git-prompt.sh</code>
which enables an interactive Git prompt which will be displayed as soon as the
Bash shell enters a Git repository.  This prompt contains information about
the current repository, the number of modified files and other things that can
be configured by users. The prompt feature using default settings becomes
active as soon as the package is installed.</p>

<p>While looking into the shell code that implements all this we noticed <a href="https://github.com/magicmonty/bash-git-prompt/blob/2.7.1/gitprompt.sh#L469">the use
of a predictable temporary file</a> in
<code class="language-plaintext highlighter-rouge">/tmp/git-index-private$$</code>. <code class="language-plaintext highlighter-rouge">bash-git-prompt</code> copies the Git index file found
in the current Git repository to this location. It turns out that this copy
operation happens every time the interactive shell user enters a new command
while being located in a Git repository. The temporary file is soon deleted
again when the Git bash prompt has been fully rendered by the program.</p>

<p>Since an interactive bash shell session is a long-lived process it is rather
simple for other users in the system to pre-create the temporary file in
question and cause all kinds of issues:</p>

<ul>
  <li>Denial-of-Service: by blocking the path, the Git prompt setup will fail to
complete and the prompt will be broken. By placing a FIFO named pipe in this
location the victim’s shell will even lock up completely.</li>
  <li>information leak: the copy of the Git index is made using the umask of
the shell. When the default umask <code class="language-plaintext highlighter-rouge">022</code> is used, then the copy of the Git
index becomes world-readable in <code class="language-plaintext highlighter-rouge">/tmp</code>. If the victim’s Git repository
contains non-public data then part of that data (e.g. file names of pending
change sets) leaks to other users in the system.</li>
  <li>integrity violation: when a local attacker places crafted data in the
location of the temporary file and denies write access, then
<code class="language-plaintext highlighter-rouge">bash-git-prompt</code> fails to write the desired Git index data to this
location, but will not stop execution despite this error. The crafted Git
index data will be fed to various invocations of the <code class="language-plaintext highlighter-rouge">git</code> command line
utility, possibly leading to a crafted bash prompt or even leading to some
forms of code execution. To determine the full extent of this, a low level
analysis of the handling of the binary Git index format would be necessary.</li>
</ul>

<p>The problem was discovered independently a while ago already, which is why
there exists <a href="https://github.com/magicmonty/bash-git-prompt/issues/561">a public GitHub issue</a> for it. An upstream
author attempted to fix the issue, but rolled back the changes due to a
regression and nothing happened since. The issue was introduced via <a href="https://github.com/magicmonty/bash-git-prompt/commit/38f7dbc0bb891719c2773714c170fe8fea035d95">commit
38f7dbc0bb8</a> in <code class="language-plaintext highlighter-rouge">bash-git-prompt</code> version 2.6.1. We
added <a href="https://build.opensuse.org/projects/devel:tools:scm/packages/bash-git-prompt/files/use-safe-tempfile.diff?expand=1">a simple patch</a> to our packaging of <code class="language-plaintext highlighter-rouge">bash-git-prompt</code>
which should address all issues for users of openSUSE.</p>

<p>At the end of September we requested a CVE from Mitre to track this issue and
they assigned CVE-2025-61659.</p>

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

<h1 id="10-steam-powerbuttond-insecure-operation-in-home-directories">10) steam-powerbuttond: Insecure Operation in Home Directories</h1>

<p>Our team’s monitoring of newly added systemd services in openSUSE led us to
<a href="https://github.com/ShadowBlip/steam-powerbuttond">steam-powerbuttond</a>. It derives from a script found on
the SteamOS Linux distribution for use on Steam Deck gaming devices.</p>

<p>The main component of this package is a Python script which runs as a systemd
service with full root privileges. This script contains <a href="https://bugzilla.suse.com/show_bug.cgi?id=1249602">various security
issues</a>. During startup the script attempts to
determine who “the first user” in the system is, by parsing the output of <code class="language-plaintext highlighter-rouge">who
| head -1</code>. This user’s home directory is then used for operations later on,
when a power button press event is detected. After processing the event, the
file <br /><code class="language-plaintext highlighter-rouge">/home/{user}/.steam/steam.pid</code> is read and used for accessing
<code class="language-plaintext highlighter-rouge">/proc/{pid}/cmdline</code>.</p>

<p>This logic leads to various possible issues, ranging from the the wrong user
being selected initially, to denial-of-service when unexpected file content is
placed in the unprivileged user’s home directory. We contacted one of the
original upstream authors about this and offered coordinated disclosure. It
turned out that the project is not supposed to be used anymore, however, and
as a result the GitHub repository has been archived by the maintainer.</p>

<p>The openSUSE <code class="language-plaintext highlighter-rouge">steam-powerbuttond</code> package is now waiting to be replaced by a
new script that is supposed to be found in SteamOS.</p>

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

<p>This edition of the SUSE security team spotlight was quite packed with topics.
We hope this can give you an insight into all the different kind of activities
we end up in on our mission to improve the security of open source software, in
the Linux ecosystem in general and openSUSE in particular. We’re looking
forward to the next issue of the spotlight series in about three months from
now.</p>

<h1 id="change-history">Change History</h1>

<table>
  <tbody>
    <tr>
      <td>2025-10-23</td>
      <td>Updated the logrotate <a href="#section-icinga-cve">Icinga2</a> sub-section to include the upstream CVE and a link to the upstream security advisory.</td>
    </tr>
  </tbody>
</table>]]></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 summer 2025 edition and first anniversary of our spotlight series. The last two months have been surprisingly busy for us in the area of code reviews and we have quite a number of interesting stories to share with you. Among others we will cover a local root exploit we found in systemd v258 release candidates, issues in logrotate drop-in configuration files, newly developed Varlink services and a symlink attack issue in chrony.]]></summary></entry></feed>