1 /*
2 * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include <stdint.h>
9 #include <string.h>
10 #include "array.h"
11 #include "tfm_boot_status.h"
12 #include "region_defs.h"
13 #include "psa_manifest/pid.h"
14 #include "internal_status_code.h"
15 #include "utilities.h"
16 #include "psa/service.h"
17 #include "thread.h"
18 #include "spm.h"
19 #include "load/partition_defs.h"
20 #include "tfm_hal_isolation.h"
21 #include "tfm_plat_shared_measurement_data.h"
22
23 /*!
24 * \def BOOT_DATA_VALID
25 *
26 * \brief Indicates that shared data between bootloader and runtime firmware was
27 * passed the sanity check with success.
28 */
29 #define BOOT_DATA_VALID (1u)
30
31 /*!
32 * \def BOOT_DATA_INVALID
33 *
34 * \brief Indicates that shared data between bootloader and runtime firmware was
35 * failed on sanity check.
36 */
37 #define BOOT_DATA_INVALID (0u)
38
39 /*!
40 * \var is_boot_data_valid
41 *
42 * \brief Indicates the status of shared data between bootloader and runtime
43 * firmware
44 */
45 static uint32_t is_boot_data_valid = BOOT_DATA_INVALID;
46
47 /*!
48 * \struct boot_data_access_policy
49 *
50 * \brief Defines the access policy of secure partitions to data items in shared
51 * data area (between bootloader and runtime firmware).
52 */
53 struct boot_data_access_policy {
54 int32_t partition_id;
55 uint32_t major_type;
56 };
57
58 /*!
59 * \var access_policy_table
60 *
61 * \brief Contains the partition_id and major_type assignments. This describes
62 * which secure partition is allowed to access which data item
63 * (identified by major_type).
64 */
65 static const struct boot_data_access_policy access_policy_table[] = {
66 /*
67 * IAR won't accept zero element array definition, so an invalid element
68 * is always defined here.
69 */
70 {INVALID_PARTITION_ID, TLV_MAJOR_INVALID},
71 #ifdef TFM_PARTITION_INITIAL_ATTESTATION
72 {TFM_SP_INITIAL_ATTESTATION, TLV_MAJOR_IAS},
73 #endif
74 #ifdef TFM_PARTITION_FIRMWARE_UPDATE
75 {TFM_SP_FWU, TLV_MAJOR_FWU},
76 #endif
77 #ifdef TFM_PARTITION_MEASURED_BOOT
78 {TFM_SP_MEASURED_BOOT, TLV_MAJOR_MBS},
79 #endif
80 #ifdef TFM_PARTITION_DPE
81 {TFM_SP_DPE, TLV_MAJOR_MBS},
82 #endif
83 };
84
85 /*!
86 * \brief Verify the access right of the active secure partition to the
87 * specified data type in the shared data area.
88 *
89 * \param[in] major_type Data type identifier.
90 *
91 * \return Returns 0 in case of success, otherwise -1.
92 */
tfm_core_check_boot_data_access_policy(uint8_t major_type)93 static int32_t tfm_core_check_boot_data_access_policy(uint8_t major_type)
94 {
95 int32_t partition_id;
96 uint32_t i;
97 int32_t rc = -1;
98 const uint32_t array_size = ARRAY_SIZE(access_policy_table);
99
100 partition_id = tfm_spm_partition_get_running_partition_id();
101
102 /*
103 * The first element of the access_policy_table is an invalid element,
104 * which isn't need to be checked, that's why the iteration
105 * starts from i=1.
106 */
107 for (i = 1; i < array_size; ++i) {
108 if (partition_id == access_policy_table[i].partition_id) {
109 if (major_type == access_policy_table[i].major_type) {
110 rc = 0;
111 break;
112 }
113 }
114 }
115
116 return rc;
117 }
118
tfm_core_validate_boot_data(void)119 void tfm_core_validate_boot_data(void)
120 {
121 #ifdef BOOT_DATA_AVAILABLE
122 struct tfm_boot_data *boot_data;
123 const uintptr_t data_base = tfm_plat_get_shared_measurement_data_base();
124 const uintptr_t data_limit = data_base + tfm_plat_get_shared_measurement_data_size() - 1;
125
126 const bool overlapping_with_ns =
127 ((data_base >= NS_DATA_START) && (data_base <= NS_DATA_LIMIT)) ||
128 ((data_limit >= NS_DATA_START) && (data_limit <= NS_DATA_LIMIT));
129 if (overlapping_with_ns) {
130 assert(false);
131 /* Not setting BOOT_DATA_VALID */
132 return;
133 }
134
135 boot_data = (struct tfm_boot_data *)data_base;
136
137 if (boot_data->header.tlv_magic == SHARED_DATA_TLV_INFO_MAGIC) {
138 is_boot_data_valid = BOOT_DATA_VALID;
139 }
140 #else
141 is_boot_data_valid = BOOT_DATA_VALID;
142 #endif /* BOOT_DATA_AVAILABLE */
143 }
144
tfm_core_get_boot_data_handler(uint32_t args[])145 void tfm_core_get_boot_data_handler(uint32_t args[])
146 {
147 uint8_t tlv_major = (uint8_t)args[0];
148 uint8_t *buf_start = (uint8_t *)args[1];
149 uint16_t buf_size = (uint16_t)args[2];
150 struct tfm_boot_data *boot_data;
151 #ifdef BOOT_DATA_AVAILABLE
152 uint8_t *ptr;
153 struct shared_data_tlv_entry tlv_entry;
154 uintptr_t tlv_end, offset;
155 size_t next_tlv_offset = 0;
156 #endif /* BOOT_DATA_AVAILABLE */
157 const struct partition_t *curr_partition = GET_CURRENT_COMPONENT();
158 fih_int fih_rc = FIH_FAILURE;
159 const uintptr_t data_base = tfm_plat_get_shared_measurement_data_base();
160
161 FIH_CALL(tfm_hal_memory_check, fih_rc,
162 curr_partition->boundary, (uintptr_t)buf_start,
163 buf_size, TFM_HAL_ACCESS_READWRITE);
164 if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
165 args[0] = (uint32_t)PSA_ERROR_INVALID_ARGUMENT;
166 return;
167 }
168
169 if (is_boot_data_valid != BOOT_DATA_VALID) {
170 args[0] = (uint32_t)PSA_ERROR_INVALID_ARGUMENT;
171 return;
172 }
173
174 /* Check whether caller has access right to given tlv_major_type */
175 if (tfm_core_check_boot_data_access_policy(tlv_major)) {
176 args[0] = (uint32_t)PSA_ERROR_INVALID_ARGUMENT;
177 return;
178 }
179
180 #ifdef BOOT_DATA_AVAILABLE
181 /* Get the boundaries of TLV section */
182 boot_data = (struct tfm_boot_data *)data_base;
183 tlv_end = data_base + boot_data->header.tlv_tot_len;
184 offset = data_base + SHARED_DATA_HEADER_SIZE;
185 #endif /* BOOT_DATA_AVAILABLE */
186
187 /* Add header to output buffer as well */
188 if (buf_size < SHARED_DATA_HEADER_SIZE) {
189 args[0] = (uint32_t)PSA_ERROR_INVALID_ARGUMENT;
190 return;
191 } else {
192 boot_data = (struct tfm_boot_data *)buf_start;
193 boot_data->header.tlv_magic = SHARED_DATA_TLV_INFO_MAGIC;
194 boot_data->header.tlv_tot_len = SHARED_DATA_HEADER_SIZE;
195 }
196
197 #ifdef BOOT_DATA_AVAILABLE
198 ptr = boot_data->data;
199 /* Iterates over the TLV section and copy TLVs with requested major
200 * type to the provided buffer.
201 */
202 for (; offset < tlv_end; offset += next_tlv_offset) {
203 /* Create local copy to avoid unaligned access */
204 (void)spm_memcpy(&tlv_entry, (const void *)offset,
205 SHARED_DATA_ENTRY_HEADER_SIZE);
206
207 next_tlv_offset = SHARED_DATA_ENTRY_HEADER_SIZE + tlv_entry.tlv_len;
208
209 if (GET_MAJOR(tlv_entry.tlv_type) == tlv_major) {
210 /* Check buffer overflow */
211 if (((ptr - buf_start) + next_tlv_offset) > buf_size) {
212 args[0] = (uint32_t)PSA_ERROR_INVALID_ARGUMENT;
213 return;
214 }
215
216 (void)spm_memcpy(ptr, (const void *)offset, next_tlv_offset);
217 ptr += next_tlv_offset;
218 boot_data->header.tlv_tot_len += next_tlv_offset;
219 }
220 }
221 #endif /* BOOT_DATA_AVAILABLE */
222
223 args[0] = (uint32_t)PSA_SUCCESS;
224 return;
225 }
226