Netdev List
 help / color / mirror / Atom feed
* [PATCH net v1] tun: fix inverted error check when re-attaching the filter
@ 2026-09-23  2:56 Rongguang Wei
  2026-09-24 17:59 ` netdev-bot+sashiko
  0 siblings, 1 reply; 4+ messages in thread
From: Rongguang Wei @ 2026-09-23  2:56 UTC (permalink / raw)
  To: netdev
  Cc: willemdebruijn.kernel, jasowangio, andrew+netdev, davem,
	Rongguang Wei

From: Rongguang Wei <weirongguang@kylinos.cn>

tun_attach() return when sk_attach_filter() succeeds instead of when it
fails, so the queue is never published in tun->tfiles[] while TUNSETIFF
still reports success.

Invert the check; nothing is published at that point, so the attach can be
aborted cleanly.

Fixes: 54f968d6efdb ("tuntap: move socket to tun_file")
Signed-off-by: Rongguang Wei <weirongguang@kylinos.cn>
---
 drivers/net/tun.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 5a302709a68a..09720883b9a1 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -754,7 +754,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
 		lock_sock(tfile->socket.sk);
 		err = sk_attach_filter(&tun->fprog, tfile->socket.sk);
 		release_sock(tfile->socket.sk);
-		if (!err)
+		if (err)
 			goto out;
 	}
 
-- 
2.25.1


No virus found
		Checked by Hillstone Network AntiVirus


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH net v1] tun: fix inverted error check when re-attaching the filter
  2026-09-23  2:56 [PATCH net v1] tun: fix inverted error check when re-attaching the filter Rongguang Wei
@ 2026-09-24 17:59 ` netdev-bot+sashiko
  2026-09-25 17:15   ` Willem de Bruijn
  0 siblings, 1 reply; 4+ messages in thread
From: netdev-bot+sashiko @ 2026-09-24 17:59 UTC (permalink / raw)
  To: clementwei90
  Cc: netdev, willemdebruijn.kernel, jasowangio, andrew+netdev, davem,
	weirongguang, kuba

Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider.

Critical: 0 · High: 0 · Medium: 1 · Low: 1

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [Medium] The re-attach path that this patch enables rebuilds the queue
  filter from a stale userspace pointer, and reads it in the wrong…
- [Low] With the check inverted, a successful sk_attach_filter() in
  tun_attach() (drivers/net/tun.c:755) no longer returns early.

--

tun: fix inverted error check when re-attaching the filter

This patch inverts the error check after sk_attach_filter() in
tun_attach(). A successful filter re-attach now continues on to publish
the queue, and a failed one aborts the attach.

> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index 5a302709a68aa..09720883b9a10 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -754,7 +754,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
>  		lock_sock(tfile->socket.sk);
>  		err = sk_attach_filter(&tun->fprog, tfile->socket.sk);
>  		release_sock(tfile->socket.sk);
> -		if (!err)
> +		if (err)
>  			goto out;
>  	}
>  

[Severity: Low]
A successful sk_attach_filter() now falls through. If a later step in
tun_attach() fails, can the filter stay attached to a socket that was
never published?

After this point, tun_attach() can still fail here:

	if (!tfile->detached &&
	    ptr_ring_resize(&tfile->tx_ring, dev->tx_queue_len,
			    GFP_KERNEL, tun_ptr_free)) {
		err = -ENOMEM;
		goto out;
	}

It can also fail in xdp_rxq_info_reg() or xdp_rxq_info_reg_mem_model().
None of these error paths call sk_detach_filter(tfile->socket.sk).

By comparison, tun_attach_filter() rolls back when it fails:

		if (ret) {
			tun_detach_filter(tun, i);
			return ret;
		}

The fd can then be reused. One way is to retry TUNSETIFF with
IFF_NOFILTER, which sets skip_filter and skips the re-attach block.
Another is to attach to a different device that has no filter. Neither
clears sk_filter, since only tun_detach_filter() calls sk_detach_filter().

tun_net_xmit() would then apply the leftover filter to packets:

	if (tfile->socket.sk->sk_filter) {
		drop_reason = sk_filter_reason(tfile->socket.sk, skb);

TUNGETIFF would also leave IFF_NOFILTER unset, even though it was
requested.

The commit message says "nothing is published at that point, so the
attach can be aborted cleanly". Is that only true when sk_attach_filter()
itself is the step that fails?

[Severity: Medium]
This path now installs the rebuilt filter on a live queue. Is
tun->fprog still safe to reuse at this point?

TUNATTACHFILTER in __tun_chr_ioctl() copies only the sock_fprog header:

		if (copy_from_user(&tun->fprog, argp, sizeof(tun->fprog)))
			break;

That leaves tun->fprog.filter as a __user pointer from the process that
issued the ioctl. On a persistent device, tun->filter_attached stays true
after all queues are closed.

Later calls reach the re-attach through this path. That includes
TUNSETIFF without IFF_NOFILTER, and TUNSETQUEUE with IFF_ATTACH_QUEUE,
which always passes skip_filter = false:

tun_set_iff() / tun_set_queue()
  tun_attach()
    sk_attach_filter(&tun->fprog, sk)
      __get_filter()
        copy_from_user(prog->insns, fprog->filter, fsize)

That read goes through current->mm. The caller may be a different process
from the one that set the filter. It may also be the same process after
the instruction buffer was freed or remapped.

Before this patch, the rebuilt filter never ended up on a working queue.
When the re-attach succeeded, the queue was not published. When it failed,
the queue was published without a filter and TUNSETIFF returned 0.

With the check inverted, there are two cases.

If the address is not mapped in the caller, TUNSETIFF and TUNSETQUEUE
now fail with -EFAULT. If the bytes there are not valid classic BPF, they
fail with -EINVAL. Does this mean a new opener of a persistent TAP with a
filter can no longer attach unless it passes IFF_NOFILTER?

If the address happens to be mapped, whatever bytes it holds become the
queue's filter, not the program the administrator installed. On a
multiqueue TAP, could different queues end up with different filters?

For this re-attach to work correctly, would it need a kernel-owned copy?
That could be a saved copy of the instructions, or a refcounted struct
bpf_prog or sk_filter.

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260923025653.59348-1-clementwei90%40163.com

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH net v1] tun: fix inverted error check when re-attaching the filter
  2026-09-24 17:59 ` netdev-bot+sashiko
