Skip to content

Commit 6f000f9

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) A new selftest for nf_queue, from Florian Westphal. This test covers two recent fixes: 07f8e4d ("tcp: also NULL skb->dev when copy was needed") and b738a18 ("tcp: ensure skb->dev is NULL before leaving TCP stack"). 2) The fwd action breaks with ifb. For safety in next extensions, make sure the fwd action only runs from ingress until it is extended to be used from a different hook. 3) The pipapo set type now reports EEXIST in case of subrange overlaps. Update the rbtree set to validate range overlaps, so far this validation is only done only from userspace. From Stefano Brivio. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 7e566df + a64d558 commit 6f000f9

File tree

8 files changed

+818
-17
lines changed

8 files changed

+818
-17
lines changed

net/netfilter/nf_tables_api.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5082,6 +5082,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
50825082
err = -EBUSY;
50835083
else if (!(nlmsg_flags & NLM_F_EXCL))
50845084
err = 0;
5085+
} else if (err == -ENOTEMPTY) {
5086+
/* ENOTEMPTY reports overlapping between this element
5087+
* and an existing one.
5088+
*/
5089+
err = -EEXIST;
50855090
}
50865091
goto err_element_clash;
50875092
}

net/netfilter/nft_fwd_netdev.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ static void nft_fwd_netdev_eval(const struct nft_expr *expr,
2828
struct nft_fwd_netdev *priv = nft_expr_priv(expr);
2929
int oif = regs->data[priv->sreg_dev];
3030

31+
/* These are used by ifb only. */
32+
pkt->skb->tc_redirected = 1;
33+
pkt->skb->tc_from_ingress = 1;
34+
3135
nf_fwd_netdev_egress(pkt, oif);
3236
regs->verdict.code = NF_STOLEN;
3337
}
@@ -190,13 +194,21 @@ static int nft_fwd_neigh_dump(struct sk_buff *skb, const struct nft_expr *expr)
190194
return -1;
191195
}
192196

197+
static int nft_fwd_validate(const struct nft_ctx *ctx,
198+
const struct nft_expr *expr,
199+
const struct nft_data **data)
200+
{
201+
return nft_chain_validate_hooks(ctx->chain, (1 << NF_NETDEV_INGRESS));
202+
}
203+
193204
static struct nft_expr_type nft_fwd_netdev_type;
194205
static const struct nft_expr_ops nft_fwd_neigh_netdev_ops = {
195206
.type = &nft_fwd_netdev_type,
196207
.size = NFT_EXPR_SIZE(sizeof(struct nft_fwd_neigh)),
197208
.eval = nft_fwd_neigh_eval,
198209
.init = nft_fwd_neigh_init,
199210
.dump = nft_fwd_neigh_dump,
211+
.validate = nft_fwd_validate,
200212
};
201213

