diff mbox series

riscv: mm: Fix ASLR on RISC-V

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

Commit Message

twd2 Sept. 12, 2019, 4:39 a.m. UTC
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

Comments

Alexandre Ghiti Sept. 12, 2019, 5:50 a.m. UTC | #1
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 mbox series

Patch

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;
+}