# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.1142 -> 1.1143 # net/ipv4/netfilter/ip_conntrack_core.c 1.17 -> 1.18 # include/linux/sysctl.h 1.22 -> 1.23 # net/ipv6/tcp_ipv6.c 1.21 -> 1.22 # include/net/tcp.h 1.21 -> 1.22 # net/ipv4/tcp.c 1.25 -> 1.26 # net/ipv4/tcp_ipv4.c 1.20 -> 1.21 # net/ipv4/route.c 1.21 -> 1.22 # (new) -> 1.1 include/linux/jhash.h # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/05/03 davem@nuts.ninka.net 1.1143 # [NET]: Fix hashing exploits in ipv4 routing, IP conntrack, and TCP synq. # # Several hash table implementations in the networking were # remotely exploitable. Remote attackers could launch attacks # whereby, using carefully choosen forged source addresses, make # every routing cache entry get hashed into the same hash chain. # # Netfilter's IP conntrack module and the TCP syn-queue implementation # had identical vulnerabilities and have been fixed too. # # The choosen solution to the problem involved using Bob's Jenkins # hash along with a randomly choosen input. For the ipv4 routing # cache we take things one step further and periodically choose a # new random secret. By default this happens every 10 minutes, but # this is configurable by the user via sysctl knobs. # -------------------------------------------- # diff -Nru a/include/net/tcp.h b/include/net/tcp.h --- a/include/net/tcp.h Tue May 6 02:39:57 2003 +++ b/include/net/tcp.h Tue May 6 02:39:57 2003 @@ -1604,6 +1604,7 @@ int qlen; int qlen_young; int clock_hand; + u32 hash_rnd; struct open_request *syn_table[TCP_SYNQ_HSIZE]; }; diff -Nru a/net/ipv4/route.c b/net/ipv4/route.c --- a/net/ipv4/route.c Tue May 6 02:39:57 2003 +++ b/net/ipv4/route.c Tue May 6 02:39:57 2003 @@ -85,6 +85,7 @@ #include #include #include +#include #include #include #include @@ -117,13 +118,14 @@ int ip_rt_mtu_expires = 10 * 60 * HZ; int ip_rt_min_pmtu = 512 + 20 + 20; int ip_rt_min_advmss = 256; - +int ip_rt_secret_interval = 10 * 60 * HZ; static unsigned long rt_deadline; #define RTprint(a...) printk(KERN_DEBUG a) static struct timer_list rt_flush_timer; static struct timer_list rt_periodic_timer; +static struct timer_list rt_secret_timer; /* * Interface to generic destination cache. @@ -194,19 +196,17 @@ static struct rt_hash_bucket *rt_hash_table; static unsigned rt_hash_mask; static int rt_hash_log; +static unsigned int rt_hash_rnd; struct rt_cache_stat rt_cache_stat[NR_CPUS]; static int rt_intern_hash(unsigned hash, struct rtable *rth, struct rtable **res); -static __inline__ unsigned rt_hash_code(u32 daddr, u32 saddr, u8 tos) +static unsigned int rt_hash_code(u32 daddr, u32 saddr, u8 tos) { - unsigned hash = ((daddr & 0xF0F0F0F0) >> 4) | - ((daddr & 0x0F0F0F0F) << 4); - hash ^= saddr ^ tos; - hash ^= (hash >> 16); - return (hash ^ (hash >> 8)) & rt_hash_mask; + return (jenkins_hash_3words(daddr, saddr, (u32) tos, rt_hash_rnd) + & rt_hash_mask); } static int rt_cache_get_info(char *buffer, char **start, off_t offset, @@ -479,6 +479,15 @@ spin_unlock_bh(&rt_flush_lock); } +static void rt_secret_rebuild(unsigned long dummy) +{ + unsigned long now = jiffies; + + get_random_bytes(&rt_hash_rnd, 4); + rt_cache_flush(0); + mod_timer(&rt_secret_timer, now + ip_rt_secret_interval); +} + /* Short description of GC goals. @@ -2414,6 +2423,15 @@ mode: 0644, proc_handler: &proc_dointvec, }, + { + ctl_name: NET_IPV4_ROUTE_SECRET_INTERVAL, + procname: "secret_interval", + data: &ip_rt_secret_interval, + maxlen: sizeof(int), + mode: 0644, + proc_handler: &proc_dointvec_jiffies, + strategy: &sysctl_jiffies, + }, { 0 } }; #endif @@ -2444,15 +2462,25 @@ *eof = 1; } - /* Copy first cpu. */ - *start = buffer; - memcpy(buffer, IP_RT_ACCT_CPU(0), length); - - /* Add the other cpus in, one int at a time */ - for (i = 1; i < smp_num_cpus; i++) { - unsigned int j; - for (j = 0; j < length/4; j++) - ((u32*)buffer)[j] += ((u32*)IP_RT_ACCT_CPU(i))[j]; + offset /= sizeof(u32); + + if (length > 0) { + u32 *src = ((u32 *) IP_RT_ACCT_CPU(0)) + offset; + u32 *dst = (u32 *) buffer; + + /* Copy first cpu. */ + *start = buffer; + memcpy(dst, src, length); + + /* Add the other cpus in, one int at a time */ + for (i = 1; i < smp_num_cpus; i++) { + unsigned int j; + + src = ((u32 *) IP_RT_ACCT_CPU(i)) + offset; + + for (j = 0; j < length/4; j++) + dst[j] += src[j]; + } } return length; } @@ -2462,6 +2490,9 @@ { int i, order, goal; + rt_hash_rnd = (int) ((num_physpages ^ (num_physpages>>8)) ^ + (jiffies ^ (jiffies >> 7))); + #ifdef CONFIG_NET_CLS_ROUTE for (order = 0; (PAGE_SIZE << order) < 256 * sizeof(struct ip_rt_acct) * NR_CPUS; order++) @@ -2518,6 +2549,7 @@ rt_flush_timer.function = rt_run_flush; rt_periodic_timer.function = rt_check_expire; + rt_secret_timer.function = rt_secret_rebuild; /* All the timers, started at system startup tend to synchronize. Perturb it a bit. @@ -2525,6 +2557,10 @@ rt_periodic_timer.expires = jiffies + net_random() % ip_rt_gc_interval + ip_rt_gc_interval; add_timer(&rt_periodic_timer); + + rt_secret_timer.expires = jiffies + net_random() % ip_rt_secret_interval + + ip_rt_secret_interval; + add_timer(&rt_secret_timer); proc_net_create ("rt_cache", 0, rt_cache_get_info); proc_net_create ("rt_cache_stat", 0, rt_cache_stat_get_info); diff -Nru a/net/ipv4/tcp.c b/net/ipv4/tcp.c --- a/net/ipv4/tcp.c Tue May 6 02:39:57 2003 +++ b/net/ipv4/tcp.c Tue May 6 02:39:57 2003 @@ -252,6 +252,7 @@ #include #include #include +#include #include #include @@ -542,6 +543,7 @@ for (lopt->max_qlen_log = 6; ; lopt->max_qlen_log++) if ((1<max_qlen_log) >= sysctl_max_syn_backlog) break; + get_random_bytes(&lopt->hash_rnd, 4); write_lock_bh(&tp->syn_wait_lock); tp->listen_opt = lopt; diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c --- a/net/ipv4/tcp_ipv4.c Tue May 6 02:39:57 2003 +++ b/net/ipv4/tcp_ipv4.c Tue May 6 02:39:57 2003 @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -868,12 +869,10 @@ return ((struct rtable*)skb->dst)->rt_iif; } -static __inline__ unsigned tcp_v4_synq_hash(u32 raddr, u16 rport) +static __inline__ u32 tcp_v4_synq_hash(u32 raddr, u16 rport, u32 rnd) { - unsigned h = raddr ^ rport; - h ^= h>>16; - h ^= h>>8; - return h&(TCP_SYNQ_HSIZE-1); + return (jenkins_hash_2words(raddr, (u32) rport, rnd) + & (TCP_SYNQ_HSIZE - 1)); } static struct open_request *tcp_v4_search_req(struct tcp_opt *tp, @@ -884,7 +883,7 @@ struct tcp_listen_opt *lopt = tp->listen_opt; struct open_request *req, **prev; - for (prev = &lopt->syn_table[tcp_v4_synq_hash(raddr, rport)]; + for (prev = &lopt->syn_table[tcp_v4_synq_hash(raddr, rport, lopt->hash_rnd)]; (req = *prev) != NULL; prev = &req->dl_next) { if (req->rmt_port == rport && @@ -904,7 +903,7 @@ { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; struct tcp_listen_opt *lopt = tp->listen_opt; - unsigned h = tcp_v4_synq_hash(req->af.v4_req.rmt_addr, req->rmt_port); + u32 h = tcp_v4_synq_hash(req->af.v4_req.rmt_addr, req->rmt_port, lopt->hash_rnd); req->expires = jiffies + TCP_TIMEOUT_INIT; req->retrans = 0; diff -Nru a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c --- a/net/ipv6/tcp_ipv6.c Tue May 6 02:39:57 2003 +++ b/net/ipv6/tcp_ipv6.c Tue May 6 02:39:57 2003 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -368,12 +369,12 @@ * Open request hash tables. */ -static __inline__ unsigned tcp_v6_synq_hash(struct in6_addr *raddr, u16 rport) +static u32 tcp_v6_synq_hash(struct in6_addr *raddr, u16 rport, u32 rnd) { - unsigned h = raddr->s6_addr32[3] ^ rport; - h ^= h>>16; - h ^= h>>8; - return h&(TCP_SYNQ_HSIZE-1); + return (jenkins_hash_3words(raddr->s6_addr32[0] ^ raddr->s6_addr32[1], + raddr->s6_addr32[2] ^ raddr->s6_addr32[3], + (u32) rport, rnd) + & (TCP_SYNQ_HSIZE - 1)); } static struct open_request *tcp_v6_search_req(struct tcp_opt *tp, @@ -386,7 +387,7 @@ struct tcp_listen_opt *lopt = tp->listen_opt; struct open_request *req, **prev; - for (prev = &lopt->syn_table[tcp_v6_synq_hash(raddr, rport)]; + for (prev = &lopt->syn_table[tcp_v6_synq_hash(raddr, rport, lopt->hash_rnd)]; (req = *prev) != NULL; prev = &req->dl_next) { if (req->rmt_port == rport && @@ -1135,7 +1136,7 @@ { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; struct tcp_listen_opt *lopt = tp->listen_opt; - unsigned h = tcp_v6_synq_hash(&req->af.v6_req.rmt_addr, req->rmt_port); + u32 h = tcp_v6_synq_hash(&req->af.v6_req.rmt_addr, req->rmt_port, lopt->hash_rnd); req->sk = NULL; req->expires = jiffies + TCP_TIMEOUT_INIT; # This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.1144 -> 1.1145 # net/ipv4/netfilter/ip_conntrack_core.c 1.18 -> 1.19 # net/ipv6/tcp_ipv6.c 1.22 -> 1.23 # net/ipv4/tcp_ipv4.c 1.21 -> 1.22 # include/linux/jhash.h 1.1 -> 1.2 # net/ipv4/route.c 1.22 -> 1.23 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/05/03 jmorris@intercode.com.au 1.1145 # [NET]: Cosmetic cleanups of jhash code. # - Consistent naming (i.e. jhash_xxx) # - Reduces the 2&1 word variants to call jhash_3words() # - Replaces __inline__ with inline. # -------------------------------------------- # diff -Nru a/net/ipv4/route.c b/net/ipv4/route.c --- a/net/ipv4/route.c Tue May 6 02:40:04 2003 +++ b/net/ipv4/route.c Tue May 6 02:40:04 2003 @@ -205,7 +205,7 @@ static unsigned int rt_hash_code(u32 daddr, u32 saddr, u8 tos) { - return (jenkins_hash_3words(daddr, saddr, (u32) tos, rt_hash_rnd) + return (jhash_3words(daddr, saddr, (u32) tos, rt_hash_rnd) & rt_hash_mask); } diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c --- a/net/ipv4/tcp_ipv4.c Tue May 6 02:40:04 2003 +++ b/net/ipv4/tcp_ipv4.c Tue May 6 02:40:04 2003 @@ -871,8 +871,7 @@ static __inline__ u32 tcp_v4_synq_hash(u32 raddr, u16 rport, u32 rnd) { - return (jenkins_hash_2words(raddr, (u32) rport, rnd) - & (TCP_SYNQ_HSIZE - 1)); + return (jhash_2words(raddr, (u32) rport, rnd) & (TCP_SYNQ_HSIZE - 1)); } static struct open_request *tcp_v4_search_req(struct tcp_opt *tp, diff -Nru a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c --- a/net/ipv6/tcp_ipv6.c Tue May 6 02:40:04 2003 +++ b/net/ipv6/tcp_ipv6.c Tue May 6 02:40:04 2003 @@ -371,10 +371,9 @@ static u32 tcp_v6_synq_hash(struct in6_addr *raddr, u16 rport, u32 rnd) { - return (jenkins_hash_3words(raddr->s6_addr32[0] ^ raddr->s6_addr32[1], - raddr->s6_addr32[2] ^ raddr->s6_addr32[3], - (u32) rport, rnd) - & (TCP_SYNQ_HSIZE - 1)); + return (jhash_3words(raddr->s6_addr32[0] ^ raddr->s6_addr32[1], + raddr->s6_addr32[2] ^ raddr->s6_addr32[3], + (u32) rport, rnd) & (TCP_SYNQ_HSIZE - 1)); } static struct open_request *tcp_v6_search_req(struct tcp_opt *tp, # This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.1145 -> 1.1146 # net/ipv4/route.c 1.23 -> 1.24 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/05/04 jmorris@intercode.com.au 1.1146 # [IPV4]: Choose new rt_hash_rnd every rt_run_flush. # -------------------------------------------- # diff -Nru a/net/ipv4/route.c b/net/ipv4/route.c --- a/net/ipv4/route.c Tue May 6 02:40:09 2003 +++ b/net/ipv4/route.c Tue May 6 02:40:09 2003 @@ -421,6 +421,8 @@ rt_deadline = 0; + get_random_bytes(&rt_hash_rnd, 4); + for (i = rt_hash_mask; i >= 0; i--) { write_lock_bh(&rt_hash_table[i].lock); rth = rt_hash_table[i].chain; @@ -483,7 +485,6 @@ { unsigned long now = jiffies; - get_random_bytes(&rt_hash_rnd, 4); rt_cache_flush(0); mod_timer(&rt_secret_timer, now + ip_rt_secret_interval); } # This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.1094 -> 1.1095 # net/ipv4/tcp_minisocks.c 1.27 -> 1.28 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/05/07 olof@austin.ibm.com 1.1095 # [TCP]: tcp_twkill leaves death row list in inconsistent state over tcp_timewait_kill. # -------------------------------------------- # diff -Nru a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c --- a/net/ipv4/tcp_minisocks.c Wed May 7 02:29:49 2003 +++ b/net/ipv4/tcp_minisocks.c Wed May 7 02:29:49 2003 @@ -444,6 +444,8 @@ while((tw = tcp_tw_death_row[tcp_tw_death_row_slot]) != NULL) { tcp_tw_death_row[tcp_tw_death_row_slot] = tw->next_death; + if (tw->next_death) + tw->next_death->pprev_death = tw->pprev_death; tw->pprev_death = NULL; spin_unlock(&tw_death_lock);