diff --git a/components/esp_common/include/esp_fault_internal.h b/components/esp_common/include/esp_fault_internal.h new file mode 100644 index 00000000000..871f2e8e773 --- /dev/null +++ b/components/esp_common/include/esp_fault_internal.h @@ -0,0 +1,94 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "sdkconfig.h" +#include "esp_rom_sys.h" + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Assert a condition is true, in a way that should be resistant to fault injection for + * single fault attacks. + * + * - Expands CONDITION multiple times (condition must have no side effects) + * - Compiler is told all registers are invalid before evaluating CONDITION each time, to avoid a fault + * causing a misread of a register used in all three evaluations of CONDITION. + * - If CONDITION is ever false, a system reset is triggered. + * + * @note Place this macro after a "normal" check of CONDITION that will fail with a normal error + * message. This is the fallback in case a fault injection attack skips or corrupts the result of + * that check. (Although ensure that an attacker can't use fault injection to skip past the "normal" + * error message, to avoid this check entirely.) + * + * @note This macro increases binary size and is slow and should be used sparingly. + * + * @note This macro does not guarantee fault injection resistance. In particular CONDITION must be + * chosen carefully - a fault injection attack which sets CONDITION to true will not be detected by + * this macro. Care must also be taken that an attacker can't use a fault to completely bypass calling + * whatever function tests ESP_FAULT_ASSERT. + * + * @note This is difficult to debug as a failure triggers an instant software reset, and UART output + * is often truncated (as FIFO is not flushed). Define the ESP_FAULT_ASSERT_DEBUG macro to debug any + * failures of this macro due to software bugs. + * + * @param CONDITION A condition which will evaluate true unless an attacker used fault injection to skip or corrupt some other critical system calculation. + * + */ +#define ESP_FAULT_ASSERT(CONDITION) do { \ + asm volatile ("" ::: "memory"); \ + if(!(CONDITION)) _ESP_FAULT_RESET(); \ + asm volatile ("" ::: "memory"); \ + if(!(CONDITION)) _ESP_FAULT_RESET(); \ + asm volatile ("" ::: "memory"); \ + if(!(CONDITION)) _ESP_FAULT_RESET(); \ +} while(0) + +#if CONFIG_IDF_TARGET_ARCH_XTENSA +#define _ESP_FAULT_ILLEGAL_INSTRUCTION asm volatile("ill.n; ill.n; ill.n; ill.n; ill.n; ill.n; ill.n;") +#elif CONFIG_IDF_TARGET_ARCH_RISCV +#define _ESP_FAULT_ILLEGAL_INSTRUCTION asm volatile("unimp; unimp; unimp; unimp; unimp;") +#elif CONFIG_IDF_TARGET_LINUX +#define _ESP_FAULT_ILLEGAL_INSTRUCTION +#else +#error "_ESP_FAULT_ILLEGAL_INSTRUCTION is not defined for this TARGET" +#endif + +// Uncomment this macro to get debug output if ESP_FAULT_ASSERT() fails +// +// Note that uncommenting this macro reduces the anti-FI effectiveness +// +//#define ESP_FAULT_ASSERT_DEBUG + +/* Internal macro, purpose is to trigger a system reset if an inconsistency due to fault injection + is detected. + + Illegal instruction opcodes are there as a fallback to crash the CPU in case it doesn't + reset as expected. +*/ +#ifndef ESP_FAULT_ASSERT_DEBUG + +#define _ESP_FAULT_RESET() do { \ + esp_rom_software_reset_system(); \ + _ESP_FAULT_ILLEGAL_INSTRUCTION; \ + } while(0) + +#else // ESP_FAULT_ASSERT_DEBUG + +#warning "Enabling ESP_FAULT_ASSERT_DEBUG makes ESP_FAULT_ASSERT() less effective" + +#define _ESP_FAULT_RESET() do { \ + esp_rom_printf("ESP_FAULT_ASSERT %s:%d\n", __FILE__, __LINE__); \ + _ESP_FAULT_ILLEGAL_INSTRUCTION; \ + } while(0) + +#endif // ESP_FAULT_ASSERT_DEBUG + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/include/esp_fault.h b/components/esp_hw_support/include/esp_fault.h index 19b0a9e0cfc..d8ec9c8e1ed 100644 --- a/components/esp_hw_support/include/esp_fault.h +++ b/components/esp_hw_support/include/esp_fault.h @@ -1,90 +1,8 @@ /* - * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include "sdkconfig.h" -#include "esp_rom_sys.h" - #pragma once -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Assert a condition is true, in a way that should be resistant to fault injection for - * single fault attacks. - * - * - Expands CONDITION multiple times (condition must have no side effects) - * - Compiler is told all registers are invalid before evaluating CONDITION each time, to avoid a fault - * causing a misread of a register used in all three evaluations of CONDITION. - * - If CONDITION is ever false, a system reset is triggered. - * - * @note Place this macro after a "normal" check of CONDITION that will fail with a normal error - * message. This is the fallback in case a fault injection attack skips or corrupts the result of - * that check. (Although ensure that an attacker can't use fault injection to skip past the "normal" - * error message, to avoid this check entirely.) - * - * @note This macro increases binary size and is slow and should be used sparingly. - * - * @note This macro does not guarantee fault injection resistance. In particular CONDITION must be - * chosen carefully - a fault injection attack which sets CONDITION to true will not be detected by - * this macro. Care must also be taken that an attacker can't use a fault to completely bypass calling - * whatever function tests ESP_FAULT_ASSERT. - * - * @note This is difficult to debug as a failure triggers an instant software reset, and UART output - * is often truncated (as FIFO is not flushed). Define the ESP_FAULT_ASSERT_DEBUG macro to debug any - * failures of this macro due to software bugs. - * - * @param CONDITION A condition which will evaluate true unless an attacker used fault injection to skip or corrupt some other critical system calculation. - * - */ -#define ESP_FAULT_ASSERT(CONDITION) do { \ - asm volatile ("" ::: "memory"); \ - if(!(CONDITION)) _ESP_FAULT_RESET(); \ - asm volatile ("" ::: "memory"); \ - if(!(CONDITION)) _ESP_FAULT_RESET(); \ - asm volatile ("" ::: "memory"); \ - if(!(CONDITION)) _ESP_FAULT_RESET(); \ -} while(0) - -#ifndef CONFIG_IDF_TARGET_ARCH_RISCV -#define _ESP_FAULT_ILLEGAL_INSTRUCTION asm volatile("ill.n; ill.n; ill.n; ill.n; ill.n; ill.n; ill.n;") -#else -#define _ESP_FAULT_ILLEGAL_INSTRUCTION asm volatile("unimp; unimp; unimp; unimp; unimp;") -#endif - -// Uncomment this macro to get debug output if ESP_FAULT_ASSERT() fails -// -// Note that uncommenting this macro reduces the anti-FI effectiveness -// -//#define ESP_FAULT_ASSERT_DEBUG - -/* Internal macro, purpose is to trigger a system reset if an inconsistency due to fault injection - is detected. - - Illegal instruction opcodes are there as a fallback to crash the CPU in case it doesn't - reset as expected. -*/ -#ifndef ESP_FAULT_ASSERT_DEBUG - -#define _ESP_FAULT_RESET() do { \ - esp_rom_software_reset_system(); \ - _ESP_FAULT_ILLEGAL_INSTRUCTION; \ - } while(0) - -#else // ESP_FAULT_ASSERT_DEBUG - -#warning "Enabling ESP_FAULT_ASSERT_DEBUG makes ESP_FAULT_ASSERT() less effective" - -#define _ESP_FAULT_RESET() do { \ - esp_rom_printf("ESP_FAULT_ASSERT %s:%d\n", __FILE__, __LINE__); \ - _ESP_FAULT_ILLEGAL_INSTRUCTION; \ - } while(0) - -#endif // ESP_FAULT_ASSERT_DEBUG - -#ifdef __cplusplus -} -#endif +#include "esp_fault_internal.h" diff --git a/components/esp_rom/patches/esp_rom_ecdsa.c b/components/esp_rom/patches/esp_rom_ecdsa.c index 0667fadca61..ae409a24f7e 100644 --- a/components/esp_rom/patches/esp_rom_ecdsa.c +++ b/components/esp_rom/patches/esp_rom_ecdsa.c @@ -11,7 +11,7 @@ #include "esp_rom_caps.h" #if ESP_ROM_ECDSA_VERIFY_PATCH #include "soc/soc_caps.h" -#include "esp_fault.h" +#include "esp_fault_internal.h" #include "rom/ecdsa.h" #define VALID_MAGIC_OK 0x6A6A6A6AU diff --git a/components/hal/ecdsa_hal.c b/components/hal/ecdsa_hal.c index 5da8baf5733..bd98fb3a794 100644 --- a/components/hal/ecdsa_hal.c +++ b/components/hal/ecdsa_hal.c @@ -14,7 +14,7 @@ #endif #if CONFIG_HAL_ECDSA_GEN_SIG_CM -#include "esp_fault.h" +#include "esp_fault_internal.h" #include "esp_random.h" #include "soc/chip_revision.h" #endif diff --git a/components/hal/esp32c6/include/hal/ecc_ll.h b/components/hal/esp32c6/include/hal/ecc_ll.h index fc0861b3148..a51b99b26ac 100644 --- a/components/hal/esp32c6/include/hal/ecc_ll.h +++ b/components/hal/esp32c6/include/hal/ecc_ll.h @@ -12,7 +12,7 @@ #include "soc/ecc_mult_reg.h" #include "soc/pcr_struct.h" #include "soc/pcr_reg.h" -#include "esp_fault.h" +#include "esp_fault_internal.h" #ifdef __cplusplus extern "C" { diff --git a/components/hal/esp32h2/include/hal/ecc_ll.h b/components/hal/esp32h2/include/hal/ecc_ll.h index 9db578ed305..2f73bb26f1e 100644 --- a/components/hal/esp32h2/include/hal/ecc_ll.h +++ b/components/hal/esp32h2/include/hal/ecc_ll.h @@ -12,7 +12,7 @@ #include "soc/ecc_mult_reg.h" #include "soc/pcr_struct.h" #include "soc/pcr_reg.h" -#include "esp_fault.h" +#include "esp_fault_internal.h" #include "soc/chip_revision.h" #include "hal/efuse_hal.h"