Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions tests/kernel/protection/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
BOARD ?= frdm_k64f
CONF_FILE = prj.conf

include ${ZEPHYR_BASE}/Makefile.test
84 changes: 84 additions & 0 deletions tests/kernel/protection/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
.. _protection_tests:

Protection tests
#################################

Overview
********
This test case verifies that protection is provided
against the following security issues:

* Write to read-only data.
* Write to text.
* Execute from data.
* Execute from stack.
* Execute from heap.

Building and Running
********************

This project can be built and executed as follows:

.. code-block:: console

$ cd tests/protection
$ make BOARD=<insert your board here>

Connect the board to your host computer using the USB port.
Flash the generated zephyr.bin on the board.
Reset the board.

Sample Output
=============

.. code-block:: console

***** BOOTING ZEPHYR OS v1.8.99 - BUILD: Jun 19 2017 12:44:27 *****
Running test suite test_protection
tc_start() - write_ro
trying to write to rodata at 0x00003124
***** BUS FAULT *****
Executing thread ID (thread): 0x200001bc
Faulting instruction address: 0x88c
Imprecise data bus error
Caught system error -- reason 0
===================================================================
PASS - write_ro.
tc_start() - write_text
trying to write to text at 0x000006c0
***** BUS FAULT *****
Executing thread ID (thread): 0x200001bc
Faulting instruction address: 0xd60
Imprecise data bus error
Caught system error -- reason 0
===================================================================
PASS - write_text.
tc_start() - exec_data
trying to call code written to 0x2000041d
***** BUS FAULT *****
Executing thread ID (thread): 0x200001bc
Faulting instruction address: 0x2000041c
Imprecise data bus error
Caught system error -- reason 0
===================================================================
PASS - exec_data.
tc_start() - exec_stack
trying to call code written to 0x20000929
***** BUS FAULT *****
Executing thread ID (thread): 0x200001bc
Faulting instruction address: 0x20000928
Imprecise data bus error
Caught system error -- reason 0
===================================================================
PASS - exec_stack.
tc_start() - exec_heap
trying to call code written to 0x20000455
***** BUS FAULT *****
Executing thread ID (thread): 0x200001bc
Faulting instruction address: 0x20000454
Imprecise data bus error
Caught system error -- reason 0
===================================================================
PASS - exec_heap.
===================================================================
PROJECT EXECUTION SUCCESSFUL
2 changes: 2 additions & 0 deletions tests/kernel/protection/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CONFIG_HEAP_MEM_POOL_SIZE=256
CONFIG_ZTEST=y
5 changes: 5 additions & 0 deletions tests/kernel/protection/src/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
include $(ZEPHYR_BASE)/tests/Makefile.test

ccflags-y += -I${ZEPHYR_BASE}/tests/include

obj-y = targets.o main.o
170 changes: 170 additions & 0 deletions tests/kernel/protection/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*
* Parts derived from tests/kernel/fatal/src/main.c, which has the
* following copyright and license:
*
* Copyright (c) 2017 Intel Corporation
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use your own copyright

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only relevant copyright is that of tests/kernel/fatal/src/main.c, from which I copied the _SysFatalErrorHandler() definition (and originally a few other bits, but those got replaced in converting to using ztest). No copyright for anything I wrote, since USG works are public domain by statute.

*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr.h>
#include <ztest.h>
#include <kernel_structs.h>
#include <string.h>
#include <stdlib.h>

#include "targets.h"

#define INFO(fmt, ...) printk(fmt, ##__VA_ARGS__)

/* ARM is a special case, in that k_thread_abort() does indeed return
* instead of calling _Swap() directly. The PendSV exception is queued
* and immediately fires upon completing the exception path; the faulting
* thread is never run again.
*/
#ifndef CONFIG_ARM
FUNC_NORETURN
#endif
void _SysFatalErrorHandler(unsigned int reason, const NANO_ESF *pEsf)
{
INFO("Caught system error -- reason %d\n", reason);
ztest_test_pass();
#ifndef CONFIG_ARM
CODE_UNREACHABLE;
#endif
}

#ifdef CONFIG_CPU_CORTEX_M
#include <arch/arm/cortex_m/cmsis.h>
/* Must clear LSB of function address to access as data. */
#define FUNC_TO_PTR(x) (void *)((uintptr_t)(x) & ~0x1)
/* Must set LSB of function address to call in Thumb mode. */
#define PTR_TO_FUNC(x) (int (*)(int))((uintptr_t)(x) | 0x1)
/* Flush preceding data writes and instruction fetches. */
#define DO_BARRIERS() do { __DSB(); __ISB(); } while (0)
#else
#define FUNC_TO_PTR(x) (void *)(x)
#define PTR_TO_FUNC(x) (int (*)(int))(x)
#define DO_BARRIERS() do { } while (0)
#endif

