Skip to content

Commit d587d82

Browse files
j-c-hPaolo Abeni
authored andcommitted
l2tp: make session IDR and tunnel session list coherent
Modify l2tp_session_register and l2tp_session_unhash so that the session IDR and tunnel session lists remain coherent. To do so, hold the session IDR lock and the tunnel's session list lock when making any changes to either list. Without this change, a rare race condition could hit the WARN_ON_ONCE in l2tp_session_unhash if a thread replaced the IDR entry while another thread was registering the same ID. [ 7126.151795][T17511] WARNING: CPU: 3 PID: 17511 at net/l2tp/l2tp_core.c:1282 l2tp_session_delete.part.0+0x87e/0xbc0 [ 7126.163754][T17511] ? show_regs+0x93/0xa0 [ 7126.164157][T17511] ? __warn+0xe5/0x3c0 [ 7126.164536][T17511] ? l2tp_session_delete.part.0+0x87e/0xbc0 [ 7126.165070][T17511] ? report_bug+0x2e1/0x500 [ 7126.165486][T17511] ? l2tp_session_delete.part.0+0x87e/0xbc0 [ 7126.166013][T17511] ? handle_bug+0x99/0x130 [ 7126.166428][T17511] ? exc_invalid_op+0x35/0x80 [ 7126.166890][T17511] ? asm_exc_invalid_op+0x1a/0x20 [ 7126.167372][T17511] ? l2tp_session_delete.part.0+0x87d/0xbc0 [ 7126.167900][T17511] ? l2tp_session_delete.part.0+0x87e/0xbc0 [ 7126.168429][T17511] ? __local_bh_enable_ip+0xa4/0x120 [ 7126.168917][T17511] l2tp_session_delete+0x40/0x50 [ 7126.169369][T17511] pppol2tp_release+0x1a1/0x3f0 [ 7126.169817][T17511] __sock_release+0xb3/0x270 [ 7126.170247][T17511] ? __pfx_sock_close+0x10/0x10 [ 7126.170697][T17511] sock_close+0x1c/0x30 [ 7126.171087][T17511] __fput+0x40b/0xb90 [ 7126.171470][T17511] task_work_run+0x16c/0x260 [ 7126.171897][T17511] ? __pfx_task_work_run+0x10/0x10 [ 7126.172362][T17511] ? srso_alias_return_thunk+0x5/0xfbef5 [ 7126.172863][T17511] ? do_raw_spin_unlock+0x174/0x230 [ 7126.173348][T17511] do_exit+0xaae/0x2b40 [ 7126.173730][T17511] ? srso_alias_return_thunk+0x5/0xfbef5 [ 7126.174235][T17511] ? __pfx_lock_release+0x10/0x10 [ 7126.174690][T17511] ? srso_alias_return_thunk+0x5/0xfbef5 [ 7126.175190][T17511] ? do_raw_spin_lock+0x12c/0x2b0 [ 7126.175650][T17511] ? __pfx_do_exit+0x10/0x10 [ 7126.176072][T17511] ? _raw_spin_unlock_irq+0x23/0x50 [ 7126.176543][T17511] do_group_exit+0xd3/0x2a0 [ 7126.176990][T17511] __x64_sys_exit_group+0x3e/0x50 [ 7126.177456][T17511] x64_sys_call+0x1821/0x1830 [ 7126.177895][T17511] do_syscall_64+0xcb/0x250 [ 7126.178317][T17511] entry_SYSCALL_64_after_hwframe+0x77/0x7f Fixes: aa5e17e ("l2tp: store l2tpv3 sessions in per-net IDR") Signed-off-by: James Chapman <[email protected]> Signed-off-by: Tom Parkin <[email protected]> Reviewed-by: Simon Horman <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
1 parent cc73bba commit d587d82

File tree

1 file changed

+14
-18
lines changed

1 file changed

+14
-18
lines changed

net/l2tp/l2tp_core.c

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -441,14 +441,15 @@ int l2tp_session_register(struct l2tp_session *session,
441441
int err;
442442

443443
spin_lock_bh(&tunnel->list_lock);
444+
spin_lock_bh(&pn->l2tp_session_idr_lock);
445+
444446
if (!tunnel->acpt_newsess) {
445447
err = -ENODEV;
446-
goto err_tlock;
448+
goto out;
447449
}
448450

449451
if (tunnel->version == L2TP_HDR_VER_3) {
450452
session_key = session->session_id;
451-
spin_lock_bh(&pn->l2tp_session_idr_lock);
452453
err = idr_alloc_u32(&pn->l2tp_v3_session_idr, NULL,
453454
&session_key, session_key, GFP_ATOMIC);
454455
/* IP encap expects session IDs to be globally unique, while
@@ -462,43 +463,36 @@ int l2tp_session_register(struct l2tp_session *session,
462463
err = l2tp_session_collision_add(pn, session,
463464
other_session);
464465
}
465-
spin_unlock_bh(&pn->l2tp_session_idr_lock);
466466
} else {
467467
session_key = l2tp_v2_session_key(tunnel->tunnel_id,
468468
session->session_id);
469-
spin_lock_bh(&pn->l2tp_session_idr_lock);
470469
err = idr_alloc_u32(&pn->l2tp_v2_session_idr, NULL,
471470
&session_key, session_key, GFP_ATOMIC);
472-
spin_unlock_bh(&pn->l2tp_session_idr_lock);
473471
}
474472

475473
if (err) {
476474
if (err == -ENOSPC)
477475
err = -EEXIST;
478-
goto err_tlock;
476+
goto out;
479477
}
480478

481479
l2tp_tunnel_inc_refcount(tunnel);
482-
483480
list_add(&session->list, &tunnel->session_list);
484-
spin_unlock_bh(&tunnel->list_lock);
485481

486-
spin_lock_bh(&pn->l2tp_session_idr_lock);
487482
if (tunnel->version == L2TP_HDR_VER_3) {
488483
if (!other_session)
489484
idr_replace(&pn->l2tp_v3_session_idr, session, session_key);
490485
} else {
491486
idr_replace(&pn->l2tp_v2_session_idr, session, session_key);
492487
}
493-
spin_unlock_bh(&pn->l2tp_session_idr_lock);
494-
495-
trace_register_session(session);
496488

497-
return 0;
498-
499-
err_tlock:
489+
out:
490+
spin_unlock_bh(&pn->l2tp_session_idr_lock);
500491
spin_unlock_bh(&tunnel->list_lock);
501492

493+
if (!err)
494+
trace_register_session(session);
495+
502496
return err;
503497
}
504498
EXPORT_SYMBOL_GPL(l2tp_session_register);
@@ -1260,13 +1254,13 @@ static void l2tp_session_unhash(struct l2tp_session *session)
12601254
struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
12611255
struct l2tp_session *removed = session;
12621256

1263-
/* Remove from the per-tunnel list */
12641257
spin_lock_bh(&tunnel->list_lock);
1258+
spin_lock_bh(&pn->l2tp_session_idr_lock);
1259+
1260+
/* Remove from the per-tunnel list */
12651261
list_del_init(&session->list);
1266-
spin_unlock_bh(&tunnel->list_lock);
12671262

12681263
/* Remove from per-net IDR */
1269-
spin_lock_bh(&pn->l2tp_session_idr_lock);
12701264
if (tunnel->version == L2TP_HDR_VER_3) {
12711265
if (hash_hashed(&session->hlist))
12721266
l2tp_session_collision_del(pn, session);
@@ -1280,7 +1274,9 @@ static void l2tp_session_unhash(struct l2tp_session *session)
12801274
session_key);
12811275
}
12821276
WARN_ON_ONCE(removed && removed != session);
1277+
12831278
spin_unlock_bh(&pn->l2tp_session_idr_lock);
1279+
spin_unlock_bh(&tunnel->list_lock);
12841280

12851281
synchronize_rcu();
12861282
}

0 commit comments

Comments
 (0)