summaryrefslogtreecommitdiff
path: root/net/l2tp
diff options
context:
space:
mode:
authorJakub Sitnicki <jakub@cloudflare.com>2022-11-14 22:16:19 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2023-02-01 10:23:12 +0300
commite34a965f771f1977f172593c73e373036c765724 (patch)
treeafee9a20bc092ca9b9901ecc1cf032870a1c02f4 /net/l2tp
parentc60fe70078d6e515f424cb868d07e00411b27fbc (diff)
downloadlinux-e34a965f771f1977f172593c73e373036c765724.tar.xz
l2tp: Serialize access to sk_user_data with sk_callback_lock
[ Upstream commit b68777d54fac21fc833ec26ea1a2a84f975ab035 ] sk->sk_user_data has multiple users, which are not compatible with each other. Writers must synchronize by grabbing the sk->sk_callback_lock. l2tp currently fails to grab the lock when modifying the underlying tunnel socket fields. Fix it by adding appropriate locking. We err on the side of safety and grab the sk_callback_lock also inside the sk_destruct callback overridden by l2tp, even though there should be no refs allowing access to the sock at the time when sk_destruct gets called. v4: - serialize write to sk_user_data in l2tp sk_destruct v3: - switch from sock lock to sk_callback_lock - document write-protection for sk_user_data v2: - update Fixes to point to origin of the bug - use real names in Reported/Tested-by tags Cc: Tom Parkin <tparkin@katalix.com> Fixes: 3557baabf280 ("[L2TP]: PPP over L2TP driver core") Reported-by: Haowei Yan <g1042620637@gmail.com> Signed-off-by: Jakub Sitnicki <jakub@cloudflare.com> Signed-off-by: David S. Miller <davem@davemloft.net> Stable-dep-of: 0b2c59720e65 ("l2tp: close all race conditions in l2tp_tunnel_register()") Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'net/l2tp')
-rw-r--r--net/l2tp/l2tp_core.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index dc8987ed08ad..e89852bc5309 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1150,8 +1150,10 @@ static void l2tp_tunnel_destruct(struct sock *sk)
}
/* Remove hooks into tunnel socket */
+ write_lock_bh(&sk->sk_callback_lock);
sk->sk_destruct = tunnel->old_sk_destruct;
sk->sk_user_data = NULL;
+ write_unlock_bh(&sk->sk_callback_lock);
/* Call the original destructor */
if (sk->sk_destruct)
@@ -1471,16 +1473,18 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
sock = sockfd_lookup(tunnel->fd, &ret);
if (!sock)
goto err;
-
- ret = l2tp_validate_socket(sock->sk, net, tunnel->encap);
- if (ret < 0)
- goto err_sock;
}
+ sk = sock->sk;
+ write_lock(&sk->sk_callback_lock);
+
+ ret = l2tp_validate_socket(sk, net, tunnel->encap);
+ if (ret < 0)
+ goto err_sock;
+
tunnel->l2tp_net = net;
pn = l2tp_pernet(net);
- sk = sock->sk;
sock_hold(sk);
tunnel->sock = sk;
@@ -1506,7 +1510,7 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
setup_udp_tunnel_sock(net, sock, &udp_cfg);
} else {
- sk->sk_user_data = tunnel;
+ rcu_assign_sk_user_data(sk, tunnel);
}
tunnel->old_sk_destruct = sk->sk_destruct;
@@ -1520,6 +1524,7 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
if (tunnel->fd >= 0)
sockfd_put(sock);
+ write_unlock(&sk->sk_callback_lock);
return 0;
err_sock:
@@ -1527,6 +1532,8 @@ err_sock:
sock_release(sock);
else
sockfd_put(sock);
+
+ write_unlock(&sk->sk_callback_lock);
err:
return ret;
}