2015-02-23 18:55:44

by Hector Marco-Gisbert

[permalink] [raw]
Subject: [PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS

[PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS

The issue appears on PIE linked executables when all memory areas of a process are randomized. In
this case, the attack "offset2lib" de-randomizes all library areas on 64 bit Linux systems in less
than one second.


Further details of the PoC attack at:
http://cybersecurity.upv.es/attacks/offset2lib/offset2lib.html


This patch loads the PIE linked executable in a different area than the libraries. The successful
fix can be tested with a simple pie compiled application:


$ ./show_mmaps_pie
54859ccd6000-54859ccd7000 r-xp ... /tmp/show_mmaps_pie
54859ced6000-54859ced7000 r--p ... /tmp/show_mmaps_pie
54859ced7000-54859ced8000 rw-p ... /tmp/show_mmaps_pie
7f75be764000-7f75be91f000 r-xp ... /lib/x86_64-linux-gnu/libc.so.6
7f75be91f000-7f75beb1f000 ---p ... /lib/x86_64-linux-gnu/libc.so.6
7f75beb1f000-7f75beb23000 r--p ... /lib/x86_64-linux-gnu/libc.so.6
7f75beb23000-7f75beb25000 rw-p ... /lib/x86_64-linux-gnu/libc.so.6
7f75beb25000-7f75beb2a000 rw-p ...
7f75beb2a000-7f75beb4d000 r-xp ... /lib64/ld-linux-x86-64.so.2
7f75bed45000-7f75bed46000 rw-p ...
7f75bed46000-7f75bed47000 r-xp ...
7f75bed47000-7f75bed4c000 rw-p ...
7f75bed4c000-7f75bed4d000 r--p ... /lib64/ld-linux-x86-64.so.2
7f75bed4d000-7f75bed4e000 rw-p ... /lib64/ld-linux-x86-64.so.2
7f75bed4e000-7f75bed4f000 rw-p ...
7fffb3741000-7fffb3762000 rw-p ... [stack]
7fffb377b000-7fffb377d000 r--p ... [vvar]
7fffb377d000-7fffb377f000 r-xp ... [vdso]


Once corrected, the PIE linked application is loaded in a different area.

We updated the "Fixing Offset2lib weakness" page:
http://cybersecurity.upv.es/solutions/aslrv2/aslrv2.html


Signed-off-by: Hector Marco-Gisbert <[email protected]>
Signed-off-by: Ismael Ripoll <[email protected]>


diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 97d07ed..ee7ea7e 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1,7 +1,6 @@
config ARM
bool
default y
- select ARCH_BINFMT_ELF_RANDOMIZE_PIE
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_HAVE_CUSTOM_GPIO_H
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index afb9caf..6755cd8 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -115,7 +115,8 @@ int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs);
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. */

-#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
+extern unsigned long randomize_et_dyn(unsigned long base);
+#define ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE / 3))

/* When the program starts, a1 contains a pointer to a function to be
registered with atexit, as per the SVR4 ABI. A value of 0 means we
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index 5e85ed3..9177100 100644
--- a/arch/arm/mm/mmap.c
+++ b/arch/arm/mm/mmap.c
@@ -30,6 +30,17 @@ static int mmap_is_legacy(void)
return sysctl_legacy_va_layout;
}

+static unsigned long mmap_rnd(void)
+{
+ unsigned long rnd = 0;
+
+ /* 8 bits of randomness in 20 address space bits */
+ if (current->flags & PF_RANDOMIZE)
+ rnd = (long)get_random_int() % (1 << 8);
+
+ return rnd << PAGE_SHIFT;
+}
+
static unsigned long mmap_base(unsigned long rnd)
{
unsigned long gap = rlimit(RLIMIT_STACK);
@@ -230,3 +241,13 @@ int devmem_is_allowed(unsigned long pfn)
}

#endif
+
+unsigned long randomize_et_dyn(unsigned long base)
+{
+ unsigned long ret;
+ if ((current->personality & ADDR_NO_RANDOMIZE) ||
+ !(current->flags & PF_RANDOMIZE))
+ return base;
+ ret = base + mmap_rnd();
+ return (ret > base) ? ret : base;
+}
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b1f9a20..5580d90 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1,6 +1,5 @@
config ARM64
def_bool y
- select ARCH_BINFMT_ELF_RANDOMIZE_PIE
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_GCOV_PROFILE_ALL
select ARCH_HAS_SG_CHAIN
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index 1f65be3..01d3aab 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -126,7 +126,7 @@ typedef struct user_fpsimd_state elf_fpregset_t;
* that it will "exec", and that there is sufficient room for the brk.
*/
extern unsigned long randomize_et_dyn(unsigned long base);
-#define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3)
+#define ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE_64 / 3))

/*
* When the program starts, a1 contains a pointer to a function to be
@@ -169,7 +169,7 @@ extern unsigned long arch_randomize_brk(struct mm_struct *mm);
#define COMPAT_ELF_PLATFORM ("v8l")
#endif

-#define COMPAT_ELF_ET_DYN_BASE (2 * TASK_SIZE_32 / 3)
+#define COMPAT_ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE_32 / 3))

/* AArch32 registers. */
#define COMPAT_ELF_NGREG 18
diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c
index 54922d1..980110c50 100644
--- a/arch/arm64/mm/mmap.c
+++ b/arch/arm64/mm/mmap.c
@@ -89,6 +89,16 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
}
EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);

+unsigned long randomize_et_dyn(unsigned long base)
+{
+ unsigned long ret;
+ if ((current->personality & ADDR_NO_RANDOMIZE) ||
+ !(current->flags & PF_RANDOMIZE))
+ return base;
+ ret = base + mmap_rnd();
+ return (ret > base) ? ret : base;
+}
+

/*
* You really shouldn't be using read() or write() on /dev/mem. This might go
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 3289969..31cc248 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -23,7 +23,6 @@ config MIPS
select HAVE_KRETPROBES
select HAVE_DEBUG_KMEMLEAK
select HAVE_SYSCALL_TRACEPOINTS
- select ARCH_BINFMT_ELF_RANDOMIZE_PIE
select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES && 64BIT
select RTC_LIB if !MACH_LOONGSON
select GENERIC_ATOMIC64 if !64BIT
diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h
index eb4d95d..fcac4c99 100644
--- a/arch/mips/include/asm/elf.h
+++ b/arch/mips/include/asm/elf.h
@@ -402,7 +402,8 @@ extern const char *__elf_platform;
that it will "exec", and that there is sufficient room for the brk. */

#ifndef ELF_ET_DYN_BASE
-#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
+extern unsigned long randomize_et_dyn(unsigned long base);
+#define ELF_ET_DYN_BASE (randomize_et_dyn(TASK_SIZE / 3 * 2))
#endif

#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c
index f1baadd..20ad644 100644
--- a/arch/mips/mm/mmap.c
+++ b/arch/mips/mm/mmap.c
@@ -196,3 +196,13 @@ int __virt_addr_valid(const volatile void *kaddr)
return pfn_valid(PFN_DOWN(virt_to_phys(kaddr)));
}
EXPORT_SYMBOL_GPL(__virt_addr_valid);
+
+unsigned long randomize_et_dyn(unsigned long base)
+{
+ unsigned long ret;
+ if ((current->personality & ADDR_NO_RANDOMIZE) ||
+ !(current->flags & PF_RANDOMIZE))
+ return base;
+ ret = base + brk_rnd();
+ return (ret > base) ? ret : base;
+}
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index a2a168e..fa4c877 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -88,7 +88,6 @@ config PPC
select ARCH_MIGHT_HAVE_PC_PARPORT
select ARCH_MIGHT_HAVE_PC_SERIO
select BINFMT_ELF
- select ARCH_BINFMT_ELF_RANDOMIZE_PIE
select OF
select OF_EARLY_FLATTREE
select OF_RESERVED_MEM
diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h
index 57d289a..4080425 100644
--- a/arch/powerpc/include/asm/elf.h
+++ b/arch/powerpc/include/asm/elf.h
@@ -28,7 +28,8 @@
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. */

-#define ELF_ET_DYN_BASE 0x20000000
+extern unsigned long randomize_et_dyn(unsigned long base);
+#define ELF_ET_DYN_BASE (randomize_et_dyn(0x20000000))

#define ELF_CORE_EFLAGS (is_elf2_task() ? 2 : 0)

diff --git a/arch/powerpc/mm/mmap.c b/arch/powerpc/mm/mmap.c
index cb8bdbe..3e642e7 100644
--- a/arch/powerpc/mm/mmap.c
+++ b/arch/powerpc/mm/mmap.c
@@ -97,3 +97,13 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
}
}
+
+unsigned long randomize_et_dyn(unsigned long base)
+{
+ unsigned long ret;
+ if ((current->personality & ADDR_NO_RANDOMIZE) ||
+ !(current->flags & PF_RANDOMIZE))
+ return base;
+ ret = base + mmap_rnd();
+ return (ret > base) ? ret : base;
+}
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index ba397bd..dcfe16c 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -85,7 +85,6 @@ config X86
select HAVE_CMPXCHG_DOUBLE
select HAVE_ARCH_KMEMCHECK
select HAVE_USER_RETURN_NOTIFIER
- select ARCH_BINFMT_ELF_RANDOMIZE_PIE
select HAVE_ARCH_JUMP_LABEL
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select SPARSE_IRQ
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index ca3347a..92c6ac4 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -249,7 +249,8 @@ extern int force_personality32;
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. */

-#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
+extern unsigned long randomize_et_dyn(unsigned long base);
+#define ELF_ET_DYN_BASE (randomize_et_dyn(TASK_SIZE / 3 * 2))

/* This yields a mask that user programs can use to figure out what
instruction set this CPU supports. This could be done in user space,
diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c
index 919b912..7b86605 100644
--- a/arch/x86/mm/mmap.c
+++ b/arch/x86/mm/mmap.c
@@ -122,3 +122,12 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
}
}
+unsigned long randomize_et_dyn(unsigned long base)
+{
+ unsigned long ret;
+ if ((current->personality & ADDR_NO_RANDOMIZE) ||
+ !(current->flags & PF_RANDOMIZE))
+ return base;
+ ret = base + mmap_rnd();
+ return (ret > base) ? ret : base;
+}
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index c055d56..1186190 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -27,8 +27,6 @@ config COMPAT_BINFMT_ELF
bool
depends on COMPAT && BINFMT_ELF

-config ARCH_BINFMT_ELF_RANDOMIZE_PIE
- bool

config ARCH_BINFMT_ELF_STATE
bool
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 02b1691..72f7ff5 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -908,21 +908,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
* default mmap base, as well as whatever program they
* might try to exec. This is because the brk will
* follow the loader, and is not movable. */
-#ifdef CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE
- /* Memory randomization might have been switched off
- * in runtime via sysctl or explicit setting of
- * personality flags.
- * If that is the case, retain the original non-zero
- * load_bias value in order to establish proper
- * non-randomized mappings.
- */
- if (current->flags & PF_RANDOMIZE)
- load_bias = 0;
- else
- load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
-#else
load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
-#endif
}

error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,


2015-02-23 19:34:38

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS

(I've added some additional CCs to make sure the arch maintainers
notice this patch.)

