diff options
| author | Peter Christensen <pch@ordbogen.com> | 2014-05-24 15:40:12 -0400 |
|---|---|---|
| committer | Simon Horman <horms@verge.net.au> | 2014-05-25 21:22:46 -0400 |
| commit | f44a5f45f544561302e855e7bd104e5f506ec01b (patch) | |
| tree | 55fb3bfc52ba08d0fca622b9a275348bd04793f2 | |
| parent | 3b084e99a3fabaeb0f9c65a0806cde30f0b2835e (diff) | |
ipvs: Fix panic due to non-linear skb
Receiving a ICMP response to an IPIP packet in a non-linear skb could
cause a kernel panic in __skb_pull.
The problem was introduced in
commit f2edb9f7706dcb2c0d9a362b2ba849efe3a97f5e ("ipvs: implement
passive PMTUD for IPIP packets").
Signed-off-by: Peter Christensen <pch@ordbogen.com>
Acked-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>
| -rw-r--r-- | net/netfilter/ipvs/ip_vs_core.c | 15 |
1 files changed, 10 insertions, 5 deletions
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 4f26ee46b51f..3d2d2c8108ca 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c | |||
| @@ -1392,15 +1392,19 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
| 1392 | 1392 | ||
| 1393 | if (ipip) { | 1393 | if (ipip) { |
| 1394 | __be32 info = ic->un.gateway; | 1394 | __be32 info = ic->un.gateway; |
| 1395 | __u8 type = ic->type; | ||
| 1396 | __u8 code = ic->code; | ||
| 1395 | 1397 | ||
| 1396 | /* Update the MTU */ | 1398 | /* Update the MTU */ |
| 1397 | if (ic->type == ICMP_DEST_UNREACH && | 1399 | if (ic->type == ICMP_DEST_UNREACH && |
| 1398 | ic->code == ICMP_FRAG_NEEDED) { | 1400 | ic->code == ICMP_FRAG_NEEDED) { |
| 1399 | struct ip_vs_dest *dest = cp->dest; | 1401 | struct ip_vs_dest *dest = cp->dest; |
| 1400 | u32 mtu = ntohs(ic->un.frag.mtu); | 1402 | u32 mtu = ntohs(ic->un.frag.mtu); |
| 1403 | __be16 frag_off = cih->frag_off; | ||
| 1401 | 1404 | ||
| 1402 | /* Strip outer IP and ICMP, go to IPIP header */ | 1405 | /* Strip outer IP and ICMP, go to IPIP header */ |
| 1403 | __skb_pull(skb, ihl + sizeof(_icmph)); | 1406 | if (pskb_pull(skb, ihl + sizeof(_icmph)) == NULL) |
| 1407 | goto ignore_ipip; | ||
| 1404 | offset2 -= ihl + sizeof(_icmph); | 1408 | offset2 -= ihl + sizeof(_icmph); |
| 1405 | skb_reset_network_header(skb); | 1409 | skb_reset_network_header(skb); |
| 1406 | IP_VS_DBG(12, "ICMP for IPIP %pI4->%pI4: mtu=%u\n", | 1410 | IP_VS_DBG(12, "ICMP for IPIP %pI4->%pI4: mtu=%u\n", |
| @@ -1408,7 +1412,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
| 1408 | ipv4_update_pmtu(skb, dev_net(skb->dev), | 1412 | ipv4_update_pmtu(skb, dev_net(skb->dev), |
| 1409 | mtu, 0, 0, 0, 0); | 1413 | mtu, 0, 0, 0, 0); |
| 1410 | /* Client uses PMTUD? */ | 1414 | /* Client uses PMTUD? */ |
| 1411 | if (!(cih->frag_off & htons(IP_DF))) | 1415 | if (!(frag_off & htons(IP_DF))) |
| 1412 | goto ignore_ipip; | 1416 | goto ignore_ipip; |
| 1413 | /* Prefer the resulting PMTU */ | 1417 | /* Prefer the resulting PMTU */ |
| 1414 | if (dest) { | 1418 | if (dest) { |
| @@ -1427,12 +1431,13 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
| 1427 | /* Strip outer IP, ICMP and IPIP, go to IP header of | 1431 | /* Strip outer IP, ICMP and IPIP, go to IP header of |
| 1428 | * original request. | 1432 | * original request. |
| 1429 | */ | 1433 | */ |
| 1430 | __skb_pull(skb, offset2); | 1434 | if (pskb_pull(skb, offset2) == NULL) |
| 1435 | goto ignore_ipip; | ||
| 1431 | skb_reset_network_header(skb); | 1436 | skb_reset_network_header(skb); |
| 1432 | IP_VS_DBG(12, "Sending ICMP for %pI4->%pI4: t=%u, c=%u, i=%u\n", | 1437 | IP_VS_DBG(12, "Sending ICMP for %pI4->%pI4: t=%u, c=%u, i=%u\n", |
| 1433 | &ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr, | 1438 | &ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr, |
| 1434 | ic->type, ic->code, ntohl(info)); | 1439 | type, code, ntohl(info)); |
| 1435 | icmp_send(skb, ic->type, ic->code, info); | 1440 | icmp_send(skb, type, code, info); |
| 1436 | /* ICMP can be shorter but anyways, account it */ | 1441 | /* ICMP can be shorter but anyways, account it */ |
| 1437 | ip_vs_out_stats(cp, skb); | 1442 | ip_vs_out_stats(cp, skb); |
| 1438 | 1443 | ||
