Skip to content

Commit

Permalink
pipewire: context: pw_context_find_format(): fix stack use-after-free
Browse files Browse the repository at this point in the history
Since fc49c16 ("context: improve negotiation") it is possible
that the out parameter `format` will be set to `filter`. However,
`filter` is a SPA POD from the local SPA POD builder `fb`, which
references the local buffer `fbuf`.

In those cases, if the callers then make use of the returned SPA POD,
a stack use-after-free happens, such as the one displayed below.

The issue could be reliably triggered by executing the `video-play`
example program, and then trying to use the same camera in firefox.
As seen below, the input node, firefox's, provides no format preference,
causing the output format to be used. Previously, this had led
to the use-after-free described above.

pw.link    | [impl-link.c: 130 link_update_state()] (46.0.1 -> 114.0.0) init -> negotiating (paused-configure)
pw.context | [  context.c: 935 pw_context_find_format()] 0x51e000000080: finding best format 3 1
pw.context | [  context.c: 943 pw_context_find_format()] 0x51e000000080: states 3 1
pw.context | [  context.c: 958 pw_context_find_format()] 0x51e000000080: Got output format:
pw.context | [  context.c: 959 pw_context_find_format()]  video/raw
pw.context | [  context.c: 959 pw_context_find_format()]            format : (Id) YUY2
pw.context | [  context.c: 959 pw_context_find_format()]              size : (Rectangle) 640x480
pw.context | [  context.c: 959 pw_context_find_format()]         framerate : (Fraction) 30/1
pw.context | [  context.c: 966 pw_context_find_format()] 0x51e000000080: no input format filter, using output format: Success
=================================================================
==418404==ERROR: AddressSanitizer: stack-use-after-return on address 0x73993ee46200 at pc 0x739941d31020 bp 0x7fff526b4670 sp 0x7fff526b4660
READ of size 4 at 0x73993ee46200 thread T0
    #0 0x739941d3101f in spa_pod_builder_raw ../spa/include/spa/pod/builder.h:150
    #1 0x739941d3b35d in do_negotiate ../src/pipewire/impl-link.c:294
    #2 0x739941d46214 in check_states ../src/pipewire/impl-link.c:727
    #3 0x739941f14405 in process_work_queue ../src/pipewire/work-queue.c:64
    #4 0x73993d0dbe99 in source_event_func ../spa/plugins/support/loop.c:894
    #5 0x73993d0d6881 in loop_iterate ../spa/plugins/support/loop.c:727
    #6 0x739941d76b05 in spa_loop_control_enter ../spa/include/spa/support/loop.h:264
    PipeWire#7 0x739941d76d93 in spa_loop_control_leave ../spa/include/spa/support/loop.h:268
    #8 0x739941d78946 in pw_main_loop_quit ../src/pipewire/main-loop.c:109
    #9 0x5a64b3cb1cec in main ../src/daemon/pipewire.c:130
    PipeWire#10 0x739940c34e07  (/usr/lib/libc.so.6+0x25e07) (BuildId: 98b3d8e0b8c534c769cb871c438b4f8f3a8e4bf3)
    PipeWire#11 0x739940c34ecb in __libc_start_main (/usr/lib/libc.so.6+0x25ecb) (BuildId: 98b3d8e0b8c534c769cb871c438b4f8f3a8e4bf3)
    PipeWire#12 0x5a64b3caf3b4 in _start (/pipewire/build/src/daemon/pipewire+0x173b4) (BuildId: f9e8403a377e28bf8bd9cf0a5b89d33f08499917)

Address 0x73993ee46200 is located in stack of thread T0 at offset 512 in frame
    #0 0x739941c6ed5e in pw_context_find_format ../src/pipewire/context.c:907

  This frame has 15 object(s):
    [...]
    [432, 480) 'fb' (line 911)
    [512, 4608) 'fbuf' (line 912) <== Memory access at offset 512 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-return ../spa/include/spa/pod/builder.h:150 in spa_pod_builder_raw
    [...]

Fixes: fc49c16 ("context: improve negotiation")
  • Loading branch information
pobrn committed Dec 10, 2024
1 parent 94e823d commit 69dcc7d
Showing 1 changed file with 18 additions and 2 deletions.
20 changes: 18 additions & 2 deletions src/pipewire/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,15 @@ int pw_context_find_format(struct pw_context *context,
if (res == -ENOENT || res == 0) {
pw_log_debug("%p: no input format filter, using output format: %s",
context, spa_strerror(res));
*format = filter;

uint32_t offset = builder->state.offset;
res = spa_pod_builder_raw_padded(builder, filter, SPA_POD_SIZE(filter));
if (res < 0) {
*error = spa_aprintf("failed to add pod");
goto error;
}

*format = spa_pod_builder_deref(builder, offset);
} else {
*error = spa_aprintf("error input enum formats: %s", spa_strerror(res));
goto error;
Expand Down Expand Up @@ -1003,7 +1011,15 @@ int pw_context_find_format(struct pw_context *context,
if (res == -ENOENT || res == 0) {
pw_log_debug("%p: no output format filter, using input format: %s",
context, spa_strerror(res));
*format = filter;

uint32_t offset = builder->state.offset;
res = spa_pod_builder_raw_padded(builder, filter, SPA_POD_SIZE(filter));
if (res < 0) {
*error = spa_aprintf("failed to add pod");
goto error;
}

*format = spa_pod_builder_deref(builder, offset);
} else {
*error = spa_aprintf("error output enum formats: %s", spa_strerror(res));
goto error;
Expand Down

0 comments on commit 69dcc7d

Please sign in to comment.