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