This patch seems white-space damaged to me. I had to do a lot of
manual editing to get it to apply. Please use "git format-patch", if
you're not already. What version of the kernel was this based on?

On Mon, Feb 23, 2015 at 10:37 AM, Hector Marco <[email protected]> wrote:
> [PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS
>
> The issue appears on PIE linked executables when all memory areas of a
> process are randomized. In this case, the attack "offset2lib" de-randomizes
> all library areas on 64 bit Linux systems in less than one second.
>
>
> Further details of the PoC attack at:
> http://cybersecurity.upv.es/attacks/offset2lib/offset2lib.html
>
>
> This patch loads the PIE linked executable in a different area than the
> libraries. The successful fix can be tested with a simple pie compiled
> application:
>
>
> $ ./show_mmaps_pie
> 54859ccd6000-54859ccd7000 r-xp ... /tmp/show_mmaps_pie
> 54859ced6000-54859ced7000 r--p ... /tmp/show_mmaps_pie
> 54859ced7000-54859ced8000 rw-p ... /tmp/show_mmaps_pie
> 7f75be764000-7f75be91f000 r-xp ... /lib/x86_64-linux-gnu/libc.so.6
> 7f75be91f000-7f75beb1f000 ---p ... /lib/x86_64-linux-gnu/libc.so.6
> 7f75beb1f000-7f75beb23000 r--p ... /lib/x86_64-linux-gnu/libc.so.6
> 7f75beb23000-7f75beb25000 rw-p ... /lib/x86_64-linux-gnu/libc.so.6
> 7f75beb25000-7f75beb2a000 rw-p ...
> 7f75beb2a000-7f75beb4d000 r-xp ... /lib64/ld-linux-x86-64.so.2
> 7f75bed45000-7f75bed46000 rw-p ...
> 7f75bed46000-7f75bed47000 r-xp ...
> 7f75bed47000-7f75bed4c000 rw-p ...
> 7f75bed4c000-7f75bed4d000 r--p ... /lib64/ld-linux-x86-64.so.2
> 7f75bed4d000-7f75bed4e000 rw-p ... /lib64/ld-linux-x86-64.so.2
> 7f75bed4e000-7f75bed4f000 rw-p ...
> 7fffb3741000-7fffb3762000 rw-p ... [stack]
> 7fffb377b000-7fffb377d000 r--p ... [vvar]
> 7fffb377d000-7fffb377f000 r-xp ... [vdso]
>
>
> Once corrected, the PIE linked application is loaded in a different area.

Thanks for working on this!

>
> We updated the "Fixing Offset2lib weakness" page:
> http://cybersecurity.upv.es/solutions/aslrv2/aslrv2.html
>
>
> Signed-off-by: Hector Marco-Gisbert <[email protected]>
> Signed-off-by: Ismael Ripoll <[email protected]>

Acked-by: Kees Cook <[email protected]>

>
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 97d07ed..ee7ea7e 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1,7 +1,6 @@
> config ARM
> bool
> default y
> - select ARCH_BINFMT_ELF_RANDOMIZE_PIE
> select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
> select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
> select ARCH_HAVE_CUSTOM_GPIO_H
> diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
> index afb9caf..6755cd8 100644
> --- a/arch/arm/include/asm/elf.h
> +++ b/arch/arm/include/asm/elf.h
> @@ -115,7 +115,8 @@ int dump_task_regs(struct task_struct *t, elf_gregset_t
> *elfregs);
> the loader. We need to make sure that it is out of the way of the
> program
> that it will "exec", and that there is sufficient room for the brk. */
>
> -#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
> +extern unsigned long randomize_et_dyn(unsigned long base);
> +#define ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE / 3))
>
> /* When the program starts, a1 contains a pointer to a function to be
> registered with atexit, as per the SVR4 ABI. A value of 0 means we
> diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
> index 5e85ed3..9177100 100644
> --- a/arch/arm/mm/mmap.c
> +++ b/arch/arm/mm/mmap.c
> @@ -30,6 +30,17 @@ static int mmap_is_legacy(void)
> return sysctl_legacy_va_layout;
> }
>
> +static unsigned long mmap_rnd(void)
> +{
> + unsigned long rnd = 0;
> +
> + /* 8 bits of randomness in 20 address space bits */
> + if (current->flags & PF_RANDOMIZE)
> + rnd = (long)get_random_int() % (1 << 8);
> +
> + return rnd << PAGE_SHIFT;
> +}
> +
> static unsigned long mmap_base(unsigned long rnd)
> {
> unsigned long gap = rlimit(RLIMIT_STACK);
> @@ -230,3 +241,13 @@ int devmem_is_allowed(unsigned long pfn)
> }
>
> #endif
> +
> +unsigned long randomize_et_dyn(unsigned long base)
> +{
> + unsigned long ret;
> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> + !(current->flags & PF_RANDOMIZE))
> + return base;
> + ret = base + mmap_rnd();
> + return (ret > base) ? ret : base;
> +}
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index b1f9a20..5580d90 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -1,6 +1,5 @@
> config ARM64
> def_bool y
> - select ARCH_BINFMT_ELF_RANDOMIZE_PIE
> select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
> select ARCH_HAS_GCOV_PROFILE_ALL
> select ARCH_HAS_SG_CHAIN
> diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
> index 1f65be3..01d3aab 100644
> --- a/arch/arm64/include/asm/elf.h
> +++ b/arch/arm64/include/asm/elf.h
> @@ -126,7 +126,7 @@ typedef struct user_fpsimd_state elf_fpregset_t;
> * that it will "exec", and that there is sufficient room for the brk.
> */
> extern unsigned long randomize_et_dyn(unsigned long base);
> -#define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3)
> +#define ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE_64 / 3))
>
> /*
> * When the program starts, a1 contains a pointer to a function to be
> @@ -169,7 +169,7 @@ extern unsigned long arch_randomize_brk(struct mm_struct
> *mm);
> #define COMPAT_ELF_PLATFORM ("v8l")
> #endif
>
> -#define COMPAT_ELF_ET_DYN_BASE (2 * TASK_SIZE_32 / 3)
> +#define COMPAT_ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE_32 /
> 3))
>
> /* AArch32 registers. */
> #define COMPAT_ELF_NGREG 18
> diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c
> index 54922d1..980110c50 100644
> --- a/arch/arm64/mm/mmap.c
> +++ b/arch/arm64/mm/mmap.c
> @@ -89,6 +89,16 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
> }
> EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
>
> +unsigned long randomize_et_dyn(unsigned long base)
> +{
> + unsigned long ret;
> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> + !(current->flags & PF_RANDOMIZE))
> + return base;
> + ret = base + mmap_rnd();
> + return (ret > base) ? ret : base;
> +}
> +
>
> /*
> * You really shouldn't be using read() or write() on /dev/mem. This might
> go
> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
> index 3289969..31cc248 100644
> --- a/arch/mips/Kconfig
> +++ b/arch/mips/Kconfig
> @@ -23,7 +23,6 @@ config MIPS
> select HAVE_KRETPROBES
> select HAVE_DEBUG_KMEMLEAK
> select HAVE_SYSCALL_TRACEPOINTS
> - select ARCH_BINFMT_ELF_RANDOMIZE_PIE
> select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES &&
> 64BIT
> select RTC_LIB if !MACH_LOONGSON
> select GENERIC_ATOMIC64 if !64BIT
> diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h
> index eb4d95d..fcac4c99 100644
> --- a/arch/mips/include/asm/elf.h
> +++ b/arch/mips/include/asm/elf.h
> @@ -402,7 +402,8 @@ extern const char *__elf_platform;
> that it will "exec", and that there is sufficient room for the brk. */
>
> #ifndef ELF_ET_DYN_BASE
> -#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
> +extern unsigned long randomize_et_dyn(unsigned long base);
> +#define ELF_ET_DYN_BASE (randomize_et_dyn(TASK_SIZE / 3 *
> 2))
> #endif
>
> #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
> diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c
> index f1baadd..20ad644 100644
> --- a/arch/mips/mm/mmap.c
> +++ b/arch/mips/mm/mmap.c
> @@ -196,3 +196,13 @@ int __virt_addr_valid(const volatile void *kaddr)
> return pfn_valid(PFN_DOWN(virt_to_phys(kaddr)));
> }
> EXPORT_SYMBOL_GPL(__virt_addr_valid);
> +
> +unsigned long randomize_et_dyn(unsigned long base)
> +{
> + unsigned long ret;
> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> + !(current->flags & PF_RANDOMIZE))
> + return base;
> + ret = base + brk_rnd();
> + return (ret > base) ? ret : base;
> +}
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index a2a168e..fa4c877 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -88,7 +88,6 @@ config PPC
> select ARCH_MIGHT_HAVE_PC_PARPORT
> select ARCH_MIGHT_HAVE_PC_SERIO
> select BINFMT_ELF
> - select ARCH_BINFMT_ELF_RANDOMIZE_PIE
> select OF
> select OF_EARLY_FLATTREE
> select OF_RESERVED_MEM
> diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h
> index 57d289a..4080425 100644
> --- a/arch/powerpc/include/asm/elf.h
> +++ b/arch/powerpc/include/asm/elf.h
> @@ -28,7 +28,8 @@
> the loader. We need to make sure that it is out of the way of the
> program
> that it will "exec", and that there is sufficient room for the brk. */
>
> -#define ELF_ET_DYN_BASE 0x20000000
> +extern unsigned long randomize_et_dyn(unsigned long base);
> +#define ELF_ET_DYN_BASE (randomize_et_dyn(0x20000000))
>
> #define ELF_CORE_EFLAGS (is_elf2_task() ? 2 : 0)
>
> diff --git a/arch/powerpc/mm/mmap.c b/arch/powerpc/mm/mmap.c
> index cb8bdbe..3e642e7 100644
> --- a/arch/powerpc/mm/mmap.c
> +++ b/arch/powerpc/mm/mmap.c
> @@ -97,3 +97,13 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
> mm->get_unmapped_area = arch_get_unmapped_area_topdown;
> }
> }
> +
> +unsigned long randomize_et_dyn(unsigned long base)
> +{
> + unsigned long ret;
> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> + !(current->flags & PF_RANDOMIZE))
> + return base;
> + ret = base + mmap_rnd();
> + return (ret > base) ? ret : base;
> +}
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index ba397bd..dcfe16c 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -85,7 +85,6 @@ config X86
> select HAVE_CMPXCHG_DOUBLE
> select HAVE_ARCH_KMEMCHECK
> select HAVE_USER_RETURN_NOTIFIER
> - select ARCH_BINFMT_ELF_RANDOMIZE_PIE
> select HAVE_ARCH_JUMP_LABEL
> select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
> select SPARSE_IRQ
> diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
> index ca3347a..92c6ac4 100644
> --- a/arch/x86/include/asm/elf.h
> +++ b/arch/x86/include/asm/elf.h
> @@ -249,7 +249,8 @@ extern int force_personality32;
> the loader. We need to make sure that it is out of the way of the
> program
> that it will "exec", and that there is sufficient room for the brk. */
>
> -#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
> +extern unsigned long randomize_et_dyn(unsigned long base);
> +#define ELF_ET_DYN_BASE (randomize_et_dyn(TASK_SIZE / 3 *
> 2))
>
> /* This yields a mask that user programs can use to figure out what
> instruction set this CPU supports. This could be done in user space,
> diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c
> index 919b912..7b86605 100644
> --- a/arch/x86/mm/mmap.c
> +++ b/arch/x86/mm/mmap.c
> @@ -122,3 +122,12 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
> mm->get_unmapped_area = arch_get_unmapped_area_topdown;
> }
> }
> +unsigned long randomize_et_dyn(unsigned long base)
> +{
> + unsigned long ret;
> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> + !(current->flags & PF_RANDOMIZE))
> + return base;
> + ret = base + mmap_rnd();
> + return (ret > base) ? ret : base;
> +}
> diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
> index c055d56..1186190 100644
> --- a/fs/Kconfig.binfmt
> +++ b/fs/Kconfig.binfmt
> @@ -27,8 +27,6 @@ config COMPAT_BINFMT_ELF
> bool
> depends on COMPAT && BINFMT_ELF
>
> -config ARCH_BINFMT_ELF_RANDOMIZE_PIE
> - bool
>
> config ARCH_BINFMT_ELF_STATE
> bool
> diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
> index 02b1691..72f7ff5 100644
> --- a/fs/binfmt_elf.c
> +++ b/fs/binfmt_elf.c
> @@ -908,21 +908,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
> * default mmap base, as well as whatever program
> they
> * might try to exec. This is because the brk will
> * follow the loader, and is not movable. */
> -#ifdef CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE
> - /* Memory randomization might have been switched off
> - * in runtime via sysctl or explicit setting of
> - * personality flags.
> - * If that is the case, retain the original non-zero
> - * load_bias value in order to establish proper
> - * non-randomized mappings.
> - */
> - if (current->flags & PF_RANDOMIZE)
> - load_bias = 0;
> - else
> - load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE -
> vaddr);
> -#else
> load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
> -#endif
> }
>
> error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,

