From 2c1a6271189949c7bd5341a34f2699add9a0af38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Tempel?= Date: Sun, 16 Feb 2020 18:13:00 +0100 Subject: [PATCH 1/4] Add mpu_noexec_ram pseudomodule --- Makefile.dep | 4 ++++ cpu/cortexm_common/vectors_cortexm.c | 20 +++++++++++++++++++- makefiles/pseudomodules.inc.mk | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Makefile.dep b/Makefile.dep index dc22797cd7e8..7ecb43bb1cef 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -30,6 +30,10 @@ ifneq (,$(filter mpu_stack_guard,$(USEMODULE))) FEATURES_REQUIRED += cortexm_mpu endif +ifneq (,$(filter mpu_noexec_ram,$(USEMODULE))) + FEATURES_REQUIRED += cortexm_mpu +endif + ifneq (,$(filter auto_init_gnrc_netif,$(USEMODULE))) USEMODULE += gnrc_netif_init_devs endif diff --git a/cpu/cortexm_common/vectors_cortexm.c b/cpu/cortexm_common/vectors_cortexm.c index a0e7a89c61af..6e9401fa865b 100644 --- a/cpu/cortexm_common/vectors_cortexm.c +++ b/cpu/cortexm_common/vectors_cortexm.c @@ -17,6 +17,7 @@ * @author Hauke Petersen * @author Daniel Krebs * @author Joakim Gebart + * @author Sören Tempel * * @} */ @@ -139,8 +140,25 @@ void reset_handler_default(void) } #endif /* CPU_HAS_BACKUP_RAM */ -#ifdef MODULE_MPU_STACK_GUARD +#if defined(MODULE_MPU_STACK_GUARD) || defined(MODULE_MPU_NOEXEC_RAM) mpu_enable(); +#endif + +#ifdef MODULE_MPU_NOEXEC_RAM + /* Mark the RAM non executable. This is a protection mechanism which + * makes exploitation of buffer overflows significantly harder. + * + * This marks the memory region from 0x20000000 to 0x3FFFFFFF as non + * executable. This is the Cortex-M SRAM region used for on-chip RAM. + */ + mpu_configure( + 2, /* Region 0 and 1 are used by mpu_stack_guard */ + (uintptr_t)&_sram, /* RAM base address */ + MPU_ATTR(1, AP_RW_RW, 0, 1, 0, 1, MPU_SIZE_512M) /* Allow read/write but no exec */ + ); +#endif + +#ifdef MODULE_MPU_STACK_GUARD if (((uintptr_t)&_sstack) != SRAM_BASE) { mpu_configure( 0, /* MPU region 0 */ diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 2964ac030acb..de5cf94da6a5 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -56,6 +56,7 @@ PSEUDOMODULES += log_printfnoformat PSEUDOMODULES += log_color PSEUDOMODULES += lora PSEUDOMODULES += mpu_stack_guard +PSEUDOMODULES += mpu_noexec_ram PSEUDOMODULES += nanocoap_% PSEUDOMODULES += netdev_default PSEUDOMODULES += netstats From 5bb3b3dfead731d1ee8ccf529b05d842f346ef8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Tempel?= Date: Sun, 16 Feb 2020 19:56:05 +0100 Subject: [PATCH 2/4] tests: add test for the mpu_noexec_ram pseudomodule The Makefiles have been copied from the mpu_stack_guard test. --- tests/mpu_noexec_ram/Makefile | 5 ++++ tests/mpu_noexec_ram/README.md | 10 +++++++ tests/mpu_noexec_ram/main.c | 51 ++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 tests/mpu_noexec_ram/Makefile create mode 100644 tests/mpu_noexec_ram/README.md create mode 100644 tests/mpu_noexec_ram/main.c diff --git a/tests/mpu_noexec_ram/Makefile b/tests/mpu_noexec_ram/Makefile new file mode 100644 index 000000000000..2354fefa05b1 --- /dev/null +++ b/tests/mpu_noexec_ram/Makefile @@ -0,0 +1,5 @@ +include ../Makefile.tests_common + +USEMODULE += mpu_noexec_ram + +include $(RIOTBASE)/Makefile.include diff --git a/tests/mpu_noexec_ram/README.md b/tests/mpu_noexec_ram/README.md new file mode 100644 index 000000000000..646b879dbfdb --- /dev/null +++ b/tests/mpu_noexec_ram/README.md @@ -0,0 +1,10 @@ +# mpu_noexec_ram + +Tests for the `mpu_noexec_ram` pseudomodule. As this module is currently +only supported on Cortex M devices, the test case is a bit ARM specific. + +## Output + +With `USEMODULE += mpu_noexec_ram` in `Makefile` this application should +execute a kernel panic from the `MEM MANAGE HANDLER`. Without this +pseudomodule activated, it will run into a hard fault. diff --git a/tests/mpu_noexec_ram/main.c b/tests/mpu_noexec_ram/main.c new file mode 100644 index 000000000000..35bc5b7c0b3c --- /dev/null +++ b/tests/mpu_noexec_ram/main.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2020 Sören Tempel + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test application for the mpu_noexec_stack pseudo-module + * + * @author Sören Tempel + * + * @} + */ + +#include +#include + +#include "cpu.h" +#include "mpu.h" + +/* RIOT's MPU headers gracefully fail when no MPU is present. + * Use this to catch if RIOT's features are correctly gating MPU use. + */ +#if !__MPU_PRESENT +#error "(!__MPU_PRESENT)" +#endif + +#define JMPBUF_SIZE 3 + +int main(void) +{ + uint32_t buf[JMPBUF_SIZE]; + + /* Fill the buffer with invalid instructions */ + for (unsigned i = 0; i < JMPBUF_SIZE; i++) { + buf[i] = UINT32_MAX; + } + + puts("Attempting to jump to stack buffer ...\n"); + __asm__ volatile ("BX %0" + : /* no output operands */ + : "r" ((uint8_t*)&buf + 1)); /* LSB must be set for thumb2 */ + + return 0; +} From 59676a1f5eb4366a6edfd56a20bedbcfcba2276a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Tempel?= Date: Mon, 17 Feb 2020 09:37:26 +0100 Subject: [PATCH 3/4] Make sure the mpu_noexec_ram regions has the lowest priority From the ARMv7-M ARM section B3.5.3: Where there is an overlap between two regions, the register with the highest region number takes priority. We want to make sure the mpu_noexec_ram region has the lowest priority to allow the mpu_stack_guard region to overwrite the first N bytes of it. This change fixes using mpu_noexec_ram and mpu_stack_guard together. --- core/sched.c | 2 +- cpu/cortexm_common/vectors_cortexm.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/sched.c b/core/sched.c index e307d7dffd4e..52a32c1dbe20 100644 --- a/core/sched.c +++ b/core/sched.c @@ -121,7 +121,7 @@ int __attribute__((used)) sched_run(void) #ifdef MODULE_MPU_STACK_GUARD mpu_configure( - 1, /* MPU region 1 */ + 2, /* MPU region 2 */ (uintptr_t)sched_active_thread->stack_start + 31, /* Base Address (rounded up) */ MPU_ATTR(1, AP_RO_RO, 0, 1, 0, 1, MPU_SIZE_32B) /* Attributes and Size */ ); diff --git a/cpu/cortexm_common/vectors_cortexm.c b/cpu/cortexm_common/vectors_cortexm.c index 6e9401fa865b..a81162ccfc7b 100644 --- a/cpu/cortexm_common/vectors_cortexm.c +++ b/cpu/cortexm_common/vectors_cortexm.c @@ -152,7 +152,7 @@ void reset_handler_default(void) * executable. This is the Cortex-M SRAM region used for on-chip RAM. */ mpu_configure( - 2, /* Region 0 and 1 are used by mpu_stack_guard */ + 0, /* Region 0 (lowest priority) */ (uintptr_t)&_sram, /* RAM base address */ MPU_ATTR(1, AP_RW_RW, 0, 1, 0, 1, MPU_SIZE_512M) /* Allow read/write but no exec */ ); @@ -161,7 +161,7 @@ void reset_handler_default(void) #ifdef MODULE_MPU_STACK_GUARD if (((uintptr_t)&_sstack) != SRAM_BASE) { mpu_configure( - 0, /* MPU region 0 */ + 1, /* MPU region 1 */ (uintptr_t)&_sstack + 31, /* Base Address (rounded up) */ MPU_ATTR(1, AP_RO_RO, 0, 1, 0, 1, MPU_SIZE_32B) /* Attributes and Size */ ); From 9772f78a0e6f40b032b61f3e23d5d05e0e5ed2c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Tempel?= Date: Tue, 18 Feb 2020 11:53:31 +0100 Subject: [PATCH 4/4] tests/mpu_noexec_ram: convert to an automated test --- tests/mpu_noexec_ram/tests/01-run.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100755 tests/mpu_noexec_ram/tests/01-run.py diff --git a/tests/mpu_noexec_ram/tests/01-run.py b/tests/mpu_noexec_ram/tests/01-run.py new file mode 100755 index 000000000000..8340c1407ae3 --- /dev/null +++ b/tests/mpu_noexec_ram/tests/01-run.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2020 Sören Tempel +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +import sys +from testrunner import run + + +def testfunc(child): + child.expect_exact("MEM MANAGE HANDLER\r\n") + + +if __name__ == "__main__": + sys.exit(run(testfunc, timeout=10))