Commit 2854378a authored by Paolo Abeni's avatar Paolo Abeni
Browse files
Florian Westphal says:

====================
netfilter: updates for net

The following patchset contains Netfilter fixes for *net*:

1) Fix crash (call recursion) when nftables synproxy extension is used
   in an object map.  When this feature was added in v5.4 the required
   hook call validation was forgotten.
   Fix from Fernando Fernandez Mancera.
2) bridge br_vlan_fill_forward_path_pvid uses incorrect
   rcu_dereference_protected(); we only have rcu read lock but not
   RTNL.  Fix from Eric Woudstra.

Last two patches address flakes in two existing selftests.

netfilter pull request nf-25-10-08

* tag 'nf-25-10-08' of https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
  selftests: netfilter: query conntrack state to check for port clash resolution
  selftests: netfilter: nft_fib.sh: fix spurious test failures
  bridge: br_vlan_fill_forward_path_pvid: use br_vlan_group_rcu()
  netfilter: nft_objref: validate objref and objrefmap expressions
====================

Link: https://patch.msgid.link/20251008125942.25056-1-fw@strlen.de


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 2c95a756 e84945bd
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1457,7 +1457,7 @@ void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
	if (!br_opt_get(br, BROPT_VLAN_ENABLED))
		return;

	vg = br_vlan_group(br);
	vg = br_vlan_group_rcu(br);

	if (idx >= 0 &&
	    ctx->vlan[idx].proto == br->vlan_proto) {
+39 −0
Original line number Diff line number Diff line
@@ -22,6 +22,35 @@ void nft_objref_eval(const struct nft_expr *expr,
	obj->ops->eval(obj, regs, pkt);
}

static int nft_objref_validate_obj_type(const struct nft_ctx *ctx, u32 type)
{
	unsigned int hooks;

	switch (type) {
	case NFT_OBJECT_SYNPROXY:
		if (ctx->family != NFPROTO_IPV4 &&
		    ctx->family != NFPROTO_IPV6 &&
		    ctx->family != NFPROTO_INET)
			return -EOPNOTSUPP;

		hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD);

		return nft_chain_validate_hooks(ctx->chain, hooks);
	default:
		break;
	}

	return 0;
}

static int nft_objref_validate(const struct nft_ctx *ctx,
			       const struct nft_expr *expr)
{
	struct nft_object *obj = nft_objref_priv(expr);

	return nft_objref_validate_obj_type(ctx, obj->ops->type->type);
}

static int nft_objref_init(const struct nft_ctx *ctx,
			   const struct nft_expr *expr,
			   const struct nlattr * const tb[])
@@ -93,6 +122,7 @@ static const struct nft_expr_ops nft_objref_ops = {
	.activate	= nft_objref_activate,
	.deactivate	= nft_objref_deactivate,
	.dump		= nft_objref_dump,
	.validate	= nft_objref_validate,
	.reduce		= NFT_REDUCE_READONLY,
};

@@ -197,6 +227,14 @@ static void nft_objref_map_destroy(const struct nft_ctx *ctx,
	nf_tables_destroy_set(ctx, priv->set);
}

static int nft_objref_map_validate(const struct nft_ctx *ctx,
				   const struct nft_expr *expr)
{
	const struct nft_objref_map *priv = nft_expr_priv(expr);

	return nft_objref_validate_obj_type(ctx, priv->set->objtype);
}