I think this is much cleaner now without
ARCH_BINFMT_ELF_RANDOMIZE_PIE. I imagine there could be some follow-up
cleanups to standardize (or at least clearly document) the intended
levels of entropy in the 4 ASLR regions on each architecture, as it
currently varies a bit.

Thanks!

-Kees

--
Kees Cook
Chrome OS Security

2015-02-23 19:55:47

by Hector Marco-Gisbert

[permalink] [raw]
Subject: Re: [PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS

[PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS

The issue appears on PIE linked executables when all memory areas of a
process are randomized. In this case, the attack "offset2lib" de-randomizes
all library areas on 64 bit Linux systems in less than one second.


Further details of the PoC attack at:
http://cybersecurity.upv.es/attacks/offset2lib/offset2lib.html


This patch loads the PIE linked executable in a different area than the
libraries. The successful fix can be tested with a simple pie compiled
application:


$ ./show_mmaps_pie
54859ccd6000-54859ccd7000 r-xp ... /tmp/show_mmaps_pie
54859ced6000-54859ced7000 r--p ... /tmp/show_mmaps_pie
54859ced7000-54859ced8000 rw-p ... /tmp/show_mmaps_pie
7f75be764000-7f75be91f000 r-xp ... /lib/x86_64-linux-gnu/libc.so.6
7f75be91f000-7f75beb1f000 ---p ... /lib/x86_64-linux-gnu/libc.so.6
7f75beb1f000-7f75beb23000 r--p ... /lib/x86_64-linux-gnu/libc.so.6
7f75beb23000-7f75beb25000 rw-p ... /lib/x86_64-linux-gnu/libc.so.6
7f75beb25000-7f75beb2a000 rw-p ...
7f75beb2a000-7f75beb4d000 r-xp ... /lib64/ld-linux-x86-64.so.2
7f75bed45000-7f75bed46000 rw-p ...
7f75bed46000-7f75bed47000 r-xp ...
7f75bed47000-7f75bed4c000 rw-p ...
7f75bed4c000-7f75bed4d000 r--p ... /lib64/ld-linux-x86-64.so.2
7f75bed4d000-7f75bed4e000 rw-p ... /lib64/ld-linux-x86-64.so.2
7f75bed4e000-7f75bed4f000 rw-p ...
7fffb3741000-7fffb3762000 rw-p ... [stack]
7fffb377b000-7fffb377d000 r--p ... [vvar]
7fffb377d000-7fffb377f000 r-xp ... [vdso]


Once corrected, the PIE linked application is loaded in a different area.

We updated the "Fixing Offset2lib weakness" page:
http://cybersecurity.upv.es/solutions/aslrv2/aslrv2.html


Signed-off-by: Hector Marco-Gisbert <[email protected]>
Signed-off-by: Ismael Ripoll <[email protected]>

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 97d07ed..ee7ea7e 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1,7 +1,6 @@
config ARM
bool
default y
- select ARCH_BINFMT_ELF_RANDOMIZE_PIE
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_HAVE_CUSTOM_GPIO_H
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index afb9caf..6755cd8 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -115,7 +115,8 @@ int dump_task_regs(struct task_struct *t,
elf_gregset_t *elfregs);
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. */

-#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
+extern unsigned long randomize_et_dyn(unsigned long base);
+#define ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE / 3))

/* When the program starts, a1 contains a pointer to a function to be
registered with atexit, as per the SVR4 ABI. A value of 0 means we
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index 5e85ed3..9177100 100644
--- a/arch/arm/mm/mmap.c
+++ b/arch/arm/mm/mmap.c
@@ -30,6 +30,17 @@ static int mmap_is_legacy(void)
return sysctl_legacy_va_layout;
}

+static unsigned long mmap_rnd(void)
+{
+ unsigned long rnd = 0;
+
+ /* 8 bits of randomness in 20 address space bits */
+ if (current->flags & PF_RANDOMIZE)
+ rnd = (long)get_random_int() % (1 << 8);
+
+ return rnd << PAGE_SHIFT;
+}
+
static unsigned long mmap_base(unsigned long rnd)
{
unsigned long gap = rlimit(RLIMIT_STACK);
@@ -230,3 +241,13 @@ int devmem_is_allowed(unsigned long pfn)
}

#endif
+
+unsigned long randomize_et_dyn(unsigned long base)
+{
+ unsigned long ret;
+ if ((current->personality & ADDR_NO_RANDOMIZE) ||
+ !(current->flags & PF_RANDOMIZE))
+ return base;
+ ret = base + mmap_rnd();
+ return (ret > base) ? ret : base;
+}
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b1f9a20..5580d90 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1,6 +1,5 @@
config ARM64
def_bool y
- select ARCH_BINFMT_ELF_RANDOMIZE_PIE
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_GCOV_PROFILE_ALL
select ARCH_HAS_SG_CHAIN
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index 1f65be3..01d3aab 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -126,7 +126,7 @@ typedef struct user_fpsimd_state elf_fpregset_t;
* that it will "exec", and that there is sufficient room for the brk.
*/
extern unsigned long randomize_et_dyn(unsigned long base);
-#define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3)
+#define ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE_64 / 3))

/*
* When the program starts, a1 contains a pointer to a function to be
@@ -169,7 +169,7 @@ extern unsigned long arch_randomize_brk(struct
mm_struct *mm);
#define COMPAT_ELF_PLATFORM ("v8l")
#endif

-#define COMPAT_ELF_ET_DYN_BASE (2 * TASK_SIZE_32 / 3)
+#define COMPAT_ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE_32 / 3))

/* AArch32 registers. */
#define COMPAT_ELF_NGREG 18
diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c
index 54922d1..980110c50 100644
--- a/arch/arm64/mm/mmap.c
+++ b/arch/arm64/mm/mmap.c
@@ -89,6 +89,16 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
}
EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);

+unsigned long randomize_et_dyn(unsigned long base)
+{
+ unsigned long ret;
+ if ((current->personality & ADDR_NO_RANDOMIZE) ||
+ !(current->flags & PF_RANDOMIZE))
+ return base;
+ ret = base + mmap_rnd();
+ return (ret > base) ? ret : base;
+}
+

/*
* You really shouldn't be using read() or write() on /dev/mem.
This might go
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 3289969..31cc248 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -23,7 +23,6 @@ config MIPS
select HAVE_KRETPROBES
select HAVE_DEBUG_KMEMLEAK
select HAVE_SYSCALL_TRACEPOINTS
- select ARCH_BINFMT_ELF_RANDOMIZE_PIE
select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES && 64BIT
select RTC_LIB if !MACH_LOONGSON
select GENERIC_ATOMIC64 if !64BIT
diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h
index eb4d95d..fcac4c99 100644
--- a/arch/mips/include/asm/elf.h
+++ b/arch/mips/include/asm/elf.h
@@ -402,7 +402,8 @@ extern const char *__elf_platform;
that it will "exec", and that there is sufficient room for the brk. */

#ifndef ELF_ET_DYN_BASE
-#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
+extern unsigned long randomize_et_dyn(unsigned long base);
+#define ELF_ET_DYN_BASE (randomize_et_dyn(TASK_SIZE / 3 * 2))
#endif

#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c
index f1baadd..20ad644 100644
--- a/arch/mips/mm/mmap.c
+++ b/arch/mips/mm/mmap.c
@@ -196,3 +196,13 @@ int __virt_addr_valid(const volatile void *kaddr)
return pfn_valid(PFN_DOWN(virt_to_phys(kaddr)));
}
EXPORT_SYMBOL_GPL(__virt_addr_valid);
+
+unsigned long randomize_et_dyn(unsigned long base)
+{
+ unsigned long ret;
+ if ((current->personality & ADDR_NO_RANDOMIZE) ||
+ !(current->flags & PF_RANDOMIZE))
+ return base;
+ ret = base + brk_rnd();
+ return (ret > base) ? ret : base;
+}
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index a2a168e..fa4c877 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -88,7 +88,6 @@ config PPC
select ARCH_MIGHT_HAVE_PC_PARPORT
select ARCH_MIGHT_HAVE_PC_SERIO
select BINFMT_ELF
- select ARCH_BINFMT_ELF_RANDOMIZE_PIE
select OF
select OF_EARLY_FLATTREE
select OF_RESERVED_MEM
diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h
index 57d289a..4080425 100644
--- a/arch/powerpc/include/asm/elf.h
+++ b/arch/powerpc/include/asm/elf.h
@@ -28,7 +28,8 @@
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. */

-#define ELF_ET_DYN_BASE 0x20000000
+extern unsigned long randomize_et_dyn(unsigned long base);
+#define ELF_ET_DYN_BASE (randomize_et_dyn(0x20000000))

#define ELF_CORE_EFLAGS (is_elf2_task() ? 2 : 0)

diff --git a/arch/powerpc/mm/mmap.c b/arch/powerpc/mm/mmap.c
index cb8bdbe..3e642e7 100644
--- a/arch/powerpc/mm/mmap.c
+++ b/arch/powerpc/mm/mmap.c
@@ -97,3 +97,13 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
}
}
+
+unsigned long randomize_et_dyn(unsigned long base)
+{
+ unsigned long ret;
+ if ((current->personality & ADDR_NO_RANDOMIZE) ||
+ !(current->flags & PF_RANDOMIZE))
+ return base;
+ ret = base + mmap_rnd();
+ return (ret > base) ? ret : base;
+}
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index ba397bd..dcfe16c 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -85,7 +85,6 @@ config X86
select HAVE_CMPXCHG_DOUBLE
select HAVE_ARCH_KMEMCHECK
select HAVE_USER_RETURN_NOTIFIER
- select ARCH_BINFMT_ELF_RANDOMIZE_PIE
select HAVE_ARCH_JUMP_LABEL
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select SPARSE_IRQ
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index ca3347a..92c6ac4 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -249,7 +249,8 @@ extern int force_personality32;
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. */

