All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sabrina Dubroca <sd@queasysnail.net>
To: Antonio Quartulli <antonio@openvpn.net>
Cc: Eric Dumazet <edumazet@google.com>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	Donald Hunter <donald.hunter@gmail.com>,
	Shuah Khan <shuah@kernel.org>,
	ryazanov.s.a@gmail.com, Andrew Lunn <andrew@lunn.ch>,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-kselftest@vger.kernel.org
Subject: Re: [PATCH net-next v11 12/23] ovpn: implement TCP transport
Date: Thu, 31 Oct 2024 16:25:47 +0100	[thread overview]
Message-ID: <ZyOhe3yKTiqCF2TH@hog> (raw)
In-Reply-To: <20241029-b4-ovpn-v11-12-de4698c73a25@openvpn.net>

2024-10-29, 11:47:25 +0100, Antonio Quartulli wrote:
> +static void ovpn_socket_release_work(struct work_struct *work)
> +{
> +	struct ovpn_socket *sock = container_of(work, struct ovpn_socket, work);
> +
> +	ovpn_socket_detach(sock->sock);
> +	kfree_rcu(sock, rcu);
> +}
> +
> +static void ovpn_socket_schedule_release(struct ovpn_socket *sock)
> +{
> +	INIT_WORK(&sock->work, ovpn_socket_release_work);
> +	schedule_work(&sock->work);

How does module unloading know that it has to wait for this work to
complete? Will ovpn_cleanup get stuck until some refcount gets
released by this work?


[...]
> +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;
> +
> +	/* ensure skb->data points to the beginning of the openvpn packet */
> +	if (!pskb_pull(skb, off)) {
> +		net_warn_ratelimited("%s: packet too small\n",
> +				     peer->ovpn->dev->name);
> +		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\n",
> +				     peer->ovpn->dev->name);
> +		goto err;
> +	}
> +
> +	/* we need the first byte of data to be accessible
> +	 * to extract the opcode and the key ID later on
> +	 */
> +	if (!pskb_may_pull(skb, 1)) {
> +		net_warn_ratelimited("%s: packet too small to fetch opcode\n",
> +				     peer->ovpn->dev->name);
> +		goto err;
> +	}
> +
> +	/* DATA_V2 packets are handled in kernel, the rest goes to user space */
> +	if (likely(ovpn_opcode_from_skb(skb, 0) == OVPN_DATA_V2)) {
> +		/* 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;
> +
> +		ovpn_recv(peer, skb);
> +	} else {
> +		/* 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;
> +err:
> +	netdev_err(peer->ovpn->dev,
> +		   "cannot process incoming TCP data for peer %u\n", peer->id);

This should also be ratelimited, and maybe just combined with the
net_warn_ratelimited just before each goto.

> +	dev_core_stats_rx_dropped_inc(peer->ovpn->dev);
> +	kfree_skb(skb);
> +	ovpn_peer_del(peer, OVPN_DEL_PEER_REASON_TRANSPORT_ERROR);
> +}

[...]
> +void ovpn_tcp_socket_detach(struct socket *sock)
> +{
[...]
> +	/* 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;
> +	rcu_assign_sk_user_data(sock->sk, NULL);
> +
> +	rcu_read_unlock();
> +
> +	/* cancel any ongoing work. Done after removing the CBs so that these
> +	 * workers cannot be re-armed
> +	 */

I'm not sure whether a barrier is needed to prevent compiler/CPU
reordering here.

> +	cancel_work_sync(&peer->tcp.tx_work);
> +	strp_done(&peer->tcp.strp);
> +}
> +
> +static void ovpn_tcp_send_sock(struct ovpn_peer *peer)
> +{
> +	struct sk_buff *skb = peer->tcp.out_msg.skb;
> +
> +	if (!skb)
> +		return;
> +
> +	if (peer->tcp.tx_in_progress)
> +		return;
> +
> +	peer->tcp.tx_in_progress = true;

Sorry, I never answered your question about my concerns in a previous
review here.

We can reach ovpn_tcp_send_sock in two different contexts:
 - lock_sock (either from ovpn_tcp_sendmsg or ovpn_tcp_tx_work)
 - bh_lock_sock (from ovpn_tcp_send_skb, ie "data path")

These are not fully mutually exclusive. lock_sock grabs bh_lock_sock
(a spinlock) for a brief period to mark the (sleeping/mutex) lock as
taken, and then releases it.

So when bh_lock_sock is held, it's not possible to grab lock_sock. But
when lock_sock is taken, it's still possible to grab bh_lock_sock.


The buggy scenario would be:

  (data path encrypt)                       (sendmsg)
  ovpn_tcp_send_skb                         lock_sock
                                              bh_lock_sock + owned=1 + bh_unlock_sock
  bh_lock_sock
  ovpn_tcp_send_sock_skb                      ovpn_tcp_send_sock_skb
    !peer->tcp.out_msg.skb                      !peer->tcp.out_msg.skb
    peer->tcp.out_msg.skb = ...                 peer->tcp.out_msg.skb = ...
    ovpn_tcp_send_sock                          ovpn_tcp_send_sock
      !peer->tcp.tx_in_progress                   !peer->tcp.tx_in_progress
      peer->tcp.tx_in_progress = true             peer->tcp.tx_in_progress = true
      // proceed                                  // proceed


That's 2 similar races, one on out_msg.skb and one on tx_in_progress.
It's a bit unlikely (but not impossible) that we'll have 2 cpus trying
to call skb_send_sock_locked at the same time, but if they just
overwrite each other's skb/len it's already pretty bad. The end of
ovpn_tcp_send_sock might also reset peer->tcp.out_msg.* just as
ovpn_tcp_send_skb -> ovpn_tcp_send_sock_skb starts setting it up
(peer->tcp.out_msg.skb gets cleared, ovpn_tcp_send_sock_skb proceeds
and sets skb+len, then maybe len gets reset to 0 by
ovpn_tcp_send_sock).


To avoid this problem, esp_output_tcp_finish (net/ipv4/esp4.c) does:

	bh_lock_sock(sk);
	if (sock_owned_by_user(sk))
		err = espintcp_queue_out(sk, skb);
	else
		err = espintcp_push_skb(sk, skb);
	bh_unlock_sock(sk);


(espintcp_push_skb is roughly equivalent to ovpn_tcp_send_sock_skb)


> +	do {
> +		int ret = skb_send_sock_locked(peer->sock->sock->sk, skb,
> +					       peer->tcp.out_msg.offset,
> +					       peer->tcp.out_msg.len);
> +		if (unlikely(ret < 0)) {
> +			if (ret == -EAGAIN)
> +				goto out;
> +
> +			net_warn_ratelimited("%s: TCP error to peer %u: %d\n",
> +					     peer->ovpn->dev->name, peer->id,
> +					     ret);
> +
> +			/* in case of TCP error we can't recover the VPN
> +			 * stream therefore we abort the connection
> +			 */
> +			ovpn_peer_del(peer,
> +				      OVPN_DEL_PEER_REASON_TRANSPORT_ERROR);
> +			break;
> +		}
> +
> +		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)
> +		dev_sw_netstats_tx_add(peer->ovpn->dev, 1, skb->len);
> +
> +	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;
> +}
> +
> +static void ovpn_tcp_tx_work(struct work_struct *work)
> +{
> +	struct ovpn_peer *peer;
> +
> +	peer = container_of(work, struct ovpn_peer, tcp.tx_work);
> +
> +	lock_sock(peer->sock->sock->sk);
> +	ovpn_tcp_send_sock(peer);
> +	release_sock(peer->sock->sock->sk);
> +}
> +
> +void ovpn_tcp_send_sock_skb(struct ovpn_peer *peer, struct sk_buff *skb)
> +{
> +	if (peer->tcp.out_msg.skb)
> +		return;

That's leaking the skb? (and not counting the drop)

> +
> +	peer->tcp.out_msg.skb = skb;
> +	peer->tcp.out_msg.len = skb->len;
> +	peer->tcp.out_msg.offset = 0;
> +
> +	ovpn_tcp_send_sock(peer);
> +}
> +
> +static int ovpn_tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
> +{
[...]
> +	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",
> +				    sock->peer->ovpn->dev->name, ret);
> +		goto unlock;
> +	}
> +
> +	ovpn_tcp_send_sock_skb(sock->peer, skb);

