esp_fault.h 4.0 KB

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