Skip to content

Commit b68777d

Browse files
jsitnickidavem330
authored andcommitted
l2tp: Serialize access to sk_user_data with sk_callback_lock
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]>
1 parent f524b72 commit b68777d

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 sk_filter;
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)
@@ -1469,16 +1471,18 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
14691471
sock = sockfd_lookup(tunnel->fd, &ret);
14701472
if (!sock)
14711473
goto err;
1472-
1473-
ret = l2tp_validate_socket(sock->sk, net, tunnel->encap);
1474-
if (ret < 0)
1475-
goto err_sock;
14761474
}
14771475

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

1481-
sk = sock->sk;
14821486
sock_hold(sk);
14831487
tunnel->sock = sk;
14841488

@@ -1504,7 +1508,7 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
15041508

15051509
setup_udp_tunnel_sock(net, sock, &udp_cfg);
15061510
} else {
1507-
sk->sk_user_data = tunnel;
1511+
rcu_assign_sk_user_data(sk, tunnel);
15081512
}
15091513

15101514
tunnel->old_sk_destruct = sk->sk_destruct;
@@ -1518,13 +1522,16 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
15181522
if (tunnel->fd >= 0)
15191523
sockfd_put(sock);
15201524

1525+
write_unlock(&sk->sk_callback_lock);
15211526
return 0;
15221527

15231528
err_sock:
15241529
if (tunnel->fd < 0)
15251530
sock_release(sock);
15261531
else
15271532
sockfd_put(sock);
1533+
1534+
write_unlock(&sk->sk_callback_lock);
15281535
err:
15291536
return ret;
15301537
}

0 commit comments

Comments
 (0)