1 /* 2 * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 #include "sdkconfig.h" 7 #include "soc/rtc_cntl_reg.h" 8 #include "esp_rom_sys.h" 9 10 #pragma once 11 12 #ifdef __cplusplus 13 extern "C" { 14 #endif 15 16 /** 17 * @brief Assert a condition is true, in a way that should be resistant to fault injection for 18 * single fault attacks. 19 * 20 * - Expands CONDITION multiple times (condition must have no side effects) 21 * - Compiler is told all registers are invalid before evaluating CONDITION each time, to avoid a fault 22 * causing a misread of a register used in all three evaluations of CONDITION. 23 * - If CONDITION is ever false, a system reset is triggered. 24 * 25 * @note Place this macro after a "normal" check of CONDITION that will fail with a normal error 26 * message. This is the fallback in case a fault injection attack skips or corrupts the result of 27 * that check. (Although ensure that an attacker can't use fault injection to skip past the "normal" 28 * error message, to avoid this check entirely.) 29 * 30 * @note This macro increases binary size and is slow and should be used sparingly. 31 * 32 * @note This macro does not guarantee fault injection resistance. In particular CONDITION must be 33 * chosen carefully - a fault injection attack which sets CONDITION to true will not be detected by 34 * this macro. Care must also be taken that an attacker can't use a fault to completely bypass calling 35 * whatever function tests ESP_FAULT_ASSERT. 36 * 37 * @note This is difficult to debug as a failure triggers an instant software reset, and UART output 38 * is often truncated (as FIFO is not flushed). Define the ESP_FAULT_ASSERT_DEBUG macro to debug any 39 * failures of this macro due to software bugs. 40 * 41 * @param CONDITION A condition which will evaluate true unless an attacker used fault injection to skip or corrupt some other critical system calculation. 42 * 43 */ 44 #define ESP_FAULT_ASSERT(CONDITION) do { \ 45 asm volatile ("" ::: "memory"); \ 46 if(!(CONDITION)) _ESP_FAULT_RESET(); \ 47 asm volatile ("" ::: "memory"); \ 48 if(!(CONDITION)) _ESP_FAULT_RESET(); \ 49 asm volatile ("" ::: "memory"); \ 50 if(!(CONDITION)) _ESP_FAULT_RESET(); \ 51 } while(0) 52 53 #ifndef CONFIG_IDF_TARGET_ARCH_RISCV 54 #define _ESP_FAULT_ILLEGAL_INSTRUCTION asm volatile("ill.n; ill.n; ill.n; ill.n; ill.n; ill.n; ill.n;") 55 #else 56 #define _ESP_FAULT_ILLEGAL_INSTRUCTION asm volatile("unimp; unimp; unimp; unimp; unimp;") 57 #endif 58 59 // Uncomment this macro to get debug output if ESP_FAULT_ASSERT() fails 60 // 61 // Note that uncommenting this macro reduces the anti-FI effectiveness 62 // 63 //#define ESP_FAULT_ASSERT_DEBUG 64 65 /* Internal macro, purpose is to trigger a system reset if an inconsistency due to fault injection 66 is detected. 67 68 Illegal instruction opcodes are there as a fallback to crash the CPU in case it doesn't 69 reset as expected. 70 */ 71 #ifndef ESP_FAULT_ASSERT_DEBUG 72 73 #define _ESP_FAULT_RESET() do { \ 74 REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST); \ 75 _ESP_FAULT_ILLEGAL_INSTRUCTION; \ 76 } while(0) 77 78 #else // ESP_FAULT_ASSERT_DEBUG 79 80 #warning "Enabling ESP_FAULT_ASSERT_DEBUG makes ESP_FAULT_ASSERT() less effective" 81 82 #define _ESP_FAULT_RESET() do { \ 83 esp_rom_printf("ESP_FAULT_ASSERT %s:%d\n", __FILE__, __LINE__); \ 84 _ESP_FAULT_ILLEGAL_INSTRUCTION; \ 85 } while(0) 86 87 #endif // ESP_FAULT_ASSERT_DEBUG 88 89 #ifdef __cplusplus 90 } 91 #endif 92