@ 2026-09-25 17:15   ` Willem de Bruijn
  2026-09-28  2:02     ` Rongguang Wei
  0 siblings, 1 reply; 4+ messages in thread
From: Willem de Bruijn @ 2026-09-25 17:15 UTC (permalink / raw)
  To: netdev-bot+sashiko, clementwei90
  Cc: netdev, willemdebruijn.kernel, jasowangio, andrew+netdev, davem,
	weirongguang, kuba

netdev-bot+sashiko@ wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential
> issue(s) to consider.
> 
> Critical: 0 · High: 0 · Medium: 1 · Low: 1
> 
> If you believe none of the issues are legitimate, please reply to each
> issue of Medium severity or higher and explain why the AI is wrong.
> If any of them are legitimate and you plan to respin, please let patchwork
> know by including "pw-bot: cr" as a separate line at the end of your reply
> (one such reply per series is enough).
> 
> - [Medium] The re-attach path that this patch enables rebuilds the queue
>   filter from a stale userspace pointer, and reads it in the wrong…
> - [Low] With the check inverted, a successful sk_attach_filter() in
>   tun_attach() (drivers/net/tun.c:755) no longer returns early.
> 
> --
> 
> tun: fix inverted error check when re-attaching the filter
> 
> This patch inverts the error check after sk_attach_filter() in
> tun_attach(). A successful filter re-attach now continues on to publish
> the queue, and a failed one aborts the attach.
> 
> > diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> > index 5a302709a68aa..09720883b9a10 100644
> > --- a/drivers/net/tun.c
> > +++ b/drivers/net/tun.c
> > @@ -754,7 +754,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
> >  		lock_sock(tfile->socket.sk);
> >  		err = sk_attach_filter(&tun->fprog, tfile->socket.sk);
> >  		release_sock(tfile->socket.sk);
> > -		if (!err)
> > +		if (err)
> >  			goto out;
> >  	}
> >  
> 
> [Severity: Low]
> A successful sk_attach_filter() now falls through. If a later step in
> tun_attach() fails, can the filter stay attached to a socket that was
> never published?
> 
> After this point, tun_attach() can still fail here:
> 
> 	if (!tfile->detached &&
> 	    ptr_ring_resize(&tfile->tx_ring, dev->tx_queue_len,
> 			    GFP_KERNEL, tun_ptr_free)) {
> 		err = -ENOMEM;
> 		goto out;
> 	}
> 
> It can also fail in xdp_rxq_info_reg() or xdp_rxq_info_reg_mem_model().
> None of these error paths call sk_detach_filter(tfile->socket.sk).