If we didn't send the packet (because one was already queued/in
progress), we should either stash it, or tell userspace that it wasn't
sent and it should retry later.

> +	ret = size;
> +unlock:
> +	release_sock(sk);
> +peer_free:
> +	ovpn_peer_put(peer);
> +	return ret;
> +}

-- 
Sabrina

  parent reply	other threads:[~2024-10-31 15:25 UTC|newest]

Thread overview: 158+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-10-29 10:47 [PATCH net-next v11 00/23] Introducing OpenVPN Data Channel Offload Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 01/23] netlink: add NLA_POLICY_MAX_LEN macro Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 02/23] net: introduce OpenVPN Data Channel Offload (ovpn) Antonio Quartulli
2024-11-06  0:31   ` Sergey Ryazanov
2024-11-15  9:56     ` Antonio Quartulli
2024-11-19  1:49       ` Sergey Ryazanov
2024-10-29 10:47 ` [PATCH net-next v11 03/23] ovpn: add basic netlink support Antonio Quartulli
2024-11-08 23:15   ` Sergey Ryazanov
2024-11-15 10:05     ` Antonio Quartulli
2024-11-19  2:05       ` Sergey Ryazanov
2024-11-19  8:12         ` Antonio Quartulli
2024-11-08 23:31   ` Sergey Ryazanov
2024-11-15 10:19     ` Antonio Quartulli
2024-11-19  2:23       ` Sergey Ryazanov
2024-11-19  8:16         ` Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 04/23] ovpn: add basic interface creation/destruction/management routines Antonio Quartulli
2024-11-09  1:01   ` Sergey Ryazanov
2024-11-12 16:47     ` Sabrina Dubroca
2024-11-12 23:56       ` Sergey Ryazanov
2024-11-14  8:07       ` Antonio Quartulli
2024-11-14 22:57         ` Sergey Ryazanov
2024-11-15 13:45           ` Antonio Quartulli
2024-11-15 13:00     ` Antonio Quartulli
2024-11-10 20:42   ` Sergey Ryazanov
2024-11-15 14:03     ` Antonio Quartulli
2024-11-19  3:08       ` Sergey Ryazanov
2024-11-19  8:45         ` Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 05/23] ovpn: keep carrier always on Antonio Quartulli
2024-11-09  1:11   ` Sergey Ryazanov
2024-11-15 14:13     ` Antonio Quartulli
2024-11-20 22:56       ` Sergey Ryazanov
2024-11-21 21:17         ` Antonio Quartulli
2024-11-23 22:25           ` Sergey Ryazanov
2024-11-23 22:52             ` Antonio Quartulli
2024-11-25  2:26               ` Sergey Ryazanov
2024-11-25 13:07                 ` Antonio Quartulli
2024-11-25 21:32                   ` Sergey Ryazanov
2024-11-26  8:17                     ` Antonio Quartulli
2024-12-02 10:40                       ` Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 06/23] ovpn: introduce the ovpn_peer object Antonio Quartulli
2024-10-30 16:37   ` Sabrina Dubroca
2024-10-30 20:47     ` Antonio Quartulli
2024-11-05 13:12       ` Sabrina Dubroca
2024-11-12 10:12         ` Antonio Quartulli
2024-11-10 13:38   ` Sergey Ryazanov
2024-11-12 17:31     ` Sabrina Dubroca
2024-11-13  1:37       ` Sergey Ryazanov
2024-11-13 10:03         ` Sabrina Dubroca
2024-11-20 23:22           ` Sergey Ryazanov
2024-11-21 21:23             ` Antonio Quartulli
2024-11-23 21:05               ` Sergey Ryazanov
2024-11-10 19:52   ` Sergey Ryazanov
2024-11-14 14:55     ` Antonio Quartulli
2024-11-20 11:56   ` Sabrina Dubroca
2024-11-21 21:27     ` Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 07/23] ovpn: introduce the ovpn_socket object Antonio Quartulli
2024-11-10 18:26   ` Sergey Ryazanov
2024-11-15 14:28     ` Antonio Quartulli
2024-11-19 13:44       ` Antonio Quartulli
2024-11-20 23:34         ` Sergey Ryazanov
2024-11-21 21:29           ` Antonio Quartulli
2024-11-20 23:58       ` Sergey Ryazanov
2024-11-21 21:36         ` Antonio Quartulli
2024-11-22  8:08           ` Sergey Ryazanov
2024-10-29 10:47 ` [PATCH net-next v11 08/23] ovpn: implement basic TX path (UDP) Antonio Quartulli
2024-10-30 17:14   ` Sabrina Dubroca
2024-10-30 20:58     ` Antonio Quartulli
2024-11-10 22:32   ` Sergey Ryazanov
2024-11-12 17:28     ` Sabrina Dubroca
2024-11-14 15:25     ` Antonio Quartulli
2024-11-10 23:54   ` Sergey Ryazanov
2024-11-15 14:39     ` Antonio Quartulli
2024-11-21  0:29       ` Sergey Ryazanov
2024-11-21 21:39         ` Antonio Quartulli
2024-11-20 11:45   ` Sabrina Dubroca
2024-11-21 21:41     ` Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 09/23] ovpn: implement basic RX " Antonio Quartulli
2024-10-31 11:29   ` Sabrina Dubroca
2024-10-31 13:04     ` Antonio Quartulli
2024-11-11  1:54   ` Sergey Ryazanov
2024-11-15 15:02     ` Antonio Quartulli
2024-11-26  0:32       ` Sergey Ryazanov
2024-11-26  8:49         ` Antonio Quartulli
2024-11-27  1:40           ` Antonio Quartulli
2024-11-29 13:20             ` Sabrina Dubroca
2024-12-01 23:34               ` Antonio Quartulli
2024-11-29 16:10         ` Sabrina Dubroca
2024-12-01 23:39           ` Antonio Quartulli
2024-12-02  3:53           ` Antonio Quartulli
2024-11-12  0:16   ` Sergey Ryazanov
2024-11-15 15:05     ` Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 10/23] ovpn: implement packet processing Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 11/23] ovpn: store tunnel and transport statistics Antonio Quartulli
2024-10-31 11:37   ` Sabrina Dubroca
2024-10-31 13:12     ` Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 12/23] ovpn: implement TCP transport Antonio Quartulli
2024-10-31 14:30   ` Antonio Quartulli
2024-10-31 15:25   ` Sabrina Dubroca [this message]
2024-11-16  0:33     ` Antonio Quartulli
2024-11-26  1:05       ` Sergey Ryazanov
2024-11-26  8:51         ` Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 13/23] ovpn: implement multi-peer support Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 14/23] ovpn: implement peer lookup logic Antonio Quartulli
2024-11-04 11:26   ` Sabrina Dubroca
2024-11-12  1:18     ` Sergey Ryazanov
2024-11-12 12:32       ` Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 15/23] ovpn: implement keepalive mechanism Antonio Quartulli
2024-11-05 18:10   ` Sabrina Dubroca
2024-11-12 13:20     ` Antonio Quartulli
2024-11-13 10:36       ` Sabrina Dubroca
2024-11-14  8:12         ` Antonio Quartulli
2024-11-14  9:03           ` Sabrina Dubroca
2024-11-22  9:41       ` Antonio Quartulli
2024-11-22 16:18         ` Sabrina Dubroca
2024-11-24  0:28           ` Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 16/23] ovpn: add support for updating local UDP endpoint Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 17/23] ovpn: add support for peer floating Antonio Quartulli
2024-11-04 11:24   ` Sabrina Dubroca
2024-11-12 13:52     ` Antonio Quartulli
2024-11-12 10:56   ` Sabrina Dubroca
2024-11-12 14:03     ` Antonio Quartulli
2024-11-13 11:25       ` Sabrina Dubroca
2024-11-14  8:26         ` Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 18/23] ovpn: implement peer add/get/dump/delete via netlink Antonio Quartulli
2024-11-04 15:14   ` Sabrina Dubroca
2024-11-12 14:19     ` Antonio Quartulli
2024-11-13 16:56       ` Sabrina Dubroca
2024-11-14  9:21         ` Antonio Quartulli
2024-11-20 11:12           ` Sabrina Dubroca
2024-11-20 11:34             ` Antonio Quartulli
2024-11-20 12:10               ` Sabrina Dubroca
2024-11-11 15:41   ` Sabrina Dubroca
2024-11-12 14:26     ` Antonio Quartulli
2024-11-13 11:05       ` Sabrina Dubroca
2024-11-14 10:32         ` Antonio Quartulli
2024-11-29 17:00           ` Sabrina Dubroca
2024-12-01 23:43             ` Antonio Quartulli
2024-11-21 16:02   ` Sabrina Dubroca
2024-11-21 21:43     ` Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 19/23] ovpn: implement key add/get/del/swap " Antonio Quartulli
2024-11-05 10:16   ` Sabrina Dubroca
2024-11-12 15:40     ` Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 20/23] ovpn: kill key and notify userspace in case of IV exhaustion Antonio Quartulli
2024-11-05 10:33   ` Sabrina Dubroca
2024-11-12 15:44     ` Antonio Quartulli
2024-11-13 14:28       ` Sabrina Dubroca
2024-11-14 10:38         ` Antonio Quartulli
2024-11-20 12:17           ` Sabrina Dubroca
2024-10-29 10:47 ` [PATCH net-next v11 21/23] ovpn: notify userspace when a peer is deleted Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 22/23] ovpn: add basic ethtool support Antonio Quartulli
2024-10-29 10:47 ` [PATCH net-next v11 23/23] testing/selftests: add test tool and scripts for ovpn module Antonio Quartulli
2024-10-31 10:00 ` [PATCH net-next v11 00/23] Introducing OpenVPN Data Channel Offload Antonio Quartulli
2024-11-01  2:12   ` Jakub Kicinski
2024-11-01  2:20 ` patchwork-bot+netdevbpf
2024-11-06  1:18 ` Sergey Ryazanov
2024-11-14 15:33   ` Antonio Quartulli
2024-11-14 22:10     ` Sergey Ryazanov
2024-11-15 15:08       ` Antonio Quartulli

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ZyOhe3yKTiqCF2TH@hog \
    --to=sd@queasysnail.net \
    --cc=andrew@lunn.ch \
    --cc=antonio@openvpn.net \
    --cc=donald.hunter@gmail.com \
    --cc=edumazet@google.com \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=ryazanov.s.a@gmail.com \
    --cc=shuah@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.