Skip to content

Commit 236d592

Browse files
committed
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Pablo Neira Ayuso says: ==================== Netfilter fixes for net 1) Restore set counter when one of the CPU loses race to add elements to sets. 2) After NF_STOLEN, skb might be there no more, update nftables trace infra to avoid access to skb in this case. From Florian Westphal. 3) nftables bridge might register a prerouting hook with zero priority, br_netfilter incorrectly skips it. Also from Florian. * git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: netfilter: br_netfilter: do not skip all hooks with 0 priority netfilter: nf_tables: avoid skb access on nf_stolen netfilter: nft_dynset: restore set element counter when failing to update ==================== Link: https://lore.kernel.org/r/ Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 9577fc5 + c257786 commit 236d592

File tree

5 files changed

+75
-32
lines changed

5 files changed

+75
-32
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,24 +1338,28 @@ void nft_unregister_flowtable_type(struct nf_flowtable_type *type);
13381338
/**
13391339
* struct nft_traceinfo - nft tracing information and state
13401340
*
1341+
* @trace: other struct members are initialised
1342+
* @nf_trace: copy of skb->nf_trace before rule evaluation
1343+
* @type: event type (enum nft_trace_types)
1344+
* @skbid: hash of skb to be used as trace id
1345+
* @packet_dumped: packet headers sent in a previous traceinfo message
13411346
* @pkt: pktinfo currently processed
13421347
* @basechain: base chain currently processed
13431348
* @chain: chain currently processed
13441349
* @rule: rule that was evaluated
13451350
* @verdict: verdict given by rule
1346-
* @type: event type (enum nft_trace_types)
1347-
* @packet_dumped: packet headers sent in a previous traceinfo message
1348-
* @trace: other struct members are initialised
13491351
*/
13501352
struct nft_traceinfo {
1353+
bool trace;
1354+
bool nf_trace;
1355+
bool packet_dumped;
1356+
enum nft_trace_types type:8;
1357+
u32 skbid;
13511358
const struct nft_pktinfo *pkt;
13521359
const struct nft_base_chain *basechain;
13531360
const struct nft_chain *chain;
13541361
const struct nft_rule_dp *rule;
13551362
const struct nft_verdict *verdict;
1356-
enum nft_trace_types type;
1357-
bool packet_dumped;
1358-
bool trace;
13591363
};
13601364

