Skip to content

Commit 7d74026

Browse files
kaberummakynes
authored andcommitted
netfilter: nf_tables: variable sized set element keys / data
This patch changes sets to support variable sized set element keys / data up to 64 bytes each by using variable sized set extensions. This allows to use concatenations with bigger data items suchs as IPv6 addresses. As a side effect, small keys/data now don't require the full 16 bytes of struct nft_data anymore but just the space they need. Signed-off-by: Patrick McHardy <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent d0a11fc commit 7d74026

File tree

5 files changed

+23
-19
lines changed

5 files changed

+23
-19
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,10 @@ struct nft_userdata {
158158
* @priv: element private data and extensions
159159
*/
160160
struct nft_set_elem {
161-
struct nft_data key;
161+
union {
162+
u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
163+
struct nft_data val;
164+
} key;
162165
void *priv;
163166
};
164167

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,9 @@ enum nft_data_attributes {
388388
};
389389
#define NFTA_DATA_MAX (__NFTA_DATA_MAX - 1)
390390

391+
/* Maximum length of a value */
392+
#define NFT_DATA_VALUE_MAXLEN 64
393+
391394
/**
392395
* enum nft_verdict_attributes - nf_tables verdict netlink attributes
393396
*

net/netfilter/nf_tables_api.c

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2608,7 +2608,7 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
26082608
}
26092609

26102610
desc.klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN]));
2611-
if (desc.klen == 0 || desc.klen > FIELD_SIZEOF(struct nft_data, data))
2611+
if (desc.klen == 0 || desc.klen > NFT_DATA_VALUE_MAXLEN)
26122612
return -EINVAL;
26132613

26142614
flags = 0;
@@ -2634,11 +2634,10 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
26342634
if (nla[NFTA_SET_DATA_LEN] == NULL)
26352635
return -EINVAL;
26362636
desc.dlen = ntohl(nla_get_be32(nla[NFTA_SET_DATA_LEN]));
2637-
if (desc.dlen == 0 ||
2638-
desc.dlen > FIELD_SIZEOF(struct nft_data, data))
2637+
if (desc.dlen == 0 || desc.dlen > NFT_DATA_VALUE_MAXLEN)
26392638
return -EINVAL;
26402639
} else
2641-
desc.dlen = sizeof(struct nft_data);
2640+
desc.dlen = sizeof(struct nft_verdict);
26422641
} else if (flags & NFT_SET_MAP)
26432642
return -EINVAL;
26442643

@@ -2854,12 +2853,10 @@ void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
28542853

28552854
const struct nft_set_ext_type nft_set_ext_types[] = {
28562855
[NFT_SET_EXT_KEY] = {
2857-
.len = sizeof(struct nft_data),
2858-
.align = __alignof__(struct nft_data),
2856+
.align = __alignof__(u32),
28592857
},
28602858
[NFT_SET_EXT_DATA] = {
2861-
.len = sizeof(struct nft_data),
2862-
.align = __alignof__(struct nft_data),
2859+
.align = __alignof__(u32),
28632860
},
28642861
[NFT_SET_EXT_FLAGS] = {
28652862
.len = sizeof(u8),
@@ -3299,15 +3296,15 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
32993296
timeout = set->timeout;
33003297
}
33013298

3302-
err = nft_data_init(ctx, &elem.key, sizeof(elem.key), &d1,
3299+
err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &d1,
33033300
nla[NFTA_SET_ELEM_KEY]);
33043301
if (err < 0)
33053302
goto err1;
33063303
err = -EINVAL;
33073304
if (d1.type != NFT_DATA_VALUE || d1.len != set->klen)
33083305
goto err2;
33093306

3310-
nft_set_ext_add(&tmpl, NFT_SET_EXT_KEY);
3307+
nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, d1.len);
33113308
if (timeout > 0) {
33123309
nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION);
33133310
if (timeout != set->timeout)
@@ -3342,7 +3339,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
33423339
goto err3;
33433340
}
33443341

3345-
nft_set_ext_add(&tmpl, NFT_SET_EXT_DATA);
3342+
nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, d2.len);
33463343
}
33473344

33483345
/* The full maximum length of userdata can exceed the maximum
@@ -3358,7 +3355,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
33583355
}
33593356

33603357
err = -ENOMEM;
3361-
elem.priv = nft_set_elem_init(set, &tmpl, elem.key.data, data.data,
3358+
elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, data.data,
33623359
timeout, GFP_KERNEL);
33633360
if (elem.priv == NULL)
33643361
goto err3;
@@ -3393,7 +3390,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
33933390
if (nla[NFTA_SET_ELEM_DATA] != NULL)
33943391
nft_data_uninit(&data, d2.type);
33953392
err2:
3396-
nft_data_uninit(&elem.key, d1.type);
3393+
nft_data_uninit(&elem.key.val, d1.type);
33973394
err1:
33983395
return err;
33993396
}
@@ -3460,7 +3457,7 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
34603457
if (nla[NFTA_SET_ELEM_KEY] == NULL)
34613458
goto err1;
34623459

3463-
err = nft_data_init(ctx, &elem.key, sizeof(elem.key), &desc,
3460+
err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &desc,
34643461
nla[NFTA_SET_ELEM_KEY]);
34653462
if (err < 0)
34663463
goto err1;
@@ -3488,7 +3485,7 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
34883485
err3:
34893486
kfree(trans);
34903487
err2:
3491-
nft_data_uninit(&elem.key, desc.type);
3488+
nft_data_uninit(&elem.key.val, desc.type);
34923489
err1:
34933490
return err;
34943491
}

net/netfilter/nft_hash.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ static int nft_hash_insert(const struct nft_set *set,
133133
struct nft_hash_cmp_arg arg = {
134134
.genmask = nft_genmask_next(read_pnet(&set->pnet)),
135135
.set = set,
136-
.key = elem->key.data,
136+
.key = elem->key.val.data,
137137
};
138138

139139
return rhashtable_lookup_insert_key(&priv->ht, &arg, &he->node,
@@ -157,7 +157,7 @@ static void *nft_hash_deactivate(const struct nft_set *set,
157157
struct nft_hash_cmp_arg arg = {
158158
.genmask = nft_genmask_next(read_pnet(&set->pnet)),
159159
.set = set,
160-
.key = elem->key.data,
160+
.key = elem->key.val.data,
161161
};
162162

163163
rcu_read_lock();

net/netfilter/nft_rbtree.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ static void *nft_rbtree_deactivate(const struct nft_set *set,
152152
while (parent != NULL) {
153153
rbe = rb_entry(parent, struct nft_rbtree_elem, node);
154154

155-
d = memcmp(nft_set_ext_key(&rbe->ext), &elem->key, set->klen);
155+
d = memcmp(nft_set_ext_key(&rbe->ext), &elem->key.val,
156+
set->klen);
156157
if (d < 0)
157158
parent = parent->rb_left;
158159
else if (d > 0)

0 commit comments

Comments
 (0)