-#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
+extern unsigned long randomize_et_dyn(unsigned long base);
+#define ELF_ET_DYN_BASE (randomize_et_dyn(TASK_SIZE / 3 * 2))

/* This yields a mask that user programs can use to figure out what
instruction set this CPU supports. This could be done in user space,
diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c
index 919b912..7b86605 100644
--- a/arch/x86/mm/mmap.c
+++ b/arch/x86/mm/mmap.c
@@ -122,3 +122,12 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
}
}
+unsigned long randomize_et_dyn(unsigned long base)
+{
+ unsigned long ret;
+ if ((current->personality & ADDR_NO_RANDOMIZE) ||
+ !(current->flags & PF_RANDOMIZE))
+ return base;
+ ret = base + mmap_rnd();
+ return (ret > base) ? ret : base;
+}
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index c055d56..1186190 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -27,8 +27,6 @@ config COMPAT_BINFMT_ELF
bool
depends on COMPAT && BINFMT_ELF

-config ARCH_BINFMT_ELF_RANDOMIZE_PIE
- bool

config ARCH_BINFMT_ELF_STATE
bool
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 02b1691..72f7ff5 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -908,21 +908,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
* default mmap base, as well as whatever program they
* might try to exec. This is because the brk will
* follow the loader, and is not movable. */
-#ifdef CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE
- /* Memory randomization might have been switched off
- * in runtime via sysctl or explicit setting of
- * personality flags.
- * If that is the case, retain the original non-zero
- * load_bias value in order to establish proper
- * non-randomized mappings.
- */
- if (current->flags & PF_RANDOMIZE)
- load_bias = 0;
- else
- load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
-#else
load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
-#endif
}

error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,



Kees Cook <[email protected]> escribi?:

> (I've added some additional CCs to make sure the arch maintainers
> notice this patch.)
>
> This patch seems white-space damaged to me. I had to do a lot of
> manual editing to get it to apply. Please use "git format-patch", if
> you're not already. What version of the kernel was this based on?
>
> On Mon, Feb 23, 2015 at 10:37 AM, Hector Marco <[email protected]> wrote:
>> [PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS
>>
>> The issue appears on PIE linked executables when all memory areas of a
>> process are randomized. In this case, the attack "offset2lib" de-randomizes
>> all library areas on 64 bit Linux systems in less than one second.
>>
>>
>> Further details of the PoC attack at:
>> http://cybersecurity.upv.es/attacks/offset2lib/offset2lib.html
>>
>>
>> This patch loads the PIE linked executable in a different area than the
>> libraries. The successful fix can be tested with a simple pie compiled
>> application:
>>
>>
>> $ ./show_mmaps_pie
>> 54859ccd6000-54859ccd7000 r-xp ... /tmp/show_mmaps_pie
>> 54859ced6000-54859ced7000 r--p ... /tmp/show_mmaps_pie
>> 54859ced7000-54859ced8000 rw-p ... /tmp/show_mmaps_pie
>> 7f75be764000-7f75be91f000 r-xp ... /lib/x86_64-linux-gnu/libc.so.6
>> 7f75be91f000-7f75beb1f000 ---p ... /lib/x86_64-linux-gnu/libc.so.6
>> 7f75beb1f000-7f75beb23000 r--p ... /lib/x86_64-linux-gnu/libc.so.6
>> 7f75beb23000-7f75beb25000 rw-p ... /lib/x86_64-linux-gnu/libc.so.6
>> 7f75beb25000-7f75beb2a000 rw-p ...
>> 7f75beb2a000-7f75beb4d000 r-xp ... /lib64/ld-linux-x86-64.so.2
>> 7f75bed45000-7f75bed46000 rw-p ...
>> 7f75bed46000-7f75bed47000 r-xp ...
>> 7f75bed47000-7f75bed4c000 rw-p ...
>> 7f75bed4c000-7f75bed4d000 r--p ... /lib64/ld-linux-x86-64.so.2
>> 7f75bed4d000-7f75bed4e000 rw-p ... /lib64/ld-linux-x86-64.so.2
>> 7f75bed4e000-7f75bed4f000 rw-p ...
>> 7fffb3741000-7fffb3762000 rw-p ... [stack]
>> 7fffb377b000-7fffb377d000 r--p ... [vvar]
>> 7fffb377d000-7fffb377f000 r-xp ... [vdso]
>>
>>
>> Once corrected, the PIE linked application is loaded in a different area.
>
> Thanks for working on this!
>
>>
>> We updated the "Fixing Offset2lib weakness" page:
>> http://cybersecurity.upv.es/solutions/aslrv2/aslrv2.html
>>
>>
>> Signed-off-by: Hector Marco-Gisbert <[email protected]>
>> Signed-off-by: Ismael Ripoll <[email protected]>
>
> Acked-by: Kees Cook <[email protected]>
>
>>
>>
>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>> index 97d07ed..ee7ea7e 100644
>> --- a/arch/arm/Kconfig
>> +++ b/arch/arm/Kconfig
>> @@ -1,7 +1,6 @@
>> config ARM
>> bool
>> default y
>> - select ARCH_BINFMT_ELF_RANDOMIZE_PIE
>> select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
>> select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
>> select ARCH_HAVE_CUSTOM_GPIO_H
>> diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
>> index afb9caf..6755cd8 100644
>> --- a/arch/arm/include/asm/elf.h
>> +++ b/arch/arm/include/asm/elf.h
>> @@ -115,7 +115,8 @@ int dump_task_regs(struct task_struct *t, elf_gregset_t
>> *elfregs);
>> the loader. We need to make sure that it is out of the way of the
>> program
>> that it will "exec", and that there is sufficient room for the brk. */
>>
>> -#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
>> +extern unsigned long randomize_et_dyn(unsigned long base);
>> +#define ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE / 3))
>>
>> /* When the program starts, a1 contains a pointer to a function to be
>> registered with atexit, as per the SVR4 ABI. A value of 0 means we
>> diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
>> index 5e85ed3..9177100 100644
>> --- a/arch/arm/mm/mmap.c
>> +++ b/arch/arm/mm/mmap.c
>> @@ -30,6 +30,17 @@ static int mmap_is_legacy(void)
>> return sysctl_legacy_va_layout;
>> }
>>
>> +static unsigned long mmap_rnd(void)
>> +{
>> + unsigned long rnd = 0;
>> +
>> + /* 8 bits of randomness in 20 address space bits */
>> + if (current->flags & PF_RANDOMIZE)
>> + rnd = (long)get_random_int() % (1 << 8);
>> +
>> + return rnd << PAGE_SHIFT;
>> +}
>> +
>> static unsigned long mmap_base(unsigned long rnd)
>> {
>> unsigned long gap = rlimit(RLIMIT_STACK);
>> @@ -230,3 +241,13 @@ int devmem_is_allowed(unsigned long pfn)
>> }
>>
>> #endif
>> +
>> +unsigned long randomize_et_dyn(unsigned long base)
>> +{
>> + unsigned long ret;
>> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
>> + !(current->flags & PF_RANDOMIZE))
>> + return base;
>> + ret = base + mmap_rnd();
>> + return (ret > base) ? ret : base;
>> +}
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index b1f9a20..5580d90 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -1,6 +1,5 @@
>> config ARM64
>> def_bool y
>> - select ARCH_BINFMT_ELF_RANDOMIZE_PIE
>> select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
>> select ARCH_HAS_GCOV_PROFILE_ALL
>> select ARCH_HAS_SG_CHAIN
>> diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
>> index 1f65be3..01d3aab 100644
>> --- a/arch/arm64/include/asm/elf.h
>> +++ b/arch/arm64/include/asm/elf.h
>> @@ -126,7 +126,7 @@ typedef struct user_fpsimd_state elf_fpregset_t;
>> * that it will "exec", and that there is sufficient room for the brk.
>> */
>> extern unsigned long randomize_et_dyn(unsigned long base);
>> -#define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3)
>> +#define ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE_64 / 3))
>>
>> /*
>> * When the program starts, a1 contains a pointer to a function to be
>> @@ -169,7 +169,7 @@ extern unsigned long arch_randomize_brk(struct mm_struct
>> *mm);
>> #define COMPAT_ELF_PLATFORM ("v8l")
>> #endif
>>
>> -#define COMPAT_ELF_ET_DYN_BASE (2 * TASK_SIZE_32 / 3)
>> +#define COMPAT_ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE_32 /
>> 3))
>>
>> /* AArch32 registers. */
>> #define COMPAT_ELF_NGREG 18
>> diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c
>> index 54922d1..980110c50 100644
>> --- a/arch/arm64/mm/mmap.c
>> +++ b/arch/arm64/mm/mmap.c
>> @@ -89,6 +89,16 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
>> }
>> EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
>>
>> +unsigned long randomize_et_dyn(unsigned long base)
>> +{
>> + unsigned long ret;
>> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
>> + !(current->flags & PF_RANDOMIZE))
>> + return base;
>> + ret = base + mmap_rnd();
>> + return (ret > base) ? ret : base;
>> +}
>> +
>>
>> /*
>> * You really shouldn't be using read() or write() on /dev/mem. This might
>> go
>> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
>> index 3289969..31cc248 100644
>> --- a/arch/mips/Kconfig
>> +++ b/arch/mips/Kconfig
>> @@ -23,7 +23,6 @@ config MIPS
>> select HAVE_KRETPROBES
>> select HAVE_DEBUG_KMEMLEAK
>> select HAVE_SYSCALL_TRACEPOINTS
>> - select ARCH_BINFMT_ELF_RANDOMIZE_PIE
>> select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES &&
>> 64BIT
>> select RTC_LIB if !MACH_LOONGSON
>> select GENERIC_ATOMIC64 if !64BIT
>> diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h
>> index eb4d95d..fcac4c99 100644
>> --- a/arch/mips/include/asm/elf.h
>> +++ b/arch/mips/include/asm/elf.h
>> @@ -402,7 +402,8 @@ extern const char *__elf_platform;
>> that it will "exec", and that there is sufficient room for the brk. */
>>
>> #ifndef ELF_ET_DYN_BASE
>> -#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
>> +extern unsigned long randomize_et_dyn(unsigned long base);
>> +#define ELF_ET_DYN_BASE (randomize_et_dyn(TASK_SIZE / 3 *
>> 2))
>> #endif
>>
>> #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
>> diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c
>> index f1baadd..20ad644 100644
>> --- a/arch/mips/mm/mmap.c
>> +++ b/arch/mips/mm/mmap.c
>> @@ -196,3 +196,13 @@ int __virt_addr_valid(const volatile void *kaddr)
>> return pfn_valid(PFN_DOWN(virt_to_phys(kaddr)));
>> }
>> EXPORT_SYMBOL_GPL(__virt_addr_valid);
>> +
>> +unsigned long randomize_et_dyn(unsigned long base)
>> +{
>> + unsigned long ret;
>> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
>> + !(current->flags & PF_RANDOMIZE))
>> + return base;
>> + ret = base + brk_rnd();
>> + return (ret > base) ? ret : base;
>> +}
>> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
>> index a2a168e..fa4c877 100644
>> --- a/arch/powerpc/Kconfig
>> +++ b/arch/powerpc/Kconfig
>> @@ -88,7 +88,6 @@ config PPC
>> select ARCH_MIGHT_HAVE_PC_PARPORT
>> select ARCH_MIGHT_HAVE_PC_SERIO
>> select BINFMT_ELF
>> - select ARCH_BINFMT_ELF_RANDOMIZE_PIE
>> select OF
>> select OF_EARLY_FLATTREE
>> select OF_RESERVED_MEM
>> diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h
>> index 57d289a..4080425 100644
>> --- a/arch/powerpc/include/asm/elf.h
>> +++ b/arch/powerpc/include/asm/elf.h
>> @@ -28,7 +28,8 @@
>> the loader. We need to make sure that it is out of the way of the
>> program
>> that it will "exec", and that there is sufficient room for the brk. */
>>
>> -#define ELF_ET_DYN_BASE 0x20000000
>> +extern unsigned long randomize_et_dyn(unsigned long base);
>> +#define ELF_ET_DYN_BASE (randomize_et_dyn(0x20000000))
>>
>> #define ELF_CORE_EFLAGS (is_elf2_task() ? 2 : 0)
>>
>> diff --git a/arch/powerpc/mm/mmap.c b/arch/powerpc/mm/mmap.c
>> index cb8bdbe..3e642e7 100644
>> --- a/arch/powerpc/mm/mmap.c
>> +++ b/arch/powerpc/mm/mmap.c
>> @@ -97,3 +97,13 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
>> mm->get_unmapped_area = arch_get_unmapped_area_topdown;
>> }
>> }
>> +
>> +unsigned long randomize_et_dyn(unsigned long base)
>> +{
>> + unsigned long ret;
>> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
>> + !(current->flags & PF_RANDOMIZE))
>> + return base;
>> + ret = base + mmap_rnd();
>> + return (ret > base) ? ret : base;
>> +}
>> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
>> index ba397bd..dcfe16c 100644
>> --- a/arch/x86/Kconfig
>> +++ b/arch/x86/Kconfig
>> @@ -85,7 +85,6 @@ config X86
>> select HAVE_CMPXCHG_DOUBLE
>> select HAVE_ARCH_KMEMCHECK
>> select HAVE_USER_RETURN_NOTIFIER
>> - select ARCH_BINFMT_ELF_RANDOMIZE_PIE
>> select HAVE_ARCH_JUMP_LABEL
>> select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
>> select SPARSE_IRQ
>> diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
>> index ca3347a..92c6ac4 100644
>> --- a/arch/x86/include/asm/elf.h
>> +++ b/arch/x86/include/asm/elf.h
>> @@ -249,7 +249,8 @@ extern int force_personality32;
>> the loader. We need to make sure that it is out of the way of the
>> program
>> that it will "exec", and that there is sufficient room for the brk. */
>>
>> -#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
>> +extern unsigned long randomize_et_dyn(unsigned long base);
>> +#define ELF_ET_DYN_BASE (randomize_et_dyn(TASK_SIZE / 3 *
>> 2))
>>
>> /* This yields a mask that user programs can use to figure out what
>> instruction set this CPU supports. This could be done in user space,
>> diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c
>> index 919b912..7b86605 100644
>> --- a/arch/x86/mm/mmap.c
>> +++ b/arch/x86/mm/mmap.c
>> @@ -122,3 +122,12 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
>> mm->get_unmapped_area = arch_get_unmapped_area_topdown;
>> }
>> }
>> +unsigned long randomize_et_dyn(unsigned long base)
>> +{
>> + unsigned long ret;
>> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
>> + !(current->flags & PF_RANDOMIZE))
>> + return base;
>> + ret = base + mmap_rnd();
>> + return (ret > base) ? ret : base;
>> +}
>> diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
>> index c055d56..1186190 100644
>> --- a/fs/Kconfig.binfmt
>> +++ b/fs/Kconfig.binfmt
>> @@ -27,8 +27,6 @@ config COMPAT_BINFMT_ELF
>> bool
>> depends on COMPAT && BINFMT_ELF
>>
>> -config ARCH_BINFMT_ELF_RANDOMIZE_PIE
>> - bool
>>
>> config ARCH_BINFMT_ELF_STATE
>> bool
>> diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
>> index 02b1691..72f7ff5 100644
>> --- a/fs/binfmt_elf.c
>> +++ b/fs/binfmt_elf.c
>> @@ -908,21 +908,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
>> * default mmap base, as well as whatever program
>> they
>> * might try to exec. This is because the brk will
>> * follow the loader, and is not movable. */
>> -#ifdef CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE
>> - /* Memory randomization might have been switched off
>> - * in runtime via sysctl or explicit setting of
>> - * personality flags.
>> - * If that is the case, retain the original non-zero
>> - * load_bias value in order to establish proper
>> - * non-randomized mappings.
>> - */
>> - if (current->flags & PF_RANDOMIZE)
>> - load_bias = 0;
>> - else
>> - load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE -
>> vaddr);
>> -#else
>> load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
>> -#endif
>> }
>>
>> error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
>
> I think this is much cleaner now without
> ARCH_BINFMT_ELF_RANDOMIZE_PIE. I imagine there could be some follow-up
> cleanups to standardize (or at least clearly document) the intended
> levels of entropy in the 4 ASLR regions on each architecture, as it
> currently varies a bit.
>
> Thanks!
>
> -Kees
>
> --
> Kees Cook
> Chrome OS Security
>


