aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2008-03-26 19:51:09 -0400
committerDavid S. Miller <davem@davemloft.net>2008-03-26 19:51:09 -0400
commit732c8bd590625e8bc0b88313b82930e336b2bec4 (patch)
tree1cf3f6b9db7b886d35bbf38bab2ca6ff82d206d8
parent0e5606e4f46b7cf52dd445af01e71ed9dbb7f735 (diff)
[IPSEC]: Fix BEET output
The IPv6 BEET output function is incorrectly including the inner header in the payload to be protected. This causes a crash as the packet doesn't actually have that many bytes for a second header. The IPv4 BEET output on the other hand is broken when it comes to handling an inner IPv6 header since it always assumes an inner IPv4 header. This patch fixes both by making sure that neither BEET output function touches the inner header at all. All access is now done through the protocol-independent cb structure. Two new attributes are added to make this work, the IP header length and the IPv4 option length. They're filled in by the inner mode's output function. Thanks to Joakim Koskela for finding this problem. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/xfrm.h6
-rw-r--r--net/ipv4/xfrm4_mode_beet.c11
-rw-r--r--net/ipv4/xfrm4_state.c2
-rw-r--r--net/ipv6/xfrm6_mode_beet.c1
-rw-r--r--net/ipv6/xfrm6_state.c2
5 files changed, 16 insertions, 6 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 4e6f9568cbe7..0d255ae008b6 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -552,6 +552,9 @@ struct xfrm_mode_skb_cb {
552 __be16 id; 552 __be16 id;
553 __be16 frag_off; 553 __be16 frag_off;
554 554
555 /* IP header length (excluding options or extension headers). */
556 u8 ihl;
557
555 /* TOS for IPv4, class for IPv6. */ 558 /* TOS for IPv4, class for IPv6. */
556 u8 tos; 559 u8 tos;
557 560
@@ -561,6 +564,9 @@ struct xfrm_mode_skb_cb {
561 /* Protocol for IPv4, NH for IPv6. */ 564 /* Protocol for IPv4, NH for IPv6. */
562 u8 protocol; 565 u8 protocol;
563 566
567 /* Option length for IPv4, zero for IPv6. */
568 u8 optlen;
569
564 /* Used by IPv6 only, zero for IPv4. */ 570 /* Used by IPv6 only, zero for IPv4. */
565 u8 flow_lbl[3]; 571 u8 flow_lbl[3];
566}; 572};
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c
index b47030ba162b..9c798abce736 100644
--- a/net/ipv4/xfrm4_mode_beet.c
+++ b/net/ipv4/xfrm4_mode_beet.c
@@ -39,13 +39,11 @@ static void xfrm4_beet_make_header(struct sk_buff *skb)
39static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb) 39static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb)
40{ 40{
41 struct ip_beet_phdr *ph; 41 struct ip_beet_phdr *ph;
42 struct iphdr *iph, *top_iph; 42 struct iphdr *top_iph;
43 int hdrlen, optlen; 43 int hdrlen, optlen;
44 44
45 iph = ip_hdr(skb);
46
47 hdrlen = 0; 45 hdrlen = 0;
48 optlen = iph->ihl * 4 - sizeof(*iph); 46 optlen = XFRM_MODE_SKB_CB(skb)->optlen;
49 if (unlikely(optlen)) 47 if (unlikely(optlen))
50 hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4); 48 hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4);
51 49
@@ -53,11 +51,12 @@ static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb)
53 hdrlen); 51 hdrlen);
54 skb->mac_header = skb->network_header + 52 skb->mac_header = skb->network_header +
55 offsetof(struct iphdr, protocol); 53 offsetof(struct iphdr, protocol);
56 skb->transport_header = skb->network_header + sizeof(*iph); 54 skb->transport_header = skb->network_header + sizeof(*top_iph);
57 55
58 xfrm4_beet_make_header(skb); 56 xfrm4_beet_make_header(skb);
59 57
60 ph = (struct ip_beet_phdr *)__skb_pull(skb, sizeof(*iph) - hdrlen); 58 ph = (struct ip_beet_phdr *)
59 __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdrlen);
61 60
62 top_iph = ip_hdr(skb); 61 top_iph = ip_hdr(skb);
63 62
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index fdeebe68a379..07735ed280d7 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -52,10 +52,12 @@ int xfrm4_extract_header(struct sk_buff *skb)
52{ 52{
53 struct iphdr *iph = ip_hdr(skb); 53 struct iphdr *iph = ip_hdr(skb);
54 54
55 XFRM_MODE_SKB_CB(skb)->ihl = sizeof(*iph);
55 XFRM_MODE_SKB_CB(skb)->id = iph->id; 56 XFRM_MODE_SKB_CB(skb)->id = iph->id;
56 XFRM_MODE_SKB_CB(skb)->frag_off = iph->frag_off; 57 XFRM_MODE_SKB_CB(skb)->frag_off = iph->frag_off;
57 XFRM_MODE_SKB_CB(skb)->tos = iph->tos; 58 XFRM_MODE_SKB_CB(skb)->tos = iph->tos;
58 XFRM_MODE_SKB_CB(skb)->ttl = iph->ttl; 59 XFRM_MODE_SKB_CB(skb)->ttl = iph->ttl;
60 XFRM_MODE_SKB_CB(skb)->optlen = iph->ihl * 4 - sizeof(*iph);
59 memset(XFRM_MODE_SKB_CB(skb)->flow_lbl, 0, 61 memset(XFRM_MODE_SKB_CB(skb)->flow_lbl, 0,
60 sizeof(XFRM_MODE_SKB_CB(skb)->flow_lbl)); 62 sizeof(XFRM_MODE_SKB_CB(skb)->flow_lbl));
61 63
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c
index 0527d11c1ae3..d6ce400f585f 100644
--- a/net/ipv6/xfrm6_mode_beet.c
+++ b/net/ipv6/xfrm6_mode_beet.c
@@ -45,6 +45,7 @@ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb)
45 skb->mac_header = skb->network_header + 45 skb->mac_header = skb->network_header +
46 offsetof(struct ipv6hdr, nexthdr); 46 offsetof(struct ipv6hdr, nexthdr);
47 skb->transport_header = skb->network_header + sizeof(*top_iph); 47 skb->transport_header = skb->network_header + sizeof(*top_iph);
48 __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl);
48 49
49 xfrm6_beet_make_header(skb); 50 xfrm6_beet_make_header(skb);
50 51
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index dc817e035e23..ff1e1db8e236 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -174,10 +174,12 @@ int xfrm6_extract_header(struct sk_buff *skb)
174{ 174{
175 struct ipv6hdr *iph = ipv6_hdr(skb); 175 struct ipv6hdr *iph = ipv6_hdr(skb);
176 176
177 XFRM_MODE_SKB_CB(skb)->ihl = sizeof(*iph);
177 XFRM_MODE_SKB_CB(skb)->id = 0; 178 XFRM_MODE_SKB_CB(skb)->id = 0;
178 XFRM_MODE_SKB_CB(skb)->frag_off = htons(IP_DF); 179 XFRM_MODE_SKB_CB(skb)->frag_off = htons(IP_DF);
179 XFRM_MODE_SKB_CB(skb)->tos = ipv6_get_dsfield(iph); 180 XFRM_MODE_SKB_CB(skb)->tos = ipv6_get_dsfield(iph);
180 XFRM_MODE_SKB_CB(skb)->ttl = iph->hop_limit; 181 XFRM_MODE_SKB_CB(skb)->ttl = iph->hop_limit;
182 XFRM_MODE_SKB_CB(skb)->optlen = 0;
181 memcpy(XFRM_MODE_SKB_CB(skb)->flow_lbl, iph->flow_lbl, 183 memcpy(XFRM_MODE_SKB_CB(skb)->flow_lbl, iph->flow_lbl,
182 sizeof(XFRM_MODE_SKB_CB(skb)->flow_lbl)); 184 sizeof(XFRM_MODE_SKB_CB(skb)->flow_lbl));
183 185