summaryrefslogtreecommitdiffstats
path: root/src/netlink.c
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2023-12-13 17:41:26 +0100
committerFlorian Westphal <fw@strlen.de>2023-12-15 02:28:15 +0100
commit600b84631410a6e853c208795246ea0c9df95c12 (patch)
treeaba47213f3e16b7d3fa8ca300a9551b8ba0b2cc5 /src/netlink.c
parentef10d65db278d77208e960d210a1f4f532ebb552 (diff)
netlink: fix stack buffer overflow with sub-reg sized prefixes
The calculation of the dynamic on-stack array is incorrect, the scratch space can be too low which gives stack corruption: AddressSanitizer: dynamic-stack-buffer-overflow on address 0x7ffdb454f064.. #1 0x7fabe92aaac4 in __mpz_export_data src/gmputil.c:108 #2 0x7fabe92d71b1 in netlink_export_pad src/netlink.c:251 #3 0x7fabe92d91d8 in netlink_gen_prefix src/netlink.c:476 div_round_up() cannot be used here, it fails to account for register padding. A 16 bit prefix will need 2 registers (start, end -- 8 bytes in total). Remove the dynamic sizing and add an assertion in case upperlayer ever passes invalid expr sizes down to us. After this fix, the combination is rejected by the kernel because of the maps' wrong data size, before the fix userspace may crash before. Signed-off-by: Florian Westphal <fw@strlen.de>
Diffstat (limited to 'src/netlink.c')
-rw-r--r--src/netlink.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/src/netlink.c b/src/netlink.c
index 76e6be58..32b18995 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -465,11 +465,14 @@ static void netlink_gen_range(const struct expr *expr,
static void netlink_gen_prefix(const struct expr *expr,
struct nft_data_linearize *nld)
{
- unsigned int len = div_round_up(expr->len, BITS_PER_BYTE) * 2;
- unsigned char data[len];
+ unsigned int len = (netlink_padded_len(expr->len) / BITS_PER_BYTE) * 2;
+ unsigned char data[NFT_MAX_EXPR_LEN_BYTES];
int offset;
mpz_t v;
+ if (len > sizeof(data))
+ BUG("Value export of %u bytes would overflow", len);
+
offset = netlink_export_pad(data, expr->prefix->value, expr);
mpz_init_bitmask(v, expr->len - expr->prefix_len);
mpz_add(v, expr->prefix->value, v);