Possible NULL reference in GIO function g_dbus_object_get_interface()
On Ubuntu 22.04 the udisksctl crashes using with the follow command line:
$ udisksctl power-off --no-user-interaction -b /dev/disk/by-id/dm-name-cryptoswap
(udisksctl power-off:189101): GLib-GIO-CRITICAL **: 01:42:17.165: g_dbus_interface_dup_object: assertion 'G_IS_DBUS_INTERFACE (interface_)' failed
Segmentation fault (core dumped)
dukpt@PROMETHEUS:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.2 LTS
Release: 22.04
Codename: jammy
$ uname -a
Linux PROMETHEUS 5.19.0-43-generic #44~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Mon May 22 13:39:36 UTC 2 x86_64 x86_64 x86_64 GNU/Linux
$ l /usr/lib/x86_64-linux-gnu/libgio-2.0.*
-rw-r--r-- 1 root root 1924496 Mär 22 03:52 /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.7200.4
lrwxrwxrwx 1 root root 22 Mär 22 03:52 /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0 -> libgio-2.0.so.0.7200.4
lrwxrwxrwx 1 root root 15 Mär 22 03:52 /usr/lib/x86_64-linux-gnu/libgio-2.0.so -> libgio-2.0.so.0
-rw-r--r-- 1 root root 4889020 Mär 22 03:52 /usr/lib/x86_64-linux-gnu/libgio-2.0.a
Analyzing the code, I think the problem is on line gdbusobject.c:153 because the value returned is never checked if not null before dereferencing to use as function pointer in iface->get_interface
Inside GDB it's possible to see one step before the crash:
[ Legend: Modified register | Code | Heap | Stack | String ]
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax : 0x00005555555947c0 → 0x0000000000000001
$rbx : 0x00007fffffffe1ae → "power-off"
$rcx : 0x1
$rdx : 0x0
$rsp : 0x00007fffffffdb10 → 0x00007fffffffe1ae → "power-off"
$rbp : 0x0
$rsi : 0x00007ffff7bc6179 → "org.freedesktop.UDisks2.Drive"
$rdi : 0x0
$rip : 0x00007ffff7ec2733 → <g_dbus_object_get_interface+19> mov rdi, QWORD PTR [rbp+0x0]
$r8 : 0x1
$r9 : 0x7fffffff
$r10 : 0x0
$r11 : 0x9d2b3760e54ea5dc
$r12 : 0x00007ffff7bc6179 → "org.freedesktop.UDisks2.Drive"
$r13 : 0x00005555555edc00 → 0x0000000000000000
$r14 : 0x0
$r15 : 0x000055555555ff44 → 0x6b006b636f6c6e75 ("unlock"?)
$eflags: [zero carry PARITY adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffdb10│+0x0000: 0x00007fffffffe1ae → "power-off" ← $rsp
0x00007fffffffdb18│+0x0008: 0x0000000000000000
0x00007fffffffdb20│+0x0010: 0x00007fffe80bf400 → 0x00007fffe8018090 → 0x0000000000000000
0x00007fffffffdb28│+0x0018: 0x00007ffff7bbf507 → <udisks_object_peek_drive+39> test rax, rax
0x00007fffffffdb30│+0x0020: 0x00007fffffffdba8 → 0x0000000000000000
0x00007fffffffdb38│+0x0028: 0x000055555555a0b5 → <main+3621> xor edx, edx
0x00007fffffffdb40│+0x0030: 0x0000555500000000
0x00007fffffffdb48│+0x0038: 0x0000555500000000
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
0x7ffff7ec272a <g_dbus_object_get_interface+10> mov rbp, rdi
0x7ffff7ec272d <g_dbus_object_get_interface+13> push rbx
0x7ffff7ec272e <g_dbus_object_get_interface+14> call 0x7ffff7ebcfd0 <g_dbus_object_get_type>
→ 0x7ffff7ec2733 <g_dbus_object_get_interface+19> mov rdi, QWORD PTR [rbp+0x0]
0x7ffff7ec2737 <g_dbus_object_get_interface+23> mov rsi, rax
0x7ffff7ec273a <g_dbus_object_get_interface+26> call 0x7ffff7dd8b50 <g_type_interface_peek@plt>
0x7ffff7ec273f <g_dbus_object_get_interface+31> mov rdi, r12
0x7ffff7ec2742 <g_dbus_object_get_interface+34> mov rbx, rax
0x7ffff7ec2745 <g_dbus_object_get_interface+37> call 0x7ffff7e957e0 <g_dbus_is_interface_name>
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "udisksctl", stopped 0x7ffff7ec2733 in g_dbus_object_get_interface (), reason: BREAKPOINT
[#1] Id 2, Name: "gmain", stopped 0x7ffff7a34d7f in __GI___poll (), reason: BREAKPOINT
[#2] Id 3, Name: "gdbus", stopped 0x7ffff7a34d7f in __GI___poll (), reason: BREAKPOINT
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x7ffff7ec2733 → g_dbus_object_get_interface(object=0x0, interface_name=0x7ffff7bc6179 "org.freedesktop.UDisks2.Drive")
[#1] 0x7ffff7bbf507 → udisks_object_peek_drive(object=0x0)
[#2] 0x55555555a0b5 → handle_command_power_off(completion_prev=<optimized out>, completion_cur=<optimized out>, request_completion=0x0, argv=0x7fffffffdb70, argc=0x7fffffffdb7c)
[#3] 0x55555555a0b5 → main(argc=<optimized out>, argv=<optimized out>)
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
At some point, g_dbus_object_get_type() returns NULL and on g_dbus_object_get_interface+19 will crash SIGSEGV due to NULL dereferencing.
I'm also opening a ticket to Ubuntu because on udisksctl.c:2208 the value of object is never checked before using it to call udisks_object_peek_drive(), which is the function that will call g_dbus_object_get_interface() with a NULL object
An attacker may find an exploitable scenario and abuse of this flaw to deny of service, achieve code execution, depending on the context also LPE.