Skip to content

Commit 4101971

Browse files
committed
Merge branch 'l2tp-races'
Cong Wang says: ==================== l2tp: fix race conditions in l2tp_tunnel_register() This patchset contains two patches, the first one is a preparation for the second one which is the actual fix. Please find more details in each patch description. I have ran the l2tp test (https://github.com/katalix/l2tp-ktest), all test cases are passed. v3: preserve EEXIST errno for user-space v2: move IDR allocation to l2tp_tunnel_register() ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 3a415d5 + 0b2c597 commit 4101971

File tree

1 file changed

+52
-53
lines changed

1 file changed

+52
-53
lines changed

net/l2tp/l2tp_core.c

Lines changed: 52 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ static struct workqueue_struct *l2tp_wq;
104104
/* per-net private data for this module */
105105
static unsigned int l2tp_net_id;
106106
struct l2tp_net {
107-
struct list_head l2tp_tunnel_list;
108-
/* Lock for write access to l2tp_tunnel_list */
109-
spinlock_t l2tp_tunnel_list_lock;
107+
/* Lock for write access to l2tp_tunnel_idr */
108+
spinlock_t l2tp_tunnel_idr_lock;
109+
struct idr l2tp_tunnel_idr;
110110
struct hlist_head l2tp_session_hlist[L2TP_HASH_SIZE_2];
111111
/* Lock for write access to l2tp_session_hlist */
112112
spinlock_t l2tp_session_hlist_lock;
@@ -208,13 +208,10 @@ struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id)
208208
struct l2tp_tunnel *tunnel;
209209

210210
rcu_read_lock_bh();
211-
list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) {
212-
if (tunnel->tunnel_id == tunnel_id &&
213-
refcount_inc_not_zero(&tunnel->ref_count)) {
214-
rcu_read_unlock_bh();
215-
216-
return tunnel;
217-
}
211+
tunnel = idr_find(&pn->l2tp_tunnel_idr, tunnel_id);
212+
if (tunnel && refcount_inc_not_zero(&tunnel->ref_count)) {
213+
rcu_read_unlock_bh();
214+
return tunnel;
218215
}
219216
rcu_read_unlock_bh();
220217

@@ -224,13 +221,14 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_get);
224221

225222
struct l2tp_tunnel *l2tp_tunnel_get_nth(const struct net *net, int nth)
226223
{
227-
const struct l2tp_net *pn = l2tp_pernet(net);
224+
struct l2tp_net *pn = l2tp_pernet(net);
225+
unsigned long tunnel_id, tmp;
228226
struct l2tp_tunnel *tunnel;
229227
int count = 0;
230228

231229
rcu_read_lock_bh();
232-
list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) {
233-
if (++count > nth &&
230+
idr_for_each_entry_ul(&pn->l2tp_tunnel_idr, tunnel, tmp, tunnel_id) {
231+
if (tunnel && ++count > nth &&
234232
refcount_inc_not_zero(&tunnel->ref_count)) {
235233
rcu_read_unlock_bh();
236234
return tunnel;
@@ -1043,7 +1041,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, uns
10431041
IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED);
10441042
nf_reset_ct(skb);
10451043

1046-
bh_lock_sock(sk);
1044+
bh_lock_sock_nested(sk);
10471045
if (sock_owned_by_user(sk)) {
10481046
kfree_skb(skb);
10491047
ret = NET_XMIT_DROP;
@@ -1227,14 +1225,22 @@ static void l2tp_udp_encap_destroy(struct sock *sk)
12271225
l2tp_tunnel_delete(tunnel);
12281226
}
12291227

1228+
static void l2tp_tunnel_remove(struct net *net, struct l2tp_tunnel *tunnel)
1229+
{
1230+
struct l2tp_net *pn = l2tp_pernet(net);
1231+
1232+
spin_lock_bh(&pn->l2tp_tunnel_idr_lock);
1233+
idr_remove(&pn->l2tp_tunnel_idr, tunnel->tunnel_id);
1234+
spin_unlock_bh(&pn->l2tp_tunnel_idr_lock);
1235+
}
1236+
12301237
/* Workqueue tunnel deletion function */
12311238
static void l2tp_tunnel_del_work(struct work_struct *work)
12321239
{
12331240
struct l2tp_tunnel *tunnel = container_of(work, struct l2tp_tunnel,
12341241
del_work);
12351242
struct sock *sk = tunnel->sock;
12361243
struct socket *sock = sk->sk_socket;
1237-
struct l2tp_net *pn;
12381244

12391245
l2tp_tunnel_closeall(tunnel);
12401246

@@ -1248,12 +1254,7 @@ static void l2tp_tunnel_del_work(struct work_struct *work)
12481254
}
12491255
}
12501256

1251-
/* Remove the tunnel struct from the tunnel list */
1252-
pn = l2tp_pernet(tunnel->l2tp_net);
1253-
spin_lock_bh(&pn->l2tp_tunnel_list_lock);
1254-
list_del_rcu(&tunnel->list);
1255-
spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
1256-
1257+
l2tp_tunnel_remove(tunnel->l2tp_net, tunnel);
12571258
/* drop initial ref */
12581259
l2tp_tunnel_dec_refcount(tunnel);
12591260

@@ -1384,8 +1385,6 @@ static int l2tp_tunnel_sock_create(struct net *net,
13841385
return err;
13851386
}
13861387

1387-
static struct lock_class_key l2tp_socket_class;
1388-
13891388
int l2tp_tunnel_create(int fd, int version, u32 tunnel_id, u32 peer_tunnel_id,
13901389
struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp)
13911390
{
@@ -1455,12 +1454,19 @@ static int l2tp_validate_socket(const struct sock *sk, const struct net *net,
14551454
int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
14561455
struct l2tp_tunnel_cfg *cfg)
14571456
{
1458-
struct l2tp_tunnel *tunnel_walk;
1459-
struct l2tp_net *pn;
1457+
struct l2tp_net *pn = l2tp_pernet(net);
1458+
u32 tunnel_id = tunnel->tunnel_id;
14601459
struct socket *sock;
14611460
struct sock *sk;
14621461
int ret;
14631462

1463+
spin_lock_bh(&pn->l2tp_tunnel_idr_lock);
1464+
ret = idr_alloc_u32(&pn->l2tp_tunnel_idr, NULL, &tunnel_id, tunnel_id,
1465+
GFP_ATOMIC);
1466+
spin_unlock_bh(&pn->l2tp_tunnel_idr_lock);
1467+
if (ret)
1468+
return ret == -ENOSPC ? -EEXIST : ret;
1469+
14641470
if (tunnel->fd < 0) {
14651471
ret = l2tp_tunnel_sock_create(net, tunnel->tunnel_id,
14661472
tunnel->peer_tunnel_id, cfg,
@@ -1474,31 +1480,16 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
14741480
}
14751481

14761482
sk = sock->sk;
1483+
lock_sock(sk);
14771484
write_lock_bh(&sk->sk_callback_lock);
14781485
ret = l2tp_validate_socket(sk, net, tunnel->encap);
1479-
if (ret < 0)
1486+
if (ret < 0) {
1487+
release_sock(sk);
14801488
goto err_inval_sock;
1489+
}
14811490
rcu_assign_sk_user_data(sk, tunnel);
14821491
write_unlock_bh(&sk->sk_callback_lock);
14831492

1484-
tunnel->l2tp_net = net;
1485-
pn = l2tp_pernet(net);
1486-
1487-
sock_hold(sk);
1488-
tunnel->sock = sk;
1489-
1490-
spin_lock_bh(&pn->l2tp_tunnel_list_lock);
1491-
list_for_each_entry(tunnel_walk, &pn->l2tp_tunnel_list, list) {
1492-
if (tunnel_walk->tunnel_id == tunnel->tunnel_id) {
1493-
spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
1494-
sock_put(sk);
1495-
ret = -EEXIST;
1496-
goto err_sock;
1497-
}
1498-
}
1499-
list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list);
1500-
spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
1501-
15021493
if (tunnel->encap == L2TP_ENCAPTYPE_UDP) {
15031494
struct udp_tunnel_sock_cfg udp_cfg = {
15041495
.sk_user_data = tunnel,
@@ -1512,9 +1503,16 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
15121503

15131504
tunnel->old_sk_destruct = sk->sk_destruct;
15141505
sk->sk_destruct = &l2tp_tunnel_destruct;
1515-
lockdep_set_class_and_name(&sk->sk_lock.slock, &l2tp_socket_class,
1516-
"l2tp_sock");
15171506
sk->sk_allocation = GFP_ATOMIC;
1507+
release_sock(sk);
1508+
1509+
sock_hold(sk);
1510+
tunnel->sock = sk;
1511+
tunnel->l2tp_net = net;
1512+
1513+
spin_lock_bh(&pn->l2tp_tunnel_idr_lock);
1514+
idr_replace(&pn->l2tp_tunnel_idr, tunnel, tunnel->tunnel_id);
1515+
spin_unlock_bh(&pn->l2tp_tunnel_idr_lock);
15181516

15191517
trace_register_tunnel(tunnel);
15201518

@@ -1523,9 +1521,6 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
15231521

15241522
return 0;
15251523

1526-
err_sock:
1527-
write_lock_bh(&sk->sk_callback_lock);
1528-
rcu_assign_sk_user_data(sk, NULL);
15291524
err_inval_sock:
15301525
write_unlock_bh(&sk->sk_callback_lock);
15311526

@@ -1534,6 +1529,7 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
15341529
else
15351530
sockfd_put(sock);
15361531
err:
1532+
l2tp_tunnel_remove(net, tunnel);
15371533
return ret;
15381534
}
15391535
EXPORT_SYMBOL_GPL(l2tp_tunnel_register);
@@ -1647,8 +1643,8 @@ static __net_init int l2tp_init_net(struct net *net)
16471643
struct l2tp_net *pn = net_generic(net, l2tp_net_id);
16481644
int hash;
16491645

1650-
INIT_LIST_HEAD(&pn->l2tp_tunnel_list);
1651-
spin_lock_init(&pn->l2tp_tunnel_list_lock);
1646+
idr_init(&pn->l2tp_tunnel_idr);
1647+
spin_lock_init(&pn->l2tp_tunnel_idr_lock);
16521648

16531649
for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++)
16541650
INIT_HLIST_HEAD(&pn->l2tp_session_hlist[hash]);
@@ -1662,11 +1658,13 @@ static __net_exit void l2tp_exit_net(struct net *net)
16621658
{
16631659
struct l2tp_net *pn = l2tp_pernet(net);
16641660
struct l2tp_tunnel *tunnel = NULL;
1661+
unsigned long tunnel_id, tmp;
16651662
int hash;
16661663

16671664
rcu_read_lock_bh();
1668-
list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) {
1669-
l2tp_tunnel_delete(tunnel);
1665+
idr_for_each_entry_ul(&pn->l2tp_tunnel_idr, tunnel, tmp, tunnel_id) {
1666+
if (tunnel)
1667+
l2tp_tunnel_delete(tunnel);
16701668
}
16711669
rcu_read_unlock_bh();
16721670

@@ -1676,6 +1674,7 @@ static __net_exit void l2tp_exit_net(struct net *net)
16761674

16771675
for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++)
16781676
WARN_ON_ONCE(!hlist_empty(&pn->l2tp_session_hlist[hash]));
1677+
idr_destroy(&pn->l2tp_tunnel_idr);
16791678
}
16801679

16811680
static struct pernet_operations l2tp_net_ops = {

0 commit comments

Comments
 (0)