diff options
| author | Cong Wang <cong.wang@bytedance.com> | 2024-12-12 19:40:54 -0800 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2025-01-02 10:34:11 +0100 |
| commit | 997cf2d8c206941b501799034edb0fb011716144 (patch) | |
| tree | f5615c61acf5910b289511166f9a0cdf78b43e3e /net | |
| parent | 4aa5dcb3891ffca0b09c3dd45328dc2b77194069 (diff) | |
| download | linux-997cf2d8c206941b501799034edb0fb011716144.tar.gz linux-997cf2d8c206941b501799034edb0fb011716144.tar.bz2 linux-997cf2d8c206941b501799034edb0fb011716144.zip | |
bpf: Check negative offsets in __bpf_skb_min_len()
[ Upstream commit 9ecc4d858b92c1bb0673ad9c327298e600c55659 ]
skb_network_offset() and skb_transport_offset() can be negative when
they are called after we pull the transport header, for example, when
we use eBPF sockmap at the point of ->sk_data_ready().
__bpf_skb_min_len() uses an unsigned int to get these offsets, this
leads to a very large number which then causes bpf_skb_change_tail()
failed unexpectedly.
Fix this by using a signed int to get these offsets and ensure the
minimum is at least zero.
Fixes: 5293efe62df8 ("bpf: add bpf_skb_change_tail helper")
Signed-off-by: Cong Wang <cong.wang@bytedance.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: John Fastabend <john.fastabend@gmail.com>
Link: https://lore.kernel.org/bpf/20241213034057.246437-2-xiyou.wangcong@gmail.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'net')
| -rw-r--r-- | net/core/filter.c | 21 |
1 files changed, 15 insertions, 6 deletions
diff --git a/net/core/filter.c b/net/core/filter.c index 9a459213d283..55495063621d 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -3751,13 +3751,22 @@ static const struct bpf_func_proto bpf_skb_adjust_room_proto = { static u32 __bpf_skb_min_len(const struct sk_buff *skb) { - u32 min_len = skb_network_offset(skb); + int offset = skb_network_offset(skb); + u32 min_len = 0; - if (skb_transport_header_was_set(skb)) - min_len = skb_transport_offset(skb); - if (skb->ip_summed == CHECKSUM_PARTIAL) - min_len = skb_checksum_start_offset(skb) + - skb->csum_offset + sizeof(__sum16); + if (offset > 0) + min_len = offset; + if (skb_transport_header_was_set(skb)) { + offset = skb_transport_offset(skb); + if (offset > 0) + min_len = offset; + } + if (skb->ip_summed == CHECKSUM_PARTIAL) { + offset = skb_checksum_start_offset(skb) + + skb->csum_offset + sizeof(__sum16); + if (offset > 0) + min_len = offset; + } return min_len; } |
