xref: /linux/drivers/net/ovpn/socket.c (revision 2c7e4a2663a1ab5a740c59c31991579b6b865a26)
1f6226ae7SAntonio Quartulli // SPDX-License-Identifier: GPL-2.0
2f6226ae7SAntonio Quartulli /*  OpenVPN data channel offload
3f6226ae7SAntonio Quartulli  *
4f6226ae7SAntonio Quartulli  *  Copyright (C) 2020-2025 OpenVPN, Inc.
5f6226ae7SAntonio Quartulli  *
6f6226ae7SAntonio Quartulli  *  Author:	James Yonan <james@openvpn.net>
7f6226ae7SAntonio Quartulli  *		Antonio Quartulli <antonio@openvpn.net>
8f6226ae7SAntonio Quartulli  */
9f6226ae7SAntonio Quartulli 
10f6226ae7SAntonio Quartulli #include <linux/net.h>
11f6226ae7SAntonio Quartulli #include <linux/netdevice.h>
12f6226ae7SAntonio Quartulli #include <linux/udp.h>
13f6226ae7SAntonio Quartulli 
14f6226ae7SAntonio Quartulli #include "ovpnpriv.h"
15f6226ae7SAntonio Quartulli #include "main.h"
16f6226ae7SAntonio Quartulli #include "io.h"
17f6226ae7SAntonio Quartulli #include "peer.h"
18f6226ae7SAntonio Quartulli #include "socket.h"
1911851cbdSAntonio Quartulli #include "tcp.h"
20f6226ae7SAntonio Quartulli #include "udp.h"
21f6226ae7SAntonio Quartulli 
ovpn_socket_release_kref(struct kref * kref)22f6226ae7SAntonio Quartulli static void ovpn_socket_release_kref(struct kref *kref)
23f6226ae7SAntonio Quartulli {
24f6226ae7SAntonio Quartulli 	struct ovpn_socket *sock = container_of(kref, struct ovpn_socket,
25f6226ae7SAntonio Quartulli 						refcount);
26f6226ae7SAntonio Quartulli 
27*ba499a07SAntonio Quartulli 	if (sock->sk->sk_protocol == IPPROTO_UDP)
28f6226ae7SAntonio Quartulli 		ovpn_udp_socket_detach(sock);
29*ba499a07SAntonio Quartulli 	else if (sock->sk->sk_protocol == IPPROTO_TCP)
3011851cbdSAntonio Quartulli 		ovpn_tcp_socket_detach(sock);
31f6226ae7SAntonio Quartulli }
32f6226ae7SAntonio Quartulli 
33f6226ae7SAntonio Quartulli /**
34f6226ae7SAntonio Quartulli  * ovpn_socket_put - decrease reference counter
35f6226ae7SAntonio Quartulli  * @peer: peer whose socket reference counter should be decreased
36f6226ae7SAntonio Quartulli  * @sock: the RCU protected peer socket
37f6226ae7SAntonio Quartulli  *
38f6226ae7SAntonio Quartulli  * This function is only used internally. Users willing to release
39f6226ae7SAntonio Quartulli  * references to the ovpn_socket should use ovpn_socket_release()
4011851cbdSAntonio Quartulli  *
4111851cbdSAntonio Quartulli  * Return: true if the socket was released, false otherwise
42f6226ae7SAntonio Quartulli  */
ovpn_socket_put(struct ovpn_peer * peer,struct ovpn_socket * sock)4311851cbdSAntonio Quartulli static bool ovpn_socket_put(struct ovpn_peer *peer, struct ovpn_socket *sock)
44f6226ae7SAntonio Quartulli {
4511851cbdSAntonio Quartulli 	return kref_put(&sock->refcount, ovpn_socket_release_kref);
46f6226ae7SAntonio Quartulli }
47f6226ae7SAntonio Quartulli 
48f6226ae7SAntonio Quartulli /**
49f6226ae7SAntonio Quartulli  * ovpn_socket_release - release resources owned by socket user
50f6226ae7SAntonio Quartulli  * @peer: peer whose socket should be released
51f6226ae7SAntonio Quartulli  *
521d36a36fSAntonio Quartulli  * This function should be invoked when the peer is being removed
531d36a36fSAntonio Quartulli  * and wants to drop its link to the socket.
54f6226ae7SAntonio Quartulli  *
55f6226ae7SAntonio Quartulli  * In case of UDP, the detach routine will drop a reference to the
56f6226ae7SAntonio Quartulli  * ovpn netdev, pointed by the ovpn_socket.
57f6226ae7SAntonio Quartulli  *
58f6226ae7SAntonio Quartulli  * In case of TCP, releasing the socket will cause dropping
59f6226ae7SAntonio Quartulli  * the refcounter for the peer it is linked to, thus allowing the peer
60f6226ae7SAntonio Quartulli  * disappear as well.
61f6226ae7SAntonio Quartulli  *
62f6226ae7SAntonio Quartulli  * This function is expected to be invoked exactly once per peer
63f6226ae7SAntonio Quartulli  *
64f6226ae7SAntonio Quartulli  * NOTE: this function may sleep
65f6226ae7SAntonio Quartulli  */
ovpn_socket_release(struct ovpn_peer * peer)66f6226ae7SAntonio Quartulli void ovpn_socket_release(struct ovpn_peer *peer)
67f6226ae7SAntonio Quartulli {
68f6226ae7SAntonio Quartulli 	struct ovpn_socket *sock;
6911851cbdSAntonio Quartulli 	bool released;
70f6226ae7SAntonio Quartulli 
71f6226ae7SAntonio Quartulli 	might_sleep();
72f6226ae7SAntonio Quartulli 
73f6226ae7SAntonio Quartulli 	sock = rcu_replace_pointer(peer->sock, NULL, true);
74f6226ae7SAntonio Quartulli 	/* release may be invoked after socket was detached */
75f6226ae7SAntonio Quartulli 	if (!sock)
76f6226ae7SAntonio Quartulli 		return;
77f6226ae7SAntonio Quartulli 
78f6226ae7SAntonio Quartulli 	/* Drop the reference while holding the sock lock to avoid
79f6226ae7SAntonio Quartulli 	 * concurrent ovpn_socket_new call to mess up with a partially
80f6226ae7SAntonio Quartulli 	 * detached socket.
81f6226ae7SAntonio Quartulli 	 *
82f6226ae7SAntonio Quartulli 	 * Holding the lock ensures that a socket with refcnt 0 is fully
83f6226ae7SAntonio Quartulli 	 * detached before it can be picked by a concurrent reader.
84f6226ae7SAntonio Quartulli 	 */
85*ba499a07SAntonio Quartulli 	lock_sock(sock->sk);
8611851cbdSAntonio Quartulli 	released = ovpn_socket_put(peer, sock);
87*ba499a07SAntonio Quartulli 	release_sock(sock->sk);
88f6226ae7SAntonio Quartulli 
89f6226ae7SAntonio Quartulli 	/* align all readers with sk_user_data being NULL */
90f6226ae7SAntonio Quartulli 	synchronize_rcu();
9111851cbdSAntonio Quartulli 
9211851cbdSAntonio Quartulli 	/* following cleanup should happen with lock released */
9311851cbdSAntonio Quartulli 	if (released) {
94*ba499a07SAntonio Quartulli 		if (sock->sk->sk_protocol == IPPROTO_UDP) {
9511851cbdSAntonio Quartulli 			netdev_put(sock->ovpn->dev, &sock->dev_tracker);
96*ba499a07SAntonio Quartulli 		} else if (sock->sk->sk_protocol == IPPROTO_TCP) {
9711851cbdSAntonio Quartulli 			/* wait for TCP jobs to terminate */
9811851cbdSAntonio Quartulli 			ovpn_tcp_socket_wait_finish(sock);
9911851cbdSAntonio Quartulli 			ovpn_peer_put(sock->peer);
10011851cbdSAntonio Quartulli 		}
101*ba499a07SAntonio Quartulli 		/* drop reference acquired in ovpn_socket_new() */
102*ba499a07SAntonio Quartulli 		sock_put(sock->sk);
10311851cbdSAntonio Quartulli 		/* we can call plain kfree() because we already waited one RCU
10411851cbdSAntonio Quartulli 		 * period due to synchronize_rcu()
10511851cbdSAntonio Quartulli 		 */
10611851cbdSAntonio Quartulli 		kfree(sock);
10711851cbdSAntonio Quartulli 	}
108f6226ae7SAntonio Quartulli }
109f6226ae7SAntonio Quartulli 
ovpn_socket_hold(struct ovpn_socket * sock)110f6226ae7SAntonio Quartulli static bool ovpn_socket_hold(struct ovpn_socket *sock)
111f6226ae7SAntonio Quartulli {
112f6226ae7SAntonio Quartulli 	return kref_get_unless_zero(&sock->refcount);
113f6226ae7SAntonio Quartulli }
114f6226ae7SAntonio Quartulli 
ovpn_socket_attach(struct ovpn_socket * ovpn_sock,struct socket * sock,struct ovpn_peer * peer)115*ba499a07SAntonio Quartulli static int ovpn_socket_attach(struct ovpn_socket *ovpn_sock,
116*ba499a07SAntonio Quartulli 			      struct socket *sock,
117*ba499a07SAntonio Quartulli 			      struct ovpn_peer *peer)
118f6226ae7SAntonio Quartulli {
119*ba499a07SAntonio Quartulli 	if (sock->sk->sk_protocol == IPPROTO_UDP)
120*ba499a07SAntonio Quartulli 		return ovpn_udp_socket_attach(ovpn_sock, sock, peer->ovpn);
121*ba499a07SAntonio Quartulli 	else if (sock->sk->sk_protocol == IPPROTO_TCP)
122*ba499a07SAntonio Quartulli 		return ovpn_tcp_socket_attach(ovpn_sock, peer);
123f6226ae7SAntonio Quartulli 
124f6226ae7SAntonio Quartulli 	return -EOPNOTSUPP;
125f6226ae7SAntonio Quartulli }
126f6226ae7SAntonio Quartulli 
127f6226ae7SAntonio Quartulli /**
128f6226ae7SAntonio Quartulli  * ovpn_socket_new - create a new socket and initialize it
129f6226ae7SAntonio Quartulli  * @sock: the kernel socket to embed
130f6226ae7SAntonio Quartulli  * @peer: the peer reachable via this socket
131f6226ae7SAntonio Quartulli  *
132f6226ae7SAntonio Quartulli  * Return: an openvpn socket on success or a negative error code otherwise
133f6226ae7SAntonio Quartulli  */
ovpn_socket_new(struct socket * sock,struct ovpn_peer * peer)134f6226ae7SAntonio Quartulli struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
135f6226ae7SAntonio Quartulli {
136f6226ae7SAntonio Quartulli 	struct ovpn_socket *ovpn_sock;
137*ba499a07SAntonio Quartulli 	struct sock *sk = sock->sk;
138f6226ae7SAntonio Quartulli 	int ret;
139f6226ae7SAntonio Quartulli 
140*ba499a07SAntonio Quartulli 	lock_sock(sk);
141f6226ae7SAntonio Quartulli 
142f6226ae7SAntonio Quartulli 	/* a TCP socket can only be owned by a single peer, therefore there
143f6226ae7SAntonio Quartulli 	 * can't be any other user
144f6226ae7SAntonio Quartulli 	 */
145*ba499a07SAntonio Quartulli 	if (sk->sk_protocol == IPPROTO_TCP && sk->sk_user_data) {
146f6226ae7SAntonio Quartulli 		ovpn_sock = ERR_PTR(-EBUSY);
147f6226ae7SAntonio Quartulli 		goto sock_release;
148f6226ae7SAntonio Quartulli 	}
149f6226ae7SAntonio Quartulli 
150f6226ae7SAntonio Quartulli 	/* a UDP socket can be shared across multiple peers, but we must make
151f6226ae7SAntonio Quartulli 	 * sure it is not owned by something else
152f6226ae7SAntonio Quartulli 	 */
153*ba499a07SAntonio Quartulli 	if (sk->sk_protocol == IPPROTO_UDP) {
154*ba499a07SAntonio Quartulli 		u8 type = READ_ONCE(udp_sk(sk)->encap_type);
155f6226ae7SAntonio Quartulli 
156f6226ae7SAntonio Quartulli 		/* socket owned by other encapsulation module */
157f6226ae7SAntonio Quartulli 		if (type && type != UDP_ENCAP_OVPNINUDP) {
158f6226ae7SAntonio Quartulli 			ovpn_sock = ERR_PTR(-EBUSY);
159f6226ae7SAntonio Quartulli 			goto sock_release;
160f6226ae7SAntonio Quartulli 		}
161f6226ae7SAntonio Quartulli 
162f6226ae7SAntonio Quartulli 		rcu_read_lock();
163*ba499a07SAntonio Quartulli 		ovpn_sock = rcu_dereference_sk_user_data(sk);
164f6226ae7SAntonio Quartulli 		if (ovpn_sock) {
165f6226ae7SAntonio Quartulli 			/* socket owned by another ovpn instance, we can't use it */
166f6226ae7SAntonio Quartulli 			if (ovpn_sock->ovpn != peer->ovpn) {
167f6226ae7SAntonio Quartulli 				ovpn_sock = ERR_PTR(-EBUSY);
168f6226ae7SAntonio Quartulli 				rcu_read_unlock();
169f6226ae7SAntonio Quartulli 				goto sock_release;
170f6226ae7SAntonio Quartulli 			}
171f6226ae7SAntonio Quartulli 
172f6226ae7SAntonio Quartulli 			/* this socket is already owned by this instance,
173f6226ae7SAntonio Quartulli 			 * therefore we can increase the refcounter and
174f6226ae7SAntonio Quartulli 			 * use it as expected
175f6226ae7SAntonio Quartulli 			 */
176f6226ae7SAntonio Quartulli 			if (WARN_ON(!ovpn_socket_hold(ovpn_sock))) {
177f6226ae7SAntonio Quartulli 				/* this should never happen because setting
178f6226ae7SAntonio Quartulli 				 * the refcnt to 0 and detaching the socket
179f6226ae7SAntonio Quartulli 				 * is expected to be atomic
180f6226ae7SAntonio Quartulli 				 */
181f6226ae7SAntonio Quartulli 				ovpn_sock = ERR_PTR(-EAGAIN);
182f6226ae7SAntonio Quartulli 				rcu_read_unlock();
183f6226ae7SAntonio Quartulli 				goto sock_release;
184f6226ae7SAntonio Quartulli 			}
185f6226ae7SAntonio Quartulli 
186f6226ae7SAntonio Quartulli 			rcu_read_unlock();
187f6226ae7SAntonio Quartulli 			goto sock_release;
188f6226ae7SAntonio Quartulli 		}
189f6226ae7SAntonio Quartulli 		rcu_read_unlock();
190f6226ae7SAntonio Quartulli 	}
191f6226ae7SAntonio Quartulli 
192f6226ae7SAntonio Quartulli 	/* socket is not owned: attach to this ovpn instance */
193f6226ae7SAntonio Quartulli 
194f6226ae7SAntonio Quartulli 	ovpn_sock = kzalloc(sizeof(*ovpn_sock), GFP_KERNEL);
195f6226ae7SAntonio Quartulli 	if (!ovpn_sock) {
196f6226ae7SAntonio Quartulli 		ovpn_sock = ERR_PTR(-ENOMEM);
197f6226ae7SAntonio Quartulli 		goto sock_release;
198f6226ae7SAntonio Quartulli 	}
199f6226ae7SAntonio Quartulli 
200*ba499a07SAntonio Quartulli 	ovpn_sock->sk = sk;
201f6226ae7SAntonio Quartulli 	kref_init(&ovpn_sock->refcount);
202f6226ae7SAntonio Quartulli 
203*ba499a07SAntonio Quartulli 	/* the newly created ovpn_socket is holding reference to sk,
204*ba499a07SAntonio Quartulli 	 * therefore we increase its refcounter.
205*ba499a07SAntonio Quartulli 	 *
206*ba499a07SAntonio Quartulli 	 * This ovpn_socket instance is referenced by all peers
207*ba499a07SAntonio Quartulli 	 * using the same socket.
208*ba499a07SAntonio Quartulli 	 *
209*ba499a07SAntonio Quartulli 	 * ovpn_socket_release() will take care of dropping the reference.
210*ba499a07SAntonio Quartulli 	 */
211*ba499a07SAntonio Quartulli 	sock_hold(sk);
212*ba499a07SAntonio Quartulli 
213*ba499a07SAntonio Quartulli 	ret = ovpn_socket_attach(ovpn_sock, sock, peer);
214f6226ae7SAntonio Quartulli 	if (ret < 0) {
215*ba499a07SAntonio Quartulli 		sock_put(sk);
216f6226ae7SAntonio Quartulli 		kfree(ovpn_sock);
217f6226ae7SAntonio Quartulli 		ovpn_sock = ERR_PTR(ret);
218f6226ae7SAntonio Quartulli 		goto sock_release;
219f6226ae7SAntonio Quartulli 	}
220f6226ae7SAntonio Quartulli 
22111851cbdSAntonio Quartulli 	/* TCP sockets are per-peer, therefore they are linked to their unique
22211851cbdSAntonio Quartulli 	 * peer
22311851cbdSAntonio Quartulli 	 */
224*ba499a07SAntonio Quartulli 	if (sk->sk_protocol == IPPROTO_TCP) {
22511851cbdSAntonio Quartulli 		INIT_WORK(&ovpn_sock->tcp_tx_work, ovpn_tcp_tx_work);
22611851cbdSAntonio Quartulli 		ovpn_sock->peer = peer;
22711851cbdSAntonio Quartulli 		ovpn_peer_hold(peer);
228*ba499a07SAntonio Quartulli 	} else if (sk->sk_protocol == IPPROTO_UDP) {
229ab66abbcSAntonio Quartulli 		/* in UDP we only link the ovpn instance since the socket is
230ab66abbcSAntonio Quartulli 		 * shared among multiple peers
231ab66abbcSAntonio Quartulli 		 */
232ab66abbcSAntonio Quartulli 		ovpn_sock->ovpn = peer->ovpn;
233ab66abbcSAntonio Quartulli 		netdev_hold(peer->ovpn->dev, &ovpn_sock->dev_tracker,
234ab66abbcSAntonio Quartulli 			    GFP_KERNEL);
235ab66abbcSAntonio Quartulli 	}
236ab66abbcSAntonio Quartulli 
237*ba499a07SAntonio Quartulli 	rcu_assign_sk_user_data(sk, ovpn_sock);
238f6226ae7SAntonio Quartulli sock_release:
239*ba499a07SAntonio Quartulli 	release_sock(sk);
240f6226ae7SAntonio Quartulli 	return ovpn_sock;
241f6226ae7SAntonio Quartulli }
242