From: Pablo Neira Ayuso <pablo@netfilter.org>
To: Thomas Haller <thaller@redhat.com>
Cc: NetFilter <netfilter-devel@vger.kernel.org>
Subject: Re: [nft PATCH] datatype: fix leak and cleanup reference counting for struct datatype
Date: Mon, 11 Sep 2023 23:39:16 +0200 [thread overview]
Message-ID: <ZP+JBMa83ArN1FQD@calendula> (raw)
In-Reply-To: <20230911090106.635361-1-thaller@redhat.com>
Hi Thomas,
On Mon, Sep 11, 2023 at 11:01:02AM +0200, Thomas Haller wrote:
> Test `./tests/shell/run-tests.sh -V tests/shell/testcases/maps/nat_addr_port`
> fails:
>
> ==118== 195 (112 direct, 83 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 3
> ==118== at 0x484682C: calloc (vg_replace_malloc.c:1554)
> ==118== by 0x48A39DD: xmalloc (utils.c:37)
> ==118== by 0x48A39DD: xzalloc (utils.c:76)
> ==118== by 0x487BDFD: datatype_alloc (datatype.c:1205)
> ==118== by 0x487BDFD: concat_type_alloc (datatype.c:1288)
> ==118== by 0x488229D: stmt_evaluate_nat_map (evaluate.c:3786)
> ==118== by 0x488229D: stmt_evaluate_nat (evaluate.c:3892)
> ==118== by 0x488229D: stmt_evaluate (evaluate.c:4450)
> ==118== by 0x488328E: rule_evaluate (evaluate.c:4956)
> ==118== by 0x48ADC71: nft_evaluate (libnftables.c:552)
> ==118== by 0x48AEC29: nft_run_cmd_from_buffer (libnftables.c:595)
> ==118== by 0x402983: main (main.c:534)
Thanks, I didn't see this with ASAN.
> I think the reference handling for datatype is wrong. It was introduced
> by commit 01a13882bb59 ('src: add reference counter for dynamic
> datatypes').
>
> We don't notice it most of the time, because instances are statically
> allocated, where datatype_get()/datatype_free() is a NOP.
>
> Fix and rework.
>
> - Commit 01a13882bb59 comments "The reference counter of any newly
> allocated datatype is set to zero". That seems not workable.
> Previously, functions like datatype_clone() would have returned the
> refcnt set to zero. Some callers would then then set the refcnt to one, but
> some wouldn't (set_datatype_alloc()). Calling datatype_free() with a
> refcnt of zero will overflow to UINT_MAX and leak:
>
> if (--dtype->refcnt > 0)
> return;
>
> While there could be schemes with such asymetric counting, juggle the
> appropriate number of datatype_get() and datatype_free() calls, this is
> confusing and error prone. The common pattern is that every
> alloc/clone/get/ref is paired with exactly one unref/free.
>
> Let datatype_clone() return references with refcnt set 1 and in
> general be always clear about where we transfer ownership (take a
> reference) and where we need to release it.
>
> - set_datatype_alloc() needs to consistently return ownership to the
> reference. Previously, some code paths would and others wouldn't.
>
> - Replace
>
> datatype_set(key, set_datatype_alloc(dtype, key->byteorder))
>
> with a datatype_set_take() (for "take" ownership).
See comments below.
> Signed-off-by: Thomas Haller <thaller@redhat.com>
>
> Fixes: 01a13882bb59 ('src: add reference counter for dynamic datatypes')
> ---
> include/datatype.h | 1 +
> include/expression.h | 3 +
> src/datatype.c | 24 ++++++--
> src/evaluate.c | 120 ++++++++++++++++++++++++--------------
> src/expression.c | 2 +-
> src/netlink.c | 33 ++++++-----
> src/netlink_delinearize.c | 2 +-
> src/payload.c | 3 +-
> 8 files changed, 120 insertions(+), 68 deletions(-)
>
> diff --git a/include/datatype.h b/include/datatype.h
> index 6146eda1d2ec..dc11b8331043 100644
> --- a/include/datatype.h
> +++ b/include/datatype.h
> @@ -176,6 +176,7 @@ extern const struct datatype *datatype_lookup(enum datatypes type);
> extern const struct datatype *datatype_lookup_byname(const char *name);
> extern struct datatype *datatype_get(const struct datatype *dtype);
> extern void datatype_set(struct expr *expr, const struct datatype *dtype);
> +extern void datatype_set_take(struct expr *expr, const struct datatype *dtype);
> extern void datatype_free(const struct datatype *dtype);
> struct datatype *datatype_clone(const struct datatype *orig_dtype);
>
> diff --git a/include/expression.h b/include/expression.h
> index 733dd3cfc89c..9a12c4c260b1 100644
> --- a/include/expression.h
> +++ b/include/expression.h
> @@ -120,7 +120,10 @@ enum symbol_types {
> * @maxval: expected maximum value
> */
> struct expr_ctx {
> + /* expr_ctx does not own the refrence to dtype. The caller must
> + * ensure the valid lifetime. */
> const struct datatype *dtype;
> +
> enum byteorder byteorder;
> unsigned int len;
> unsigned int maxval;
> diff --git a/src/datatype.c b/src/datatype.c
> index 1531a5d2a601..6dcf7f972e27 100644
> --- a/src/datatype.c
> +++ b/src/datatype.c
> @@ -1205,6 +1205,7 @@ static struct datatype *datatype_alloc(void)
>
> dtype = xzalloc(sizeof(*dtype));
> dtype->flags = DTYPE_F_ALLOC;
> + dtype->refcnt = 1;
>
> return dtype;
> }
> @@ -1222,12 +1223,22 @@ struct datatype *datatype_get(const struct datatype *ptr)
> return dtype;
> }
>
> +void datatype_set_take(struct expr *expr, const struct datatype *dtype)
> +{
> + const struct datatype *dtype_free;
> +
> + dtype_free = expr->dtype;
> + expr->dtype = dtype;
> + datatype_free(dtype_free);
> +}
> +
> void datatype_set(struct expr *expr, const struct datatype *dtype)
> {
> - if (dtype == expr->dtype)
> - return;
> - datatype_free(expr->dtype);
> + const struct datatype *dtype_free;
> +
> + dtype_free = expr->dtype;
> expr->dtype = datatype_get(dtype);
> + datatype_free(dtype_free);
> }
I'd suggest:
void __datatype_set(struct expr *expr, const struct datatype *dtype)
{
const struct datatype *dtype_free;
dtype_free = expr->dtype;
expr->dtype = dtype;
datatype_free(dtype_free);
}
void datatype_set(struct expr *expr, const struct datatype *dtype)
{
__datatype_set(expr, datatype_get(dtype));
}
There is similar notation with underscore in the kernel code, I would
prefer to use the __ for those cases where the datatype refcnt is not
touched.
> struct datatype *datatype_clone(const struct datatype *orig_dtype)
> @@ -1239,7 +1250,7 @@ struct datatype *datatype_clone(const struct datatype *orig_dtype)
> dtype->name = xstrdup(orig_dtype->name);
> dtype->desc = xstrdup(orig_dtype->desc);
> dtype->flags = DTYPE_F_ALLOC | orig_dtype->flags;
> - dtype->refcnt = 0;
> + dtype->refcnt = 1;
>
> return dtype;
> }
> @@ -1252,6 +1263,9 @@ void datatype_free(const struct datatype *ptr)
> return;
> if (!(dtype->flags & DTYPE_F_ALLOC))
> return;
> +
> + assert(dtype->refcnt != 0);
> +
> if (--dtype->refcnt > 0)
> return;
>
> @@ -1304,7 +1318,7 @@ const struct datatype *set_datatype_alloc(const struct datatype *orig_dtype,
>
> /* Restrict dynamic datatype allocation to generic integer datatype. */
> if (orig_dtype != &integer_type)
> - return orig_dtype;
> + return datatype_get(orig_dtype);
>
> dtype = datatype_clone(orig_dtype);
> dtype->byteorder = byteorder;
> diff --git a/src/evaluate.c b/src/evaluate.c
> index 922ce42114a5..8a7b076d96f5 100644
> --- a/src/evaluate.c
> +++ b/src/evaluate.c
> @@ -83,7 +83,7 @@ static void key_fix_dtype_byteorder(struct expr *key)
> if (dtype->byteorder == key->byteorder)
> return;
>
> - datatype_set(key, set_datatype_alloc(dtype, key->byteorder));
> + datatype_set_take(key, set_datatype_alloc(dtype, key->byteorder));
> }
>
> static int set_evaluate(struct eval_ctx *ctx, struct set *set);
> @@ -1522,8 +1522,7 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
> clone = datatype_clone(i->dtype);
> clone->size = i->len;
> clone->byteorder = i->byteorder;
> - clone->refcnt = 1;
> - i->dtype = clone;
> + datatype_set_take(i, clone);
> }
>
> if (dtype == NULL && i->dtype->size == 0)
> @@ -1551,7 +1550,7 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
> }
>
> (*expr)->flags |= flags;
> - datatype_set(*expr, concat_type_alloc(ntype));
> + datatype_set_take(*expr, concat_type_alloc(ntype));
> (*expr)->len = size;
>
> if (off > 0)
> @@ -1887,10 +1886,11 @@ static int mapping_expr_expand(struct eval_ctx *ctx)
>
> static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
> {
The update here in expr_evaluate_map() seems to be related to this
chunk:
dtype = set_datatype_alloc(ectx.dtype, ectx.byteorder);
if (dtype->type == TYPE_VERDICT)
data = verdict_expr_alloc(&netlink_location, 0, NULL);
else
data = constant_expr_alloc(&netlink_location, dtype,
dtype->byteorder, ectx.len, NULL);
turn this into:
if (ectx.dtype->type == TYPE_VERDICT) {
data = verdict_expr_alloc(&netlink_location, 0, NULL);
} else {
dtype = set_datatype_alloc(ectx.dtype, ectx.byteorder);
data = constant_expr_alloc(&netlink_location, dtype,
dtype->byteorder, ectx.len, NULL);
}
to disentangle this.
dtype is now attached to the constant expression, so there is no need
to handle for datatype_free() case anymore in this function (this will
significantly reduce the size of this patch).
> + const struct datatype *dtype = NULL;
> struct expr *map = *expr, *mappings;
> struct expr_ctx ectx = ctx->ectx;
> - const struct datatype *dtype;
> struct expr *key, *data;
> + int r;
>
> if (map->map->etype == EXPR_CT &&
> (map->map->ct.key == NFT_CT_SRC ||
> @@ -1948,23 +1948,31 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
> map->mappings = mappings;
>
> ctx->set = mappings->set;
> - if (expr_evaluate(ctx, &map->mappings->set->init) < 0)
> - return -1;
> + if (expr_evaluate(ctx, &map->mappings->set->init) < 0) {
> + r = -1;
> + goto out;
> + }
>
> if (set_is_interval(map->mappings->set->init->set_flags) &&
> !(map->mappings->set->init->set_flags & NFT_SET_CONCAT) &&
> - interval_set_eval(ctx, ctx->set, map->mappings->set->init) < 0)
> - return -1;
> + interval_set_eval(ctx, ctx->set, map->mappings->set->init) < 0) {
> + r = -1;
> + goto out;
> + }
>
> expr_set_context(&ctx->ectx, ctx->set->key->dtype, ctx->set->key->len);
> - if (binop_transfer(ctx, expr) < 0)
> - return -1;
> + if (binop_transfer(ctx, expr) < 0) {
> + r = -1;
> + goto out;
> + }
>
> if (ctx->set->data->flags & EXPR_F_INTERVAL) {
> ctx->set->data->len *= 2;
>
> - if (mapping_expr_expand(ctx))
> - return -1;
> + if (mapping_expr_expand(ctx)) {
> + r = -1;
> + goto out;
> + }
> }
>
> ctx->set->key->len = ctx->ectx.len;
> @@ -1974,12 +1982,16 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
> map_set_concat_info(map);
> break;
> case EXPR_SYMBOL:
> - if (expr_evaluate(ctx, &map->mappings) < 0)
> - return -1;
> + if (expr_evaluate(ctx, &map->mappings) < 0) {
> + r = -1;
> + goto out;
> + }
> if (map->mappings->etype != EXPR_SET_REF ||
> - !set_is_datamap(map->mappings->set->flags))
> - return expr_error(ctx->msgs, map->mappings,
> + !set_is_datamap(map->mappings->set->flags)) {
> + r = expr_error(ctx->msgs, map->mappings,
> "Expression is not a map");
> + goto out;
> + }
> break;
> case EXPR_SET_REF:
> /* symbol has been already evaluated to set reference */
> @@ -1989,22 +2001,30 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
> expr_name(map->mappings));
> }
>
> - if (!datatype_equal(map->map->dtype, map->mappings->set->key->dtype))
> - return expr_binary_error(ctx->msgs, map->mappings, map->map,
> + if (!datatype_equal(map->map->dtype, map->mappings->set->key->dtype)) {
> + r = expr_binary_error(ctx->msgs, map->mappings, map->map,
> "datatype mismatch, map expects %s, "
> "mapping expression has type %s",
> map->mappings->set->key->dtype->desc,
> map->map->dtype->desc);
> + goto out;
> + }
>
> datatype_set(map, map->mappings->set->data->dtype);
> map->flags |= EXPR_F_CONSTANT;
>
> /* Data for range lookups needs to be in big endian order */
> if (map->mappings->set->flags & NFT_SET_INTERVAL &&
> - byteorder_conversion(ctx, &map->map, BYTEORDER_BIG_ENDIAN) < 0)
> - return -1;
> + byteorder_conversion(ctx, &map->map, BYTEORDER_BIG_ENDIAN) < 0) {
> + r = -1;
> + goto out;
> + }
>
> - return 0;
> + r = 0;
> +
> +out:
> + datatype_free(dtype);
> + return r;
> }
>
> static bool data_mapping_has_interval(struct expr *data)
> @@ -3766,8 +3786,10 @@ static int stmt_evaluate_nat_map(struct eval_ctx *ctx, struct stmt *stmt)
> {
> struct proto_ctx *pctx = eval_proto_ctx(ctx);
> struct expr *one, *two, *data, *tmp;
> - const struct datatype *dtype;
> - int addr_type, err;
> + const struct datatype *dtype = NULL;
> + const struct datatype *dtype2;
> + int addr_type;
> + int r;
>
> if (stmt->nat.family == NFPROTO_INET)
> expr_family_infer(pctx, stmt->nat.addr, &stmt->nat.family);
> @@ -3787,18 +3809,23 @@ static int stmt_evaluate_nat_map(struct eval_ctx *ctx, struct stmt *stmt)
> dtype = concat_type_alloc((addr_type << TYPE_BITS) | TYPE_INET_SERVICE);
>
> expr_set_context(&ctx->ectx, dtype, dtype->size);
> - if (expr_evaluate(ctx, &stmt->nat.addr))
> - return -1;
> + if (expr_evaluate(ctx, &stmt->nat.addr)) {
> + r = -1;
Could you use something larger that `r' ? I use pattern matching when
searching for variables in my editor, and this is too short. If you
dislike 'err' and 'ret' just pick something else, please.
> + goto out;
> + }
>
> if (pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc == NULL &&
> !nat_evaluate_addr_has_th_expr(stmt->nat.addr)) {
> - return stmt_binary_error(ctx, stmt->nat.addr, stmt,
> + r = stmt_binary_error(ctx, stmt->nat.addr, stmt,
> "transport protocol mapping is only "
> "valid after transport protocol match");
> + goto out;
> }
>
> - if (stmt->nat.addr->etype != EXPR_MAP)
> - return 0;
> + if (stmt->nat.addr->etype != EXPR_MAP) {
> + r = 0;
> + goto out;
> + }
>
> data = stmt->nat.addr->mappings->set->data;
> if (data->flags & EXPR_F_INTERVAL)
> @@ -3806,37 +3833,43 @@ static int stmt_evaluate_nat_map(struct eval_ctx *ctx, struct stmt *stmt)
>
> datatype_set(data, dtype);
Note here above, dtype is set to data expression, then...
>
> - if (expr_ops(data)->type != EXPR_CONCAT)
> - return __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
> + if (expr_ops(data)->type != EXPR_CONCAT) {
> + r = __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
> BYTEORDER_BIG_ENDIAN,
> &stmt->nat.addr);
> + goto out;
... this goto is not needed anymore? dtype has been already set to data.
So this patch can be simplified. Same things for goto below in the
scope of this function.
> + }
>
> one = list_first_entry(&data->expressions, struct expr, list);
> two = list_entry(one->list.next, struct expr, list);
>
> - if (one == two || !list_is_last(&two->list, &data->expressions))
> - return __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
> + if (one == two || !list_is_last(&two->list, &data->expressions)) {
> + r = __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
> BYTEORDER_BIG_ENDIAN,
> &stmt->nat.addr);
> + goto out;
> + }
>
> - dtype = get_addr_dtype(stmt->nat.family);
> + dtype2 = get_addr_dtype(stmt->nat.family);
> tmp = one;
> - err = __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
> + r = __stmt_evaluate_arg(ctx, stmt, dtype2, dtype2->size,
> BYTEORDER_BIG_ENDIAN,
> &tmp);
> - if (err < 0)
> - return err;
> + if (r < 0)
> + goto out;
> if (tmp != one)
> BUG("Internal error: Unexpected alteration of l3 expression");
>
> tmp = two;
> - err = nat_evaluate_transport(ctx, stmt, &tmp);
> - if (err < 0)
> - return err;
> + r = nat_evaluate_transport(ctx, stmt, &tmp);
> + if (r < 0)
> + goto out;
> if (tmp != two)
> BUG("Internal error: Unexpected alteration of l4 expression");
>
> - return err;
> +out:
> + datatype_free(dtype);
> + return r;
> }
>
> static bool nat_concat_map(struct eval_ctx *ctx, struct stmt *stmt)
> @@ -4550,8 +4583,7 @@ static int set_expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
> dtype = datatype_clone(i->dtype);
> dtype->size = i->len;
> dtype->byteorder = i->byteorder;
> - dtype->refcnt = 1;
> - i->dtype = dtype;
> + datatype_set_take(i, dtype);
> }
>
> if (i->dtype->size == 0 && i->len == 0)
> @@ -4574,7 +4606,7 @@ static int set_expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
> }
>
> (*expr)->flags |= flags;
> - datatype_set(*expr, concat_type_alloc(ntype));
> + datatype_set_take(*expr, concat_type_alloc(ntype));
> (*expr)->len = size;
>
> expr_set_context(&ctx->ectx, (*expr)->dtype, (*expr)->len);
> diff --git a/src/expression.c b/src/expression.c
> index 147320f08937..232f48a16f7f 100644
> --- a/src/expression.c
> +++ b/src/expression.c
> @@ -1014,7 +1014,7 @@ static struct expr *concat_expr_parse_udata(const struct nftnl_udata *attr)
> if (!dtype)
> goto err_free;
>
> - concat_expr->dtype = datatype_get(dtype);
> + datatype_set_take(concat_expr, dtype);
> concat_expr->len = len;
>
> return concat_expr;
> diff --git a/src/netlink.c b/src/netlink.c
> index af6fd427bd57..eb559cf33abe 100644
> --- a/src/netlink.c
> +++ b/src/netlink.c
> @@ -799,6 +799,9 @@ enum nft_data_types dtype_map_to_kernel(const struct datatype *dtype)
>
> static const struct datatype *dtype_map_from_kernel(enum nft_data_types type)
> {
> + /* The function always returns ownership of a reference. But for
> + * &verdict_Type and datatype_lookup(), those are static instances,
> + * we can omit the datatype_get() call. */
Please:
/* xxx
* yyy
*/
netdev comment style is preferred.
> switch (type) {
> case NFT_DATA_VERDICT:
> return &verdict_type;
> @@ -934,12 +937,14 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
> const struct nftnl_udata *ud[NFTNL_UDATA_SET_MAX + 1] = {};
> enum byteorder keybyteorder = BYTEORDER_INVALID;
> enum byteorder databyteorder = BYTEORDER_INVALID;
> - const struct datatype *keytype, *datatype = NULL;
> struct expr *typeof_expr_key, *typeof_expr_data;
> struct setelem_parse_ctx set_parse_ctx;
> + const struct datatype *datatype = NULL;
> + const struct datatype *keytype = NULL;
> + const struct datatype *dtype2 = NULL;
> + const struct datatype *dtype = NULL;
> const char *udata, *comment = NULL;
> uint32_t flags, key, objtype = 0;
> - const struct datatype *dtype;
> uint32_t data_interval = 0;
> bool automerge = false;
> struct set *set;
> @@ -978,7 +983,8 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
> if (keytype == NULL) {
> netlink_io_error(ctx, NULL, "Unknown data type in set key %u",
> key);
> - return NULL;
> + set = NULL;
> + goto out;
Why this goto out? Not really needed.
> }
>
> flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
> @@ -991,8 +997,8 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
> netlink_io_error(ctx, NULL,
> "Unknown data type in set key %u",
> data);
> - datatype_free(keytype);
> - return NULL;
> + set = NULL;
> + goto out;
> }
> }
>
> @@ -1030,19 +1036,18 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
> if (datatype) {
Move this code under this if (datatype) branch into function in a
preparation patch.
Please, call it:
netlink_delinearize_set_typeof()
or pick a better name if you like so there is no need for dtype2.
It will help clean up this chunk that you are passing by here.
Thanks!
> uint32_t dlen;
>
> - dtype = set_datatype_alloc(datatype, databyteorder);
> + dtype2 = set_datatype_alloc(datatype, databyteorder);
> klen = nftnl_set_get_u32(nls, NFTNL_SET_DATA_LEN) * BITS_PER_BYTE;
>
> dlen = data_interval ? klen / 2 : klen;
>
> if (set_udata_key_valid(typeof_expr_data, dlen)) {
> typeof_expr_data->len = klen;
> - datatype_free(datatype_get(dtype));
> set->data = typeof_expr_data;
> } else {
> expr_free(typeof_expr_data);
> set->data = constant_expr_alloc(&netlink_location,
> - dtype,
> + dtype2,
> databyteorder, klen,
> NULL);
>
> @@ -1053,16 +1058,12 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
>
> if (data_interval)
> set->data->flags |= EXPR_F_INTERVAL;
> -
> - if (dtype != datatype)
> - datatype_free(datatype);
> }
>
> dtype = set_datatype_alloc(keytype, keybyteorder);
> klen = nftnl_set_get_u32(nls, NFTNL_SET_KEY_LEN) * BITS_PER_BYTE;
>
> if (set_udata_key_valid(typeof_expr_key, klen)) {
> - datatype_free(datatype_get(dtype));
> set->key = typeof_expr_key;
> set->key_typeof_valid = true;
> } else {
> @@ -1072,9 +1073,6 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
> NULL);
> }
>
> - if (dtype != keytype)
> - datatype_free(keytype);
> -
> set->flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
> set->handle.handle.id = nftnl_set_get_u64(nls, NFTNL_SET_HANDLE);
>
> @@ -1102,6 +1100,11 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
> }
> }
>
> +out:
> + datatype_free(datatype);
> + datatype_free(keytype);
> + datatype_free(dtype2);
> + datatype_free(dtype);
> return set;
> }
>
> diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
> index bde783bdf4ad..f4e9dda473c9 100644
> --- a/src/netlink_delinearize.c
> +++ b/src/netlink_delinearize.c
> @@ -2769,7 +2769,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
> }
> ctx->flags &= ~RULE_PP_IN_CONCATENATION;
> list_splice(&tmp, &expr->expressions);
> - datatype_set(expr, concat_type_alloc(ntype));
> + datatype_set_take(expr, concat_type_alloc(ntype));
> break;
> }
> case EXPR_UNARY:
> diff --git a/src/payload.c b/src/payload.c
> index 179ddcbdd3fe..03aa552dec77 100644
> --- a/src/payload.c
> +++ b/src/payload.c
> @@ -254,8 +254,7 @@ static struct expr *payload_expr_parse_udata(const struct nftnl_udata *attr)
> dtype = datatype_clone(&xinteger_type);
> dtype->size = len;
> dtype->byteorder = BYTEORDER_BIG_ENDIAN;
> - dtype->refcnt = 1;
> - expr->dtype = dtype;
> + datatype_set_take(expr, dtype);
> }
>
> if (ud[NFTNL_UDATA_SET_KEY_PAYLOAD_INNER_DESC]) {
> --
> 2.41.0
>
next prev parent reply other threads:[~2023-09-12 2:47 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-11 9:01 [nft PATCH] datatype: fix leak and cleanup reference counting for struct datatype Thomas Haller
2023-09-11 21:39 ` Pablo Neira Ayuso [this message]
2023-09-12 7:18 ` Thomas Haller
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZP+JBMa83ArN1FQD@calendula \
--to=pablo@netfilter.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=thaller@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).