Skip to content

linux-pipewire: Fix use-after-free in log message#13698

Open
pobrn wants to merge 1 commit into
obsproject:masterfrom
pobrn:pw_log_uaf
Open

linux-pipewire: Fix use-after-free in log message#13698
pobrn wants to merge 1 commit into
obsproject:masterfrom
pobrn:pw_log_uaf

Conversation

@pobrn

@pobrn pobrn commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Description

When a device disappears, it is removed from the hash table and a message is logged. However, this log message uses the device's id, which is freed when it is removed from the hash table.

So swap the order to fix that.

Motivation and Context

on_registry_global_remove_cb() runs into a use-after-free when it removes a device:

Details
==1810573==ERROR: AddressSanitizer: heap-use-after-free on address 0x7c3a80ad11a0 at pc 0x7fca9a6d0192 bp 0x7bca2aab6e50 sp 0x7bca2aab65c8
READ of size 45 at 0x7c3a80ad11a0 thread T34
    #0 0x7fca9a6d0191  (/usr/lib/libasan.so.8+0xd0191) (BuildId: b28f87d70f4aadfdfe6abce3776c226f5569bd6a)
    #1 0x7fca9a6f17ce in vsnprintf (/usr/lib/libasan.so.8+0xf17ce) (BuildId: b28f87d70f4aadfdfe6abce3776c226f5569bd6a)
    #2 0x55ad9acc5162 in do_log /obs-studio/frontend/obs-main.cpp:205
    #3 0x7fca96e1ad69 in blogva /obs-studio/libobs/util/base.c:116
    #4 0x7fca96e1ae94 in blog /obs-studio/libobs/util/base.c:124
    #5 0x7bca46f3dc40 in on_registry_global_remove_cb /obs-studio/plugins/linux-pipewire/camera-portal.c:1033
    #6 0x7bca3659339e in registry_demarshal_global_remove ../pipewire/src/modules/module-protocol-native/protocol-native.c:1838
    #7 0x7bca36580fe5 in process_remote ../pipewire/src/modules/module-protocol-native.c:1127
    #8 0x7bca365816b7 in on_remote_data ../pipewire/src/modules/module-protocol-native.c:1161
    #9 0x7bca47b9db06 in loop_iterate ../pipewire/spa/plugins/support/loop.c:847
    #10 0x7bca46dbe110 in spa_loop_control_iterate_fast ../pipewire/spa/include/spa/support/loop.h:408
    #11 0x7bca46dbe110 in pw_loop_iterate ../pipewire/src/pipewire/loop.h:95
    #12 0x7bca46dbe110 in do_loop ../pipewire/src/pipewire/thread-loop.c:177
    #13 0x7fca9a661858  (/usr/lib/libasan.so.8+0x61858) (BuildId: b28f87d70f4aadfdfe6abce3776c226f5569bd6a)
    #14 0x7fca93c97738  (/usr/lib/libc.so.6+0x97738) (BuildId: d8ceb52a8c6e1fefece4ca75f7396d1d5bffc565)
    #15 0x7fca93d1bedb  (/usr/lib/libc.so.6+0x11bedb) (BuildId: d8ceb52a8c6e1fefece4ca75f7396d1d5bffc565)

0x7c3a80ad11a0 is located 32 bytes inside of 77-byte region [0x7c3a80ad1180,0x7c3a80ad11cd)
freed by thread T34 here:
    #0 0x7fca9a72ae91  (/usr/lib/libasan.so.8+0x12ae91) (BuildId: b28f87d70f4aadfdfe6abce3776c226f5569bd6a)
    #1 0x7fca96e1bb55 in a_free /obs-studio/libobs/util/bmem.c:93
    #2 0x7fca96e1bca0 in bfree /obs-studio/libobs/util/bmem.c:143
    #3 0x7fca930df2ee  (/usr/lib/libglib-2.0.so.0+0x422ee) (BuildId: 6d161c3dc593ef99967915cfe1c4b48d96841477)
    #4 0x7fca930e78eb  (/usr/lib/libglib-2.0.so.0+0x4a8eb) (BuildId: 6d161c3dc593ef99967915cfe1c4b48d96841477)
    #5 0x7bca46f3dbf9 in on_registry_global_remove_cb /obs-studio/plugins/linux-pipewire/camera-portal.c:1032
    #6 0x7bca3659339e in registry_demarshal_global_remove ../pipewire/src/modules/module-protocol-native/protocol-native.c:1838
    #7 0x7bca36580fe5 in process_remote ../pipewire/src/modules/module-protocol-native.c:1127
    #8 0x7bca365816b7 in on_remote_data ../pipewire/src/modules/module-protocol-native.c:1161
    #9 0x7bca47b9db06 in loop_iterate ../pipewire/spa/plugins/support/loop.c:847
    #10 0x7bca46dbe110 in spa_loop_control_iterate_fast ../pipewire/spa/include/spa/support/loop.h:408
    #11 0x7bca46dbe110 in pw_loop_iterate ../pipewire/src/pipewire/loop.h:95
    #12 0x7bca46dbe110 in do_loop ../pipewire/src/pipewire/thread-loop.c:177
    #13 0x7fca9a661858  (/usr/lib/libasan.so.8+0x61858) (BuildId: b28f87d70f4aadfdfe6abce3776c226f5569bd6a)
    #14 0x7fca93c97738  (/usr/lib/libc.so.6+0x97738) (BuildId: d8ceb52a8c6e1fefece4ca75f7396d1d5bffc565)

