]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
netlink: add and use nft_data_memcpy helper
authorFlorian Westphal <fw@strlen.de>
Fri, 8 Dec 2023 14:34:29 +0000 (15:34 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 22 Jan 2025 23:05:48 +0000 (00:05 +0100)
commit 130060afa9f6f11e14ea5cf372545407179f16ac upstream.

There is a stack overflow somewhere in this code, we end
up memcpy'ing a way too large expr into a fixed-size on-stack
buffer.

This is hard to diagnose, most of this code gets inlined so
the crash happens later on return from alloc_nftnl_setelem.

Condense the mempy into a helper and add a BUG so we can catch
the overflow before it occurs.

->value is too small (4, should be 16), but for normal
cases (well-formed data must fit into max reg space, i.e.
64 byte) the chain buffer that comes after value in the
structure provides a cushion.

In order to have the new BUG() not trigger on valid data,
bump value to the correct size, this is userspace so the additional
60 bytes of stack usage is no concern.

Signed-off-by: Florian Westphal <fw@strlen.de>
include/netlink.h
src/netlink.c

index 63d07edf419eacac1e1f816c8a61602903ae7a91..2baa24175430244d5c5329325474d0d10edca6d9 100644 (file)
@@ -92,7 +92,7 @@ extern struct nftnl_rule *netlink_rule_alloc(const struct nlmsghdr *nlh);
 
 struct nft_data_linearize {
        uint32_t        len;
-       uint32_t        value[4];
+       uint32_t        value[NFT_REG32_COUNT];
        char            chain[NFT_CHAIN_MAXNAMELEN];
        uint32_t        chain_id;
        int             verdict;
index 4d7c7458382a6507a851ed32f9cd8019d4c28ac7..a562000f6c12e9e36ee71e965fdf499a893fce7c 100644 (file)
@@ -307,6 +307,16 @@ static int __netlink_gen_concat_key(uint32_t flags, const struct expr *i,
        return netlink_export_pad(data, i->value, i);
 }
 
+static void nft_data_memcpy(struct nft_data_linearize *nld,
+                           const void *src, unsigned int len)
+{
+       if (len > sizeof(nld->value))
+               BUG("nld buffer overflow: want to copy %u, max %u\n", len, (unsigned int)sizeof(nld->value));
+
+       memcpy(nld->value, src, len);
+       nld->len = len;
+}
+
 static void netlink_gen_concat_key(const struct expr *expr,
                                    struct nft_data_linearize *nld)
 {
@@ -319,8 +329,7 @@ static void netlink_gen_concat_key(const struct expr *expr,
        list_for_each_entry(i, &expr->expressions, list)
                offset += __netlink_gen_concat_key(expr->flags, i, data + offset);
 
-       memcpy(nld->value, data, len);
-       nld->len = len;
+       nft_data_memcpy(nld, data, len);
 }
 
 static int __netlink_gen_concat_data(int end, const struct expr *i,
@@ -366,8 +375,7 @@ static void __netlink_gen_concat_expand(const struct expr *expr,
        list_for_each_entry(i, &expr->expressions, list)
                offset += __netlink_gen_concat_data(true, i, data + offset);
 
-       memcpy(nld->value, data, len);
-       nld->len = len;
+       nft_data_memcpy(nld, data, len);
 }
 
 static void __netlink_gen_concat(const struct expr *expr,
@@ -382,8 +390,7 @@ static void __netlink_gen_concat(const struct expr *expr,
        list_for_each_entry(i, &expr->expressions, list)
                offset += __netlink_gen_concat_data(expr->flags, i, data + offset);
 
-       memcpy(nld->value, data, len);
-       nld->len = len;
+       nft_data_memcpy(nld, data, len);
 }
 
 static void netlink_gen_concat_data(const struct expr *expr,
@@ -452,8 +459,7 @@ static void netlink_gen_range(const struct expr *expr,
        memset(data, 0, len);
        offset = netlink_export_pad(data, expr->left->value, expr->left);
        netlink_export_pad(data + offset, expr->right->value, expr->right);
-       memcpy(nld->value, data, len);
-       nld->len = len;
+       nft_data_memcpy(nld, data, len);
 }
 
 static void netlink_gen_prefix(const struct expr *expr,
@@ -470,8 +476,7 @@ static void netlink_gen_prefix(const struct expr *expr,
        netlink_export_pad(data + offset, v, expr->prefix);
        mpz_clear(v);
 
-       memcpy(nld->value, data, len);
-       nld->len = len;
+       nft_data_memcpy(nld, data, len);
 }
 
 static void netlink_gen_key(const struct expr *expr,