summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--net/ipv6/af_inet6.c2
-rw-r--r--net/ipv6/ip6_output.c18
-rw-r--r--net/ipv6/udp.c2
3 files changed, 16 insertions, 6 deletions
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 86578237ee6c..914c7d5c1974 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -825,6 +825,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, u32 features)
sizeof(*ipv6h));
if (proto == IPPROTO_UDP) {
unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
+ if (unfrag_ip6hlen < 0)
+ return ERR_PTR(unfrag_ip6hlen);
fptr = (struct frag_hdr *)(skb_network_header(skb) +
unfrag_ip6hlen);
fptr->frag_off = htons(offset);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index c59f646a7d4f..dd310608c9cb 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -562,13 +562,12 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
{
u16 offset = sizeof(struct ipv6hdr);
- struct ipv6_opt_hdr *exthdr =
- (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
unsigned int packet_len = skb->tail - skb->network_header;
int found_rhdr = 0;
*nexthdr = &ipv6_hdr(skb)->nexthdr;
- while (offset + 1 <= packet_len) {
+ while (offset <= packet_len) {
+ struct ipv6_opt_hdr *exthdr;
switch (**nexthdr) {
@@ -589,13 +588,16 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
return offset;
}
- offset += ipv6_optlen(exthdr);
- *nexthdr = &exthdr->nexthdr;
+ if (offset + sizeof(struct ipv6_opt_hdr) > packet_len)
+ return -EINVAL;
+
exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
offset);
+ offset += ipv6_optlen(exthdr);
+ *nexthdr = &exthdr->nexthdr;
}
- return offset;
+ return -EINVAL;
}
void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
@@ -630,6 +632,10 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
struct net *net = dev_net(skb_dst(skb)->dev);
hlen = ip6_find_1stfragopt(skb, &prevhdr);
+ if (hlen < 0) {
+ err = hlen;
+ goto fail;
+ }
nexthdr = *prevhdr;
mtu = ip6_skb_dst_mtu(skb);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 03a7ed110a1b..8157ae079fa8 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1353,6 +1353,8 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, u32 features)
* bytes to insert fragment header.
*/
unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
+ if (unfrag_ip6hlen < 0)
+ return ERR_PTR(unfrag_ip6hlen);
nexthdr = *prevhdr;
*prevhdr = NEXTHDR_FRAGMENT;
unfrag_len = skb_network_header(skb) - skb_mac_header(skb) +