diff options
| author | WANG Cong <xiyou.wangcong@gmail.com> | 2016-07-06 01:12:36 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2016-07-08 23:46:37 -0400 |
| commit | 205e1e255c479f3fd77446415706463b282f94e4 (patch) | |
| tree | 98e80b94c077894fb29591ba610da272349549cd /drivers/net/ppp | |
| parent | 06708f81528725148473c0869d6af5f809c6824b (diff) | |
ppp: defer netns reference release for ppp channel
Matt reported that we have a NULL pointer dereference
in ppp_pernet() from ppp_connect_channel(),
i.e. pch->chan_net is NULL.
This is due to that a parallel ppp_unregister_channel()
could happen while we are in ppp_connect_channel(), during
which pch->chan_net set to NULL. Since we need a reference
to net per channel, it makes sense to sync the refcnt
with the life time of the channel, therefore we should
release this reference when we destroy it.
Fixes: 1f461dcdd296 ("ppp: take reference on channels netns")
Reported-by: Matt Bennett <Matt.Bennett@alliedtelesis.co.nz>
Cc: Paul Mackerras <paulus@samba.org>
Cc: linux-ppp@vger.kernel.org
Cc: Guillaume Nault <g.nault@alphalink.fr>
Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Reviewed-by: Cyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ppp')
| -rw-r--r-- | drivers/net/ppp/ppp_generic.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 8dedafa1a95d..a30ee427efab 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c | |||
| @@ -2601,8 +2601,6 @@ ppp_unregister_channel(struct ppp_channel *chan) | |||
| 2601 | spin_lock_bh(&pn->all_channels_lock); | 2601 | spin_lock_bh(&pn->all_channels_lock); |
| 2602 | list_del(&pch->list); | 2602 | list_del(&pch->list); |
| 2603 | spin_unlock_bh(&pn->all_channels_lock); | 2603 | spin_unlock_bh(&pn->all_channels_lock); |
| 2604 | put_net(pch->chan_net); | ||
| 2605 | pch->chan_net = NULL; | ||
| 2606 | 2604 | ||
| 2607 | pch->file.dead = 1; | 2605 | pch->file.dead = 1; |
| 2608 | wake_up_interruptible(&pch->file.rwait); | 2606 | wake_up_interruptible(&pch->file.rwait); |
| @@ -3136,6 +3134,9 @@ ppp_disconnect_channel(struct channel *pch) | |||
| 3136 | */ | 3134 | */ |
| 3137 | static void ppp_destroy_channel(struct channel *pch) | 3135 | static void ppp_destroy_channel(struct channel *pch) |
| 3138 | { | 3136 | { |
| 3137 | put_net(pch->chan_net); | ||
| 3138 | pch->chan_net = NULL; | ||
| 3139 | |||
| 3139 | atomic_dec(&channel_count); | 3140 | atomic_dec(&channel_count); |
| 3140 | 3141 | ||
| 3141 | if (!pch->file.dead) { | 3142 | if (!pch->file.dead) { |
