boot: Harden critical path against fault attacks
Add fault attack mitigation measures to code vital for the correct
validation of images.
Change-Id: If6eb1110a8c2966faf105d07ad2e95482a80a8d9
Signed-off-by: Raef Coles <raef.coles@arm.com>
Signed-off-by: Tamas Ban <tamas.ban@arm.com>
diff --git a/boot/bootutil/src/fault_injection_hardening.c b/boot/bootutil/src/fault_injection_hardening.c
new file mode 100644
index 0000000..5ee109c
--- /dev/null
+++ b/boot/bootutil/src/fault_injection_hardening.c
@@ -0,0 +1,78 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Copyright (c) 2020 Arm Limited
+ */
+
+#include "bootutil/fault_injection_hardening.h"
+
+#ifdef FIH_ENABLE_DOUBLE_VARS
+/* Variable that could be (but isn't) changed at runtime to force the compiler
+ * not to optimize the double check. Value doesn't matter.
+ */
+volatile int _fih_mask = _FIH_MASK_VALUE;
+fih_int FIH_SUCCESS = {FIH_POSITIVE_VALUE, _FIH_MASK_VALUE ^ FIH_POSITIVE_VALUE};
+fih_int FIH_FAILURE = {FIH_NEGATIVE_VALUE, _FIH_MASK_VALUE ^ FIH_NEGATIVE_VALUE};
+#else
+fih_int FIH_SUCCESS = {FIH_POSITIVE_VALUE};
+fih_int FIH_FAILURE = {FIH_NEGATIVE_VALUE};
+#endif /* FIH_ENABLE_DOUBLE_VARS */
+
+#ifdef FIH_ENABLE_CFI
+
+#ifdef FIH_ENABLE_DOUBLE_VARS
+fih_int _fih_cfi_ctr = {0, 0 ^ _FIH_MASK_VALUE};
+#else
+fih_int _fih_cfi_ctr = {0};
+#endif /* FIH_ENABLE_DOUBLE_VARS */
+
+/* Increment the CFI counter by one, and return the value before the increment.
+ */
+fih_int fih_cfi_get_and_increment(void)
+{
+ fih_int saved = _fih_cfi_ctr;
+ _fih_cfi_ctr = fih_int_encode(fih_int_decode(saved) + 1);
+ return saved;
+}
+
+/* Validate that the saved precall value is the same as the value of the global
+ * counter. For this to be the case, a fih_ret must have been called between
+ * these functions being executed. If the values aren't the same then panic.
+ */
+void fih_cfi_validate(fih_int saved)
+{
+ if (fih_int_decode(saved) != fih_int_decode(_fih_cfi_ctr)) {
+ FIH_PANIC;
+ }
+}
+
+/* Decrement the global CFI counter by one, so that it has the same value as
+ * before the cfi_precall
+ */
+void fih_cfi_decrement(void)
+{
+ _fih_cfi_ctr = fih_int_encode(fih_int_decode(_fih_cfi_ctr) - 1);
+}
+
+#endif /* FIH_ENABLE_CFI */
+
+#ifdef FIH_ENABLE_GLOBAL_FAIL
+/* Global failure loop for bootloader code. Uses attribute used to prevent
+ * compiler removing due to non-standard calling procedure. Multiple loop jumps
+ * used to make unlooping difficult.
+ */
+__attribute__((used))
+__attribute__((noinline))
+void fih_panic_loop(void)
+{
+ __asm volatile ("b fih_panic_loop");
+ __asm volatile ("b fih_panic_loop");
+ __asm volatile ("b fih_panic_loop");
+ __asm volatile ("b fih_panic_loop");
+ __asm volatile ("b fih_panic_loop");
+ __asm volatile ("b fih_panic_loop");
+ __asm volatile ("b fih_panic_loop");
+ __asm volatile ("b fih_panic_loop");
+ __asm volatile ("b fih_panic_loop");
+}
+#endif /* FIH_ENABLE_GLOBAL_FAIL */