aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteffen Klassert <steffen.klassert@secunet.com>2014-02-21 02:41:09 -0500
committerSteffen Klassert <steffen.klassert@secunet.com>2014-02-25 01:04:17 -0500
commit70be6c91c86596ad2b60c73587880b47df170a41 (patch)
treef1728dd87ed10e66916277f89caef5a261b5a70f
parentd099160e029391de857464d987b141f30434052b (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.h50
-rw-r--r--net/ipv4/xfrm4_protocol.c7
-rw-r--r--net/xfrm/xfrm_input.c5
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 {
599int xfrm_register_km(struct xfrm_mgr *km); 599int xfrm_register_km(struct xfrm_mgr *km);
600int xfrm_unregister_km(struct xfrm_mgr *km); 600int xfrm_unregister_km(struct xfrm_mgr *km);
601 601
602struct 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 */
607struct xfrm_skb_cb { 621struct 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 */
632struct xfrm_mode_skb_cb { 643struct 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 */
667struct xfrm_spi_skb_cb { 675struct 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
1511static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) 1516static 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
1790static 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);