diff options
author | Laurent ALFONSI <laurent.alfonsi@st.com> | 2011-06-20 08:43:13 +0200 |
---|---|---|
committer | Riku Voipio <riku.voipio@iki.fi> | 2011-06-21 20:30:09 +0300 |
commit | 14322bad88c46e41b962ff8f4a6f524dd883670c (patch) | |
tree | 0ee597cebc6ded214c1b771458aea3dc1a3b1c4b /linux-user | |
parent | 055e090687d31429b4cd080626d2bf9ce8bbfe59 (diff) |
linux-user: Define AT_RANDOM to support target stack protection mechanism.
The dynamic linker from the GNU C library v2.10+ uses the ELF
auxiliary vector AT_RANDOM [1] as a pointer to 16 bytes with random
values to initialize the stack protection mechanism. Technically the
emulated GNU dynamic linker crashes due to a NULL pointer
derefencement if it is built with stack protection enabled and if
AT_RANDOM is not defined by the QEMU ELF loader.
[1] This ELF auxiliary vector was introduced in Linux v2.6.29.
This patch can be tested with the code above:
#include <elf.h> /* Elf*_auxv_t, AT_RANDOM, */
#include <stdio.h> /* printf(3), */
#include <stdlib.h> /* exit(3), EXIT_*, */
#include <stdint.h> /* uint8_t, */
#include <string.h> /* memcpy(3), */
#if defined(__LP64__) || defined(__ILP64__) || defined(__LLP64__)
# define Elf_auxv_t Elf64_auxv_t
#else
# define Elf_auxv_t Elf32_auxv_t
#endif
main(int argc, char* argv[], char* envp[])
{
Elf_auxv_t *auxv;
/* *envp = NULL marks end of envp. */
while (*envp++ != NULL);
/* auxv->a_type = AT_NULL marks the end of auxv. */
for (auxv = (Elf_auxv_t *)envp; auxv->a_type != AT_NULL; auxv++) {
if (auxv->a_type == AT_RANDOM) {
int i;
uint8_t rand_bytes[16];
printf("AT_RANDOM is: 0x%x\n", auxv->a_un.a_val);
memcpy(rand_bytes, (const uint8_t *)auxv->a_un.a_val, sizeof(rand_bytes));
printf("it points to: ");
for (i = 0; i < 16; i++) {
printf("0x%02x ", rand_bytes[i]);
}
printf("\n");
exit(EXIT_SUCCESS);
}
}
exit(EXIT_FAILURE);
}
Changes introduced in v2 and v3:
* Fix typos + thinko (AT_RANDOM is used for stack canary, not for
ASLR)
* AT_RANDOM points to 16 random bytes stored inside the user
stack.
* Add a small test program.
Signed-off-by: Cédric VINCENT <cedric.vincent@st.com>
Signed-off-by: Laurent ALFONSI <laurent.alfonsi@st.com>
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
Diffstat (limited to 'linux-user')
-rw-r--r-- | linux-user/elfload.c | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c index a13eb7be62..b2746f2558 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -927,7 +927,7 @@ struct exec #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) -#define DLINFO_ITEMS 12 +#define DLINFO_ITEMS 13 static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) { @@ -1202,6 +1202,9 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, { abi_ulong sp; int size; + int i; + abi_ulong u_rand_bytes; + uint8_t k_rand_bytes[16]; abi_ulong u_platform; const char *k_platform; const int n = sizeof(elf_addr_t); @@ -1231,6 +1234,20 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, /* FIXME - check return value of memcpy_to_target() for failure */ memcpy_to_target(sp, k_platform, len); } + + /* + * Generate 16 random bytes for userspace PRNG seeding (not + * cryptically secure but it's not the aim of QEMU). + */ + srand((unsigned int) time(NULL)); + for (i = 0; i < 16; i++) { + k_rand_bytes[i] = rand(); + } + sp -= 16; + u_rand_bytes = sp; + /* FIXME - check return value of memcpy_to_target() for failure */ + memcpy_to_target(sp, k_rand_bytes, 16); + /* * Force 16 byte _final_ alignment here for generality. */ @@ -1271,6 +1288,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid()); NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP); NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK)); + NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes); + if (k_platform) NEW_AUX_ENT(AT_PLATFORM, u_platform); #ifdef ARCH_DLINFO |