Patchwork linux-user: Define AT_RANDOM to support target dynamic linkers that do ASLR

login
register
mail settings
Submitter vincent
Date June 1, 2011, 11:42 a.m.
Message ID <1306928551-31723-1-git-send-email-cedric.vincent@st.com>
Download mbox | patch
Permalink /patch/98171/
State New
Headers show

Comments

vincent - June 1, 2011, 11:42 a.m.
From: Laurent ALFONSI <laurent.alfonsi@st.com>

The dynamic linker of the GNU C library v2.10+ uses the ELF auxialiary
vector AT_RANDOM as a pointer to a 16-bit random value.  Prior this
patch the value of AT_RANDOM was not defined by the ELF loader of QEMU
so the GNU dynamic linker de-referenced the NULL pointer instead.  As
a consequence any target program linked to the GNU C library v2.10+
crashed due to a SEGFAULT.

Note AT_RANDOM now points to the start of the text segment thus the
16-bit value is not random at all, however it is definitively
readable.  This "dummy" behavior could be improved later.

Signed-off-by: Laurent ALFONSI <laurent.alfonsi@st.com>
Signed-off-by: Cédric VINCENT <cedric.vincent@st.com>
---

You can easily test this patch with ARMedSlack-13+:

    ftp://ftp.armedslack.org/armedslack/armedslack-devtools/minirootfs/roots/

 linux-user/elfload.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)
Richard Henderson - June 1, 2011, 1:26 p.m.
On 06/01/2011 04:42 AM, Cédric VINCENT wrote:
> +    /* The dynamic linker of the GNU C library v2.10+ uses the ELF
> +     * auxialiary vector AT_RANDOM as a pointer to a 16-bit random
> +     * value.  Note the start of the text segment is not random at
> +     * all, however it is definitively readeable. */
> +    NEW_AUX_ENT(AT_RANDOM, (abi_ulong) info->start_code);

16 bytes, not 16 bits.  Typos for auxiliary and readable.


r~
vincent - June 1, 2011, 1:47 p.m.
On Wed, Jun 01, 2011 at 03:26:09PM +0200, Richard Henderson wrote:
> 
> 16 bytes, not 16 bits.

You're right it's not 16 bits, it's "sizeof(uintptr_t)" actually:

    http://repo.or.cz/w/glibc.git/blob/glibc-2.10:/sysdeps/unix/sysv/linux/dl-osinfo.h#l89

>  Typos for auxiliary and readable.

Thanks.
Richard Henderson - June 1, 2011, 3:33 p.m.
On 06/01/2011 06:47 AM, cedric.vincent@st.com wrote:
> On Wed, Jun 01, 2011 at 03:26:09PM +0200, Richard Henderson wrote:
>>
>> 16 bytes, not 16 bits.
> 
> You're right it's not 16 bits, it's "sizeof(uintptr_t)" actually:

No, it's not.

        unsigned char k_rand_bytes[16];
        elf_addr_t __user *u_rand_bytes;
...
        /*
         * Generate 16 random bytes for userspace PRNG seeding.
         */
        get_random_bytes(k_rand_bytes, sizeof(k_rand_bytes));
        u_rand_bytes = (elf_addr_t __user *)
                       STACK_ALLOC(p, sizeof(k_rand_bytes));
        if (__copy_to_user(u_rand_bytes, k_rand_bytes, sizeof(k_rand_bytes)))
                return -EFAULT;
...
        NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes);


Frankly, it's trivial to do this right in create_elf_tables.
Grab 16 bytes at SP right at the beginning of the function,
fill it with whatever random values seem good.

I suggest at minimum a command-line argument to force a 
particular AT_RANDOM value, for repeatability.


r~
vincent - June 3, 2011, 6:46 a.m.
On Wed, Jun 01, 2011 at 05:33:55PM +0200, Richard Henderson wrote:
> On 06/01/2011 06:47 AM, cedric.vincent@st.com wrote:
> > On Wed, Jun 01, 2011 at 03:26:09PM +0200, Richard Henderson wrote:
> >>
> >> 16 bytes, not 16 bits.
> > 
> > You're right it's not 16 bits, it's "sizeof(uintptr_t)" actually:
> 
> No, it's not.
> 
>         unsigned char k_rand_bytes[16];
>         elf_addr_t __user *u_rand_bytes;
> ...
>         /*
>          * Generate 16 random bytes for userspace PRNG seeding.
>          */
>         get_random_bytes(k_rand_bytes, sizeof(k_rand_bytes));
>         u_rand_bytes = (elf_addr_t __user *)
>                        STACK_ALLOC(p, sizeof(k_rand_bytes));
>         if (__copy_to_user(u_rand_bytes, k_rand_bytes, sizeof(k_rand_bytes)))
>                 return -EFAULT;
> ...
>         NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes);

It's clearer to me now, thanks.


> Frankly, it's trivial to do this right in create_elf_tables.
> Grab 16 bytes at SP right at the beginning of the function,
> fill it with whatever random values seem good.
> 
> I suggest at minimum a command-line argument to force a 
> particular AT_RANDOM value, for repeatability.

OK, I will submit you such a patch soon.

Thanks,
Cédric.
Laurent Alfonsi - June 13, 2011, 12:03 p.m.
>>          unsigned char k_rand_bytes[16];
>>          elf_addr_t __user *u_rand_bytes;
>> ...
>>          /*
>>           * Generate 16 random bytes for userspace PRNG seeding.
>>           */
>>          get_random_bytes(k_rand_bytes, sizeof(k_rand_bytes));
>>          u_rand_bytes = (elf_addr_t __user *)
>>                         STACK_ALLOC(p, sizeof(k_rand_bytes));
>>          if (__copy_to_user(u_rand_bytes, k_rand_bytes, sizeof(k_rand_bytes)))
>>                  return -EFAULT;
>> ...
>>          NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes);
> It's clearer to me now, thanks.
It is fine with me, I also understand better now.
And this now brings me to another point : In that case, it might have 
sense to also add the auxv AT_RANDOM_SIZE.
     http://sources.redhat.com/ml/libc-alpha/2008-10/msg00016.html

>> I suggest at minimum a command-line argument to force a
>> particular AT_RANDOM value, for repeatability.
Yep, I agree.

Laurent.
Richard Henderson - June 13, 2011, 3:53 p.m.
On 06/13/2011 05:03 AM, Laurent Alfonsi wrote:
> And this now brings me to another point : In that case, it might have
> sense to also add the auxv AT_RANDOM_SIZE.
>     http://sources.redhat.com/ml/libc-alpha/2008-10/msg00016.html

That never made it into the upstream kernel though.


r~

Patch

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index dcfeb7a..6f67286 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)
 {
@@ -1271,6 +1271,13 @@  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));
+
+    /* The dynamic linker of the GNU C library v2.10+ uses the ELF
+     * auxialiary vector AT_RANDOM as a pointer to a 16-bit random
+     * value.  Note the start of the text segment is not random at
+     * all, however it is definitively readeable. */
+    NEW_AUX_ENT(AT_RANDOM, (abi_ulong) info->start_code);
+
     if (k_platform)
         NEW_AUX_ENT(AT_PLATFORM, u_platform);
 #ifdef ARCH_DLINFO