summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorCong Wang <cong.wang@bytedance.com>2024-12-13 04:40:54 +0100
committerDaniel Borkmann <daniel@iogearbox.net>2024-12-20 23:13:31 +0100
commit9ecc4d858b92c1bb0673ad9c327298e600c55659 (patch)
treead4cc5de86b1a3c6304cbc6d0053a2e49ddbcdf6 /net
parenttcp_bpf: Fix copied value in tcp_bpf_sendmsg (diff)
downloadlinux-9ecc4d858b92c1bb0673ad9c327298e600c55659.tar.xz
linux-9ecc4d858b92c1bb0673ad9c327298e600c55659.zip
bpf: Check negative offsets in __bpf_skb_min_len()
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
Diffstat (limited to 'net')
-rw-r--r--net/core/filter.c21
1 files changed, 15 insertions, 6 deletions
diff --git a/net/core/filter.c b/net/core/filter.c
index 21131ec25f24..834614071727 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -3734,13 +3734,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;
}