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