linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] rfcomm/core.c avoid dangling pointer, check session exists
@ 2011-05-21 19:02 David Fries
  2011-05-30 20:48 ` Gustavo F. Padovan
  0 siblings, 1 reply; 3+ messages in thread
From: David Fries @ 2011-05-21 19:02 UTC (permalink / raw)
  To: linux-bluetooth, linux-kernel; +Cc: Gustavo F. Padovan, Marcel Holtmann

rfcomm_process_sessions is calling rfcomm_process_rx, but
in this case the session is closed and freed leaving a
dangling pointer that blows up when rfcomm_process_rx returns
and rfcomm_process_dlcs is called with the now dangling session
pointer.  Check to see if the entry is still in the list.

Signed-off-by: David Fries <David@Fries.net>
Cc: Marcel Holtmann <marcel@holtmann.org>
Cc: "Gustavo F. Padovan" <padovan@profusion.mobi>
---
I sent out an ealier patch,
Date: Mon, 21 Mar 2011 21:38:10 -0500
Subject: [PATCH] rfcomm/core.c avoid dangling pointer, check session

That version added a return value to rfcomm_session_close to determine
if the session was closed.  I thought this would be cleaner.

I can reproduce using blueman-manager on desktop, and Motorola S305 bluetooth
headset, 2.6.39, but it can take a few attempts.  Start out with the
desktop as the last device the S305 paired with.
desktop, connect to the S305,
S305, turn on
desktop (connection fails)
desktop (connection automatically comes up now that S305 is on)
desktop disconnect S305
desktop (kernel panic)

While rfcomm_process_sessions looks symmetrical,
rfcomm_session_hold(s);
rfcomm_process_rx
rfcomm_process_dlcs
rfcomm_session_put(s);

rfcomm_process_rx
if (sk->sk_state == BT_CLOSED) {
        if (!s->initiator)
                rfcomm_session_put(s);
        rfcomm_session_close(s, sk->sk_err);

Which isn't symmetrical.  I don't know enough about the subsystem to
know if there is a better cleaner way to fix this, or if my patch is
the best solution.

 net/bluetooth/rfcomm/core.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index c997393..ac47ef3 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1952,6 +1952,12 @@ static inline void rfcomm_process_sessions(void)
 
 		default:
 			rfcomm_process_rx(s);
+			/* The current session can be closed as part of rx
+			 * in which case s is now dangling.  Check if it
+			 * has been removed.
+			 */
+			if(n->prev != p)
+				continue;
 			break;
 		}
 
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] rfcomm/core.c avoid dangling pointer, check session exists
  2011-05-21 19:02 [PATCH] rfcomm/core.c avoid dangling pointer, check session exists David Fries
@ 2011-05-30 20:48 ` Gustavo F. Padovan
  2011-05-30 21:24   ` David Fries
  0 siblings, 1 reply; 3+ messages in thread
From: Gustavo F. Padovan @ 2011-05-30 20:48 UTC (permalink / raw)
  To: David Fries; +Cc: linux-bluetooth, linux-kernel, Marcel Holtmann

Hi David,

* David Fries <david@fries.net> [2011-05-21 14:02:53 -0500]:

> rfcomm_process_sessions is calling rfcomm_process_rx, but
> in this case the session is closed and freed leaving a
> dangling pointer that blows up when rfcomm_process_rx returns
> and rfcomm_process_dlcs is called with the now dangling session
> pointer.  Check to see if the entry is still in the list.
> 
> Signed-off-by: David Fries <David@Fries.net>
> Cc: Marcel Holtmann <marcel@holtmann.org>
> Cc: "Gustavo F. Padovan" <padovan@profusion.mobi>
> ---
> I sent out an ealier patch,
> Date: Mon, 21 Mar 2011 21:38:10 -0500
> Subject: [PATCH] rfcomm/core.c avoid dangling pointer, check session
> 
> That version added a return value to rfcomm_session_close to determine
> if the session was closed.  I thought this would be cleaner.
> 
> I can reproduce using blueman-manager on desktop, and Motorola S305 bluetooth
> headset, 2.6.39, but it can take a few attempts.  Start out with the
> desktop as the last device the S305 paired with.
> desktop, connect to the S305,
> S305, turn on
> desktop (connection fails)
> desktop (connection automatically comes up now that S305 is on)
> desktop disconnect S305
> desktop (kernel panic)
> 
> While rfcomm_process_sessions looks symmetrical,
> rfcomm_session_hold(s);
> rfcomm_process_rx
> rfcomm_process_dlcs
> rfcomm_session_put(s);
> 
> rfcomm_process_rx
> if (sk->sk_state == BT_CLOSED) {
>         if (!s->initiator)
>                 rfcomm_session_put(s);
>         rfcomm_session_close(s, sk->sk_err);
> 
> Which isn't symmetrical.  I don't know enough about the subsystem to
> know if there is a better cleaner way to fix this, or if my patch is
> the best solution.
> 
>  net/bluetooth/rfcomm/core.c |    6 ++++++
>  1 files changed, 6 insertions(+), 0 deletions(-)
> 
> diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
> index c997393..ac47ef3 100644
> --- a/net/bluetooth/rfcomm/core.c
> +++ b/net/bluetooth/rfcomm/core.c
> @@ -1952,6 +1952,12 @@ static inline void rfcomm_process_sessions(void)
>  
>  		default:
>  			rfcomm_process_rx(s);
> +			/* The current session can be closed as part of rx
> +			 * in which case s is now dangling.  Check if it
> +			 * has been removed.
> +			 */
> +			if(n->prev != p)
> +				continue;
>  			break;
>  		}

I don't like this, it's not the proper fix. So I'm trying to figure out this
and fix it. Can you try this patch:


padovan bluetooth-next-2.6 $ git diff
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 5759bb7..75c58ed 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1958,6 +1958,9 @@ static inline void rfcomm_process_sessions(void)
                        break;
                }
 
+               if (s->sock->sk->sk_state == BT_CLOSED)
+                       continue;
+
                rfcomm_process_dlcs(s);
 
                rfcomm_session_put(s);

-- 
Gustavo F. Padovan
http://profusion.mobi

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] rfcomm/core.c avoid dangling pointer, check session exists
  2011-05-30 20:48 ` Gustavo F. Padovan
