Merge tag 'nf-25-10-08' of https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
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: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user