Skip to content

Commit 8cfd9b0

Browse files
committed
netfilter: nftables: generalize set expressions support
Currently, the set infrastucture allows for one single expressions per element. This patch extends the existing infrastructure to allow for up to two expressions. This is not updating the netlink API yet, this is coming as an initial preparation patch. Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 86d21fc commit 8cfd9b0

File tree

3 files changed

+70
-28
lines changed

3 files changed

+70
-28
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,8 @@ struct nft_set_type {
396396
};
397397
#define to_set_type(o) container_of(o, struct nft_set_type, ops)
398398

399+
#define NFT_SET_EXPR_MAX 2
400+
399401
/**
400402
* struct nft_set - nf_tables set instance
401403
*
@@ -448,13 +450,14 @@ struct nft_set {
448450
u16 policy;
449451
u16 udlen;
450452
unsigned char *udata;
451-
struct nft_expr *expr;
452453
/* runtime data below here */
453454
const struct nft_set_ops *ops ____cacheline_aligned;
454455
u16 flags:14,
455456
genmask:2;
456457
u8 klen;
457458
u8 dlen;
459+
u8 num_exprs;
460+
struct nft_expr *exprs[NFT_SET_EXPR_MAX];
458461
unsigned char data[]
459462
__attribute__((aligned(__alignof__(u64))));
460463
};

net/netfilter/nf_tables_api.c

Lines changed: 64 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3841,9 +3841,9 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
38413841

38423842
nla_nest_end(skb, nest);
38433843

3844-
if (set->expr) {
3844+
if (set->num_exprs == 1) {
38453845
nest = nla_nest_start_noflag(skb, NFTA_SET_EXPR);
3846-
if (nf_tables_fill_expr_info(skb, set->expr) < 0)
3846+
if (nf_tables_fill_expr_info(skb, set->exprs[0]) < 0)
38473847
goto nla_put_failure;
38483848

38493849
nla_nest_end(skb, nest);
@@ -4279,6 +4279,8 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
42794279
err = PTR_ERR(expr);
42804280
goto err_set_alloc_name;
42814281
}
4282+
set->exprs[0] = expr;
4283+
set->num_exprs++;
42824284
}
42834285

42844286
udata = NULL;
@@ -4296,7 +4298,6 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
42964298
set->dtype = dtype;
42974299
set->objtype = objtype;
42984300
set->dlen = desc.dlen;
4299-
set->expr = expr;
43004301
set->flags = flags;
43014302
set->size = desc.size;
43024303
set->policy = policy;
@@ -4325,8 +4326,8 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
43254326
err_set_trans:
43264327
ops->destroy(set);
43274328
err_set_init:
4328-
if (expr)
4329-
nft_expr_destroy(&ctx, expr);
4329+
for (i = 0; i < set->num_exprs; i++)
4330+
nft_expr_destroy(&ctx, set->exprs[i]);
43304331
err_set_alloc_name:
43314332
kfree(set->name);
43324333
err_set_name:
@@ -4336,11 +4337,13 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
43364337

43374338
static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
43384339
{
4340+
int i;
4341+
43394342
if (WARN_ON(set->use > 0))
43404343
return;
43414344

4342-
if (set->expr)
4343-
nft_expr_destroy(ctx, set->expr);
4345+
for (i = 0; i < set->num_exprs; i++)
4346+
nft_expr_destroy(ctx, set->exprs[i]);
43444347

43454348
set->ops->destroy(set);
43464349
kfree(set->name);
@@ -5139,17 +5142,46 @@ static void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
51395142
kfree(elem);
51405143
}
51415144

5145+
static int nft_set_elem_expr_clone(const struct nft_ctx *ctx,
5146+
struct nft_set *set,
5147+
struct nft_expr *expr_array[])
5148+
{
5149+
struct nft_expr *expr;
5150+
int err, i, k;
5151+
5152+
for (i = 0; i < set->num_exprs; i++) {
5153+
expr = kzalloc(set->exprs[i]->ops->size, GFP_KERNEL);
5154+
if (!expr)
5155+
goto err_expr;
5156+
5157+
err = nft_expr_clone(expr, set->exprs[i]);
5158+
if (err < 0) {
5159+
nft_expr_destroy(ctx, expr);
5160+
goto err_expr;
5161+
}
5162+
expr_array[i] = expr;
5163+
}
5164+
5165+
return 0;
5166+
5167+
err_expr:
5168+
for (k = i - 1; k >= 0; k++)
5169+
nft_expr_destroy(ctx, expr_array[i]);
5170+
5171+
return -ENOMEM;
5172+
}
5173+
51425174
static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
51435175
const struct nlattr *attr, u32 nlmsg_flags)
51445176
{
5177+
struct nft_expr *expr_array[NFT_SET_EXPR_MAX] = {};
51455178
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
51465179
u8 genmask = nft_genmask_next(ctx->net);
51475180
struct nft_set_ext_tmpl tmpl;
51485181
struct nft_set_ext *ext, *ext2;
51495182
struct nft_set_elem elem;
51505183
struct nft_set_binding *binding;
51515184
struct nft_object *obj = NULL;
5152-
struct nft_expr *expr = NULL;
51535185
struct nft_userdata *udata;
51545186
struct nft_data_desc desc;
51555187
enum nft_registers dreg;
@@ -5158,7 +5190,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
51585190
u64 timeout;
51595191
u64 expiration;
51605192
u8 ulen;
5161-
int err;
5193+
int err, i;
51625194

51635195
err = nla_parse_nested_deprecated(nla, NFTA_SET_ELEM_MAX, attr,
51645196
nft_set_elem_policy, NULL);
@@ -5216,23 +5248,27 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
52165248
return err;
52175249
}
52185250

5219-
if (nla[NFTA_SET_ELEM_EXPR] != NULL) {
5251+
if (nla[NFTA_SET_ELEM_EXPR]) {
5252+
struct nft_expr *expr;
5253+
5254+
if (set->num_exprs != 1)
5255+
return -EOPNOTSUPP;
5256+
52205257
expr = nft_set_elem_expr_alloc(ctx, set,
52215258
nla[NFTA_SET_ELEM_EXPR]);
52225259
if (IS_ERR(expr))
52235260
return PTR_ERR(expr);
52245261

5225-
err = -EOPNOTSUPP;
5226-
if (set->expr && set->expr->ops != expr->ops)
5227-
goto err_set_elem_expr;
5228-
} else if (set->expr) {
5229-
expr = kzalloc(set->expr->ops->size, GFP_KERNEL);
5230-
if (!expr)
5231-
return -ENOMEM;
5262+
expr_array[0] = expr;
52325263

5233-
err = nft_expr_clone(expr, set->expr);
5234-
if (err < 0)
5264+
if (set->exprs[0] && set->exprs[0]->ops != expr->ops) {
5265+
err = -EOPNOTSUPP;
52355266
goto err_set_elem_expr;
5267+
}
5268+
} else if (set->num_exprs > 0) {
5269+
err = nft_set_elem_expr_clone(ctx, set, expr_array);
5270+
if (err < 0)
5271+
goto err_set_elem_expr_clone;
52365272
}
52375273

52385274
err = nft_setelem_parse_key(ctx, set, &elem.key.val,
@@ -5257,9 +5293,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
52575293
nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
52585294
}
52595295

5260-
if (expr)
5296+
if (set->num_exprs == 1)
52615297
nft_set_ext_add_length(&tmpl, NFT_SET_EXT_EXPR,
5262-
expr->ops->size);
5298+
expr_array[0]->ops->size);
52635299

52645300
if (nla[NFTA_SET_ELEM_OBJREF] != NULL) {
52655301
if (!(set->flags & NFT_SET_OBJECT)) {
@@ -5341,10 +5377,12 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
53415377
*nft_set_ext_obj(ext) = obj;
53425378
obj->use++;
53435379
}
5344-
if (expr) {
5380+
if (set->num_exprs == 1) {
5381+
struct nft_expr *expr = expr_array[0];
5382+
53455383
memcpy(nft_set_ext_expr(ext), expr, expr->ops->size);
53465384
kfree(expr);
5347-
expr = NULL;
5385+
expr_array[0] = NULL;
53485386
}
53495387

53505388
trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set);
@@ -5406,9 +5444,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
54065444
err_parse_key:
54075445
nft_data_release(&elem.key.val, NFT_DATA_VALUE);
54085446
err_set_elem_expr:
5409-
if (expr != NULL)
5410-
nft_expr_destroy(ctx, expr);
5411-
5447+
for (i = 0; i < set->num_exprs && expr_array[i]; i++)
5448+
nft_expr_destroy(ctx, expr_array[i]);
5449+
err_set_elem_expr_clone:
54125450
return err;
54135451
}
54145452

net/netfilter/nft_dynset.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
188188
if (IS_ERR(priv->expr))
189189
return PTR_ERR(priv->expr);
190190

191-
if (set->expr && set->expr->ops != priv->expr->ops) {
191+
if (set->num_exprs == 1 &&
192+
set->exprs[0]->ops != priv->expr->ops) {
192193
err = -EOPNOTSUPP;
193194
goto err_expr_free;
194195
}

0 commit comments

Comments
 (0)