1
0
Fork 0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-06-08 00:07:34 +09:00
linux/drivers/net/ovpn/tcp.c
Antonio Quartulli a6a5e87b3e ovpn: avoid sleep in atomic context in TCP RX error path
Upon error along the TCP data_ready event path, we have
the following chain of calls:

strp_data_ready()
  ovpn_tcp_rcv()
    ovpn_peer_del()
      ovpn_socket_release()

Since strp_data_ready() may be invoked from softirq context, and
ovpn_socket_release() may sleep, the above sequence may cause a
sleep in atomic context like the following:

    BUG: sleeping function called from invalid context at ./ovpn-backports-ovpn-net-next-main-6.15.0-rc5-20250522/drivers/net/ovpn/socket.c:71
    in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 25, name: ksoftirqd/3
    5 locks held by ksoftirqd/3/25:
     #0: ffffffe000cd0580 (rcu_read_lock){....}-{1:2}, at: netif_receive_skb+0xb8/0x5b0
     OpenVPN/ovpn-backports#1: ffffffe000cd0580 (rcu_read_lock){....}-{1:2}, at: netif_receive_skb+0xb8/0x5b0
     OpenVPN/ovpn-backports#2: ffffffe000cd0580 (rcu_read_lock){....}-{1:2}, at: ip_local_deliver_finish+0x66/0x1e0
     OpenVPN/ovpn-backports#3: ffffffe003ce9818 (slock-AF_INET/1){+.-.}-{2:2}, at: tcp_v4_rcv+0x156e/0x17a0
     OpenVPN/ovpn-backports#4: ffffffe000cd0580 (rcu_read_lock){....}-{1:2}, at: ovpn_tcp_data_ready+0x0/0x1b0 [ovpn]
    CPU: 3 PID: 25 Comm: ksoftirqd/3 Not tainted 5.10.104+ #0
    Call Trace:
    walk_stackframe+0x0/0x1d0
    show_stack+0x2e/0x44
    dump_stack+0xc2/0x102
    ___might_sleep+0x29c/0x2b0
    __might_sleep+0x62/0xa0
    ovpn_socket_release+0x24/0x2d0 [ovpn]
    unlock_ovpn+0x6e/0x190 [ovpn]
    ovpn_peer_del+0x13c/0x390 [ovpn]
    ovpn_tcp_rcv+0x280/0x560 [ovpn]
    __strp_recv+0x262/0x940
    strp_recv+0x66/0x80
    tcp_read_sock+0x122/0x410
    strp_data_ready+0x156/0x1f0
    ovpn_tcp_data_ready+0x92/0x1b0 [ovpn]
    tcp_data_ready+0x6c/0x150
    tcp_rcv_established+0xb36/0xc50
    tcp_v4_do_rcv+0x25e/0x380
    tcp_v4_rcv+0x166a/0x17a0
    ip_protocol_deliver_rcu+0x8c/0x250
    ip_local_deliver_finish+0xf8/0x1e0
    ip_local_deliver+0xc2/0x2d0
    ip_rcv+0x1f2/0x330
    __netif_receive_skb+0xfc/0x290
    netif_receive_skb+0x104/0x5b0
    br_pass_frame_up+0x190/0x3f0
    br_handle_frame_finish+0x3e2/0x7a0
    br_handle_frame+0x750/0xab0
    __netif_receive_skb_core.constprop.0+0x4c0/0x17f0
    __netif_receive_skb+0xc6/0x290
    netif_receive_skb+0x104/0x5b0
    xgmac_dma_rx+0x962/0xb40
    __napi_poll.constprop.0+0x5a/0x350
    net_rx_action+0x1fe/0x4b0
    __do_softirq+0x1f8/0x85c
    run_ksoftirqd+0x80/0xd0
    smpboot_thread_fn+0x1f0/0x3e0
    kthread+0x1e6/0x210
    ret_from_kernel_thread+0x8/0xc

Fix this issue by postponing the ovpn_peer_del() call to
a scheduled worker, as we already do in ovpn_tcp_send_sock()
for the very same reason.

Fixes: 11851cbd60 ("ovpn: implement TCP transport")
Reported-by: Qingfang Deng <dqfext@gmail.com>
Closes: https://github.com/OpenVPN/ovpn-net-next/issues/13
Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
2025-06-03 13:08:15 +02:00

601 lines
15 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* OpenVPN data channel offload
*
* Copyright (C) 2019-2025 OpenVPN, Inc.
*
* Author: Antonio Quartulli <antonio@openvpn.net>
*/
#include <linux/skbuff.h>
#include <net/hotdata.h>
#include <net/inet_common.h>
#include <net/ipv6.h>
#include <net/tcp.h>
#include <net/transp_v6.h>
#include <net/route.h>
#include <trace/events/sock.h>
#include "ovpnpriv.h"
#include "main.h"
#include "io.h"
#include "peer.h"
#include "proto.h"
#include "skb.h"
#include "tcp.h"
#define OVPN_TCP_DEPTH_NESTING 2
#if OVPN_TCP_DEPTH_NESTING == SINGLE_DEPTH_NESTING
#error "OVPN TCP requires its own lockdep subclass"
#endif
static struct proto ovpn_tcp_prot __ro_after_init;
static struct proto_ops ovpn_tcp_ops __ro_after_init;
static struct proto ovpn_tcp6_prot __ro_after_init;
static struct proto_ops ovpn_tcp6_ops __ro_after_init;
static int ovpn_tcp_parse(struct strparser *strp, struct sk_buff *skb)
{
struct strp_msg *rxm = strp_msg(skb);
__be16 blen;
u16 len;
int err;
/* when packets are written to the TCP stream, they are prepended with
* two bytes indicating the actual packet size.
* Parse accordingly and return the actual size (including the size
* header)
*/
if (skb->len < rxm->offset + 2)
return 0;
err = skb_copy_bits(skb, rxm->offset, &blen, sizeof(blen));
if (err < 0)
return err;
len = be16_to_cpu(blen);
if (len < 2)
return -EINVAL;
return len + 2;
}
/* queue skb for sending to userspace via recvmsg on the socket */
static void ovpn_tcp_to_userspace(struct ovpn_peer *peer, struct sock *sk,
struct sk_buff *skb)
{
skb_set_owner_r(skb, sk);
memset(skb->cb, 0, sizeof(skb->cb));
skb_queue_tail(&peer->tcp.user_queue, skb);
peer->tcp.sk_cb.sk_data_ready(sk);
}
static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb)
{
struct ovpn_peer *peer = container_of(strp, struct ovpn_peer, tcp.strp);
struct strp_msg *msg = strp_msg(skb);
size_t pkt_len = msg->full_len - 2;
size_t off = msg->offset + 2;
u8 opcode;
/* ensure skb->data points to the beginning of the openvpn packet */
if (!pskb_pull(skb, off)) {
net_warn_ratelimited("%s: packet too small for peer %u\n",
netdev_name(peer->ovpn->dev), peer->id);
goto err;
}
/* strparser does not trim the skb for us, therefore we do it now */
if (pskb_trim(skb, pkt_len) != 0) {
net_warn_ratelimited("%s: trimming skb failed for peer %u\n",
netdev_name(peer->ovpn->dev), peer->id);
goto err;
}
/* we need the first 4 bytes of data to be accessible
* to extract the opcode and the key ID later on
*/
if (!pskb_may_pull(skb, OVPN_OPCODE_SIZE)) {
net_warn_ratelimited("%s: packet too small to fetch opcode for peer %u\n",
netdev_name(peer->ovpn->dev), peer->id);
goto err;
}
/* DATA_V2 packets are handled in kernel, the rest goes to user space */
opcode = ovpn_opcode_from_skb(skb, 0);
if (unlikely(opcode != OVPN_DATA_V2)) {
if (opcode == OVPN_DATA_V1) {
net_warn_ratelimited("%s: DATA_V1 detected on the TCP stream\n",
netdev_name(peer->ovpn->dev));
goto err;
}
/* The packet size header must be there when sending the packet
* to userspace, therefore we put it back
*/
skb_push(skb, 2);
ovpn_tcp_to_userspace(peer, strp->sk, skb);
return;
}
/* hold reference to peer as required by ovpn_recv().
*
* NOTE: in this context we should already be holding a reference to
* this peer, therefore ovpn_peer_hold() is not expected to fail
*/
if (WARN_ON(!ovpn_peer_hold(peer)))
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);
}
static int ovpn_tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
int flags, int *addr_len)
{
int err = 0, off, copied = 0, ret;
struct ovpn_socket *sock;
struct ovpn_peer *peer;
struct sk_buff *skb;
rcu_read_lock();
sock = rcu_dereference_sk_user_data(sk);
if (unlikely(!sock || !sock->peer || !ovpn_peer_hold(sock->peer))) {
rcu_read_unlock();
return -EBADF;
}
peer = sock->peer;
rcu_read_unlock();
skb = __skb_recv_datagram(sk, &peer->tcp.user_queue, flags, &off, &err);
if (!skb) {
if (err == -EAGAIN && sk->sk_shutdown & RCV_SHUTDOWN) {
ret = 0;
goto out;
}
ret = err;
goto out;
}
copied = len;
if (copied > skb->len)
copied = skb->len;
else if (copied < skb->len)
msg->msg_flags |= MSG_TRUNC;
err = skb_copy_datagram_msg(skb, 0, msg, copied);
if (unlikely(err)) {
kfree_skb(skb);
ret = err;
goto out;
}
if (flags & MSG_TRUNC)
copied = skb->len;
kfree_skb(skb);
ret = copied;
out:
ovpn_peer_put(peer);
return ret;
}
void ovpn_tcp_socket_detach(struct ovpn_socket *ovpn_sock)
{
struct ovpn_peer *peer = ovpn_sock->peer;
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() */
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(sk, NULL);
}
void ovpn_tcp_socket_wait_finish(struct ovpn_socket *sock)
{
struct ovpn_peer *peer = sock->peer;
/* NOTE: we don't wait for peer->tcp.defer_del_work to finish:
* either the worker is not running or this function
* was invoked by that worker.
*/
cancel_work_sync(&sock->tcp_tx_work);
strp_done(&peer->tcp.strp);
skb_queue_purge(&peer->tcp.out_queue);
kfree_skb(peer->tcp.out_msg.skb);
peer->tcp.out_msg.skb = NULL;
}
static void ovpn_tcp_send_sock(struct ovpn_peer *peer, struct sock *sk)
{
struct sk_buff *skb = peer->tcp.out_msg.skb;
int ret, flags;
if (!skb)
return;
if (peer->tcp.tx_in_progress)
return;
peer->tcp.tx_in_progress = true;
do {
flags = ovpn_skb_cb(skb)->nosignal ? MSG_NOSIGNAL : 0;
ret = skb_send_sock_locked_with_flags(sk, skb,
peer->tcp.out_msg.offset,
peer->tcp.out_msg.len,
flags);
if (unlikely(ret < 0)) {
if (ret == -EAGAIN)
goto out;
net_warn_ratelimited("%s: TCP error to peer %u: %d\n",
netdev_name(peer->ovpn->dev),
peer->id, ret);
/* in case of TCP error we can't recover the VPN
* stream therefore we abort the connection
*/
ovpn_peer_hold(peer);
schedule_work(&peer->tcp.defer_del_work);
/* we bail out immediately and keep tx_in_progress set
* to true. This way we prevent more TX attempts
* which would lead to more invocations of
* schedule_work()
*/
return;
}
peer->tcp.out_msg.len -= ret;
peer->tcp.out_msg.offset += ret;
} while (peer->tcp.out_msg.len > 0);
if (!peer->tcp.out_msg.len) {
preempt_disable();
dev_dstats_tx_add(peer->ovpn->dev, skb->len);
preempt_enable();
}
kfree_skb(peer->tcp.out_msg.skb);
peer->tcp.out_msg.skb = NULL;
peer->tcp.out_msg.len = 0;
peer->tcp.out_msg.offset = 0;
out:
peer->tcp.tx_in_progress = false;
}
void ovpn_tcp_tx_work(struct work_struct *work)
{
struct ovpn_socket *sock;
sock = container_of(work, struct ovpn_socket, tcp_tx_work);
lock_sock(sock->sk);
if (sock->peer)
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,
struct sk_buff *skb)
{
if (peer->tcp.out_msg.skb)
ovpn_tcp_send_sock(peer, sk);
if (peer->tcp.out_msg.skb) {
dev_dstats_tx_dropped(peer->ovpn->dev);
kfree_skb(skb);
return;
}
peer->tcp.out_msg.skb = skb;
peer->tcp.out_msg.len = skb->len;
peer->tcp.out_msg.offset = 0;
ovpn_tcp_send_sock(peer, sk);
}
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(&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);
kfree_skb(skb);
goto unlock;
}
__skb_queue_tail(&peer->tcp.out_queue, skb);
} else {
ovpn_tcp_send_sock_skb(peer, sk, skb);
}
unlock:
spin_unlock(&sk->sk_lock.slock);
}
static void ovpn_tcp_release(struct sock *sk)
{
struct sk_buff_head queue;
struct ovpn_socket *sock;
struct ovpn_peer *peer;
struct sk_buff *skb;
rcu_read_lock();
sock = rcu_dereference_sk_user_data(sk);
if (!sock) {
rcu_read_unlock();
return;
}
peer = sock->peer;
/* during initialization this function is called before
* assigning sock->peer
*/
if (unlikely(!peer || !ovpn_peer_hold(peer))) {
rcu_read_unlock();
return;
}
rcu_read_unlock();
__skb_queue_head_init(&queue);
skb_queue_splice_init(&peer->tcp.out_queue, &queue);
while ((skb = __skb_dequeue(&queue)))
ovpn_tcp_send_sock_skb(peer, sk, skb);
peer->tcp.sk_cb.prot->release_cb(sk);
ovpn_peer_put(peer);
}
static int ovpn_tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
{
struct ovpn_socket *sock;
int ret, linear = PAGE_SIZE;
struct ovpn_peer *peer;
struct sk_buff *skb;
lock_sock(sk);
rcu_read_lock();
sock = rcu_dereference_sk_user_data(sk);
if (unlikely(!sock || !sock->peer || !ovpn_peer_hold(sock->peer))) {
rcu_read_unlock();
release_sock(sk);
return -EIO;
}
rcu_read_unlock();
peer = sock->peer;
if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_NOSIGNAL)) {
ret = -EOPNOTSUPP;
goto peer_free;
}
if (peer->tcp.out_msg.skb) {
ret = -EAGAIN;
goto peer_free;
}
if (size < linear)
linear = size;
skb = sock_alloc_send_pskb(sk, linear, size - linear,
msg->msg_flags & MSG_DONTWAIT, &ret, 0);
if (!skb) {
net_err_ratelimited("%s: skb alloc failed: %d\n",
netdev_name(peer->ovpn->dev), ret);
goto peer_free;
}
skb_put(skb, linear);
skb->len = size;
skb->data_len = size - linear;
ret = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, size);
if (ret) {
kfree_skb(skb);
net_err_ratelimited("%s: skb copy from iter failed: %d\n",
netdev_name(peer->ovpn->dev), ret);
goto peer_free;
}
ovpn_skb_cb(skb)->nosignal = msg->msg_flags & MSG_NOSIGNAL;
ovpn_tcp_send_sock_skb(peer, sk, skb);
ret = size;
peer_free:
release_sock(sk);
ovpn_peer_put(peer);
return ret;
}
static int ovpn_tcp_disconnect(struct sock *sk, int flags)
{
return -EBUSY;
}
static void ovpn_tcp_data_ready(struct sock *sk)
{
struct ovpn_socket *sock;
trace_sk_data_ready(sk);
rcu_read_lock();
sock = rcu_dereference_sk_user_data(sk);
if (likely(sock && sock->peer))
strp_data_ready(&sock->peer->tcp.strp);
rcu_read_unlock();
}
static void ovpn_tcp_write_space(struct sock *sk)
{
struct ovpn_socket *sock;
rcu_read_lock();
sock = rcu_dereference_sk_user_data(sk);
if (likely(sock && sock->peer)) {
schedule_work(&sock->tcp_tx_work);
sock->peer->tcp.sk_cb.sk_write_space(sk);
}
rcu_read_unlock();
}
static void ovpn_tcp_build_protos(struct proto *new_prot,
struct proto_ops *new_ops,
const struct proto *orig_prot,
const struct proto_ops *orig_ops);
static void ovpn_tcp_peer_del_work(struct work_struct *work)
{
struct ovpn_peer *peer = container_of(work, struct ovpn_peer,
tcp.defer_del_work);
ovpn_peer_del(peer, OVPN_DEL_PEER_REASON_TRANSPORT_ERROR);
ovpn_peer_put(peer);
}
/* Set TCP encapsulation callbacks */
int ovpn_tcp_socket_attach(struct ovpn_socket *ovpn_sock,
struct ovpn_peer *peer)
{
struct strp_callbacks cb = {
.rcv_msg = ovpn_tcp_rcv,
.parse_msg = ovpn_tcp_parse,
};
int ret;
/* make sure no pre-existing encapsulation handler exists */
if (ovpn_sock->sk->sk_user_data)
return -EBUSY;
/* only a fully connected socket is expected. Connection should be
* handled in userspace
*/
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),
ovpn_sock->sk->sk_state);
return -EINVAL;
}
ret = strp_init(&peer->tcp.strp, ovpn_sock->sk, &cb);
if (ret < 0) {
DEBUG_NET_WARN_ON_ONCE(1);
return ret;
}
INIT_WORK(&peer->tcp.defer_del_work, ovpn_tcp_peer_del_work);
__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 = 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 */
ovpn_sock->sk->sk_data_ready = ovpn_tcp_data_ready;
ovpn_sock->sk->sk_write_space = ovpn_tcp_write_space;
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 {
ovpn_sock->sk->sk_prot = &ovpn_tcp6_prot;
ovpn_sock->sk->sk_socket->ops = &ovpn_tcp6_ops;
}
/* avoid using task_frag */
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);
return 0;
}
static void ovpn_tcp_close(struct sock *sk, long timeout)
{
struct ovpn_socket *sock;
struct ovpn_peer *peer;
rcu_read_lock();
sock = rcu_dereference_sk_user_data(sk);
if (!sock || !sock->peer || !ovpn_peer_hold(sock->peer)) {
rcu_read_unlock();
return;
}
peer = sock->peer;
rcu_read_unlock();
ovpn_peer_del(sock->peer, OVPN_DEL_PEER_REASON_TRANSPORT_DISCONNECT);
peer->tcp.sk_cb.prot->close(sk, timeout);
ovpn_peer_put(peer);
}
static __poll_t ovpn_tcp_poll(struct file *file, struct socket *sock,
poll_table *wait)
{
__poll_t mask = datagram_poll(file, sock, wait);
struct ovpn_socket *ovpn_sock;
rcu_read_lock();
ovpn_sock = rcu_dereference_sk_user_data(sock->sk);
if (ovpn_sock && ovpn_sock->peer &&
!skb_queue_empty(&ovpn_sock->peer->tcp.user_queue))
mask |= EPOLLIN | EPOLLRDNORM;
rcu_read_unlock();
return mask;
}
static void ovpn_tcp_build_protos(struct proto *new_prot,
struct proto_ops *new_ops,
const struct proto *orig_prot,
const struct proto_ops *orig_ops)
{
memcpy(new_prot, orig_prot, sizeof(*new_prot));
memcpy(new_ops, orig_ops, sizeof(*new_ops));
new_prot->recvmsg = ovpn_tcp_recvmsg;
new_prot->sendmsg = ovpn_tcp_sendmsg;
new_prot->disconnect = ovpn_tcp_disconnect;
new_prot->close = ovpn_tcp_close;
new_prot->release_cb = ovpn_tcp_release;
new_ops->poll = ovpn_tcp_poll;
}
/* Initialize TCP static objects */
void __init ovpn_tcp_init(void)
{
ovpn_tcp_build_protos(&ovpn_tcp_prot, &ovpn_tcp_ops, &tcp_prot,
&inet_stream_ops);
#if IS_ENABLED(CONFIG_IPV6)
ovpn_tcp_build_protos(&ovpn_tcp6_prot, &ovpn_tcp6_ops, &tcpv6_prot,
&inet6_stream_ops);
#endif
}