Skip to content

Commit fd94d9d

Browse files
author
Florian Westphal
committed
netfilter: nftables: exthdr: fix 4-byte stack OOB write
If priv->len is a multiple of 4, then dst[len / 4] can write past the destination array which leads to stack corruption. This construct is necessary to clean the remainder of the register in case ->len is NOT a multiple of the register size, so make it conditional just like nft_payload.c does. The bug was added in 4.1 cycle and then copied/inherited when tcp/sctp and ip option support was added. Bug reported by Zero Day Initiative project (ZDI-CAN-21950, ZDI-CAN-21951, ZDI-CAN-21961). Fixes: 49499c3 ("netfilter: nf_tables: switch registers to 32 bit addressing") Fixes: 935b7f6 ("netfilter: nft_exthdr: add TCP option matching") Fixes: 133dc20 ("netfilter: nft_exthdr: Support SCTP chunks") Fixes: dbb5281 ("netfilter: nf_tables: add support for matching IPv4 options") Signed-off-by: Florian Westphal <fw@strlen.de>
1 parent 1a961e7 commit fd94d9d

File tree

1 file changed

+14
-8
lines changed

1 file changed

+14
-8
lines changed

net/netfilter/nft_exthdr.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ static unsigned int optlen(const u8 *opt, unsigned int offset)
3535
return opt[offset + 1];
3636
}
3737

38+
static int nft_skb_copy_to_reg(const struct sk_buff *skb, int offset, u32 *dest, unsigned int len)
39+
{
40+
if (len % NFT_REG32_SIZE)
41+
dest[len / NFT_REG32_SIZE] = 0;
42+
43+
return skb_copy_bits(skb, offset, dest, len);
44+
}
45+
3846
static void nft_exthdr_ipv6_eval(const struct nft_expr *expr,
3947
struct nft_regs *regs,
4048
const struct nft_pktinfo *pkt)
@@ -56,8 +64,7 @@ static void nft_exthdr_ipv6_eval(const struct nft_expr *expr,
5664
}
5765
offset += priv->offset;
5866

59-
dest[priv->len / NFT_REG32_SIZE] = 0;
60-
if (skb_copy_bits(pkt->skb, offset, dest, priv->len) < 0)
67+
if (nft_skb_copy_to_reg(pkt->skb, offset, dest, priv->len) < 0)
6168
goto err;
6269
return;
6370
err:
@@ -153,8 +160,7 @@ static void nft_exthdr_ipv4_eval(const struct nft_expr *expr,
153160
}
154161
offset += priv->offset;
155162

156-
dest[priv->len / NFT_REG32_SIZE] = 0;
157-
if (skb_copy_bits(pkt->skb, offset, dest, priv->len) < 0)
163+
if (nft_skb_copy_to_reg(pkt->skb, offset, dest, priv->len) < 0)
158164
goto err;
159165
return;
160166
err:
@@ -210,7 +216,8 @@ static void nft_exthdr_tcp_eval(const struct nft_expr *expr,
210216
if (priv->flags & NFT_EXTHDR_F_PRESENT) {
211217
*dest = 1;
212218
} else {
213-
dest[priv->len / NFT_REG32_SIZE] = 0;
219+
if (priv->len % NFT_REG32_SIZE)
220+
dest[priv->len / NFT_REG32_SIZE] = 0;
214221
memcpy(dest, opt + offset, priv->len);
215222
}
216223

@@ -388,9 +395,8 @@ static void nft_exthdr_sctp_eval(const struct nft_expr *expr,
388395
offset + ntohs(sch->length) > pkt->skb->len)
389396
break;
390397

391-
dest[priv->len / NFT_REG32_SIZE] = 0;
392-
if (skb_copy_bits(pkt->skb, offset + priv->offset,
393-
dest, priv->len) < 0)
398+
if (nft_skb_copy_to_reg(pkt->skb, offset + priv->offset,
399+
dest, priv->len) < 0)
394400
break;
395401
return;
396402
}

0 commit comments

Comments
 (0)