Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ELF: implement AT_RANDOM for glibc PRNG seeding

While discussing[1] the need for glibc to have access to random bytes
during program load, it seems that an earlier attempt to implement
AT_RANDOM got stalled. This implements a random 16 byte string, available
to every ELF program via a new auxv AT_RANDOM vector.

[1] http://sourceware.org/ml/libc-alpha/2008-10/msg00006.html

Ulrich said:

glibc needs right after startup a bit of random data for internal
protections (stack canary etc). What is now in upstream glibc is that we
always unconditionally open /dev/urandom, read some data, and use it. For
every process startup. That's slow.

...

The solution is to provide a limited amount of random data to the
starting process in the aux vector. I suggested 16 bytes and this is
what the patch implements. If we need only 16 bytes or less we use the
data directly. If we need more we'll use the 16 bytes to see a PRNG.
This avoids the costly /dev/urandom use and it allows the kernel to use
the most adequate source of random data for this purpose. It might not
be the same pool as that for /dev/urandom.

Concerns were expressed about the depletion of the randomness pool. But
this patch doesn't make the situation worse, it doesn't deplete entropy
more than happens now.

Signed-off-by: Kees Cook <kees.cook@canonical.com>
Cc: Jakub Jelinek <jakub@redhat.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Ulrich Drepper <drepper@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Kees Cook and committed by
Linus Torvalds
f06295b4 a6684999

+15 -3
+12
fs/binfmt_elf.c
··· 152 152 elf_addr_t __user *sp; 153 153 elf_addr_t __user *u_platform; 154 154 elf_addr_t __user *u_base_platform; 155 + elf_addr_t __user *u_rand_bytes; 155 156 const char *k_platform = ELF_PLATFORM; 156 157 const char *k_base_platform = ELF_BASE_PLATFORM; 158 + unsigned char k_rand_bytes[16]; 157 159 int items; 158 160 elf_addr_t *elf_info; 159 161 int ei_index = 0; ··· 198 196 return -EFAULT; 199 197 } 200 198 199 + /* 200 + * Generate 16 random bytes for userspace PRNG seeding. 201 + */ 202 + get_random_bytes(k_rand_bytes, sizeof(k_rand_bytes)); 203 + u_rand_bytes = (elf_addr_t __user *) 204 + STACK_ALLOC(p, sizeof(k_rand_bytes)); 205 + if (__copy_to_user(u_rand_bytes, k_rand_bytes, sizeof(k_rand_bytes))) 206 + return -EFAULT; 207 + 201 208 /* Create the ELF interpreter info */ 202 209 elf_info = (elf_addr_t *)current->mm->saved_auxv; 203 210 /* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */ ··· 239 228 NEW_AUX_ENT(AT_GID, cred->gid); 240 229 NEW_AUX_ENT(AT_EGID, cred->egid); 241 230 NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm)); 231 + NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes); 242 232 NEW_AUX_ENT(AT_EXECFN, bprm->exec); 243 233 if (k_platform) { 244 234 NEW_AUX_ENT(AT_PLATFORM,
+3 -3
include/linux/auxvec.h
··· 23 23 #define AT_PLATFORM 15 /* string identifying CPU for optimizations */ 24 24 #define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */ 25 25 #define AT_CLKTCK 17 /* frequency at which times() increments */ 26 - 26 + /* AT_* values 18 through 22 are reserved */ 27 27 #define AT_SECURE 23 /* secure mode boolean */ 28 - 29 28 #define AT_BASE_PLATFORM 24 /* string identifying real platform, may 30 29 * differ from AT_PLATFORM. */ 30 + #define AT_RANDOM 25 /* address of 16 random bytes */ 31 31 32 32 #define AT_EXECFN 31 /* filename of program */ 33 33 34 34 #ifdef __KERNEL__ 35 - #define AT_VECTOR_SIZE_BASE 18 /* NEW_AUX_ENT entries in auxiliary table */ 35 + #define AT_VECTOR_SIZE_BASE 19 /* NEW_AUX_ENT entries in auxiliary table */ 36 36 /* number of "#define AT_.*" above, minus {AT_NULL, AT_IGNORE, AT_NOTELF} */ 37 37 #endif 38 38