Message ID | 1501495658-119725-1-git-send-email-gfree.wind@vip.163.com |
---|---|
State | Accepted, archived |
Delegated to: | David Miller |
Headers | show |
From: gfree.wind@vip.163.com Date: Mon, 31 Jul 2017 18:07:38 +0800 > From: Gao Feng <gfree.wind@vip.163.com> > > The PPTP set the pptp_sock_destruct as the sock's sk_destruct, it would > trigger this bug when __sk_free is invoked in atomic context, because of > the call path pptp_sock_destruct->del_chan->synchronize_rcu. > > Now move the synchronize_rcu to pptp_release from del_chan. This is the > only one case which would free the sock and need the synchronize_rcu. > > The following is the panic I met with kernel 3.3.8, but this issue should > exist in current kernel too according to the codes. ... > Signed-off-by: Gao Feng <gfree.wind@vip.163.com> Applied, thanks.
On Mon, Jul 31, 2017 at 3:07 AM, <gfree.wind@vip.163.com> wrote: > From: Gao Feng <gfree.wind@vip.163.com> > > The PPTP set the pptp_sock_destruct as the sock's sk_destruct, it would > trigger this bug when __sk_free is invoked in atomic context, because of > the call path pptp_sock_destruct->del_chan->synchronize_rcu. > > Now move the synchronize_rcu to pptp_release from del_chan. This is the > only one case which would free the sock and need the synchronize_rcu. I don't understand the last part. From my understanding, this RCU is supposed to protect the pppox_sock pointers in 'callid_sock' which could be NULL'ed in del_chan(). And the pppox_sock is freed when the last refcnt is gone, that is, when sock dctor is called. pptp_release() is ONLY called when the fd in user-space is gone, not necessarily the last refcnt.
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index eac499c..6dde9a0 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -131,7 +131,6 @@ static void del_chan(struct pppox_sock *sock) clear_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap); RCU_INIT_POINTER(callid_sock[sock->proto.pptp.src_addr.call_id], NULL); spin_unlock(&chan_lock); - synchronize_rcu(); } static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) @@ -520,6 +519,7 @@ static int pptp_release(struct socket *sock) po = pppox_sk(sk); del_chan(po); + synchronize_rcu(); pppox_unbind_sock(sk); sk->sk_state = PPPOX_DEAD;