mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-28 12:34:26 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			784 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			784 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| --- a/drivers/char/random.c
 | |
| +++ b/drivers/char/random.c
 | |
| @@ -125,21 +125,26 @@
 | |
|   * The current exported interfaces for gathering environmental noise
 | |
|   * from the devices are:
 | |
|   *
 | |
| + *	void add_device_randomness(const void *buf, unsigned int size);
 | |
|   * 	void add_input_randomness(unsigned int type, unsigned int code,
 | |
|   *                                unsigned int value);
 | |
| - * 	void add_interrupt_randomness(int irq);
 | |
| + *	void add_interrupt_randomness(int irq, int irq_flags);
 | |
|   * 	void add_disk_randomness(struct gendisk *disk);
 | |
|   *
 | |
|   * add_input_randomness() uses the input layer interrupt timing, as well as
 | |
|   * the event type information from the hardware.
 | |
|   *
 | |
| - * add_interrupt_randomness() uses the inter-interrupt timing as random
 | |
| - * inputs to the entropy pool.  Note that not all interrupts are good
 | |
| - * sources of randomness!  For example, the timer interrupts is not a
 | |
| - * good choice, because the periodicity of the interrupts is too
 | |
| - * regular, and hence predictable to an attacker.  Network Interface
 | |
| - * Controller interrupts are a better measure, since the timing of the
 | |
| - * NIC interrupts are more unpredictable.
 | |
| + * add_interrupt_randomness() uses the interrupt timing as random
 | |
| + * inputs to the entropy pool. Using the cycle counters and the irq source
 | |
| + * as inputs, it feeds the randomness roughly once a second.
 | |
| + *
 | |
| + * add_device_randomness() is for adding data to the random pool that
 | |
| + * is likely to differ between two devices (or possibly even per boot).
 | |
| + * This would be things like MAC addresses or serial numbers, or the
 | |
| + * read-out of the RTC. This does *not* add any actual entropy to the
 | |
| + * pool, but it initializes the pool to different values for devices
 | |
| + * that might otherwise be identical and have very little entropy
 | |
| + * available to them (particularly common in the embedded world).
 | |
|   *
 | |
|   * add_disk_randomness() uses what amounts to the seek time of block
 | |
|   * layer request events, on a per-disk_devt basis, as input to the
 | |
| @@ -248,6 +253,7 @@
 | |
|  #include <linux/percpu.h>
 | |
|  #include <linux/cryptohash.h>
 | |
|  #include <linux/fips.h>
 | |
| +#include <linux/ptrace.h>
 | |
|  
 | |
|  #ifdef CONFIG_GENERIC_HARDIRQS
 | |
|  # include <linux/irq.h>
 | |
| @@ -256,8 +262,12 @@
 | |
|  #include <asm/processor.h>
 | |
|  #include <asm/uaccess.h>
 | |
|  #include <asm/irq.h>
 | |
| +#include <asm/irq_regs.h>
 | |
|  #include <asm/io.h>
 | |
|  
 | |
| +#define CREATE_TRACE_POINTS
 | |
| +#include <trace/events/random.h>
 | |
| +
 | |
|  /*
 | |
|   * Configuration information
 | |
|   */
 | |
| @@ -420,8 +430,10 @@ struct entropy_store {
 | |
|  	/* read-write data: */
 | |
|  	spinlock_t lock;
 | |
|  	unsigned add_ptr;
 | |
| +	unsigned input_rotate;
 | |
|  	int entropy_count;
 | |
| -	int input_rotate;
 | |
| +	int entropy_total;
 | |
| +	unsigned int initialized:1;
 | |
|  	__u8 last_data[EXTRACT_SIZE];
 | |
|  };
 | |
|  
 | |
| @@ -454,6 +466,10 @@ static struct entropy_store nonblocking_
 | |
|  	.pool = nonblocking_pool_data
 | |
|  };
 | |
|  
 | |
| +static __u32 const twist_table[8] = {
 | |
| +	0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
 | |
| +	0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
 | |
| +
 | |
|  /*
 | |
|   * This function adds bytes into the entropy "pool".  It does not
 | |
|   * update the entropy estimate.  The caller should call
 | |
| @@ -464,29 +480,24 @@ static struct entropy_store nonblocking_
 | |
|   * it's cheap to do so and helps slightly in the expected case where
 | |
|   * the entropy is concentrated in the low-order bits.
 | |
|   */
 | |
| -static void mix_pool_bytes_extract(struct entropy_store *r, const void *in,
 | |
| -				   int nbytes, __u8 out[64])
 | |
| +static void _mix_pool_bytes(struct entropy_store *r, const void *in,
 | |
| +			    int nbytes, __u8 out[64])
 | |
|  {
 | |
| -	static __u32 const twist_table[8] = {
 | |
| -		0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
 | |
| -		0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
 | |
|  	unsigned long i, j, tap1, tap2, tap3, tap4, tap5;
 | |
|  	int input_rotate;
 | |
|  	int wordmask = r->poolinfo->poolwords - 1;
 | |
|  	const char *bytes = in;
 | |
|  	__u32 w;
 | |
| -	unsigned long flags;
 | |
|  
 | |
| -	/* Taps are constant, so we can load them without holding r->lock.  */
 | |
|  	tap1 = r->poolinfo->tap1;
 | |
|  	tap2 = r->poolinfo->tap2;
 | |
|  	tap3 = r->poolinfo->tap3;
 | |
|  	tap4 = r->poolinfo->tap4;
 | |
|  	tap5 = r->poolinfo->tap5;
 | |
|  
 | |
| -	spin_lock_irqsave(&r->lock, flags);
 | |
| -	input_rotate = r->input_rotate;
 | |
| -	i = r->add_ptr;
 | |
| +	smp_rmb();
 | |
| +	input_rotate = ACCESS_ONCE(r->input_rotate);
 | |
| +	i = ACCESS_ONCE(r->add_ptr);
 | |
|  
 | |
|  	/* mix one byte at a time to simplify size handling and churn faster */
 | |
|  	while (nbytes--) {
 | |
| @@ -513,19 +524,61 @@ static void mix_pool_bytes_extract(struc
 | |
|  		input_rotate += i ? 7 : 14;
 | |
|  	}
 | |
|  
 | |
| -	r->input_rotate = input_rotate;
 | |
| -	r->add_ptr = i;
 | |
| +	ACCESS_ONCE(r->input_rotate) = input_rotate;
 | |
| +	ACCESS_ONCE(r->add_ptr) = i;
 | |
| +	smp_wmb();
 | |
|  
 | |
|  	if (out)
 | |
|  		for (j = 0; j < 16; j++)
 | |
|  			((__u32 *)out)[j] = r->pool[(i - j) & wordmask];
 | |
| +}
 | |
| +
 | |
| +static void __mix_pool_bytes(struct entropy_store *r, const void *in,
 | |
| +			     int nbytes, __u8 out[64])
 | |
| +{
 | |
| +	trace_mix_pool_bytes_nolock(r->name, nbytes, _RET_IP_);
 | |
| +	_mix_pool_bytes(r, in, nbytes, out);
 | |
| +}
 | |
|  
 | |
| +static void mix_pool_bytes(struct entropy_store *r, const void *in,
 | |
| +			   int nbytes, __u8 out[64])
 | |
| +{
 | |
| +	unsigned long flags;
 | |
| +
 | |
| +	trace_mix_pool_bytes(r->name, nbytes, _RET_IP_);
 | |
| +	spin_lock_irqsave(&r->lock, flags);
 | |
| +	_mix_pool_bytes(r, in, nbytes, out);
 | |
|  	spin_unlock_irqrestore(&r->lock, flags);
 | |
|  }
 | |
|  
 | |
| -static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes)
 | |
| +struct fast_pool {
 | |
| +	__u32		pool[4];
 | |
| +	unsigned long	last;
 | |
| +	unsigned short	count;
 | |
| +	unsigned char	rotate;
 | |
| +	unsigned char	last_timer_intr;
 | |
| +};
 | |
| +
 | |
| +/*
 | |
| + * This is a fast mixing routine used by the interrupt randomness
 | |
| + * collector.  It's hardcoded for an 128 bit pool and assumes that any
 | |
| + * locks that might be needed are taken by the caller.
 | |
| + */
 | |
| +static void fast_mix(struct fast_pool *f, const void *in, int nbytes)
 | |
|  {
 | |
| -       mix_pool_bytes_extract(r, in, bytes, NULL);
 | |
| +	const char	*bytes = in;
 | |
| +	__u32		w;
 | |
| +	unsigned	i = f->count;
 | |
| +	unsigned	input_rotate = f->rotate;
 | |
| +
 | |
| +	while (nbytes--) {
 | |
| +		w = rol32(*bytes++, input_rotate & 31) ^ f->pool[i & 3] ^
 | |
| +			f->pool[(i + 1) & 3];
 | |
| +		f->pool[i & 3] = (w >> 3) ^ twist_table[w & 7];
 | |
| +		input_rotate += (i++ & 3) ? 7 : 14;
 | |
| +	}
 | |
| +	f->count = i;
 | |
| +	f->rotate = input_rotate;
 | |
|  }
 | |
|  
 | |
|  /*
 | |
| @@ -533,30 +586,38 @@ static void mix_pool_bytes(struct entrop
 | |
|   */
 | |
|  static void credit_entropy_bits(struct entropy_store *r, int nbits)
 | |
|  {
 | |
| -	unsigned long flags;
 | |
| -	int entropy_count;
 | |
| +	int entropy_count, orig;
 | |
|  
 | |
|  	if (!nbits)
 | |
|  		return;
 | |
|  
 | |
| -	spin_lock_irqsave(&r->lock, flags);
 | |
| -
 | |
|  	DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name);
 | |
| -	entropy_count = r->entropy_count;
 | |
| +retry:
 | |
| +	entropy_count = orig = ACCESS_ONCE(r->entropy_count);
 | |
|  	entropy_count += nbits;
 | |
| +
 | |
|  	if (entropy_count < 0) {
 | |
|  		DEBUG_ENT("negative entropy/overflow\n");
 | |
|  		entropy_count = 0;
 | |
|  	} else if (entropy_count > r->poolinfo->POOLBITS)
 | |
|  		entropy_count = r->poolinfo->POOLBITS;
 | |
| -	r->entropy_count = entropy_count;
 | |
| +	if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
 | |
| +		goto retry;
 | |
| +
 | |
| +	if (!r->initialized && nbits > 0) {
 | |
| +		r->entropy_total += nbits;
 | |
| +		if (r->entropy_total > 128)
 | |
| +			r->initialized = 1;
 | |
| +	}
 | |
| +
 | |
| +	trace_credit_entropy_bits(r->name, nbits, entropy_count,
 | |
| +				  r->entropy_total, _RET_IP_);
 | |
|  
 | |
|  	/* should we wake readers? */
 | |
|  	if (r == &input_pool && entropy_count >= random_read_wakeup_thresh) {
 | |
|  		wake_up_interruptible(&random_read_wait);
 | |
|  		kill_fasync(&fasync, SIGIO, POLL_IN);
 | |
|  	}
 | |
| -	spin_unlock_irqrestore(&r->lock, flags);
 | |
|  }
 | |
|  
 | |
|  /*********************************************************************
 | |
| @@ -609,6 +670,25 @@ static void set_timer_rand_state(unsigne
 | |
|  }
 | |
|  #endif
 | |
|  
 | |
| +/*
 | |
| + * Add device- or boot-specific data to the input and nonblocking
 | |
| + * pools to help initialize them to unique values.
 | |
| + *
 | |
| + * None of this adds any entropy, it is meant to avoid the
 | |
| + * problem of the nonblocking pool having similar initial state
 | |
| + * across largely identical devices.
 | |
| + */
 | |
| +void add_device_randomness(const void *buf, unsigned int size)
 | |
| +{
 | |
| +	unsigned long time = get_cycles() ^ jiffies;
 | |
| +
 | |
| +	mix_pool_bytes(&input_pool, buf, size, NULL);
 | |
| +	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);
 | |
| +}
 | |
| +EXPORT_SYMBOL(add_device_randomness);
 | |
| +
 | |
|  static struct timer_rand_state input_timer_state;
 | |
|  
 | |
|  /*
 | |
| @@ -637,13 +717,9 @@ static void add_timer_randomness(struct
 | |
|  		goto out;
 | |
|  
 | |
|  	sample.jiffies = jiffies;
 | |
| -
 | |
| -	/* Use arch random value, fall back to cycles */
 | |
| -	if (!arch_get_random_int(&sample.cycles))
 | |
| -		sample.cycles = get_cycles();
 | |
| -
 | |
| +	sample.cycles = get_cycles();
 | |
|  	sample.num = num;
 | |
| -	mix_pool_bytes(&input_pool, &sample, sizeof(sample));
 | |
| +	mix_pool_bytes(&input_pool, &sample, sizeof(sample), NULL);
 | |
|  
 | |
|  	/*
 | |
|  	 * Calculate number of bits of randomness we probably added.
 | |
| @@ -700,17 +776,48 @@ void add_input_randomness(unsigned int t
 | |
|  }
 | |
|  EXPORT_SYMBOL_GPL(add_input_randomness);
 | |
|  
 | |
| -void add_interrupt_randomness(int irq)
 | |
| +static DEFINE_PER_CPU(struct fast_pool, irq_randomness);
 | |
| +
 | |
| +void add_interrupt_randomness(int irq, int irq_flags)
 | |
|  {
 | |
| -	struct timer_rand_state *state;
 | |
| +	struct entropy_store	*r;
 | |
| +	struct fast_pool	*fast_pool = &__get_cpu_var(irq_randomness);
 | |
| +	struct pt_regs		*regs = get_irq_regs();
 | |
| +	unsigned long		now = jiffies;
 | |
| +	__u32			input[4], cycles = get_cycles();
 | |
| +
 | |
| +	input[0] = cycles ^ jiffies;
 | |
| +	input[1] = irq;
 | |
| +	if (regs) {
 | |
| +		__u64 ip = instruction_pointer(regs);
 | |
| +		input[2] = ip;
 | |
| +		input[3] = ip >> 32;
 | |
| +	}
 | |
|  
 | |
| -	state = get_timer_rand_state(irq);
 | |
| +	fast_mix(fast_pool, input, sizeof(input));
 | |
|  
 | |
| -	if (state == NULL)
 | |
| +	if ((fast_pool->count & 1023) &&
 | |
| +	    !time_after(now, fast_pool->last + HZ))
 | |
|  		return;
 | |
|  
 | |
| -	DEBUG_ENT("irq event %d\n", irq);
 | |
| -	add_timer_randomness(state, 0x100 + irq);
 | |
| +	fast_pool->last = now;
 | |
| +
 | |
| +	r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool;
 | |
| +	__mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool), NULL);
 | |
| +	/*
 | |
| +	 * If we don't have a valid cycle counter, and we see
 | |
| +	 * back-to-back timer interrupts, then skip giving credit for
 | |
| +	 * any entropy.
 | |
| +	 */
 | |
