Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | /* * Parts derived from tests/kernel/fatal/src/main.c, which has the * following copyright and license: * * Copyright (c) 2017 Intel Corporation * * 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 #if defined(CONFIG_ARM) #define NO_EXECUTE_SUPPORT 1 #elif defined(CONFIG_X86) /* i386 MMU doesn't control execute capabilities, only on x86_64 */ #else #error "Architecture not supported" #endif static int __attribute__((noinline)) add_one(int i) { return (i + 1); } #ifdef NO_EXECUTE_SUPPORT 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"); } } #endif 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"); } #ifdef NO_EXECUTE_SUPPORT 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 #endif /* NO_EXECUTE_SUPPORT */ void test_main(void *unused1, void *unused2, void *unused3) { ztest_test_suite(test_protection, #ifdef NO_EXECUTE_SUPPORT ztest_unit_test(exec_data), ztest_unit_test(exec_stack), #if (CONFIG_HEAP_MEM_POOL_SIZE > 0) ztest_unit_test(exec_heap), #endif #endif /* NO_EXECUTE_SUPPORT */ ztest_unit_test(write_ro), ztest_unit_test(write_text) ); ztest_run_test_suite(test_protection); } |