On 11.12.2012 13:33:04, +0100, Stephan Mueller <smuel...@chronox.de> wrote:
Hi, I just noticed a misuse of a variable in my initial patch > + if (r->limit == 2 && r->entropy_count >= r->poolinfo->poolwords) Instead of r->entropy_count, the code should use entropy_count. Please see new patch attached. Signed-off-by: Stephan Mueller <smuel...@chronox.de> --- diff -purN linux-3.6/drivers/char/random.c linux-3.6-sm/drivers/char/random.c --- linux-3.6/drivers/char/random.c 2012-10-01 01:47:46.000000000 +0200 +++ linux-3.6-sm/drivers/char/random.c 2012-12-12 11:06:23.443403746 +0100 @@ -404,11 +404,12 @@ static bool debug; module_param(debug, bool, 0644); #define DEBUG_ENT(fmt, arg...) do { \ if (debug) \ - printk(KERN_DEBUG "random %04d %04d %04d: " \ + printk(KERN_DEBUG "random %04d %04d %04d %04d: " \ fmt,\ input_pool.entropy_count,\ blocking_pool.entropy_count,\ nonblocking_pool.entropy_count,\ + kernel_pool.entropy_count,\ ## arg); } while (0) #else #define DEBUG_ENT(fmt, arg...) do {} while (0) @@ -428,7 +429,11 @@ struct entropy_store { __u32 *pool; const char *name; struct entropy_store *pull; - int limit; + int limit; /* 0 -> no limit when extracting data (nonblocking) + * 1 -> limit extracted data based on entropy counter + * 2 -> no limit when extracting data and disabling + * use of seed source once pool has full entropy + */ /* read-write data: */ spinlock_t lock; @@ -443,6 +448,7 @@ struct entropy_store { static __u32 input_pool_data[INPUT_POOL_WORDS]; static __u32 blocking_pool_data[OUTPUT_POOL_WORDS]; static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS]; +static __u32 kernel_pool_data[OUTPUT_POOL_WORDS]; static struct entropy_store input_pool = { .poolinfo = &poolinfo_table[0], @@ -469,6 +475,15 @@ static struct entropy_store nonblocking_ .pool = nonblocking_pool_data }; +static struct entropy_store kernel_pool = { + .poolinfo = &poolinfo_table[1], + .name = "kernel", + .limit = 2, + .pull = &input_pool, + .lock = __SPIN_LOCK_UNLOCKED(&kernel_pool.lock), + .pool = kernel_pool_data +}; + static __u32 const twist_table[8] = { 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158, 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 }; @@ -613,6 +628,15 @@ retry: r->initialized = 1; } + /* + * An entropy pool that is marked with limit 2 will only be + * seeded by the input_pool until it is full of entropy. + */ + if (r->limit == 2 && entropy_count >= r->poolinfo->poolwords) + { + r->pull = NULL; + } + trace_credit_entropy_bits(r->name, nbits, entropy_count, r->entropy_total, _RET_IP_); @@ -652,6 +676,8 @@ void add_device_randomness(const void *b mix_pool_bytes(&input_pool, &time, sizeof(time), NULL); mix_pool_bytes(&nonblocking_pool, buf, size, NULL); mix_pool_bytes(&nonblocking_pool, &time, sizeof(time), NULL); + mix_pool_bytes(&kernel_pool, buf, size, NULL); + mix_pool_bytes(&kernel_pool, &time, sizeof(time), NULL); } EXPORT_SYMBOL(add_device_randomness); @@ -820,7 +846,7 @@ static void xfer_secondary_pool(struct e if (r->pull && r->entropy_count < nbytes * 8 && r->entropy_count < r->poolinfo->POOLBITS) { /* If we're limited, always leave two wakeup worth's BITS */ - int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; + int rsvd = r->limit == 1 ? 0 : random_read_wakeup_thresh/4; int bytes = nbytes; /* pull at least as many as BYTES as wakeup BITS */ @@ -868,7 +894,7 @@ static size_t account(struct entropy_sto nbytes = 0; } else { /* If limited, never pull more than available */ - if (r->limit && nbytes + reserved >= r->entropy_count / 8) + if (r->limit == 1 && nbytes + reserved >= r->entropy_count / 8) nbytes = r->entropy_count/8 - reserved; if (r->entropy_count / 8 >= nbytes + reserved) @@ -883,7 +909,7 @@ static size_t account(struct entropy_sto } DEBUG_ENT("debiting %d entropy credits from %s%s\n", - nbytes * 8, r->name, r->limit ? "" : " (unlimited)"); + nbytes * 8, r->name, r->limit == 1 ? "" : " (unlimited)"); spin_unlock_irqrestore(&r->lock, flags); @@ -1037,6 +1063,21 @@ void get_random_bytes(void *buf, int nby EXPORT_SYMBOL(get_random_bytes); /* + * This function exports the kernel random number pool. It is of + * slightly less quality than the nonblocking_pool exported by + * the function get_random_bytes because once it is filled completely + * with entropy, it is never seeded again. Yet, the quality of the + * random bytes depend on the SHA-1 hash and should be sufficient + * for purposes like ASLR and stack protection. + */ +void get_random_kernel_bytes(void *buf, int nbytes) +{ + extract_entropy(&kernel_pool, buf, nbytes, 0, 0); +} +EXPORT_SYMBOL(get_random_kernel_bytes); + + +/* * This function will use the architecture-specific hardware random * number generator if it is available. The arch-specific hw RNG will * almost certainly be faster than what we can do in software, but it @@ -1110,6 +1151,7 @@ static int rand_initialize(void) init_std_data(&input_pool); init_std_data(&blocking_pool); init_std_data(&nonblocking_pool); + init_std_data(&kernel_pool); return 0; } module_init(rand_initialize); @@ -1239,6 +1281,9 @@ static ssize_t random_write(struct file ret = write_pool(&nonblocking_pool, buffer, count); if (ret) return ret; + ret = write_pool(&kernel_pool, buffer, count); + if (ret) + return ret; return (ssize_t)count; } diff -purN linux-3.6/fs/binfmt_elf.c linux-3.6-sm/fs/binfmt_elf.c --- linux-3.6/fs/binfmt_elf.c 2012-10-01 01:47:46.000000000 +0200 +++ linux-3.6-sm/fs/binfmt_elf.c 2012-12-11 10:25:36.357094685 +0100 @@ -193,7 +193,7 @@ create_elf_tables(struct linux_binprm *b /* * Generate 16 random bytes for userspace PRNG seeding. */ - get_random_bytes(k_rand_bytes, sizeof(k_rand_bytes)); + get_random_kernel_bytes(k_rand_bytes, sizeof(k_rand_bytes)); u_rand_bytes = (elf_addr_t __user *) STACK_ALLOC(p, sizeof(k_rand_bytes)); if (__copy_to_user(u_rand_bytes, k_rand_bytes, sizeof(k_rand_bytes))) diff -purN linux-3.6/include/linux/random.h linux-3.6-sm/include/linux/random.h --- linux-3.6/include/linux/random.h 2012-10-01 01:47:46.000000000 +0200 +++ linux-3.6-sm/include/linux/random.h 2012-12-11 10:31:45.033100217 +0100 @@ -54,6 +54,7 @@ extern void add_input_randomness(unsigne extern void add_interrupt_randomness(int irq, int irq_flags); extern void get_random_bytes(void *buf, int nbytes); +extern void get_random_kernel_bytes(void *buf, int nbytes); extern void get_random_bytes_arch(void *buf, int nbytes); void generate_random_uuid(unsigned char uuid_out[16]); -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/