This is a real point.

This patch fixes the intent of the original patch by inverting the
check.

But the state change should also be reverted if tun_attach fails later
on. The only similar example is xdp_rxq_info_reg further down, which
does get reverted if xdp_rxq_info_reg_mem_model fails.
 
> By comparison, tun_attach_filter() rolls back when it fails:
> 
> 		if (ret) {
> 			tun_detach_filter(tun, i);
> 			return ret;
> 		}
> 
> The fd can then be reused. One way is to retry TUNSETIFF with
> IFF_NOFILTER, which sets skip_filter and skips the re-attach block.
> Another is to attach to a different device that has no filter. Neither
> clears sk_filter, since only tun_detach_filter() calls sk_detach_filter().
> 
> tun_net_xmit() would then apply the leftover filter to packets:
> 
> 	if (tfile->socket.sk->sk_filter) {
> 		drop_reason = sk_filter_reason(tfile->socket.sk, skb);
> 
> TUNGETIFF would also leave IFF_NOFILTER unset, even though it was
> requested.
> 
> The commit message says "nothing is published at that point, so the
> attach can be aborted cleanly". Is that only true when sk_attach_filter()
> itself is the step that fails?
> 
> [Severity: Medium]
> This path now installs the rebuilt filter on a live queue. Is
> tun->fprog still safe to reuse at this point?
> 
> TUNATTACHFILTER in __tun_chr_ioctl() copies only the sock_fprog header:
> 
> 		if (copy_from_user(&tun->fprog, argp, sizeof(tun->fprog)))
> 			break;
> 
> That leaves tun->fprog.filter as a __user pointer from the process that
> issued the ioctl. On a persistent device, tun->filter_attached stays true
> after all queues are closed.
> 
> Later calls reach the re-attach through this path. That includes
> TUNSETIFF without IFF_NOFILTER, and TUNSETQUEUE with IFF_ATTACH_QUEUE,
> which always passes skip_filter = false:
> 
> tun_set_iff() / tun_set_queue()
>   tun_attach()
>     sk_attach_filter(&tun->fprog, sk)
>       __get_filter()
>         copy_from_user(prog->insns, fprog->filter, fsize)
> 
> That read goes through current->mm. The caller may be a different process
> from the one that set the filter. It may also be the same process after
> the instruction buffer was freed or remapped.

This is a very good point.

It is a separate bug from this one, and should be a separate fix.

The BPF program should be copied into the kernel immediately if it
can be attached again later.

But, as the below text explains, flipping the test may now fail
TUNSETIFF because sk_filter_attach fails, where previously it would
continue since sk_attach_filter error is expected (even if it did
complete without the filter installed as intended). Ideally, both
fixes are sent together, but I won't hold anyone to that.

> 
> Before this patch, the rebuilt filter never ended up on a working queue.
> When the re-attach succeeded, the queue was not published. When it failed,
> the queue was published without a filter and TUNSETIFF returned 0.
> 
> With the check inverted, there are two cases.
> 
> If the address is not mapped in the caller, TUNSETIFF and TUNSETQUEUE
> now fail with -EFAULT. If the bytes there are not valid classic BPF, they
> fail with -EINVAL. Does this mean a new opener of a persistent TAP with a
> filter can no longer attach unless it passes IFF_NOFILTER?
> 
> If the address happens to be mapped, whatever bytes it holds become the
> queue's filter, not the program the administrator installed. On a
> multiqueue TAP, could different queues end up with different filters?
> 
> For this re-attach to work correctly, would it need a kernel-owned copy?
> That could be a saved copy of the instructions, or a refcounted struct
> bpf_prog or sk_filter.
> 
> -- 
> Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260923025653.59348-1-clementwei90%40163.com



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH net v1] tun: fix inverted error check when re-attaching the filter
  2026-09-25 17:15   ` Willem de Bruijn
@ 2026-09-28  2:02     ` Rongguang Wei
  0 siblings, 0 replies; 4+ messages in thread
