Skip to content

Commit 7b225d0

Browse files
committed
netfilter: nf_tables: add NFTA_SET_ELEM_KEY_END attribute
Add NFTA_SET_ELEM_KEY_END attribute to convey the closing element of the interval between kernel and userspace. This patch also adds the NFT_SET_EXT_KEY_END extension to store the closing element value in this interval. v4: No changes v3: New patch [sbrivio: refactor error paths and labels; add corresponding nft_set_ext_type for new key; rebase] Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 20a1452 commit 7b225d0

File tree

4 files changed

+79
-24
lines changed

4 files changed

+79
-24
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,13 +231,18 @@ struct nft_userdata {
231231
* struct nft_set_elem - generic representation of set elements
232232
*
233233
* @key: element key
234+
* @key_end: closing element key
234235
* @priv: element private data and extensions
235236
*/
236237
struct nft_set_elem {
237238
union {
238239
u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
239240
struct nft_data val;
240241
} key;
242+
union {
243+
u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
244+
struct nft_data val;
245+
} key_end;
241246
void *priv;
242247
};
243248

@@ -502,6 +507,7 @@ void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set);
502507
* enum nft_set_extensions - set extension type IDs
503508
*
504509
* @NFT_SET_EXT_KEY: element key
510+
* @NFT_SET_EXT_KEY_END: upper bound element key, for ranges
505511
* @NFT_SET_EXT_DATA: mapping data
506512
* @NFT_SET_EXT_FLAGS: element flags
507513
* @NFT_SET_EXT_TIMEOUT: element timeout
@@ -513,6 +519,7 @@ void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set);
513519
*/
514520
enum nft_set_extensions {
515521
NFT_SET_EXT_KEY,
522+
NFT_SET_EXT_KEY_END,
516523
NFT_SET_EXT_DATA,
517524
NFT_SET_EXT_FLAGS,
518525
NFT_SET_EXT_TIMEOUT,
@@ -606,6 +613,11 @@ static inline struct nft_data *nft_set_ext_key(const struct nft_set_ext *ext)
606613
return nft_set_ext(ext, NFT_SET_EXT_KEY);
607614
}
608615

616+
static inline struct nft_data *nft_set_ext_key_end(const struct nft_set_ext *ext)
617+
{
618+
return nft_set_ext(ext, NFT_SET_EXT_KEY_END);
619+
}
620+
609621
static inline struct nft_data *nft_set_ext_data(const struct nft_set_ext *ext)
610622
{
611623
return nft_set_ext(ext, NFT_SET_EXT_DATA);
@@ -655,7 +667,7 @@ static inline struct nft_object **nft_set_ext_obj(const struct nft_set_ext *ext)
655667

656668
void *nft_set_elem_init(const struct nft_set *set,
657669
const struct nft_set_ext_tmpl *tmpl,
658-
const u32 *key, const u32 *data,
670+
const u32 *key, const u32 *key_end, const u32 *data,
659671
u64 timeout, u64 expiration, gfp_t gfp);
660672
void nft_set_elem_destroy(const struct nft_set *set, void *elem,
661673
bool destroy_expr);

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ enum nft_set_elem_flags {
370370
* @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
371371
* @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)
372372
* @NFTA_SET_ELEM_OBJREF: stateful object reference (NLA_STRING)
373+
* @NFTA_SET_ELEM_KEY_END: closing key value (NLA_NESTED: nft_data)
373374
*/
374375
enum nft_set_elem_attributes {
375376
NFTA_SET_ELEM_UNSPEC,
@@ -382,6 +383,7 @@ enum nft_set_elem_attributes {
382383
NFTA_SET_ELEM_EXPR,
383384
NFTA_SET_ELEM_PAD,
384385
NFTA_SET_ELEM_OBJREF,
386+
NFTA_SET_ELEM_KEY_END,
385387
__NFTA_SET_ELEM_MAX
386388
};
387389
#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)

net/netfilter/nf_tables_api.c

Lines changed: 63 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4215,6 +4215,9 @@ const struct nft_set_ext_type nft_set_ext_types[] = {
42154215
.len = sizeof(struct nft_userdata),
42164216
.align = __alignof__(struct nft_userdata),
42174217
},
4218+
[NFT_SET_EXT_KEY_END] = {
4219+
.align = __alignof__(u32),
4220+
},
42184221
};
42194222
EXPORT_SYMBOL_GPL(nft_set_ext_types);
42204223

@@ -4233,6 +4236,7 @@ static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
42334236
[NFTA_SET_ELEM_EXPR] = { .type = NLA_NESTED },
42344237
[NFTA_SET_ELEM_OBJREF] = { .type = NLA_STRING,
42354238
.len = NFT_OBJ_MAXNAMELEN - 1 },
4239+
[NFTA_SET_ELEM_KEY_END] = { .type = NLA_NESTED },
42364240
};
42374241

42384242
static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
@@ -4282,6 +4286,11 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
42824286
NFT_DATA_VALUE, set->klen) < 0)
42834287
goto nla_put_failure;
42844288

4289+
if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END) &&
4290+
nft_data_dump(skb, NFTA_SET_ELEM_KEY_END, nft_set_ext_key_end(ext),
4291+
NFT_DATA_VALUE, set->klen) < 0)
4292+
goto nla_put_failure;
4293+
42854294
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) &&
42864295
nft_data_dump(skb, NFTA_SET_ELEM_DATA, nft_set_ext_data(ext),
42874296
set->dtype == NFT_DATA_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE,
@@ -4569,6 +4578,13 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
45694578
if (err < 0)
45704579
return err;
45714580

4581+
if (nla[NFTA_SET_ELEM_KEY_END]) {
4582+
err = nft_setelem_parse_key(ctx, set, &elem.key_end.val,
4583+
nla[NFTA_SET_ELEM_KEY_END]);
4584+
if (err < 0)
4585+
return err;
4586+
}
4587+
45724588
priv = set->ops->get(ctx->net, set, &elem, flags);
45734589
if (IS_ERR(priv))
45744590
return PTR_ERR(priv);
@@ -4694,8 +4710,8 @@ static struct nft_trans *nft_trans_elem_alloc(struct nft_ctx *ctx,
46944710

46954711
void *nft_set_elem_init(const struct nft_set *set,
46964712
const struct nft_set_ext_tmpl *tmpl,
4697-
const u32 *key, const u32 *data,
4698-
u64 timeout, u64 expiration, gfp_t gfp)
4713+
const u32 *key, const u32 *key_end,
4714+
const u32 *data, u64 timeout, u64 expiration, gfp_t gfp)
46994715
{
47004716
struct nft_set_ext *ext;
47014717
void *elem;
@@ -4708,6 +4724,8 @@ void *nft_set_elem_init(const struct nft_set *set,
47084724
nft_set_ext_init(ext, tmpl);
47094725

47104726
memcpy(nft_set_ext_key(ext), key, set->klen);
4727+
if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END))
4728+
memcpy(nft_set_ext_key_end(ext), key_end, set->klen);
47114729
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
47124730
memcpy(nft_set_ext_data(ext), data, set->dlen);
47134731
if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) {
@@ -4842,9 +4860,19 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
48424860
err = nft_setelem_parse_key(ctx, set, &elem.key.val,
48434861
nla[NFTA_SET_ELEM_KEY]);
48444862
if (err < 0)
4845-
goto err1;
4863+
return err;
48464864

48474865
nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
4866+
4867+
if (nla[NFTA_SET_ELEM_KEY_END]) {
4868+
err = nft_setelem_parse_key(ctx, set, &elem.key_end.val,
4869+
nla[NFTA_SET_ELEM_KEY_END]);
4870+
if (err < 0)
4871+
goto err_parse_key;
4872+
4873+
nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY_END, set->klen);
4874+
}
4875+
48484876
if (timeout > 0) {
48494877
nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION);
48504878
if (timeout != set->timeout)
@@ -4854,14 +4882,14 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
48544882
if (nla[NFTA_SET_ELEM_OBJREF] != NULL) {
48554883
if (!(set->flags & NFT_SET_OBJECT)) {
48564884
err = -EINVAL;
4857-
goto err2;
4885+
goto err_parse_key_end;
48584886
}
48594887
obj = nft_obj_lookup(ctx->net, ctx->table,
48604888
nla[NFTA_SET_ELEM_OBJREF],
48614889
set->objtype, genmask);
48624890
if (IS_ERR(obj)) {
48634891
err = PTR_ERR(obj);
4864-
goto err2;
4892+
goto err_parse_key_end;
48654893
}
48664894
nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF);
48674895
}
@@ -4870,11 +4898,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
48704898
err = nft_data_init(ctx, &data, sizeof(data), &desc,
48714899
nla[NFTA_SET_ELEM_DATA]);
48724900
if (err < 0)
4873-
goto err2;
4901+
goto err_parse_key_end;
48744902

48754903
err = -EINVAL;
48764904
if (set->dtype != NFT_DATA_VERDICT && desc.len != set->dlen)
4877-
goto err3;
4905+
goto err_parse_data;
48784906

48794907
dreg = nft_type_to_reg(set->dtype);
48804908
list_for_each_entry(binding, &set->bindings, list) {
@@ -4892,7 +4920,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
48924920
&data,
48934921
desc.type, desc.len);
48944922
if (err < 0)
4895-
goto err3;
4923+
goto err_parse_data;
48964924

48974925
if (desc.type == NFT_DATA_VERDICT &&
48984926
(data.verdict.code == NFT_GOTO ||
@@ -4917,10 +4945,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
49174945
}
49184946

49194947
err = -ENOMEM;
4920-
elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, data.data,
4948+
elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data,
4949+
elem.key_end.val.data, data.data,
49214950
timeout, expiration, GFP_KERNEL);
49224951
if (elem.priv == NULL)
4923-
goto err3;
4952+
goto err_parse_data;
49244953

49254954
ext = nft_set_elem_ext(set, elem.priv);
49264955
if (flags)
@@ -4937,7 +4966,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
49374966

49384967
trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set);
49394968
if (trans == NULL)
4940-
goto err4;
4969+
goto err_trans;
49414970

49424971
ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK;
49434972
err = set->ops->insert(ctx->net, set, &elem, &ext2);
@@ -4948,7 +4977,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
49484977
nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF) ^
49494978
nft_set_ext_exists(ext2, NFT_SET_EXT_OBJREF)) {
49504979
err = -EBUSY;
4951-
goto err5;
4980+
goto err_element_clash;
49524981
}
49534982
if ((nft_set_ext_exists(ext, NFT_SET_EXT_DATA) &&
49544983
nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) &&
@@ -4961,33 +4990,35 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
49614990
else if (!(nlmsg_flags & NLM_F_EXCL))
49624991
err = 0;
49634992
}
4964-
goto err5;
4993+
goto err_element_clash;
49654994
}
49664995

49674996
if (set->size &&
49684997
!atomic_add_unless(&set->nelems, 1, set->size + set->ndeact)) {
49694998
err = -ENFILE;
4970-
goto err6;
4999+
goto err_set_full;
49715000
}
49725001

49735002
nft_trans_elem(trans) = elem;
49745003
list_add_tail(&trans->list, &ctx->net->nft.commit_list);
49755004
return 0;
49765005

4977-
err6:
5006+
err_set_full:
49785007
set->ops->remove(ctx->net, set, &elem);
4979-
err5:
5008+
err_element_clash:
49805009
kfree(trans);
4981-
err4:
5010+
err_trans:
49825011
if (obj)
49835012
obj->use--;
49845013
kfree(elem.priv);
4985-
err3:
5014+
err_parse_data:
49865015
if (nla[NFTA_SET_ELEM_DATA] != NULL)
49875016
nft_data_release(&data, desc.type);
4988-
err2:
5017+
err_parse_key_end:
5018+
nft_data_release(&elem.key_end.val, NFT_DATA_VALUE);
5019+
err_parse_key:
49895020
nft_data_release(&elem.key.val, NFT_DATA_VALUE);
4990-
err1:
5021+
49915022
return err;
49925023
}
49935024

@@ -5112,9 +5143,19 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
51125143

51135144
nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
51145145

5146+
if (nla[NFTA_SET_ELEM_KEY_END]) {
5147+
err = nft_setelem_parse_key(ctx, set, &elem.key_end.val,
5148+
nla[NFTA_SET_ELEM_KEY_END]);
5149+
if (err < 0)
5150+
return err;
5151+
5152+
nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY_END, set->klen);
5153+
}
5154+
51155155
err = -ENOMEM;
5116-
elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, NULL, 0,
5117-
0, GFP_KERNEL);
5156+
elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data,
5157+
elem.key_end.val.data, NULL, 0, 0,
5158+
GFP_KERNEL);
51185159
if (elem.priv == NULL)
51195160
goto fail_elem;
51205161

net/netfilter/nft_dynset.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
5454

5555
timeout = priv->timeout ? : set->timeout;
5656
elem = nft_set_elem_init(set, &priv->tmpl,
57-
&regs->data[priv->sreg_key],
57+
&regs->data[priv->sreg_key], NULL,
5858
&regs->data[priv->sreg_data],
5959
timeout, 0, GFP_ATOMIC);
6060
if (elem == NULL)

0 commit comments

Comments
 (0)