Re: [Bluez PATCH v1] CHROMIUM: audio: fix crash during recovering process

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



+ ChromeOS-BT-Platform-SW-Core

On Tue, Dec 24, 2019 at 2:48 PM howardchung@xxxxxxxxxx
<howardchung@xxxxxxxxxx> wrote:
>
> From: howardchung <howardchung@xxxxxxxxxx>
>
> The crash with stack trace:
>
> (libc-2.27.so -raise.c:51 )                     raise
> (libc-2.27.so -abort.c:79 )                     abort
> (libc-2.27.so -libc_fatal.c:181 )               __libc_message
> (libc-2.27.so -malloc.c:5350 )                  malloc_printerr
> (libc-2.27.so -malloc.c:4157 )                  _int_free
> (libglib-2.0.so.0.5200.3 -gslist.c:878 )        g_slist_free_full
> (bluetoothd -a2dp.c:165 )                       setup_unref
> (bluetoothd -a2dp.c:2184 )                      a2dp_cancel
> (bluetoothd -sink.c:317 )                       sink_unregister
> (bluetoothd -service.c:176 )                    service_remove
> (bluetoothd -device.c:4678 )                    device_remove
> (bluetoothd -adapter.c:6573 )                   adapter_remove
> (bluetoothd -adapter.c:8832 )                   index_removed
> (bluetoothd -queue.c:220 )                      queue_foreach
> (bluetoothd -mgmt.c:304 )                       can_read_data
> (bluetoothd -io-glib.c:170 )                    watch_callback
> (libglib-2.0.so.0.5200.3 -gmain.c:3234 )        g_main_context_dispatch
> (libglib-2.0.so.0.5200.3 -gmain.c:3972 )        g_main_context_iterate
> (libglib-2.0.so.0.5200.3 -gmain.c:4168 )        g_main_loop_run
> (bluetoothd -main.c:798 )                       main
> (libc-2.27.so -libc-start.c:308 )               __libc_start_main
> (bluetoothd + 0x0000b089 )                      _start
> (bluetoothd + 0x0000b05f )                      _init
>
> triggered when 'usb disconnect' happened during AVDTP_SET_CONFIGURATION
> request is sent but haven't recevied the responce.
> In this situation, the recovering process goes into sink.c:sink_free and
> then a2dp.c:a2dp_cancel, avdtp.c:cancel_request, avdtp.c:connection_lost,
> avdtp.c:release_stream.
>
> During recovering, the reference count of setup and avdtp decrease more
> than it increase, which ends up causing the crash.
>
> The reference count of setup decreases one more time since
> a2dp.c:setconf_cfm(called by cfm->set_configuration in
> avdtp.c:cancel_request) was called in the 'error mode', which didn't
> reference the setup, but in a2dp.c:abort_cfm(called by cfm->abort in
> avdtp.c:release_stream), the reference count decreased by 1.
>
> In this case, abort_cfm shouldn't be called as we already know
> setconf_cfm didn't send any request. Setting avdtp_sep_state to
> AVDTP_STATE_ABORTING should avoid this issue.
>
> The reference count of avdtp decrease one more time since
> both sink.c:sink_free and sink.c:sink_set_state(called from
> avdtp.c:connection_lost -> avdtp.c:avdtp_set_state) unreference avdtp
> for the session. The changes in sink.c should avoid the issue.
>
> Signed-off-by: howardchung@xxxxxxxxxx <howardchung@xxxxxxxxxx>
> ---
> How to test:
>         The crash can be simulated by the following procedure.
>         1. injecting sleep(10) right before calling a2dp_config in
>            sink.c:select_complete.
>         2. connect with a bluetooth headset
>         3. run 'rmmod btusb' after ~5 seconds(before the connection
>            complete)
> The procedure can reproduce the crash with ~50% probability.
> Even if the bluetoothd didn't crash or it crashed with different
> signature, the reference count can end up with some invalid number.
>
> After the patch applies, there is no crash after running the test above 10
> times in a row.
>
>  profiles/audio/avdtp.c | 3 +++
>  profiles/audio/sink.c  | 4 +++-
>  2 files changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c
> index 91b1e4b96..f42f21bbb 100644
> --- a/profiles/audio/avdtp.c
> +++ b/profiles/audio/avdtp.c
> @@ -3550,6 +3550,7 @@ int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream)
>  {
>         struct seid_req req;
>         int ret;
> +       struct avdtp_local_sep *sep = stream->lsep;
>
>         if (!stream && session->discover) {
>                 /* Don't call cb since it being aborted */
> @@ -3564,6 +3565,8 @@ int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream)
>         if (stream->lsep->state == AVDTP_STATE_ABORTING)
>                 return -EINVAL;
>
> +       avdtp_sep_set_state(session, sep, AVDTP_STATE_ABORTING);
> +
>         if (session->req && stream == session->req->stream)
>                 return cancel_request(session, ECANCELED);
>
> diff --git a/profiles/audio/sink.c b/profiles/audio/sink.c
> index 966440534..7c5e77577 100644
> --- a/profiles/audio/sink.c
> +++ b/profiles/audio/sink.c
> @@ -308,8 +308,10 @@ static void sink_free(struct btd_service *service)
>                 avdtp_stream_remove_cb(sink->session, sink->stream,
>                                         sink->cb_id);
>
> -       if (sink->session)
> +       if (sink->session) {
>                 avdtp_unref(sink->session);
> +               sink->session = NULL;
> +       }
>
>         if (sink->connect_id > 0) {
>                 btd_service_connecting_complete(sink->service, -ECANCELED);
> --
> 2.24.1.735.g03f4e72817-goog
>



[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux