Phil Sutter [Tue, 2 Jun 2026 15:15:48 +0000 (17:15 +0200)]
parser_bison: Fix for bison < 3.6
Support for 'custom' parse.error value was added in bison-3.6. Fall back
to previous value for earlier versions.
This is harder to get right than it seems: On one hand, preprocessor
macros can't be used in parser_bison.y's declaration section and
automake forbids conditional changes to AM_YFLAGS on the other.
Another aspect complicating things is compiling with (an up to date)
parser_bison.c in place vs. without: Dist tarballs generally have it in
place, relieving users from having to provide a YACC when compiling. The
existing parser_bison.c either uses parse.error=custom or not which does
not (should not) change when compiling. Hiding yyreport_syntax_error()
behind a CPPFLAG which may be set or not depending on bison presence and
version then causes trouble if it doesn't match how parser_bison.c was
created.
Avoid these pitfalls by:
- Not relying upon a preprocessor define to control parser_bison.c
compilation, instead check existence of the bison-internal
YY_LAC_ESTABLISH macro
- Exporting the above macro existence check in a variable for use by
main.c (thereby crossing the libnftables library boundary)
Also:
- Introduce have_prebuilt_bison variable in configure.ac, unifying the
parser_bison.c existence check and solidify the latter by also
comparing its timestamp
- Report extended parser errors enableval in configure only if
parser_bison.c will be recreated, otherwise we can't quite tell if it
will turn out to be enabled or not
Suggested-by: Jan Kończak <jan.konczak@cs.put.poznan.pl> Fixes: 67b822f2b2624 ("parser_bison: on syntax errors, output expected tokens") Signed-off-by: Phil Sutter <phil@nwl.cc>
Phil Sutter [Fri, 29 May 2026 00:22:55 +0000 (02:22 +0200)]
netlink: Call tunnel getters unconditionally
All the nftnl_obj_get_u*() and nftnl_tunnel_opt_get_u*() functions
return 0 if the attribute is not present. Since 'obj' is zeroed upon
allocation and no unions are used within per object or tunnel type data,
assigning that value won't change behaviour.
Keep the check before calling nftnl_obj_tunnel_opts_foreach though. It
looks like that function does not check tun->tun_opts before
dereferencing it.
Also make sure obj->tunnel.{src,dst} is not initialized twice (once for
IPv4 and once for IPv6) which happens if merely the _is_set() check is
removed. Let netlink_obj_tunnel_parse_addr() choose between two
attributes to use and so assign just once to each of the fields. Prefer
NFTNL_OBJ_TUNNEL_IPV6_{SRC,DST} attributes over IPV4 ones in there to
avoid a functional change in the odd case both IPV4 and IPV6 attributes
are present. The old code would parse both and the later parsed IPV6 one
would win.
Florian Westphal [Thu, 28 May 2026 08:24:36 +0000 (10:24 +0200)]
tests: shell: add template match bug test
Template should not be matched via "ct" expression. Else this
makes us read an l3num of 0. This is a test for kernel commit 3027ecbdb5fd ("netfilter: nft_ct: bail out on template ct in get eval").
mnl: support RLIMIT_NOFILE soft limit > FD_SETSIZE
Use poll(2) instead of select(2) to poll the netlink socket so processes
which raise their file descriptor soft limit beyond FD_SETSIZE can use
libnftables without risk of the process aborting when too many files are
open.
Signed-off-by: Cory Snider <csnider@mirantis.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
parser_json: initialize geneve options list for empty tunnel array
json_parse_cmd_add_object() only initializes obj->tunnel.geneve_opts on
the first iteration of the json_array_foreach() loop, guarded by
"if (index == 0)". A geneve tunnel object whose options array is empty
("tunnel": []) never enters the loop, so the list head is left
uninitialized. obj_tunnel_add_opts() (src/mnl.c) later walks it with
list_for_each_entry() and passes the bogus element to libnftnl, which
dereferences the near-NULL pointer and crashes nft:
Initialize the list head unconditionally before the loop and drop the
per-iteration guard, so an empty array leaves a valid empty list. The
equivalent native-syntax empty definition was already handled in commit f9047c1f ("evaluate: tunnel: don't assume src is set"); this covers the
JSON parser path, which that fix did not reach.
segtree: fix get element command with open intervals
Skip the closing end element in case this is an open interval.
Otherwise, a bogus end element max(type) + 1 is provided, eg. in
inet_service, this results as a 0x10000 with end interval flag
which is interpreted by the kernel as a matching closing element.
Fixes: a43cc8d53096 ("src: support for get element command") Reported-by: Melbin K Mathew <mlbnkm1@gmail.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Phil Sutter [Tue, 26 May 2026 13:49:58 +0000 (15:49 +0200)]
intervals: Fix for inconsistent union field use
Reported by a static code analyzer: key->value belongs to a different
struct in the embedded anonymous union than key->range.* which is
accessed elsewhere in that function.
It is correct in that the function asserts key->etype to be
EXPR_RANGE_VALUE, so key->value is not necessarily valid (it just
happens to match key->range.low's offset.
Fixes: 91dc281a82ea6 ("src: rework singleton interval transformation to reduce memory consumption") Signed-off-by: Phil Sutter <phil@nwl.cc>
Phil Sutter [Wed, 10 Jun 2026 11:54:01 +0000 (13:54 +0200)]
profiling: Include unistd.h to avoid compiler warnings
RHEL8's gcc-8.5.0 emits these warnings:
src/profiling.c: In function ‘get_signalfd’:
src/profiling.c:32:3: warning: implicit declaration of function ‘close’; did you mean ‘pclose’? [-Wimplicit-function-declaration]
close(fd);
^~~~~
pclose
src/profiling.c: In function ‘check_signalfd’:
src/profiling.c:42:6: warning: implicit declaration of function ‘read’; did you mean ‘fread’? [-Wimplicit-function-declaration]
if (read(fd, &info, sizeof(info)) < (signed)sizeof(info))
^~~~
fread
Fixes: 868040f892238 ("configure: Implement --enable-profiling option") Signed-off-by: Phil Sutter <phil@nwl.cc>
tools/check-tree.sh reports:
ERR: "tests/shell/testcases/parsing/exclusive_start_cond" has no "tests/shell/testcases/parsing/dumps/exclusive_start_cond.{nft,nodump}" file
Dump files are useful to test the bison and json input parsers
and because they can be used as inputs for nft-afl fuzzing.
Phil Sutter [Thu, 7 May 2026 20:05:38 +0000 (22:05 +0200)]
scanner: Accept all statements' first words in all scopes
To fix for token lookahead with exclusive start conditions, we must
accept all keywords which may immediately follow the exclusive scope in
that scope as well. This affects basically the first word of every
statement which may follow a limit statement.
Add a test case to make sure things stay that way. A few quirks exist
though:
- xt statement would need special testing since having it in a rule is
supposed to fail the command
- The parser formally accepts nonsensical things like strings, numbers
and variable references on LHS, but these seem to be needed for the
data part in map elements only
Florian Westphal [Thu, 21 May 2026 14:18:55 +0000 (16:18 +0200)]
parser_json: fix map/set type confusion crash in map statement parser
Quoting Alessandro Gario:
Anthropic is conducting research into the use of large language models
for automated vulnerability discovery in open source software. As part
of that work, Anthropic used Claude to scan a set of widely used open
source projects for security issues. Anthropic then engaged Trail of
Bits to independently triage, manually validate, and develop patches
for the findings. [..]
json_parse_map_stmt() in src/parser_json.c:2584 passes
&stmt->set.stmt_list to json_parse_set_stmt_list(), but the
statement object is a map_stmt. The function reads as a copy/edit of
json_parse_set_stmt() that forgot to retarget the list-head pointer.
Reported-by: Alessandro Gario <alessandro.gario@trailofbits.com> Fixes: 27a2da23d508 ("netlink_linearize: skip set element expression in map statement key") Signed-off-by: Florian Westphal <fw@strlen.de>
The reset and list commands use the netlink GET/DUMP nfnetlink API which
provides no check semantics, compared to the NEW/DELETE nfnetlink batch
API which indeed does.
Emulate -c/--check for the reset command by handling this as a list
command, so the state of the objects is just listed, not reset. This
allows to check for presence and dump the content of the objects.
seen with gcc-16.0.1:
src/libnftables.c: In function 'nft_ctx_add_var':
src/libnftables.c:153:27: warning: initialization discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
153 | char *separator = strchr(var, '=');
function arg says "const char *", write to this memory is not expected.
tests: shell: add test case for netdev + dormant table
both commit update and abort path need to release memory associated with
netdev hooks. kfree gets skipped because it mixes registration and
allocation.
doc: note meta cgroup returns zero on cgroupv2-only hosts
Commit 2ff29969 ("doc: Clarify cgroup meta variable") corrected the
terminology and pointed readers to socket cgroupv2. The man page still
gives no indication that meta cgroup silently returns zero on
cgroupv2-only hosts with CONFIG_CGROUP_NET_CLASSID=y (the distribution
default) and no active net_cls hierarchy, the common configuration
on modern systems. Rules load without error and match nothing.
Make the behaviour explicit in the meta expression types table.
Signed-off-by: Avinash H. Duduskar <avinashhd@protonmail.com> Signed-off-by: Florian Westphal <fw@strlen.de>
Using a predicatable filename in /tmp is not good practice.
This test runs with uid 0 and stray symlink could lead to unwanted
effects. Use a temporary file and auto-delete it unless -k/--keep gets
passed to us.
Florian Westphal [Wed, 25 Feb 2026 11:05:40 +0000 (12:05 +0100)]
tests: shell: add test case for basechain abort path
Add coverage for failing basechain add.
'inet' has to register both ipv6 and ipv4 rules.
If all ipv6 slots are already taken, the chain add will fail.
As it was already exposed (albeit only for a very short time) to
dumpers and packet path, it must not be free'd before an RCU
grace period has elapsed. Check for this.
check-tree.sh throws several warnings like this one:
WARN: "tests/shell/testcases/maps/typeof_maps_0" has a dump file "tests/shell/testcases/maps/dumps/typeof_maps_0.nft" but lacks a JSON dump "tests/shell/testcases/maps/dumps/typeof_maps_0.json-nft"
In most cases the dump file is missing due to missing features on the
json side (e.g. anon chains). But some features have been added
meanwhile and we can add 4 more json dumps.
Fix various bugs reported by tools/check-tree.sh.
This also enables the merge_vmap case, it lacked +x mode and
adds many new dump files that were forgotten.
Phil Sutter [Wed, 18 Mar 2026 21:05:34 +0000 (22:05 +0100)]
segtree: Fix for variable-sized object may not be initialized
Seen with gcc-11.5.0 on an aarch64 machine, build failed. Looking at the
code, r1len (or r1->len, actually) really seems variable. So use
memset() and fix build for that older compiler version at least.
Fixes: e8b17865833b8 ("segtree: Fix range aggregation on Big Endian") Signed-off-by: Phil Sutter <phil@nwl.cc> Acked-by: Florian Westphal <fw@strlen.de>
Phil Sutter [Wed, 25 Feb 2026 20:07:32 +0000 (21:07 +0100)]
cache: Filter for table when listing flowtables
Respect an optionally specified table name to filter listed flowtables
to by populating the filter accordingly.
Fixes: a1a6b0a5c3c4 ("cache: finer grain cache population for list commands") Signed-off-by: Phil Sutter <phil@nwl.cc> Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org> Tested-by: Eric Garver <eric@garver.life>
Phil Sutter [Sat, 14 Feb 2026 14:02:04 +0000 (15:02 +0100)]
cache: Filter for table when listing sets or maps
Respect an optionally specified table name to filter listed sets or maps
to by populating the filter accordingly.
Fixes: a1a6b0a5c3c4 ("cache: finer grain cache population for list commands") Signed-off-by: Phil Sutter <phil@nwl.cc> Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org> Tested-by: Eric Garver <eric@garver.life>
Phil Sutter [Fri, 6 Mar 2026 16:02:17 +0000 (17:02 +0100)]
cache: Relax chain_cache_dump filter application
While populating chain cache, a filter was only effective if it limited
fetching to both a table and a chain. Make it apply to 'list chains'
command as well which at most specifies a family and table.
Since the code is OK with filter->list fields being NULL, merely check
for filter to be non-NULL (which is the case if nft_cache_update() is
called by nft_cmd_enoent_chain()).
Fixes: 17297d1acbbf ("cache: Filter chain list on kernel side") Signed-off-by: Phil Sutter <phil@nwl.cc> Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org> Tested-by: Eric Garver <eric@garver.life>
Phil Sutter [Sat, 14 Feb 2026 13:58:03 +0000 (14:58 +0100)]
cache: Respect family in all list commands
Some list commands did not set filter->list.family even if one was given
on command line, fix this.
Fixes: b3ed8fd8c9f33 ("cache: missing family in cache filtering") Signed-off-by: Phil Sutter <phil@nwl.cc> Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org> Tested-by: Eric Garver <eric@garver.life>
Phil Sutter [Wed, 25 Feb 2026 19:16:57 +0000 (20:16 +0100)]
cache: Include chains, flowtables and objects in netlink debug output
In order to test cache filter effectiveness, netlink debug output is
useful as it shows what is actually received from the kernel and maybe
discarded immediately by user space. Therefore add dump calls for these
rule set elements as well.
While at it, move the netlink_dump_rule() call to an earlier spot,
namely into the nft_mnl_talk() callback to match other netlink dump
calls.
Signed-off-by: Phil Sutter <phil@nwl.cc> Tested-by: Eric Garver <eric@garver.life>
This change breaks 'time' expression tests in py test suite. It looks
like with os.unshare, modifications to os.environ are lost. Neither
unshare module nor unshare command suffer from this problem.
Fixes: c29407ab300f8 ("tests: py: use `os.unshare` Python function") Suggested-by: Jeremy Sowden <jeremy@azazel.net> Suggested-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Phil Sutter <phil@nwl.cc>
Generate a random interval set, then flush and reload it a few times.
Note that this test fails with several up-to-date distros that lack
nft commit e83e32c8d1cd ("mnl: restore create element command with large batches").
This hints that we will likely need to revert 648946966a08 ("netfilter: nft_set_rbtree: validate open interval overlap") soon,
or risk major breakage in most current distros .
Florian Westphal [Wed, 25 Feb 2026 11:05:40 +0000 (12:05 +0100)]
mnl: restore nft monitor to working state
monitor tests are currently broken:
./run-tests.sh: line 60: 6490 Aborted $nft -nn monitor $monitor_args > $monitor_output
*** bit out of range 0 - FD_SETSIZE on fd_set ***: terminated
The new iptables 1.8.12 release is broken on docker, pinpointed to the
getauxval() change that apparently can be nonzero in presence of LSMs.
That makes getauxval() useless for the purpose of detecting a setcap
binary. As nftables contains a change just like iptables, it is safe to
assume nftables is broken as well.
tests: shell: add regression test for catchall chain count restore
When deleting a map that has a catchall element that jumps to a chain,
the chain use counter is decremented. In case this drops the use
counter to 0, the chain can be queued for removal.
This decrement has to be un-done in case the transaction is aborted.
Otherwise the chain use counter in this test remains at 0 and the
deletion of the live/in-use chain will work, even though its referenced
from the catchall element.
This results in a use-after-free.
Reported-by: Andrew Fasano <andrew.fasano@nist.gov> Signed-off-by: Florian Westphal <fw@strlen.de>
Alan Ross [Fri, 13 Feb 2026 22:53:23 +0000 (17:53 -0500)]
main: refuse to run under file capabilities
Extend the existing setuid guard in main() to also detect
file capabilities via getauxval(AT_SECURE).
Some container runtimes and minimal distributions grant cap_net_admin
via file capabilities (setcap cap_net_admin+ep /usr/sbin/nft)
rather than running through sudo. In that configuration the kernel
sets AT_SECURE and the dynamic linker strips LD_PRELOAD, but
getuid() == geteuid() so the existing setuid check passes.
CAP_NET_ADMIN is quite powerful; even without dlopen(), we should not
sanction setcap-installations — a control flow bug could still be
exploited as the capability-elevated user.
getauxval(AT_SECURE) is nonzero whenever the kernel has set AT_SECURE
in the auxiliary vector — this covers both classic setuid/setgid and
file capabilities. Exit with status 111, matching the existing
setuid behavior.
Signed-off-by: Alan Ross <alan@sleuthco.ai> Signed-off-by: Florian Westphal <fw@strlen.de>
Phil Sutter [Fri, 23 Jan 2026 00:38:20 +0000 (01:38 +0100)]
configure: Implement --enable-profiling option
This will set compiler flag --coverage so code coverage may be inspected
using gcov.
In order to successfully profile processes which are killed or
interrupted as well, add a signal handler for those cases which calls
exit(). This is relevant for test cases invoking nft monitor.
Phil Sutter [Thu, 5 Feb 2026 14:38:17 +0000 (15:38 +0100)]
Makefile: Pass PKG_CONFIG_PATH to internal builds
When building nftables git HEAD, I use a script which also builds libmnl
and libnftnl in their respective repositories and populates
PKG_CONFIG_PATH variable so nftables is linked against them instead of
host libraries. This is mandatory as host-installed libraries are
chronically outdated and linking against them would fail.
Pass this variable to build test suite as well as the VPATH build
performed by distcheck target based on the presumption that if a custom
PKG_CONFIG_PATH was needed for the main build, these derived builds will
need it as well.
Signed-off-by: Phil Sutter <phil@nwl.cc> Signed-off-by: Florian Westphal <fw@strlen.de>
The previous representation makes it natural for expr_print() to print the
timeout, expiration, statements and comments.
1.1.1.1 counter packets 1 bytes 564 : 0x00000001,
This patch adds an exception for expr_mapping_print() to stick to the
existing representation.
The JSON representation provides this set element information too in the
lhs, which is does not really belong there because it is exposing
transparently the syntax tree for set elements. A workaround to retain
compatibility is included in this patch.
The end goal is to replace EXPR_SET_ELEM by a smaller shim object, to
further reduce memory consumption in set elements in userspace.
This is preparation work that is required to reduce memory footprint
with sets and maps.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Florian Westphal <fw@strlen.de>
Introduce the NFT_TEST_EXCLUDES environment variable to allow excluding
one or more specific test cases.
Some patches may be considered too aggressive to backport to
downstream releases. For example,
tests/shell/testcases/packetpath/reject_loopback
... fails on all downstream kernels that lack
"netfilter: nf_reject: don't reply to ICMP error messages", but such patch
might be considered too intrusive for some distributions.
This allows downstream CI to just skip these tests without local modifications.
It also allows to exclude all known and expected SKIP subtests which
allows to detect newly introduced SKIP items, which may indicate new bugs.
Signed-off-by: Yi Chen <yiche@redhat.com> Signed-off-by: Florian Westphal <fw@strlen.de>
Phil Sutter [Fri, 23 Jan 2026 17:29:02 +0000 (18:29 +0100)]
tests: shell: Add a basic test for src/xt.c
The feature test introduced in this patch checks iptables-nft presence
and usability as well as translation support presence in nft (as it may
not be compiled in).
The actual test case will optionally call ip6tables-nft and ebtables-nft
as well.
Phil Sutter [Fri, 23 Jan 2026 00:21:21 +0000 (01:21 +0100)]
xt: Print comment match data as well
In order to translate comment matches into the single nftables rule
comment, libxtables does not immediately (maybe mid-rule) print a
comment match's string but instead stores it into struct
xt_xlate::comment array for later.
Since xt_stmt_xlate() is called by a statement's .print callback which
can't communicate data back to caller, nftables has to print it right
away.
Since parser_bison accepts rule comments only at end of line though, the
output from above can't be restored anymore. Which is a bad idea to
begin with so accept this quirk and avoid refactoring the statement
printing API.
Phil Sutter [Thu, 18 Dec 2025 12:55:23 +0000 (13:55 +0100)]
doc: nft.8: Describe iface_type data type
An entry in data-types.txt offers space for a name-value table. Even if
one would refer to ARPHRD_*, some names are not derived from the
respective macro name and thus not intuitive.