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