x86, kaslr: Provide randomness functions
Adds potential sources of randomness: RDRAND, RDTSC, or the i8254. This moves the pre-alternatives inline rdrand function into the header so both pieces of code can use it. Availability of RDRAND is then controlled by CONFIG_ARCH_RANDOM, if someone wants to disable it even for kASLR. Signed-off-by: Kees Cook <keescook@chromium.org> Link: http://lkml.kernel.org/r/1381450698-28710-4-git-send-email-keescook@chromium.org Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
This commit is contained in:
		
							parent
							
								
									8ab3820fd5
								
							
						
					
					
						commit
						5bfce5ef55
					
				| @ -1,6 +1,59 @@ | |||||||
| #include "misc.h" | #include "misc.h" | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_RANDOMIZE_BASE | #ifdef CONFIG_RANDOMIZE_BASE | ||||||
|  | #include <asm/msr.h> | ||||||
|  | #include <asm/archrandom.h> | ||||||
|  | 
 | ||||||
|  | #define I8254_PORT_CONTROL	0x43 | ||||||
|  | #define I8254_PORT_COUNTER0	0x40 | ||||||
|  | #define I8254_CMD_READBACK	0xC0 | ||||||
|  | #define I8254_SELECT_COUNTER0	0x02 | ||||||
|  | #define I8254_STATUS_NOTREADY	0x40 | ||||||
|  | static inline u16 i8254(void) | ||||||
|  | { | ||||||
|  | 	u16 status, timer; | ||||||
|  | 
 | ||||||
|  | 	do { | ||||||
|  | 		outb(I8254_PORT_CONTROL, | ||||||
|  | 		     I8254_CMD_READBACK | I8254_SELECT_COUNTER0); | ||||||
|  | 		status = inb(I8254_PORT_COUNTER0); | ||||||
|  | 		timer  = inb(I8254_PORT_COUNTER0); | ||||||
|  | 		timer |= inb(I8254_PORT_COUNTER0) << 8; | ||||||
|  | 	} while (status & I8254_STATUS_NOTREADY); | ||||||
|  | 
 | ||||||
|  | 	return timer; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static unsigned long get_random_long(void) | ||||||
|  | { | ||||||
|  | 	unsigned long random; | ||||||
|  | 
 | ||||||
|  | 	if (has_cpuflag(X86_FEATURE_RDRAND)) { | ||||||
|  | 		debug_putstr("KASLR using RDRAND...\n"); | ||||||
|  | 		if (rdrand_long(&random)) | ||||||
|  | 			return random; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (has_cpuflag(X86_FEATURE_TSC)) { | ||||||
|  | 		uint32_t raw; | ||||||
|  | 
 | ||||||
|  | 		debug_putstr("KASLR using RDTSC...\n"); | ||||||
|  | 		rdtscl(raw); | ||||||
|  | 
 | ||||||
|  | 		/* Only use the low bits of rdtsc. */ | ||||||
|  | 		random = raw & 0xffff; | ||||||
|  | 	} else { | ||||||
|  | 		debug_putstr("KASLR using i8254...\n"); | ||||||
|  | 		random = i8254(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Extend timer bits poorly... */ | ||||||
|  | 	random |= (random << 16); | ||||||
|  | #ifdef CONFIG_X86_64 | ||||||
|  | 	random |= (random << 32); | ||||||
|  | #endif | ||||||
|  | 	return random; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| unsigned char *choose_kernel_location(unsigned char *input, | unsigned char *choose_kernel_location(unsigned char *input, | ||||||
| 				      unsigned long input_size, | 				      unsigned long input_size, | ||||||
|  | |||||||
| @ -52,6 +52,8 @@ unsigned char *choose_kernel_location(unsigned char *input, | |||||||
| 				      unsigned long input_size, | 				      unsigned long input_size, | ||||||
| 				      unsigned char *output, | 				      unsigned char *output, | ||||||
| 				      unsigned long output_size); | 				      unsigned long output_size); | ||||||
|  | /* cpuflags.c */ | ||||||
|  | bool has_cpuflag(int flag); | ||||||
| #else | #else | ||||||
| static inline | static inline | ||||||
| unsigned char *choose_kernel_location(unsigned char *input, | unsigned char *choose_kernel_location(unsigned char *input, | ||||||
|  | |||||||
| @ -39,6 +39,20 @@ | |||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_ARCH_RANDOM | #ifdef CONFIG_ARCH_RANDOM | ||||||
| 
 | 
 | ||||||
|  | /* Instead of arch_get_random_long() when alternatives haven't run. */ | ||||||
|  | static inline int rdrand_long(unsigned long *v) | ||||||
|  | { | ||||||
|  | 	int ok; | ||||||
|  | 	asm volatile("1: " RDRAND_LONG "\n\t" | ||||||
|  | 		     "jc 2f\n\t" | ||||||
|  | 		     "decl %0\n\t" | ||||||
|  | 		     "jnz 1b\n\t" | ||||||
|  | 		     "2:" | ||||||
|  | 		     : "=r" (ok), "=a" (*v) | ||||||
|  | 		     : "0" (RDRAND_RETRY_LOOPS)); | ||||||
|  | 	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)					\ | ||||||
| {								\ | {								\ | ||||||
| @ -68,6 +82,13 @@ GET_RANDOM(arch_get_random_int, unsigned int, RDRAND_INT, ASM_NOP3); | |||||||
| 
 | 
 | ||||||
| #endif /* CONFIG_X86_64 */ | #endif /* CONFIG_X86_64 */ | ||||||
| 
 | 
 | ||||||
|  | #else | ||||||
|  | 
 | ||||||
|  | static inline int rdrand_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); | ||||||
|  | |||||||
| @ -31,20 +31,6 @@ static int __init x86_rdrand_setup(char *s) | |||||||
| } | } | ||||||
| __setup("nordrand", x86_rdrand_setup); | __setup("nordrand", x86_rdrand_setup); | ||||||
| 
 | 
 | ||||||
| /* We can't use arch_get_random_long() here since alternatives haven't run */ |  | ||||||
| static inline int rdrand_long(unsigned long *v) |  | ||||||
| { |  | ||||||
| 	int ok; |  | ||||||
| 	asm volatile("1: " RDRAND_LONG "\n\t" |  | ||||||
| 		     "jc 2f\n\t" |  | ||||||
| 		     "decl %0\n\t" |  | ||||||
| 		     "jnz 1b\n\t" |  | ||||||
| 		     "2:" |  | ||||||
| 		     : "=r" (ok), "=a" (*v) |  | ||||||
| 		     : "0" (RDRAND_RETRY_LOOPS)); |  | ||||||
| 	return ok; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /*
 | /*
 | ||||||
|  * Force a reseed cycle; we are architecturally guaranteed a reseed |  * Force a reseed cycle; we are architecturally guaranteed a reseed | ||||||
|  * after no more than 512 128-bit chunks of random data.  This also |  * after no more than 512 128-bit chunks of random data.  This also | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user