static const struct nft_expr_ops nft_objref_map_ops = {
	.type		= &nft_objref_type,
	.size		= NFT_EXPR_SIZE(sizeof(struct nft_objref_map)),
@@ -206,6 +244,7 @@ static const struct nft_expr_ops nft_objref_map_ops = {
	.deactivate	= nft_objref_map_deactivate,
	.destroy	= nft_objref_map_destroy,
	.dump		= nft_objref_map_dump,
	.validate	= nft_objref_map_validate,
	.reduce		= NFT_REDUCE_READONLY,
};

+41 −17
Original line number Diff line number Diff line
@@ -17,9 +17,31 @@ cleanup()

checktool "socat -h" "run test without socat"
checktool "iptables --version" "run test without iptables"
checktool "conntrack --version" "run test without conntrack"

trap cleanup EXIT

connect_done()
{
	local ns="$1"
	local port="$2"

	ip netns exec "$ns" ss -nt -o state established "dport = :$port" | grep -q "$port"
}

check_ctstate()
{
	local ns="$1"
	local dp="$2"

	if ! ip netns exec "$ns" conntrack --get -s 192.168.1.2 -d 192.168.1.1 -p tcp \
	     --sport 10000 --dport "$dp" --state ESTABLISHED > /dev/null 2>&1;then
		echo "FAIL: Did not find expected state for dport $2"
		ip netns exec "$ns" bash -c 'conntrack -L; conntrack -S; ss -nt'
		ret=1
	fi
}

setup_ns ns1 ns2

# Connect the namespaces using a veth pair
@@ -44,15 +66,18 @@ socatpid=$!
ip netns exec "$ns2" sysctl -q net.ipv4.ip_local_port_range="10000 10000"

# add a virtual IP using DNAT
ip netns exec "$ns2" iptables -t nat -A OUTPUT -d 10.96.0.1/32 -p tcp --dport 443 -j DNAT --to-destination 192.168.1.1:5201
ip netns exec "$ns2" iptables -t nat -A OUTPUT -d 10.96.0.1/32 -p tcp --dport 443 -j DNAT --to-destination 192.168.1.1:5201 || exit 1

# ... and route it to the other namespace
ip netns exec "$ns2" ip route add 10.96.0.1 via 192.168.1.1

# add a persistent connection from the other namespace
ip netns exec "$ns2" socat -t 10 - TCP:192.168.1.1:5201 > /dev/null &
# listener should be up by now, wait if it isn't yet.
wait_local_port_listen "$ns1" 5201 tcp

sleep 1
# add a persistent connection from the other namespace
sleep 10 | ip netns exec "$ns2" socat -t 10 - TCP:192.168.1.1:5201 > /dev/null &
cpid0=$!
busywait "$BUSYWAIT_TIMEOUT" connect_done "$ns2" "5201"

# ip daddr:dport will be rewritten to 192.168.1.1 5201
# NAT must reallocate source port 10000 because
@@ -71,26 +96,25 @@ fi
ip netns exec "$ns1" iptables -t nat -A PREROUTING -p tcp --dport 5202 -j REDIRECT --to-ports 5201
ip netns exec "$ns1" iptables -t nat -A PREROUTING -p tcp --dport 5203 -j REDIRECT --to-ports 5201

sleep 5 | ip netns exec "$ns2" socat -t 5 -u STDIN TCP:192.168.1.1:5202,connect-timeout=5 >/dev/null &
sleep 5 | ip netns exec "$ns2" socat -T 5 -u STDIN TCP:192.168.1.1:5202,connect-timeout=5 >/dev/null &
cpid1=$!

# if connect succeeds, client closes instantly due to EOF on stdin.
# if connect hangs, it will time out after 5s.
echo | ip netns exec "$ns2" socat -t 3 -u STDIN TCP:192.168.1.1:5203,connect-timeout=5 >/dev/null &
sleep 5 | ip netns exec "$ns2" socat -T 5 -u STDIN TCP:192.168.1.1:5203,connect-timeout=5 >/dev/null &
cpid2=$!

time_then=$(date +%s)
wait $cpid2
rv=$?
time_now=$(date +%s)
busywait "$BUSYWAIT_TIMEOUT" connect_done "$ns2" 5202
busywait "$BUSYWAIT_TIMEOUT" connect_done "$ns2" 5203

# Check how much time has elapsed, expectation is for
# 'cpid2' to connect and then exit (and no connect delay).
delta=$((time_now - time_then))
check_ctstate "$ns1" 5202
check_ctstate "$ns1" 5203

if [ $delta -lt 2 ] && [ $rv -eq 0 ]; then
kill $socatpid $cpid0 $cpid1 $cpid2
socatpid=0

if [ $ret -eq 0 ]; then
	echo "PASS: could connect to service via redirected ports"
else
	echo "FAIL: socat cannot connect to service via redirect ($delta seconds elapsed, returned $rv)"
	echo "FAIL: socat cannot connect to service via redirect"
	ret=1
fi

+8 −5
Original line number Diff line number Diff line
@@ -256,12 +256,12 @@ test_ping_unreachable() {
  local daddr4=$1
  local daddr6=$2

  if ip netns exec "$ns1" ping -c 1 -w 1 -q "$daddr4" > /dev/null; then
  if ip netns exec "$ns1" ping -c 1 -W 0.1 -q "$daddr4" > /dev/null; then
	echo "FAIL: ${ns1} could reach $daddr4" 1>&2
	return 1
  fi

  if ip netns exec "$ns1" ping -c 1 -w 1 -q "$daddr6" > /dev/null; then
  if ip netns exec "$ns1" ping -c 1 -W 0.1 -q "$daddr6" > /dev/null; then
	echo "FAIL: ${ns1} could reach $daddr6" 1>&2
	return 1
  fi
@@ -437,14 +437,17 @@ check_type()
	local addr="$3"
	local type="$4"
	local count="$5"
	local lret=0

	[ -z "$count" ] && count=1

	if ! ip netns exec "$nsrouter" nft get element inet t "$setname" { "$iifname" . "$addr" . "$type" } |grep -q "counter packets $count";then
		echo "FAIL: did not find $iifname . $addr . $type in $setname"
		echo "FAIL: did not find $iifname . $addr . $type in $setname with $count packets"
		ip netns exec "$nsrouter" nft list set inet t "$setname"
		ret=1
		return 1
		# do not fail right away, delete entry if it exists so later test that
		# checks for unwanted keys don't get confused by this *expected* key.
		lret=1
	fi

	# delete the entry, this allows to check if anything unexpected appeared
@@ -456,7 +459,7 @@ check_type()
		return 1
	fi

	return 0
	return $lret
}

check_local()