M2: live netfilter data path (pf_test per direction), pfattach bring-up, NET_LOCK reentrancy fix, static pfctl

- pfk_hooks: PRE→PF_IN, LOCAL_OUT/POST→PF_OUT v4+v6; replacement/buffer
  handling with NF_STOLEN + re-injection (documented divergence: re-entry)
- pfk_mod: pf_status_init/pfattach + pfi attach via pfk_if event callback
- pfk_kern: NET_LOCK holder reentrancy (fix deadlock when notifier fires
  under the write lock — observed as full-VM network hang)
- tools: static pfctl link for musl VMs
This commit is contained in:
lgcosta committed 2026-11-11 15:20:01 -03:00
1 parent 0119e70960
commit 5323ee2c71
49 files changed
+20028 -28

No files matched your search

+14
View File
@@ -0,0 +1,14 @@
/* PFLINUX: <sys/_null.h> — OpenBSD's NULL guard header, required by the
* vendored <sys/queue.h> and <sys/tree.h>. */
#ifndef _PFLINUX_SYS__NULL_H
#define _PFLINUX_SYS__NULL_H
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
#endif /* _PFLINUX_SYS__NULL_H */
+45
View File
@@ -0,0 +1,45 @@
/* PFLINUX: <sys/ioctl.h> — OpenBSD 8.0 ioctl encoding for userland pfctl.
*
* net/pfvar.h builds every DIOC* number with _IO/_IOW/_IOR/_IOWR. pf.ko
* (see module/include/pfk.h) interprets ioctl commands using the OpenBSD
* sys/ioccom.h bit layout, NOT Linux asm/ioctl.h, so this header must
* reproduce pfk.h's PFKXIOC_* encoding byte-for-byte. We pull in the real
* glibc <sys/ioctl.h> first (ioctl(2) prototype, Linux SIOC* constants used
* by <net/if.h>) and then redefine the _IO family.
*
* Values copied from module/include/pfk.h lines 135-152.
*/
#ifndef _PFLINUX_SYS_IOCTL_H
#define _PFLINUX_SYS_IOCTL_H
#include_next <sys/ioctl.h>
#include <sys/types.h>
#undef _IO
#undef _IOR
#undef _IOW
#undef _IOWR
#define PFKXIOC_NRBITS 8
#define PFKXIOC_TYPEBITS 8
#define PFKXIOC_SIZEBITS 13
#define PFKXIOC_DIRBITS 2
#define PFKXIOC_NRSHIFT 0
#define PFKXIOC_TYPESHIFT (PFKXIOC_NRSHIFT + PFKXIOC_NRBITS)
#define PFKXIOC_SIZESHIFT (PFKXIOC_TYPESHIFT + PFKXIOC_TYPEBITS)
#define PFKXIOC_DIRSHIFT (PFKXIOC_SIZESHIFT + PFKXIOC_SIZEBITS + 1)
#define PFKXIOC_NONE 0U
#define PFKXIOC_WRITE 1U /* OpenBSD IOC_IN (copyin) */
#define PFKXIOC_READ 2U /* OpenBSD IOC_OUT (copyout) */
#define PFKXIOC(dir,type,nr,size) \
(((dir) << PFKXIOC_DIRSHIFT) | ((type) << PFKXIOC_TYPESHIFT) | \
((nr) << PFKXIOC_NRSHIFT) | ((size) << PFKXIOC_SIZESHIFT))
#define _IO(t, n) PFKXIOC(PFKXIOC_NONE, (t), (n), 0)
#define _IOWR(t, n, s) PFKXIOC(PFKXIOC_WRITE|PFKXIOC_READ, (t), (n), sizeof(s))
#define _IOW(t, n, s) PFKXIOC(PFKXIOC_WRITE, (t), (n), sizeof(s))
#define _IOR(t, n, s) PFKXIOC(PFKXIOC_READ, (t), (n), sizeof(s))
#endif /* _PFLINUX_SYS_IOCTL_H */
+63
View File
@@ -0,0 +1,63 @@
/* PFLINUX: <sys/refcnt.h> — userland twin of
* module/include/compat/sys/refcnt.h. The kernel side is
* `struct refcnt { refcount_t rc; }` where refcount_t wraps a single
* atomic_t (4 bytes on Linux). Only struct pf_anchor embeds it and
* pf_anchor never crosses /dev/pf, but size/alignment are kept equal. */
#ifndef _PFLINUX_SYS_REFCNT_H
#define _PFLINUX_SYS_REFCNT_H
#include <sys/types.h>
struct refcnt {
unsigned int rc;
};
#define REFCNT_INITIALIZER { .rc = 1 }
static inline void
refcnt_init(struct refcnt *r, unsigned int v)
{
r->rc = v ? v : 1;
}
static inline unsigned int
refcnt_value(const struct refcnt *r)
{
return (r->rc);
}
static inline void
refcnt_take(struct refcnt *r)
{
r->rc++;
}
static inline int
refcnt_take_not0(struct refcnt *r)
{
if (r->rc == 0)
return (0);
r->rc++;
return (1);
}
static inline unsigned int
refcnt_rele(struct refcnt *r)
{
return (--r->rc);
}
static inline unsigned int
refcnt_rele_wake(struct refcnt *r)
{
return (refcnt_rele(r));
}
static inline void
refcnt_finalize(struct refcnt *r, const void *unused)
{
(void)r;
(void)unused;
}
#endif /* _PFLINUX_SYS_REFCNT_H */
+28
View File
@@ -0,0 +1,28 @@
/* PFLINUX: <sys/sysctl.h> — OpenBSD sysctl(3) surface used by pfctl.
* Linux removed both <sys/sysctl.h> and the legacy sysctl(2) syscall; the
* constants below mirror OpenBSD 8.0 (sys/sysctl.h) and sysctl() is
* implemented in tools/compat-user/sysctl.c for exactly the three MIBs
* pfctl queries. */
#ifndef _PFLINUX_SYS_SYSCTL_H
#define _PFLINUX_SYS_SYSCTL_H
#include <sys/types.h>
#include <stddef.h>
#define CTL_UNSPEC 0
#define CTL_KERN 1
#define CTL_VM 2
#define CTL_NET 4 /* PF_ROUTE etc. */
#define CTL_HW 6
#define KERN_MAXCLUSTERS 67 /* int: mbuf cluster limit */
#define HW_PHYSMEM64 19 /* int64_t: total RAM */
struct kinfo_proc; /* forward: nothing pfctl uses, avoid clash */
__BEGIN_DECLS
int sysctl(const int *name, u_int namelen, void *old, size_t *oldlenp,
const void *new, size_t newlen);
__END_DECLS
#endif /* _PFLINUX_SYS_SYSCTL_H */
+8
View File
@@ -0,0 +1,8 @@
/* PFLINUX: <sys/syslimits.h> — glibc ships no such header; PATH_MAX etc.
* live in <limits.h>. */
#ifndef _PFLINUX_SYS_SYSLIMITS_H
#define _PFLINUX_SYS_SYSLIMITS_H
#include <limits.h>
#endif /* _PFLINUX_SYS_SYSLIMITS_H */
+18
View File
@@ -0,0 +1,18 @@
/* PFLINUX: <sys/timeout.h> — pfvar.h embeds struct timeout by value inside
* struct pf_pktdelay. pf_pktdelay is kernel-internal only (it never
* appears in any ioctl payload; the kernel side uses the real
* module/include/compat/sys/timeout.h with linux/timer.h), so userland
* just needs the type to be complete for pfvar.h to compile. */
#ifndef _PFLINUX_SYS_TIMEOUT_H
#define _PFLINUX_SYS_TIMEOUT_H
#include <sys/types.h>
typedef void (timeout_fn)(void *);
struct timeout {
timeout_fn *fn;
void *arg;
};
#endif /* _PFLINUX_SYS_TIMEOUT_H */