From: Rongguang Wei @ 2026-09-28  2:02 UTC (permalink / raw)
  To: Willem de Bruijn, netdev-bot+sashiko
  Cc: netdev, jasowangio, andrew+netdev, davem, weirongguang, kuba



on 2026/9/26 01:15, Willem de Bruijn wrote:
> netdev-bot+sashiko@ wrote:
>> Thank you for your contribution! Sashiko AI review found 2 potential
>> issue(s) to consider.
>>
>> Critical: 0 · High: 0 · Medium: 1 · Low: 1
>>
>> If you believe none of the issues are legitimate, please reply to each
>> issue of Medium severity or higher and explain why the AI is wrong.
>> If any of them are legitimate and you plan to respin, please let patchwork
>> know by including "pw-bot: cr" as a separate line at the end of your reply
>> (one such reply per series is enough).
>>
>> - [Medium] The re-attach path that this patch enables rebuilds the queue
>>   filter from a stale userspace pointer, and reads it in the wrong…
>> - [Low] With the check inverted, a successful sk_attach_filter() in
>>   tun_attach() (drivers/net/tun.c:755) no longer returns early.
>>
>> --
>>
>> tun: fix inverted error check when re-attaching the filter
>>
>> This patch inverts the error check after sk_attach_filter() in
>> tun_attach(). A successful filter re-attach now continues on to publish
>> the queue, and a failed one aborts the attach.
>>
>>> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
>>> index 5a302709a68aa..09720883b9a10 100644
>>> --- a/drivers/net/tun.c
>>> +++ b/drivers/net/tun.c
>>> @@ -754,7 +754,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
>>>  		lock_sock(tfile->socket.sk);
>>>  		err = sk_attach_filter(&tun->fprog, tfile->socket.sk);
>>>  		release_sock(tfile->socket.sk);
>>> -		if (!err)
>>> +		if (err)
>>>  			goto out;
>>>  	}
>>>  
>>
>> [Severity: Low]
>> A successful sk_attach_filter() now falls through. If a later step in
>> tun_attach() fails, can the filter stay attached to a socket that was
>> never published?
>>
>> After this point, tun_attach() can still fail here:
>>
>> 	if (!tfile->detached &&
>> 	    ptr_ring_resize(&tfile->tx_ring, dev->tx_queue_len,
>> 			    GFP_KERNEL, tun_ptr_free)) {
>> 		err = -ENOMEM;
>> 		goto out;
>> 	}
>>
>> It can also fail in xdp_rxq_info_reg() or xdp_rxq_info_reg_mem_model().
>> None of these error paths call sk_detach_filter(tfile->socket.sk).
> 
> This is a real point.
> 
> This patch fixes the intent of the original patch by inverting the
> check.
> 
> But the state change should also be reverted if tun_attach fails later
> on. The only similar example is xdp_rxq_info_reg further down, which
> does get reverted if xdp_rxq_info_reg_mem_model fails.
>  
>> By comparison, tun_attach_filter() rolls back when it fails:
>>
>> 		if (ret) {
>> 			tun_detach_filter(tun, i);
>> 			return ret;
>> 		}
>>
>> The fd can then be reused. One way is to retry TUNSETIFF with
>> IFF_NOFILTER, which sets skip_filter and skips the re-attach block.
>> Another is to attach to a different device that has no filter. Neither
>> clears sk_filter, since only tun_detach_filter() calls sk_detach_filter().
>>
>> tun_net_xmit() would then apply the leftover filter to packets:
>>
>> 	if (tfile->socket.sk->sk_filter) {
>> 		drop_reason = sk_filter_reason(tfile->socket.sk, skb);
>>
>> TUNGETIFF would also leave IFF_NOFILTER unset, even though it was
>> requested.
Thank you, v2 will add the missing rollback and detach the filter again if a
later step of tun_attach() fails.
>>
>> The commit message says "nothing is published at that point, so the
>> attach can be aborted cleanly". Is that only true when sk_attach_filter()
>> itself is the step that fails?
You are right and I will drop that sentence and describe the rollback instead.
>>
>> [Severity: Medium]
>> This path now installs the rebuilt filter on a live queue. Is
>> tun->fprog still safe to reuse at this point?
>>
>> TUNATTACHFILTER in __tun_chr_ioctl() copies only the sock_fprog header:
>>
>> 		if (copy_from_user(&tun->fprog, argp, sizeof(tun->fprog)))
>> 			break;
>>
>> That leaves tun->fprog.filter as a __user pointer from the process that
>> issued the ioctl. On a persistent device, tun->filter_attached stays true
>> after all queues are closed.
>>
>> Later calls reach the re-attach through this path. That includes
>> TUNSETIFF without IFF_NOFILTER, and TUNSETQUEUE with IFF_ATTACH_QUEUE,
>> which always passes skip_filter = false:
>>
>> tun_set_iff() / tun_set_queue()
>>   tun_attach()
>>     sk_attach_filter(&tun->fprog, sk)
>>       __get_filter()
>>         copy_from_user(prog->insns, fprog->filter, fsize)
>>
>> That read goes through current->mm. The caller may be a different process
>> from the one that set the filter. It may also be the same process after
>> the instruction buffer was freed or remapped.
> 
> This is a very good point.
> 
> It is a separate bug from this one, and should be a separate fix.
> 
> The BPF program should be copied into the kernel immediately if it
> can be attached again later.
> 
> But, as the below text explains, flipping the test may now fail
> TUNSETIFF because sk_filter_attach fails, where previously it would
> continue since sk_attach_filter error is expected (even if it did
> complete without the filter installed as intended). Ideally, both
> fixes are sent together, but I won't hold anyone to that.
>I intend to send it as a second patch in the series.
>>
>> Before this patch, the rebuilt filter never ended up on a working queue.
>> When the re-attach succeeded, the queue was not published. When it failed,
>> the queue was published without a filter and TUNSETIFF returned 0.
>>
>> With the check inverted, there are two cases.
>>
>> If the address is not mapped in the caller, TUNSETIFF and TUNSETQUEUE
>> now fail with -EFAULT. If the bytes there are not valid classic BPF, they
>> fail with -EINVAL. Does this mean a new opener of a persistent TAP with a
>> filter can no longer attach unless it passes IFF_NOFILTER?
>>
>> If the address happens to be mapped, whatever bytes it holds become the
>> queue's filter, not the program the administrator installed. On a
>> multiqueue TAP, could different queues end up with different filters?
>>
>> For this re-attach to work correctly, would it need a kernel-owned copy?
>> That could be a saved copy of the instructions, or a refcounted struct
>> bpf_prog or sk_filter.>> -- 
>> Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260923025653.59348-1-clementwei90%40163.com
> 
pw-bot: cr


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-09-28  2:02 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-23  2:56 [PATCH net v1] tun: fix inverted error check when re-attaching the filter Rongguang Wei
2026-09-24 17:59 ` netdev-bot+sashiko
2026-09-25 17:15   ` Willem de Bruijn
2026-09-28  2:02     ` Rongguang Wei

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox