Re: [Bluez PATCH v3] audio/a2dp - fix crash during recovering process

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

 



Hi Luiz,

Thanks for the comment.
I did the qualification test with and without the patch on both Chrome
OS and Linux with bluez-5.52.
The results are all the same.
The tests I’ve run are as follows.

A2DP/SRC/AS/BV-01-I
A2DP/SRC/CC/BV-09-I
A2DP/SRC/CC/BV-10-I
A2DP/SRC/REL/BV-01-I
A2DP/SRC/REL/BV-02-I
A2DP/SRC/SET/BV-01-I
A2DP/SRC/SET/BV-02-I
A2DP/SRC/SET/BV-03-I
A2DP/SRC/SET/BV-04-I
A2DP/SRC/SET/BV-05-I
A2DP/SRC/SET/BV-06-I
IOPT/CL/A2DP-SRC/SFC/BV-01-I
AVDTP/SRC/ACP/SIG/SMG/BV-06-C
AVDTP/SRC/ACP/SIG/SMG/BV-08-C
AVDTP/SRC/ACP/SIG/SMG/BV-10-C
AVDTP/SRC/ACP/SIG/SMG/BV-16-C
AVDTP/SRC/ACP/SIG/SMG/BV-18-C
AVDTP/SRC/ACP/SIG/SMG/BV-20-C
AVDTP/SRC/ACP/SIG/SMG/BV-24-C
AVDTP/SRC/ACP/SIG/SMG/BI-05-C
AVDTP/SRC/ACP/SIG/SMG/BI-08-C
AVDTP/SRC/ACP/SIG/SMG/BI-17-C
AVDTP/SRC/ACP/SIG/SMG/BI-20-C
AVDTP/SRC/ACP/SIG/SMG/BI-23-C
AVDTP/SRC/ACP/SIG/SMG/BI-28-C*
AVDTP/SRC/ACP/TRA/BTR/BI-01-C
AVDTP/SRC/INT/SIG/SMG/BV-05-C
AVDTP/SRC/INT/SIG/SMG/BV-07-C
AVDTP/SRC/INT/SIG/SMG/BV-09-C
AVDTP/SRC/INT/SIG/SMG/BV-15-C
AVDTP/SRC/INT/SIG/SMG/BV-17-C
AVDTP/SRC/INT/SIG/SMG/BV-19-C
AVDTP/SRC/INT/SIG/SMG/BV-23-C
AVDTP/SRC/INT/SIG/SMG/BV-31-C
AVDTP/SRC/INT/SIG/SMG/BI-30-C
AVDTP/SRC/INT/TRA/BTR/BV-01-C

Except for AVDTP/SRC/ACP/SIG/SMG/BI-28-C, the other tests had been passed.
Please let me know if I need more verification.

Thanks,
Howard

On Fri, Jan 10, 2020 at 4:09 PM Yun-hao Chung <howardchung@xxxxxxxxxx> wrote:
>
> ---------- Forwarded message ---------
> From: howardchung@xxxxxxxxxx <howardchung@xxxxxxxxxx>
> Date: Fri, Jan 10, 2020 at 3:57 PM
> Subject: [Bluez PATCH v3] audio/a2dp - fix crash during recovering process
> To: <linux-bluetooth@xxxxxxxxxxxxxxx>, <luiz.von.dentz@xxxxxxxxx>
> Cc: <chromeos-bluetooth-upstreaming@xxxxxxxxxxxx>, howardchung
> <howardchung@xxxxxxxxxx>
>
>
> 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 received the response.
> 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.
>
> ---
> 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.
>
> Changes in v3:
> - Update the title
> - Remove the signed-off-by section
>
> Changes in v2:
> - Fixed typo in commit message
>
>  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 51ead684a..620a76c90 100644
> --- a/profiles/audio/avdtp.c
> +++ b/profiles/audio/avdtp.c
> @@ -3484,6 +3484,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 */
> @@ -3498,6 +3499,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 7cac21034..726e2f562 100644
> --- a/profiles/audio/sink.c
> +++ b/profiles/audio/sink.c
> @@ -309,8 +309,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.25.0.rc1.283.g88dfdc4193-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