[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
(usagi-users 01462) 5 bugs in AH + fragmentation ( and PATCH)
- To: usagi-users@xxxxxxxxxxxxxx
- Subject: (usagi-users 01462) 5 bugs in AH + fragmentation ( and PATCH)
- From: "David Stevens" <dlstevens@xxxxxxxxxx>
- Date: Thu, 16 May 2002 01:38:11 -0700
- Importance: Normal
- Reply-to: usagi-users@xxxxxxxxxxxxxx
- Sender: "David Stevens" <dlstevens@xxxxxxxxxx>
- Sensitivity:
I've found 5 bugs relating to AH and fragmentation. A patch for all of them
is listed below, relative to the 5/19 usagi snapshot.
Details:
1) On input processing, a reassembled packet normally will not be in one
contiguous buffer. Fix: changed "memcpy" to use skb_copy_bits()
2) A recent change removed the lines:
pseudo_authhdr->spi = authhdr->spi;
pseudo_authhdr->seq_no = authhdr->seq_no;
from ipsec6_ah_calc(). Without them, the sequence number and spi are
not included in the digest calculation, and all output AH digests for
fragmented packets are incorrect. Fix: readd the lines
3) The raw socket "getfrag" function maintains partial checksums in a
private header for fragments. AH uses these to assemble the full
packet for AH computation, and then the getfrag function is called
again on packet delivery. The second set of calls was using old
partial checksum state, resulting in incorrect ICMP checksums ("0").
Fix: reset the partial checksum to 0 when the packet is complete.
4) The UDP getfrag() function had a similar problem to 3) - similar fix.
5) Ordinarly, the fragment header is not removed from a reassembled input
packet. This results in incorrect digests when using AH, because
it incorrectly includes the fragment header. Fix: remove fragment
headers when CONFIG_IPV6_IPSEC is set.
+-DLS
Patch:
diff -ruN --exclude=CVS usagi-0519/net/ipv6/ipsec6_input.c usagi-0519fix/net/ipv6/ipsec6_input.c
--- usagi-0519/net/ipv6/ipsec6_input.c Sat May 11 00:54:41 2002
+++ usagi-0519fix/net/ipv6/ipsec6_input.c Tue May 14 13:12:10 2002
@@ -52,6 +52,7 @@
__u8* authdata;
size_t authsize;
char *packet;
+ int offset;
IPSEC6_DEBUG("start auth header processing\n");
@@ -103,7 +104,12 @@
}
authdata = packet + ((authsize + 3) & ~3);
- memcpy(packet, (char*)((*skb)->nh.ipv6h), authsize);
+ offset = (char *)((*skb)->nh.ipv6h) - (char *)((*skb)->data);
+
+ if (skb_copy_bits(*skb, offset, packet, authsize)) {
+ printk(KERN_ERR "ipsec6_input_check_ah: packet copy failed\n");
+ goto unlock_finish;
+ }
zero_out_for_ah((struct inet6_skb_parm*)(*skb)->cb, packet);
diff -ruN --exclude=CVS usagi-0519/net/ipv6/ipsec6_utils.c usagi-0519fix/net/ipv6/ipsec6_utils.c
--- usagi-0519/net/ipv6/ipsec6_utils.c Mon May 13 03:15:58 2002
+++ usagi-0519fix/net/ipv6/ipsec6_utils.c Thu May 16 01:27:28 2002
@@ -280,6 +280,9 @@
memcpy(pseudo_packet,skb->nh.ipv6h,skb->len);
+ pseudo_authhdr->spi = authhdr->spi;
+ pseudo_authhdr->seq_no = authhdr->seq_no;
+
zero_out_for_ah(parm, pseudo_packet);
sa->auth_algo.dx->di->hmac_atomic(sa->auth_algo.dx,
diff -ruN --exclude=CVS usagi-0519/net/ipv6/raw.c usagi-0519fix/net/ipv6/raw.c
--- usagi-0519/net/ipv6/raw.c Wed Feb 20 08:58:07 2002
+++ usagi-0519fix/net/ipv6/raw.c Tue May 14 11:55:11 2002
@@ -474,6 +474,7 @@
printk(KERN_DEBUG "icmp: cksum offset too big\n");
return -EINVAL;
}
+ hdr->cksum = 0;
}
return 0;
}
diff -ruN --exclude=CVS usagi-0519/net/ipv6/reassembly.c usagi-0519fix/net/ipv6/reassembly.c
--- usagi-0519/net/ipv6/reassembly.c Sun May 6 16:52:58 2001
+++ usagi-0519fix/net/ipv6/reassembly.c Tue May 14 11:55:11 2002
@@ -555,11 +555,13 @@
nhoff = head->h.raw - head->nh.raw;
if (payload_len > 65535) {
- payload_len -= 8;
- if (payload_len > 65535)
+ if (payload_len > 65535 + 8)
goto out_oversize;
remove_fraghdr = 1;
}
+#ifdef CONFIG_IPV6_IPSEC
+ remove_fraghdr = 1;
+#endif /* CONFIG_IPV6_IPSEC */
/* Head of list must not be cloned. */
if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
@@ -597,6 +599,7 @@
memmove(head->head+8, head->head, (head->data-head->head)-8);
head->mac.raw += 8;
head->nh.raw += 8;
+ payload_len -= 8;
} else {
((struct frag_hdr*)head->h.raw)->frag_off = 0;
}
diff -ruN --exclude=CVS usagi-0519/net/ipv6/udp.c usagi-0519fix/net/ipv6/udp.c
--- usagi-0519/net/ipv6/udp.c Thu Nov 15 05:29:30 2001
+++ usagi-0519fix/net/ipv6/udp.c Tue May 14 11:55:11 2002
@@ -829,6 +829,9 @@
dst = buff;
+ if (udh->wcheck == 0)
+ udh->uh.check = 0;
+
if (offset) {
offset -= sizeof(struct udphdr);
} else {
@@ -863,6 +866,7 @@
udh->uh.check = -1;
memcpy(buff, udh, sizeof(struct udphdr));
+ udh->wcheck = 0;
}
return 0;
}