Skip to content

Commit 87d9205

Browse files
jsitnickigregkh
authored andcommitted
l2tp: Serialize access to sk_user_data with sk_callback_lock
[ Upstream commit b68777d ] 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 <[email protected]> Fixes: 3557baa ("[L2TP]: PPP over L2TP driver core") Reported-by: Haowei Yan <[email protected]> Signed-off-by: Jakub Sitnicki <[email protected]> Signed-off-by: David S. Miller <[email protected]> Stable-dep-of: 0b2c597 ("l2tp: close all race conditions in l2tp_tunnel_register()") Signed-off-by: Sasha Levin <[email protected]>
1 parent c53acbf commit 87d9205

File tree

2 files changed

+14
-7
lines changed

2 files changed

+14
-7
lines changed

include/net/sock.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ struct bpf_local_storage;
323323
* @sk_tskey: counter to disambiguate concurrent tstamp requests
324324
* @sk_zckey: counter to order MSG_ZEROCOPY notifications
325325
* @sk_socket: Identd and reporting IO signals
326-
* @sk_user_data: RPC layer private data
326+
* @sk_user_data: RPC layer private data. Write-protected by @sk_callback_lock.
327327
* @sk_frag: cached page frag
328328
* @sk_peek_off: current peek_offset value
329329
* @sk_send_head: front of stuff to transmit

net/l2tp/l2tp_core.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,8 +1150,10 @@ static void l2tp_tunnel_destruct(struct sock *sk)
11501150
}
11511151

11521152
/* Remove hooks into tunnel socket */
1153+
write_lock_bh(&sk->sk_callback_lock);
11531154
sk->sk_destruct = tunnel->old_sk_destruct;
11541155
sk->sk_user_data = NULL;
1156+
write_unlock_bh(&sk->sk_callback_lock);
11551157

11561158
/* Call the original destructor */
11571159
if (sk->sk_destruct)
@@ -1471,16 +1473,18 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
14711473
sock = sockfd_lookup(tunnel->fd, &ret);
14721474
if (!sock)
14731475
goto err;
1474-
1475-
ret = l2tp_validate_socket(sock->sk, net, tunnel->encap);
1476-
if (ret < 0)
1477-
goto err_sock;
14781476
}
14791477

1478+
sk = sock->sk;
1479+
write_lock(&sk->sk_callback_lock);
1480+
1481+
ret = l2tp_validate_socket(sk, net, tunnel->encap);
1482+
if (ret < 0)
1483+
goto err_sock;
1484+
14801485
tunnel->l2tp_net = net;
14811486
pn = l2tp_pernet(net);
14821487

1483-
sk = sock->sk;
14841488
sock_hold(sk);
14851489
tunnel->sock = sk;
14861490

@@ -1506,7 +1510,7 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
15061510

15071511
setup_udp_tunnel_sock(net, sock, &udp_cfg);
15081512
} else {
1509-
sk->sk_user_data = tunnel;
1513+
rcu_assign_sk_user_data(sk, tunnel);
15101514
}
15111515

15121516
tunnel->old_sk_destruct = sk->sk_destruct;
@@ -1520,13 +1524,16 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
15201524
if (tunnel->fd >= 0)
15211525
sockfd_put(sock);
15221526

1527+
write_unlock(&sk->sk_callback_lock);
15231528
return 0;
15241529

15251530
err_sock:
15261531
if (tunnel->fd < 0)
15271532
sock_release(sock);
15281533
else
15291534
sockfd_put(sock);
1535+
1536+
write_unlock(&sk->sk_callback_lock);
15301537
err:
15311538
return ret;
15321539
}

0 commit comments

Comments
 (0)