diff options
Diffstat (limited to 'net/ipv6/fou6.c')
| -rw-r--r-- | net/ipv6/fou6.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/net/ipv6/fou6.c b/net/ipv6/fou6.c index bd675c61deb1..867474abe269 100644 --- a/net/ipv6/fou6.c +++ b/net/ipv6/fou6.c | |||
| @@ -72,7 +72,7 @@ static int gue6_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, | |||
| 72 | 72 | ||
| 73 | static int gue6_err_proto_handler(int proto, struct sk_buff *skb, | 73 | static int gue6_err_proto_handler(int proto, struct sk_buff *skb, |
| 74 | struct inet6_skb_parm *opt, | 74 | struct inet6_skb_parm *opt, |
| 75 | u8 type, u8 code, int offset, u32 info) | 75 | u8 type, u8 code, int offset, __be32 info) |
| 76 | { | 76 | { |
| 77 | const struct inet6_protocol *ipprot; | 77 | const struct inet6_protocol *ipprot; |
| 78 | 78 | ||
| @@ -90,10 +90,11 @@ static int gue6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 90 | { | 90 | { |
| 91 | int transport_offset = skb_transport_offset(skb); | 91 | int transport_offset = skb_transport_offset(skb); |
| 92 | struct guehdr *guehdr; | 92 | struct guehdr *guehdr; |
| 93 | size_t optlen; | 93 | size_t len, optlen; |
| 94 | int ret; | 94 | int ret; |
| 95 | 95 | ||
| 96 | if (skb->len < sizeof(struct udphdr) + sizeof(struct guehdr)) | 96 | len = sizeof(struct udphdr) + sizeof(struct guehdr); |
| 97 | if (!pskb_may_pull(skb, len)) | ||
| 97 | return -EINVAL; | 98 | return -EINVAL; |
| 98 | 99 | ||
| 99 | guehdr = (struct guehdr *)&udp_hdr(skb)[1]; | 100 | guehdr = (struct guehdr *)&udp_hdr(skb)[1]; |
| @@ -128,9 +129,21 @@ static int gue6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 128 | 129 | ||
| 129 | optlen = guehdr->hlen << 2; | 130 | optlen = guehdr->hlen << 2; |
| 130 | 131 | ||
| 132 | if (!pskb_may_pull(skb, len + optlen)) | ||
| 133 | return -EINVAL; | ||
| 134 | |||
| 135 | guehdr = (struct guehdr *)&udp_hdr(skb)[1]; | ||
| 131 | if (validate_gue_flags(guehdr, optlen)) | 136 | if (validate_gue_flags(guehdr, optlen)) |
| 132 | return -EINVAL; | 137 | return -EINVAL; |
| 133 | 138 | ||
| 139 | /* Handling exceptions for direct UDP encapsulation in GUE would lead to | ||
| 140 | * recursion. Besides, this kind of encapsulation can't even be | ||
| 141 | * configured currently. Discard this. | ||
| 142 | */ | ||
| 143 | if (guehdr->proto_ctype == IPPROTO_UDP || | ||
| 144 | guehdr->proto_ctype == IPPROTO_UDPLITE) | ||
| 145 | return -EOPNOTSUPP; | ||
| 146 | |||
| 134 | skb_set_transport_header(skb, -(int)sizeof(struct icmp6hdr)); | 147 | skb_set_transport_header(skb, -(int)sizeof(struct icmp6hdr)); |
| 135 | ret = gue6_err_proto_handler(guehdr->proto_ctype, skb, | 148 | ret = gue6_err_proto_handler(guehdr->proto_ctype, skb, |
| 136 | opt, type, code, offset, info); | 149 | opt, type, code, offset, info); |
