* [bluez/bluez] ada0e7: a2dp: Fix crash on NULL stream in transport_cb
@ 2026-09-21 22:42 IAROSLAV VOITOVYCH
0 siblings, 0 replies; only message in thread
From: IAROSLAV VOITOVYCH @ 2026-09-21 22:42 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1170691
Home: https://github.com/bluez/bluez
Commit: ada0e72a47c65b948f954bf77640d4c207cac33d
https://github.com/bluez/bluez/commit/ada0e72a47c65b948f954bf77640d4c207cac33d
Author: Iaroslav Voitovych <yaroslav.voytovych@gmail.com>
Date: 2026-09-21 (Mon, 21 Sep 2026)
Changed paths:
M profiles/audio/a2dp.c
Log Message:
-----------
a2dp: Fix crash on NULL stream in transport_cb
transport_cb() runs from bt_io_accept() and begins by confirming that
the a2dp_setup it was handed still exists:
if (!g_slist_find(setups, setup)) {
warn("bt_io_accept: setup %p no longer valid", setup);
...
}
That establishes the lifetime of the setup, not of the stream it
points at. Several paths in a2dp.c clear setup->stream while leaving
the setup itself on the list, so by the time the accept completes the
setup can be valid and its stream NULL. confirm_cb() already refuses
to start the accept when setup->stream is NULL; nothing re-checks it
when the accept completes, and it is then passed on unchecked:
if (!avdtp_stream_set_transport(setup->stream,
g_io_channel_unix_get_fd(io),
imtu, omtu))
and avdtp_stream_set_transport() dereferences it immediately:
gboolean avdtp_stream_set_transport(struct avdtp_stream *stream, ...)
{
GIOChannel *io = g_io_channel_unix_new(fd);
if (stream != stream->session->pending_open) {
Observed as a crash on a QCA9377 (13d3:3503) whose controller stops
answering HCI during audio use. From the retained core, %r13 held NULL
and the faulting instruction was the first field load off it:
bluetoothd[398112]: segfault at 10 ip 0000635d944b47e5 \
sp 00007ffefcba28d0 error 4 in bluetoothd[367e5,635d944a3000+f3000]
r13 0x0
=> 0x635d944b47e5: mov 0x10(%r13),%rdi
With the check in place and the daemon logging before it bails, the
guard fired four times in 19 days of ordinary use on the same machine
(once on 2026-08-26, three times on 2026-09-02, across two daemon
lifetimes and three distinct setup pointers). Each of those is an
accept that completed after the stream had been cleared; unpatched,
each is the dereference above.
Check the stream immediately before it is used, so every existing path
keeps its current behaviour up to the point that was previously
unsafe. In particular a bt_io_accept() error or a bt_io_get() failure
still reports the real I/O error rather than this secondary lifecycle
condition.
commit 125a2e237e7c ("a2dp: Fix possible crash when accepting stream
transport") previously hardened this same asynchronous accept window
against the whole setup disappearing while the accept was pending.
This covers the remaining case where the setup survives and its stream
does not.
commit 90a600895d80 ("avdtp: Handle case where remote send L2CAP
connect ahead of Open") also changed avdtp_stream_set_transport()
itself, to handle a transport arriving before Open. The function still
dereferences stream before reaching that handling, so it does not
cover a NULL argument from transport_cb().
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-09-21 22:43 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-21 22:42 [bluez/bluez] ada0e7: a2dp: Fix crash on NULL stream in transport_cb IAROSLAV VOITOVYCH
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox