]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
netfilter: nf_tables: fully validate NFT_DATA_VALUE on store to data registers
authorPablo Neira Ayuso <pablo@netfilter.org>
Wed, 26 Jun 2024 21:15:38 +0000 (23:15 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Jul 2024 07:08:27 +0000 (09:08 +0200)
[ 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: 96518518cc41 ("netfilter: add nftables")
Reported-by: Linus Torvalds <torvalds@linuxfoundation.org>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
include/net/netfilter/nf_tables.h
net/netfilter/nf_tables_api.c
net/netfilter/nft_lookup.c

index cf314ce2fd17825baae483ea2920a849349f6c01..4f77e2f8e1ca8e80c74285101c9405fe56bf3e51 100644 (file)
@@ -467,6 +467,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;
index 44d4d97b45d135aa8ee487e723ca0c87cf4085f5..ddbb0f4bff427045c8486e0428c652ee86f0ace2 100644 (file)
@@ -4301,8 +4301,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) &&
@@ -8048,6 +8047,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)
@@ -8056,8 +8058,6 @@ static int nft_validate_register_store(const struct nft_ctx *ctx,
                    FIELD_SIZEOF(struct nft_regs, data))
                        return -ERANGE;
 
-               if (data != NULL && type != NFT_DATA_VALUE)
-                       return -EINVAL;
                return 0;
        }
 }
index e0ffd463a13208cbbe91d605169b265643dab86a..6d49b82d598aefe0c318b5556cf4a6974cc41445 100644 (file)
@@ -98,7 +98,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;