202214
static const struct nft_expr_ops nft_fwd_netdev_ops = {
@@ -205,6 +217,7 @@ static const struct nft_expr_ops nft_fwd_netdev_ops = {
205217
.eval = nft_fwd_netdev_eval,
206218
.init = nft_fwd_netdev_init,
207219
.dump = nft_fwd_netdev_dump,
220+
.validate = nft_fwd_validate,
208221
.offload = nft_fwd_netdev_offload,
209222
};
210223

net/netfilter/nft_set_pipapo.c

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,21 +1098,41 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
10981098
struct nft_pipapo_field *f;
10991099
int i, bsize_max, err = 0;
11001100

1101+
if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END))
1102+
end = (const u8 *)nft_set_ext_key_end(ext)->data;
1103+
else
1104+
end = start;
1105+
11011106
dup = pipapo_get(net, set, start, genmask);
1102-
if (PTR_ERR(dup) == -ENOENT) {
1103-
if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END)) {
1104-
end = (const u8 *)nft_set_ext_key_end(ext)->data;
1105-
dup = pipapo_get(net, set, end, nft_genmask_next(net));
1106-
} else {
1107-
end = start;
1107+
if (!IS_ERR(dup)) {
1108+
/* Check if we already have the same exact entry */
1109+
const struct nft_data *dup_key, *dup_end;
1110+
1111+
dup_key = nft_set_ext_key(&dup->ext);
1112+
if (nft_set_ext_exists(&dup->ext, NFT_SET_EXT_KEY_END))
1113+
dup_end = nft_set_ext_key_end(&dup->ext);
1114+
else
1115+
dup_end = dup_key;
1116+
1117+
if (!memcmp(start, dup_key->data, sizeof(*dup_key->data)) &&
1118+
!memcmp(end, dup_end->data, sizeof(*dup_end->data))) {
1119+
*ext2 = &dup->ext;
1120+
return -EEXIST;
11081121
}
1122+
1123+
return -ENOTEMPTY;
1124+
}
1125+
1126+
if (PTR_ERR(dup) == -ENOENT) {
1127+
/* Look for partially overlapping entries */
1128+
dup = pipapo_get(net, set, end, nft_genmask_next(net));
11091129
}
11101130

11111131
if (PTR_ERR(dup) != -ENOENT) {
11121132
if (IS_ERR(dup))
11131133
return PTR_ERR(dup);
11141134
*ext2 = &dup->ext;
1115-
return -EEXIST;
1135+
return -ENOTEMPTY;
11161136
}
11171137

11181138
/* Validate */

net/netfilter/nft_set_rbtree.c

Lines changed: 78 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ static bool nft_rbtree_interval_end(const struct nft_rbtree_elem *rbe)
3333
(*nft_set_ext_flags(&rbe->ext) & NFT_SET_ELEM_INTERVAL_END);
3434
}
3535

36+
static bool nft_rbtree_interval_start(const struct nft_rbtree_elem *rbe)
37+
{
38+
return !nft_rbtree_interval_end(rbe);
39+
}
40+
3641
static bool nft_rbtree_equal(const struct nft_set *set, const void *this,
3742
const struct nft_rbtree_elem *interval)
3843
{
@@ -64,7 +69,7 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set
6469
if (interval &&
6570
nft_rbtree_equal(set, this, interval) &&
6671
nft_rbtree_interval_end(rbe) &&
67-
!nft_rbtree_interval_end(interval))
72+
nft_rbtree_interval_start(interval))
6873
continue;
6974
interval = rbe;
7075
} else if (d > 0)
@@ -89,7 +94,7 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set
8994

9095
if (set->flags & NFT_SET_INTERVAL && interval != NULL &&
9196
nft_set_elem_active(&interval->ext, genmask) &&
92-
!nft_rbtree_interval_end(interval)) {
97+
nft_rbtree_interval_start(interval)) {
9398
*ext = &interval->ext;
9499
return true;
95100
}
@@ -208,8 +213,43 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
208213
u8 genmask = nft_genmask_next(net);
209214
struct nft_rbtree_elem *rbe;
210215
struct rb_node *parent, **p;
216+
bool overlap = false;
211217
int d;
212218

