https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=298877

            Bug ID: 298877
           Summary: pf: netlink GETRULE drops per-rule timeouts (wrong
                    nested attribute type in nlattr_add_timeout)
           Product: Base System
           Version: 15.1-RELEASE
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: kern
          Assignee: [email protected]
          Reporter: [email protected]
                CC: [email protected]

After I upgraded our first machine from 14.4 to 15.1 I noticed there is some
difference in the output of "pfctl -s rules" - missing "src.track 10". We
noticed this immediately because we compare output of live rule set with the
output of "pfctl -nvf /etc/pf.conf" as the part of the monitoring of the
machine state.

All previous versions of FreeBSD, 14.4 included has the same output but on 15.1
it's different


# pfctl -s rules | grep https
pass in on bge0 inet proto tcp from any to (bge0) port = https flags S/SA keep
state (source-track rule, max-src-conn-rate 100/10, overload <bruteforce> flush
global)

# pfctl -nvf /etc/pf.conf | grep https
pass in on bge0 inet proto tcp from any to (bge0) port = https flags S/SA keep
state (source-track rule, max-src-conn-rate 100/10, overload <bruteforce> flush
global, src.track 10)

I tried to analyze it with the help of LLM with the following result.

=============

Description:

Since FreeBSD 15.0, "pfctl -s rules" no longer shows per-rule timeout
options (e.g. "tcp.established 3600", "src.track 10"), while
"pfctl -nvf pf.conf" does. On 14.x both outputs were identical.

This includes the src.track timeout that pfctl's parser adds implicitly
to every rule with "max-src-conn-rate N/S" (timeout[PFTM_SRC_NODE] = S),
so any rule using max-src-conn-rate now prints differently in the two
commands.

The timeouts are loaded into the kernel correctly; only the read-back
path is broken.

Root cause:

sys/netpfil/pf/pf_nl.c, nlattr_add_timeout() emits the elements of the
nested PF_RT_TIMEOUT attribute with the outer attribute type:

    for (int i = 0; i < PFTM_MAX; i++)
        nlattr_add_u32(nw, PF_RT_TIMEOUT, timeout[i]);

Both parsers of this nested attribute expect PF_TT_TIMEOUT (1), not
PF_RT_TIMEOUT (14):
  - kernel: nla_p_timeouts[] in pf_nl.c (used for ADDRULE)
  - libpfctl: ap_timeouts[] in lib/libpfctl/libpfctl.c (used for GETRULE)
libpfctl's writer, snl_add_msg_attr_timeouts(), correctly uses
PF_TT_TIMEOUT, which is why rule loading works.

On GETRULE, libpfctl silently ignores the unknown type-14 attributes,
all timeouts are read back as 0, and print_rule() omits them.

Present in releng/15.0, releng/15.1, stable/15 and main.

Impact:
  - Scripts comparing the loaded ruleset with "pfctl -nvf" output
    report false differences after upgrading to 15.x.
  - "pfctl -s rules" output is no longer a faithful representation of
    the loaded ruleset; saving it and reloading it silently drops
    explicit per-rule timeouts.

Proposed fix:

--- a/sys/netpfil/pf/pf_nl.c
+++ b/sys/netpfil/pf/pf_nl.c
@@ nlattr_add_timeout()
        for (int i = 0; i < PFTM_MAX; i++)
-               nlattr_add_u32(nw, PF_RT_TIMEOUT, timeout[i]);
+               nlattr_add_u32(nw, PF_TT_TIMEOUT, timeout[i]);

A regression test in tests/sys/netpfil/pf comparing "pfctl -sr" with
the loaded rule for a rule carrying a per-rule timeout would catch
this.

MFC to stable/15 (and an EN for 15.x) would be appreciated.

=============

I didn't test this fix yet.

-- 
You are receiving this mail because:
You are the assignee for the bug.

Reply via email to