Patchwork [1/1,HARDY,CVE-2012-2744] netfilter: nf_conntrack_reasm: properly handle packets fragmented into a single fragment

login
register
mail settings
Submitter Brad Figg
Date July 11, 2012, 8:38 p.m.
Message ID <1342039122-29194-2-git-send-email-brad.figg@canonical.com>
Download mbox | patch
Permalink /patch/170511/
State New
Headers show

Comments

Brad Figg - July 11, 2012, 8:38 p.m.
From: Patrick McHardy <kaber@trash.net>

CVE-2012-2744

BugLink: http://bugs.launchpad.net/bugs/1234567

When an ICMPV6_PKT_TOOBIG message is received with a MTU below 1280,
all further packets include a fragment header.

Unlike regular defragmentation, conntrack also needs to "reassemble"
those fragments in order to obtain a packet without the fragment
header for connection tracking. Currently nf_conntrack_reasm checks
whether a fragment has either IP6_MF set or an offset != 0, which
makes it ignore those fragments.

Remove the invalid check and make reassembly handle fragment queues
containing only a single fragment.

Reported-and-tested-by: Ulrich Weber <uweber@astaro.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
(backported from commit 9e2dcf72023d1447f09c47d77c99b0c49659e5ce upstream)
Signed-off-by: Brad Figg <brad.figg@canonical.com>
---
 .../src/net/ipv6/netfilter/nf_conntrack_reasm.c    |    8 +-------
 .../src/net/ipv6/netfilter/nf_conntrack_reasm.c    |    8 +-------
 net/ipv6/netfilter/nf_conntrack_reasm.c            |    8 +-------
 3 files changed, 3 insertions(+), 21 deletions(-)

Patch

diff --git a/debian/binary-custom.d/openvz/src/net/ipv6/netfilter/nf_conntrack_reasm.c b/debian/binary-custom.d/openvz/src/net/ipv6/netfilter/nf_conntrack_reasm.c
index fd6054a..c555cfa 100644
--- a/debian/binary-custom.d/openvz/src/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/debian/binary-custom.d/openvz/src/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -481,7 +481,7 @@  nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
 
 	/* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */
 	fp = skb_shinfo(head)->frag_list;
-	if (NFCT_FRAG6_CB(fp)->orig == NULL)
+	if (fp && NFCT_FRAG6_CB(fp)->orig == NULL)
 		/* at above code, head skb is divided into two skbs. */
 		fp = fp->next;
 
@@ -607,12 +607,6 @@  struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
 	hdr = ipv6_hdr(clone);
 	fhdr = (struct frag_hdr *)skb_transport_header(clone);
 
-	if (!(fhdr->frag_off & htons(0xFFF9))) {
-		pr_debug("Invalid fragment offset\n");
-		/* It is not a fragmented frame */
-		goto ret_orig;
-	}
-
 	if (atomic_read(&ve_nf_frags.mem) > ve_nf_frags_ctl.high_thresh)
 		nf_ct_frag6_evictor();
 
diff --git a/debian/binary-custom.d/xen/src/net/ipv6/netfilter/nf_conntrack_reasm.c b/debian/binary-custom.d/xen/src/net/ipv6/netfilter/nf_conntrack_reasm.c
index 89f95f9..c138783 100644
--- a/debian/binary-custom.d/xen/src/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/debian/binary-custom.d/xen/src/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -473,7 +473,7 @@  nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
 
 	/* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */
 	fp = skb_shinfo(head)->frag_list;
-	if (NFCT_FRAG6_CB(fp)->orig == NULL)
+	if (fp && NFCT_FRAG6_CB(fp)->orig == NULL)
 		/* at above code, head skb is divided into two skbs. */
 		fp = fp->next;
 
@@ -599,12 +599,6 @@  struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
 	hdr = ipv6_hdr(clone);
 	fhdr = (struct frag_hdr *)skb_transport_header(clone);
 
-	if (!(fhdr->frag_off & htons(0xFFF9))) {
-		pr_debug("Invalid fragment offset\n");
-		/* It is not a fragmented frame */
-		goto ret_orig;
-	}
-
 	if (atomic_read(&nf_frags.mem) > nf_frags_ctl.high_thresh)
 		nf_ct_frag6_evictor();
 
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 89f95f9..c138783 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -473,7 +473,7 @@  nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
 
 	/* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */
 	fp = skb_shinfo(head)->frag_list;
-	if (NFCT_FRAG6_CB(fp)->orig == NULL)
+	if (fp && NFCT_FRAG6_CB(fp)->orig == NULL)
 		/* at above code, head skb is divided into two skbs. */
 		fp = fp->next;
 
@@ -599,12 +599,6 @@  struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
 	hdr = ipv6_hdr(clone);
 	fhdr = (struct frag_hdr *)skb_transport_header(clone);
 
-	if (!(fhdr->frag_off & htons(0xFFF9))) {
-		pr_debug("Invalid fragment offset\n");
-		/* It is not a fragmented frame */
-		goto ret_orig;
-	}
-
 	if (atomic_read(&nf_frags.mem) > nf_frags_ctl.high_thresh)
 		nf_ct_frag6_evictor();