| From: Guillaume Nault <g.nault@alphalink.fr> |
| Date: Thu, 19 Apr 2018 16:20:48 +0200 |
| Subject: l2tp: fix {pppol2tp, l2tp_dfs}_seq_stop() in case of seq_file |
| overflow |
| |
| commit 5411b6187adf62909e3b998ac782e722904c7487 upstream. |
| |
| Commit 0e0c3fee3a59 ("l2tp: hold reference on tunnels printed in pppol2tp proc file") |
| assumed that if pppol2tp_seq_stop() was called with non-NULL private |
| data (the 'v' pointer), then pppol2tp_seq_start() would not be called |
| again. It turns out that this isn't guaranteed, and overflowing the |
| seq_file's buffer in pppol2tp_seq_show() is a way to get into this |
| situation. |
| |
| Therefore, pppol2tp_seq_stop() needs to reset pd->tunnel, so that |
| pppol2tp_seq_start() won't drop a reference again if it gets called. |
| We also have to clear pd->session, because the rest of the code expects |
| a non-NULL tunnel when pd->session is set. |
| |
| The l2tp_debugfs module has the same issue. Fix it in the same way. |
| |
| Fixes: 0e0c3fee3a59 ("l2tp: hold reference on tunnels printed in pppol2tp proc file") |
| Fixes: f726214d9b23 ("l2tp: hold reference on tunnels printed in l2tp/tunnels debugfs file") |
| Signed-off-by: Guillaume Nault <g.nault@alphalink.fr> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| net/l2tp/l2tp_debugfs.c | 5 ++++- |
| net/l2tp/l2tp_ppp.c | 5 ++++- |
| 2 files changed, 8 insertions(+), 2 deletions(-) |
| |
| --- a/net/l2tp/l2tp_debugfs.c |
| +++ b/net/l2tp/l2tp_debugfs.c |
| @@ -106,8 +106,11 @@ static void l2tp_dfs_seq_stop(struct seq |
| return; |
| |
| /* Drop reference taken by last invocation of l2tp_dfs_next_tunnel() */ |
| - if (pd->tunnel) |
| + if (pd->tunnel) { |
| l2tp_tunnel_dec_refcount(pd->tunnel); |
| + pd->tunnel = NULL; |
| + pd->session = NULL; |
| + } |
| } |
| |
| static void l2tp_dfs_seq_tunnel_show(struct seq_file *m, void *v) |
| --- a/net/l2tp/l2tp_ppp.c |
| +++ b/net/l2tp/l2tp_ppp.c |
| @@ -1650,8 +1650,11 @@ static void pppol2tp_seq_stop(struct seq |
| return; |
| |
| /* Drop reference taken by last invocation of pppol2tp_next_tunnel() */ |
| - if (pd->tunnel) |
| + if (pd->tunnel) { |
| l2tp_tunnel_dec_refcount(pd->tunnel); |
| + pd->tunnel = NULL; |
| + pd->session = NULL; |
| + } |
| } |
| |
| static void pppol2tp_seq_tunnel_show(struct seq_file *m, void *v) |