2020-10-30 23:10:57

by Miao-chen Chou

[permalink] [raw]
Subject: [BlueZ PATCH v1] adapter: Fix a crash caused by lingering discovery client pointer

This cleans up the lingering pointer, adapter->client, during powering
off the adapter. The crash occurs when a D-Bus client set Powered
property to false and immediately calls StopDiscovery() when there is
ongoing discovery. As a part of powering off the adapter,
adapter->discovery_list gets cleared, and given that adapter->client
refers to one of the clients in adapter->discovery_list, adapter->client
should be cleared along with it.

Reviewed-by: Alain Michaud <[email protected]>
Reviewed-by: Sonny Sasaka <[email protected]>
---

src/adapter.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/src/adapter.c b/src/adapter.c
index c0053000a..74bfb0448 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1507,8 +1507,10 @@ static void discovery_free(void *user_data)
client->discovery_filter = NULL;
}

- if (client->msg)
+ if (client->msg) {
dbus_message_unref(client->msg);
+ client->msg = NULL;
+ }

g_free(client->owner);
g_free(client);
@@ -5301,6 +5303,19 @@ static void free_service_auth(gpointer data, gpointer user_data)

static void remove_discovery_list(struct btd_adapter *adapter)
{
+ DBusMessage *msg;
+
+ if (adapter->client) {
+ msg = adapter->client->msg;
+ if (msg) {
+ g_dbus_send_message(dbus_conn, btd_error_busy(msg));
+ dbus_message_unref(msg);
+ adapter->client->msg = NULL;
+ }
+
+ adapter->client = NULL;
+ }
+
g_slist_free_full(adapter->set_filter_list, discovery_free);
adapter->set_filter_list = NULL;

--
2.26.2


2020-10-30 23:49:09

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [BlueZ PATCH v1] adapter: Fix a crash caused by lingering discovery client pointer

Hi Miao-chen,

On Fri, Oct 30, 2020 at 4:13 PM Miao-chen Chou <[email protected]> wrote:
>
> This cleans up the lingering pointer, adapter->client, during powering
> off the adapter. The crash occurs when a D-Bus client set Powered
> property to false and immediately calls StopDiscovery() when there is
> ongoing discovery. As a part of powering off the adapter,
> adapter->discovery_list gets cleared, and given that adapter->client
> refers to one of the clients in adapter->discovery_list, adapter->client
> should be cleared along with it.
>
> Reviewed-by: Alain Michaud <[email protected]>
> Reviewed-by: Sonny Sasaka <[email protected]>
> ---
>
> src/adapter.c | 17 ++++++++++++++++-
> 1 file changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/src/adapter.c b/src/adapter.c
> index c0053000a..74bfb0448 100644
> --- a/src/adapter.c
> +++ b/src/adapter.c
> @@ -1507,8 +1507,10 @@ static void discovery_free(void *user_data)
> client->discovery_filter = NULL;
> }
>
> - if (client->msg)
> + if (client->msg) {
> dbus_message_unref(client->msg);
> + client->msg = NULL;
> + }

This shouldn't make any difference as the whole list is freed and so
is the client.

>
> g_free(client->owner);
> g_free(client);
> @@ -5301,6 +5303,19 @@ static void free_service_auth(gpointer data, gpointer user_data)
>
> static void remove_discovery_list(struct btd_adapter *adapter)
> {
> + DBusMessage *msg;
> +
> + if (adapter->client) {
> + msg = adapter->client->msg;
> + if (msg) {
> + g_dbus_send_message(dbus_conn, btd_error_busy(msg));
> + dbus_message_unref(msg);
> + adapter->client->msg = NULL;
> + }
> +
> + adapter->client = NULL;

Shouldn't you call discovery_free as well here? Or perhaps we could
move the lines above inside discovery_free so it detects if the
adapter->client is pointing to a client that is being freed.

> + }
> +
> g_slist_free_full(adapter->set_filter_list, discovery_free);
> adapter->set_filter_list = NULL;
>
> --
> 2.26.2
>


--
Luiz Augusto von Dentz

2020-11-02 21:08:31

by Miao-chen Chou

[permalink] [raw]
Subject: Re: [BlueZ PATCH v1] adapter: Fix a crash caused by lingering discovery client pointer

Hi Luiz,

On Fri, Oct 30, 2020 at 4:48 PM Luiz Augusto von Dentz
<[email protected]> wrote:
>
> Hi Miao-chen,
>
> On Fri, Oct 30, 2020 at 4:13 PM Miao-chen Chou <[email protected]> wrote:
> >
> > This cleans up the lingering pointer, adapter->client, during powering
> > off the adapter. The crash occurs when a D-Bus client set Powered
> > property to false and immediately calls StopDiscovery() when there is
> > ongoing discovery. As a part of powering off the adapter,
> > adapter->discovery_list gets cleared, and given that adapter->client
> > refers to one of the clients in adapter->discovery_list, adapter->client
> > should be cleared along with it.
> >
> > Reviewed-by: Alain Michaud <[email protected]>
> > Reviewed-by: Sonny Sasaka <[email protected]>
> > ---
> >
> > src/adapter.c | 17 ++++++++++++++++-
> > 1 file changed, 16 insertions(+), 1 deletion(-)
> >
> > diff --git a/src/adapter.c b/src/adapter.c
> > index c0053000a..74bfb0448 100644
> > --- a/src/adapter.c
> > +++ b/src/adapter.c
> > @@ -1507,8 +1507,10 @@ static void discovery_free(void *user_data)
> > client->discovery_filter = NULL;
> > }
> >
> > - if (client->msg)
> > + if (client->msg) {
> > dbus_message_unref(client->msg);
> > + client->msg = NULL;
> > + }
>
> This shouldn't make any difference as the whole list is freed and so
> is the client.
Please see my below reply.
>
> >
> > g_free(client->owner);
> > g_free(client);
> > @@ -5301,6 +5303,19 @@ static void free_service_auth(gpointer data, gpointer user_data)
> >
> > static void remove_discovery_list(struct btd_adapter *adapter)
> > {
> > + DBusMessage *msg;
> > +
> > + if (adapter->client) {
> > + msg = adapter->client->msg;
> > + if (msg) {
> > + g_dbus_send_message(dbus_conn, btd_error_busy(msg));
> > + dbus_message_unref(msg);
> > + adapter->client->msg = NULL;
> > + }
> > +
> > + adapter->client = NULL;
>
> Shouldn't you call discovery_free as well here? Or perhaps we could
> move the lines above inside discovery_free so it detects if the
> adapter->client is pointing to a client that is being freed.
>
discovery_free are done in the following lines, so there is no need to
call discovery_free() for a referencing pointer, adapter->client. It's
a good point to move it so discovery_free() instead.
> > + }
> > +
> > g_slist_free_full(adapter->set_filter_list, discovery_free);
> > adapter->set_filter_list = NULL;
> >
> > --
> > 2.26.2
> >
>
>
> --
> Luiz Augusto von Dentz

Regards,
Miao