2015-02-24 07:39:12

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS


* Hector Marco Gisbert <[email protected]> wrote:

> +unsigned long randomize_et_dyn(unsigned long base)
> +{
> + unsigned long ret;
> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> + !(current->flags & PF_RANDOMIZE))
> + return base;
> + ret = base + mmap_rnd();
> + return (ret > base) ? ret : base;
> +}

> +unsigned long randomize_et_dyn(unsigned long base)
> +{
> + unsigned long ret;
> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> + !(current->flags & PF_RANDOMIZE))
> + return base;
> + ret = base + mmap_rnd();
> + return (ret > base) ? ret : base;
> +}

> +unsigned long randomize_et_dyn(unsigned long base)
> +{
> + unsigned long ret;
> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> + !(current->flags & PF_RANDOMIZE))
> + return base;
> + ret = base + brk_rnd();
> + return (ret > base) ? ret : base;
> +}

> +unsigned long randomize_et_dyn(unsigned long base)
> +{
> + unsigned long ret;
> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> + !(current->flags & PF_RANDOMIZE))
> + return base;
> + ret = base + mmap_rnd();
> + return (ret > base) ? ret : base;
> +}

> +unsigned long randomize_et_dyn(unsigned long base)
> +{
> + unsigned long ret;
> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> + !(current->flags & PF_RANDOMIZE))
> + return base;
> + ret = base + mmap_rnd();
> + return (ret > base) ? ret : base;
> +}

That pointless repetition should be avoided.

Thanks,

Ingo

2015-02-26 22:38:19

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS

On Tue, 24 Feb 2015 08:39:06 +0100 Ingo Molnar <[email protected]> wrote:

>
> * Hector Marco Gisbert <[email protected]> wrote:
>
> > +unsigned long randomize_et_dyn(unsigned long base)
> > +{
> > + unsigned long ret;
> > + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> > + !(current->flags & PF_RANDOMIZE))
> > + return base;
> > + ret = base + mmap_rnd();
> > + return (ret > base) ? ret : base;
> > +}
>
> > +unsigned long randomize_et_dyn(unsigned long base)
> > +{
> > + unsigned long ret;
> > + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> > + !(current->flags & PF_RANDOMIZE))
> > + return base;
> > + ret = base + mmap_rnd();
> > + return (ret > base) ? ret : base;
> > +}
>
> > +unsigned long randomize_et_dyn(unsigned long base)
> > +{
> > + unsigned long ret;
> > + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> > + !(current->flags & PF_RANDOMIZE))
> > + return base;
> > + ret = base + brk_rnd();
> > + return (ret > base) ? ret : base;
> > +}
>
> > +unsigned long randomize_et_dyn(unsigned long base)
> > +{
> > + unsigned long ret;
> > + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> > + !(current->flags & PF_RANDOMIZE))
> > + return base;
> > + ret = base + mmap_rnd();
> > + return (ret > base) ? ret : base;
> > +}
>
> > +unsigned long randomize_et_dyn(unsigned long base)
> > +{
> > + unsigned long ret;
> > + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> > + !(current->flags & PF_RANDOMIZE))
> > + return base;
> > + ret = base + mmap_rnd();
> > + return (ret > base) ? ret : base;
> > +}
>
> That pointless repetition should be avoided.

That's surprisingly hard!

After renaming mips brk_rnd() to mmap_rnd() I had a shot. I'm not very
confident in the result. Does that __weak trick even work?

Someone tell me how important Hector's patch is?


From: Andrew Morton <[email protected]>
Subject: fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix

Consolidate randomize_et_dyn() implementations into fs/binfmt_elf.c.

There doesn't seem to be a compile-time way of making randomize_et_dyn()
go away on architectures which don't need it, so mark it __weak to cause
it to be discarded at link time.

Cc: "H. Peter Anvin" <[email protected]>
Cc: Benjamin Herrenschmidt <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Hector Marco Gisbert <[email protected]>
Cc: Hector Marco-Gisbert <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Ismael Ripoll <[email protected]>
Cc: Kees Cook <[email protected]>
Cc: Ralf Baechle <[email protected]>
Cc: Russell King <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Will Deacon <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
---

arch/arm/include/asm/elf.h | 3 +--
arch/arm/mm/mmap.c | 13 ++-----------
arch/arm64/Kconfig | 2 +-
arch/arm64/include/asm/elf.h | 3 +--
arch/arm64/mm/mmap.c | 14 ++------------
arch/mips/include/asm/elf.h | 1 -
arch/mips/mm/mmap.c | 13 ++-----------
arch/powerpc/include/asm/elf.h | 2 --
arch/powerpc/mm/mmap.c | 13 ++-----------
arch/x86/include/asm/elf.h | 2 --
arch/x86/mm/mmap.c | 12 ++----------
fs/binfmt_elf.c | 21 +++++++++++++++++++++
include/linux/elf-randomization.h | 7 +++++++
13 files changed, 41 insertions(+), 65 deletions(-)

diff -puN arch/arm/Kconfig~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/arm/Kconfig
diff -puN arch/arm/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/arm/include/asm/elf.h
--- a/arch/arm/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
+++ a/arch/arm/include/asm/elf.h
@@ -2,7 +2,7 @@
#define __ASMARM_ELF_H

