mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 02:53:36 +02:00
This bugfix batch includes the following changes:
* dropped bogus call to setup_udp_tunnel_sock() during cleanup, substituted by proper state unwind * fixed race condition between peer removal (by kernel space) and socket closing (by user space) * fixed sleep in atomic context along TCP RX error path * fixes for ovpn kselftests -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEmavcbPjUEuTeX8D8C3DlOqA41YcFAmg+17IACgkQC3DlOqA4 1YfGnQf7BCqweJAqPZs45DrMO/zu0mygbvzxI5x1VnBSQvtUfEEwgY3Mk9Y/8OxW +QxD9yYl8sf30ZzGTFFYtBq0XwvcP0Nlo4WFD7+2ufvFgojIAwCsF25of+hODGLZ 5KF83VYDAMvUmK7Rq4gGyi/HC7+rWNhShfoXBh6nfQjNa75NWwIwp8wEsTMovq2Y DiH6VzCjkUgnRjJYG5g/D6n0pHnbUkrAPi3AT+aB8PX9sikrTZhBWX4mmY8n6Xlo KT83ByzJqc5svnbsQEGRuhXbyuKipBhcVmOohmulBB/uhXUZHDcem9L0wp1hR2SB y/lZQxt9bNdEXfh0J7r5QxI2vkZgZQ== =Y6+P -----END PGP SIGNATURE----- Merge tag 'ovpn-net-20250603' of https://github.com/OpenVPN/ovpn-net-next Antonio Quartulli says: ==================== In this batch you can find the following bug fixes: Patch 1: when releasing a UDP socket we were wrongly invoking setup_udp_tunnel_sock() with an empty config. This was not properly shutting down the UDP encap state. With this patch we simply undo what was done during setup. Patch 2: ovpn was holding a reference to a 'struct socket' without increasing its reference counter. This was intended and worked as expected until we hit a race condition where user space tries to close the socket while kernel space is also releasing it. In this case the (struct socket *)->sk member would disappear under our feet leading to a null-ptr-deref. This patch fixes this issue by having struct ovpn_socket hold a reference directly to the sk member while also increasing its reference counter. Patch 3: in case of errors along the TCP RX path (softirq) we want to immediately delete the peer, but this operation may sleep. With this patch we move the peer deletion to a scheduled worker. Patch 4 and 5 are instead fixing minor issues in the ovpn kselftests. * tag 'ovpn-net-20250603' of https://github.com/OpenVPN/ovpn-net-next: selftest/net/ovpn: fix missing file selftest/net/ovpn: fix TCP socket creation ovpn: avoid sleep in atomic context in TCP RX error path ovpn: ensure sk is still valid during cleanup ovpn: properly deconfigure UDP-tunnel ==================== Link: https://patch.msgid.link/20250603111110.4575-1-antonio@openvpn.net/ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
ec6a328b2e
|
|
@ -134,7 +134,7 @@ void ovpn_decrypt_post(void *data, int ret)
|
|||
|
||||
rcu_read_lock();
|
||||
sock = rcu_dereference(peer->sock);
|
||||
if (sock && sock->sock->sk->sk_protocol == IPPROTO_UDP)
|
||||
if (sock && sock->sk->sk_protocol == IPPROTO_UDP)
|
||||
/* check if this peer changed local or remote endpoint */
|
||||
ovpn_peer_endpoints_update(peer, skb);
|
||||
rcu_read_unlock();
|
||||
|
|
@ -270,12 +270,12 @@ void ovpn_encrypt_post(void *data, int ret)
|
|||
if (unlikely(!sock))
|
||||
goto err_unlock;
|
||||
|
||||
switch (sock->sock->sk->sk_protocol) {
|
||||
switch (sock->sk->sk_protocol) {
|
||||
case IPPROTO_UDP:
|
||||
ovpn_udp_send_skb(peer, sock->sock, skb);
|
||||
ovpn_udp_send_skb(peer, sock->sk, skb);
|
||||
break;
|
||||
case IPPROTO_TCP:
|
||||
ovpn_tcp_send_skb(peer, sock->sock, skb);
|
||||
ovpn_tcp_send_skb(peer, sock->sk, skb);
|
||||
break;
|
||||
default:
|
||||
/* no transport configured yet */
|
||||
|
|
|
|||
|
|
@ -501,7 +501,7 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
|
|||
/* when using a TCP socket the remote IP is not expected */
|
||||
rcu_read_lock();
|
||||
sock = rcu_dereference(peer->sock);
|
||||
if (sock && sock->sock->sk->sk_protocol == IPPROTO_TCP &&
|
||||
if (sock && sock->sk->sk_protocol == IPPROTO_TCP &&
|
||||
(attrs[OVPN_A_PEER_REMOTE_IPV4] ||
|
||||
attrs[OVPN_A_PEER_REMOTE_IPV6])) {
|
||||
rcu_read_unlock();
|
||||
|
|
@ -559,14 +559,14 @@ static int ovpn_nl_send_peer(struct sk_buff *skb, const struct genl_info *info,
|
|||
goto err_unlock;
|
||||
}
|
||||
|
||||
if (!net_eq(genl_info_net(info), sock_net(sock->sock->sk))) {
|
||||
if (!net_eq(genl_info_net(info), sock_net(sock->sk))) {
|
||||
id = peernet2id_alloc(genl_info_net(info),
|
||||
sock_net(sock->sock->sk),
|
||||
sock_net(sock->sk),
|
||||
GFP_ATOMIC);
|
||||
if (nla_put_s32(skb, OVPN_A_PEER_SOCKET_NETNSID, id))
|
||||
goto err_unlock;
|
||||
}
|
||||
local_port = inet_sk(sock->sock->sk)->inet_sport;
|
||||
local_port = inet_sk(sock->sk)->inet_sport;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (nla_put_u32(skb, OVPN_A_PEER_ID, peer->id))
|
||||
|
|
@ -1153,8 +1153,8 @@ int ovpn_nl_peer_del_notify(struct ovpn_peer *peer)
|
|||
ret = -EINVAL;
|
||||
goto err_unlock;
|
||||
}
|
||||
genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sock->sk),
|
||||
msg, 0, OVPN_NLGRP_PEERS, GFP_ATOMIC);
|
||||
genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sk), msg, 0,
|
||||
OVPN_NLGRP_PEERS, GFP_ATOMIC);
|
||||
rcu_read_unlock();
|
||||
|
||||
return 0;
|
||||
|
|
@ -1218,8 +1218,8 @@ int ovpn_nl_key_swap_notify(struct ovpn_peer *peer, u8 key_id)
|
|||
ret = -EINVAL;
|
||||
goto err_unlock;
|
||||
}
|
||||
genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sock->sk),
|
||||
msg, 0, OVPN_NLGRP_PEERS, GFP_ATOMIC);
|
||||
genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sk), msg, 0,
|
||||
OVPN_NLGRP_PEERS, GFP_ATOMIC);
|
||||
rcu_read_unlock();
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1145,7 +1145,7 @@ static void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, struct sock *sk,
|
|||
|
||||
if (sk) {
|
||||
ovpn_sock = rcu_access_pointer(peer->sock);
|
||||
if (!ovpn_sock || ovpn_sock->sock->sk != sk) {
|
||||
if (!ovpn_sock || ovpn_sock->sk != sk) {
|
||||
spin_unlock_bh(&ovpn->lock);
|
||||
ovpn_peer_put(peer);
|
||||
return;
|
||||
|
|
@ -1175,7 +1175,7 @@ static void ovpn_peers_release_mp(struct ovpn_priv *ovpn, struct sock *sk,
|
|||
if (sk) {
|
||||
rcu_read_lock();
|
||||
ovpn_sock = rcu_dereference(peer->sock);
|
||||
remove = ovpn_sock && ovpn_sock->sock->sk == sk;
|
||||
remove = ovpn_sock && ovpn_sock->sk == sk;
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ static void ovpn_socket_release_kref(struct kref *kref)
|
|||
struct ovpn_socket *sock = container_of(kref, struct ovpn_socket,
|
||||
refcount);
|
||||
|
||||
if (sock->sock->sk->sk_protocol == IPPROTO_UDP)
|
||||
if (sock->sk->sk_protocol == IPPROTO_UDP)
|
||||
ovpn_udp_socket_detach(sock);
|
||||
else if (sock->sock->sk->sk_protocol == IPPROTO_TCP)
|
||||
else if (sock->sk->sk_protocol == IPPROTO_TCP)
|
||||
ovpn_tcp_socket_detach(sock);
|
||||
}
|
||||
|
||||
|
|
@ -75,14 +75,6 @@ void ovpn_socket_release(struct ovpn_peer *peer)
|
|||
if (!sock)
|
||||
return;
|
||||
|
||||
/* sanity check: we should not end up here if the socket
|
||||
* was already closed
|
||||
*/
|
||||
if (!sock->sock->sk) {
|
||||
DEBUG_NET_WARN_ON_ONCE(1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Drop the reference while holding the sock lock to avoid
|
||||
* concurrent ovpn_socket_new call to mess up with a partially
|
||||
* detached socket.
|
||||
|
|
@ -90,22 +82,24 @@ void ovpn_socket_release(struct ovpn_peer *peer)
|
|||
* Holding the lock ensures that a socket with refcnt 0 is fully
|
||||
* detached before it can be picked by a concurrent reader.
|
||||
*/
|
||||
lock_sock(sock->sock->sk);
|
||||
lock_sock(sock->sk);
|
||||
released = ovpn_socket_put(peer, sock);
|
||||
release_sock(sock->sock->sk);
|
||||
release_sock(sock->sk);
|
||||
|
||||
/* align all readers with sk_user_data being NULL */
|
||||
synchronize_rcu();
|
||||
|
||||
/* following cleanup should happen with lock released */
|
||||
if (released) {
|
||||
if (sock->sock->sk->sk_protocol == IPPROTO_UDP) {
|
||||
if (sock->sk->sk_protocol == IPPROTO_UDP) {
|
||||
netdev_put(sock->ovpn->dev, &sock->dev_tracker);
|
||||
} else if (sock->sock->sk->sk_protocol == IPPROTO_TCP) {
|
||||
} else if (sock->sk->sk_protocol == IPPROTO_TCP) {
|
||||
/* wait for TCP jobs to terminate */
|
||||
ovpn_tcp_socket_wait_finish(sock);
|
||||
ovpn_peer_put(sock->peer);
|
||||
}
|
||||
/* drop reference acquired in ovpn_socket_new() */
|
||||
sock_put(sock->sk);
|
||||
/* we can call plain kfree() because we already waited one RCU
|
||||
* period due to synchronize_rcu()
|
||||
*/
|
||||
|
|
@ -118,12 +112,14 @@ static bool ovpn_socket_hold(struct ovpn_socket *sock)
|
|||
return kref_get_unless_zero(&sock->refcount);
|
||||
}
|
||||
|
||||
static int ovpn_socket_attach(struct ovpn_socket *sock, struct ovpn_peer *peer)
|
||||
static int ovpn_socket_attach(struct ovpn_socket *ovpn_sock,
|
||||
struct socket *sock,
|
||||
struct ovpn_peer *peer)
|
||||
{
|
||||
if (sock->sock->sk->sk_protocol == IPPROTO_UDP)
|
||||
return ovpn_udp_socket_attach(sock, peer->ovpn);
|
||||
else if (sock->sock->sk->sk_protocol == IPPROTO_TCP)
|
||||
return ovpn_tcp_socket_attach(sock, peer);
|
||||
if (sock->sk->sk_protocol == IPPROTO_UDP)
|
||||
return ovpn_udp_socket_attach(ovpn_sock, sock, peer->ovpn);
|
||||
else if (sock->sk->sk_protocol == IPPROTO_TCP)
|
||||
return ovpn_tcp_socket_attach(ovpn_sock, peer);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
@ -138,14 +134,15 @@ static int ovpn_socket_attach(struct ovpn_socket *sock, struct ovpn_peer *peer)
|
|||
struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
|
||||
{
|
||||
struct ovpn_socket *ovpn_sock;
|
||||
struct sock *sk = sock->sk;
|
||||
int ret;
|
||||
|
||||
lock_sock(sock->sk);
|
||||
lock_sock(sk);
|
||||
|
||||
/* a TCP socket can only be owned by a single peer, therefore there
|
||||
* can't be any other user
|
||||
*/
|
||||
if (sock->sk->sk_protocol == IPPROTO_TCP && sock->sk->sk_user_data) {
|
||||
if (sk->sk_protocol == IPPROTO_TCP && sk->sk_user_data) {
|
||||
ovpn_sock = ERR_PTR(-EBUSY);
|
||||
goto sock_release;
|
||||
}
|
||||
|
|
@ -153,8 +150,8 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
|
|||
/* a UDP socket can be shared across multiple peers, but we must make
|
||||
* sure it is not owned by something else
|
||||
*/
|
||||
if (sock->sk->sk_protocol == IPPROTO_UDP) {
|
||||
u8 type = READ_ONCE(udp_sk(sock->sk)->encap_type);
|
||||
if (sk->sk_protocol == IPPROTO_UDP) {
|
||||
u8 type = READ_ONCE(udp_sk(sk)->encap_type);
|
||||
|
||||
/* socket owned by other encapsulation module */
|
||||
if (type && type != UDP_ENCAP_OVPNINUDP) {
|
||||
|
|
@ -163,7 +160,7 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
|
|||
}
|
||||
|
||||
rcu_read_lock();
|
||||
ovpn_sock = rcu_dereference_sk_user_data(sock->sk);
|
||||
ovpn_sock = rcu_dereference_sk_user_data(sk);
|
||||
if (ovpn_sock) {
|
||||
/* socket owned by another ovpn instance, we can't use it */
|
||||
if (ovpn_sock->ovpn != peer->ovpn) {
|
||||
|
|
@ -200,11 +197,22 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
|
|||
goto sock_release;
|
||||
}
|
||||
|
||||
ovpn_sock->sock = sock;
|
||||
ovpn_sock->sk = sk;
|
||||
kref_init(&ovpn_sock->refcount);
|
||||
|
||||
ret = ovpn_socket_attach(ovpn_sock, peer);
|
||||
/* the newly created ovpn_socket is holding reference to sk,
|
||||
* therefore we increase its refcounter.
|
||||
*
|
||||
* This ovpn_socket instance is referenced by all peers
|
||||
* using the same socket.
|
||||
*
|
||||
* ovpn_socket_release() will take care of dropping the reference.
|
||||
*/
|
||||
sock_hold(sk);
|
||||
|
||||
ret = ovpn_socket_attach(ovpn_sock, sock, peer);
|
||||
if (ret < 0) {
|
||||
sock_put(sk);
|
||||
kfree(ovpn_sock);
|
||||
ovpn_sock = ERR_PTR(ret);
|
||||
goto sock_release;
|
||||
|
|
@ -213,11 +221,11 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
|
|||
/* TCP sockets are per-peer, therefore they are linked to their unique
|
||||
* peer
|
||||
*/
|
||||
if (sock->sk->sk_protocol == IPPROTO_TCP) {
|
||||
if (sk->sk_protocol == IPPROTO_TCP) {
|
||||
INIT_WORK(&ovpn_sock->tcp_tx_work, ovpn_tcp_tx_work);
|
||||
ovpn_sock->peer = peer;
|
||||
ovpn_peer_hold(peer);
|
||||
} else if (sock->sk->sk_protocol == IPPROTO_UDP) {
|
||||
} else if (sk->sk_protocol == IPPROTO_UDP) {
|
||||
/* in UDP we only link the ovpn instance since the socket is
|
||||
* shared among multiple peers
|
||||
*/
|
||||
|
|
@ -226,8 +234,8 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
|
|||
GFP_KERNEL);
|
||||
}
|
||||
|
||||
rcu_assign_sk_user_data(sock->sk, ovpn_sock);
|
||||
rcu_assign_sk_user_data(sk, ovpn_sock);
|
||||
sock_release:
|
||||
release_sock(sock->sk);
|
||||
release_sock(sk);
|
||||
return ovpn_sock;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ struct ovpn_peer;
|
|||
* @ovpn: ovpn instance owning this socket (UDP only)
|
||||
* @dev_tracker: reference tracker for associated dev (UDP only)
|
||||
* @peer: unique peer transmitting over this socket (TCP only)
|
||||
* @sock: the low level sock object
|
||||
* @sk: the low level sock object
|
||||
* @refcount: amount of contexts currently referencing this object
|
||||
* @work: member used to schedule release routine (it may block)
|
||||
* @tcp_tx_work: work for deferring outgoing packet processing (TCP only)
|
||||
|
|
@ -36,7 +36,7 @@ struct ovpn_socket {
|
|||
struct ovpn_peer *peer;
|
||||
};
|
||||
|
||||
struct socket *sock;
|
||||
struct sock *sk;
|
||||
struct kref refcount;
|
||||
struct work_struct work;
|
||||
struct work_struct tcp_tx_work;
|
||||
|
|
|
|||
|
|
@ -124,14 +124,18 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb)
|
|||
* this peer, therefore ovpn_peer_hold() is not expected to fail
|
||||
*/
|
||||
if (WARN_ON(!ovpn_peer_hold(peer)))
|
||||
goto err;
|
||||
goto err_nopeer;
|
||||
|
||||
ovpn_recv(peer, skb);
|
||||
return;
|
||||
err:
|
||||
/* take reference for deferred peer deletion. should never fail */
|
||||
if (WARN_ON(!ovpn_peer_hold(peer)))
|
||||
goto err_nopeer;
|
||||
schedule_work(&peer->tcp.defer_del_work);
|
||||
dev_dstats_rx_dropped(peer->ovpn->dev);
|
||||
err_nopeer:
|
||||
kfree_skb(skb);
|
||||
ovpn_peer_del(peer, OVPN_DEL_PEER_REASON_TRANSPORT_ERROR);
|
||||
}
|
||||
|
||||
static int ovpn_tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
||||
|
|
@ -186,18 +190,18 @@ static int ovpn_tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
|||
void ovpn_tcp_socket_detach(struct ovpn_socket *ovpn_sock)
|
||||
{
|
||||
struct ovpn_peer *peer = ovpn_sock->peer;
|
||||
struct socket *sock = ovpn_sock->sock;
|
||||
struct sock *sk = ovpn_sock->sk;
|
||||
|
||||
strp_stop(&peer->tcp.strp);
|
||||
skb_queue_purge(&peer->tcp.user_queue);
|
||||
|
||||
/* restore CBs that were saved in ovpn_sock_set_tcp_cb() */
|
||||
sock->sk->sk_data_ready = peer->tcp.sk_cb.sk_data_ready;
|
||||
sock->sk->sk_write_space = peer->tcp.sk_cb.sk_write_space;
|
||||
sock->sk->sk_prot = peer->tcp.sk_cb.prot;
|
||||
sock->sk->sk_socket->ops = peer->tcp.sk_cb.ops;
|
||||
sk->sk_data_ready = peer->tcp.sk_cb.sk_data_ready;
|
||||
sk->sk_write_space = peer->tcp.sk_cb.sk_write_space;
|
||||
sk->sk_prot = peer->tcp.sk_cb.prot;
|
||||
sk->sk_socket->ops = peer->tcp.sk_cb.ops;
|
||||
|
||||
rcu_assign_sk_user_data(sock->sk, NULL);
|
||||
rcu_assign_sk_user_data(sk, NULL);
|
||||
}
|
||||
|
||||
void ovpn_tcp_socket_wait_finish(struct ovpn_socket *sock)
|
||||
|
|
@ -283,10 +287,10 @@ void ovpn_tcp_tx_work(struct work_struct *work)
|
|||
|
||||
sock = container_of(work, struct ovpn_socket, tcp_tx_work);
|
||||
|
||||
lock_sock(sock->sock->sk);
|
||||
lock_sock(sock->sk);
|
||||
if (sock->peer)
|
||||
ovpn_tcp_send_sock(sock->peer, sock->sock->sk);
|
||||
release_sock(sock->sock->sk);
|
||||
ovpn_tcp_send_sock(sock->peer, sock->sk);
|
||||
release_sock(sock->sk);
|
||||
}
|
||||
|
||||
static void ovpn_tcp_send_sock_skb(struct ovpn_peer *peer, struct sock *sk,
|
||||
|
|
@ -307,15 +311,15 @@ static void ovpn_tcp_send_sock_skb(struct ovpn_peer *peer, struct sock *sk,
|
|||
ovpn_tcp_send_sock(peer, sk);
|
||||
}
|
||||
|
||||
void ovpn_tcp_send_skb(struct ovpn_peer *peer, struct socket *sock,
|
||||
void ovpn_tcp_send_skb(struct ovpn_peer *peer, struct sock *sk,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
u16 len = skb->len;
|
||||
|
||||
*(__be16 *)__skb_push(skb, sizeof(u16)) = htons(len);
|
||||
|
||||
spin_lock_nested(&sock->sk->sk_lock.slock, OVPN_TCP_DEPTH_NESTING);
|
||||
if (sock_owned_by_user(sock->sk)) {
|
||||
spin_lock_nested(&sk->sk_lock.slock, OVPN_TCP_DEPTH_NESTING);
|
||||
if (sock_owned_by_user(sk)) {
|
||||
if (skb_queue_len(&peer->tcp.out_queue) >=
|
||||
READ_ONCE(net_hotdata.max_backlog)) {
|
||||
dev_dstats_tx_dropped(peer->ovpn->dev);
|
||||
|
|
@ -324,10 +328,10 @@ void ovpn_tcp_send_skb(struct ovpn_peer *peer, struct socket *sock,
|
|||
}
|
||||
__skb_queue_tail(&peer->tcp.out_queue, skb);
|
||||
} else {
|
||||
ovpn_tcp_send_sock_skb(peer, sock->sk, skb);
|
||||
ovpn_tcp_send_sock_skb(peer, sk, skb);
|
||||
}
|
||||
unlock:
|
||||
spin_unlock(&sock->sk->sk_lock.slock);
|
||||
spin_unlock(&sk->sk_lock.slock);
|
||||
}
|
||||
|
||||
static void ovpn_tcp_release(struct sock *sk)
|
||||
|
|
@ -474,7 +478,6 @@ static void ovpn_tcp_peer_del_work(struct work_struct *work)
|
|||
int ovpn_tcp_socket_attach(struct ovpn_socket *ovpn_sock,
|
||||
struct ovpn_peer *peer)
|
||||
{
|
||||
struct socket *sock = ovpn_sock->sock;
|
||||
struct strp_callbacks cb = {
|
||||
.rcv_msg = ovpn_tcp_rcv,
|
||||
.parse_msg = ovpn_tcp_parse,
|
||||
|
|
@ -482,20 +485,20 @@ int ovpn_tcp_socket_attach(struct ovpn_socket *ovpn_sock,
|
|||
int ret;
|
||||
|
||||
/* make sure no pre-existing encapsulation handler exists */
|
||||
if (sock->sk->sk_user_data)
|
||||
if (ovpn_sock->sk->sk_user_data)
|
||||
return -EBUSY;
|
||||
|
||||
/* only a fully connected socket is expected. Connection should be
|
||||
* handled in userspace
|
||||
*/
|
||||
if (sock->sk->sk_state != TCP_ESTABLISHED) {
|
||||
if (ovpn_sock->sk->sk_state != TCP_ESTABLISHED) {
|
||||
net_err_ratelimited("%s: provided TCP socket is not in ESTABLISHED state: %d\n",
|
||||
netdev_name(peer->ovpn->dev),
|
||||
sock->sk->sk_state);
|
||||
ovpn_sock->sk->sk_state);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = strp_init(&peer->tcp.strp, sock->sk, &cb);
|
||||
ret = strp_init(&peer->tcp.strp, ovpn_sock->sk, &cb);
|
||||
if (ret < 0) {
|
||||
DEBUG_NET_WARN_ON_ONCE(1);
|
||||
return ret;
|
||||
|
|
@ -503,31 +506,31 @@ int ovpn_tcp_socket_attach(struct ovpn_socket *ovpn_sock,
|
|||
|
||||
INIT_WORK(&peer->tcp.defer_del_work, ovpn_tcp_peer_del_work);
|
||||
|
||||
__sk_dst_reset(sock->sk);
|
||||
__sk_dst_reset(ovpn_sock->sk);
|
||||
skb_queue_head_init(&peer->tcp.user_queue);
|
||||
skb_queue_head_init(&peer->tcp.out_queue);
|
||||
|
||||
/* save current CBs so that they can be restored upon socket release */
|
||||
peer->tcp.sk_cb.sk_data_ready = sock->sk->sk_data_ready;
|
||||
peer->tcp.sk_cb.sk_write_space = sock->sk->sk_write_space;
|
||||
peer->tcp.sk_cb.prot = sock->sk->sk_prot;
|
||||
peer->tcp.sk_cb.ops = sock->sk->sk_socket->ops;
|
||||
peer->tcp.sk_cb.sk_data_ready = ovpn_sock->sk->sk_data_ready;
|
||||
peer->tcp.sk_cb.sk_write_space = ovpn_sock->sk->sk_write_space;
|
||||
peer->tcp.sk_cb.prot = ovpn_sock->sk->sk_prot;
|
||||
peer->tcp.sk_cb.ops = ovpn_sock->sk->sk_socket->ops;
|
||||
|
||||
/* assign our static CBs and prot/ops */
|
||||
sock->sk->sk_data_ready = ovpn_tcp_data_ready;
|
||||
sock->sk->sk_write_space = ovpn_tcp_write_space;
|
||||
ovpn_sock->sk->sk_data_ready = ovpn_tcp_data_ready;
|
||||
ovpn_sock->sk->sk_write_space = ovpn_tcp_write_space;
|
||||
|
||||
if (sock->sk->sk_family == AF_INET) {
|
||||
sock->sk->sk_prot = &ovpn_tcp_prot;
|
||||
sock->sk->sk_socket->ops = &ovpn_tcp_ops;
|
||||
if (ovpn_sock->sk->sk_family == AF_INET) {
|
||||
ovpn_sock->sk->sk_prot = &ovpn_tcp_prot;
|
||||
ovpn_sock->sk->sk_socket->ops = &ovpn_tcp_ops;
|
||||
} else {
|
||||
sock->sk->sk_prot = &ovpn_tcp6_prot;
|
||||
sock->sk->sk_socket->ops = &ovpn_tcp6_ops;
|
||||
ovpn_sock->sk->sk_prot = &ovpn_tcp6_prot;
|
||||
ovpn_sock->sk->sk_socket->ops = &ovpn_tcp6_ops;
|
||||
}
|
||||
|
||||
/* avoid using task_frag */
|
||||
sock->sk->sk_allocation = GFP_ATOMIC;
|
||||
sock->sk->sk_use_task_frag = false;
|
||||
ovpn_sock->sk->sk_allocation = GFP_ATOMIC;
|
||||
ovpn_sock->sk->sk_use_task_frag = false;
|
||||
|
||||
/* enqueue the RX worker */
|
||||
strp_check_rcv(&peer->tcp.strp);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ void ovpn_tcp_socket_wait_finish(struct ovpn_socket *sock);
|
|||
* Required by the OpenVPN protocol in order to extract packets from
|
||||
* the TCP stream on the receiver side.
|
||||
*/
|
||||
void ovpn_tcp_send_skb(struct ovpn_peer *peer, struct socket *sock, struct sk_buff *skb);
|
||||
void ovpn_tcp_send_skb(struct ovpn_peer *peer, struct sock *sk,
|
||||
struct sk_buff *skb);
|
||||
void ovpn_tcp_tx_work(struct work_struct *work);
|
||||
|
||||
#endif /* _NET_OVPN_TCP_H_ */
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ static struct ovpn_socket *ovpn_socket_from_udp_sock(struct sock *sk)
|
|||
return NULL;
|
||||
|
||||
/* make sure that sk matches our stored transport socket */
|
||||
if (unlikely(!ovpn_sock->sock || sk != ovpn_sock->sock->sk))
|
||||
if (unlikely(!ovpn_sock->sk || sk != ovpn_sock->sk))
|
||||
return NULL;
|
||||
|
||||
return ovpn_sock;
|
||||
|
|
@ -335,32 +335,22 @@ static int ovpn_udp_output(struct ovpn_peer *peer, struct dst_cache *cache,
|
|||
/**
|
||||
* ovpn_udp_send_skb - prepare skb and send it over via UDP
|
||||
* @peer: the destination peer
|
||||
* @sock: the RCU protected peer socket
|
||||
* @sk: peer socket
|
||||
* @skb: the packet to send
|
||||
*/
|
||||
void ovpn_udp_send_skb(struct ovpn_peer *peer, struct socket *sock,
|
||||
void ovpn_udp_send_skb(struct ovpn_peer *peer, struct sock *sk,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
int ret = -1;
|
||||
int ret;
|
||||
|
||||
skb->dev = peer->ovpn->dev;
|
||||
/* no checksum performed at this layer */
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
|
||||
/* get socket info */
|
||||
if (unlikely(!sock)) {
|
||||
net_warn_ratelimited("%s: no sock for remote peer %u\n",
|
||||
netdev_name(peer->ovpn->dev), peer->id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* crypto layer -> transport (UDP) */
|
||||
ret = ovpn_udp_output(peer, &peer->dst_cache, sock->sk, skb);
|
||||
out:
|
||||
if (unlikely(ret < 0)) {
|
||||
ret = ovpn_udp_output(peer, &peer->dst_cache, sk, skb);
|
||||
if (unlikely(ret < 0))
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void ovpn_udp_encap_destroy(struct sock *sk)
|
||||
|
|
@ -383,6 +373,7 @@ static void ovpn_udp_encap_destroy(struct sock *sk)
|
|||
/**
|
||||
* ovpn_udp_socket_attach - set udp-tunnel CBs on socket and link it to ovpn
|
||||
* @ovpn_sock: socket to configure
|
||||
* @sock: the socket container to be passed to setup_udp_tunnel_sock()
|
||||
* @ovpn: the openvp instance to link
|
||||
*
|
||||
* After invoking this function, the sock will be controlled by ovpn so that
|
||||
|
|
@ -390,7 +381,7 @@ static void ovpn_udp_encap_destroy(struct sock *sk)
|
|||
*
|
||||
* Return: 0 on success or a negative error code otherwise
|
||||
*/
|
||||
int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock,
|
||||
int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, struct socket *sock,
|
||||
struct ovpn_priv *ovpn)
|
||||
{
|
||||
struct udp_tunnel_sock_cfg cfg = {
|
||||
|
|
@ -398,17 +389,16 @@ int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock,
|
|||
.encap_rcv = ovpn_udp_encap_recv,
|
||||
.encap_destroy = ovpn_udp_encap_destroy,
|
||||
};
|
||||
struct socket *sock = ovpn_sock->sock;
|
||||
struct ovpn_socket *old_data;
|
||||
int ret;
|
||||
|
||||
/* make sure no pre-existing encapsulation handler exists */
|
||||
rcu_read_lock();
|
||||
old_data = rcu_dereference_sk_user_data(sock->sk);
|
||||
old_data = rcu_dereference_sk_user_data(ovpn_sock->sk);
|
||||
if (!old_data) {
|
||||
/* socket is currently unused - we can take it */
|
||||
rcu_read_unlock();
|
||||
setup_udp_tunnel_sock(sock_net(sock->sk), sock, &cfg);
|
||||
setup_udp_tunnel_sock(sock_net(ovpn_sock->sk), sock, &cfg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -421,7 +411,7 @@ int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock,
|
|||
* Unlikely TCP, a single UDP socket can be used to talk to many remote
|
||||
* hosts and therefore openvpn instantiates one only for all its peers
|
||||
*/
|
||||
if ((READ_ONCE(udp_sk(sock->sk)->encap_type) == UDP_ENCAP_OVPNINUDP) &&
|
||||
if ((READ_ONCE(udp_sk(ovpn_sock->sk)->encap_type) == UDP_ENCAP_OVPNINUDP) &&
|
||||
old_data->ovpn == ovpn) {
|
||||
netdev_dbg(ovpn->dev,
|
||||
"provided socket already owned by this interface\n");
|
||||
|
|
@ -442,8 +432,16 @@ int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock,
|
|||
*/
|
||||
void ovpn_udp_socket_detach(struct ovpn_socket *ovpn_sock)
|
||||
{
|
||||
struct udp_tunnel_sock_cfg cfg = { };
|
||||
struct sock *sk = ovpn_sock->sk;
|
||||
|
||||
setup_udp_tunnel_sock(sock_net(ovpn_sock->sock->sk), ovpn_sock->sock,
|
||||
&cfg);
|
||||
/* Re-enable multicast loopback */
|
||||
inet_set_bit(MC_LOOP, sk);
|
||||
/* Disable CHECKSUM_UNNECESSARY to CHECKSUM_COMPLETE conversion */
|
||||
inet_dec_convert_csum(sk);
|
||||
|
||||
WRITE_ONCE(udp_sk(sk)->encap_type, 0);
|
||||
WRITE_ONCE(udp_sk(sk)->encap_rcv, NULL);
|
||||
WRITE_ONCE(udp_sk(sk)->encap_destroy, NULL);
|
||||
|
||||
rcu_assign_sk_user_data(sk, NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,11 +15,11 @@ struct ovpn_peer;
|
|||
struct ovpn_priv;
|
||||
struct socket;
|
||||
|
||||
int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock,
|
||||
int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, struct socket *sock,
|
||||
struct ovpn_priv *ovpn);
|
||||
void ovpn_udp_socket_detach(struct ovpn_socket *ovpn_sock);
|
||||
|
||||
void ovpn_udp_send_skb(struct ovpn_peer *peer, struct socket *sock,
|
||||
void ovpn_udp_send_skb(struct ovpn_peer *peer, struct sock *sk,
|
||||
struct sk_buff *skb);
|
||||
|
||||
#endif /* _NET_OVPN_UDP_H_ */
|
||||
|
|
|
|||
|
|
@ -2166,6 +2166,7 @@ static int ovpn_parse_cmd_args(struct ovpn_ctx *ovpn, int argc, char *argv[])
|
|||
|
||||
ovpn->peers_file = argv[4];
|
||||
|
||||
ovpn->sa_family = AF_INET;
|
||||
if (argc > 5 && !strcmp(argv[5], "ipv6"))
|
||||
ovpn->sa_family = AF_INET6;
|
||||
break;
|
||||
|
|
|
|||
9
tools/testing/selftests/net/ovpn/test-large-mtu.sh
Executable file
9
tools/testing/selftests/net/ovpn/test-large-mtu.sh
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2025 OpenVPN, Inc.
|
||||
#
|
||||
# Author: Antonio Quartulli <antonio@openvpn.net>
|
||||
|
||||
MTU="1500"
|
||||
|
||||
source test.sh
|
||||
Loading…
Reference in New Issue
Block a user