On 2026-04-19 18:45, Atanas Vladimirov wrote:
On 2026-04-19 12:53, Alexandr Nedvedicky wrote:
Hello,

I agree this is a bug.

On Sat, Apr 18, 2026 at 08:33:44PM +0300, Atanas Vladimirov wrote:
</snip>

Index: sys/net/pf_if.c
===================================================================
--- sys/net/pf_if.c
+++ sys/net/pf_if.c
@@ -852,8 +852,17 @@ pfi_set_flags(const char *name, int flags)
             } else
                 panic("%s pfi_kif_get() returned NULL\n",
                     __func__);
-        } else
+        } else {
             p->pfik_flags_new = p->pfik_flags | flags;
+            /*
+             * The kif already existed (created by
+             * pfi_attach_ifnet()/pfi_attach_ifgroup()).  Take a
+             * flag ref so it survives a transient disappearance
+             * of the backing ifnet/ifgroup, e.g. vmd(8) destroying
+             * and recreating tap(4) across a VM reboot.
+             */
+            if (ISSET(flags, PFI_IFLAG_SKIP) &&
+                p->pfik_flagrefs == 0)
+                pfi_kif_ref(p, PFI_KIF_REF_FLAG);
+        }
     } else {
         RB_FOREACH(p, pfi_ifhead, &pfi_ifs)
             p->pfik_flags_new = p->pfik_flags | flags;


however diff above triggered an assert() on one of my test boxes:

kernel diagnostic assertion "(p->pfik_flagrefs == 0) || (p->pfik_flagref s == 1)" failed: file "/home/sashan/src.sashan/sys/net/pf_if.c", line 901
    Stopped at      db_enter+0x14:  popq    %rbp
        TID    PID    UID     PRFLAGS     PFLAGS  CPU  COMMAND
    * 30662  18016      0         0x3          0    0K pfctl
    db_enter() at db_enter+0x14
    panic(ffffffff82672a84) at panic+0xd5
__assert(ffffffff826aeb78,ffffffff8270f923,385,ffffffff82628d6b) at __assert+0x
    29
    pfi_clear_flags(ffff80001c8d6200,100) at pfi_clear_flags+0x206
pfioctl(14900,c028445a,ffff80001c8d6200,3,ffff80001c7f14d8) at pfioctl+0xe0f VOP_IOCTL(fffffd802b6e6cd0,c028445a,ffff80001c8d6200,3,fffffd8004ffda90,ffff800
    01c7f14d8) at VOP_IOCTL+0x60
vn_ioctl(fffffd802909ebd0,c028445a,ffff80001c8d6200,ffff80001c7f14d8) at vn_ioc
    tl+0x86
sys_ioctl(ffff80001c7f14d8,ffff80001c8d63b0,ffff80001c8d6330) at sys_ioctl+0x30
    e
    syscall(ffff80001c8d63b0) at syscall+0x5f9
    Xsyscall() at Xsyscall+0x128

the /etc/pf.conf on that test box contained two 'set skip on' statements
for lo0 interface. Diff below avoids the assert on that box.

Taking a closer look at pfi_set_flags() function I think the branch
with RB_FOREACH() should be removed. The pfctl(8) always fills name
so that code is never reached on behalf of pfctl. Also the RB_FOREACH()
loop body suffers from the same bug we attempt to fix here.

OK ?

Thanks, Alexandr!

I'll try to test your diff and report back.

I confirm that the patch works as it should.
The tap group and tap0 are skipped and the VM gets
dhcp lease immediately on boot.

Once again thanks for your effort!

Best wishes,
Atanas



thanks and
regards
sashan

--------8<---------------8<---------------8<------------------8<--------
diff --git a/sys/net/pf_if.c b/sys/net/pf_if.c
index 0c6681e757e..bba7237c904 100644
--- a/sys/net/pf_if.c
+++ b/sys/net/pf_if.c
@@ -854,8 +854,22 @@ pfi_set_flags(const char *name, int flags)
                        } else
                                panic("%s pfi_kif_get() returned NULL\n",
                                    __func__);
-               } else
+               } else {
+                       /*
+                        * pf.conf may accidentally contain two set skip on ...
+                        * statements. For example:
+                        *     set skip lo
+                        *     set skip lo
+                        * We need to grab reference only when skip flag is
+                        * set to avoid tripping assert pfi_clear_flags()
+                        */
+                       if (ISSET(flags, PFI_IFLAG_SKIP) &&
+                           !ISSET(p->pfik_flags_new, PFI_IFLAG_SKIP) &&
+                           !ISSET(p->pfik_flags, PFI_IFLAG_SKIP))
+                               pfi_kif_ref(p, PFI_KIF_REF_FLAG);
+
                        p->pfik_flags_new = p->pfik_flags | flags;
+               }
        } else {
                RB_FOREACH(p, pfi_ifhead, &pfi_ifs)
                        p->pfik_flags_new = p->pfik_flags | flags;

Reply via email to