@@ -5150,6 +5150,24 @@ static void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
kfree(elem);
}
+static int nft_set_elem_expr_setup(struct nft_ctx *ctx,
+ const struct nft_set_ext *ext,
+ struct nft_expr *expr)
+{
+ struct nft_expr *elem_expr = nft_set_ext_expr(ext);
+ int err;
+
+ if (expr == NULL)
+ return 0;
+
+ err = nft_expr_clone(elem_expr, expr);
+ if (err < 0)
+ return -ENOMEM;
+
+ nft_expr_destroy(ctx, expr);
+ return 0;
+}
+
static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
const struct nlattr *attr, u32 nlmsg_flags)
{
@@ -5352,15 +5370,17 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
*nft_set_ext_obj(ext) = obj;
obj->use++;
}
- if (expr) {
- memcpy(nft_set_ext_expr(ext), expr, expr->ops->size);
- kfree(expr);
- expr = NULL;
- }
+
+ err = nft_set_elem_expr_setup(ctx, ext, expr);
+ if (err < 0)
+ goto err_elem_expr;
+ expr = NULL;
trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set);
- if (trans == NULL)
- goto err_trans;
+ if (trans == NULL) {
+ err = -ENOMEM;
+ goto err_elem_expr;
+ }
ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK;
err = set->ops->insert(ctx->net, set, &elem, &ext2);
@@ -5404,7 +5424,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
set->ops->remove(ctx->net, set, &elem);
err_element_clash:
kfree(trans);
-err_trans:
+err_elem_expr:
if (obj)
obj->use--;