| From 48f97c2fad6e12d860ed5af5a3e4304af2a22f02 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 6 Dec 2019 22:09:14 +0100 |
| Subject: netfilter: nf_tables: validate NFT_DATA_VALUE after nft_data_init() |
| |
| From: Pablo Neira Ayuso <pablo@netfilter.org> |
| |
| [ Upstream commit 0d2c96af797ba149e559c5875c0151384ab6dd14 ] |
| |
| Userspace might bogusly sent NFT_DATA_VERDICT in several netlink |
| attributes that assume NFT_DATA_VALUE. Moreover, make sure that error |
| path invokes nft_data_release() to decrement the reference count on the |
| chain object. |
| |
| Fixes: 96518518cc41 ("netfilter: add nftables") |
| Fixes: 0f3cd9b36977 ("netfilter: nf_tables: add range expression") |
| Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/netfilter/nf_tables_api.c | 4 +++- |
| net/netfilter/nft_bitwise.c | 4 ++-- |
| net/netfilter/nft_cmp.c | 6 ++++++ |
| net/netfilter/nft_range.c | 10 ++++++++++ |
| 4 files changed, 21 insertions(+), 3 deletions(-) |
| |
| diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c |
| index 7120eba71ac5..4c03c14e46bc 100644 |
| --- a/net/netfilter/nf_tables_api.c |
| +++ b/net/netfilter/nf_tables_api.c |
| @@ -4252,8 +4252,10 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set, |
| return err; |
| |
| err = -EINVAL; |
| - if (desc.type != NFT_DATA_VALUE || desc.len != set->klen) |
| + 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)) |
| diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c |
| index 02afa752dd2e..10e9d50e4e19 100644 |
| --- a/net/netfilter/nft_bitwise.c |
| +++ b/net/netfilter/nft_bitwise.c |
| @@ -80,7 +80,7 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, |
| tb[NFTA_BITWISE_MASK]); |
| if (err < 0) |
| return err; |
| - if (d1.len != priv->len) { |
| + if (d1.type != NFT_DATA_VALUE || d1.len != priv->len) { |
| err = -EINVAL; |
| goto err1; |
| } |
| @@ -89,7 +89,7 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, |
| tb[NFTA_BITWISE_XOR]); |
| if (err < 0) |
| goto err1; |
| - if (d2.len != priv->len) { |
| + if (d2.type != NFT_DATA_VALUE || d2.len != priv->len) { |
| err = -EINVAL; |
| goto err2; |
| } |
| diff --git a/net/netfilter/nft_cmp.c b/net/netfilter/nft_cmp.c |
| index 0744b2bb46da..ae730dba60c8 100644 |
| --- a/net/netfilter/nft_cmp.c |
| +++ b/net/netfilter/nft_cmp.c |
| @@ -80,6 +80,12 @@ static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr, |
| if (err < 0) |
| return err; |
| |
| + if (desc.type != NFT_DATA_VALUE) { |
| + err = -EINVAL; |
| + nft_data_release(&priv->data, desc.type); |
| + return err; |
| + } |
| + |
| priv->sreg = nft_parse_register(tb[NFTA_CMP_SREG]); |
| err = nft_validate_register_load(priv->sreg, desc.len); |
| if (err < 0) |
| diff --git a/net/netfilter/nft_range.c b/net/netfilter/nft_range.c |
| index 4701fa8a45e7..89efcc5a533d 100644 |
| --- a/net/netfilter/nft_range.c |
| +++ b/net/netfilter/nft_range.c |
| @@ -66,11 +66,21 @@ static int nft_range_init(const struct nft_ctx *ctx, const struct nft_expr *expr |
| if (err < 0) |
| return err; |
| |
| + if (desc_from.type != NFT_DATA_VALUE) { |
| + err = -EINVAL; |
| + goto err1; |
| + } |
| + |
| err = nft_data_init(NULL, &priv->data_to, sizeof(priv->data_to), |
| &desc_to, tb[NFTA_RANGE_TO_DATA]); |
| if (err < 0) |
| goto err1; |
| |
| + if (desc_to.type != NFT_DATA_VALUE) { |
| + err = -EINVAL; |
| + goto err2; |
| + } |
| + |
| if (desc_from.len != desc_to.len) { |
| err = -EINVAL; |
| goto err2; |
| -- |
| 2.20.1 |
| |