Netdev List
 help / color / mirror / Atom feed
From: "Alexei Starovoitov" <alexei.starovoitov@gmail.com>
To: "Jakub Kicinski" <kuba@kernel.org>
Cc: "Rongguang Wei" <clementwei90@163.com>, <netdev@vger.kernel.org>,
	<bpf@vger.kernel.org>, <willemdebruijn.kernel@gmail.com>,
	<jasowangio@gmail.com>, <andrew+netdev@lunn.ch>,
	<davem@davemloft.net>, <daniel@iogearbox.net>,
	<andrii@kernel.org>, <eddyz87@gmail.com>,
	"Rongguang Wei" <weirongguang@kylinos.cn>,
	"Willem de Bruijn" <willemb@google.com>
Subject: Re: [PATCH net v10 1/2] tun: keep a kernel copy of the socket filter program
Date: Sat, 14 Nov 2026 01:25:08 +0000	[thread overview]
Message-ID: <DMUJISP1U0SF.2VE8F3IUBU0F0@gmail.com> (raw)
In-Reply-To: <20261113162751.309d3544@kernel.org>

On Fri, Nov 13, 2026 at 04:27 PM Jakub Kicinski <kuba@kernel.org> wrote:
> Alexei, would you mind glancing over this one?
> Nothing stands out but the net/core/filter.c changes deserve a BPF ack.
> (Or feel free to take it via bpf if you prefer.)

Ohh. Thanks for flagging. I completely missed it,
since it was '[PATCH net] tun: ..' I didn't notice that it touches key sk_filter pieces.

And, yeah, I don't like it.
It exports too much bpf internal stuff into tun device.
Here is an alternative that my bot came up with and
imo it's much better.
Especially the part where EXPORT_SYMBOLs are removed.

pw-bot: cr

