aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Chapman <[email protected]>2024-07-29 16:38:12 +0100
committerDavid S. Miller <[email protected]>2024-07-31 09:25:13 +0100
commit0aa45570c3241e3bdba1a8b5b30d200c819b5b15 (patch)
treedb23f65675c903124d1b935c7766b751b3c164e9
parent89b768ec2dfefaeba5212de14fc71368e12d06ba (diff)
l2tp: add idr consistency check in session_register
l2tp_session_register uses an idr_alloc then idr_replace pattern to insert sessions into the session IDR. To catch invalid locking, add a WARN_ON_ONCE if the IDR entry is modified by another thread between alloc and replace steps. Also add comments to make expectations clear. Signed-off-by: James Chapman <[email protected]> Signed-off-by: Tom Parkin <[email protected]> Signed-off-by: David S. Miller <[email protected]>
-rw-r--r--net/l2tp/l2tp_core.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index cd9b157e8b4d..fd03c17dd20c 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -474,6 +474,7 @@ int l2tp_session_register(struct l2tp_session *session,
{
struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
struct l2tp_session *other_session = NULL;
+ void *old = NULL;
u32 session_key;
int err;
@@ -517,13 +518,19 @@ int l2tp_session_register(struct l2tp_session *session,
WRITE_ONCE(session->tunnel, tunnel);
list_add_rcu(&session->list, &tunnel->session_list);
+ /* this makes session available to lockless getters */
if (tunnel->version == L2TP_HDR_VER_3) {
if (!other_session)
- idr_replace(&pn->l2tp_v3_session_idr, session, session_key);
+ old = idr_replace(&pn->l2tp_v3_session_idr, session, session_key);
} else {
- idr_replace(&pn->l2tp_v2_session_idr, session, session_key);
+ old = idr_replace(&pn->l2tp_v2_session_idr, session, session_key);
}
+ /* old should be NULL, unless something removed or modified
+ * the IDR entry after our idr_alloc_32 above (which shouldn't
+ * happen).
+ */
+ WARN_ON_ONCE(old);
out:
spin_unlock_bh(&pn->l2tp_session_idr_lock);
spin_unlock_bh(&tunnel->list_lock);