Commit 61002418 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso Committed by Wang Hai
Browse files

netfilter: nf_tables: fully validate NFT_DATA_VALUE on store to data registers

stable inclusion
from stable-v5.10.221
commit 5d43d789b57943720dca4181a05f6477362b94cf
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IAGEO4
CVE: CVE-2024-42070

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=5d43d789b57943720dca4181a05f6477362b94cf



--------------------------------

[ Upstream commit 7931d32955e09d0a11b1fe0b6aac1bfa061c005c ]

register store validation for NFT_DATA_VALUE is conditional, however,
the datatype is always either NFT_DATA_VALUE or NFT_DATA_VERDICT. This
only requires a new helper function to infer the register type from the
set datatype so this conditional check can be removed. Otherwise,
pointer to chain object can be leaked through the registers.

Fixes: 96518518 ("netfilter: add nftables")
Reported-by: default avatarLinus Torvalds <torvalds@linuxfoundation.org>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarWang Hai <wanghai38@huawei.com>
parent ddbf1dbd
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -504,6 +504,11 @@ static inline void *nft_set_priv(const struct nft_set *set)
	return (void *)set->data;
}

static inline enum nft_data_types nft_set_datatype(const struct nft_set *set)
{
	return set->dtype == NFT_DATA_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE;
}

static inline bool nft_set_gc_is_pending(const struct nft_set *s)
{
	return refcount_read(&s->refs) != 1;
+4 −4
Original line number Diff line number Diff line
@@ -5007,8 +5007,7 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,

	if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) &&
	    nft_data_dump(skb, NFTA_SET_ELEM_DATA, nft_set_ext_data(ext),
			  set->dtype == NFT_DATA_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE,
			  set->dlen) < 0)
			  nft_set_datatype(set), set->dlen) < 0)
		goto nla_put_failure;

	if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPR) &&
@@ -9382,6 +9381,9 @@ static int nft_validate_register_store(const struct nft_ctx *ctx,

		return 0;
	default:
		if (type != NFT_DATA_VALUE)
			return -EINVAL;

		if (reg < NFT_REG_1 * NFT_REG_SIZE / NFT_REG32_SIZE)
			return -EINVAL;
		if (len == 0)
@@ -9390,8 +9392,6 @@ static int nft_validate_register_store(const struct nft_ctx *ctx,
		    sizeof_field(struct nft_regs, data))
			return -ERANGE;

		if (data != NULL && type != NFT_DATA_VALUE)
			return -EINVAL;
		return 0;
	}
}
+2 −1
Original line number Diff line number Diff line
@@ -101,7 +101,8 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
			return -EINVAL;

		err = nft_parse_register_store(ctx, tb[NFTA_LOOKUP_DREG],
					       &priv->dreg, NULL, set->dtype,
					       &priv->dreg, NULL,
					       nft_set_datatype(set),
					       set->dlen);
		if (err < 0)
			return err;