mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-14 16:46:15 -04:00
rmnet_core: Strengthen IPv6 fragment check in rmnet_frag_skip_exthdr()
Apparently, 4-6 XLAT scenarios can insert an empty fragment header into the IPv6 header chain to indicate that fragmentation is supported in the host IPv4 network. This header contains 0 for both the fragment_offset and MF fields, so simply checking the value of frag_off passed to the rmnet_frag_ipv6_skip_exthdr() function is not sufficient to properly catch this rogue header. Instead, we need to implement a "less clever" version. kernel oops at net/core/skbuff.c:4217! Call trace: skb_segment+0xcf0/0xd2c __udp_gso_segment+0xa4/0x544 udp6_ufo_fragment+0x2dc/0x344 ipv6_gso_segment+0x170/0x350 skb_mac_gso_segment+0xd4/0x1b0 __skb_gso_segment+0xcc/0x12c udp_rcv_segment.76914+0x54/0x16c udpv6_queue_rcv_skb+0x78/0x148 __udp6_lib_rcv+0x38c/0x4cc udpv6_rcv+0x20/0x30 ip6_protocol_deliver_rcu+0x3c0/0x63c ip6_input+0x60/0x184 ip6_rcv_finish+0x84/0x150 ipv6_rcv+0x5c/0x14c __netif_receive_skb+0x80/0x184 Change-Id: Ica2779b1da17bc46d397b42283369f3750edbf82 Signed-off-by: Sean Tranchetti <quic_stranche@quicinc.com> Signed-off-by: Sharath Chandra Vurukala <quic_sharathv@quicinc.com>
This commit is contained in:
parent
a2e9110709
commit
916deeb7c7
2 changed files with 25 additions and 9 deletions
|
|
@ -323,12 +323,13 @@ int rmnet_frag_descriptor_add_frags_from(struct rmnet_frag_descriptor *to,
|
|||
EXPORT_SYMBOL(rmnet_frag_descriptor_add_frags_from);
|
||||
|
||||
int rmnet_frag_ipv6_skip_exthdr(struct rmnet_frag_descriptor *frag_desc,
|
||||
int start, u8 *nexthdrp, __be16 *fragp)
|
||||
int start, u8 *nexthdrp, __be16 *frag_offp,
|
||||
bool *frag_hdrp)
|
||||
{
|
||||
u8 nexthdr = *nexthdrp;
|
||||
|
||||
*fragp = 0;
|
||||
|
||||
*frag_offp = 0;
|
||||
*frag_hdrp = false;
|
||||
while (ipv6_ext_hdr(nexthdr)) {
|
||||
struct ipv6_opt_hdr *hp, __hp;
|
||||
int hdrlen;
|
||||
|
|
@ -350,8 +351,9 @@ int rmnet_frag_ipv6_skip_exthdr(struct rmnet_frag_descriptor *frag_desc,
|
|||
if (!fp)
|
||||
return -EINVAL;
|
||||
|
||||
*fragp = *fp;
|
||||
if (ntohs(*fragp) & ~0x7)
|
||||
*frag_offp = *fp;
|
||||
*frag_hdrp = true;
|
||||
if (ntohs(*frag_offp) & ~0x7)
|
||||
break;
|
||||
hdrlen = 8;
|
||||
} else if (nexthdr == NEXTHDR_AUTH) {
|
||||
|
|
@ -1144,6 +1146,7 @@ rmnet_frag_segment_coal_data(struct rmnet_frag_descriptor *coal_desc,
|
|||
struct ipv6hdr *ip6h, __ip6h;
|
||||
int ip_len;
|
||||
__be16 frag_off;
|
||||
bool frag_hdr;
|
||||
u8 protocol;
|
||||
|
||||
ip6h = rmnet_frag_header_ptr(coal_desc, 0, sizeof(*ip6h),
|
||||
|
|
@ -1156,10 +1159,11 @@ rmnet_frag_segment_coal_data(struct rmnet_frag_descriptor *coal_desc,
|
|||
ip_len = rmnet_frag_ipv6_skip_exthdr(coal_desc,
|
||||
sizeof(*ip6h),
|
||||
&protocol,
|
||||
&frag_off);
|
||||
&frag_off,
|
||||
&frag_hdr);
|
||||
coal_desc->trans_proto = protocol;
|
||||
|
||||
/* If we run into a problem, or this has a fragment header
|
||||
/* If we run into a problem, or this is fragmented packet
|
||||
* (which should technically not be possible, if the HW
|
||||
* works as intended...), bail.
|
||||
*/
|
||||
|
|
@ -1168,6 +1172,14 @@ rmnet_frag_segment_coal_data(struct rmnet_frag_descriptor *coal_desc,
|
|||
return;
|
||||
}
|
||||
|
||||
if (frag_hdr) {
|
||||
/* There is a fragment header, but this is not a
|
||||
* fragmented packet. We can handle this, but it
|
||||
* cannot be coalesced because of kernel limitations.
|
||||
*/
|
||||
gro = false;
|
||||
}
|
||||
|
||||
coal_desc->ip_len = (u16)ip_len;
|
||||
if (coal_desc->ip_len > sizeof(*ip6h)) {
|
||||
/* Don't allow coalescing of any packets with IPv6
|
||||
|
|
@ -1449,6 +1461,7 @@ static int rmnet_frag_checksum_pkt(struct rmnet_frag_descriptor *frag_desc)
|
|||
struct ipv6hdr *ip6h, __ip6h;
|
||||
int ip_len;
|
||||
__be16 frag_off;
|
||||
bool frag_hdr;
|
||||
u8 protocol;
|
||||
|
||||
ip6h = rmnet_frag_header_ptr(frag_desc, offset, sizeof(*ip6h),
|
||||
|
|
@ -1460,7 +1473,8 @@ static int rmnet_frag_checksum_pkt(struct rmnet_frag_descriptor *frag_desc)
|
|||
protocol = ip6h->nexthdr;
|
||||
ip_len = rmnet_frag_ipv6_skip_exthdr(frag_desc,
|
||||
offset + sizeof(*ip6h),
|
||||
&protocol, &frag_off);
|
||||
&protocol, &frag_off,
|
||||
&frag_hdr);
|
||||
if (ip_len < 0 || frag_off)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
|
@ -75,7 +76,8 @@ int rmnet_frag_descriptor_add_frags_from(struct rmnet_frag_descriptor *to,
|
|||
struct rmnet_frag_descriptor *from,
|
||||
u32 off, u32 len);
|
||||
int rmnet_frag_ipv6_skip_exthdr(struct rmnet_frag_descriptor *frag_desc,
|
||||
int start, u8 *nexthdrp, __be16 *fragp);
|
||||
int start, u8 *nexthdrp, __be16 *frag_offp,
|
||||
bool *frag_hdrp);
|
||||
|
||||
/* QMAP command packets */
|
||||
void rmnet_frag_command(struct rmnet_frag_descriptor *frag_desc,
|
||||
|
|
|
|||
Loading…
Reference in a new issue