mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
netfilter: nft_payload: fix mask build for partial field offload
nft_payload_offload_mask() builds the offload match mask for a payload
expression that covers only part of a header field. For a partial IPv6
address match (field_len = 16, priv_len = 1) that shift is 1 << 120, which
is undefined on the 32-bit int operand. It also trims only one word, so
the remaining words stay 0xffffffff (and when priv_len is a multiple of 4
the trim is skipped entirely), leaving the mask covering more bytes than
the rule matches.
UBSAN: shift-out-of-bounds in net/netfilter/nft_payload.c:278:20
shift exponent 120 is too large for 32-bit type 'int'
...
The match is byte-granular and struct nft_data is zero-initialised, so the
correct mask is simply the first priv_len bytes set to 0xff. Set those
bytes directly and drop the word/shift trimming; this removes the undefined
shift and no longer over-masks the trailing bytes.
Fixes: a5d45bc0dc ("netfilter: nftables_offload: build mask based from the matching bytes")
Reported-by: AutonomousCodeSecurity@microsoft.com
Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
da7d894c41
commit
39e88f28fb
|
|
@ -259,9 +259,7 @@ static int nft_payload_dump(struct sk_buff *skb,
|
|||
static bool nft_payload_offload_mask(struct nft_offload_reg *reg,
|
||||
u32 priv_len, u32 field_len)
|
||||
{
|
||||
unsigned int remainder, delta, k;
|
||||
struct nft_data mask = {};
|
||||
__be32 remainder_mask;
|
||||
|
||||
if (priv_len == field_len) {
|
||||
memset(®->mask, 0xff, priv_len);
|
||||
|
|
@ -270,15 +268,7 @@ static bool nft_payload_offload_mask(struct nft_offload_reg *reg,
|
|||
return false;
|
||||
}
|
||||
|
||||
memset(&mask, 0xff, field_len);
|
||||
remainder = priv_len % sizeof(u32);
|
||||
if (remainder) {
|
||||
k = priv_len / sizeof(u32);
|
||||
delta = field_len - priv_len;
|
||||
remainder_mask = htonl(~((1 << (delta * BITS_PER_BYTE)) - 1));
|
||||
mask.data[k] = (__force u32)remainder_mask;
|
||||
}
|
||||
|
||||
memset(&mask, 0xff, priv_len);
|
||||
memcpy(®->mask, &mask, field_len);
|
||||
|
||||
return true;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user