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