Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 28fe1023 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso Committed by Greg Kroah-Hartman
Browse files

netfilter: nf_tables: add nft_setelem_parse_key()



[ 20a1452c35425b2cef76f21f8395ef069dfddfa9 ]

Add helper function to parse the set element key netlink attribute.

v4: No changes
v3: New patch

[sbrivio: refactor error paths and labels; use NFT_DATA_VALUE_MAXLEN
  instead of sizeof(*key) in helper, value can be longer than that;
  rebase]
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent eb5b579b
Loading
Loading
Loading
Loading
+45 −46
Original line number Diff line number Diff line
@@ -4292,11 +4292,28 @@ static int nft_setelem_parse_flags(const struct nft_set *set,
	return 0;
}

static int nft_setelem_parse_key(struct nft_ctx *ctx, struct nft_set *set,
				 struct nft_data *key, struct nlattr *attr)
{
	struct nft_data_desc desc;
	int err;

	err = nft_data_init(ctx, key, NFT_DATA_VALUE_MAXLEN, &desc, attr);
	if (err < 0)
		return err;

	if (desc.type != NFT_DATA_VALUE || desc.len != set->klen) {
		nft_data_release(key, desc.type);
		return -EINVAL;
	}

	return 0;
}

static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
			    const struct nlattr *attr)
{
	struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
	struct nft_data_desc desc;
	struct nft_set_elem elem;
	struct sk_buff *skb;
	uint32_t flags = 0;
@@ -4315,17 +4332,11 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
	if (err < 0)
		return err;

	err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &desc,
	err = nft_setelem_parse_key(ctx, set, &elem.key.val,
				    nla[NFTA_SET_ELEM_KEY]);
	if (err < 0)
		return err;

	err = -EINVAL;
	if (desc.type != NFT_DATA_VALUE || desc.len != set->klen) {
		nft_data_release(&elem.key.val, desc.type);
		return err;
	}

	priv = set->ops->get(ctx->net, set, &elem, flags);
	if (IS_ERR(priv))
		return PTR_ERR(priv);
@@ -4518,13 +4529,13 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
{
	struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
	u8 genmask = nft_genmask_next(ctx->net);
	struct nft_data_desc d1, d2;
	struct nft_set_ext_tmpl tmpl;
	struct nft_set_ext *ext, *ext2;
	struct nft_set_elem elem;
	struct nft_set_binding *binding;
	struct nft_object *obj = NULL;
	struct nft_userdata *udata;
	struct nft_data_desc desc;
	struct nft_data data;
	enum nft_registers dreg;
	struct nft_trans *trans;
@@ -4590,15 +4601,12 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
			return err;
	}

	err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &d1,
	err = nft_setelem_parse_key(ctx, set, &elem.key.val,
				    nla[NFTA_SET_ELEM_KEY]);
	if (err < 0)
		goto err1;
	err = -EINVAL;
	if (d1.type != NFT_DATA_VALUE || d1.len != set->klen)
		goto err2;

	nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, d1.len);
	nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
	if (timeout > 0) {
		nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION);
		if (timeout != set->timeout)
@@ -4621,13 +4629,13 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
	}

	if (nla[NFTA_SET_ELEM_DATA] != NULL) {
		err = nft_data_init(ctx, &data, sizeof(data), &d2,
		err = nft_data_init(ctx, &data, sizeof(data), &desc,
				    nla[NFTA_SET_ELEM_DATA]);
		if (err < 0)
			goto err2;

		err = -EINVAL;
		if (set->dtype != NFT_DATA_VERDICT && d2.len != set->dlen)
		if (set->dtype != NFT_DATA_VERDICT && desc.len != set->dlen)
			goto err3;

		dreg = nft_type_to_reg(set->dtype);
@@ -4644,18 +4652,18 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,

			err = nft_validate_register_store(&bind_ctx, dreg,
							  &data,
							  d2.type, d2.len);
							  desc.type, desc.len);
			if (err < 0)
				goto err3;

			if (d2.type == NFT_DATA_VERDICT &&
			if (desc.type == NFT_DATA_VERDICT &&
			    (data.verdict.code == NFT_GOTO ||
			     data.verdict.code == NFT_JUMP))
				nft_validate_state_update(ctx->net,
							  NFT_VALIDATE_NEED);
		}

		nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, d2.len);
		nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, desc.len);
	}

	/* The full maximum length of userdata can exceed the maximum
@@ -4738,9 +4746,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
	kfree(elem.priv);
err3:
	if (nla[NFTA_SET_ELEM_DATA] != NULL)
		nft_data_release(&data, d2.type);
		nft_data_release(&data, desc.type);
err2:
	nft_data_release(&elem.key.val, d1.type);
	nft_data_release(&elem.key.val, NFT_DATA_VALUE);
err1:
	return err;
}
@@ -4836,7 +4844,6 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
{
	struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
	struct nft_set_ext_tmpl tmpl;
	struct nft_data_desc desc;
	struct nft_set_elem elem;
	struct nft_set_ext *ext;
	struct nft_trans *trans;
@@ -4847,11 +4854,10 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
	err = nla_parse_nested_deprecated(nla, NFTA_SET_ELEM_MAX, attr,
					  nft_set_elem_policy, NULL);
	if (err < 0)
		goto err1;
		return err;

	err = -EINVAL;
	if (nla[NFTA_SET_ELEM_KEY] == NULL)
		goto err1;
		return -EINVAL;

	nft_set_ext_prepare(&tmpl);

@@ -4861,37 +4867,31 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
	if (flags != 0)
		nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);

	err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &desc,
	err = nft_setelem_parse_key(ctx, set, &elem.key.val,
				    nla[NFTA_SET_ELEM_KEY]);
	if (err < 0)
		goto err1;

	err = -EINVAL;
	if (desc.type != NFT_DATA_VALUE || desc.len != set->klen)
		goto err2;
		return err;

	nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, desc.len);
	nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);

	err = -ENOMEM;
	elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, NULL, 0,
				      0, GFP_KERNEL);
	if (elem.priv == NULL)
		goto err2;
		goto fail_elem;

	ext = nft_set_elem_ext(set, elem.priv);
	if (flags)
		*nft_set_ext_flags(ext) = flags;

	trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set);
	if (trans == NULL) {
		err = -ENOMEM;
		goto err3;
	}
	if (trans == NULL)
		goto fail_trans;

	priv = set->ops->deactivate(ctx->net, set, &elem);
	if (priv == NULL) {
		err = -ENOENT;
		goto err4;
		goto fail_ops;
	}
	kfree(elem.priv);
	elem.priv = priv;
@@ -4902,13 +4902,12 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
	list_add_tail(&trans->list, &ctx->net->nft.commit_list);
	return 0;

err4:
fail_ops:
	kfree(trans);
err3:
fail_trans:
	kfree(elem.priv);
err2:
	nft_data_release(&elem.key.val, desc.type);
err1:
fail_elem:
	nft_data_release(&elem.key.val, NFT_DATA_VALUE);
	return err;
}