From: Manfred Spraul Below are fixes for secret key loading of the secure sequence number generator. The tcp sequence number generator needs a random seed that is reset every few minutes. Since the sequence numbers should be constantly increasing, for each rekey 2^24 is added to the sequence number. The actual use of the sequence number generator is lockless, synchronization is achieved by having two copies of the control structure. The attached patch: - fixes a race in rekey_seq_generator(): schedule_work doesn't provide synchronization, keyptr->rekey_time must be checked again under a spinlock - removes the _bh from the ip_lock spinlock: it now always runs from process context, no need to disable bottom-halfs. - replaces do_gettimeofday with get_seconds(): get_seconds is faster and usec resolution is not required. - replaces tmpdata with a simple char array - saves some stack space, no need to create an unused copy of the whole control structure on the stack. - Adds a late_initcall for the first initialization after boot. init_call would be too early, I've checked that the late_initcall runs before net/ipv4/ipconfig.c, i.e. the BOOTP/DHCP autoconfiguration. Signed-Off-By: Manfred Spraul Signed-off-by: Andrew Morton --- 25-akpm/drivers/char/random.c | 37 ++++++++++++++++++++++--------------- 1 files changed, 22 insertions(+), 15 deletions(-) diff -puN drivers/char/random.c~fix-secure-tcp-sequence-number-generator drivers/char/random.c --- 25/drivers/char/random.c~fix-secure-tcp-sequence-number-generator 2004-09-30 22:36:06.527879216 -0700 +++ 25-akpm/drivers/char/random.c 2004-09-30 22:36:06.533878304 -0700 @@ -2218,28 +2218,28 @@ static struct keydata { __u32 secret[12]; } ____cacheline_aligned ip_keydata[2]; -static spinlock_t ip_lock = SPIN_LOCK_UNLOCKED; static unsigned int ip_cnt; static void rekey_seq_generator(void *private_) { - struct keydata *keyptr, tmp; - struct timeval tv; +static spinlock_t ip_lock = SPIN_LOCK_UNLOCKED; + struct keydata *keyptr; + char newkey[sizeof(keyptr->secret)]; - do_gettimeofday(&tv); - get_random_bytes(tmp.secret, sizeof(tmp.secret)); + get_random_bytes(newkey, sizeof(newkey)); - spin_lock_bh(&ip_lock); + spin_lock(&ip_lock); keyptr = &ip_keydata[ip_cnt&1]; + if ((get_seconds() - keyptr->rekey_time) > REKEY_INTERVAL) { - keyptr = &ip_keydata[1^(ip_cnt&1)]; - keyptr->rekey_time = tv.tv_sec; - memcpy(keyptr->secret, tmp.secret, sizeof(keyptr->secret)); - keyptr->count = (ip_cnt&COUNT_MASK)<rekey_time = get_seconds(); + memcpy(keyptr->secret, newkey, sizeof(keyptr->secret)); + keyptr->count = (ip_cnt&COUNT_MASK)<rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) { + if ((time - keyptr->rekey_time) > REKEY_INTERVAL) { schedule_work(&rekey_work); } return keyptr; } +static __init int seqgen_init(void) +{ + rekey_seq_generator(NULL); + return 0; +} +late_initcall(seqgen_init); + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, __u16 sport, __u16 dport) _