Received: by 2002:a05:6a10:22f:0:0:0:0 with SMTP id 15csp1375749pxk; Fri, 18 Sep 2020 10:43:43 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwEObJArpbP0CwOXLIsbMiNEgcieU7T3ZBwYfaRyDR5bglIxj6KEGi7fgyMIc0Lp5yJmlEU X-Received: by 2002:a17:906:934e:: with SMTP id p14mr36463749ejw.348.1600451022959; Fri, 18 Sep 2020 10:43:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1600451022; cv=none; d=google.com; s=arc-20160816; b=RbNiaThuuIWdnULcqdzCTcFafvpgaN0GfjeCfbN0K4B8loxzn4BPg6XTFNyHFr7i2S b38J0NIfJzKqjJaghcLfshLD3eRfamRyksmixVL/OoGURVWgwObXJ8+k/9ctfH1pjLhD L0Av4EZvDXTlufPhkU6xrklEsaP/BnezuCDMxZ1b43u+lpQgEE50/kjJuTa+7zbEnWtQ soUm52Amh4QRx3Z5bZKdgXpSM7oMarzXIjMo8NEV5lmyoUTphahwJOqqIfsdcfRCZhHQ eD7BbaT+8nOs68yH347OrPwN//3JAtlvCOLoZwNGgwgwaFB8mrZybtUL4EIKs0wZrH+B 8XIQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:subject:message-id:date:from:in-reply-to :references:mime-version:dkim-signature; bh=h2SK2ruiDT8U5SSsr85d6fpub5Fo0LTc0NW0N6lMueg=; b=ao8QR9IaeshWKGbiq+xKqcZ7JGxsHR54W8nyaTY/LE3gVhk+nWCxDHKd9Q5UDpFZ1O do3foi1R2NktpFbGAMaB/BGCu4LPSYCJWVa40Llv31aEmbWWGVIWZNbBhgg0/byoq8vG lugVunT0g5j+X3DWqFf4vMP+fBhHMim2bNdl1QJZsVstWpIi//4Uby052ETmvgf4E0zP e4LW+av3JjpNHXF+QfgDXfDXaWYLR4BE5wGMMbQlb7F4PPOg99v2cy78Y0FGfAJPlw1S IdTBU/xoFl/PtfmBxg6A2W2Dtz1IMOovr5S3gzTIsTjj3Dee7/qXMkVP2Vgy9lYHXEW8 OCtw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=rq6DW8Bx; spf=pass (google.com: domain of linux-bluetooth-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-bluetooth-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id c11si2677619ejb.541.2020.09.18.10.43.15; Fri, 18 Sep 2020 10:43:42 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-bluetooth-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=rq6DW8Bx; spf=pass (google.com: domain of linux-bluetooth-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-bluetooth-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726115AbgIRRnE (ORCPT + 99 others); Fri, 18 Sep 2020 13:43:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57576 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725955AbgIRRnE (ORCPT ); Fri, 18 Sep 2020 13:43:04 -0400 Received: from mail-oi1-x241.google.com (mail-oi1-x241.google.com [IPv6:2607:f8b0:4864:20::241]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 69BB1C0613CE for ; Fri, 18 Sep 2020 10:43:04 -0700 (PDT) Received: by mail-oi1-x241.google.com with SMTP id v20so7969003oiv.3 for ; Fri, 18 Sep 2020 10:43:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=h2SK2ruiDT8U5SSsr85d6fpub5Fo0LTc0NW0N6lMueg=; b=rq6DW8Bxv7+GmV8gqQryMJo7KGa9XUqMZFXmRBlIwtm0WNjH6FVf6W9+qxYP1772TT CNBHyQWWgKlEdmBE/oFnmaeXP2kus2KeazGP0kERuzsNDQ127PoTly2hTjBLzzYvV2Rz j6Dsswg2WFg5SESOGgAi9db8DVRfPvRy/ktrAiM5i2WD4iODZitiRkyv2ZMx0H0Vtdjn cpQptoteMdLQktFISwfkTeeyVFuL505Qp2lW8T3CR41R9OWgSJd5ntAzZ3hM3rtCl9FI 8nB/685FQSRxgt0DDfNNwe8nszK4sUmBUDF8RFhpE0g3uUNdKtO16RNS9wAkzTnKTxcJ dVMA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=h2SK2ruiDT8U5SSsr85d6fpub5Fo0LTc0NW0N6lMueg=; b=F5hs3X2VVPrRlWScWKUZ0uPEMmUrcNOijSEPWrN7NlkBGxFfzMMslmY4KZi7M6yvri X2pPHrAD3D+hjYbTq7MDoRUlQi8VDyzpF41Dh0yHn2C2jTdlK/FoDFdVHTXQzl8Iu2wJ 8fJBXtDIe98m2krsXi1S4gZUKTT63W2iSuShP7cjxWOaVQQiBrGt/tOujkGzrQKwAgN4 hKh0WG0CeV1mYyGjkxpQvhmu8rsqPnbh2wnuk/ebI0YwkI3ICDszicTo6RyIhXQyoXOf DHF9ryMJD9oGzdOM9uxtVItI46aGWqsp9qn2rF506RfCHjJMG0ntPouZUJ6i9t0B02ul M4mA== X-Gm-Message-State: AOAM5320ice1zq8CCX+mkjD2SqJ+FzY4r3rUGmLL5dxnK/6M2roqb7PH Kuu1Lt3iM7xHc0KLrWiz7I1iyDH5VGe+zH/jNwTJk5/s X-Received: by 2002:aca:3e08:: with SMTP id l8mr9522001oia.152.1600450983490; Fri, 18 Sep 2020 10:43:03 -0700 (PDT) MIME-Version: 1.0 References: <20200917221034.154218-1-sonnysasaka@chromium.org> In-Reply-To: <20200917221034.154218-1-sonnysasaka@chromium.org> From: Luiz Augusto von Dentz Date: Fri, 18 Sep 2020 10:42:52 -0700 Message-ID: Subject: Re: [PATCH BlueZ v2] a2dp: Keep track of ref ownership of a2dp_setup To: Sonny Sasaka Cc: "linux-bluetooth@vger.kernel.org" , Alain Michaud Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org Hi Sonny, On Thu, Sep 17, 2020 at 3:13 PM Sonny Sasaka wrote: > > Currently transport_cb and abort_cfm make assumption that they have an > a2dp_setup reference held as a result of open_ind invocation. In the > field this is not always true, for example when the peer device opens an > L2CAP channel for AVDTP transport channel without sending AVDTP_OPEN > request through the AVDTP signaling channel first. Although in this case > the peer device does not behave correctly, we should protect this > possible crash from happening by making sure that transport_cb and > abort_cfm are really holding a reference of a2dp_setup object before > trying to unref them. > > After grabbing a reference, open_ind stores the pointer in > stream->user_data. If this field is set, that means there is a pending > AVDTP_OPEN command and it needs to be unref-fed later once and only > once: when the transport channel is created (transport_cb) or when the > AVDTP_OPEN command is aborted (abort_cfm). If this field is not set, > nothing should unref it. This enforces that the reference counting is > correct regardless of the behavior of the peer device. > > A sample crash stack trace from Chrome OS: > * thread #1, stop reason = signal SIGSEGV > * frame #0: 0x0c64f0e8 bluetoothd`queue_remove_all at queue.c:351 > frame #1: 0x0c64f086 bluetoothd`queue_destroy at queue.c:73 > frame #2: 0x0c6022b0 bluetoothd`setup_unref at a2dp.c:222 > frame #3: 0x0c604942 bluetoothd`transport_cb at a2dp.c:2229 > frame #4: 0x0c61e35c bluetoothd`accept_cb at btio.c:203 > frame #5: 0xf679523c libglib-2.0.so.0`g_main_context_dispatch at gmain.c:3182 > frame #6: 0xf67954aa libglib-2.0.so.0`g_main_context_iterate at gmain.c:3920 > frame #7: 0xf679569a libglib-2.0.so.0`g_main_loop_run at gmain.c:4116 > frame #8: 0x0c65a5a0 bluetoothd`mainloop_run at mainloop-glib.c:79 > frame #9: 0x0c65a7ea bluetoothd`mainloop_run_with_signal at mainloop-notify.c:201 > frame #10: 0x0c6477ec bluetoothd`main at main.c:772 > frame #11: 0xf65bc0a2 libc.so.6`__libc_start_main at libc-start.c:308 > > Reviewed-by: Alain Michaud > > --- > profiles/audio/a2dp.c | 34 ++++++++++++++++++++++++++-------- > profiles/audio/avdtp.c | 17 +++++++++++++++++ > profiles/audio/avdtp.h | 5 +++++ > 3 files changed, 48 insertions(+), 8 deletions(-) > > diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c > index 2feea66c0..26147f96e 100644 > --- a/profiles/audio/a2dp.c > +++ b/profiles/audio/a2dp.c > @@ -915,6 +915,11 @@ static void update_last_used(struct a2dp_channel *chan, struct a2dp_sep *lsep, > avdtp_get_seid(rsep)); > } > > +static void destroy_setup(void *data) > +{ > + setup_unref(data); > +} > + > static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep, > struct avdtp_stream *stream, uint8_t *err, > void *user_data) > @@ -927,10 +932,21 @@ static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep, > else > DBG("Source %p: Open_Ind", sep); > > + if (avdtp_stream_get_user_data(stream)) { > + warn("setup already exists"); > + return FALSE; > + } I've sent a patch fixing the code when Open is sent multiple times, we were actually overwriting pending_open and its timer, I think it might be the source of these crashes, not an unbalanced reference of the setup. Also it is possible that the headsets doing this sort of operation would like us to start the L2CAP connection procedure so we could perhaps attempt to connect it after a sorter timer, but it might be hard to check how well it would work without having such a headset to test if it really does help. > setup = a2dp_setup_get(session); > if (!setup) > return FALSE; > > + /* > + * Use avdtp_stream's user_data to keep the reference ownership of the > + * setup object. This ensures that this reference will be unref-ed > + * exactly once. > + */ > + avdtp_stream_set_user_data(stream, setup, destroy_setup); > setup->stream = stream; > > if (!err && setup->chan) > @@ -1285,14 +1301,13 @@ static void abort_cfm(struct avdtp *session, struct avdtp_local_sep *sep, > void *user_data) > { > struct a2dp_sep *a2dp_sep = user_data; > - struct a2dp_setup *setup; > + struct a2dp_setup *setup = avdtp_stream_get_user_data(stream); > > if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) > DBG("Sink %p: Abort_Cfm", sep); > else > DBG("Source %p: Abort_Cfm", sep); > > - setup = find_setup_by_session(session); > if (!setup) > return; > > @@ -1302,6 +1317,7 @@ static void abort_cfm(struct avdtp *session, struct avdtp_local_sep *sep, > } > > setup_unref(setup); > + avdtp_stream_set_user_data(stream, NULL, NULL); > } > > static gboolean reconf_ind(struct avdtp *session, struct avdtp_local_sep *sep, > @@ -2216,11 +2232,12 @@ fail: > > static void transport_cb(GIOChannel *io, GError *err, gpointer user_data) > { > - struct a2dp_setup *setup = user_data; > + struct avdtp_stream *stream = user_data; > + struct a2dp_setup *setup = avdtp_stream_get_user_data(stream); > uint16_t omtu, imtu; > > - if (!g_slist_find(setups, setup)) { > - warn("bt_io_accept: setup %p no longer valid", setup); > + if (!setup) { > + warn("transport_cb: setup does not exist"); > g_io_channel_shutdown(io, TRUE, NULL); > return; > } > @@ -2238,8 +2255,7 @@ static void transport_cb(GIOChannel *io, GError *err, gpointer user_data) > goto drop; > } > > - if (!avdtp_stream_set_transport(setup->stream, > - g_io_channel_unix_get_fd(io), > + if (!avdtp_stream_set_transport(stream, g_io_channel_unix_get_fd(io), > imtu, omtu)) > goto drop; > > @@ -2249,6 +2265,7 @@ static void transport_cb(GIOChannel *io, GError *err, gpointer user_data) > setup->io = NULL; > > setup_unref(setup); > + avdtp_stream_set_user_data(stream, NULL, NULL); > > return; > > @@ -2297,7 +2314,8 @@ static void confirm_cb(GIOChannel *io, gpointer data) > goto drop; > } > > - if (!bt_io_accept(io, transport_cb, setup, NULL, &err)) { > + if (!bt_io_accept(io, transport_cb, setup->stream, NULL, > + &err)) { > error("bt_io_accept: %s", err->message); > g_error_free(err); > goto drop; > diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c > index 782268c08..76d06f47c 100644 > --- a/profiles/audio/avdtp.c > +++ b/profiles/audio/avdtp.c > @@ -366,6 +366,8 @@ struct avdtp_stream { > GSList *caps; > GSList *callbacks; > struct avdtp_service_capability *codec; > + void *user_data; > + avdtp_stream_user_data_destroy_t user_data_destroy; > guint io_id; /* Transport GSource ID */ > guint timer; /* Waiting for other side to close or open > * the transport channel */ > @@ -727,6 +729,9 @@ static void stream_free(void *data) > g_slist_free_full(stream->callbacks, g_free); > g_slist_free_full(stream->caps, g_free); > > + if (stream->user_data && stream->user_data_destroy) > + stream->user_data_destroy(stream->user_data); > + > g_free(stream); > } > > @@ -3147,6 +3152,18 @@ struct avdtp_remote_sep *avdtp_stream_get_remote_sep( > return NULL; > } > > +void avdtp_stream_set_user_data(struct avdtp_stream *stream, void *data, > + avdtp_stream_user_data_destroy_t destroy) > +{ > + stream->user_data = data; > + stream->user_data_destroy = destroy; > +} > + > +void *avdtp_stream_get_user_data(struct avdtp_stream *stream) > +{ > + return stream->user_data; > +} > + > gboolean avdtp_stream_set_transport(struct avdtp_stream *stream, int fd, > size_t imtu, size_t omtu) > { > diff --git a/profiles/audio/avdtp.h b/profiles/audio/avdtp.h > index 011fea89e..247e9df75 100644 > --- a/profiles/audio/avdtp.h > +++ b/profiles/audio/avdtp.h > @@ -133,6 +133,8 @@ typedef void (*avdtp_set_configuration_cb) (struct avdtp *session, > struct avdtp_stream *stream, > struct avdtp_error *err); > > +typedef void (*avdtp_stream_user_data_destroy_t)(void *data); > + > /* Callbacks for when a reply is received to a command that we sent */ > struct avdtp_sep_cfm { > void (*set_configuration) (struct avdtp *session, > @@ -260,6 +262,9 @@ gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream, > GSList *caps); > struct avdtp_remote_sep *avdtp_stream_get_remote_sep( > struct avdtp_stream *stream); > +void avdtp_stream_set_user_data(struct avdtp_stream *stream, void *data, > + avdtp_stream_user_data_destroy_t destroy); > +void *avdtp_stream_get_user_data(struct avdtp_stream *stream); > > unsigned int avdtp_add_state_cb(struct btd_device *dev, > avdtp_session_state_cb cb, void *user_data); > -- > 2.26.2 > -- Luiz Augusto von Dentz