1 /*
2  * Copyright (c) 2019 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_MISC_SPECULATION_H
8 #define ZEPHYR_MISC_SPECULATION_H
9 
10 #include <zephyr/types.h>
11 
12 /**
13  * Sanitize an array index against bounds check bypass attacks aka the
14  * Spectre V1 vulnerability.
15  *
16  * CPUs with speculative execution may speculate past any size checks and
17  * leak confidential data due to analysis of micro-architectural properties.
18  * This will unconditionally truncate any out-of-bounds indexes to
19  * zero in the speculative execution path using bit twiddling instead of
20  * any branch instructions.
21  *
22  * Example usage:
23  *
24  * if (index < size) {
25  *     index = k_array_index_sanitize(index, size);
26  *     data = array[index];
27  * }
28  *
29  * @param index Untrusted array index which has been validated, but not used
30  * @param array_size Size of the array
31  * @return The original index value if < size, or 0
32  */
k_array_index_sanitize(uint32_t index,uint32_t array_size)33 static inline uint32_t k_array_index_sanitize(uint32_t index, uint32_t array_size)
34 {
35 #ifdef CONFIG_BOUNDS_CHECK_BYPASS_MITIGATION
36 	int32_t signed_index = index, signed_array_size = array_size;
37 
38 	/* Take the difference between index and max.
39 	 * A proper value will result in a negative result. We also AND in
40 	 * the complement of index, so that we automatically reject any large
41 	 * indexes which would wrap around the difference calculation.
42 	 *
43 	 * Sign-extend just the sign bit to produce a mask of all 1s (accept)
44 	 * or all 0s (truncate).
45 	 */
46 	uint32_t mask = ((signed_index - signed_array_size) & ~signed_index) >> 31;
47 
48 	return index & mask;
49 #else
50 	ARG_UNUSED(array_size);
51 
52 	return index;
53 #endif /* CONFIG_BOUNDS_CHECK_BYPASS_MITIGATION */
54 }
55 #endif /* ZEPHYR_MISC_SPECULATION_H */
56