[PATCH net] pppoe: delete session hash entries by pointer match
flat view
WARM1d
LANDED
From: Qingfang Deng <hidden>
Date: 2026-10-20 09:21:29
Also in:
lkml, stable
Subsystem:
networking drivers, ppp over ethernet, the rest · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
Landed in mainline as b5b8c81836e2 on 2026-10-22.
pppoe_connect() copies the requested PPPoE address to a socket before
attempting to insert the socket into the session hash table. If the
tuple already exists, __set_item() returns -EALREADY, but the copied
address and ifindex remain set on the failed socket.
Closing that socket then deletes the existing socket's hash entry
through pppoe_release(), preventing it from receiving further session
traffic. An unprivileged process in the same network namespace can
trigger this through a duplicate connection attempt.
To avoid the accidental delete, pass the pppox_sock to __delete_item(),
and unlink only an entry whose pointer matches the requested socket.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Qingfang Deng <redacted>
---
drivers/net/ppp/pppoe.c | 22 ++++++++--------------
1 file changed, 8 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index bf7414b46a26..ee0e318d6a2a 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c@@ -194,18 +194,16 @@ static int __set_item(struct pppoe_net *pn, struct pppox_sock *po) return 0; } -static void __delete_item(struct pppoe_net *pn, __be16 sid, - char *addr, int ifindex) +static void __delete_item(struct pppoe_net *pn, const struct pppox_sock *po) { - int hash = hash_item(sid, addr); + int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote); struct pppox_sock *ret, __rcu **src; ret = rcu_dereference_protected(pn->hash_table[hash], lockdep_is_held(&pn->hash_lock)); src = &pn->hash_table[hash]; while (ret) { - if (cmp_addr(&ret->pppoe_pa, sid, addr) && - ret->pppoe_ifindex == ifindex) { + if (ret == po) { struct pppox_sock *next; next = rcu_dereference_protected(ret->next,
@@ -236,11 +234,10 @@ static inline struct pppox_sock *get_item(struct pppoe_net *pn, __be16 sid, return po; } -static inline void delete_item(struct pppoe_net *pn, __be16 sid, - char *addr, int ifindex) +static void delete_item(struct pppoe_net *pn, const struct pppox_sock *po) { spin_lock(&pn->hash_lock); - __delete_item(pn, sid, addr, ifindex); + __delete_item(pn, po); spin_unlock(&pn->hash_lock); }
@@ -570,8 +567,7 @@ static int pppoe_release(struct socket *sock) * protect "po" from concurrent updates * on pppoe_flush_dev */ - delete_item(pn, po->pppoe_pa.sid, po->pppoe_pa.remote, - po->pppoe_ifindex); + delete_item(pn, po); sock_orphan(sk); sock->sk = NULL;
@@ -621,8 +617,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr_unsized *uservaddr if (stage_session(po->pppoe_pa.sid)) { pppox_unbind_sock(sk); pn = pppoe_pernet(sock_net(sk)); - delete_item(pn, po->pppoe_pa.sid, - po->pppoe_pa.remote, po->pppoe_ifindex); + delete_item(pn, po); if (po->pppoe_dev) { dev_put(po->pppoe_dev); po->pppoe_dev = NULL;
@@ -672,8 +667,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr_unsized *uservaddr error = ppp_register_net_channel(dev_net(dev), &po->chan); if (error) { - delete_item(pn, po->pppoe_pa.sid, - po->pppoe_pa.remote, po->pppoe_ifindex); + delete_item(pn, po); goto err_put; }
--
2.43.0