previously allocated by thread T34 here:
    #0 0x7fca9a72c0c1 in malloc (/usr/lib/libasan.so.8+0x12c0c1) (BuildId: b28f87d70f4aadfdfe6abce3776c226f5569bd6a)
    #1 0x7fca96e1b81c in a_malloc /obs-studio/libobs/util/bmem.c:55
    #2 0x7fca96e1bb99 in bmalloc /obs-studio/libobs/util/bmem.c:108
    #3 0x7fca96e1bcd7 in bmemdup /obs-studio/libobs/util/bmem.c:159
    #4 0x7bca46f1d21c in bstrdup_n /obs-studio/libobs/util/bmem.h:58
    #5 0x7bca46f1d309 in bstrdup /obs-studio/libobs/util/bmem.h:81
    #6 0x7bca46f3d61c in on_registry_global_cb /obs-studio/plugins/linux-pipewire/camera-portal.c:1010
    #7 0x7bca365931cc in registry_demarshal_global ../pipewire/src/modules/module-protocol-native/protocol-native.c:1823
    #8 0x7bca36580fe5 in process_remote ../pipewire/src/modules/module-protocol-native.c:1127
    #9 0x7bca365816b7 in on_remote_data ../pipewire/src/modules/module-protocol-native.c:1161
    #10 0x7bca47b9db06 in loop_iterate ../pipewire/spa/plugins/support/loop.c:847
    #11 0x7bca46dbe110 in spa_loop_control_iterate_fast ../pipewire/spa/include/spa/support/loop.h:408
    #12 0x7bca46dbe110 in pw_loop_iterate ../pipewire/src/pipewire/loop.h:95
    #13 0x7bca46dbe110 in do_loop ../pipewire/src/pipewire/thread-loop.c:177
    #14 0x7fca9a661858  (/usr/lib/libasan.so.8+0x61858) (BuildId: b28f87d70f4aadfdfe6abce3776c226f5569bd6a)
    #15 0x7fca93c97738  (/usr/lib/libc.so.6+0x97738) (BuildId: d8ceb52a8c6e1fefece4ca75f7396d1d5bffc565)

