Skip to content

Commit 22488e4

Browse files
committed
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says: ==================== Netfilter fixes for net The following patchset contains Netfilter fixes for net: 1) Fix a crash when stateful expression with its own gc callback is used in a set definition. 2) Skip IPv6 packets from any link-local address in IPv6 fib expression. Add a selftest for this scenario, from Florian Westphal. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 0280f42 + 12f36e9 commit 22488e4

File tree

4 files changed

+283
-47
lines changed

4 files changed

+283
-47
lines changed

net/ipv6/netfilter/nft_fib_ipv6.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,17 @@ void nft_fib6_eval_type(const struct nft_expr *expr, struct nft_regs *regs,
135135
}
136136
EXPORT_SYMBOL_GPL(nft_fib6_eval_type);
137137

138+
static bool nft_fib_v6_skip_icmpv6(const struct sk_buff *skb, u8 next, const struct ipv6hdr *iph)
139+
{
140+
if (likely(next != IPPROTO_ICMPV6))
141+
return false;
142+
143+
if (ipv6_addr_type(&iph->saddr) != IPV6_ADDR_ANY)
144+
return false;
145+
146+
return ipv6_addr_type(&iph->daddr) & IPV6_ADDR_LINKLOCAL;
147+
}
148+
138149
void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
139150
const struct nft_pktinfo *pkt)
140151
{
@@ -163,10 +174,13 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
163174

164175
lookup_flags = nft_fib6_flowi_init(&fl6, priv, pkt, oif, iph);
165176

166-
if (nft_hook(pkt) == NF_INET_PRE_ROUTING &&
167-
nft_fib_is_loopback(pkt->skb, nft_in(pkt))) {
168-
nft_fib_store_result(dest, priv, nft_in(pkt));
169-
return;
177+
if (nft_hook(pkt) == NF_INET_PRE_ROUTING ||
178+
nft_hook(pkt) == NF_INET_INGRESS) {
179+
if (nft_fib_is_loopback(pkt->skb, nft_in(pkt)) ||
180+
nft_fib_v6_skip_icmpv6(pkt->skb, pkt->tprot, iph)) {
181+
nft_fib_store_result(dest, priv, nft_in(pkt));
182+
return;
183+
}
170184
}
171185

172186
*dest = 0;

net/netfilter/nf_tables_api.c

Lines changed: 43 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4364,13 +4364,45 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
43644364
err = nf_tables_set_alloc_name(&ctx, set, name);
43654365
kfree(name);
43664366
if (err < 0)
4367-
goto err_set_alloc_name;
4367+
goto err_set_name;
4368+
4369+
udata = NULL;
4370+
if (udlen) {
4371+
udata = set->data + size;
4372+
nla_memcpy(udata, nla[NFTA_SET_USERDATA], udlen);
4373+
}
4374+
4375+
INIT_LIST_HEAD(&set->bindings);
4376+
INIT_LIST_HEAD(&set->catchall_list);
4377+
set->table = table;
4378+
write_pnet(&set->net, net);
4379+
set->ops = ops;
4380+
set->ktype = ktype;
4381+
set->klen = desc.klen;
4382+
set->dtype = dtype;
4383+
set->objtype = objtype;
4384+
set->dlen = desc.dlen;
4385+
set->flags = flags;
4386+
set->size = desc.size;
4387+
set->policy = policy;
4388+
set->udlen = udlen;
4389+
set->udata = udata;
4390+
set->timeout = timeout;
4391+
set->gc_int = gc_int;
4392+
4393+
set->field_count = desc.field_count;
4394+
for (i = 0; i < desc.field_count; i++)
4395+
set->field_len[i] = desc.field_len[i];
4396+
4397+
err = ops->init(set, &desc, nla);
4398+
if (err < 0)
4399+
goto err_set_init;
43684400

43694401
if (nla[NFTA_SET_EXPR]) {
43704402
expr = nft_set_elem_expr_alloc(&ctx, set, nla[NFTA_SET_EXPR]);
43714403
if (IS_ERR(expr)) {
43724404
err = PTR_ERR(expr);
4373-
goto err_set_alloc_name;
4405+
goto err_set_expr_alloc;
43744406
}
43754407
set->exprs[0] = expr;
43764408
set->num_exprs++;
@@ -4381,75 +4413,44 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
43814413

43824414
if (!(flags & NFT_SET_EXPR)) {
43834415
err = -EINVAL;
4384-
goto err_set_alloc_name;
4416+
goto err_set_expr_alloc;
43854417
}
43864418
i = 0;
43874419
nla_for_each_nested(tmp, nla[NFTA_SET_EXPRESSIONS], left) {
43884420
if (i == NFT_SET_EXPR_MAX) {
43894421
err = -E2BIG;
4390-
goto err_set_init;
4422+
goto err_set_expr_alloc;
43914423
}
43924424
if (nla_type(tmp) != NFTA_LIST_ELEM) {
43934425
err = -EINVAL;
4394-
goto err_set_init;
4426+
goto err_set_expr_alloc;
43954427
}
43964428
expr = nft_set_elem_expr_alloc(&ctx, set, tmp);
43974429
if (IS_ERR(expr)) {
43984430
err = PTR_ERR(expr);
4399-
goto err_set_init;
4431+
goto err_set_expr_alloc;
44004432
}
44014433
set->exprs[i++] = expr;
44024434
set->num_exprs++;
44034435
}
44044436
}
44054437

4406-
udata = NULL;
4407-
if (udlen) {
4408-
udata = set->data + size;
4409-
nla_memcpy(udata, nla[NFTA_SET_USERDATA], udlen);
4410-
}
4411-
4412-
INIT_LIST_HEAD(&set->bindings);
4413-
INIT_LIST_HEAD(&set->catchall_list);
4414-
set->table = table;
4415-
write_pnet(&set->net, net);
4416-
set->ops = ops;
4417-
set->ktype = ktype;
4418-
set->klen = desc.klen;
4419-
set->dtype = dtype;
4420-
set->objtype = objtype;
4421-
set->dlen = desc.dlen;
4422-
set->flags = flags;
4423-
set->size = desc.size;
4424-
set->policy = policy;
4425-
set->udlen = udlen;
4426-
set->udata = udata;
4427-
set->timeout = timeout;
4428-
set->gc_int = gc_int;
44294438
set->handle = nf_tables_alloc_handle(table);
44304439

4431-
set->field_count = desc.field_count;
4432-
for (i = 0; i < desc.field_count; i++)
4433-
set->field_len[i] = desc.field_len[i];
4434-
4435-
err = ops->init(set, &desc, nla);
4436-
if (err < 0)
4437-
goto err_set_init;
4438-
44394440
err = nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set);
44404441
if (err < 0)
4441-
goto err_set_trans;
4442+
goto err_set_expr_alloc;
44424443

44434444
list_add_tail_rcu(&set->list, &table->sets);
44444445
table->use++;
44454446
return 0;
44464447

4447-
err_set_trans:
4448-
ops->destroy(set);
4449-
err_set_init:
4448+
err_set_expr_alloc:
44504449
for (i = 0; i < set->num_exprs; i++)
44514450
nft_expr_destroy(&ctx, set->exprs[i]);
4452-
err_set_alloc_name:
4451+
4452+
ops->destroy(set);
4453+
err_set_init:
44534454
kfree(set->name);
44544455
err_set_name:
44554456
kvfree(set);

tools/testing/selftests/netfilter/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# SPDX-License-Identifier: GPL-2.0
22
# Makefile for netfilter selftests
33

4-
TEST_PROGS := nft_trans_stress.sh nft_nat.sh bridge_brouter.sh \
4+
TEST_PROGS := nft_trans_stress.sh nft_fib.sh nft_nat.sh bridge_brouter.sh \
55
conntrack_icmp_related.sh nft_flowtable.sh ipvs.sh \
66
nft_concat_range.sh nft_conntrack_helper.sh \
77
nft_queue.sh nft_meta.sh nf_nat_edemux.sh \
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
#!/bin/bash
2+
#
3+
# This tests the fib expression.
4+
#
5+
# Kselftest framework requirement - SKIP code is 4.
6+
ksft_skip=4
7+
ret=0
8+
9+
sfx=$(mktemp -u "XXXXXXXX")
10+
ns1="ns1-$sfx"
11+
ns2="ns2-$sfx"
12+
nsrouter="nsrouter-$sfx"
13+
timeout=4
14+
15+
log_netns=$(sysctl -n net.netfilter.nf_log_all_netns)
16+
17+
cleanup()
18+
{
19+
ip netns del ${ns1}
20+
ip netns del ${ns2}
21+
ip netns del ${nsrouter}
22+
23+
[ $log_netns -eq 0 ] && sysctl -q net.netfilter.nf_log_all_netns=$log_netns
24+
}
25+
26+
nft --version > /dev/null 2>&1
27+
if [ $? -ne 0 ];then
28+
echo "SKIP: Could not run test without nft tool"
29+
exit $ksft_skip
30+
fi
31+
32+
ip -Version > /dev/null 2>&1
33+
if [ $? -ne 0 ];then
34+
echo "SKIP: Could not run test without ip tool"
35+
exit $ksft_skip
36+
fi
37+
38+
ip netns add ${nsrouter}
39+
if [ $? -ne 0 ];then
40+
echo "SKIP: Could not create net namespace"
41+
exit $ksft_skip
42+
fi
43+
44+
trap cleanup EXIT
45+
46+
dmesg | grep -q ' nft_rpfilter: '
47+
if [ $? -eq 0 ]; then
48+
dmesg -c | grep ' nft_rpfilter: '
49+
echo "WARN: a previous test run has failed" 1>&2
50+
fi
51+
52+
sysctl -q net.netfilter.nf_log_all_netns=1
53+
ip netns add ${ns1}
54+
ip netns add ${ns2}
55+
56+
load_ruleset() {
57+
local netns=$1
58+
59+
ip netns exec ${netns} nft -f /dev/stdin <<EOF
60+
table inet filter {
61+
chain prerouting {
62+
type filter hook prerouting priority 0; policy accept;
63+
fib saddr . iif oif missing counter log prefix "$netns nft_rpfilter: " drop
64+
}
65+
}
66+
EOF
67+
}
68+
69+
load_ruleset_count() {
70+
local netns=$1
71+
72+
ip netns exec ${netns} nft -f /dev/stdin <<EOF
73+
table inet filter {
74+
chain prerouting {
75+
type filter hook prerouting priority 0; policy accept;
76+
ip daddr 1.1.1.1 fib saddr . iif oif missing counter drop
77+
ip6 daddr 1c3::c01d fib saddr . iif oif missing counter drop
78+
}
79+
}
80+
EOF
81+
}
82+
83+
check_drops() {
84+
dmesg | grep -q ' nft_rpfilter: '
85+
if [ $? -eq 0 ]; then
86+
dmesg | grep ' nft_rpfilter: '
87+
echo "FAIL: rpfilter did drop packets"
88+
return 1
89+
fi
90+
91+
return 0
92+
}
93+
94+
check_fib_counter() {
95+
local want=$1
96+
local ns=$2
97+
local address=$3
98+
99+
line=$(ip netns exec ${ns} nft list table inet filter | grep 'fib saddr . iif' | grep $address | grep "packets $want" )
100+
ret=$?
101+
102+
if [ $ret -ne 0 ];then
103+
echo "Netns $ns fib counter doesn't match expected packet count of $want for $address" 1>&2
104+
ip netns exec ${ns} nft list table inet filter
105+
return 1
106+
fi
107+
108+
if [ $want -gt 0 ]; then
109+
echo "PASS: fib expression did drop packets for $address"
110+
fi
111+
112+
return 0
113+
}
114+
115+
load_ruleset ${nsrouter}
116+
load_ruleset ${ns1}
117+
load_ruleset ${ns2}
118+
119+
ip link add veth0 netns ${nsrouter} type veth peer name eth0 netns ${ns1} > /dev/null 2>&1
120+
if [ $? -ne 0 ];then
121+
echo "SKIP: No virtual ethernet pair device support in kernel"
122+
exit $ksft_skip
123+
fi
124+
ip link add veth1 netns ${nsrouter} type veth peer name eth0 netns ${ns2}
125+
126+
ip -net ${nsrouter} link set lo up
127+
ip -net ${nsrouter} link set veth0 up
128+
ip -net ${nsrouter} addr add 10.0.1.1/24 dev veth0
129+
ip -net ${nsrouter} addr add dead:1::1/64 dev veth0
130+
131+
ip -net ${nsrouter} link set veth1 up
132+
ip -net ${nsrouter} addr add 10.0.2.1/24 dev veth1
133+
ip -net ${nsrouter} addr add dead:2::1/64 dev veth1
134+
135+
ip -net ${ns1} link set lo up
136+
ip -net ${ns1} link set eth0 up
137+
138+
ip -net ${ns2} link set lo up
139+
ip -net ${ns2} link set eth0 up
140+
141+
ip -net ${ns1} addr add 10.0.1.99/24 dev eth0
142+
ip -net ${ns1} addr add dead:1::99/64 dev eth0
143+
ip -net ${ns1} route add default via 10.0.1.1
144+
ip -net ${ns1} route add default via dead:1::1
145+
146+
ip -net ${ns2} addr add 10.0.2.99/24 dev eth0
147+
ip -net ${ns2} addr add dead:2::99/64 dev eth0
148+
ip -net ${ns2} route add default via 10.0.2.1
149+
ip -net ${ns2} route add default via dead:2::1
150+
151+
test_ping() {
152+
local daddr4=$1
153+
local daddr6=$2
154+
155+
ip netns exec ${ns1} ping -c 1 -q $daddr4 > /dev/null
156+
ret=$?
157+
if [ $ret -ne 0 ];then
158+
check_drops
159+
echo "FAIL: ${ns1} cannot reach $daddr4, ret $ret" 1>&2
160+
return 1
161+
fi
162+
163+
ip netns exec ${ns1} ping -c 3 -q $daddr6 > /dev/null
164+
ret=$?
165+
if [ $ret -ne 0 ];then
166+
check_drops
167+
echo "FAIL: ${ns1} cannot reach $daddr6, ret $ret" 1>&2
168+
return 1
169+
fi
170+
171+
return 0
172+
}
173+
174+
ip netns exec ${nsrouter} sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
175+
ip netns exec ${nsrouter} sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
176+
ip netns exec ${nsrouter} sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
177+
178+
sleep 3
179+
180+
test_ping 10.0.2.1 dead:2::1 || exit 1
181+
check_drops || exit 1
182+
183+
test_ping 10.0.2.99 dead:2::99 || exit 1
184+
check_drops || exit 1
185+
186+
echo "PASS: fib expression did not cause unwanted packet drops"
187+
188+
ip netns exec ${nsrouter} nft flush table inet filter
189+
190+
ip -net ${ns1} route del default
191+
ip -net ${ns1} -6 route del default
192+
193+
ip -net ${ns1} addr del 10.0.1.99/24 dev eth0
194+
ip -net ${ns1} addr del dead:1::99/64 dev eth0
195+
196+
ip -net ${ns1} addr add 10.0.2.99/24 dev eth0
197+
ip -net ${ns1} addr add dead:2::99/64 dev eth0
198+
199+
ip -net ${ns1} route add default via 10.0.2.1
200+
ip -net ${ns1} -6 route add default via dead:2::1
201+
202+
ip -net ${nsrouter} addr add dead:2::1/64 dev veth0
203+
204+
# switch to ruleset that doesn't log, this time
205+
# its expected that this does drop the packets.
206+
load_ruleset_count ${nsrouter}
207+
208+
# ns1 has a default route, but nsrouter does not.
209+
# must not check return value, ping to 1.1.1.1 will
210+
# fail.
211+
check_fib_counter 0 ${nsrouter} 1.1.1.1 || exit 1
212+
check_fib_counter 0 ${nsrouter} 1c3::c01d || exit 1
213+
214+
ip netns exec ${ns1} ping -c 1 -W 1 -q 1.1.1.1 > /dev/null
215+
check_fib_counter 1 ${nsrouter} 1.1.1.1 || exit 1
216+
217+
sleep 2
218+
ip netns exec ${ns1} ping -c 3 -q 1c3::c01d > /dev/null
219+
check_fib_counter 3 ${nsrouter} 1c3::c01d || exit 1
220+
221+
exit 0

0 commit comments

Comments
 (0)