@ 2011-05-30 21:24   ` David Fries
  0 siblings, 0 replies; 3+ messages in thread
From: David Fries @ 2011-05-30 21:24 UTC (permalink / raw)
  To: Gustavo F. Padovan
  Cc: akpm, linux-bluetooth, linux-kernel, Marcel Holtmann, linville

On Mon, May 30, 2011 at 05:48:52PM -0300, Gustavo F. Padovan wrote:
> Hi David,
> 
> * David Fries <david@fries.net> [2011-05-21 14:02:53 -0500]:
> 
> > rfcomm_process_sessions is calling rfcomm_process_rx, but
> > in this case the session is closed and freed leaving a
> > dangling pointer that blows up when rfcomm_process_rx returns
> > and rfcomm_process_dlcs is called with the now dangling session
> > pointer.  Check to see if the entry is still in the list.
> > 
> > Signed-off-by: David Fries <David@Fries.net>
> > Cc: Marcel Holtmann <marcel@holtmann.org>
> > Cc: "Gustavo F. Padovan" <padovan@profusion.mobi>
> > ---
> > I sent out an ealier patch,
> > Date: Mon, 21 Mar 2011 21:38:10 -0500
> > Subject: [PATCH] rfcomm/core.c avoid dangling pointer, check session
> > 
> > That version added a return value to rfcomm_session_close to determine
> > if the session was closed.  I thought this would be cleaner.
> > 
> > I can reproduce using blueman-manager on desktop, and Motorola S305 bluetooth
> > headset, 2.6.39, but it can take a few attempts.  Start out with the
> > desktop as the last device the S305 paired with.
> > desktop, connect to the S305,
> > S305, turn on
> > desktop (connection fails)
> > desktop (connection automatically comes up now that S305 is on)
> > desktop disconnect S305
> > desktop (kernel panic)
> > 
> > While rfcomm_process_sessions looks symmetrical,
> > rfcomm_session_hold(s);
> > rfcomm_process_rx
> > rfcomm_process_dlcs
> > rfcomm_session_put(s);
> > 
> > rfcomm_process_rx
> > if (sk->sk_state == BT_CLOSED) {
> >         if (!s->initiator)
> >                 rfcomm_session_put(s);
> >         rfcomm_session_close(s, sk->sk_err);
> > 
> > Which isn't symmetrical.  I don't know enough about the subsystem to
> > know if there is a better cleaner way to fix this, or if my patch is
> > the best solution.
> > 
> >  net/bluetooth/rfcomm/core.c |    6 ++++++
> >  1 files changed, 6 insertions(+), 0 deletions(-)
> > 
> > diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
> > index c997393..ac47ef3 100644
> > --- a/net/bluetooth/rfcomm/core.c
> > +++ b/net/bluetooth/rfcomm/core.c
> > @@ -1952,6 +1952,12 @@ static inline void rfcomm_process_sessions(void)
> >  
> >  		default:
> >  			rfcomm_process_rx(s);
> > +			/* The current session can be closed as part of rx
> > +			 * in which case s is now dangling.  Check if it
> > +			 * has been removed.
> > +			 */
> > +			if(n->prev != p)
> > +				continue;
> >  			break;
> >  		}
> 
> I don't like this, it's not the proper fix. So I'm trying to figure out this
> and fix it. Can you try this patch:

Not without some explaination as to what it's trying to accomplish
(other than crash my computer), it's just a single CPU system, so it
isn't a very good test case for crashes in use after free anyway.
s->sock has been released by sock_release, s has been freed by kfree
(in rfcomm_session_del), which leaves s->sock-> completely dangling by
now.  That's why I was using something other than s to determine if
it's dangling, and looking to see if it was still in the list looked
like the best way to me.

I posted an earlier patch, 'Date: Mon, 21 Mar 2011 21:38:10 -0500'
where I added a return value to to rfcomm_session_put, as another way
to determine if s has been freed and now dangling.  The other question
is why check BT_CLOSED outside of default?  It's only
rfcomm_process_rx that will delete the session with something still
holding on to it.

I would rather see a fix where rfcomm_process_rx doesn't do the put
which caused this situation.  Also, now that I look at it,
rfcomm_process_rx is doing a close after it did a put, which means the
entire close is dealing with a dangling pointer.  Looks to me like the
order could be switched, pending the outcome of the propper fix.

	if (sk->sk_state == BT_CLOSED) {
		if (!s->initiator)
			rfcomm_session_put(s);

		rfcomm_session_close(s, sk->sk_err);
	}

> padovan bluetooth-next-2.6 $ git diff
> diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
> index 5759bb7..75c58ed 100644
> --- a/net/bluetooth/rfcomm/core.c
> +++ b/net/bluetooth/rfcomm/core.c
> @@ -1958,6 +1958,9 @@ static inline void rfcomm_process_sessions(void)
>                         break;
>                 }
>  
> +               if (s->sock->sk->sk_state == BT_CLOSED)
> +                       continue;
> +
>                 rfcomm_process_dlcs(s);
>  
>                 rfcomm_session_put(s);
> 
> -- 
> Gustavo F. Padovan
> http://profusion.mobi

-- 
David Fries <david@fries.net>    PGP pub CB1EE8F0
http://fries.net/~david/

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2011-05-30 21:24 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-21 19:02 [PATCH] rfcomm/core.c avoid dangling pointer, check session exists David Fries
2011-05-30 20:48 ` Gustavo F. Padovan
2011-05-30 21:24   ` David Fries

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).