diff options
author | Steffen Klassert <steffen.klassert@secunet.com> | 2014-02-21 02:41:09 -0500 |
---|---|---|
committer | Steffen Klassert <steffen.klassert@secunet.com> | 2014-02-25 01:04:17 -0500 |
commit | 70be6c91c86596ad2b60c73587880b47df170a41 (patch) | |
tree | f1728dd87ed10e66916277f89caef5a261b5a70f | |
parent | d099160e029391de857464d987b141f30434052b (diff) |
xfrm: Add xfrm_tunnel_skb_cb to the skb common buffer
IPsec vti_rcv needs to remind the tunnel pointer to
check it later at the vti_rcv_cb callback. So add
this pointer to the IPsec common buffer, initialize
it and check it to avoid transport state matching of
a tunneled packet.
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
-rw-r--r-- | include/net/xfrm.h | 50 | ||||
-rw-r--r-- | net/ipv4/xfrm4_protocol.c | 7 | ||||
-rw-r--r-- | net/xfrm/xfrm_input.c | 5 |
3 files changed, 50 insertions, 12 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 345a15084557..33112599fa47 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -599,16 +599,27 @@ struct xfrm_mgr { | |||
599 | int xfrm_register_km(struct xfrm_mgr *km); | 599 | int xfrm_register_km(struct xfrm_mgr *km); |
600 | int xfrm_unregister_km(struct xfrm_mgr *km); | 600 | int xfrm_unregister_km(struct xfrm_mgr *km); |
601 | 601 | ||
602 | struct xfrm_tunnel_skb_cb { | ||
603 | union { | ||
604 | struct inet_skb_parm h4; | ||
605 | struct inet6_skb_parm h6; | ||
606 | } header; | ||
607 | |||
608 | union { | ||
609 | struct ip_tunnel *ip4; | ||
610 | struct ip6_tnl *ip6; | ||
611 | } tunnel; | ||
612 | }; | ||
613 | |||
614 | #define XFRM_TUNNEL_SKB_CB(__skb) ((struct xfrm_tunnel_skb_cb *)&((__skb)->cb[0])) | ||
615 | |||
602 | /* | 616 | /* |
603 | * This structure is used for the duration where packets are being | 617 | * This structure is used for the duration where packets are being |
604 | * transformed by IPsec. As soon as the packet leaves IPsec the | 618 | * transformed by IPsec. As soon as the packet leaves IPsec the |
605 | * area beyond the generic IP part may be overwritten. | 619 | * area beyond the generic IP part may be overwritten. |
606 | */ | 620 | */ |
607 | struct xfrm_skb_cb { | 621 | struct xfrm_skb_cb { |
608 | union { | 622 | struct xfrm_tunnel_skb_cb header; |
609 | struct inet_skb_parm h4; | ||
610 | struct inet6_skb_parm h6; | ||
611 | } header; | ||
612 | 623 | ||
613 | /* Sequence number for replay protection. */ | 624 | /* Sequence number for replay protection. */ |
614 | union { | 625 | union { |
@@ -630,10 +641,7 @@ struct xfrm_skb_cb { | |||
630 | * to transmit header information to the mode input/output functions. | 641 | * to transmit header information to the mode input/output functions. |
631 | */ | 642 | */ |
632 | struct xfrm_mode_skb_cb { | 643 | struct xfrm_mode_skb_cb { |
633 | union { | 644 | struct xfrm_tunnel_skb_cb header; |
634 | struct inet_skb_parm h4; | ||
635 | struct inet6_skb_parm h6; | ||
636 | } header; | ||
637 | 645 | ||
638 | /* Copied from header for IPv4, always set to zero and DF for IPv6. */ | 646 | /* Copied from header for IPv4, always set to zero and DF for IPv6. */ |
639 | __be16 id; | 647 | __be16 id; |
@@ -665,10 +673,7 @@ struct xfrm_mode_skb_cb { | |||
665 | * related information. | 673 | * related information. |
666 | */ | 674 | */ |
667 | struct xfrm_spi_skb_cb { | 675 | struct xfrm_spi_skb_cb { |
668 | union { | 676 | struct xfrm_tunnel_skb_cb header; |
669 | struct inet_skb_parm h4; | ||
670 | struct inet6_skb_parm h6; | ||
671 | } header; | ||
672 | 677 | ||
673 | unsigned int daddroff; | 678 | unsigned int daddroff; |
674 | unsigned int family; | 679 | unsigned int family; |
@@ -1510,6 +1515,7 @@ int xfrm4_rcv(struct sk_buff *skb); | |||
1510 | 1515 | ||
1511 | static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) | 1516 | static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) |
1512 | { | 1517 | { |
1518 | XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; | ||
1513 | XFRM_SPI_SKB_CB(skb)->family = AF_INET; | 1519 | XFRM_SPI_SKB_CB(skb)->family = AF_INET; |
1514 | XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); | 1520 | XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); |
1515 | return xfrm_input(skb, nexthdr, spi, 0); | 1521 | return xfrm_input(skb, nexthdr, spi, 0); |
@@ -1781,4 +1787,24 @@ static inline int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, | |||
1781 | return 0; | 1787 | return 0; |
1782 | } | 1788 | } |
1783 | 1789 | ||
1790 | static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x, | ||
1791 | unsigned int family) | ||
1792 | { | ||
1793 | bool tunnel = false; | ||
1794 | |||
1795 | switch(family) { | ||
1796 | case AF_INET: | ||
1797 | if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4) | ||
1798 | tunnel = true; | ||
1799 | break; | ||
1800 | case AF_INET6: | ||
1801 | if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6) | ||
1802 | tunnel = true; | ||
1803 | break; | ||
1804 | } | ||
1805 | if (tunnel && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL)) | ||
1806 | return -EINVAL; | ||
1807 | |||
1808 | return 0; | ||
1809 | } | ||
1784 | #endif /* _NET_XFRM_H */ | 1810 | #endif /* _NET_XFRM_H */ |
diff --git a/net/ipv4/xfrm4_protocol.c b/net/ipv4/xfrm4_protocol.c index 862a26c2014f..cdc09efca442 100644 --- a/net/ipv4/xfrm4_protocol.c +++ b/net/ipv4/xfrm4_protocol.c | |||
@@ -65,6 +65,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, | |||
65 | int ret; | 65 | int ret; |
66 | struct xfrm4_protocol *handler; | 66 | struct xfrm4_protocol *handler; |
67 | 67 | ||
68 | XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; | ||
68 | XFRM_SPI_SKB_CB(skb)->family = AF_INET; | 69 | XFRM_SPI_SKB_CB(skb)->family = AF_INET; |
69 | XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); | 70 | XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); |
70 | 71 | ||
@@ -84,6 +85,8 @@ static int xfrm4_esp_rcv(struct sk_buff *skb) | |||
84 | int ret; | 85 | int ret; |
85 | struct xfrm4_protocol *handler; | 86 | struct xfrm4_protocol *handler; |
86 | 87 | ||
88 | XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; | ||
89 | |||
87 | for_each_protocol_rcu(esp4_handlers, handler) | 90 | for_each_protocol_rcu(esp4_handlers, handler) |
88 | if ((ret = handler->handler(skb)) != -EINVAL) | 91 | if ((ret = handler->handler(skb)) != -EINVAL) |
89 | return ret; | 92 | return ret; |
@@ -108,6 +111,8 @@ static int xfrm4_ah_rcv(struct sk_buff *skb) | |||
108 | int ret; | 111 | int ret; |
109 | struct xfrm4_protocol *handler; | 112 | struct xfrm4_protocol *handler; |
110 | 113 | ||
114 | XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; | ||
115 | |||
111 | for_each_protocol_rcu(ah4_handlers, handler) | 116 | for_each_protocol_rcu(ah4_handlers, handler) |
112 | if ((ret = handler->handler(skb)) != -EINVAL) | 117 | if ((ret = handler->handler(skb)) != -EINVAL) |
113 | return ret;; | 118 | return ret;; |
@@ -132,6 +137,8 @@ static int xfrm4_ipcomp_rcv(struct sk_buff *skb) | |||
132 | int ret; | 137 | int ret; |
133 | struct xfrm4_protocol *handler; | 138 | struct xfrm4_protocol *handler; |
134 | 139 | ||
140 | XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; | ||
141 | |||
135 | for_each_protocol_rcu(ipcomp4_handlers, handler) | 142 | for_each_protocol_rcu(ipcomp4_handlers, handler) |
136 | if ((ret = handler->handler(skb)) != -EINVAL) | 143 | if ((ret = handler->handler(skb)) != -EINVAL) |
137 | return ret; | 144 | return ret; |
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 99e3a9e5285e..4218164f4f5e 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c | |||
@@ -163,6 +163,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) | |||
163 | 163 | ||
164 | skb->sp->xvec[skb->sp->len++] = x; | 164 | skb->sp->xvec[skb->sp->len++] = x; |
165 | 165 | ||
166 | if (xfrm_tunnel_check(skb, x, family)) { | ||
167 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); | ||
168 | goto drop; | ||
169 | } | ||
170 | |||
166 | spin_lock(&x->lock); | 171 | spin_lock(&x->lock); |
167 | if (unlikely(x->km.state == XFRM_STATE_ACQ)) { | 172 | if (unlikely(x->km.state == XFRM_STATE_ACQ)) { |
168 | XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR); | 173 | XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR); |