A number of cleanups plus support for the RDSEED instruction, which
will be showing up in Intel Broadwell CPU's. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABCAAGBQJTPaDyAAoJENNvdpvBGATwIVkP/Ao77ATdIBKr7kJJ+7q/jroo hfg2EOBzYwFSTZ4EUCwTwCNOqcAnr8xBYRWDDTxoiT0ORQN+4QkIXlukTBZbeCUg 5ZCvRYhNcrieCBX69X/0aQ7yAkMR5/KSjccww3Tr6bLEItEBS7/gkeGv0H/E1DOg /1C3vbDDRPchM2qGM/TS/2Wd3WU5jWJk4cURJUlweBWHGXItOk6yHIY/+h3t4Bj1 eJfxwG21BLJ1t159uvMj5Sw9Ketwnzgc4hsU6Ai/o37+Q12LYJ6xRCHsAatr6aA8 dsObrfnD15T3gH/elVzB0tpBkor9pESkJAvUxWdMNMNGVU01ONuBz6rbSUqLdKu4 GXA+9iHq4Ti43f4M886PweSweFr1+lFIiQrdAQaWZdrooLCMJCgjMNM+7wnlu8ho Eit65rq4k6y5Fb5GTB8Am/TCb3HNYhXnrMERA0meKx+/K8yaMygzHtPoT+DHdn8z GWDwNiMYrtTeiJ5nduljO3M2lYJDIWLkCD9SwupXe5HEj3qSHS/aiT5ng6YP+oOK mmUiWWgpVv3unO6pJw49pbzuAWXnbHVWMV2VDILVxn7mZZ0NAOL3OGAmK7US+Z/J qww9s89A2oba8vTbdrW7JuiP9ESlujpfrLQQgnW6WInMHY2dfo5hSo84ULLeLMXQ SqT1yywl4U888jqBYioB =RtMT -----END PGP SIGNATURE----- Merge tag 'random_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/random Pull /dev/random changes from Ted Ts'o: "A number of cleanups plus support for the RDSEED instruction, which will be showing up in Intel Broadwell CPU's" * tag 'random_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/random: random: Add arch_has_random[_seed]() random: If we have arch_get_random_seed*(), try it before blocking random: Use arch_get_random_seed*() at init time and once a second x86, random: Enable the RDSEED instruction random: use the architectural HWRNG for the SHA's IV in extract_buf() random: clarify bits/bytes in wakeup thresholds random: entropy_bytes is actually bits random: simplify accounting code random: tighten bound on random_read_wakeup_thresh random: forget lock in lockless accounting random: simplify accounting logic random: fix comment on "account" random: simplify loop in random_read random: fix description of get_random_bytes random: fix comment on proc_do_uuid random: fix typos / spelling errors in comments
This commit is contained in:
commit
d1d9cfc330
@ -25,8 +25,26 @@ static inline int arch_get_random_int(unsigned int *v)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int arch_has_random(void)
|
||||||
|
{
|
||||||
|
return !!ppc_md.get_random_long;
|
||||||
|
}
|
||||||
|
|
||||||
int powernv_get_random_long(unsigned long *v);
|
int powernv_get_random_long(unsigned long *v);
|
||||||
|
|
||||||
|
static inline int arch_get_random_seed_long(unsigned long *v)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline int arch_get_random_seed_int(unsigned int *v)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline int arch_has_random_seed(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_ARCH_RANDOM */
|
#endif /* CONFIG_ARCH_RANDOM */
|
||||||
|
|
||||||
#endif /* _ASM_POWERPC_ARCHRANDOM_H */
|
#endif /* _ASM_POWERPC_ARCHRANDOM_H */
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the Linux kernel.
|
* This file is part of the Linux kernel.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011, Intel Corporation
|
* Copyright (c) 2011-2014, Intel Corporation
|
||||||
* Authors: Fenghua Yu <fenghua.yu@intel.com>,
|
* Authors: Fenghua Yu <fenghua.yu@intel.com>,
|
||||||
* H. Peter Anvin <hpa@linux.intel.com>
|
* H. Peter Anvin <hpa@linux.intel.com>
|
||||||
*
|
*
|
||||||
@ -31,10 +31,13 @@
|
|||||||
#define RDRAND_RETRY_LOOPS 10
|
#define RDRAND_RETRY_LOOPS 10
|
||||||
|
|
||||||
#define RDRAND_INT ".byte 0x0f,0xc7,0xf0"
|
#define RDRAND_INT ".byte 0x0f,0xc7,0xf0"
|
||||||
|
#define RDSEED_INT ".byte 0x0f,0xc7,0xf8"
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
# define RDRAND_LONG ".byte 0x48,0x0f,0xc7,0xf0"
|
# define RDRAND_LONG ".byte 0x48,0x0f,0xc7,0xf0"
|
||||||
|
# define RDSEED_LONG ".byte 0x48,0x0f,0xc7,0xf8"
|
||||||
#else
|
#else
|
||||||
# define RDRAND_LONG RDRAND_INT
|
# define RDRAND_LONG RDRAND_INT
|
||||||
|
# define RDSEED_LONG RDSEED_INT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_RANDOM
|
#ifdef CONFIG_ARCH_RANDOM
|
||||||
@ -53,6 +56,16 @@ static inline int rdrand_long(unsigned long *v)
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A single attempt at RDSEED */
|
||||||
|
static inline bool rdseed_long(unsigned long *v)
|
||||||
|
{
|
||||||
|
unsigned char ok;
|
||||||
|
asm volatile(RDSEED_LONG "\n\t"
|
||||||
|
"setc %0"
|
||||||
|
: "=qm" (ok), "=a" (*v));
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
#define GET_RANDOM(name, type, rdrand, nop) \
|
#define GET_RANDOM(name, type, rdrand, nop) \
|
||||||
static inline int name(type *v) \
|
static inline int name(type *v) \
|
||||||
{ \
|
{ \
|
||||||
@ -70,18 +83,40 @@ static inline int name(type *v) \
|
|||||||
return ok; \
|
return ok; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define GET_SEED(name, type, rdseed, nop) \
|
||||||
|
static inline int name(type *v) \
|
||||||
|
{ \
|
||||||
|
unsigned char ok; \
|
||||||
|
alternative_io("movb $0, %0\n\t" \
|
||||||
|
nop, \
|
||||||
|
rdseed "\n\t" \
|
||||||
|
"setc %0", \
|
||||||
|
X86_FEATURE_RDSEED, \
|
||||||
|
ASM_OUTPUT2("=q" (ok), "=a" (*v))); \
|
||||||
|
return ok; \
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
|
|
||||||
GET_RANDOM(arch_get_random_long, unsigned long, RDRAND_LONG, ASM_NOP5);
|
GET_RANDOM(arch_get_random_long, unsigned long, RDRAND_LONG, ASM_NOP5);
|
||||||
GET_RANDOM(arch_get_random_int, unsigned int, RDRAND_INT, ASM_NOP4);
|
GET_RANDOM(arch_get_random_int, unsigned int, RDRAND_INT, ASM_NOP4);
|
||||||
|
|
||||||
|
GET_SEED(arch_get_random_seed_long, unsigned long, RDSEED_LONG, ASM_NOP5);
|
||||||
|
GET_SEED(arch_get_random_seed_int, unsigned int, RDSEED_INT, ASM_NOP4);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
GET_RANDOM(arch_get_random_long, unsigned long, RDRAND_LONG, ASM_NOP3);
|
GET_RANDOM(arch_get_random_long, unsigned long, RDRAND_LONG, ASM_NOP3);
|
||||||
GET_RANDOM(arch_get_random_int, unsigned int, RDRAND_INT, ASM_NOP3);
|
GET_RANDOM(arch_get_random_int, unsigned int, RDRAND_INT, ASM_NOP3);
|
||||||
|
|
||||||
|
GET_SEED(arch_get_random_seed_long, unsigned long, RDSEED_LONG, ASM_NOP4);
|
||||||
|
GET_SEED(arch_get_random_seed_int, unsigned int, RDSEED_INT, ASM_NOP4);
|
||||||
|
|
||||||
#endif /* CONFIG_X86_64 */
|
#endif /* CONFIG_X86_64 */
|
||||||
|
|
||||||
|
#define arch_has_random() static_cpu_has(X86_FEATURE_RDRAND)
|
||||||
|
#define arch_has_random_seed() static_cpu_has(X86_FEATURE_RDSEED)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline int rdrand_long(unsigned long *v)
|
static inline int rdrand_long(unsigned long *v)
|
||||||
@ -89,6 +124,11 @@ static inline int rdrand_long(unsigned long *v)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool rdseed_long(unsigned long *v)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_ARCH_RANDOM */
|
#endif /* CONFIG_ARCH_RANDOM */
|
||||||
|
|
||||||
extern void x86_init_rdrand(struct cpuinfo_x86 *c);
|
extern void x86_init_rdrand(struct cpuinfo_x86 *c);
|
||||||
|
@ -295,17 +295,17 @@
|
|||||||
* The minimum number of bits of entropy before we wake up a read on
|
* The minimum number of bits of entropy before we wake up a read on
|
||||||
* /dev/random. Should be enough to do a significant reseed.
|
* /dev/random. Should be enough to do a significant reseed.
|
||||||
*/
|
*/
|
||||||
static int random_read_wakeup_thresh = 64;
|
static int random_read_wakeup_bits = 64;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the entropy count falls under this number of bits, then we
|
* If the entropy count falls under this number of bits, then we
|
||||||
* should wake up processes which are selecting or polling on write
|
* should wake up processes which are selecting or polling on write
|
||||||
* access to /dev/random.
|
* access to /dev/random.
|
||||||
*/
|
*/
|
||||||
static int random_write_wakeup_thresh = 28 * OUTPUT_POOL_WORDS;
|
static int random_write_wakeup_bits = 28 * OUTPUT_POOL_WORDS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The minimum number of seconds between urandom pool resending. We
|
* The minimum number of seconds between urandom pool reseeding. We
|
||||||
* do this to limit the amount of entropy that can be drained from the
|
* do this to limit the amount of entropy that can be drained from the
|
||||||
* input pool even if there are heavy demands on /dev/urandom.
|
* input pool even if there are heavy demands on /dev/urandom.
|
||||||
*/
|
*/
|
||||||
@ -322,7 +322,7 @@ static int random_min_urandom_seed = 60;
|
|||||||
* Register. (See M. Matsumoto & Y. Kurita, 1992. Twisted GFSR
|
* Register. (See M. Matsumoto & Y. Kurita, 1992. Twisted GFSR
|
||||||
* generators. ACM Transactions on Modeling and Computer Simulation
|
* generators. ACM Transactions on Modeling and Computer Simulation
|
||||||
* 2(3):179-194. Also see M. Matsumoto & Y. Kurita, 1994. Twisted
|
* 2(3):179-194. Also see M. Matsumoto & Y. Kurita, 1994. Twisted
|
||||||
* GFSR generators II. ACM Transactions on Mdeling and Computer
|
* GFSR generators II. ACM Transactions on Modeling and Computer
|
||||||
* Simulation 4:254-266)
|
* Simulation 4:254-266)
|
||||||
*
|
*
|
||||||
* Thanks to Colin Plumb for suggesting this.
|
* Thanks to Colin Plumb for suggesting this.
|
||||||
@ -666,10 +666,10 @@ retry:
|
|||||||
r->entropy_total, _RET_IP_);
|
r->entropy_total, _RET_IP_);
|
||||||
|
|
||||||
if (r == &input_pool) {
|
if (r == &input_pool) {
|
||||||
int entropy_bytes = entropy_count >> ENTROPY_SHIFT;
|
int entropy_bits = entropy_count >> ENTROPY_SHIFT;
|
||||||
|
|
||||||
/* should we wake readers? */
|
/* should we wake readers? */
|
||||||
if (entropy_bytes >= random_read_wakeup_thresh) {
|
if (entropy_bits >= random_read_wakeup_bits) {
|
||||||
wake_up_interruptible(&random_read_wait);
|
wake_up_interruptible(&random_read_wait);
|
||||||
kill_fasync(&fasync, SIGIO, POLL_IN);
|
kill_fasync(&fasync, SIGIO, POLL_IN);
|
||||||
}
|
}
|
||||||
@ -678,9 +678,9 @@ retry:
|
|||||||
* forth between them, until the output pools are 75%
|
* forth between them, until the output pools are 75%
|
||||||
* full.
|
* full.
|
||||||
*/
|
*/
|
||||||
if (entropy_bytes > random_write_wakeup_thresh &&
|
if (entropy_bits > random_write_wakeup_bits &&
|
||||||
r->initialized &&
|
r->initialized &&
|
||||||
r->entropy_total >= 2*random_read_wakeup_thresh) {
|
r->entropy_total >= 2*random_read_wakeup_bits) {
|
||||||
static struct entropy_store *last = &blocking_pool;
|
static struct entropy_store *last = &blocking_pool;
|
||||||
struct entropy_store *other = &blocking_pool;
|
struct entropy_store *other = &blocking_pool;
|
||||||
|
|
||||||
@ -844,6 +844,8 @@ void add_interrupt_randomness(int irq, int irq_flags)
|
|||||||
cycles_t cycles = random_get_entropy();
|
cycles_t cycles = random_get_entropy();
|
||||||
__u32 input[4], c_high, j_high;
|
__u32 input[4], c_high, j_high;
|
||||||
__u64 ip;
|
__u64 ip;
|
||||||
|
unsigned long seed;
|
||||||
|
int credit;
|
||||||
|
|
||||||
c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0;
|
c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0;
|
||||||
j_high = (sizeof(now) > 4) ? now >> 32 : 0;
|
j_high = (sizeof(now) > 4) ? now >> 32 : 0;
|
||||||
@ -862,20 +864,33 @@ void add_interrupt_randomness(int irq, int irq_flags)
|
|||||||
|
|
||||||
r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool;
|
r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool;
|
||||||
__mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool), NULL);
|
__mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool), NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we don't have a valid cycle counter, and we see
|
* If we don't have a valid cycle counter, and we see
|
||||||
* back-to-back timer interrupts, then skip giving credit for
|
* back-to-back timer interrupts, then skip giving credit for
|
||||||
* any entropy.
|
* any entropy, otherwise credit 1 bit.
|
||||||
*/
|
*/
|
||||||
|
credit = 1;
|
||||||
if (cycles == 0) {
|
if (cycles == 0) {
|
||||||
if (irq_flags & __IRQF_TIMER) {
|
if (irq_flags & __IRQF_TIMER) {
|
||||||
if (fast_pool->last_timer_intr)
|
if (fast_pool->last_timer_intr)
|
||||||
return;
|
credit = 0;
|
||||||
fast_pool->last_timer_intr = 1;
|
fast_pool->last_timer_intr = 1;
|
||||||
} else
|
} else
|
||||||
fast_pool->last_timer_intr = 0;
|
fast_pool->last_timer_intr = 0;
|
||||||
}
|
}
|
||||||
credit_entropy_bits(r, 1);
|
|
||||||
|
/*
|
||||||
|
* If we have architectural seed generator, produce a seed and
|
||||||
|
* add it to the pool. For the sake of paranoia count it as
|
||||||
|
* 50% entropic.
|
||||||
|
*/
|
||||||
|
if (arch_get_random_seed_long(&seed)) {
|
||||||
|
__mix_pool_bytes(r, &seed, sizeof(seed), NULL);
|
||||||
|
credit += sizeof(seed) * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
credit_entropy_bits(r, credit);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_BLOCK
|
#ifdef CONFIG_BLOCK
|
||||||
@ -924,19 +939,19 @@ static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
|
|||||||
{
|
{
|
||||||
__u32 tmp[OUTPUT_POOL_WORDS];
|
__u32 tmp[OUTPUT_POOL_WORDS];
|
||||||
|
|
||||||
/* For /dev/random's pool, always leave two wakeup worth's BITS */
|
/* For /dev/random's pool, always leave two wakeups' worth */
|
||||||
int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4;
|
int rsvd_bytes = r->limit ? 0 : random_read_wakeup_bits / 4;
|
||||||
int bytes = nbytes;
|
int bytes = nbytes;
|
||||||
|
|
||||||
/* pull at least as many as BYTES as wakeup BITS */
|
/* pull at least as much as a wakeup */
|
||||||
bytes = max_t(int, bytes, random_read_wakeup_thresh / 8);
|
bytes = max_t(int, bytes, random_read_wakeup_bits / 8);
|
||||||
/* but never more than the buffer size */
|
/* but never more than the buffer size */
|
||||||
bytes = min_t(int, bytes, sizeof(tmp));
|
bytes = min_t(int, bytes, sizeof(tmp));
|
||||||
|
|
||||||
trace_xfer_secondary_pool(r->name, bytes * 8, nbytes * 8,
|
trace_xfer_secondary_pool(r->name, bytes * 8, nbytes * 8,
|
||||||
ENTROPY_BITS(r), ENTROPY_BITS(r->pull));
|
ENTROPY_BITS(r), ENTROPY_BITS(r->pull));
|
||||||
bytes = extract_entropy(r->pull, tmp, bytes,
|
bytes = extract_entropy(r->pull, tmp, bytes,
|
||||||
random_read_wakeup_thresh / 8, rsvd);
|
random_read_wakeup_bits / 8, rsvd_bytes);
|
||||||
mix_pool_bytes(r, tmp, bytes, NULL);
|
mix_pool_bytes(r, tmp, bytes, NULL);
|
||||||
credit_entropy_bits(r, bytes*8);
|
credit_entropy_bits(r, bytes*8);
|
||||||
}
|
}
|
||||||
@ -952,35 +967,22 @@ static void push_to_pool(struct work_struct *work)
|
|||||||
struct entropy_store *r = container_of(work, struct entropy_store,
|
struct entropy_store *r = container_of(work, struct entropy_store,
|
||||||
push_work);
|
push_work);
|
||||||
BUG_ON(!r);
|
BUG_ON(!r);
|
||||||
_xfer_secondary_pool(r, random_read_wakeup_thresh/8);
|
_xfer_secondary_pool(r, random_read_wakeup_bits/8);
|
||||||
trace_push_to_pool(r->name, r->entropy_count >> ENTROPY_SHIFT,
|
trace_push_to_pool(r->name, r->entropy_count >> ENTROPY_SHIFT,
|
||||||
r->pull->entropy_count >> ENTROPY_SHIFT);
|
r->pull->entropy_count >> ENTROPY_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These functions extracts randomness from the "entropy pool", and
|
* This function decides how many bytes to actually take from the
|
||||||
* returns it in a buffer.
|
* given pool, and also debits the entropy count accordingly.
|
||||||
*
|
|
||||||
* The min parameter specifies the minimum amount we can pull before
|
|
||||||
* failing to avoid races that defeat catastrophic reseeding while the
|
|
||||||
* reserved parameter indicates how much entropy we must leave in the
|
|
||||||
* pool after each pull to avoid starving other readers.
|
|
||||||
*
|
|
||||||
* Note: extract_entropy() assumes that .poolwords is a multiple of 16 words.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static size_t account(struct entropy_store *r, size_t nbytes, int min,
|
static size_t account(struct entropy_store *r, size_t nbytes, int min,
|
||||||
int reserved)
|
int reserved)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
int wakeup_write = 0;
|
|
||||||
int have_bytes;
|
int have_bytes;
|
||||||
int entropy_count, orig;
|
int entropy_count, orig;
|
||||||
size_t ibytes;
|
size_t ibytes;
|
||||||
|
|
||||||
/* Hold lock while accounting */
|
|
||||||
spin_lock_irqsave(&r->lock, flags);
|
|
||||||
|
|
||||||
BUG_ON(r->entropy_count > r->poolinfo->poolfracbits);
|
BUG_ON(r->entropy_count > r->poolinfo->poolfracbits);
|
||||||
|
|
||||||
/* Can we pull enough? */
|
/* Can we pull enough? */
|
||||||
@ -988,29 +990,19 @@ retry:
|
|||||||
entropy_count = orig = ACCESS_ONCE(r->entropy_count);
|
entropy_count = orig = ACCESS_ONCE(r->entropy_count);
|
||||||
have_bytes = entropy_count >> (ENTROPY_SHIFT + 3);
|
have_bytes = entropy_count >> (ENTROPY_SHIFT + 3);
|
||||||
ibytes = nbytes;
|
ibytes = nbytes;
|
||||||
if (have_bytes < min + reserved) {
|
|
||||||
ibytes = 0;
|
|
||||||
} else {
|
|
||||||
/* If limited, never pull more than available */
|
/* If limited, never pull more than available */
|
||||||
if (r->limit && ibytes + reserved >= have_bytes)
|
if (r->limit)
|
||||||
ibytes = have_bytes - reserved;
|
ibytes = min_t(size_t, ibytes, have_bytes - reserved);
|
||||||
|
if (ibytes < min)
|
||||||
if (have_bytes >= ibytes + reserved)
|
ibytes = 0;
|
||||||
entropy_count -= ibytes << (ENTROPY_SHIFT + 3);
|
entropy_count = max_t(int, 0,
|
||||||
else
|
entropy_count - (ibytes << (ENTROPY_SHIFT + 3)));
|
||||||
entropy_count = reserved << (ENTROPY_SHIFT + 3);
|
|
||||||
|
|
||||||
if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
|
if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
|
||||||
goto retry;
|
goto retry;
|
||||||
|
|
||||||
if ((r->entropy_count >> ENTROPY_SHIFT)
|
|
||||||
< random_write_wakeup_thresh)
|
|
||||||
wakeup_write = 1;
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&r->lock, flags);
|
|
||||||
|
|
||||||
trace_debit_entropy(r->name, 8 * ibytes);
|
trace_debit_entropy(r->name, 8 * ibytes);
|
||||||
if (wakeup_write) {
|
if (ibytes &&
|
||||||
|
(r->entropy_count >> ENTROPY_SHIFT) < random_write_wakeup_bits) {
|
||||||
wake_up_interruptible(&random_write_wait);
|
wake_up_interruptible(&random_write_wait);
|
||||||
kill_fasync(&fasync, SIGIO, POLL_OUT);
|
kill_fasync(&fasync, SIGIO, POLL_OUT);
|
||||||
}
|
}
|
||||||
@ -1018,6 +1010,12 @@ retry:
|
|||||||
return ibytes;
|
return ibytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function does the actual extraction for extract_entropy and
|
||||||
|
* extract_entropy_user.
|
||||||
|
*
|
||||||
|
* Note: we assume that .poolwords is a multiple of 16 words.
|
||||||
|
*/
|
||||||
static void extract_buf(struct entropy_store *r, __u8 *out)
|
static void extract_buf(struct entropy_store *r, __u8 *out)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -1029,23 +1027,23 @@ static void extract_buf(struct entropy_store *r, __u8 *out)
|
|||||||
__u8 extract[64];
|
__u8 extract[64];
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
/* Generate a hash across the pool, 16 words (512 bits) at a time */
|
|
||||||
sha_init(hash.w);
|
|
||||||
spin_lock_irqsave(&r->lock, flags);
|
|
||||||
for (i = 0; i < r->poolinfo->poolwords; i += 16)
|
|
||||||
sha_transform(hash.w, (__u8 *)(r->pool + i), workspace);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we have a architectural hardware random number
|
* If we have an architectural hardware random number
|
||||||
* generator, mix that in, too.
|
* generator, use it for SHA's initial vector
|
||||||
*/
|
*/
|
||||||
|
sha_init(hash.w);
|
||||||
for (i = 0; i < LONGS(20); i++) {
|
for (i = 0; i < LONGS(20); i++) {
|
||||||
unsigned long v;
|
unsigned long v;
|
||||||
if (!arch_get_random_long(&v))
|
if (!arch_get_random_long(&v))
|
||||||
break;
|
break;
|
||||||
hash.l[i] ^= v;
|
hash.l[i] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Generate a hash across the pool, 16 words (512 bits) at a time */
|
||||||
|
spin_lock_irqsave(&r->lock, flags);
|
||||||
|
for (i = 0; i < r->poolinfo->poolwords; i += 16)
|
||||||
|
sha_transform(hash.w, (__u8 *)(r->pool + i), workspace);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We mix the hash back into the pool to prevent backtracking
|
* We mix the hash back into the pool to prevent backtracking
|
||||||
* attacks (where the attacker knows the state of the pool
|
* attacks (where the attacker knows the state of the pool
|
||||||
@ -1079,6 +1077,15 @@ static void extract_buf(struct entropy_store *r, __u8 *out)
|
|||||||
memset(&hash, 0, sizeof(hash));
|
memset(&hash, 0, sizeof(hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function extracts randomness from the "entropy pool", and
|
||||||
|
* returns it in a buffer.
|
||||||
|
*
|
||||||
|
* The min parameter specifies the minimum amount we can pull before
|
||||||
|
* failing to avoid races that defeat catastrophic reseeding while the
|
||||||
|
* reserved parameter indicates how much entropy we must leave in the
|
||||||
|
* pool after each pull to avoid starving other readers.
|
||||||
|
*/
|
||||||
static ssize_t extract_entropy(struct entropy_store *r, void *buf,
|
static ssize_t extract_entropy(struct entropy_store *r, void *buf,
|
||||||
size_t nbytes, int min, int reserved)
|
size_t nbytes, int min, int reserved)
|
||||||
{
|
{
|
||||||
@ -1129,6 +1136,10 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function extracts randomness from the "entropy pool", and
|
||||||
|
* returns it in a userspace buffer.
|
||||||
|
*/
|
||||||
static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
|
static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
|
||||||
size_t nbytes)
|
size_t nbytes)
|
||||||
{
|
{
|
||||||
@ -1170,8 +1181,9 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
|
|||||||
/*
|
/*
|
||||||
* This function is the exported kernel interface. It returns some
|
* This function is the exported kernel interface. It returns some
|
||||||
* number of good random numbers, suitable for key generation, seeding
|
* number of good random numbers, suitable for key generation, seeding
|
||||||
* TCP sequence numbers, etc. It does not use the hw random number
|
* TCP sequence numbers, etc. It does not rely on the hardware random
|
||||||
* generator, if available; use get_random_bytes_arch() for that.
|
* number generator. For random bytes direct from the hardware RNG
|
||||||
|
* (when available), use get_random_bytes_arch().
|
||||||
*/
|
*/
|
||||||
void get_random_bytes(void *buf, int nbytes)
|
void get_random_bytes(void *buf, int nbytes)
|
||||||
{
|
{
|
||||||
@ -1238,7 +1250,8 @@ static void init_std_data(struct entropy_store *r)
|
|||||||
r->last_pulled = jiffies;
|
r->last_pulled = jiffies;
|
||||||
mix_pool_bytes(r, &now, sizeof(now), NULL);
|
mix_pool_bytes(r, &now, sizeof(now), NULL);
|
||||||
for (i = r->poolinfo->poolbytes; i > 0; i -= sizeof(rv)) {
|
for (i = r->poolinfo->poolbytes; i > 0; i -= sizeof(rv)) {
|
||||||
if (!arch_get_random_long(&rv))
|
if (!arch_get_random_seed_long(&rv) &&
|
||||||
|
!arch_get_random_long(&rv))
|
||||||
rv = random_get_entropy();
|
rv = random_get_entropy();
|
||||||
mix_pool_bytes(r, &rv, sizeof(rv), NULL);
|
mix_pool_bytes(r, &rv, sizeof(rv), NULL);
|
||||||
}
|
}
|
||||||
@ -1281,56 +1294,71 @@ void rand_initialize_disk(struct gendisk *disk)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attempt an emergency refill using arch_get_random_seed_long().
|
||||||
|
*
|
||||||
|
* As with add_interrupt_randomness() be paranoid and only
|
||||||
|
* credit the output as 50% entropic.
|
||||||
|
*/
|
||||||
|
static int arch_random_refill(void)
|
||||||
|
{
|
||||||
|
const unsigned int nlongs = 64; /* Arbitrary number */
|
||||||
|
unsigned int n = 0;
|
||||||
|
unsigned int i;
|
||||||
|
unsigned long buf[nlongs];
|
||||||
|
|
||||||
|
if (!arch_has_random_seed())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < nlongs; i++) {
|
||||||
|
if (arch_get_random_seed_long(&buf[n]))
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n) {
|
||||||
|
unsigned int rand_bytes = n * sizeof(unsigned long);
|
||||||
|
|
||||||
|
mix_pool_bytes(&input_pool, buf, rand_bytes, NULL);
|
||||||
|
credit_entropy_bits(&input_pool, rand_bytes*4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
|
random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
|
||||||
{
|
{
|
||||||
ssize_t n, retval = 0, count = 0;
|
ssize_t n;
|
||||||
|
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
while (nbytes > 0) {
|
nbytes = min_t(size_t, nbytes, SEC_XFER_SIZE);
|
||||||
n = nbytes;
|
while (1) {
|
||||||
if (n > SEC_XFER_SIZE)
|
n = extract_entropy_user(&blocking_pool, buf, nbytes);
|
||||||
n = SEC_XFER_SIZE;
|
if (n < 0)
|
||||||
|
return n;
|
||||||
n = extract_entropy_user(&blocking_pool, buf, n);
|
|
||||||
|
|
||||||
if (n < 0) {
|
|
||||||
retval = n;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
trace_random_read(n*8, (nbytes-n)*8,
|
trace_random_read(n*8, (nbytes-n)*8,
|
||||||
ENTROPY_BITS(&blocking_pool),
|
ENTROPY_BITS(&blocking_pool),
|
||||||
ENTROPY_BITS(&input_pool));
|
ENTROPY_BITS(&input_pool));
|
||||||
|
if (n > 0)
|
||||||
|
return n;
|
||||||
|
|
||||||
if (n == 0) {
|
/* Pool is (near) empty. Maybe wait and retry. */
|
||||||
if (file->f_flags & O_NONBLOCK) {
|
|
||||||
retval = -EAGAIN;
|
/* First try an emergency refill */
|
||||||
break;
|
if (arch_random_refill())
|
||||||
}
|
continue;
|
||||||
|
|
||||||
|
if (file->f_flags & O_NONBLOCK)
|
||||||
|
return -EAGAIN;
|
||||||
|
|
||||||
wait_event_interruptible(random_read_wait,
|
wait_event_interruptible(random_read_wait,
|
||||||
ENTROPY_BITS(&input_pool) >=
|
ENTROPY_BITS(&input_pool) >=
|
||||||
random_read_wakeup_thresh);
|
random_read_wakeup_bits);
|
||||||
|
if (signal_pending(current))
|
||||||
if (signal_pending(current)) {
|
return -ERESTARTSYS;
|
||||||
retval = -ERESTARTSYS;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
count += n;
|
|
||||||
buf += n;
|
|
||||||
nbytes -= n;
|
|
||||||
break; /* This break makes the device work */
|
|
||||||
/* like a named pipe */
|
|
||||||
}
|
|
||||||
|
|
||||||
return (count ? count : retval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
@ -1358,9 +1386,9 @@ random_poll(struct file *file, poll_table * wait)
|
|||||||
poll_wait(file, &random_read_wait, wait);
|
poll_wait(file, &random_read_wait, wait);
|
||||||
poll_wait(file, &random_write_wait, wait);
|
poll_wait(file, &random_write_wait, wait);
|
||||||
mask = 0;
|
mask = 0;
|
||||||
if (ENTROPY_BITS(&input_pool) >= random_read_wakeup_thresh)
|
if (ENTROPY_BITS(&input_pool) >= random_read_wakeup_bits)
|
||||||
mask |= POLLIN | POLLRDNORM;
|
mask |= POLLIN | POLLRDNORM;
|
||||||
if (ENTROPY_BITS(&input_pool) < random_write_wakeup_thresh)
|
if (ENTROPY_BITS(&input_pool) < random_write_wakeup_bits)
|
||||||
mask |= POLLOUT | POLLWRNORM;
|
mask |= POLLOUT | POLLWRNORM;
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
@ -1507,18 +1535,18 @@ EXPORT_SYMBOL(generate_random_uuid);
|
|||||||
#include <linux/sysctl.h>
|
#include <linux/sysctl.h>
|
||||||
|
|
||||||
static int min_read_thresh = 8, min_write_thresh;
|
static int min_read_thresh = 8, min_write_thresh;
|
||||||
static int max_read_thresh = INPUT_POOL_WORDS * 32;
|
static int max_read_thresh = OUTPUT_POOL_WORDS * 32;
|
||||||
static int max_write_thresh = INPUT_POOL_WORDS * 32;
|
static int max_write_thresh = INPUT_POOL_WORDS * 32;
|
||||||
static char sysctl_bootid[16];
|
static char sysctl_bootid[16];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These functions is used to return both the bootid UUID, and random
|
* This function is used to return both the bootid UUID, and random
|
||||||
* UUID. The difference is in whether table->data is NULL; if it is,
|
* UUID. The difference is in whether table->data is NULL; if it is,
|
||||||
* then a new UUID is generated and returned to the user.
|
* then a new UUID is generated and returned to the user.
|
||||||
*
|
*
|
||||||
* If the user accesses this via the proc interface, it will be returned
|
* If the user accesses this via the proc interface, the UUID will be
|
||||||
* as an ASCII string in the standard UUID format. If accesses via the
|
* returned as an ASCII string in the standard UUID format; if via the
|
||||||
* sysctl system call, it is returned as 16 bytes of binary data.
|
* sysctl system call, as 16 bytes of binary data.
|
||||||
*/
|
*/
|
||||||
static int proc_do_uuid(struct ctl_table *table, int write,
|
static int proc_do_uuid(struct ctl_table *table, int write,
|
||||||
void __user *buffer, size_t *lenp, loff_t *ppos)
|
void __user *buffer, size_t *lenp, loff_t *ppos)
|
||||||
@ -1583,7 +1611,7 @@ struct ctl_table random_table[] = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.procname = "read_wakeup_threshold",
|
.procname = "read_wakeup_threshold",
|
||||||
.data = &random_read_wakeup_thresh,
|
.data = &random_read_wakeup_bits,
|
||||||
.maxlen = sizeof(int),
|
.maxlen = sizeof(int),
|
||||||
.mode = 0644,
|
.mode = 0644,
|
||||||
.proc_handler = proc_dointvec_minmax,
|
.proc_handler = proc_dointvec_minmax,
|
||||||
@ -1592,7 +1620,7 @@ struct ctl_table random_table[] = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.procname = "write_wakeup_threshold",
|
.procname = "write_wakeup_threshold",
|
||||||
.data = &random_write_wakeup_thresh,
|
.data = &random_write_wakeup_bits,
|
||||||
.maxlen = sizeof(int),
|
.maxlen = sizeof(int),
|
||||||
.mode = 0644,
|
.mode = 0644,
|
||||||
.proc_handler = proc_dointvec_minmax,
|
.proc_handler = proc_dointvec_minmax,
|
||||||
|
@ -88,6 +88,22 @@ static inline int arch_get_random_int(unsigned int *v)
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
static inline int arch_has_random(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline int arch_get_random_seed_long(unsigned long *v)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline int arch_get_random_seed_int(unsigned int *v)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline int arch_has_random_seed(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Pseudo random number generator from numerical recipes. */
|
/* Pseudo random number generator from numerical recipes. */
|
||||||
|
Loading…
Reference in New Issue
Block a user