pulse-server: use-after-free when server is unloaded
It is possible for a PulseAudio client to cause the unloading of the server it is connected to:
pactl load-module module-native-protocol-tcp port=9999
pactl -s localhost:9999 unload-module module-native-protocol-tcp
which results in the following use-after-free:
==145078==ERROR: AddressSanitizer: heap-use-after-free on address 0x613000008390 at pc 0x7f2c60adc1b7 bp 0x7ffdc2fd3880 sp 0x7ffdc2fd3870
READ of size 8 at 0x613000008390 thread T0
#0 0x7f2c60adc1b6 in reply_new ../src/modules/module-protocol-pulse/pulse-server.c:293
#1 0x7f2c60adc207 in reply_simple_ack ../src/modules/module-protocol-pulse/pulse-server.c:306
#2 0x7f2c60adffbb in do_unload_module ../src/modules/module-protocol-pulse/pulse-server.c:5094
#3 0x7f2c60b195cb in handle_packet ../src/modules/module-protocol-pulse/pulse-server.c:5429
#4 0x7f2c60b1a66e in do_read ../src/modules/module-protocol-pulse/pulse-server.c:5584
#5 0x7f2c60b1b2ec in on_client_data ../src/modules/module-protocol-pulse/pulse-server.c:5610
#6 0x7f2c6213e456 in source_io_func ../spa/plugins/support/loop.c:321
#7 0x7f2c62144707 in loop_iterate ../spa/plugins/support/loop.c:309
#8 0x7f2c67163c59 in pw_main_loop_run ../src/pipewire/main-loop.c:154
#9 0x55fec27deadd in main ../src/daemon/pipewire.c:118
#10 0x7f2c66187b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)
#11 0x55fec27de23d in _start (/home/pb/temp/src/pipewire/build/src/daemon/pipewire+0x323d)
0x613000008390 is located 16 bytes inside of 352-byte region [0x613000008380,0x6130000084e0)
freed by thread T0 here:
#0 0x7f2c67806f19 in __interceptor_free /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:127
#1 0x7f2c60a8d438 in client_free ../src/modules/module-protocol-pulse/pulse-server.c:5388
#2 0x7f2c60b1d067 in server_free ../src/modules/module-protocol-pulse/pulse-server.c:5848
#3 0x7f2c60b3f468 in module_native_protocol_tcp_unload ../src/modules/module-protocol-pulse/modules/module-native-protocol-tcp.c:73
#4 0x7f2c60ad9572 in module_unload ../src/modules/module-protocol-pulse/module.c:103
#5 0x7f2c60adffad in do_unload_module ../src/modules/module-protocol-pulse/pulse-server.c:5092
#6 0x7f2c60b195cb in handle_packet ../src/modules/module-protocol-pulse/pulse-server.c:5429
#7 0x7f2c60b1a66e in do_read ../src/modules/module-protocol-pulse/pulse-server.c:5584
#8 0x7f2c60b1b2ec in on_client_data ../src/modules/module-protocol-pulse/pulse-server.c:5610
#9 0x7f2c6213e456 in source_io_func ../spa/plugins/support/loop.c:321
#10 0x7f2c62144707 in loop_iterate ../spa/plugins/support/loop.c:309
#11 0x7f2c67163c59 in pw_main_loop_run ../src/pipewire/main-loop.c:154
#12 0x55fec27deadd in main ../src/daemon/pipewire.c:118
#13 0x7f2c66187b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)
previously allocated by thread T0 here:
#0 0x7f2c67807459 in __interceptor_calloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:154
#1 0x7f2c60a8e300 in on_connect ../src/modules/module-protocol-pulse/pulse-server.c:5723
#2 0x7f2c6213e456 in source_io_func ../spa/plugins/support/loop.c:321
#3 0x7f2c62144707 in loop_iterate ../spa/plugins/support/loop.c:309
#4 0x7f2c67163c59 in pw_main_loop_run ../src/pipewire/main-loop.c:154
#5 0x55fec27deadd in main ../src/daemon/pipewire.c:118
#6 0x7f2c66187b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)
SUMMARY: AddressSanitizer: heap-use-after-free ../src/modules/module-protocol-pulse/pulse-server.c:293 in reply_new
Shadow bytes around the buggy address:
0x0c267fff9020: fd fd fd fd fd fd fd fd fd fd fd fd fd fa fa fa
0x0c267fff9030: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
0x0c267fff9040: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c267fff9050: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c267fff9060: fd fd fd fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c267fff9070: fd fd[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c267fff9080: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c267fff9090: fd fd fd fd fd fd fd fd fd fd fd fd fa fa fa fa
0x0c267fff90a0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
0x0c267fff90b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c267fff90c0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
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
Shadow gap: cc
==145078==ABORTING
since pulse-server.c:on_client_data()
does not acquire an extra reference to the client, it assumes that the server's reference will keep the client alive, but that is not case since the server can go away while the client is being served.