| +	if (cycles == 0) {
 | |
| +		if (irq_flags & __IRQF_TIMER) {
 | |
| +			if (fast_pool->last_timer_intr)
 | |
| +				return;
 | |
| +			fast_pool->last_timer_intr = 1;
 | |
| +		} else
 | |
| +			fast_pool->last_timer_intr = 0;
 | |
| +	}
 | |
| +	credit_entropy_bits(r, 1);
 | |
|  }
 | |
|  
 | |
|  #ifdef CONFIG_BLOCK
 | |
| @@ -742,7 +849,11 @@ static ssize_t extract_entropy(struct en
 | |
|   */
 | |
|  static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
 | |
|  {
 | |
| -	__u32 tmp[OUTPUT_POOL_WORDS];
 | |
| +	union {
 | |
| +		__u32	tmp[OUTPUT_POOL_WORDS];
 | |
| +		long	hwrand[4];
 | |
| +	} u;
 | |
| +	int	i;
 | |
|  
 | |
|  	if (r->pull && r->entropy_count < nbytes * 8 &&
 | |
|  	    r->entropy_count < r->poolinfo->POOLBITS) {
 | |
| @@ -753,17 +864,22 @@ static void xfer_secondary_pool(struct e
 | |
|  		/* pull at least as many as BYTES as wakeup BITS */
 | |
|  		bytes = max_t(int, bytes, random_read_wakeup_thresh / 8);
 | |
|  		/* but never more than the buffer size */
 | |
| -		bytes = min_t(int, bytes, sizeof(tmp));
 | |
| +		bytes = min_t(int, bytes, sizeof(u.tmp));
 | |
|  
 | |
|  		DEBUG_ENT("going to reseed %s with %d bits "
 | |
|  			  "(%d of %d requested)\n",
 | |
|  			  r->name, bytes * 8, nbytes * 8, r->entropy_count);
 | |
|  
 | |
| -		bytes = extract_entropy(r->pull, tmp, bytes,
 | |
| +		bytes = extract_entropy(r->pull, u.tmp, bytes,
 | |
|  					random_read_wakeup_thresh / 8, rsvd);
 | |
| -		mix_pool_bytes(r, tmp, bytes);
 | |
| +		mix_pool_bytes(r, u.tmp, bytes, NULL);
 | |
|  		credit_entropy_bits(r, bytes*8);
 | |
|  	}
 | |
| +	for (i = 0; i < 4; i++)
 | |
| +		if (arch_get_random_long(&u.hwrand[i]))
 | |
| +			break;
 | |
| +	if (i)
 | |
| +		mix_pool_bytes(r, &u.hwrand, i * sizeof(u.hwrand[0]), 0);
 | |
|  }
 | |
|  
 | |
|  /*
 | |
| @@ -822,9 +938,11 @@ static void extract_buf(struct entropy_s
 | |
|  	int i;
 | |
|  	__u32 hash[5], workspace[SHA_WORKSPACE_WORDS];
 | |
|  	__u8 extract[64];
 | |
| +	unsigned long flags;
 | |
|  
 | |
|  	/* Generate a hash across the pool, 16 words (512 bits) at a time */
 | |
|  	sha_init(hash);
 | |
| +	spin_lock_irqsave(&r->lock, flags);
 | |
|  	for (i = 0; i < r->poolinfo->poolwords; i += 16)
 | |
|  		sha_transform(hash, (__u8 *)(r->pool + i), workspace);
 | |
|  
 | |
| @@ -837,7 +955,8 @@ static void extract_buf(struct entropy_s
 | |
|  	 * brute-forcing the feedback as hard as brute-forcing the
 | |
|  	 * hash.
 | |
|  	 */
 | |
| -	mix_pool_bytes_extract(r, hash, sizeof(hash), extract);
 | |
| +	__mix_pool_bytes(r, hash, sizeof(hash), extract);
 | |
| +	spin_unlock_irqrestore(&r->lock, flags);
 | |
|  
 | |
|  	/*
 | |
|  	 * To avoid duplicates, we atomically extract a portion of the
 | |
| @@ -860,12 +979,12 @@ static void extract_buf(struct entropy_s
 | |
|  }
 | |
|  
 | |
|  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)
 | |
|  {
 | |
|  	ssize_t ret = 0, i;
 | |
|  	__u8 tmp[EXTRACT_SIZE];
 | |
| -	unsigned long flags;
 | |
|  
 | |
| +	trace_extract_entropy(r->name, nbytes, r->entropy_count, _RET_IP_);
 | |
|  	xfer_secondary_pool(r, nbytes);
 | |
|  	nbytes = account(r, nbytes, min, reserved);
 | |
|  
 | |
| @@ -873,6 +992,8 @@ static ssize_t extract_entropy(struct en
 | |
|  		extract_buf(r, tmp);
 | |
|  
 | |
|  		if (fips_enabled) {
 | |
| +			unsigned long flags;
 | |
| +
 | |
|  			spin_lock_irqsave(&r->lock, flags);
 | |
|  			if (!memcmp(tmp, r->last_data, EXTRACT_SIZE))
 | |
|  				panic("Hardware RNG duplicated output!\n");
 | |
| @@ -898,6 +1019,7 @@ static ssize_t extract_entropy_user(stru
 | |
|  	ssize_t ret = 0, i;
 | |
|  	__u8 tmp[EXTRACT_SIZE];
 | |
|  
 | |
| +	trace_extract_entropy_user(r->name, nbytes, r->entropy_count, _RET_IP_);
 | |
|  	xfer_secondary_pool(r, nbytes);
 | |
|  	nbytes = account(r, nbytes, 0, 0);
 | |
|  
 | |
| @@ -931,17 +1053,35 @@ static ssize_t extract_entropy_user(stru
 | |
|  
 | |
|  /*
 | |
|   * This function is the exported kernel interface.  It returns some
 | |
| - * number of good random numbers, suitable for seeding TCP sequence
 | |
| - * numbers, etc.
 | |
| + * number of good random numbers, suitable for key generation, seeding
 | |
| + * TCP sequence numbers, etc.  It does not use the hw random number
 | |
| + * generator, if available; use get_random_bytes_arch() for that.
 | |
|   */
 | |
|  void get_random_bytes(void *buf, int nbytes)
 | |
|  {
 | |
| +	extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0);
 | |
| +}
 | |
| +EXPORT_SYMBOL(get_random_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
 | |
| + * is impossible to verify that it is implemented securely (as
 | |
| + * opposed, to, say, the AES encryption of a sequence number using a
 | |
| + * key known by the NSA).  So it's useful if we need the speed, but
 | |
| + * only if we're willing to trust the hardware manufacturer not to
 | |
| + * have put in a back door.
 | |
| + */
 | |
| +void get_random_bytes_arch(void *buf, int nbytes)
 | |
| +{
 | |
|  	char *p = buf;
 | |
|  
 | |
| +	trace_get_random_bytes(nbytes, _RET_IP_);
 | |
|  	while (nbytes) {
 | |
|  		unsigned long v;
 | |
|  		int chunk = min(nbytes, (int)sizeof(unsigned long));
 | |
| -		
 | |
| +
 | |
|  		if (!arch_get_random_long(&v))
 | |
|  			break;
 | |
|  		
 | |
| @@ -950,9 +1090,11 @@ void get_random_bytes(void *buf, int nby
 | |
|  		nbytes -= chunk;
 | |
|  	}
 | |
|  
 | |
| -	extract_entropy(&nonblocking_pool, p, nbytes, 0, 0);
 | |
| +	if (nbytes)
 | |
| +		extract_entropy(&nonblocking_pool, p, nbytes, 0, 0);
 | |
|  }
 | |
| -EXPORT_SYMBOL(get_random_bytes);
 | |
| +EXPORT_SYMBOL(get_random_bytes_arch);
 | |
| +
 | |
|  
 | |
|  /*
 | |
|   * init_std_data - initialize pool with system data
 | |
| @@ -966,21 +1108,18 @@ EXPORT_SYMBOL(get_random_bytes);
 | |
|  static void init_std_data(struct entropy_store *r)
 | |
|  {
 | |
|  	int i;
 | |
| -	ktime_t now;
 | |
| -	unsigned long flags;
 | |
| +	ktime_t now = ktime_get_real();
 | |
| +	unsigned long rv;
 | |
|  
 | |
| -	spin_lock_irqsave(&r->lock, flags);
 | |
|  	r->entropy_count = 0;
 | |
| -	spin_unlock_irqrestore(&r->lock, flags);
 | |
| -
 | |
| -	now = ktime_get_real();
 | |
| -	mix_pool_bytes(r, &now, sizeof(now));
 | |
| -	for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof flags) {
 | |
| -		if (!arch_get_random_long(&flags))
 | |
| +	r->entropy_total = 0;
 | |
| +	mix_pool_bytes(r, &now, sizeof(now), NULL);
 | |
| +	for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof(rv)) {
 | |
| +		if (!arch_get_random_long(&rv))
 | |
|  			break;
 | |
| -		mix_pool_bytes(r, &flags, sizeof(flags));
 | |
| +		mix_pool_bytes(r, &rv, sizeof(rv), NULL);
 | |
|  	}
 | |
| -	mix_pool_bytes(r, utsname(), sizeof(*(utsname())));
 | |
| +	mix_pool_bytes(r, utsname(), sizeof(*(utsname())), NULL);
 | |
|  }
 | |
|  
 | |
|  static int rand_initialize(void)
 | |
| @@ -1117,7 +1256,7 @@ write_pool(struct entropy_store *r, cons
 | |
|  		count -= bytes;
 | |
|  		p += bytes;
 | |
|  
 | |
| -		mix_pool_bytes(r, buf, bytes);
 | |
| +		mix_pool_bytes(r, buf, bytes, NULL);
 | |
|  		cond_resched();
 | |
|  	}
 | |
|  
 | |
| @@ -1274,6 +1413,7 @@ static int proc_do_uuid(ctl_table *table
 | |
|  }
 | |
|  
 | |
|  static int sysctl_poolsize = INPUT_POOL_WORDS * 32;
 | |
| +extern ctl_table random_table[];
 | |
|  ctl_table random_table[] = {
 | |
|  	{
 | |
|  		.procname	= "poolsize",
 | |
| @@ -1339,7 +1479,7 @@ late_initcall(random_int_secret_init);
 | |
|   * value is not cryptographically secure but for several uses the cost of
 | |
|   * depleting entropy is too high
 | |
|   */
 | |
| -DEFINE_PER_CPU(__u32 [MD5_DIGEST_WORDS], get_random_int_hash);
 | |
| +static DEFINE_PER_CPU(__u32 [MD5_DIGEST_WORDS], get_random_int_hash);
 | |
|  unsigned int get_random_int(void)
 | |
|  {
 | |
|  	__u32 *hash;
 | |
| --- a/drivers/mfd/ab3100-core.c
 | |
| +++ b/drivers/mfd/ab3100-core.c
 | |
| @@ -409,8 +409,6 @@ static irqreturn_t ab3100_irq_handler(in
 | |
|  	u32 fatevent;
 | |
|  	int err;
 | |
|  
 | |
| -	add_interrupt_randomness(irq);
 | |
| -
 | |
|  	err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1,
 | |
|  				       event_regs, 3);
 | |
|  	if (err)
 | |
| --- a/drivers/usb/core/hub.c
 | |
| +++ b/drivers/usb/core/hub.c
 | |
| @@ -24,6 +24,7 @@
 | |
|  #include <linux/kthread.h>
 | |
|  #include <linux/mutex.h>
 | |
|  #include <linux/freezer.h>
 | |
| +#include <linux/random.h>
 | |
|  
 | |
|  #include <asm/uaccess.h>
 | |
|  #include <asm/byteorder.h>
 | |
| @@ -1896,6 +1897,14 @@ int usb_new_device(struct usb_device *ud
 | |
|  	/* Tell the world! */
 | |
|  	announce_device(udev);
 | |
|  
 | |
| +	if (udev->serial)
 | |
| +		add_device_randomness(udev->serial, strlen(udev->serial));
 | |
| +	if (udev->product)
 | |
| +		add_device_randomness(udev->product, strlen(udev->product));
 | |
| +	if (udev->manufacturer)
 | |
| +		add_device_randomness(udev->manufacturer,
 | |
| +				      strlen(udev->manufacturer));
 | |
| +
 | |
|  	device_enable_async_suspend(&udev->dev);
 | |
|  	/* Register the device.  The device driver is responsible
 | |
|  	 * for configuring the device and invoking the add-device
 | |
| --- a/include/linux/random.h
 | |
| +++ b/include/linux/random.h
 | |
| @@ -50,11 +50,13 @@ struct rnd_state {
 | |
|  
 | |
|  extern void rand_initialize_irq(int irq);
 | |
|  
 | |
| +extern void add_device_randomness(const void *, unsigned int);
 | |
|  extern void add_input_randomness(unsigned int type, unsigned int code,
 | |
|  				 unsigned int value);
 | |
| -extern void add_interrupt_randomness(int irq);
 | |
| +extern void add_interrupt_randomness(int irq, int irq_flags);
 | |
|  
 | |
|  extern void get_random_bytes(void *buf, int nbytes);
 | |
| +extern void get_random_bytes_arch(void *buf, int nbytes);
 | |
|  void generate_random_uuid(unsigned char uuid_out[16]);
 | |
|  
 | |
|  #ifndef MODULE
 | |
| --- /dev/null
 | |
| +++ b/include/trace/events/random.h
 | |
| @@ -0,0 +1,134 @@
 | |
| +#undef TRACE_SYSTEM
 | |
| +#define TRACE_SYSTEM random
 | |
| +
 | |
| +#if !defined(_TRACE_RANDOM_H) || defined(TRACE_HEADER_MULTI_READ)
 | |
| +#define _TRACE_RANDOM_H
 | |
| +
 | |
| +#include <linux/writeback.h>
 | |
| +#include <linux/tracepoint.h>
 | |
| +
 | |
| +DECLARE_EVENT_CLASS(random__mix_pool_bytes,
 | |
| +	TP_PROTO(const char *pool_name, int bytes, unsigned long IP),
 | |
| +
 | |
| +	TP_ARGS(pool_name, bytes, IP),
 | |
| +
 | |
| +	TP_STRUCT__entry(
 | |
| +		__field( const char *,	pool_name		)
 | |
| +		__field(	  int,	bytes			)
 | |
| +		__field(unsigned long,	IP			)
 | |
| +	),
 | |
| +
 | |
| +	TP_fast_assign(
 | |
| +		__entry->pool_name	= pool_name;
 | |
| +		__entry->bytes		= bytes;
 | |
| +		__entry->IP		= IP;
 | |
| +	),
 | |
| +
 | |
| +	TP_printk("%s pool: bytes %d caller %pF",
 | |
| +		  __entry->pool_name, __entry->bytes, (void *)__entry->IP)
 | |
| +);
 | |
| +
 | |
| +DEFINE_EVENT(random__mix_pool_bytes, mix_pool_bytes,
 | |
| +	TP_PROTO(const char *pool_name, int bytes, unsigned long IP),
 | |
| +
 | |
| +	TP_ARGS(pool_name, bytes, IP)
 | |
| +);
 | |
| +
 | |
| +DEFINE_EVENT(random__mix_pool_bytes, mix_pool_bytes_nolock,
 | |
| +	TP_PROTO(const char *pool_name, int bytes, unsigned long IP),
 | |
| +
 | |
| +	TP_ARGS(pool_name, bytes, IP)
 | |
| +);
 | |
| +
 | |
| +TRACE_EVENT(credit_entropy_bits,
 | |
| +	TP_PROTO(const char *pool_name, int bits, int entropy_count,
 | |
| +		 int entropy_total, unsigned long IP),
 | |
| +
 | |
| +	TP_ARGS(pool_name, bits, entropy_count, entropy_total, IP),
 | |
| +
 | |
| +	TP_STRUCT__entry(
 | |
| +		__field( const char *,	pool_name		)
 | |
| +		__field(	  int,	bits			)
 | |
| +		__field(	  int,	entropy_count		)
 | |
| +		__field(	  int,	entropy_total		)
 | |
| +		__field(unsigned long,	IP			)
 | |
| +	),
 | |
| +
 | |
| +	TP_fast_assign(
 | |
| +		__entry->pool_name	= pool_name;
 | |
| +		__entry->bits		= bits;
 | |
| +		__entry->entropy_count	= entropy_count;
 | |
| +		__entry->entropy_total	= entropy_total;
 | |
| +		__entry->IP		= IP;
 | |
| +	),
 | |
| +
 | |
| +	TP_printk("%s pool: bits %d entropy_count %d entropy_total %d "
 | |
| +		  "caller %pF", __entry->pool_name, __entry->bits,
 | |
| +		  __entry->entropy_count, __entry->entropy_total,
 | |
| +		  (void *)__entry->IP)
 | |
| +);
 | |
| +
 | |
| +TRACE_EVENT(get_random_bytes,
 | |
| +	TP_PROTO(int nbytes, unsigned long IP),
 | |
| +
 | |
| +	TP_ARGS(nbytes, IP),
 | |
| +
 | |
| +	TP_STRUCT__entry(
 | |
| +		__field(	  int,	nbytes			)
 | |
| +		__field(unsigned long,	IP			)
 | |
| +	),
 | |
| +
 | |
| +	TP_fast_assign(
 | |
| +		__entry->nbytes		= nbytes;
 | |
| +		__entry->IP		= IP;
 | |
| +	),
 | |
| +
 | |
| +	TP_printk("nbytes %d caller %pF", __entry->nbytes, (void *)__entry->IP)
 | |
| +);
 | |
| +
 | |
| +DECLARE_EVENT_CLASS(random__extract_entropy,
 | |
| +	TP_PROTO(const char *pool_name, int nbytes, int entropy_count,
 | |
| +		 unsigned long IP),
 | |
| +
 | |
| +	TP_ARGS(pool_name, nbytes, entropy_count, IP),
 | |
| +
 | |
| +	TP_STRUCT__entry(
 | |
| +		__field( const char *,	pool_name		)
 | |
| +		__field(	  int,	nbytes			)
 | |
| +		__field(	  int,	entropy_count		)
 | |
| +		__field(unsigned long,	IP			)
 | |
| +	),
 | |
| +
 | |
| +	TP_fast_assign(
 | |
| +		__entry->pool_name	= pool_name;
 | |
| +		__entry->nbytes		= nbytes;
 | |
| +		__entry->entropy_count	= entropy_count;
 | |
| +		__entry->IP		= IP;
 | |
| +	),
 | |
| +
 | |
| +	TP_printk("%s pool: nbytes %d entropy_count %d caller %pF",
 | |
| +		  __entry->pool_name, __entry->nbytes, __entry->entropy_count,
 | |
| +		  (void *)__entry->IP)
 | |
| +);
 | |
| +
 | |
| +
 | |
| +DEFINE_EVENT(random__extract_entropy, extract_entropy,
 | |
| +	TP_PROTO(const char *pool_name, int nbytes, int entropy_count,
 | |
| +		 unsigned long IP),
 | |
| +
 | |
| +	TP_ARGS(pool_name, nbytes, entropy_count, IP)
 | |
| +);
 | |
| +
 | |
| +DEFINE_EVENT(random__extract_entropy, extract_entropy_user,
 | |
| +	TP_PROTO(const char *pool_name, int nbytes, int entropy_count,
 | |
| +		 unsigned long IP),
 | |
| +
 | |
| +	TP_ARGS(pool_name, nbytes, entropy_count, IP)
 | |
| +);
 | |
| +
 | |
| +
 | |
| +
 | |
| +#endif /* _TRACE_RANDOM_H */
 | |
| +
 | |
| +/* This part must be outside protection */
 | |
| +#include <trace/define_trace.h>
 | |
| --- a/kernel/irq/handle.c
 | |
| +++ b/kernel/irq/handle.c
 | |
| @@ -117,7 +117,7 @@ irqreturn_t
 | |
|  handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
 | |
|  {
 | |
|  	irqreturn_t retval = IRQ_NONE;
 | |
| -	unsigned int random = 0, irq = desc->irq_data.irq;
 | |
| +	unsigned int flags = 0, irq = desc->irq_data.irq;
 | |
|  
 | |
|  	do {
 | |
|  		irqreturn_t res;
 | |
| @@ -145,7 +145,7 @@ handle_irq_event_percpu(struct irq_desc
 | |
|  
 | |
|  			/* Fall through to add to randomness */
 | |
|  		case IRQ_HANDLED:
 | |
| -			random |= action->flags;
 | |
| +			flags |= action->flags;
 | |
|  			break;
 | |
|  
 | |
|  		default:
 | |
| @@ -156,8 +156,7 @@ handle_irq_event_percpu(struct irq_desc
 | |
|  		action = action->next;
 | |
|  	} while (action);
 | |
|  
 | |
| -	if (random & IRQF_SAMPLE_RANDOM)
 | |
| -		add_interrupt_randomness(irq);
 | |
| +	add_interrupt_randomness(irq, flags);
 | |
|  
 | |
|  	if (!noirqdebug)
 | |
|  		note_interrupt(irq, desc, retval);
 | |
| --- a/net/core/dev.c
 | |
| +++ b/net/core/dev.c
 | |
| @@ -1176,6 +1176,7 @@ static int __dev_open(struct net_device
 | |
|  		net_dmaengine_get();
 | |
|  		dev_set_rx_mode(dev);
 | |
|  		dev_activate(dev);
 | |
| +		add_device_randomness(dev->dev_addr, dev->addr_len);
 | |
|  	}
 | |
|  
 | |
|  	return ret;
 | |
| @@ -4823,6 +4824,7 @@ int dev_set_mac_address(struct net_devic
 | |
|  	err = ops->ndo_set_mac_address(dev, sa);
 | |
|  	if (!err)
 | |
|  		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
 | |
| +	add_device_randomness(dev->dev_addr, dev->addr_len);
 | |
|  	return err;
 | |
|  }
 | |
|  EXPORT_SYMBOL(dev_set_mac_address);
 | |
| @@ -5602,6 +5604,7 @@ int register_netdevice(struct net_device
 | |
|  	dev_init_scheduler(dev);
 | |
|  	dev_hold(dev);
 | |
|  	list_netdevice(dev);
 | |
| +	add_device_randomness(dev->dev_addr, dev->addr_len);
 | |
|  
 | |
|  	/* Notify protocols, that a new device appeared. */
 | |
|  	ret = call_netdevice_notifiers(NETDEV_REGISTER, dev);
 | |
| --- a/net/core/rtnetlink.c
 | |
| +++ b/net/core/rtnetlink.c
 | |
| @@ -1371,6 +1371,7 @@ static int do_setlink(struct net_device
 | |
|  			goto errout;
 | |
|  		send_addr_notify = 1;
 | |
|  		modified = 1;
 | |
| +		add_device_randomness(dev->dev_addr, dev->addr_len);
 | |
|  	}
 | |
|  
 | |
|  	if (tb[IFLA_MTU]) {
 |