Data Types for use in Hardened Code. More...
#include <stdint.h>
#include "sw/device/lib/base/hardened_asm.h"
#include "sw/device/lib/base/macros.h"
#include "sw/device/lib/base/stdasm.h"
#include <assert.h>
Go to the source code of this file.
Macros | |
#define | HARDENED_CHECK_OP_EQ_ == |
#define | HARDENED_CHECK_OP_NE_ != |
#define | HARDENED_CHECK_OP_LT_ < |
#define | HARDENED_CHECK_OP_GT_ > |
#define | HARDENED_CHECK_OP_LE_ <= |
#define | HARDENED_CHECK_OP_GE_ >= |
#define | HARDENED_CHECK_(op_, a_, b_) assert((uint64_t)(a_)OT_CAT(HARDENED_CHECK_OP_, op_)(uint64_t)(b_)) |
#define | HARDENED_TRAP_() __builtin_trap() |
#define | HARDENED_TRAP() HARDENED_TRAP_() |
If the following code is (unexpectedly) reached a trap instruction will be executed. | |
#define | HARDENED_CHECK_EQ(a_, b_) HARDENED_CHECK_(EQ_, a_, b_) |
Compare two values in a way that is manifestly true: that is, under normal program execution, the comparison is a tautology. More... | |
#define | HARDENED_CHECK_NE(a_, b_) HARDENED_CHECK_(NE_, a_, b_) |
#define | HARDENED_CHECK_LT(a_, b_) HARDENED_CHECK_(LT_, a_, b_) |
#define | HARDENED_CHECK_GT(a_, b_) HARDENED_CHECK_(GT_, a_, b_) |
#define | HARDENED_CHECK_LE(a_, b_) HARDENED_CHECK_(LE_, a_, b_) |
#define | HARDENED_CHECK_GE(a_, b_) HARDENED_CHECK_(GE_, a_, b_) |
Typedefs | |
typedef enum hardened_bool | hardened_bool_t |
This is a boolean type for use in hardened contexts. More... | |
typedef enum hardened_byte_bool | hardened_byte_bool_t |
A byte-sized hardened boolean. More... | |
typedef uint32_t | ct_bool32_t |
A constant-time, 32-bit boolean value. More... | |
typedef uintptr_t | ct_boolw_t |
A constant-time, pointer-sized boolean value. More... | |
Enumerations | |
enum | hardened_bool { kHardenedBoolTrue = HARDENED_BOOL_TRUE , kHardenedBoolFalse = HARDENED_BOOL_FALSE , kHardenedBoolTrue = 0x739 , kHardenedBoolFalse = 0x1d4 } |
This is a boolean type for use in hardened contexts. More... | |
enum | hardened_byte_bool { kHardenedByteBoolTrue = HARDENED_BYTE_BOOL_TRUE , kHardenedByteBoolFalse = HARDENED_BYTE_BOOL_FALSE } |
A byte-sized hardened boolean. More... | |
Functions | |
OT_WARN_UNUSED_RESULT uint32_t | launder32 (uint32_t val) |
OT_WARN_UNUSED_RESULT uintptr_t | launderw (uintptr_t val) |
Launders the pointer-sized value val . More... | |
void | barrier32 (uint32_t val) |
Creates a reordering barrier for val . More... | |
void | barrierw (uintptr_t val) |
Creates a reordering barrier for val . More... | |
OT_WARN_UNUSED_RESULT ct_bool32_t | ct_sltz32 (int32_t a) |
Performs constant-time signed comparison to zero. More... | |
OT_WARN_UNUSED_RESULT ct_bool32_t | ct_sltu32 (uint32_t a, uint32_t b) |
Performs constant-time unsigned ascending comparison. More... | |
OT_WARN_UNUSED_RESULT ct_bool32_t | ct_seqz32 (uint32_t a) |
Performs constant-time zero equality. More... | |
OT_WARN_UNUSED_RESULT ct_bool32_t | ct_seq32 (uint32_t a, uint32_t b) |
Performs constant-time equality. More... | |
OT_WARN_UNUSED_RESULT uint32_t | ct_cmov32 (ct_bool32_t c, uint32_t a, uint32_t b) |
Performs a constant-time select. More... | |
OT_WARN_UNUSED_RESULT ct_boolw_t | ct_sltzw (intptr_t a) |
Performs constant-time signed comparison to zero. More... | |
OT_WARN_UNUSED_RESULT ct_boolw_t | ct_sltuw (uintptr_t a, uintptr_t b) |
Performs constant-time unsigned ascending comparison. More... | |
OT_WARN_UNUSED_RESULT ct_boolw_t | ct_seqzw (uintptr_t a) |
Performs constant-time zero equality. More... | |
OT_WARN_UNUSED_RESULT ct_boolw_t | ct_seqw (uintptr_t a, uintptr_t b) |
Performs constant-time equality. More... | |
OT_WARN_UNUSED_RESULT uintptr_t | ct_cmovw (ct_boolw_t c, uintptr_t a, uintptr_t b) |
Performs a constant-time select. More... | |
Data Types for use in Hardened Code.
Definition in file hardened.h.
#define HARDENED_CHECK_EQ | ( | a_, | |
b_ | |||
) | HARDENED_CHECK_(EQ_, a_, b_) |
Compare two values in a way that is manifestly true: that is, under normal program execution, the comparison is a tautology.
If the comparison fails, we can deduce the device is under attack, so an illegal instruction will be executed. The manner in which the comparison is done is carefully constructed in assembly to minimize the possibility of adversarial faults. This macro also implicitly launders both arguments since the compiler doesn't see the comparison and can't learn any new information from it.
There are six variants of this macro: one for each of the six comparison operations.
This macro is intended to be used along with launder32()
to handle detected faults when implementing redundant checks, i.e. in places where the compiler could otherwise prove statically unreachable. For example:
See launder32()
for more details.
Definition at line 646 of file hardened.h.
typedef uint32_t ct_bool32_t |
A constant-time, 32-bit boolean value.
Values of this type MUST be either all zero bits or all one bits, representing false
and true
respectively.
Although it is possible to convert an existing bool
into a ct_bool32_t
by writing -((ct_bool32_t) my_bool)
, we recommend against it
Definition at line 380 of file hardened.h.
typedef uintptr_t ct_boolw_t |
A constant-time, pointer-sized boolean value.
Values of this type MUST be either all zero bits or all one bits.
Definition at line 482 of file hardened.h.
typedef enum hardened_bool hardened_bool_t |
This is a boolean type for use in hardened contexts.
The intention is that this is used instead of <stdbool.h>
's #bool, where a higher hamming distance is required between the truthy and the falsey value.
The values below were chosen at random, with some specific restrictions. They have a Hamming Distance of 8, and they are 11-bit values so they can be materialized with a single instruction on RISC-V. They are also specifically not the complement of each other.
typedef enum hardened_byte_bool hardened_byte_bool_t |
A byte-sized hardened boolean.
This type is intended for cases where a byte-sized hardened boolean is required.
The values below were chosen to ensure that the hamming difference between them is greater than 5 and they are not bitwise complements of each other.
enum hardened_bool |
This is a boolean type for use in hardened contexts.
The intention is that this is used instead of <stdbool.h>
's #bool, where a higher hamming distance is required between the truthy and the falsey value.
The values below were chosen at random, with some specific restrictions. They have a Hamming Distance of 8, and they are 11-bit values so they can be materialized with a single instruction on RISC-V. They are also specifically not the complement of each other.
Definition at line 34 of file hardened.h.
enum hardened_byte_bool |
A byte-sized hardened boolean.
This type is intended for cases where a byte-sized hardened boolean is required.
The values below were chosen to ensure that the hamming difference between them is greater than 5 and they are not bitwise complements of each other.
Enumerator | |
---|---|
kHardenedByteBoolTrue | The truthy value. |
kHardenedByteBoolFalse | The falsy value. |
Definition at line 54 of file hardened.h.
|
inline |
Creates a reordering barrier for val
.
barrier32()
takes an argument and discards it, while introducing an "impure" dependency on that value. This forces the compiler to schedule instructions such that the intermediate val
actually appears in a register. Because it is impure, barrier32()
operations will not be reordered past each other or MMIO operations, although they can be reordered past functions if LTO inlines them.
Most compilers will try to reorder arithmetic operations in such a way that they form large basic blocks, since modern microarchitectures can take advantage of instruction-level parallelism. Unfortunately, this means that instructions that we want to interleave with other instructions are likely to get separated; this includes static interleavings, loop-invariant code motion, and some kinds of unroll-and-jam.
For example, given
A compiler will likely reorder this as
The compiler is further entitled to constant-propagate product
. barrier32()
can be used to avoid this:
Note that we must place barriers on the result of the function calls, too, so that the compiler believes that there is a potential dependency between the return value of the function, and the followup value of product
.
This is also useful for avoiding loop reordering:
A sufficiently intelligent compiler might notice that it can linearize this loop; however, the barriers in each loop iteration force a particular order is observed.
val | A value to create a barrier for. |
Definition at line 360 of file hardened.h.
|
inline |
Creates a reordering barrier for val
.
See barrier32()
for detailed semantics.
val | A value to create a barrier for. |
Definition at line 369 of file hardened.h.
|
inline |
Performs a constant-time select.
Returns a
if c
is true; otherwise, returns b
.
This function should be used with one of the comparison functions above; do NOT create c
using an if
or ?:
operation.
c | The condition to test. |
a | The value to return on true. |
b | The value to return on false. |
c ? a : b
. Definition at line 467 of file hardened.h.
|
inline |
Performs a constant-time select.
Returns a
if c
is true; otherwise, returns b
.
This function should be used with one of the comparison functions above; do NOT create c
using an if
or ?:
operation.
c | The condition to test. |
a | The value to return on true. |
b | The value to return on false. |
c ? a : b
. Definition at line 545 of file hardened.h.
|
inline |
Performs constant-time equality.
Returns a == b
as a constant-time boolean.
a == b
. Definition at line 448 of file hardened.h.
|
inline |
Performs constant-time equality.
Returns a == b
as a constant-time boolean.
a == b
. Definition at line 529 of file hardened.h.
|
inline |
Performs constant-time zero equality.
Returns a == 0
as a constant-time boolean.
a == 0
. Definition at line 428 of file hardened.h.
|
inline |
Performs constant-time zero equality.
Returns a == 0
as a constant-time boolean.
a == 0
. Definition at line 517 of file hardened.h.
|
inline |
Performs constant-time unsigned ascending comparison.
Returns a < b
as a constant-time boolean.
a < b
. Definition at line 415 of file hardened.h.
|
inline |
Performs constant-time unsigned ascending comparison.
Returns a < b
as a constant-time boolean.
a < b
. Definition at line 505 of file hardened.h.
|
inline |
Performs constant-time signed comparison to zero.
Returns whether a < 0
, as a constant-time boolean. In other words, this checks if a
is negative, i.e., it's sign bit is set.
a < 0
. Definition at line 400 of file hardened.h.
|
inline |
Performs constant-time signed comparison to zero.
Returns whether a < 0
, as a constant-time boolean. In other words, this checks if a
is negative, i.e., it's sign bit is set.
a < 0
. Definition at line 493 of file hardened.h.
|
inline |
Launders the pointer-sized value val
.
See launder32()
for detailed semantics.
val | A 32-bit integer to launder. |
val
at runtime. Definition at line 265 of file hardened.h.