#include <asm/hwcap.h>
-
+#include <linux/elf-randomization.h>
/*
* ELF register definitions..
*/
@@ -115,7 +115,6 @@ int dump_task_regs(struct task_struct *t
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. */

-extern unsigned long randomize_et_dyn(unsigned long base);
#define ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE / 3))

/* When the program starts, a1 contains a pointer to a function to be
diff -puN arch/arm/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/arm/mm/mmap.c
--- a/arch/arm/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
+++ a/arch/arm/mm/mmap.c
@@ -7,6 +7,7 @@
#include <linux/shm.h>
#include <linux/sched.h>
#include <linux/io.h>
+#include <linux/elf-randomization.h>
#include <linux/personality.h>
#include <linux/random.h>
#include <asm/cachetype.h>
@@ -30,7 +31,7 @@ static int mmap_is_legacy(void)
return sysctl_legacy_va_layout;
}

-static unsigned long mmap_rnd(void)
+unsigned long mmap_rnd(void)
{
unsigned long rnd = 0;

@@ -241,13 +242,3 @@ int devmem_is_allowed(unsigned long pfn)
}

#endif
-
-unsigned long randomize_et_dyn(unsigned long base)
-{
- unsigned long ret;
- if ((current->personality & ADDR_NO_RANDOMIZE) ||
- !(current->flags & PF_RANDOMIZE))
- return base;
- ret = base + mmap_rnd();
- return (ret > base) ? ret : base;
-}
diff -puN arch/arm64/Kconfig~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/arm64/Kconfig
--- a/arch/arm64/Kconfig~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
+++ a/arch/arm64/Kconfig
@@ -1,4 +1,4 @@
-config ARM64
+qconfig ARM64
def_bool y
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_GCOV_PROFILE_ALL
diff -puN arch/arm64/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/arm64/include/asm/elf.h
--- a/arch/arm64/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
+++ a/arch/arm64/include/asm/elf.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 ARM Ltd.
+ * Copyright (C) 20q12 ARM Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -125,7 +125,6 @@ typedef struct user_fpsimd_state elf_fpr
* the loader. We need to make sure that it is out of the way of the program
* that it will "exec", and that there is sufficient room for the brk.
*/
-extern unsigned long randomize_et_dyn(unsigned long base);
#define ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE_64 / 3))

/*
diff -puN arch/arm64/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/arm64/mm/mmap.c
--- a/arch/arm64/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
+++ a/arch/arm64/mm/mmap.c
@@ -17,6 +17,7 @@
*/

#include <linux/elf.h>
+#include <linux/elf-randomization.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/mman.h>
@@ -47,7 +48,7 @@ static int mmap_is_legacy(void)
return sysctl_legacy_va_layout;
}

-static unsigned long mmap_rnd(void)
+unsigned long mmap_rnd(void)
{
unsigned long rnd = 0;

@@ -89,17 +90,6 @@ void arch_pick_mmap_layout(struct mm_str
}
EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);

-unsigned long randomize_et_dyn(unsigned long base)
-{
- unsigned long ret;
- if ((current->personality & ADDR_NO_RANDOMIZE) ||
- !(current->flags & PF_RANDOMIZE))
- return base;
- ret = base + mmap_rnd();
- return (ret > base) ? ret : base;
-}
-
-
/*
* You really shouldn't be using read() or write() on /dev/mem. This might go
* away in the future.
diff -puN arch/mips/Kconfig~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/mips/Kconfig
diff -puN arch/mips/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/mips/include/asm/elf.h
--- a/arch/mips/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
+++ a/arch/mips/include/asm/elf.h
@@ -402,7 +402,6 @@ extern const char *__elf_platform;
that it will "exec", and that there is sufficient room for the brk. */

#ifndef ELF_ET_DYN_BASE
-extern unsigned long randomize_et_dyn(unsigned long base);
#define ELF_ET_DYN_BASE (randomize_et_dyn(TASK_SIZE / 3 * 2))
#endif

diff -puN arch/mips/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/mips/mm/mmap.c
--- a/arch/mips/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
+++ a/arch/mips/mm/mmap.c
@@ -9,6 +9,7 @@
#include <linux/compiler.h>
#include <linux/errno.h>
#include <linux/mm.h>
+#include <linux/elf-randomization.h>
#include <linux/mman.h>
#include <linux/module.h>
#include <linux/personality.h>
@@ -164,7 +165,7 @@ void arch_pick_mmap_layout(struct mm_str
}
}

-static inline unsigned long mmap_rnd(void)
+unsigned long mmap_rnd(void)
{
unsigned long rnd = get_random_int();

@@ -196,13 +197,3 @@ int __virt_addr_valid(const volatile voi
return pfn_valid(PFN_DOWN(virt_to_phys(kaddr)));
}
EXPORT_SYMBOL_GPL(__virt_addr_valid);
-
-unsigned long randomize_et_dyn(unsigned long base)
-{
- unsigned long ret;
- if ((current->personality & ADDR_NO_RANDOMIZE) ||
- !(current->flags & PF_RANDOMIZE))
- return base;
- ret = base + brk_rnd();
- return (ret > base) ? ret : base;
-}
diff -puN arch/powerpc/Kconfig~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/powerpc/Kconfig
diff -puN arch/powerpc/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/powerpc/include/asm/elf.h
--- a/arch/powerpc/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
+++ a/arch/powerpc/include/asm/elf.h
@@ -27,8 +27,6 @@
use of this is to invoke "./ld.so someprog" to test out a new version of
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. */
-
-extern unsigned long randomize_et_dyn(unsigned long base);
#define ELF_ET_DYN_BASE (randomize_et_dyn(0x20000000))

#define ELF_CORE_EFLAGS (is_elf2_task() ? 2 : 0)
diff -puN arch/powerpc/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/powerpc/mm/mmap.c
--- a/arch/powerpc/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
+++ a/arch/powerpc/mm/mmap.c
@@ -24,6 +24,7 @@

#include <linux/personality.h>
#include <linux/mm.h>
+#include <linux/elf-randomization.h>
#include <linux/random.h>
#include <linux/sched.h>

@@ -53,7 +54,7 @@ static inline int mmap_is_legacy(void)
return sysctl_legacy_va_layout;
}

-static unsigned long mmap_rnd(void)
+unsigned long mmap_rnd(void)
{
unsigned long rnd = 0;

@@ -97,13 +98,3 @@ void arch_pick_mmap_layout(struct mm_str
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
}
}
-
-unsigned long randomize_et_dyn(unsigned long base)
-{
- unsigned long ret;
- if ((current->personality & ADDR_NO_RANDOMIZE) ||
- !(current->flags & PF_RANDOMIZE))
- return base;
- ret = base + mmap_rnd();
- return (ret > base) ? ret : base;
-}
diff -puN arch/x86/Kconfig~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/x86/Kconfig
diff -puN arch/x86/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/x86/include/asm/elf.h
--- a/arch/x86/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
+++ a/arch/x86/include/asm/elf.h
@@ -248,8 +248,6 @@ extern int force_personality32;
use of this is to invoke "./ld.so someprog" to test out a new version of
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. */
-
-extern unsigned long randomize_et_dyn(unsigned long base);
#define ELF_ET_DYN_BASE (randomize_et_dyn(TASK_SIZE / 3 * 2))

/* This yields a mask that user programs can use to figure out what
diff -puN arch/x86/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/x86/mm/mmap.c
--- a/arch/x86/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
+++ a/arch/x86/mm/mmap.c
@@ -29,6 +29,7 @@
#include <linux/random.h>
#include <linux/limits.h>
#include <linux/sched.h>
+#include <linux/elf-randomization.h>
#include <asm/elf.h>

struct va_alignment __read_mostly va_align = {
@@ -65,7 +66,7 @@ static int mmap_is_legacy(void)
return sysctl_legacy_va_layout;
}

-static unsigned long mmap_rnd(void)
+unsigned long mmap_rnd(void)
{
unsigned long rnd = 0;

@@ -122,12 +123,3 @@ void arch_pick_mmap_layout(struct mm_str
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
}
}
-unsigned long randomize_et_dyn(unsigned long base)
-{
- unsigned long ret;
- if ((current->personality & ADDR_NO_RANDOMIZE) ||
- !(current->flags & PF_RANDOMIZE))
- return base;
- ret = base + mmap_rnd();
- return (ret > base) ? ret : base;
-}
diff -puN fs/Kconfig.binfmt~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix fs/Kconfig.binfmt
diff -puN fs/binfmt_elf.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix fs/binfmt_elf.c
--- a/fs/binfmt_elf.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
+++ a/fs/binfmt_elf.c
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/personality.h>
#include <linux/elfcore.h>
+#include <linux/elf-randomization.h>
#include <linux/init.h>
#include <linux/highuid.h>
#include <linux/compiler.h>
@@ -2300,6 +2301,26 @@ out:

#endif /* CONFIG_ELF_CORE */

