> 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); }