Skip to content

Commit 62b982e

Browse files
qsndavem330
authored andcommitted
l2tp: fix race condition in l2tp_tunnel_delete
If we try to delete the same tunnel twice, the first delete operation does a lookup (l2tp_tunnel_get), finds the tunnel, calls l2tp_tunnel_delete, which queues it for deletion by l2tp_tunnel_del_work. The second delete operation also finds the tunnel and calls l2tp_tunnel_delete. If the workqueue has already fired and started running l2tp_tunnel_del_work, then l2tp_tunnel_delete will queue the same tunnel a second time, and try to free the socket again. Add a dead flag to prevent firing the workqueue twice. Then we can remove the check of queue_work's result that was meant to prevent that race but doesn't. Reproducer: ip l2tp add tunnel tunnel_id 3000 peer_tunnel_id 4000 local 192.168.0.2 remote 192.168.0.1 encap udp udp_sport 5000 udp_dport 6000 ip l2tp add session name l2tp1 tunnel_id 3000 session_id 1000 peer_session_id 2000 ip link set l2tp1 up ip l2tp del tunnel tunnel_id 3000 ip l2tp del tunnel tunnel_id 3000 Fixes: f8ccac0 ("l2tp: put tunnel socket release on a workqueue") Reported-by: Jianlin Shi <[email protected]> Signed-off-by: Sabrina Dubroca <[email protected]> Acked-by: Guillaume Nault <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 36f6ee2 commit 62b982e

File tree

2 files changed

+8
-7
lines changed

2 files changed

+8
-7
lines changed

net/l2tp/l2tp_core.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,14 +1688,12 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_create);
16881688

16891689
/* This function is used by the netlink TUNNEL_DELETE command.
16901690
*/
1691-
int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel)
1691+
void l2tp_tunnel_delete(struct l2tp_tunnel *tunnel)
16921692
{
1693-
l2tp_tunnel_inc_refcount(tunnel);
1694-
if (false == queue_work(l2tp_wq, &tunnel->del_work)) {
1695-
l2tp_tunnel_dec_refcount(tunnel);
1696-
return 1;
1693+
if (!test_and_set_bit(0, &tunnel->dead)) {
1694+
l2tp_tunnel_inc_refcount(tunnel);
1695+
queue_work(l2tp_wq, &tunnel->del_work);
16971696
}
1698-
return 0;
16991697
}
17001698
EXPORT_SYMBOL_GPL(l2tp_tunnel_delete);
17011699

net/l2tp/l2tp_core.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ struct l2tp_tunnel_cfg {
161161

162162
struct l2tp_tunnel {
163163
int magic; /* Should be L2TP_TUNNEL_MAGIC */
164+
165+
unsigned long dead;
166+
164167
struct rcu_head rcu;
165168
rwlock_t hlist_lock; /* protect session_hlist */
166169
bool acpt_newsess; /* Indicates whether this
@@ -255,7 +258,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id,
255258
u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg,
256259
struct l2tp_tunnel **tunnelp);
257260
void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel);
258-
int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel);
261+
void l2tp_tunnel_delete(struct l2tp_tunnel *tunnel);
259262
struct l2tp_session *l2tp_session_create(int priv_size,
260263
struct l2tp_tunnel *tunnel,
261264
u32 session_id, u32 peer_session_id,

0 commit comments

Comments
 (0)