[Openswan dev] [PATCH] Openswan: fix ipcomp skb offset calculations
Florian Westphal
fwestphal at astaro.com
Mon Dec 1 03:50:01 EST 2008
When a compressed packed is received, the kernel panics
(also see http://bugs.xelerance.com/view.php?id=982 , which appears to describe
the same issue):
esi: c7158000 edi: c4066866 ebp: dfdbfa80 esp: dfdbfa58
ds: 007b es: 007b ss: 0068
Process swapper (pid: 0, threadinfo=dfdbe000 task=dfd9dac0)
Stack: <0>00000000 dfdbfb68 d2fc0938 00000006 c7158000 dfdbfb68 c4066866 d2f
dfdbfb68 c760b5e8 dfdbfabc e0a8a4e6 00000000 00000000 00000000 00000007
caaa9977 00000000 c71582ec 00007d14 c71582eb dfdbfb18 caaa9847 00000000
Call Trace:
[<c010388d>] show_stack_log_lvl+0xab/0xb6
[<c01039cc>] show_registers+0x134/0x1a8
[<c0103ba4>] die+0x164/0x1e9
[<c02bf650>] do_page_fault+0x377/0x528
[<c01033fb>] error_code+0x4f/0x54
[<e0a8a4e6>] ipcomp_inflate_codes+0x64e/0x658 [ipsec]
[<e0a89ba4>] ipcomp_deflate_blocks+0x7bf/0xa53 [ipsec]
[<e0a8abc0>] ipcomp_inflate+0x207/0x345 [ipsec]
[<e0a87951>] skb_decompress+0x4f8/0x79c [ipsec]
[<e0a7c66c>] ipsec_rcv_ipcomp_decomp+0x151/0x22d [ipsec]
[<e0a6fa8a>] ipsec_rcv_decap_once+0x7e1/0xc41 [ipsec]
[<e0a6ff4b>] ipsec_rcv_decap+0x61/0x920 [ipsec]
[<e0a70e57>] ipsec_rcv+0x4ef/0x544 [ipsec]
[<c0284ae8>] ip_local_deliver+0x161/0x229
[<c028490e>] ip_rcv+0x401/0x47a
[<c026dbd9>] netif_receive_skb+0x383/0x418
[<c026f1b6>] process_backlog+0x8a/0xf5
[<c026f28f>] net_rx_action+0x6e/0x108
[<c011c47a>] __do_softirq+0x60/0xce
[<c011c519>] do_softirq+0x31/0x36
[<c011c688>] irq_exit+0x34/0x36
[<c01046c2>] do_IRQ+0x4e/0x5a
[<c01032a2>] common_interrupt+0x1a/0x20
[<c0101984>] cpu_idle+0x5c/0x71
[<c010c9bb>] start_secondary+0x3c1/0x3c9
[<00000000>] _stext+0x3feffd68/0x2d
We observe this with 2.4.13, but this appears to be present
in 2.6.19 as well.
It is due to bogus offset calculations in ipcomp.c:skb_copy_ipcomp().
"offset" is the difference between two skbs, yet the value is used to
set the skb protocol header fields.
offset=n->head-skb->head;
n->nh.raw=skb->nh.raw+offset;
got changed to
offset=n->head-skb->head;
skb_set_network_header(n, offset);
which will make the network header point to somewhere
outside the skbs allocated memory area,
causing the kernel to OOOPS on the first receipt of a compressed packet.
This makes things work again for us with 2.4.13 on a Linux 2.6.16-based kernel,
it would be great if you could double-check this because we don't use all
the code paths there due to #ifdefs.
Index: linux-2.6.16.62/net/ipsec/ipcomp.c
===================================================================
--- linux-2.6.16.62.orig/net/ipsec/ipcomp.c 2008-11-24 09:33:25.000000000 +0100
+++ linux-2.6.16.62/net/ipsec/ipcomp.c 2008-11-24 10:52:44.000000000 +0100
@@ -583,9 +583,9 @@ struct sk_buff *skb_copy_ipcomp(struct s
{
struct sk_buff *n;
struct iphdr *iph;
- unsigned long offset;
unsigned int iphlen;
-
+ int headlen;
+
if(!skb) {
KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
"klips_debug:skb_copy_ipcomp: "
@@ -608,15 +608,10 @@ struct sk_buff *skb_copy_ipcomp(struct s
n=alloc_skb(skb_end_pointer(skb) - skb->head + data_growth, gfp_mask);
if(n==NULL)
return NULL;
-
- /*
- * Shift between the two data areas in bytes
- */
-
- offset=n->head-skb->head;
/* Set the data pointer */
- skb_reserve(n,skb->data-skb->head);
+ headlen = skb_headroom(skb);
+ skb_reserve(n, headlen);
/* Set the tail pointer and length */
safe_skb_put(n,skb->len+data_growth);
/* Copy the bytes up to and including the ip header */
@@ -630,14 +625,18 @@ struct sk_buff *skb_copy_ipcomp(struct s
n->prev=NULL;
n->sk=NULL;
n->dev=skb->dev;
- if (skb_transport_header(skb))
- skb_set_transport_header(n, offset);
+
+ if (skb_transport_header(skb)) {
+ headlen = skb->h.raw - skb->data;
+ skb_set_transport_header(n, headlen);
+ }
n->protocol=skb->protocol;
#ifdef NET_21
n->csum = 0;
n->priority=skb->priority;
n->dst=dst_clone(skb->dst);
- skb_set_network_header(n, offset);
+ headlen = skb->nh.raw - skb->data;
+ skb_set_network_header(n, headlen);
#ifndef NETDEV_23
n->is_clone=0;
#endif /* NETDEV_23 */
@@ -653,7 +652,8 @@ struct sk_buff *skb_copy_ipcomp(struct s
#else /* NET_21 */
n->link3=NULL;
n->when=skb->when;
- n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset);
+ headlen = skb->ip_hdr - skb->data;
+ n->ip_hdr=(struct iphdr *) (((char *) n->data) + headlen);
n->saddr=skb->saddr;
n->daddr=skb->daddr;
n->raddr=skb->raddr;
@@ -668,8 +668,10 @@ struct sk_buff *skb_copy_ipcomp(struct s
n->users=0;
memcpy(n->proto_priv, skb->proto_priv, sizeof(skb->proto_priv));
#endif /* NET_21 */
- if (skb_mac_header(skb))
- skb_set_mac_header(n, offset);
+ if (skb_mac_header(skb)) {
+ headlen = skb_mac_header(skb) - skb->data;
+ skb_set_mac_header(n, headlen);
+ }
#ifndef NETDEV_23
n->used=skb->used;
#endif /* !NETDEV_23 */
--
Florian Westphal <fwestphal at astaro.com> | Linux Kernel Programmer
Astaro AG | www.astaro.com | Phone 49-721-25516-0 | Fax -200
Amalienbadstrasse 36 / Bau 33a | 76227 Karlsruhe | Germany
More information about the Dev
mailing list