219+
/* Detect overlaps as we descend the tree. Set the flag in these cases:
220+
*
221+
* a1. |__ _ _? >|__ _ _ (insert start after existing start)
222+
* a2. _ _ __>| ?_ _ __| (insert end before existing end)
223+
* a3. _ _ ___| ?_ _ _>| (insert end after existing end)
224+
* a4. >|__ _ _ _ _ __| (insert start before existing end)
225+
*
226+
* and clear it later on, as we eventually reach the points indicated by
227+
* '?' above, in the cases described below. We'll always meet these
228+
* later, locally, due to tree ordering, and overlaps for the intervals
229+
* that are the closest together are always evaluated last.
230+
*
231+
* b1. |__ _ _! >|__ _ _ (insert start after existing end)
232+
* b2. _ _ __>| !_ _ __| (insert end before existing start)
233+
* b3. !_____>| (insert end after existing start)
234+
*
235+
* Case a4. resolves to b1.:
236+
* - if the inserted start element is the leftmost, because the '0'
237+
* element in the tree serves as end element
238+
* - otherwise, if an existing end is found. Note that end elements are
239+
* always inserted after corresponding start elements.
240+
*
241+
* For a new, rightmost pair of elements, we'll hit cases b1. and b3.,
242+
* in that order.
243+
*
244+
* The flag is also cleared in two special cases:
245+
*
246+
* b4. |__ _ _!|<_ _ _ (insert start right before existing end)
247+
* b5. |__ _ >|!__ _ _ (insert end right after existing start)
248+
*
249+
* which always happen as last step and imply that no further
250+
* overlapping is possible.
251+
*/
252+
213253
parent = NULL;
214254
p = &priv->root.rb_node;
215255
while (*p != NULL) {
@@ -218,17 +258,42 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
218258
d = memcmp(nft_set_ext_key(&rbe->ext),
219259
nft_set_ext_key(&new->ext),
220260
set->klen);
221-
if (d < 0)
261+
if (d < 0) {
222262
p = &parent->rb_left;
223-
else if (d > 0)
263+
264+
if (nft_rbtree_interval_start(new)) {
265+
overlap = nft_rbtree_interval_start(rbe) &&
266+
nft_set_elem_active(&rbe->ext,
267+
genmask);
268+
} else {
269+
overlap = nft_rbtree_interval_end(rbe) &&
270+
nft_set_elem_active(&rbe->ext,
271+
genmask);
272+
}
273+
} else if (d > 0) {
224274
p = &parent->rb_right;
225-
else {
275+
276+
if (nft_rbtree_interval_end(new)) {
277+
overlap = nft_rbtree_interval_end(rbe) &&
278+
nft_set_elem_active(&rbe->ext,
279+
genmask);
280+
} else if (nft_rbtree_interval_end(rbe) &&
281+
nft_set_elem_active(&rbe->ext, genmask)) {
282+
overlap = true;
283+
}
284+
} else {
226285
if (nft_rbtree_interval_end(rbe) &&
227-
!nft_rbtree_interval_end(new)) {
286+
nft_rbtree_interval_start(new)) {
228287
p = &parent->rb_left;
229-
} else if (!nft_rbtree_interval_end(rbe) &&
288+
289+
if (nft_set_elem_active(&rbe->ext, genmask))
290+
overlap = false;
291+
} else if (nft_rbtree_interval_start(rbe) &&
230292
nft_rbtree_interval_end(new)) {
231293
p = &parent->rb_right;
294+
295+
if (nft_set_elem_active(&rbe->ext, genmask))
296+
overlap = false;
232297
} else if (nft_set_elem_active(&rbe->ext, genmask)) {
233298
*ext = &rbe->ext;
234299
return -EEXIST;
@@ -237,6 +302,10 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
237302
}
238303
}
239304
}
305+
306+
if (overlap)
307+
return -ENOTEMPTY;
308+
240309
rb_link_node_rcu(&new->node, parent, p);
241310
rb_insert_color(&new->node, &priv->root);
242311
return 0;
@@ -317,10 +386,10 @@ static void *nft_rbtree_deactivate(const struct net *net,
317386
parent = parent->rb_right;
318387
else {
319388
if (nft_rbtree_interval_end(rbe) &&
320-
!nft_rbtree_interval_end(this)) {
389+
nft_rbtree_interval_start(this)) {
321390
parent = parent->rb_left;
322391
continue;
323-
} else if (!nft_rbtree_interval_end(rbe) &&
392+
} else if (nft_rbtree_interval_start(rbe) &&
324393
nft_rbtree_interval_end(this)) {
325394
parent = parent->rb_right;
326395
continue;

tools/testing/selftests/netfilter/Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
TEST_PROGS := nft_trans_stress.sh nft_nat.sh bridge_brouter.sh \
55
conntrack_icmp_related.sh nft_flowtable.sh ipvs.sh \
6-
nft_concat_range.sh
6+
nft_concat_range.sh \
7+
nft_queue.sh
8+
9+
LDLIBS = -lmnl
10+
TEST_GEN_FILES = nf-queue
711

812
include ../lib.mk
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
CONFIG_NET_NS=y
22
CONFIG_NF_TABLES_INET=y
3+
CONFIG_NFT_QUEUE=m
4+
CONFIG_NFT_NAT=m
5+
CONFIG_NFT_REDIR=m
6+
CONFIG_NFT_MASQ=m
7+
CONFIG_NFT_FLOW_OFFLOAD=m
8+
CONFIG_NF_CT_NETLINK=m

0 commit comments

Comments
 (0)