> I got tired of waiting for Zach to cook up a patch so I tossed
> the following into my tree :-)

Haha, sorry, I didn't realize I was racing the clock :).  We disappeared
this weekend.

That matches what I came up with, but did we miss the IPv6 part?  Here's
that half if you still need it.

Herbert, does it look OK?  I don't have v6 stuff setup here..

- z
[IPv6] reassembly: Always compute hash under the fragment lock.

This closes a race where an ipq6hashfn() caller could get a hash value
and race with the cycling of the random seed.  By the time they got to the
read_lock they'd have a stale hash value and might not find previous fragments
of their datagram.

This matches the previous patch to IPv4.

Signed-off-by: Zach Brown <[EMAIL PROTECTED]>

Index: 2.6.17-rc1-mm1-fraghash/net/ipv6/reassembly.c
===================================================================
--- 2.6.17-rc1-mm1-fraghash.orig/net/ipv6/reassembly.c
+++ 2.6.17-rc1-mm1-fraghash/net/ipv6/reassembly.c
@@ -121,6 +121,10 @@ static __inline__ void fq_unlink(struct 
 	write_unlock(&ip6_frag_lock);
 }
 
+/*
+ * callers should be careful not to use the hash value outside the ipfrag_lock
+ * as doing so could race with ipfrag_hash_rnd being recalculated.
+ */
 static unsigned int ip6qhashfn(u32 id, struct in6_addr *saddr,
 			       struct in6_addr *daddr)
 {
@@ -322,15 +326,16 @@ out:
 /* Creation primitives. */
 
 
-static struct frag_queue *ip6_frag_intern(unsigned int hash,
-					  struct frag_queue *fq_in)
+static struct frag_queue *ip6_frag_intern(struct frag_queue *fq_in)
 {
 	struct frag_queue *fq;
+	unsigned int hash;
 #ifdef CONFIG_SMP
 	struct hlist_node *n;
 #endif
 
 	write_lock(&ip6_frag_lock);
+	hash = ip6qhashfn(fq_in->id, &fq_in->saddr, &fq_in->daddr);
 #ifdef CONFIG_SMP
 	hlist_for_each_entry(fq, n, &ip6_frag_hash[hash], list) {
 		if (fq->id == fq_in->id && 
@@ -360,7 +365,7 @@ static struct frag_queue *ip6_frag_inter
 
 
 static struct frag_queue *
-ip6_frag_create(unsigned int hash, u32 id, struct in6_addr *src, struct in6_addr *dst)
+ip6_frag_create(u32 id, struct in6_addr *src, struct in6_addr *dst)
 {
 	struct frag_queue *fq;
 
@@ -377,7 +382,7 @@ ip6_frag_create(unsigned int hash, u32 i
 	spin_lock_init(&fq->lock);
 	atomic_set(&fq->refcnt, 1);
 
-	return ip6_frag_intern(hash, fq);
+	return ip6_frag_intern(fq);
 
 oom:
 	IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
@@ -389,9 +394,10 @@ fq_find(u32 id, struct in6_addr *src, st
 {
 	struct frag_queue *fq;
 	struct hlist_node *n;
-	unsigned int hash = ip6qhashfn(id, src, dst);
+	unsigned int hash;
 
 	read_lock(&ip6_frag_lock);
+	hash = ip6qhashfn(id, src, dst);
 	hlist_for_each_entry(fq, n, &ip6_frag_hash[hash], list) {
 		if (fq->id == id && 
 		    ipv6_addr_equal(src, &fq->saddr) &&
@@ -403,7 +409,7 @@ fq_find(u32 id, struct in6_addr *src, st
 	}
 	read_unlock(&ip6_frag_lock);
 
-	return ip6_frag_create(hash, id, src, dst);
+	return ip6_frag_create(id, src, dst);
 }
 
 

Reply via email to