Skip to content

Commit

Permalink
tests/riscv: Add pmp noexecute RAM test
Browse files Browse the repository at this point in the history
  • Loading branch information
Teufelchen1 committed Jun 12, 2023
1 parent 2fdb99e commit 58d374c
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 1 deletion.
4 changes: 4 additions & 0 deletions Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ ifneq (,$(filter mpu_noexec_ram,$(USEMODULE)))
FEATURES_REQUIRED += cortexm_mpu
endif

ifneq (,$(filter pmp_noexec_ram,$(USEMODULE)))
FEATURES_REQUIRED += periph_pmp
endif

ifneq (,$(filter lwip_%,$(USEMODULE)))
USEPKG += lwip
endif
Expand Down
2 changes: 1 addition & 1 deletion core/lib/include/panic.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ typedef enum {
PANIC_HARD_REBOOT,
PANIC_ASSERT_FAIL,
PANIC_EXPECT_FAIL,
PANIC_MEM_MANAGE, /**< memory management fault */
#ifdef MODULE_CORTEXM_COMMON
PANIC_NMI_HANDLER, /**< non maskable interrupt */
PANIC_HARD_FAULT, /**< hard fault */
#if defined(CPU_CORE_CORTEX_M3) || defined(CPU_CORE_CORTEX_M33) || \
defined(CPU_CORE_CORTEX_M4) || defined(CPU_CORE_CORTEX_M4F) || \
defined(CPU_CORE_CORTEX_M7)
PANIC_MEM_MANAGE, /**< memory controller interrupt */
PANIC_BUS_FAULT, /**< bus fault */
PANIC_USAGE_FAULT, /**< undefined instruction or unaligned access */
PANIC_DEBUG_MON, /**< debug interrupt */
Expand Down
15 changes: 15 additions & 0 deletions cpu/fe310/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
#include "kernel_init.h"
#include "periph/init.h"
#include "periph_conf.h"
#ifdef MODULE_PMP_NOEXEC_RAM
#include "pmp.h"
#endif

#include "vendor/riscv_csr.h"

Expand Down Expand Up @@ -108,6 +111,18 @@ void cpu_init(void)
/* Common RISC-V initialization */
riscv_init();

#ifdef MODULE_PMP_NOEXEC_RAM
/* This marks the complete RAM region from 0x80000000 to 0x80004000 as non
* executable. Using PMP entry 0.
*
* RAM starts at 2 GiB and is 16K in size
*/
write_pmpaddr(0, make_napot(0x80000000, 0x4000));

/* Lock & select NAPOT, only allow write and read */
set_pmpcfg(0, PMP_L | PMP_NAPOT | PMP_W | PMP_R);
#endif

/* Initialize stdio */
early_init();

Expand Down
4 changes: 4 additions & 0 deletions cpu/riscv_common/irq_arch.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ static void handle_trap(uword_t mcause)
write_csr(mepc, return_pc + 4);
break;
}
case CAUSE_FAULT_FETCH:
case CAUSE_FAULT_LOAD:
case CAUSE_FAULT_STORE:
core_panic(PANIC_MEM_MANAGE, "MEM MANAGE HANDLER");
default:
#ifdef DEVELHELP
printf("Unhandled trap:\n");
Expand Down
9 changes: 9 additions & 0 deletions makefiles/pseudomodules.inc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,15 @@ PSEUDOMODULES += mpu_stack_guard
PSEUDOMODULES += mpu_noexec_ram
## @}

## @defgroup pseudomodule_pmp_noexec_ram pmp_noexec_ram
## @{
## @brief Mark RAM as non-executable using the PMP
##
## Mark the RAM non executable.
## This is a protection mechanism which makes exploitation of buffer overflows significantly harder.
PSEUDOMODULES += pmp_noexec_ram
## @}

## @defgroup pseudomodule_md5sum md5sum
## @ingroup sys_shell_commands
## @{
Expand Down
7 changes: 7 additions & 0 deletions tests/cpu/pmp_noexec_ram/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
BOARD ?= hifive1b

include ../Makefile.cpu_common

USEMODULE += pmp_noexec_ram

include $(RIOTBASE)/Makefile.include
11 changes: 11 additions & 0 deletions tests/cpu/pmp_noexec_ram/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# mpu_noexec_ram

Tests for the `pmp_noexec_ram` pseudomodule.
Only supported on RISC-V devices with PMP.

## Output

With `USEMODULE += pmp_noexec_ram` in `Makefile` this application should
execute a kernel panic, stating `Instruction access fault` (0x01) in the
`mcause` reigster. Without this pseudomodule activated, the hard fault
will be triggered by `Illegal instruction` (0x02) instead.
43 changes: 43 additions & 0 deletions tests/cpu/pmp_noexec_ram/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2023 Bennet Blischke <bennet.blischke@haw-hamburg.de>
*
* 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 pmp_noexec_ram pseudo-module
*
* @author Sören Tempel <tempel@uni-bremen.de>
* @author Bennet Blischke <bennet.blischke@haw-hamburg.de>
*
* @}
*/

#include <stdio.h>
#include <stdint.h>

#include "cpu.h"
#include "pmp.h"

#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 ("jr %0" :: "r" ((uint8_t*)&buf));

return 0;
}
18 changes: 18 additions & 0 deletions tests/cpu/pmp_noexec_ram/tests/01-run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env python3

# Copyright (C) 2020 Sören Tempel <tempel@uni-bremen.de>
#
# 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))

0 comments on commit 58d374c

Please sign in to comment.