+/* Not all architectures implement mmap_rnd() */
+unsigned long __weak mmap_rnd(void)
+{
+}
+
+/*
+ * Not all architectures use randomize_et_dyn(), so use __weak to let the
+ * linker omit it from vmlinux
+ */
+unsigned long __weak randomize_et_dyn(unsigned long base)
+{
+ unsigned long ret;
+
+ if ((current->personality & ADDR_NO_RANDOMIZE) ||
+ !(current->flags & PF_RANDOMIZE))
+ return base;
+ ret = base + mmap_rnd();
+ return max(ret, base);
+}
+
static int __init init_elf_binfmt(void)
{
register_binfmt(&elf_format);
diff -puN include/linux/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix include/linux/elf.h
diff -puN /dev/null include/linux/elf-randomization.h
--- /dev/null
+++ a/include/linux/elf-randomization.h
@@ -0,0 +1,7 @@
+#ifndef __ELF_RANDOMIZATION_H
+#define __ELF_RANDOMIZATION_H
+
+unsigned long randomize_et_dyn(unsigned long base);
+unsigned long mmap_rnd(void);
+
+#endif /* __ELF_RANDOMIZATION_H */
_

2015-02-26 22:43:28

by David Daney

[permalink] [raw]
Subject: Re: [PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS

On 02/26/2015 02:38 PM, Andrew Morton wrote:
[...]
>
> From: Andrew Morton<[email protected]>
> Subject: fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
>
> Consolidate randomize_et_dyn() implementations into fs/binfmt_elf.c.
>
> There doesn't seem to be a compile-time way of making randomize_et_dyn()
> go away on architectures which don't need it, so mark it __weak to cause
> it to be discarded at link time.
>
> Cc: "H. Peter Anvin"<[email protected]>
> Cc: Benjamin Herrenschmidt<[email protected]>
> Cc: Catalin Marinas<[email protected]>
> Cc: Hector Marco Gisbert<[email protected]>
> Cc: Hector Marco-Gisbert<[email protected]>
> Cc: Ingo Molnar<[email protected]>
> Cc: Ismael Ripoll<[email protected]>
> Cc: Kees Cook<[email protected]>
> Cc: Ralf Baechle<[email protected]>
> Cc: Russell King<[email protected]>
> Cc: Thomas Gleixner<[email protected]>
> Cc: Will Deacon<[email protected]>
> Signed-off-by: Andrew Morton<[email protected]>
[...]
> diff -puN arch/arm64/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/arm64/include/asm/elf.h
> --- a/arch/arm64/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
> +++ a/arch/arm64/include/asm/elf.h
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (C) 2012 ARM Ltd.
> + * Copyright (C) 20q12 ARM Ltd.

This particular change looks like it may be a typo.

> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License version 2 as

2015-02-26 23:01:12

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS

On Thu, Feb 26, 2015 at 02:38:15PM -0800, Andrew Morton wrote:
> diff -puN arch/arm64/Kconfig~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/arm64/Kconfig
> --- a/arch/arm64/Kconfig~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
> +++ a/arch/arm64/Kconfig
> @@ -1,4 +1,4 @@
> -config ARM64
> +qconfig ARM64

Is this a typo?

--
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

2015-02-26 23:04:00

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS

On Thu, 26 Feb 2015 14:38:15 -0800 Andrew Morton <[email protected]> wrote:

> Does that __weak trick even work?

Nope.

--- a/fs/binfmt_elf.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix-fix
+++ a/fs/binfmt_elf.c
@@ -2307,10 +2307,10 @@ unsigned long __weak mmap_rnd(void)
}

/*
- * Not all architectures use randomize_et_dyn(), so use __weak to let the
- * linker omit it from vmlinux
+ * Not all architectures use randomize_et_dyn(), but there doesn't seem to be
+ * a compile-time way of avoiding its generation.
*/
-unsigned long __weak randomize_et_dyn(unsigned long base)
+unsigned long randomize_et_dyn(unsigned long base)
{
unsigned long ret;

_

2015-02-26 23:05:25

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS

On Thu, 26 Feb 2015 23:00:52 +0000 Russell King - ARM Linux <[email protected]> wrote:

> On Thu, Feb 26, 2015 at 02:38:15PM -0800, Andrew Morton wrote:
> > diff -puN arch/arm64/Kconfig~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/arm64/Kconfig
> > --- a/arch/arm64/Kconfig~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
> > +++ a/arch/arm64/Kconfig
> > @@ -1,4 +1,4 @@
> > -config ARM64
> > +qconfig ARM64
>
> Is this a typo?

yup. But the coffee's nice and strong.

2015-02-26 23:26:53

by Stephen Rothwell

[permalink] [raw]
Subject: Re: [PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS

Hi Andrew,

[Just resending to correct addresses - sorry for those who get a duplicate]

On Thu, 26 Feb 2015 14:38:15 -0800 Andrew Morton <[email protected]> wrote:
>
> diff -puN fs/binfmt_elf.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix fs/binfmt_elf.c
> --- a/fs/binfmt_elf.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
> +++ a/fs/binfmt_elf.c
> @@ -22,6 +22,7 @@
> #include <linux/slab.h>
> #include <linux/personality.h>
> #include <linux/elfcore.h>
> +#include <linux/elf-randomization.h>
> #include <linux/init.h>
> #include <linux/highuid.h>
> #include <linux/compiler.h>
> @@ -2300,6 +2301,26 @@ out:
>
> #endif /* CONFIG_ELF_CORE */
>
> +/* Not all architectures implement mmap_rnd() */
> +unsigned long __weak mmap_rnd(void)
> +{
> +}
> +
> +/*
> + * Not all architectures use randomize_et_dyn(), so use __weak to let the
> + * linker omit it from vmlinux
> + */
> +unsigned long __weak randomize_et_dyn(unsigned long base)
> +{
> + unsigned long ret;
> +
> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> + !(current->flags & PF_RANDOMIZE))
> + return base;
> + ret = base + mmap_rnd();
> + return max(ret, base);
> +}
> +

Didn't we have some trouble with some compilers when the weak function
(mmap_rnd) was defined and used in the same file i.e. the wrong one was
used?

--
Cheers,
Stephen Rothwell [email protected]


Attachments:
(No filename) (819.00 B)
OpenPGP digital signature

2015-02-26 23:34:38

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS

On Thu, Feb 26, 2015 at 2:38 PM, Andrew Morton
<[email protected]> wrote:
> On Tue, 24 Feb 2015 08:39:06 +0100 Ingo Molnar <[email protected]> wrote:
>
>>
>> * Hector Marco Gisbert <[email protected]> wrote:
>>
>> > +unsigned long randomize_et_dyn(unsigned long base)
>> > +{
>> > + unsigned long ret;
>> > + if ((current->personality & ADDR_NO_RANDOMIZE) ||
>> > + !(current->flags & PF_RANDOMIZE))
>> > + return base;
>> > + ret = base + mmap_rnd();
>> > + return (ret > base) ? ret : base;
>> > +}
>>
>> > +unsigned long randomize_et_dyn(unsigned long base)
>> > +{
>> > + unsigned long ret;
>> > + if ((current->personality & ADDR_NO_RANDOMIZE) ||
>> > + !(current->flags & PF_RANDOMIZE))
>> > + return base;
>> > + ret = base + mmap_rnd();
>> > + return (ret > base) ? ret : base;
>> > +}
>>
>> > +unsigned long randomize_et_dyn(unsigned long base)
>> > +{
>> > + unsigned long ret;
>> > + if ((current->personality & ADDR_NO_RANDOMIZE) ||
>> > + !(current->flags & PF_RANDOMIZE))
>> > + return base;
>> > + ret = base + brk_rnd();
>> > + return (ret > base) ? ret : base;
>> > +}
>>
>> > +unsigned long randomize_et_dyn(unsigned long base)
>> > +{
>> > + unsigned long ret;
>> > + if ((current->personality & ADDR_NO_RANDOMIZE) ||
>> > + !(current->flags & PF_RANDOMIZE))
>> > + return base;
>> > + ret = base + mmap_rnd();
>> > + return (ret > base) ? ret : base;
>> > +}
>>
>> > +unsigned long randomize_et_dyn(unsigned long base)
>> > +{
>> > + unsigned long ret;
>> > + if ((current->personality & ADDR_NO_RANDOMIZE) ||
>> > + !(current->flags & PF_RANDOMIZE))
>> > + return base;
>> > + ret = base + mmap_rnd();
>> > + return (ret > base) ? ret : base;
>> > +}
>>
>> That pointless repetition should be avoided.
>
> That's surprisingly hard!
>
> After renaming mips brk_rnd() to mmap_rnd() I had a shot. I'm not very
> confident in the result. Does that __weak trick even work?

In theory, it shouldn't be needed since only randomize_et_dyn will
call mmap_rnd, and only architectures that use randomize_et_dyn will
call it ... and will define mmap_rnd.

>
> Someone tell me how important Hector's patch is?

I consider it a reasonable improvement to userspace ASLR. I look at it
more as a new feature than a bug fix, but it could be argued as a bug
fix too.

>
>
> From: Andrew Morton <[email protected]>
> Subject: fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
>
> Consolidate randomize_et_dyn() implementations into fs/binfmt_elf.c.
>
> There doesn't seem to be a compile-time way of making randomize_et_dyn()
> go away on architectures which don't need it, so mark it __weak to cause
> it to be discarded at link time.
>
> Cc: "H. Peter Anvin" <[email protected]>
> Cc: Benjamin Herrenschmidt <[email protected]>
> Cc: Catalin Marinas <[email protected]>
> Cc: Hector Marco Gisbert <[email protected]>
> Cc: Hector Marco-Gisbert <[email protected]>
> Cc: Ingo Molnar <[email protected]>
> Cc: Ismael Ripoll <[email protected]>
> Cc: Kees Cook <[email protected]>
> Cc: Ralf Baechle <[email protected]>
> Cc: Russell King <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: Will Deacon <[email protected]>
> Signed-off-by: Andrew Morton <[email protected]>

Acked-by: Kees Cook <[email protected]>

Thanks for fixing it up!

-Kees

> ---
>
> arch/arm/include/asm/elf.h | 3 +--
> arch/arm/mm/mmap.c | 13 ++-----------
> arch/arm64/Kconfig | 2 +-
> arch/arm64/include/asm/elf.h | 3 +--
> arch/arm64/mm/mmap.c | 14 ++------------
> arch/mips/include/asm/elf.h | 1 -
> arch/mips/mm/mmap.c | 13 ++-----------
> arch/powerpc/include/asm/elf.h | 2 --
> arch/powerpc/mm/mmap.c | 13 ++-----------
> arch/x86/include/asm/elf.h | 2 --
> arch/x86/mm/mmap.c | 12 ++----------
> fs/binfmt_elf.c | 21 +++++++++++++++++++++
> include/linux/elf-randomization.h | 7 +++++++
> 13 files changed, 41 insertions(+), 65 deletions(-)
>
> diff -puN arch/arm/Kconfig~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/arm/Kconfig
> diff -puN arch/arm/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/arm/include/asm/elf.h
> --- a/arch/arm/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
> +++ a/arch/arm/include/asm/elf.h
> @@ -2,7 +2,7 @@
> #define __ASMARM_ELF_H
>
> #include <asm/hwcap.h>
> -
> +#include <linux/elf-randomization.h>
> /*
> * ELF register definitions..
> */
> @@ -115,7 +115,6 @@ int dump_task_regs(struct task_struct *t
> the loader. We need to make sure that it is out of the way of the program
> that it will "exec", and that there is sufficient room for the brk. */
>
> -extern unsigned long randomize_et_dyn(unsigned long base);
> #define ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE / 3))
>
> /* When the program starts, a1 contains a pointer to a function to be
> diff -puN arch/arm/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/arm/mm/mmap.c
> --- a/arch/arm/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
> +++ a/arch/arm/mm/mmap.c
> @@ -7,6 +7,7 @@
> #include <linux/shm.h>
> #include <linux/sched.h>
> #include <linux/io.h>
> +#include <linux/elf-randomization.h>
> #include <linux/personality.h>
> #include <linux/random.h>
> #include <asm/cachetype.h>
> @@ -30,7 +31,7 @@ static int mmap_is_legacy(void)
> return sysctl_legacy_va_layout;
> }
>
> -static unsigned long mmap_rnd(void)
> +unsigned long mmap_rnd(void)
> {
> unsigned long rnd = 0;
>
> @@ -241,13 +242,3 @@ int devmem_is_allowed(unsigned long pfn)
> }
>
> #endif
> -
> -unsigned long randomize_et_dyn(unsigned long base)
> -{
> - unsigned long ret;
> - if ((current->personality & ADDR_NO_RANDOMIZE) ||
> - !(current->flags & PF_RANDOMIZE))
> - return base;
> - ret = base + mmap_rnd();
> - return (ret > base) ? ret : base;
> -}
> diff -puN arch/arm64/Kconfig~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/arm64/Kconfig
> --- a/arch/arm64/Kconfig~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
> +++ a/arch/arm64/Kconfig
> @@ -1,4 +1,4 @@
> -config ARM64
> +qconfig ARM64
> def_bool y
> select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
> select ARCH_HAS_GCOV_PROFILE_ALL
> diff -puN arch/arm64/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/arm64/include/asm/elf.h
> --- a/arch/arm64/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
> +++ a/arch/arm64/include/asm/elf.h
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (C) 2012 ARM Ltd.
> + * Copyright (C) 20q12 ARM Ltd.
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License version 2 as
> @@ -125,7 +125,6 @@ typedef struct user_fpsimd_state elf_fpr
> * the loader. We need to make sure that it is out of the way of the program
> * that it will "exec", and that there is sufficient room for the brk.
> */
> -extern unsigned long randomize_et_dyn(unsigned long base);
> #define ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE_64 / 3))
>
> /*
> diff -puN arch/arm64/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/arm64/mm/mmap.c
> --- a/arch/arm64/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
> +++ a/arch/arm64/mm/mmap.c
> @@ -17,6 +17,7 @@
> */
>
> #include <linux/elf.h>
> +#include <linux/elf-randomization.h>
> #include <linux/fs.h>
> #include <linux/mm.h>
> #include <linux/mman.h>
> @@ -47,7 +48,7 @@ static int mmap_is_legacy(void)
> return sysctl_legacy_va_layout;
> }
>
> -static unsigned long mmap_rnd(void)
> +unsigned long mmap_rnd(void)
> {
> unsigned long rnd = 0;
>
> @@ -89,17 +90,6 @@ void arch_pick_mmap_layout(struct mm_str
> }
> EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
>
> -unsigned long randomize_et_dyn(unsigned long base)
> -{
> - unsigned long ret;
> - if ((current->personality & ADDR_NO_RANDOMIZE) ||
> - !(current->flags & PF_RANDOMIZE))
> - return base;
> - ret = base + mmap_rnd();
> - return (ret > base) ? ret : base;
> -}
> -
> -
> /*
> * You really shouldn't be using read() or write() on /dev/mem. This might go
> * away in the future.
> diff -puN arch/mips/Kconfig~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/mips/Kconfig
> diff -puN arch/mips/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/mips/include/asm/elf.h
> --- a/arch/mips/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
> +++ a/arch/mips/include/asm/elf.h
> @@ -402,7 +402,6 @@ extern const char *__elf_platform;
> that it will "exec", and that there is sufficient room for the brk. */
>
> #ifndef ELF_ET_DYN_BASE
> -extern unsigned long randomize_et_dyn(unsigned long base);
> #define ELF_ET_DYN_BASE (randomize_et_dyn(TASK_SIZE / 3 * 2))
> #endif
>
> diff -puN arch/mips/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/mips/mm/mmap.c
> --- a/arch/mips/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
> +++ a/arch/mips/mm/mmap.c
> @@ -9,6 +9,7 @@
> #include <linux/compiler.h>
> #include <linux/errno.h>
> #include <linux/mm.h>
> +#include <linux/elf-randomization.h>
> #include <linux/mman.h>
> #include <linux/module.h>
> #include <linux/personality.h>
> @@ -164,7 +165,7 @@ void arch_pick_mmap_layout(struct mm_str
> }
> }
>
> -static inline unsigned long mmap_rnd(void)
> +unsigned long mmap_rnd(void)
> {
> unsigned long rnd = get_random_int();
>
> @@ -196,13 +197,3 @@ int __virt_addr_valid(const volatile voi
> return pfn_valid(PFN_DOWN(virt_to_phys(kaddr)));
> }
> EXPORT_SYMBOL_GPL(__virt_addr_valid);
> -
> -unsigned long randomize_et_dyn(unsigned long base)
> -{
> - unsigned long ret;
> - if ((current->personality & ADDR_NO_RANDOMIZE) ||
> - !(current->flags & PF_RANDOMIZE))
> - return base;
> - ret = base + brk_rnd();
> - return (ret > base) ? ret : base;
> -}
> diff -puN arch/powerpc/Kconfig~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/powerpc/Kconfig
> diff -puN arch/powerpc/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/powerpc/include/asm/elf.h
> --- a/arch/powerpc/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
> +++ a/arch/powerpc/include/asm/elf.h
> @@ -27,8 +27,6 @@
> use of this is to invoke "./ld.so someprog" to test out a new version of
> the loader. We need to make sure that it is out of the way of the program
> that it will "exec", and that there is sufficient room for the brk. */
> -
> -extern unsigned long randomize_et_dyn(unsigned long base);
> #define ELF_ET_DYN_BASE (randomize_et_dyn(0x20000000))
>
> #define ELF_CORE_EFLAGS (is_elf2_task() ? 2 : 0)
> diff -puN arch/powerpc/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/powerpc/mm/mmap.c
> --- a/arch/powerpc/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
> +++ a/arch/powerpc/mm/mmap.c
> @@ -24,6 +24,7 @@
>
> #include <linux/personality.h>
> #include <linux/mm.h>
> +#include <linux/elf-randomization.h>
> #include <linux/random.h>
> #include <linux/sched.h>
>
> @@ -53,7 +54,7 @@ static inline int mmap_is_legacy(void)
> return sysctl_legacy_va_layout;
> }
>
> -static unsigned long mmap_rnd(void)
> +unsigned long mmap_rnd(void)
> {
> unsigned long rnd = 0;
>
> @@ -97,13 +98,3 @@ void arch_pick_mmap_layout(struct mm_str
> mm->get_unmapped_area = arch_get_unmapped_area_topdown;
> }
> }
> -
> -unsigned long randomize_et_dyn(unsigned long base)
> -{
> - unsigned long ret;
> - if ((current->personality & ADDR_NO_RANDOMIZE) ||
> - !(current->flags & PF_RANDOMIZE))
> - return base;
> - ret = base + mmap_rnd();
> - return (ret > base) ? ret : base;
> -}
> diff -puN arch/x86/Kconfig~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/x86/Kconfig
> diff -puN arch/x86/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/x86/include/asm/elf.h
> --- a/arch/x86/include/asm/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
> +++ a/arch/x86/include/asm/elf.h
> @@ -248,8 +248,6 @@ extern int force_personality32;
> use of this is to invoke "./ld.so someprog" to test out a new version of
> the loader. We need to make sure that it is out of the way of the program
> that it will "exec", and that there is sufficient room for the brk. */
> -
> -extern unsigned long randomize_et_dyn(unsigned long base);
> #define ELF_ET_DYN_BASE (randomize_et_dyn(TASK_SIZE / 3 * 2))
>
> /* This yields a mask that user programs can use to figure out what
> diff -puN arch/x86/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix arch/x86/mm/mmap.c
> --- a/arch/x86/mm/mmap.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
> +++ a/arch/x86/mm/mmap.c
> @@ -29,6 +29,7 @@
> #include <linux/random.h>
> #include <linux/limits.h>
> #include <linux/sched.h>
> +#include <linux/elf-randomization.h>
> #include <asm/elf.h>
>
> struct va_alignment __read_mostly va_align = {
> @@ -65,7 +66,7 @@ static int mmap_is_legacy(void)
> return sysctl_legacy_va_layout;
> }
>
> -static unsigned long mmap_rnd(void)
> +unsigned long mmap_rnd(void)
> {
> unsigned long rnd = 0;
>
> @@ -122,12 +123,3 @@ void arch_pick_mmap_layout(struct mm_str
> mm->get_unmapped_area = arch_get_unmapped_area_topdown;
> }
> }
> -unsigned long randomize_et_dyn(unsigned long base)
> -{
> - unsigned long ret;
> - if ((current->personality & ADDR_NO_RANDOMIZE) ||
> - !(current->flags & PF_RANDOMIZE))
> - return base;
> - ret = base + mmap_rnd();
> - return (ret > base) ? ret : base;
> -}
> diff -puN fs/Kconfig.binfmt~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix fs/Kconfig.binfmt
> diff -puN fs/binfmt_elf.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix fs/binfmt_elf.c
> --- a/fs/binfmt_elf.c~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix
> +++ a/fs/binfmt_elf.c
> @@ -22,6 +22,7 @@
> #include <linux/slab.h>
> #include <linux/personality.h>
> #include <linux/elfcore.h>
> +#include <linux/elf-randomization.h>
> #include <linux/init.h>
> #include <linux/highuid.h>
> #include <linux/compiler.h>
> @@ -2300,6 +2301,26 @@ out:
>
> #endif /* CONFIG_ELF_CORE */
>
> +/* Not all architectures implement mmap_rnd() */
> +unsigned long __weak mmap_rnd(void)
> +{
> +}
> +
> +/*
> + * Not all architectures use randomize_et_dyn(), so use __weak to let the
> + * linker omit it from vmlinux
> + */
> +unsigned long __weak randomize_et_dyn(unsigned long base)
> +{
> + unsigned long ret;
> +
> + if ((current->personality & ADDR_NO_RANDOMIZE) ||
> + !(current->flags & PF_RANDOMIZE))
> + return base;
> + ret = base + mmap_rnd();
> + return max(ret, base);
> +}
> +
> static int __init init_elf_binfmt(void)
> {
> register_binfmt(&elf_format);
> diff -puN include/linux/elf.h~fix-offset2lib-issue-for-x86-arm-powerpc-and-mips-fix include/linux/elf.h
> diff -puN /dev/null include/linux/elf-randomization.h
> --- /dev/null
> +++ a/include/linux/elf-randomization.h
> @@ -0,0 +1,7 @@
> +#ifndef __ELF_RANDOMIZATION_H
> +#define __ELF_RANDOMIZATION_H
> +
> +unsigned long randomize_et_dyn(unsigned long base);
> +unsigned long mmap_rnd(void);
> +
> +#endif /* __ELF_RANDOMIZATION_H */
> _
>



--
Kees Cook
Chrome OS Security

2015-02-26 23:39:31

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS

On Thu, 26 Feb 2015 15:34:36 -0800 Kees Cook <[email protected]> wrote:

> >> That pointless repetition should be avoided.
> >
> > That's surprisingly hard!
> >
> > After renaming mips brk_rnd() to mmap_rnd() I had a shot. I'm not very
> > confident in the result. Does that __weak trick even work?
>
> In theory, it shouldn't be needed since only randomize_et_dyn will
> call mmap_rnd, and only architectures that use randomize_et_dyn will
> call it ... and will define mmap_rnd.

But randomize_et_dyn() is compiled for all architectures. Or it was,
until I did the CONFIG_ARCH_HAVE_ELF_ASLR thing.

It seems odd that we have this per-arch feature but no Kconfig switch
for it.

2015-02-27 00:20:04

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH] Fix offset2lib issue for x86*, ARM*, PowerPC and MIPS

On Thu, Feb 26, 2015 at 4:11 PM, Kees Cook <[email protected]> wrote:
> On Thu, Feb 26, 2015 at 4:06 PM, Andrew Morton
> <[email protected]> wrote:
>> On Thu, 26 Feb 2015 15:37:37 -0800 Kees Cook <[email protected]> wrote:
>>
>>> Agh, no, please let's avoid the CONFIG addition.
>>
>> That is precisely how we do this.
>>
>>> Hector mentioned in private mail that he was looking at an alternative
>>> that adds exec_base to struct mm which would avoid all this insanity.
>>>
>>> Can't we do something like:
>>>
>>> #ifndef mmap_rnd
>>> # define mmap_rnd 0
>>> #endif
>>
>> Sure, and sprinkle
>>
>> #define mmap_rnd mmap_rnd
>>
>> in five arch header files where nobody thinks to look.
>>
>> For better or for worse, we are consolidating such things into arch/*/Kconfig.
>
> Okay, fair enough. Even with your configs (though shouldn't they be
> ARCH_HAS or just HAVE?) I've now stumbled over the issue that we can't
> put randomize_et_dyn in binfmt_elf because it conflicts with linking
> against compat_binfmt_elf.

Instead of all this, how about we rework the existing CONFIG and just
change around how s390 does this to match the other architectures and
remove the ifdef in binfmt_elf.c at the same time? Let me work
something up...

-Kees

--
Kees Cook
Chrome OS Security