From b1a4f4c2e2b1432abc576c9c95b284a3bbecdf45 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 6 Jul 2006 16:11:16 -0400 Subject: [PATCH] Fix a 64bit bug in compression code. A pointer difference was being cast to a unsigned int by passing it to skb_put(), which made it into a very large positive offset and resulted in an OOPS. skb_put() does not work with negative offsets, so we use skb_trim() in those instances. --- net/ipsec/ipcomp.c | 31 ++++++++++++++++++++++++++----- 1 files changed, 26 insertions(+), 5 deletions(-) diff --git a/net/ipsec/ipcomp.c b/net/ipsec/ipcomp.c index 1eac65b..e48979f 100644 --- a/net/ipsec/ipcomp.c +++ b/net/ipsec/ipcomp.c @@ -82,6 +82,28 @@ void my_zfree(voidpf opaque, voidpf addr kfree(address); } +/* + * We use this function because sometimes we want to pass a negative offset + * into skb_put(), this does not work on 64bit platforms because long to + * unsigned int casting. + */ +static inline unsigned char * +safe_skb_put(struct sk_buff *skb, int extend) +{ + unsigned char *ptr; + + if (extend>0) { + // increase the size of the packet + ptr = skb_put(skb, extend); + } else { + // shrink the size of the packet + ptr = skb->tail; + skb_trim (skb, skb->len + extend); + } + + return ptr; +} + struct sk_buff *skb_compress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags) { struct iphdr *iph; @@ -293,9 +315,8 @@ #endif kfree(buffer); /* Update skb length/tail by "unputting" the shrinkage */ - skb_put(skb, - cpyldsz + sizeof(struct ipcomphdr) - pyldsz); - + safe_skb_put (skb, cpyldsz + sizeof(struct ipcomphdr) - pyldsz); + #ifdef CONFIG_KLIPS_DEBUG if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) { __u8 *c; @@ -523,7 +544,7 @@ #if 1 /* XXX checksum is done by ipsec_r #endif /* Update skb length/tail by "unputting" the unused data area */ - skb_put(nskb, -zs.avail_out); + safe_skb_put(nskb, -zs.avail_out); ipsec_kfree_skb(skb); @@ -595,7 +616,7 @@ #endif /* NET_21 */ /* Set the data pointer */ skb_reserve(n,skb->data-skb->head); /* Set the tail pointer and length */ - skb_put(n,skb->len+data_growth); + safe_skb_put(n,skb->len+data_growth); /* Copy the bytes up to and including the ip header */ memcpy(n->head, skb->head, -- 1.4.0