commit fca05d4d61e65fa573a3768f9019a42143c03349 upstream. If the set definition contains stateful expressions, allocate them for the newly added entries from the packet path. [ This backport includes nft_set_elem_expr_clone() which has been taken from 8cfd9b0f8515 ("netfilter: nftables: generalize set expressions support") and skip redundant expressions when set already provides it per ce5379963b28 ("netfilter: nft_dynset: dump expressions when set definition contains no expressions") ] Fixes: 65038428b2c6 ("netfilter: nf_tables: allow to specify stateful expression in set definition") Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> --- include/net/netfilter/nf_tables.h | 2 ++ net/netfilter/nf_tables_api.c | 23 +++++++++++++++++++++++ net/netfilter/nft_dynset.c | 7 ++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 484f9cdf2dd0..0f1103c43cb8 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -731,6 +731,8 @@ void *nft_set_elem_init(const struct nft_set *set, const struct nft_set_ext_tmpl *tmpl, const u32 *key, const u32 *key_end, const u32 *data, u64 timeout, u64 expiration, gfp_t gfp); +int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set, + struct nft_expr **pexpr); void nft_set_elem_destroy(const struct nft_set *set, void *elem, bool destroy_expr); void nf_tables_set_elem_destroy(const struct nft_ctx *ctx, diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 2bd1c7e7edc3..28ea2ed3f337 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -5548,6 +5548,29 @@ static int nft_set_elem_expr_setup(struct nft_ctx *ctx, return 0; } +int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set, + struct nft_expr **pexpr) +{ + struct nft_expr *expr; + int err; + + expr = kzalloc(set->expr->ops->size, GFP_KERNEL); + if (!expr) + goto err_expr; + + err = nft_expr_clone(expr, set->expr, GFP_KERNEL); + if (err < 0) { + kfree(expr); + goto err_expr; + } + *pexpr = expr; + + return 0; + +err_expr: + return -ENOMEM; +} + static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, const struct nlattr *attr, u32 nlmsg_flags) { diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c index 9461293182e8..fc81bda6cc6b 100644 --- a/net/netfilter/nft_dynset.c +++ b/net/netfilter/nft_dynset.c @@ -192,6 +192,10 @@ static int nft_dynset_init(const struct nft_ctx *ctx, err = -EOPNOTSUPP; goto err_expr_free; } + } else if (set->expr) { + err = nft_set_elem_expr_clone(ctx, set, &priv->expr); + if (err < 0) + return err; } nft_set_ext_prepare(&priv->tmpl); @@ -272,7 +276,8 @@ static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr) nf_jiffies64_to_msecs(priv->timeout), NFTA_DYNSET_PAD)) goto nla_put_failure; - if (priv->expr && nft_expr_dump(skb, NFTA_DYNSET_EXPR, priv->expr)) + if (!priv->set->expr && priv->expr && + nft_expr_dump(skb, NFTA_DYNSET_EXPR, priv->expr)) goto nla_put_failure; if (nla_put_be32(skb, NFTA_DYNSET_FLAGS, htonl(flags))) goto nla_put_failure; -- 2.30.2