The diff is on top of bpf-next. It builds, and that is as far as I took it.

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index dcec731..324acba 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -142,6 +142,7 @@ struct tun_file {
 	struct napi_struct napi;
 	bool napi_enabled;
 	bool napi_frags_enabled;
+	bool nofilter;			/* attached with IFF_NOFILTER */
 	struct mutex napi_mutex;	/* Protects access to the above napi */
 	struct list_head next;
 	struct tun_struct *detached;
@@ -176,7 +177,7 @@ struct tun_prog {
 };

 /* Since the socket were moved to tun_file, to preserve the behavior of persist
- * device, socket filter, sndbuf and vnet header size were restore when the
+ * device, sndbuf and vnet header size were restore when the
  * file were attached to a persist device.
  */
 struct tun_struct {
@@ -197,8 +198,6 @@ struct tun_struct {
 	int			sndbuf;
 	struct tap_filter	txflt;
 	struct sock_fprog	fprog;
-	/* protected by rtnl lock */
-	bool			filter_attached;
 	u32			msg_enable;
 	spinlock_t lock;
 	struct hlist_head flows[TUN_NUM_FLOW_ENTRIES];
@@ -213,6 +212,7 @@ struct tun_struct {
 	struct bpf_prog __rcu *xdp_prog;
 	struct tun_prog __rcu *steering_prog;
 	struct tun_prog __rcu *filter_prog;
+	struct tun_prog __rcu *cbpf_prog;
 	struct ethtool_link_ksettings link_ksettings;
 	/* init args */
 	struct file *file;
@@ -756,15 +756,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
 		goto out;

 	err = 0;
-
-	/* Re-attach the filter to persist device */
-	if (!skip_filter && (tun->filter_attached == true)) {
-		lock_sock(tfile->socket.sk);
-		err = sk_attach_filter(&tun->fprog, tfile->socket.sk);
-		release_sock(tfile->socket.sk);
-		if (!err)
-			goto out;
-	}
+	tfile->nofilter = skip_filter;

 	if (!tfile->detached &&
 	    ptr_ring_resize(&tfile->tx_ring, dev->tx_queue_len,
@@ -1071,6 +1063,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
 	int txq = skb->queue_mapping;
 	struct netdev_queue *queue;
 	struct tun_file *tfile;
+	struct tun_prog *prog;
 	int len = skb->len;
 	int ret;

@@ -1096,10 +1089,13 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
 		goto drop;
 	}

-	if (tfile->socket.sk->sk_filter) {
-		drop_reason = sk_filter_reason(tfile->socket.sk, skb);
-		if (drop_reason)
+	prog = rcu_dereference(tun->cbpf_prog);
+	if (prog && !READ_ONCE(tfile->nofilter)) {
+		len = bpf_prog_run_clear_cb(prog->prog, skb);
+		if (len == 0 || pskb_trim(skb, len)) {
+			drop_reason = SKB_DROP_REASON_SOCKET_FILTER;
 			goto drop;
+		}
 	}

 	len = run_ebpf_filter(tun, skb, len);
@@ -2410,6 +2406,7 @@ static void tun_free_netdev(struct net_device *dev)
 	security_tun_dev_free_security(tun->security);
 	__tun_set_ebpf(tun, &tun->steering_prog, NULL);
 	__tun_set_ebpf(tun, &tun->filter_prog, NULL);
+	__tun_set_ebpf(tun, &tun->cbpf_prog, NULL);
 }

 static void tun_setup(struct net_device *dev)
@@ -2964,7 +2961,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 		tun->vnet_hdr_sz = sizeof(struct virtio_net_hdr);

 		tun->align = NET_SKB_PAD;
-		tun->filter_attached = false;
 		tun->sndbuf = tfile->socket.sk->sk_sndbuf;
 		tun->rx_batched = 0;
 		RCU_INIT_POINTER(tun->steering_prog, NULL);
@@ -3068,39 +3064,34 @@ static int set_offload(struct tun_struct *tun, unsigned long arg)
 	return 0;
 }

-static void tun_detach_filter(struct tun_struct *tun, int n)
+static int tun_attach_filter(struct tun_struct *tun, void __user *data)
 {
-	int i;
+	struct sock_fprog fprog;
 	struct tun_file *tfile;
+	struct bpf_prog *prog;
+	int i, ret;

-	for (i = 0; i < n; i++) {
-		tfile = rtnl_dereference(tun->tfiles[i]);
-		lock_sock(tfile->socket.sk);
-		sk_detach_filter(tfile->socket.sk);
-		release_sock(tfile->socket.sk);
-	}
+	if (copy_from_user(&fprog, data, sizeof(fprog)))
+		return -EFAULT;

-	tun->filter_attached = false;
-}
+	ret = bpf_prog_create_from_user(&prog, &fprog, NULL, false);
+	if (ret)
+		return ret;

-static int tun_attach_filter(struct tun_struct *tun)
-{
-	int i, ret = 0;
-	struct tun_file *tfile;
+	ret = __tun_set_ebpf(tun, &tun->cbpf_prog, prog);
+	if (ret) {
+		bpf_prog_destroy(prog);
+		return ret;
+	}

 	for (i = 0; i < tun->numqueues; i++) {
 		tfile = rtnl_dereference(tun->tfiles[i]);
-		lock_sock(tfile->socket.sk);
-		ret = sk_attach_filter(&tun->fprog, tfile->socket.sk);
-		release_sock(tfile->socket.sk);
-		if (ret) {
-			tun_detach_filter(tun, i);
-			return ret;
-		}
+		WRITE_ONCE(tfile->nofilter, false);
 	}

-	tun->filter_attached = true;
-	return ret;
+	/* Only TUNGETFILTER reads it */
+	tun->fprog = fprog;
+	return 0;
 }

 static void tun_set_sndbuf(struct tun_struct *tun)
@@ -3296,7 +3287,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,

 		if (tfile->detached)
 			ifr.ifr_flags |= IFF_DETACH_QUEUE;
-		if (!tfile->socket.sk->sk_filter)
+		if (tfile->nofilter || !rcu_access_pointer(tun->cbpf_prog))
 			ifr.ifr_flags |= IFF_NOFILTER;

 		if (copy_to_user(argp, &ifr, ifreq_len))
@@ -3439,11 +3430,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
 		ret = -EINVAL;
 		if ((tun->flags & TUN_TYPE_MASK) != IFF_TAP)
 			break;
-		ret = -EFAULT;
-		if (copy_from_user(&tun->fprog, argp, sizeof(tun->fprog)))
-			break;
-
-		ret = tun_attach_filter(tun);
+		ret = tun_attach_filter(tun, argp);
 		break;

 	case TUNDETACHFILTER:
@@ -3451,8 +3438,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
 		ret = -EINVAL;
 		if ((tun->flags & TUN_TYPE_MASK) != IFF_TAP)
 			break;
-		ret = 0;
-		tun_detach_filter(tun, tun->numqueues);
+		ret = __tun_set_ebpf(tun, &tun->cbpf_prog, NULL);
 		break;

 	case TUNGETFILTER:
diff --git a/net/core/filter.c b/net/core/filter.c
index 9245009..1c742f2 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -1565,7 +1565,6 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)

 	return 0;
 }
-EXPORT_SYMBOL_GPL(sk_attach_filter);

 int sk_reuseport_attach_filter(struct sock_fprog *fprog, struct sock *sk)
 {
@@ -11779,7 +11778,6 @@ int sk_detach_filter(struct sock *sk)

 	return ret;
 }
-EXPORT_SYMBOL_GPL(sk_detach_filter);

 int sk_get_filter(struct sock *sk, sockptr_t optval, unsigned int len)
 {

  reply	other threads:[~2026-11-14  1:25 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-09  2:38 [PATCH net v10 0/2] tun: fix re-attaching the socket filter Rongguang Wei
2026-11-09  2:38 ` [PATCH net v10 1/2] tun: keep a kernel copy of the socket filter program Rongguang Wei
2026-11-11 20:41   ` netdev-bot+sashiko
2026-11-12  1:40     ` weirongguang
2026-11-14  0:27   ` Jakub Kicinski
2026-11-14  1:25     ` Alexei Starovoitov [this message]
2026-11-09  2:38 ` [PATCH net v10 2/2] selftests: net: add TAP socket filter attach tests Rongguang Wei
  -- strict thread matches above, loose matches on Subject: below --
2026-11-09  2:37 [PATCH net v10 0/2] tun: fix re-attaching the socket filter Rongguang Wei
2026-11-09  2:37 ` [PATCH net v10 1/2] tun: keep a kernel copy of the socket filter program Rongguang Wei

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=DMUJISP1U0SF.2VE8F3IUBU0F0@gmail.com \
    --to=alexei.starovoitov@gmail.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=andrii@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=clementwei90@163.com \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=eddyz87@gmail.com \
    --cc=jasowangio@gmail.com \
    --cc=kuba@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=weirongguang@kylinos.cn \
    --cc=willemb@google.com \
    --cc=willemdebruijn.kernel@gmail.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox