diff options
Diffstat (limited to 'net/ipv4/icmp.c')
-rw-r--r-- | net/ipv4/icmp.c | 82 |
1 files changed, 79 insertions, 3 deletions
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 13d74598d3e4..3c41a6f7e6ec 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c | |||
@@ -92,6 +92,7 @@ | |||
92 | #include <asm/system.h> | 92 | #include <asm/system.h> |
93 | #include <asm/uaccess.h> | 93 | #include <asm/uaccess.h> |
94 | #include <net/checksum.h> | 94 | #include <net/checksum.h> |
95 | #include <net/xfrm.h> | ||
95 | 96 | ||
96 | /* | 97 | /* |
97 | * Build xmit assembly blocks | 98 | * Build xmit assembly blocks |
@@ -563,11 +564,71 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) | |||
563 | } | 564 | } |
564 | } | 565 | } |
565 | }; | 566 | }; |
567 | int err; | ||
568 | struct rtable *rt2; | ||
569 | |||
566 | security_skb_classify_flow(skb_in, &fl); | 570 | security_skb_classify_flow(skb_in, &fl); |
567 | if (ip_route_output_key(&rt, &fl)) | 571 | if (__ip_route_output_key(&rt, &fl)) |
572 | goto out_unlock; | ||
573 | |||
574 | /* No need to clone since we're just using its address. */ | ||
575 | rt2 = rt; | ||
576 | |||
577 | err = xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0); | ||
578 | switch (err) { | ||
579 | case 0: | ||
580 | if (rt != rt2) | ||
581 | goto route_done; | ||
582 | break; | ||
583 | case -EPERM: | ||
584 | rt = NULL; | ||
585 | break; | ||
586 | default: | ||
587 | goto out_unlock; | ||
588 | } | ||
589 | |||
590 | if (xfrm_decode_session_reverse(skb_in, &fl, AF_INET)) | ||
591 | goto out_unlock; | ||
592 | |||
593 | if (inet_addr_type(fl.fl4_src) == RTN_LOCAL) | ||
594 | err = __ip_route_output_key(&rt2, &fl); | ||
595 | else { | ||
596 | struct flowi fl2 = {}; | ||
597 | struct dst_entry *odst; | ||
598 | |||
599 | fl2.fl4_dst = fl.fl4_src; | ||
600 | if (ip_route_output_key(&rt2, &fl2)) | ||
601 | goto out_unlock; | ||
602 | |||
603 | /* Ugh! */ | ||
604 | odst = skb_in->dst; | ||
605 | err = ip_route_input(skb_in, fl.fl4_dst, fl.fl4_src, | ||
606 | RT_TOS(tos), rt2->u.dst.dev); | ||
607 | |||
608 | dst_release(&rt2->u.dst); | ||
609 | rt2 = (struct rtable *)skb_in->dst; | ||
610 | skb_in->dst = odst; | ||
611 | } | ||
612 | |||
613 | if (err) | ||
614 | goto out_unlock; | ||
615 | |||
616 | err = xfrm_lookup((struct dst_entry **)&rt2, &fl, NULL, | ||
617 | XFRM_LOOKUP_ICMP); | ||
618 | if (err == -ENOENT) { | ||
619 | if (!rt) | ||
620 | goto out_unlock; | ||
621 | goto route_done; | ||
622 | } | ||
623 | |||
624 | dst_release(&rt->u.dst); | ||
625 | rt = rt2; | ||
626 | |||
627 | if (err) | ||
568 | goto out_unlock; | 628 | goto out_unlock; |
569 | } | 629 | } |
570 | 630 | ||
631 | route_done: | ||
571 | if (!icmpv4_xrlim_allow(rt, type, code)) | 632 | if (!icmpv4_xrlim_allow(rt, type, code)) |
572 | goto ende; | 633 | goto ende; |
573 | 634 | ||
@@ -916,6 +977,22 @@ int icmp_rcv(struct sk_buff *skb) | |||
916 | struct icmphdr *icmph; | 977 | struct icmphdr *icmph; |
917 | struct rtable *rt = (struct rtable *)skb->dst; | 978 | struct rtable *rt = (struct rtable *)skb->dst; |
918 | 979 | ||
980 | if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb) && | ||
981 | skb->sp->xvec[skb->sp->len - 1]->props.flags & XFRM_STATE_ICMP) { | ||
982 | int nh; | ||
983 | |||
984 | if (!pskb_may_pull(skb, sizeof(*icmph) + sizeof(struct iphdr))) | ||
985 | goto drop; | ||
986 | |||
987 | nh = skb_network_offset(skb); | ||
988 | skb_set_network_header(skb, sizeof(*icmph)); | ||
989 | |||
990 | if (!xfrm4_policy_check_reverse(NULL, XFRM_POLICY_IN, skb)) | ||
991 | goto drop; | ||
992 | |||
993 | skb_set_network_header(skb, nh); | ||
994 | } | ||
995 | |||
919 | ICMP_INC_STATS_BH(ICMP_MIB_INMSGS); | 996 | ICMP_INC_STATS_BH(ICMP_MIB_INMSGS); |
920 | 997 | ||
921 | switch (skb->ip_summed) { | 998 | switch (skb->ip_summed) { |
@@ -929,8 +1006,7 @@ int icmp_rcv(struct sk_buff *skb) | |||
929 | goto error; | 1006 | goto error; |
930 | } | 1007 | } |
931 | 1008 | ||
932 | if (!pskb_pull(skb, sizeof(struct icmphdr))) | 1009 | __skb_pull(skb, sizeof(*icmph)); |
933 | goto error; | ||
934 | 1010 | ||
935 | icmph = icmp_hdr(skb); | 1011 | icmph = icmp_hdr(skb); |
936 | 1012 | ||