static int __attribute__((noinline)) add_one(int i)
{
return (i + 1);
}

static void execute_from_buffer(u8_t *dst)
{
void *src = FUNC_TO_PTR(add_one);
int (*func)(int i) = PTR_TO_FUNC(dst);
int i = 1;

/* Copy add_one() code to destination buffer. */
memcpy(dst, src, BUF_SIZE);
DO_BARRIERS();

/*
* Try executing from buffer we just filled.
* Optimally, this triggers a fault.
* If not, we check to see if the function
* returned the expected result as confirmation
* that we truly executed the code we wrote.
*/
INFO("trying to call code written to %p\n", func);
i = func(i);
INFO("returned from code at %p\n", func);
if (i == 2) {
INFO("Execute from target buffer succeeded!\n");
} else {
INFO("Did not get expected return value!\n");
}
}

static void write_ro(void)
{
u32_t *ptr = (u32_t *)&rodata_var;

/*
* Try writing to rodata. Optimally, this triggers a fault.
* If not, we check to see if the rodata value actually changed.
*/
INFO("trying to write to rodata at %p\n", ptr);
*ptr = ~RODATA_VALUE;

DO_BARRIERS();

if (*ptr == RODATA_VALUE) {
INFO("rodata value still the same\n");
} else if (*ptr == ~RODATA_VALUE) {
INFO("rodata modified!\n");
} else {
INFO("something went wrong!\n");
}

zassert_unreachable("Write to rodata did not fault");
}

static void write_text(void)
{
void *src = FUNC_TO_PTR(add_one);
void *dst = FUNC_TO_PTR(overwrite_target);
int i = 1;

/*
* Try writing to a function in the text section.
* Optimally, this triggers a fault.
* If not, we try calling the function after overwriting
* to see if it returns the expected result as
* confirmation that we truly executed the code we wrote.
*/
INFO("trying to write to text at %p\n", dst);
memcpy(dst, src, BUF_SIZE);
DO_BARRIERS();
i = overwrite_target(i);
if (i == 2) {
INFO("Overwrite of text succeeded!\n");
} else {
INFO("Did not get expected return value!\n");
}

zassert_unreachable("Write to text did not fault");
}

static void exec_data(void)
{
execute_from_buffer(data_buf);
zassert_unreachable("Execute from data did not fault");
}

static void exec_stack(void)
{
u8_t stack_buf[BUF_SIZE] __aligned(sizeof(int));

execute_from_buffer(stack_buf);
zassert_unreachable("Execute from stack did not fault");
}

#if (CONFIG_HEAP_MEM_POOL_SIZE > 0)
static void exec_heap(void)
{
u8_t *heap_buf = k_malloc(BUF_SIZE);

execute_from_buffer(heap_buf);
k_free(heap_buf);
zassert_unreachable("Execute from heap did not fault");
}
#endif

void test_main(void *unused1, void *unused2, void *unused3)
{
ztest_test_suite(test_protection,
ztest_unit_test(write_ro),
ztest_unit_test(write_text),
ztest_unit_test(exec_data),
ztest_unit_test(exec_stack)
#if (CONFIG_HEAP_MEM_POOL_SIZE > 0)
, ztest_unit_test(exec_heap)
#endif
);
ztest_run_test_suite(test_protection);
}
14 changes: 14 additions & 0 deletions tests/kernel/protection/src/targets.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include <zephyr.h>
#include <misc/printk.h>

#include "targets.h"

const u32_t rodata_var = RODATA_VALUE;

u8_t data_buf[BUF_SIZE] __aligned(sizeof(int));

int overwrite_target(int i)
{
printk("text not modified\n");
return (i - 1);
}
12 changes: 12 additions & 0 deletions tests/kernel/protection/src/targets.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef _PROT_TEST_TARGETS_H_
#define _PROT_TEST_TARGETS_H_

#define RODATA_VALUE 0xF00FF00F
extern const u32_t rodata_var;

#define BUF_SIZE 16
extern u8_t data_buf[BUF_SIZE];

extern int overwrite_target(int i);

#endif
3 changes: 3 additions & 0 deletions tests/kernel/protection/testcase.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[test]
tags = core security ignore_faults
filter = CONFIG_CPU_HAS_MPU or CONFIG_X86_MMU