Message ID | 3883C7B2-4CA1-4E13-9A02-F3DA4F5DA585@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | riscv: mm: Fix ASLR on RISC-V | expand |
On 9/12/19 12:39 AM, Wende Tan wrote: > The ASLR on RISC-V does not work well (only randomize stack addresses) > because RISC-V arch is lacking of `arch_mmap_rnd()`, > `arch_pick_mmap_layout()` and `arch_randomize_brk()`. Add them. Hi Wende, A patchset introducing those functions has already been merged in linux-next, please take a look at the newly introduced ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT config option. Thanks anyway, Alex > > Signed-off-by: Wende Tan <twd2.me@gmail.com> > --- > arch/riscv/Kconfig | 9 ++++ > arch/riscv/include/asm/processor.h | 5 +++ > arch/riscv/mm/Makefile | 1 + > arch/riscv/mm/mmap.c | 86 ++++++++++++++++++++++++++++++++++++++ > 4 files changed, 101 insertions(+) > create mode 100644 arch/riscv/mm/mmap.c > > diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig > index 59a4727..0f3b8ba 100644 > --- a/arch/riscv/Kconfig > +++ b/arch/riscv/Kconfig > @@ -18,6 +18,7 @@ config RISCV > select OF_EARLY_FLATTREE > select OF_IRQ > select ARCH_HAS_BINFMT_FLAT > + select ARCH_HAS_ELF_RANDOMIZE > select ARCH_WANT_FRAME_POINTERS > select CLONE_BACKWARDS > select COMMON_CLK > @@ -31,6 +32,7 @@ config RISCV > select GENERIC_SMP_IDLE_THREAD > select GENERIC_ATOMIC64 if !64BIT > select HAVE_ARCH_AUDITSYSCALL > + select HAVE_ARCH_MMAP_RND_BITS if MMU > select HAVE_MEMBLOCK_NODE_MAP > select HAVE_DMA_CONTIGUOUS > select HAVE_FUTEX_CMPXCHG if FUTEX > @@ -58,6 +60,13 @@ config RISCV > config MMU > def_bool y > > +config ARCH_MMAP_RND_BITS_MIN > + default 12 > + > +config ARCH_MMAP_RND_BITS_MAX > + default 24 if 64BIT > + default 12 > + > config ZONE_DMA32 > bool > default y if 64BIT > diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h > index f539149..2638748 100644 > --- a/arch/riscv/include/asm/processor.h > +++ b/arch/riscv/include/asm/processor.h > @@ -20,6 +20,11 @@ > #define STACK_TOP_MAX STACK_TOP > #define STACK_ALIGN 16 > > +/* > + * RISC-V has an arch_pick_mmap_layout() > + */ > +#define HAVE_ARCH_PICK_MMAP_LAYOUT 1 > + > #ifndef __ASSEMBLY__ > > struct task_struct; > diff --git a/arch/riscv/mm/Makefile b/arch/riscv/mm/Makefile > index 74055e1..742e6f3 100644 > --- a/arch/riscv/mm/Makefile > +++ b/arch/riscv/mm/Makefile > @@ -11,6 +11,7 @@ obj-y += extable.o > obj-y += ioremap.o > obj-y += cacheflush.o > obj-y += context.o > +obj-y += mmap.o > obj-y += sifive_l2_cache.o > > obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o > diff --git a/arch/riscv/mm/mmap.c b/arch/riscv/mm/mmap.c > new file mode 100644 > index 00000000..07c7933 > --- /dev/null > +++ b/arch/riscv/mm/mmap.c > @@ -0,0 +1,86 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Based on arch/mips/mm/mmap.c > + * > + * Copyright (C) 2011 Wind River Systems, > + * written by Ralf Baechle <ralf@linux-mips.org> > + * Copyright (C) 2019 Wende Tan <twd2.me@gmail.com> > + */ > +#include <linux/compiler.h> > +#include <linux/elf-randomize.h> > +#include <linux/errno.h> > +#include <linux/mm.h> > +#include <linux/mman.h> > +#include <linux/personality.h> > +#include <linux/random.h> > +#include <linux/sched/mm.h> > + > +/* gap between mmap and stack */ > +#define RISCV_MIN_GAP (128 * 1024 * 1024UL) > +#define RISCV_MAX_GAP ((TASK_SIZE) / 6 * 5) > + > +unsigned long arch_mmap_rnd(void) > +{ > + unsigned long rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1); > + > + return rnd << PAGE_SHIFT; > +} > + > +static int mmap_is_legacy(struct rlimit *rlim_stack) > +{ > + if (current->personality & ADDR_COMPAT_LAYOUT) > + return 1; > + > + if (rlim_stack->rlim_cur == RLIM_INFINITY) > + return 1; > + > + return sysctl_legacy_va_layout; > +} > + > +static unsigned long mmap_base(unsigned long rnd, struct rlimit *rlim_stack) > +{ > + unsigned long gap = rlim_stack->rlim_cur; > + > + if (gap < RISCV_MIN_GAP) > + gap = RISCV_MIN_GAP; > + else if (gap > RISCV_MAX_GAP) > + gap = RISCV_MAX_GAP; > + > + return PAGE_ALIGN(TASK_SIZE - gap - rnd); > +} > + > +void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack) > +{ > + unsigned long random_factor = 0UL; > + > + if (current->flags & PF_RANDOMIZE) > + random_factor = arch_mmap_rnd(); > + > + if (mmap_is_legacy(rlim_stack)) { > + mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; > + mm->get_unmapped_area = arch_get_unmapped_area; > + } else { > + mm->mmap_base = mmap_base(random_factor, rlim_stack); > + mm->get_unmapped_area = arch_get_unmapped_area_topdown; > + } > +} > + > +static inline unsigned long brk_rnd(void) > +{ > + unsigned long rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1); > + > + return rnd << PAGE_SHIFT; > +} > + > +unsigned long arch_randomize_brk(struct mm_struct *mm) > +{ > + unsigned long base = mm->brk; > + unsigned long ret; > + > + ret = PAGE_ALIGN(base + brk_rnd()); > + > + if (ret < mm->brk) > + return mm->brk; > + > + return ret; > +}
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 59a4727..0f3b8ba 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -18,6 +18,7 @@ config RISCV select OF_EARLY_FLATTREE select OF_IRQ select ARCH_HAS_BINFMT_FLAT + select ARCH_HAS_ELF_RANDOMIZE select ARCH_WANT_FRAME_POINTERS select CLONE_BACKWARDS select COMMON_CLK @@ -31,6 +32,7 @@ config RISCV select GENERIC_SMP_IDLE_THREAD select GENERIC_ATOMIC64 if !64BIT select HAVE_ARCH_AUDITSYSCALL + select HAVE_ARCH_MMAP_RND_BITS if MMU select HAVE_MEMBLOCK_NODE_MAP select HAVE_DMA_CONTIGUOUS select HAVE_FUTEX_CMPXCHG if FUTEX @@ -58,6 +60,13 @@ config RISCV config MMU def_bool y +config ARCH_MMAP_RND_BITS_MIN + default 12 + +config ARCH_MMAP_RND_BITS_MAX + default 24 if 64BIT + default 12 + config ZONE_DMA32 bool default y if 64BIT diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index f539149..2638748 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -20,6 +20,11 @@ #define STACK_TOP_MAX STACK_TOP #define STACK_ALIGN 16 +/* + * RISC-V has an arch_pick_mmap_layout() + */ +#define HAVE_ARCH_PICK_MMAP_LAYOUT 1 + #ifndef __ASSEMBLY__ struct task_struct; diff --git a/arch/riscv/mm/Makefile b/arch/riscv/mm/Makefile index 74055e1..742e6f3 100644 --- a/arch/riscv/mm/Makefile +++ b/arch/riscv/mm/Makefile @@ -11,6 +11,7 @@ obj-y += extable.o obj-y += ioremap.o obj-y += cacheflush.o obj-y += context.o +obj-y += mmap.o obj-y += sifive_l2_cache.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o diff --git a/arch/riscv/mm/mmap.c b/arch/riscv/mm/mmap.c new file mode 100644 index 00000000..07c7933 --- /dev/null +++ b/arch/riscv/mm/mmap.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Based on arch/mips/mm/mmap.c + * + * Copyright (C) 2011 Wind River Systems, + * written by Ralf Baechle <ralf@linux-mips.org> + * Copyright (C) 2019 Wende Tan <twd2.me@gmail.com> + */ +#include <linux/compiler.h> +#include <linux/elf-randomize.h> +#include <linux/errno.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/personality.h> +#include <linux/random.h> +#include <linux/sched/mm.h> + +/* gap between mmap and stack */ +#define RISCV_MIN_GAP (128 * 1024 * 1024UL) +#define RISCV_MAX_GAP ((TASK_SIZE) / 6 * 5) + +unsigned long arch_mmap_rnd(void) +{ + unsigned long rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1); + + return rnd << PAGE_SHIFT; +} + +static int mmap_is_legacy(struct rlimit *rlim_stack) +{ + if (current->personality & ADDR_COMPAT_LAYOUT) + return 1; + + if (rlim_stack->rlim_cur == RLIM_INFINITY) + return 1; + + return sysctl_legacy_va_layout; +} + +static unsigned long mmap_base(unsigned long rnd, struct rlimit *rlim_stack) +{ + unsigned long gap = rlim_stack->rlim_cur; + + if (gap < RISCV_MIN_GAP) + gap = RISCV_MIN_GAP; + else if (gap > RISCV_MAX_GAP) + gap = RISCV_MAX_GAP; + + return PAGE_ALIGN(TASK_SIZE - gap - rnd); +} + +void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack) +{ + unsigned long random_factor = 0UL; + + if (current->flags & PF_RANDOMIZE) + random_factor = arch_mmap_rnd(); + + if (mmap_is_legacy(rlim_stack)) { + mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; + mm->get_unmapped_area = arch_get_unmapped_area; + } else { + mm->mmap_base = mmap_base(random_factor, rlim_stack); + mm->get_unmapped_area = arch_get_unmapped_area_topdown; + } +} + +static inline unsigned long brk_rnd(void) +{ + unsigned long rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1); + + return rnd << PAGE_SHIFT; +} + +unsigned long arch_randomize_brk(struct mm_struct *mm) +{ + unsigned long base = mm->brk; + unsigned long ret; + + ret = PAGE_ALIGN(base + brk_rnd()); + + if (ret < mm->brk) + return mm->brk; + + return ret; +}
The ASLR on RISC-V does not work well (only randomize stack addresses) because RISC-V arch is lacking of `arch_mmap_rnd()`, `arch_pick_mmap_layout()` and `arch_randomize_brk()`. Add them. Signed-off-by: Wende Tan <twd2.me@gmail.com> --- arch/riscv/Kconfig | 9 ++++ arch/riscv/include/asm/processor.h | 5 +++ arch/riscv/mm/Makefile | 1 + arch/riscv/mm/mmap.c | 86 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+) create mode 100644 arch/riscv/mm/mmap.c