13611365
void nft_trace_init(struct nft_traceinfo *info, const struct nft_pktinfo *pkt,

net/bridge/br_netfilter_hooks.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,9 +1012,24 @@ int br_nf_hook_thresh(unsigned int hook, struct net *net,
10121012
return okfn(net, sk, skb);
10131013

10141014
ops = nf_hook_entries_get_hook_ops(e);
1015-
for (i = 0; i < e->num_hook_entries &&
1016-
ops[i]->priority <= NF_BR_PRI_BRNF; i++)
1017-
;
1015+
for (i = 0; i < e->num_hook_entries; i++) {
1016+
/* These hooks have already been called */
1017+
if (ops[i]->priority < NF_BR_PRI_BRNF)
1018+
continue;
1019+
1020+
/* These hooks have not been called yet, run them. */
1021+
if (ops[i]->priority > NF_BR_PRI_BRNF)
1022+
break;
1023+
1024+
/* take a closer look at NF_BR_PRI_BRNF. */
1025+
if (ops[i]->hook == br_nf_pre_routing) {
1026+
/* This hook diverted the skb to this function,
1027+
* hooks after this have not been run yet.
1028+
*/
1029+
i++;
1030+
break;
1031+
}
1032+
}
10181033

10191034
nf_hook_state_init(&state, hook, NFPROTO_BRIDGE, indev, outdev,
10201035
sk, net, okfn);

net/netfilter/nf_tables_core.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@ static noinline void __nft_trace_packet(struct nft_traceinfo *info,
2525
const struct nft_chain *chain,
2626
enum nft_trace_types type)
2727
{
28-
const struct nft_pktinfo *pkt = info->pkt;
29-
30-
if (!info->trace || !pkt->skb->nf_trace)
28+
if (!info->trace || !info->nf_trace)
3129
return;
3230

3331
info->chain = chain;
@@ -42,11 +40,24 @@ static inline void nft_trace_packet(struct nft_traceinfo *info,
4240
enum nft_trace_types type)
4341
{
4442
if (static_branch_unlikely(&nft_trace_enabled)) {
43+
const struct nft_pktinfo *pkt = info->pkt;
44+
45+
info->nf_trace = pkt->skb->nf_trace;
4546
info->rule = rule;
4647
__nft_trace_packet(info, chain, type);
4748
}
4849
}
4950

51+
static inline void nft_trace_copy_nftrace(struct nft_traceinfo *info)
52+
{
53+
if (static_branch_unlikely(&nft_trace_enabled)) {
54+
const struct nft_pktinfo *pkt = info->pkt;
55+
56+
if (info->trace)
57+
info->nf_trace = pkt->skb->nf_trace;
58+
}
59+
}
60+
5061
static void nft_bitwise_fast_eval(const struct nft_expr *expr,
5162
struct nft_regs *regs)
5263
{
@@ -85,15 +96,21 @@ static noinline void __nft_trace_verdict(struct nft_traceinfo *info,
8596
const struct nft_chain *chain,
8697
const struct nft_regs *regs)
8798
{
99+
const struct nft_pktinfo *pkt = info->pkt;
88100
enum nft_trace_types type;
89101

90102
switch (regs->verdict.code) {
91103
case NFT_CONTINUE:
92104
case NFT_RETURN:
93105
type = NFT_TRACETYPE_RETURN;
94106
break;
107+
case NF_STOLEN:
108+
type = NFT_TRACETYPE_RULE;
109+
/* can't access skb->nf_trace; use copy */
110+
break;
95111
default:
96112
type = NFT_TRACETYPE_RULE;
113+
info->nf_trace = pkt->skb->nf_trace;
97114
break;
98115
}
99116

@@ -254,6 +271,7 @@ nft_do_chain(struct nft_pktinfo *pkt, void *priv)
254271
switch (regs.verdict.code) {
255272
case NFT_BREAK:
256273
regs.verdict.code = NFT_CONTINUE;
274+
nft_trace_copy_nftrace(&info);
257275
continue;
258276
case NFT_CONTINUE:
259277
nft_trace_packet(&info, chain, rule,

net/netfilter/nf_tables_trace.c

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include <linux/module.h>
88
#include <linux/static_key.h>
99
#include <linux/hash.h>
10-
#include <linux/jhash.h>
10+
#include <linux/siphash.h>
1111
#include <linux/if_vlan.h>
1212
#include <linux/init.h>
1313
#include <linux/skbuff.h>
@@ -25,22 +25,6 @@
2525
DEFINE_STATIC_KEY_FALSE(nft_trace_enabled);
2626
EXPORT_SYMBOL_GPL(nft_trace_enabled);
2727

28-
static int trace_fill_id(struct sk_buff *nlskb, struct sk_buff *skb)
29-
{
30-
__be32 id;
31-
32-
/* using skb address as ID results in a limited number of
33-
* values (and quick reuse).
34-
*
35-
* So we attempt to use as many skb members that will not
36-
* change while skb is with netfilter.
37-
*/
38-
id = (__be32)jhash_2words(hash32_ptr(skb), skb_get_hash(skb),
39-
skb->skb_iif);
40-
41-
return nla_put_be32(nlskb, NFTA_TRACE_ID, id);
42-
}
43-
4428
static int trace_fill_header(struct sk_buff *nlskb, u16 type,
4529
const struct sk_buff *skb,
4630
int off, unsigned int len)
@@ -186,6 +170,7 @@ void nft_trace_notify(struct nft_traceinfo *info)
186170
struct nlmsghdr *nlh;
187171
struct sk_buff *skb;
188172
unsigned int size;
173+
u32 mark = 0;
189174
u16 event;
190175

191176
if (!nfnetlink_has_listeners(nft_net(pkt), NFNLGRP_NFTRACE))
@@ -229,7 +214,7 @@ void nft_trace_notify(struct nft_traceinfo *info)
229214
if (nla_put_be32(skb, NFTA_TRACE_TYPE, htonl(info->type)))
230215
goto nla_put_failure;
231216

232-
if (trace_fill_id(skb, pkt->skb))
217+
if (nla_put_u32(skb, NFTA_TRACE_ID, info->skbid))
233218
goto nla_put_failure;
234219

235220
if (nla_put_string(skb, NFTA_TRACE_CHAIN, info->chain->name))
@@ -249,16 +234,24 @@ void nft_trace_notify(struct nft_traceinfo *info)
249234
case NFT_TRACETYPE_RULE:
250235
if (nft_verdict_dump(skb, NFTA_TRACE_VERDICT, info->verdict))
251236
goto nla_put_failure;
237+
238+
/* pkt->skb undefined iff NF_STOLEN, disable dump */
239+
if (info->verdict->code == NF_STOLEN)
240+
info->packet_dumped = true;
241+
else
242+
mark = pkt->skb->mark;
243+
252244
break;
253245
case NFT_TRACETYPE_POLICY:
246+
mark = pkt->skb->mark;
247+
254248
if (nla_put_be32(skb, NFTA_TRACE_POLICY,
255249
htonl(info->basechain->policy)))
256250
goto nla_put_failure;
257251
break;
258252
}
259253

260-
if (pkt->skb->mark &&
261-
nla_put_be32(skb, NFTA_TRACE_MARK, htonl(pkt->skb->mark)))
254+
if (mark && nla_put_be32(skb, NFTA_TRACE_MARK, htonl(mark)))
262255
goto nla_put_failure;
263256

264257
if (!info->packet_dumped) {
@@ -283,9 +276,20 @@ void nft_trace_init(struct nft_traceinfo *info, const struct nft_pktinfo *pkt,
283276
const struct nft_verdict *verdict,
284277
const struct nft_chain *chain)
285278
{
279+
static siphash_key_t trace_key __read_mostly;
280+
struct sk_buff *skb = pkt->skb;
281+
286282
info->basechain = nft_base_chain(chain);
287283
info->trace = true;
284+
info->nf_trace = pkt->skb->nf_trace;
288285
info->packet_dumped = false;
289286
info->pkt = pkt;
290287
info->verdict = verdict;
288+
289+
net_get_random_once(&trace_key, sizeof(trace_key));
290+
291+
info->skbid = (u32)siphash_3u32(hash32_ptr(skb),
292+
skb_get_hash(skb),
293+
skb->skb_iif,
294+
&trace_key);
291295
}

net/netfilter/nft_set_hash.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ static bool nft_rhash_update(struct nft_set *set, const u32 *key,
143143
/* Another cpu may race to insert the element with the same key */
144144
if (prev) {
145145
nft_set_elem_destroy(set, he, true);
146+
atomic_dec(&set->nelems);
146147
he = prev;
147148
}
148149

@@ -152,6 +153,7 @@ static bool nft_rhash_update(struct nft_set *set, const u32 *key,
152153

153154
err2:
154155
nft_set_elem_destroy(set, he, true);
156+
atomic_dec(&set->nelems);
155157
err1:
156158
return false;
157159
}

0 commit comments

Comments
 (0)