* [PATCHv3 0/2] Fix kernel crash in rfcomm/l2cap
@ 2010-10-29 13:42 Emeltchenko Andrei
2010-10-29 13:43 ` [PATCHv3 1/2] Bluetooth: Check sk is not owned before freeing l2cap_conn Emeltchenko Andrei
2010-10-29 13:43 ` [PATCHv3 2/2] Bluetooth: timer check sk is not owned before freeing Emeltchenko Andrei
0 siblings, 2 replies; 7+ messages in thread
From: Emeltchenko Andrei @ 2010-10-29 13:42 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@nokia.com>
Yet another version of patches fixing kernel crash in RFCOMM / L2CAP.
Do not delete l2cap channel and socket sk when sk is owned by user.
To delete l2cap channel standard timer is used.
lock_sock and release_sock do not hold a normal spinlock directly but
instead hold the owner field. This means bh_lock_sock can still execute
even if the socket is "locked". More info can be found here:
http://www.linuxfoundation.org/collaborate/workgroups/networking/socketlocks
When sending following sequence:
...
No. Time Source Destination Protocol Info
89 1.951202 RFCOMM Rcvd DISC DLCI=20
90 1.951324 RFCOMM Sent UA DLCI=20
91 1.959381 HCI_EVT Number of Completed Packets
92 1.966461 RFCOMM Rcvd DISC DLCI=0
93 1.966492 L2CAP Rcvd Disconnect Request
94 1.972595 L2CAP Sent Disconnect Response
...
krfcommd kernel thread is preempted with l2cap tasklet which remove l2cap_conn
(L2CAP connection handler structure). Then rfcomm thread tries to send RFCOMM
UA which is reply to RFCOMM DISC and when de-referencing l2cap_conn crash
happens.
Andrei Emeltchenko (2):
Bluetooth: Check sk is not owned before freeing l2cap_conn
Bluetooth: timer check sk is not owned before freeing
net/bluetooth/l2cap.c | 58 ++++++++++++++++++++++++++++++++++++++----------
1 files changed, 46 insertions(+), 12 deletions(-)
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCHv3 1/2] Bluetooth: Check sk is not owned before freeing l2cap_conn 2010-10-29 13:42 [PATCHv3 0/2] Fix kernel crash in rfcomm/l2cap Emeltchenko Andrei @ 2010-10-29 13:43 ` Emeltchenko Andrei 2010-10-29 21:27 ` Gustavo F. Padovan 2010-10-29 13:43 ` [PATCHv3 2/2] Bluetooth: timer check sk is not owned before freeing Emeltchenko Andrei 1 sibling, 1 reply; 7+ messages in thread From: Emeltchenko Andrei @ 2010-10-29 13:43 UTC (permalink / raw) To: linux-bluetooth From: Andrei Emeltchenko <andrei.emeltchenko@nokia.com> Check that socket sk is not locked in user process before removing l2cap connection handler. lock_sock and release_sock do not hold a normal spinlock directly but instead hold the owner field. This means bh_lock_sock can still execute even if the socket is "locked". More info can be found here: http://www.linuxfoundation.org/collaborate/workgroups/networking/socketlocks krfcommd kernel thread may be preempted with l2cap tasklet which remove l2cap_conn structure. If krfcommd is in process of sending of RFCOMM reply (like "RFCOMM UA" reply to "RFCOMM DISC") then kernel crash happens. ... [ 694.175933] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 694.184936] pgd = c0004000 [ 694.187683] [00000000] *pgd=00000000 [ 694.191711] Internal error: Oops: 5 [#1] PREEMPT [ 694.196350] last sysfs file: /sys/devices/platform/hci_h4p/firmware/hci_h4p/loading [ 694.260375] CPU: 0 Not tainted (2.6.32.10 #1) [ 694.265106] PC is at l2cap_sock_sendmsg+0x43c/0x73c [l2cap] [ 694.270721] LR is at 0xd7017303 ... [ 694.525085] Backtrace: [ 694.527587] [<bf266be0>] (l2cap_sock_sendmsg+0x0/0x73c [l2cap]) from [<c02f2cc8>] (sock_sendmsg+0xb8/0xd8) [ 694.537292] [<c02f2c10>] (sock_sendmsg+0x0/0xd8) from [<c02f3044>] (kernel_sendmsg+0x48/0x80) Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@nokia.com> --- net/bluetooth/l2cap.c | 26 ++++++++++++++++++++++++++ 1 files changed, 26 insertions(+), 0 deletions(-) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 6f931cc..b1344d8 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3078,6 +3078,14 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd break; default: + /* don't delete l2cap channel if sk is owned by user */ + if (sock_owned_by_user(sk)) { + sk->sk_state = BT_DISCONN; + l2cap_sock_clear_timer(sk); + l2cap_sock_set_timer(sk, HZ); + break; + } + l2cap_chan_del(sk, ECONNREFUSED); break; } @@ -3283,6 +3291,15 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd sk->sk_shutdown = SHUTDOWN_MASK; + /* don't delete l2cap channel if sk is owned by user */ + if (sock_owned_by_user(sk)) { + sk->sk_state = BT_DISCONN; + l2cap_sock_clear_timer(sk); + l2cap_sock_set_timer(sk, HZ); + bh_unlock_sock(sk); + return 0; + } + l2cap_chan_del(sk, ECONNRESET); bh_unlock_sock(sk); @@ -3305,6 +3322,15 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd if (!sk) return 0; + /* don't delete l2cap channel if sk is owned by user */ + if (sock_owned_by_user(sk)) { + sk->sk_state = BT_DISCONN; + l2cap_sock_clear_timer(sk); + l2cap_sock_set_timer(sk, HZ); + bh_unlock_sock(sk); + return 0; + } + l2cap_chan_del(sk, 0); bh_unlock_sock(sk); -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCHv3 1/2] Bluetooth: Check sk is not owned before freeing l2cap_conn 2010-10-29 13:43 ` [PATCHv3 1/2] Bluetooth: Check sk is not owned before freeing l2cap_conn Emeltchenko Andrei @ 2010-10-29 21:27 ` Gustavo F. Padovan 0 siblings, 0 replies; 7+ messages in thread From: Gustavo F. Padovan @ 2010-10-29 21:27 UTC (permalink / raw) To: Emeltchenko Andrei; +Cc: linux-bluetooth Hi Andrei, * Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2010-10-29 16:43:00 +0300]: > From: Andrei Emeltchenko <andrei.emeltchenko@nokia.com> > > Check that socket sk is not locked in user process before removing > l2cap connection handler. > > lock_sock and release_sock do not hold a normal spinlock directly but > instead hold the owner field. This means bh_lock_sock can still execute > even if the socket is "locked". More info can be found here: > http://www.linuxfoundation.org/collaborate/workgroups/networking/socketlocks > > krfcommd kernel thread may be preempted with l2cap tasklet which remove > l2cap_conn structure. If krfcommd is in process of sending of RFCOMM reply > (like "RFCOMM UA" reply to "RFCOMM DISC") then kernel crash happens. > > ... > [ 694.175933] Unable to handle kernel NULL pointer dereference at virtual address 00000000 > [ 694.184936] pgd = c0004000 > [ 694.187683] [00000000] *pgd=00000000 > [ 694.191711] Internal error: Oops: 5 [#1] PREEMPT > [ 694.196350] last sysfs file: /sys/devices/platform/hci_h4p/firmware/hci_h4p/loading > [ 694.260375] CPU: 0 Not tainted (2.6.32.10 #1) > [ 694.265106] PC is at l2cap_sock_sendmsg+0x43c/0x73c [l2cap] > [ 694.270721] LR is at 0xd7017303 > ... > [ 694.525085] Backtrace: > [ 694.527587] [<bf266be0>] (l2cap_sock_sendmsg+0x0/0x73c [l2cap]) from [<c02f2cc8>] (sock_sendmsg+0xb8/0xd8) > [ 694.537292] [<c02f2c10>] (sock_sendmsg+0x0/0xd8) from [<c02f3044>] (kernel_sendmsg+0x48/0x80) > > Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@nokia.com> > --- > net/bluetooth/l2cap.c | 26 ++++++++++++++++++++++++++ > 1 files changed, 26 insertions(+), 0 deletions(-) > > diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c > index 6f931cc..b1344d8 100644 > --- a/net/bluetooth/l2cap.c > +++ b/net/bluetooth/l2cap.c > @@ -3078,6 +3078,14 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd > break; > > default: > + /* don't delete l2cap channel if sk is owned by user */ > + if (sock_owned_by_user(sk)) { > + sk->sk_state = BT_DISCONN; > + l2cap_sock_clear_timer(sk); > + l2cap_sock_set_timer(sk, HZ); > + break; > + } > + > l2cap_chan_del(sk, ECONNREFUSED); > break; > } > @@ -3283,6 +3291,15 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd > > sk->sk_shutdown = SHUTDOWN_MASK; > > + /* don't delete l2cap channel if sk is owned by user */ > + if (sock_owned_by_user(sk)) { > + sk->sk_state = BT_DISCONN; > + l2cap_sock_clear_timer(sk); > + l2cap_sock_set_timer(sk, HZ); > + bh_unlock_sock(sk); > + return 0; > + } > + > l2cap_chan_del(sk, ECONNRESET); > bh_unlock_sock(sk); > > @@ -3305,6 +3322,15 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd > if (!sk) > return 0; > > + /* don't delete l2cap channel if sk is owned by user */ > + if (sock_owned_by_user(sk)) { > + sk->sk_state = BT_DISCONN; > + l2cap_sock_clear_timer(sk); > + l2cap_sock_set_timer(sk, HZ); 1 second is too much. Change it to HZ/5 as well. I think it is a reasonable value. -- Gustavo F. Padovan ProFUSION embedded systems - http://profusion.mobi ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCHv3 2/2] Bluetooth: timer check sk is not owned before freeing 2010-10-29 13:42 [PATCHv3 0/2] Fix kernel crash in rfcomm/l2cap Emeltchenko Andrei 2010-10-29 13:43 ` [PATCHv3 1/2] Bluetooth: Check sk is not owned before freeing l2cap_conn Emeltchenko Andrei @ 2010-10-29 13:43 ` Emeltchenko Andrei 2010-10-29 21:17 ` Gustavo F. Padovan 1 sibling, 1 reply; 7+ messages in thread From: Emeltchenko Andrei @ 2010-10-29 13:43 UTC (permalink / raw) To: linux-bluetooth From: Andrei Emeltchenko <andrei.emeltchenko@nokia.com> In timer context we might delete l2cap channel used by krfcommd. The check makes sure that sk is not owned. If sk is owned we restart timer for HZ/5. Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@nokia.com> --- net/bluetooth/l2cap.c | 32 ++++++++++++++++++++------------ 1 files changed, 20 insertions(+), 12 deletions(-) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index b1344d8..c67b3c6 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -83,6 +83,18 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); /* ---- L2CAP timers ---- */ +static void l2cap_sock_set_timer(struct sock *sk, long timeout) +{ + BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout); + sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout); +} + +static void l2cap_sock_clear_timer(struct sock *sk) +{ + BT_DBG("sock %p state %d", sk, sk->sk_state); + sk_stop_timer(sk, &sk->sk_timer); +} + static void l2cap_sock_timeout(unsigned long arg) { struct sock *sk = (struct sock *) arg; @@ -92,6 +104,14 @@ static void l2cap_sock_timeout(unsigned long arg) bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + /* sk is owned by user. Try again later */ + l2cap_sock_set_timer(sk, HZ / 5); + bh_unlock_sock(sk); + sock_put(sk); + return; + } + if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG) reason = ECONNREFUSED; else if (sk->sk_state == BT_CONNECT && @@ -108,18 +128,6 @@ static void l2cap_sock_timeout(unsigned long arg) sock_put(sk); } -static void l2cap_sock_set_timer(struct sock *sk, long timeout) -{ - BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout); - sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout); -} - -static void l2cap_sock_clear_timer(struct sock *sk) -{ - BT_DBG("sock %p state %d", sk, sk->sk_state); - sk_stop_timer(sk, &sk->sk_timer); -} - /* ---- L2CAP channels ---- */ static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) { -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCHv3 2/2] Bluetooth: timer check sk is not owned before freeing 2010-10-29 13:43 ` [PATCHv3 2/2] Bluetooth: timer check sk is not owned before freeing Emeltchenko Andrei @ 2010-10-29 21:17 ` Gustavo F. Padovan 2010-11-01 14:20 ` Andrei Emeltchenko 0 siblings, 1 reply; 7+ messages in thread From: Gustavo F. Padovan @ 2010-10-29 21:17 UTC (permalink / raw) To: Emeltchenko Andrei; +Cc: linux-bluetooth Hi Andrei, * Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2010-10-29 16:43:01 +0300]: > From: Andrei Emeltchenko <andrei.emeltchenko@nokia.com> > > In timer context we might delete l2cap channel used by krfcommd. > The check makes sure that sk is not owned. If sk is owned we > restart timer for HZ/5. > > Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@nokia.com> > --- > net/bluetooth/l2cap.c | 32 ++++++++++++++++++++------------ > 1 files changed, 20 insertions(+), 12 deletions(-) > > diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c > index b1344d8..c67b3c6 100644 > --- a/net/bluetooth/l2cap.c > +++ b/net/bluetooth/l2cap.c > @@ -83,6 +83,18 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, > static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); > > /* ---- L2CAP timers ---- */ > +static void l2cap_sock_set_timer(struct sock *sk, long timeout) > +{ > + BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout); > + sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout); > +} > + > +static void l2cap_sock_clear_timer(struct sock *sk) > +{ > + BT_DBG("sock %p state %d", sk, sk->sk_state); > + sk_stop_timer(sk, &sk->sk_timer); > +} > + > static void l2cap_sock_timeout(unsigned long arg) > { > struct sock *sk = (struct sock *) arg; > @@ -92,6 +104,14 @@ static void l2cap_sock_timeout(unsigned long arg) > > bh_lock_sock(sk); > > + if (sock_owned_by_user(sk)) { > + /* sk is owned by user. Try again later */ > + l2cap_sock_set_timer(sk, HZ / 5); > + bh_unlock_sock(sk); > + sock_put(sk); You can't do a sock_put() here, you have to keep the referencee to the socket while the timer is enabled. -- Gustavo F. Padovan ProFUSION embedded systems - http://profusion.mobi ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCHv3 2/2] Bluetooth: timer check sk is not owned before freeing 2010-10-29 21:17 ` Gustavo F. Padovan @ 2010-11-01 14:20 ` Andrei Emeltchenko 2010-11-02 15:15 ` Gustavo F. Padovan 0 siblings, 1 reply; 7+ messages in thread From: Andrei Emeltchenko @ 2010-11-01 14:20 UTC (permalink / raw) To: Gustavo F. Padovan; +Cc: linux-bluetooth Hi Gustavo On Sat, Oct 30, 2010 at 12:17 AM, Gustavo F. Padovan <padovan@profusion.mobi> wrote: > Hi Andrei, > > * Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2010-10-29 16:43:01 +0300]: > >> From: Andrei Emeltchenko <andrei.emeltchenko@nokia.com> >> >> In timer context we might delete l2cap channel used by krfcommd. >> The check makes sure that sk is not owned. If sk is owned we >> restart timer for HZ/5. >> >> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@nokia.com> >> --- >> net/bluetooth/l2cap.c | 32 ++++++++++++++++++++------------ >> 1 files changed, 20 insertions(+), 12 deletions(-) >> >> diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c >> index b1344d8..c67b3c6 100644 >> --- a/net/bluetooth/l2cap.c >> +++ b/net/bluetooth/l2cap.c >> @@ -83,6 +83,18 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, >> static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); >> >> /* ---- L2CAP timers ---- */ >> +static void l2cap_sock_set_timer(struct sock *sk, long timeout) >> +{ >> + BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout); >> + sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout); >> +} >> + >> +static void l2cap_sock_clear_timer(struct sock *sk) >> +{ >> + BT_DBG("sock %p state %d", sk, sk->sk_state); >> + sk_stop_timer(sk, &sk->sk_timer); >> +} >> + >> static void l2cap_sock_timeout(unsigned long arg) >> { >> struct sock *sk = (struct sock *) arg; >> @@ -92,6 +104,14 @@ static void l2cap_sock_timeout(unsigned long arg) >> >> bh_lock_sock(sk); >> >> + if (sock_owned_by_user(sk)) { >> + /* sk is owned by user. Try again later */ >> + l2cap_sock_set_timer(sk, HZ / 5); >> + bh_unlock_sock(sk); >> + sock_put(sk); > > You can't do a sock_put() here, you have to keep the referencee to the > socket while the timer is enabled. sk_reset_timer is holding sock when timer restarts. The same way done in TCP code in function: static void tcp_delack_timer(unsigned long data) Regards, Andrei ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCHv3 2/2] Bluetooth: timer check sk is not owned before freeing 2010-11-01 14:20 ` Andrei Emeltchenko @ 2010-11-02 15:15 ` Gustavo F. Padovan 0 siblings, 0 replies; 7+ messages in thread From: Gustavo F. Padovan @ 2010-11-02 15:15 UTC (permalink / raw) To: Andrei Emeltchenko; +Cc: linux-bluetooth Hi Andrei, * Andrei Emeltchenko <andrei.emeltchenko.news@gmail.com> [2010-11-01 16:20:15 +0200]: > Hi Gustavo > > On Sat, Oct 30, 2010 at 12:17 AM, Gustavo F. Padovan > <padovan@profusion.mobi> wrote: > > Hi Andrei, > > > > * Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2010-10-29 16:43:01 +0300]: > > > >> From: Andrei Emeltchenko <andrei.emeltchenko@nokia.com> > >> > >> In timer context we might delete l2cap channel used by krfcommd. > >> The check makes sure that sk is not owned. If sk is owned we > >> restart timer for HZ/5. > >> > >> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@nokia.com> > >> --- > >> net/bluetooth/l2cap.c | 32 ++++++++++++++++++++------------ > >> 1 files changed, 20 insertions(+), 12 deletions(-) > >> > >> diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c > >> index b1344d8..c67b3c6 100644 > >> --- a/net/bluetooth/l2cap.c > >> +++ b/net/bluetooth/l2cap.c > >> @@ -83,6 +83,18 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, > >> static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); > >> > >> /* ---- L2CAP timers ---- */ > >> +static void l2cap_sock_set_timer(struct sock *sk, long timeout) > >> +{ > >> + BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout); > >> + sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout); > >> +} > >> + > >> +static void l2cap_sock_clear_timer(struct sock *sk) > >> +{ > >> + BT_DBG("sock %p state %d", sk, sk->sk_state); > >> + sk_stop_timer(sk, &sk->sk_timer); > >> +} > >> + > >> static void l2cap_sock_timeout(unsigned long arg) > >> { > >> struct sock *sk = (struct sock *) arg; > >> @@ -92,6 +104,14 @@ static void l2cap_sock_timeout(unsigned long arg) > >> > >> bh_lock_sock(sk); > >> > >> + if (sock_owned_by_user(sk)) { > >> + /* sk is owned by user. Try again later */ > >> + l2cap_sock_set_timer(sk, HZ / 5); > >> + bh_unlock_sock(sk); > >> + sock_put(sk); > > > > You can't do a sock_put() here, you have to keep the referencee to the > > socket while the timer is enabled. > > sk_reset_timer is holding sock when timer restarts. The same way done > in TCP code in function: > static void tcp_delack_timer(unsigned long data) Yes, I got confused, you're right. -- Gustavo F. Padovan ProFUSION embedded systems - http://profusion.mobi ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2010-11-02 15:15 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-10-29 13:42 [PATCHv3 0/2] Fix kernel crash in rfcomm/l2cap Emeltchenko Andrei 2010-10-29 13:43 ` [PATCHv3 1/2] Bluetooth: Check sk is not owned before freeing l2cap_conn Emeltchenko Andrei 2010-10-29 21:27 ` Gustavo F. Padovan 2010-10-29 13:43 ` [PATCHv3 2/2] Bluetooth: timer check sk is not owned before freeing Emeltchenko Andrei 2010-10-29 21:17 ` Gustavo F. Padovan 2010-11-01 14:20 ` Andrei Emeltchenko 2010-11-02 15:15 ` Gustavo F. Padovan
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).