esp_fault.h 3.5 KB

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