Skip to content

Commit

Permalink
l2tp: hold reference on tunnels printed in pppol2tp proc file
Browse files Browse the repository at this point in the history
Use l2tp_tunnel_get_nth() instead of l2tp_tunnel_find_nth(), to be safe
against concurrent tunnel deletion.

Unlike sessions, we can't drop the reference held on tunnels in
pppol2tp_seq_show(). Tunnels are reused across several calls to
pppol2tp_seq_start() when iterating over sessions. These iterations
need the tunnel for accessing the next session. Therefore the only safe
moment for dropping the reference is just before searching for the next
tunnel.

Normally, the last invocation of pppol2tp_next_tunnel() doesn't find
any new tunnel, so it drops the last tunnel without taking any new
reference. However, in case of error, pppol2tp_seq_stop() is called
directly, so we have to drop the reference there.

Fixes: fd558d1 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts")
Signed-off-by: Guillaume Nault <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Guillaume Nault authored and davem330 committed Apr 13, 2018
1 parent 5846c13 commit 0e0c3fe
Showing 1 changed file with 17 additions and 7 deletions.
24 changes: 17 additions & 7 deletions net/l2tp/l2tp_ppp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1551,16 +1551,19 @@ struct pppol2tp_seq_data {

static void pppol2tp_next_tunnel(struct net *net, struct pppol2tp_seq_data *pd)
{
/* Drop reference taken during previous invocation */
if (pd->tunnel)
l2tp_tunnel_dec_refcount(pd->tunnel);

for (;;) {
pd->tunnel = l2tp_tunnel_find_nth(net, pd->tunnel_idx);
pd->tunnel = l2tp_tunnel_get_nth(net, pd->tunnel_idx);
pd->tunnel_idx++;

if (pd->tunnel == NULL)
break;
/* Only accept L2TPv2 tunnels */
if (!pd->tunnel || pd->tunnel->version == 2)
return;

/* Ignore L2TPv3 tunnels */
if (pd->tunnel->version < 3)
break;
l2tp_tunnel_dec_refcount(pd->tunnel);
}
}

Expand Down Expand Up @@ -1609,7 +1612,14 @@ static void *pppol2tp_seq_next(struct seq_file *m, void *v, loff_t *pos)

static void pppol2tp_seq_stop(struct seq_file *p, void *v)
{
/* nothing to do */
struct pppol2tp_seq_data *pd = v;

if (!pd || pd == SEQ_START_TOKEN)
return;

/* Drop reference taken by last invocation of pppol2tp_next_tunnel() */
if (pd->tunnel)
l2tp_tunnel_dec_refcount(pd->tunnel);
}

static void pppol2tp_seq_tunnel_show(struct seq_file *m, void *v)
Expand Down

0 comments on commit 0e0c3fe

Please sign in to comment.