Thread T34 created by T0 here:
    #0 0x7fca9a7226f4 in pthread_create (/usr/lib/libasan.so.8+0x1226f4) (BuildId: b28f87d70f4aadfdfe6abce3776c226f5569bd6a)
    #1 0x7bca46dc2f90 in impl_create ../pipewire/src/pipewire/thread.c:106
    #2 0x7bca46dbda37 in spa_thread_utils_create ../pipewire/spa/include/spa/support/thread.h:72
    #3 0x7bca46dbda37 in pw_thread_utils_create ../pipewire/src/pipewire/thread.h:39
    #4 0x7bca46dbda37 in pw_thread_loop_start ../pipewire/src/pipewire/thread-loop.c:208
    #5 0x7bca46f6551d in obs_pipewire_connect_fd /obs-studio/plugins/linux-pipewire/pipewire.c:1126
    #6 0x7bca46f3e46c in on_pipewire_remote_opened_cb /obs-studio/plugins/linux-pipewire/camera-portal.c:1075
    #7 0x7fca868c3b9b  (/usr/lib/libgio-2.0.so.0+0xb1b9b) (BuildId: cb4fa6906c94b535cadf10f9f05664b98c7c4684)
    #8 0x7fca868c99b9  (/usr/lib/libgio-2.0.so.0+0xb79b9) (BuildId: cb4fa6906c94b535cadf10f9f05664b98c7c4684)
    #9 0x7fca86942880  (/usr/lib/libgio-2.0.so.0+0x130880) (BuildId: cb4fa6906c94b535cadf10f9f05664b98c7c4684)
    #10 0x7fca868c3b9b  (/usr/lib/libgio-2.0.so.0+0xb1b9b) (BuildId: cb4fa6906c94b535cadf10f9f05664b98c7c4684)
    #11 0x7fca868c99b9  (/usr/lib/libgio-2.0.so.0+0xb79b9) (BuildId: cb4fa6906c94b535cadf10f9f05664b98c7c4684)
    #12 0x7fca869389b2  (/usr/lib/libgio-2.0.so.0+0x1269b2) (BuildId: cb4fa6906c94b535cadf10f9f05664b98c7c4684)
    #13 0x7fca868c3b9b  (/usr/lib/libgio-2.0.so.0+0xb1b9b) (BuildId: cb4fa6906c94b535cadf10f9f05664b98c7c4684)
    #14 0x7fca868c3be4  (/usr/lib/libgio-2.0.so.0+0xb1be4) (BuildId: cb4fa6906c94b535cadf10f9f05664b98c7c4684)
    #15 0x7fca930febfc  (/usr/lib/libglib-2.0.so.0+0x61bfc) (BuildId: 6d161c3dc593ef99967915cfe1c4b48d96841477)
    #16 0x7fca93100e56  (/usr/lib/libglib-2.0.so.0+0x63e56) (BuildId: 6d161c3dc593ef99967915cfe1c4b48d96841477)
    #17 0x7fca93100fe4 in g_main_context_iteration (/usr/lib/libglib-2.0.so.0+0x63fe4) (BuildId: 6d161c3dc593ef99967915cfe1c4b48d96841477)
    #18 0x7fca9509d0b1 in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) (/usr/lib/libQt6Core.so.6+0x49d0b1) (BuildId: 50723f7e355b98a46271409a4b19b6f476f04eca)
    #19 0x7fca94d91982 in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) (/usr/lib/libQt6Core.so.6+0x191982) (BuildId: 50723f7e355b98a46271409a4b19b6f476f04eca)
    #20 0x7fca94d86ea9 in QCoreApplication::exec() (/usr/lib/libQt6Core.so.6+0x186ea9) (BuildId: 50723f7e355b98a46271409a4b19b6f476f04eca)
    #21 0x55ad9acca381 in run_program /obs-studio/frontend/obs-main.cpp:692
    #22 0x55ad9acccf1b in main /obs-studio/frontend/obs-main.cpp:1092
    #23 0x7fca93c27740  (/usr/lib/libc.so.6+0x27740) (BuildId: d8ceb52a8c6e1fefece4ca75f7396d1d5bffc565)
    #24 0x7fca93c27878 in __libc_start_main (/usr/lib/libc.so.6+0x27878) (BuildId: d8ceb52a8c6e1fefece4ca75f7396d1d5bffc565)
    #25 0x55ad99612764 in _start (/obs-studio/build/rundir/Debug/bin/obs+0x39cf764) (BuildId: 4ffb2a3ba7852eaf04f3872c37943f357af4e184)

SUMMARY: AddressSanitizer: heap-use-after-free /obs-studio/frontend/obs-main.cpp:205 in do_log
Shadow bytes around the buggy address:
  0x7c3a80ad0f00: fd fd fd fd fd fd fa fa fa fa fd fd fd fd fd fd
  0x7c3a80ad0f80: fd fd fd fd fa fa fa fa 00 00 00 00 00 00 00 00
  0x7c3a80ad1000: 02 fa fa fa fa fa 00 00 00 00 00 00 00 00 00 01
  0x7c3a80ad1080: fa fa fa fa 00 00 00 00 00 00 00 00 00 03 fa fa
  0x7c3a80ad1100: fa fa 00 00 00 00 00 00 00 00 00 02 fa fa fa fa
=>0x7c3a80ad1180: fd fd fd fd[fd]fd fd fd fd fd fa fa fa fa 00 00
  0x7c3a80ad1200: 00 00 00 00 00 00 00 fa fa fa fa fa 00 00 00 00
  0x7c3a80ad1280: 00 00 00 00 00 fa fa fa fa fa 00 00 00 00 00 00
  0x7c3a80ad1300: 00 00 00 fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x7c3a80ad1380: 00 fa fa fa fa fa 00 00 00 00 00 00 00 00 00 fa
  0x7c3a80ad1400: fa fa fa fa 00 00 00 00 00 00 00 00 00 fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==1810573==ABORTING

How Has This Been Tested?

Removable USB webcamera.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)

Checklist:

  • I have read the contributing document.
  • My code has been run through clang-format.
  • My code follows the project's style guidelines
  • My code is not on the master branch.
  • My code has been tested.
  • All commit messages are properly formatted and commits squashed where appropriate.
  • I have included updates to all appropriate documentation.

When a device disappears, it is removed from the hash table and
a message is logged. However, this log message uses the device's
id, which is freed when it is removed from the hash table.

So swap the order to fix that.

@tytan652 tytan652 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GHashTable is constructed with set destructors, so LGTM.

@tytan652 tytan652 added kind/bug Categorizes issue or PR as related to a bug. platform/linux Categorizes issue or PR as affecting Linux specifically labels Jul 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/bug Categorizes issue or PR as related to a bug. platform/linux Categorizes issue or PR as affecting Linux specifically

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants