1 /*
2 * Copyright (c) 2018-2023 Arm Limited
3 * Copyright (c) 2020 Linaro Limited
4 * Copyright (c) 2023, Nordic Semiconductor ASA
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include <stddef.h>
20 #include <stdint.h>
21 #include <limits.h>
22 #include <stdbool.h>
23 #include <string.h>
24
25 #include "mcuboot_config/mcuboot_config.h"
26 #include "bootutil/crypto/sha.h"
27
28 #if defined(MCUBOOT_MEASURED_BOOT) || defined(MCUBOOT_DATA_SHARING)
29 #include "bootutil/boot_record.h"
30 #include "bootutil/boot_status.h"
31 #include "bootutil_priv.h"
32 #include "bootutil/image.h"
33 #include "flash_map_backend/flash_map_backend.h"
34
35 #if !defined(MCUBOOT_CUSTOM_DATA_SHARING_FUNCTION)
36 /**
37 * @var shared_memory_init_done
38 *
39 * @brief Indicates whether shared memory area was already initialized.
40 *
41 */
42 static bool shared_memory_init_done;
43
44 /* See in boot_record.h */
45 int
boot_add_data_to_shared_area(uint8_t major_type,uint16_t minor_type,size_t size,const uint8_t * data)46 boot_add_data_to_shared_area(uint8_t major_type,
47 uint16_t minor_type,
48 size_t size,
49 const uint8_t *data)
50 {
51 struct shared_data_tlv_entry tlv_entry = {0};
52 struct shared_boot_data *boot_data;
53 uint16_t boot_data_size;
54 uintptr_t tlv_end, offset;
55
56 if (data == NULL) {
57 return SHARED_MEMORY_GEN_ERROR;
58 }
59
60 boot_data = (struct shared_boot_data *)MCUBOOT_SHARED_DATA_BASE;
61
62 /* Check whether first time to call this function. If does then initialise
63 * shared data area.
64 */
65 if (!shared_memory_init_done) {
66 memset((void *)MCUBOOT_SHARED_DATA_BASE, 0, MCUBOOT_SHARED_DATA_SIZE);
67 boot_data->header.tlv_magic = SHARED_DATA_TLV_INFO_MAGIC;
68 boot_data->header.tlv_tot_len = SHARED_DATA_HEADER_SIZE;
69 shared_memory_init_done = true;
70 }
71
72 /* Check whether TLV entry is already added.
73 * Get the boundaries of TLV section
74 */
75 tlv_end = MCUBOOT_SHARED_DATA_BASE + boot_data->header.tlv_tot_len;
76 offset = MCUBOOT_SHARED_DATA_BASE + SHARED_DATA_HEADER_SIZE;
77
78 /* Iterates over the TLV section looks for the same entry if found then
79 * returns with error: SHARED_MEMORY_OVERWRITE
80 */
81 while (offset < tlv_end) {
82 /* Create local copy to avoid unaligned access */
83 memcpy(&tlv_entry, (const void *)offset, SHARED_DATA_ENTRY_HEADER_SIZE);
84 if (GET_MAJOR(tlv_entry.tlv_type) == major_type &&
85 GET_MINOR(tlv_entry.tlv_type) == minor_type) {
86 return SHARED_MEMORY_OVERWRITE;
87 }
88
89 offset += SHARED_DATA_ENTRY_SIZE(tlv_entry.tlv_len);
90 }
91
92 /* Add TLV entry */
93 tlv_entry.tlv_type = SET_TLV_TYPE(major_type, minor_type);
94 tlv_entry.tlv_len = size;
95
96 if (!boot_u16_safe_add(&boot_data_size, boot_data->header.tlv_tot_len,
97 SHARED_DATA_ENTRY_SIZE(size))) {
98 return SHARED_MEMORY_GEN_ERROR;
99 }
100
101 /* Verify overflow of shared area */
102 if (boot_data_size > MCUBOOT_SHARED_DATA_SIZE) {
103 return SHARED_MEMORY_OVERFLOW;
104 }
105
106 offset = tlv_end;
107 memcpy((void *)offset, &tlv_entry, SHARED_DATA_ENTRY_HEADER_SIZE);
108
109 offset += SHARED_DATA_ENTRY_HEADER_SIZE;
110 memcpy((void *)offset, data, size);
111
112 boot_data->header.tlv_tot_len += SHARED_DATA_ENTRY_SIZE(size);
113
114 return SHARED_MEMORY_OK;
115 }
116 #endif /* MCUBOOT_MEASURED_BOOT OR MCUBOOT_DATA_SHARING */
117 #endif /* !MCUBOOT_CUSTOM_DATA_SHARING_FUNCTION */
118
119 #ifdef MCUBOOT_MEASURED_BOOT
120 /* See in boot_record.h */
121 int
boot_save_boot_status(uint8_t sw_module,const struct image_header * hdr,const struct flash_area * fap)122 boot_save_boot_status(uint8_t sw_module,
123 const struct image_header *hdr,
124 const struct flash_area *fap)
125 {
126
127 struct image_tlv_iter it;
128 uint32_t offset;
129 uint16_t len;
130 uint16_t type;
131 uint16_t ias_minor;
132 size_t record_len = 0;
133 uint8_t image_hash[IMAGE_HASH_SIZE];
134 uint8_t buf[MAX_BOOT_RECORD_SZ];
135 bool boot_record_found = false;
136 bool hash_found = false;
137 int rc;
138
139 /* Manifest data is concatenated to the end of the image.
140 * It is encoded in TLV format.
141 */
142
143 rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
144 if (rc) {
145 return -1;
146 }
147
148 /* Traverse through the TLV area to find the boot record
149 * and image hash TLVs.
150 */
151 while (true) {
152 rc = bootutil_tlv_iter_next(&it, &offset, &len, &type);
153 if (rc < 0) {
154 return -1;
155 } else if (rc > 0) {
156 break;
157 }
158
159 if (type == IMAGE_TLV_BOOT_RECORD) {
160 if (len > sizeof(buf)) {
161 return -1;
162 }
163 rc = flash_area_read(fap, offset, buf, len);
164 if (rc) {
165 return -1;
166 }
167
168 record_len = len;
169 boot_record_found = true;
170
171 } else if (type == EXPECTED_HASH_TLV) {
172 /* Get the image's hash value from the manifest section. */
173 if (len > sizeof(image_hash)) {
174 return -1;
175 }
176 rc = flash_area_read(fap, offset, image_hash, len);
177 if (rc) {
178 return -1;
179 }
180
181 hash_found = true;
182
183 /* The boot record TLV is part of the protected TLV area which is
184 * located before the other parts of the TLV area (including the
185 * image hash) so at this point it is okay to break the loop
186 * as the boot record TLV should have already been found.
187 */
188 break;
189 }
190 }
191
192 if (!boot_record_found || !hash_found) {
193 return -1;
194 }
195
196 /* Ensure that we have enough in the record for the hash. This
197 * prevents an underflow in the calculation below.
198 */
199 if (record_len < sizeof(image_hash)) {
200 return -1;
201 }
202
203 /* Update the measurement value (hash of the image) data item in the
204 * boot record. It is always the last item in the structure to make
205 * it easy to calculate its position.
206 * The image hash is computed over the image header, the image itself and
207 * the protected TLV area (which should already include the image hash as
208 * part of the boot record TLV). For this reason this field has been
209 * filled with zeros during the image signing process.
210 */
211 offset = record_len - sizeof(image_hash);
212 /* The size of 'buf' has already been checked when
213 * the BOOT_RECORD TLV was read, it won't overflow.
214 */
215 memcpy(buf + offset, image_hash, sizeof(image_hash));
216
217 /* Add the CBOR encoded boot record to the shared data area. */
218 ias_minor = SET_IAS_MINOR(sw_module, SW_BOOT_RECORD);
219 rc = boot_add_data_to_shared_area(TLV_MAJOR_IAS,
220 ias_minor,
221 record_len,
222 buf);
223 if (rc != SHARED_MEMORY_OK) {
224 return rc;
225 }
226
227 return 0;
228 }
229 #endif /* MCUBOOT_MEASURED_BOOT */
230
231 #ifdef MCUBOOT_DATA_SHARING_BOOTINFO
boot_save_shared_data(const struct image_header * hdr,const struct flash_area * fap,const uint8_t slot,const int max_app_size)232 int boot_save_shared_data(const struct image_header *hdr, const struct flash_area *fap,
233 const uint8_t slot, const int max_app_size)
234 {
235 int rc;
236
237 #if defined(MCUBOOT_SINGLE_APPLICATION_SLOT)
238 uint8_t mode = MCUBOOT_MODE_SINGLE_SLOT;
239 #elif defined(MCUBOOT_SWAP_USING_SCRATCH)
240 uint8_t mode = MCUBOOT_MODE_SWAP_USING_SCRATCH;
241 #elif defined(MCUBOOT_OVERWRITE_ONLY)
242 uint8_t mode = MCUBOOT_MODE_UPGRADE_ONLY;
243 #elif defined(MCUBOOT_SWAP_USING_MOVE)
244 uint8_t mode = MCUBOOT_MODE_SWAP_USING_MOVE;
245 #elif defined(MCUBOOT_DIRECT_XIP)
246 #if defined(MCUBOOT_DIRECT_XIP_REVERT)
247 uint8_t mode = MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT;
248 #else
249 uint8_t mode = MCUBOOT_MODE_DIRECT_XIP;
250 #endif
251 #elif defined(MCUBOOT_RAM_LOAD)
252 uint8_t mode = MCUBOOT_MODE_RAM_LOAD;
253 #elif defined(MCUBOOT_FIRMWARE_LOADER)
254 uint8_t mode = MCUBOOT_MODE_FIRMWARE_LOADER;
255 #else
256 #error "Unknown mcuboot operating mode"
257 #endif
258
259 #if defined(MCUBOOT_SIGN_RSA)
260 uint8_t signature_type = MCUBOOT_SIGNATURE_TYPE_RSA;
261 #elif defined(MCUBOOT_SIGN_EC256)
262 uint8_t signature_type = MCUBOOT_SIGNATURE_TYPE_ECDSA_P256;
263 #elif defined(MCUBOOT_SIGN_ED25519)
264 uint8_t signature_type = MCUBOOT_SIGNATURE_TYPE_ED25519;
265 #else
266 uint8_t signature_type = MCUBOOT_SIGNATURE_TYPE_NONE;
267 #endif
268
269 #if defined(MCUBOOT_SERIAL_RECOVERY)
270 uint8_t recovery = MCUBOOT_RECOVERY_MODE_SERIAL_RECOVERY;
271 #elif defined(MCUBOOT_USB_DFU)
272 uint8_t recovery = MCUBOOT_RECOVERY_MODE_DFU;
273 #else
274 uint8_t recovery = MCUBOOT_RECOVERY_MODE_NONE;
275 #endif
276
277 #if defined(MCUBOOT_VERSION_AVAILABLE)
278 struct image_version mcuboot_version = {
279 .iv_major = MCUBOOT_VERSION_MAJOR,
280 .iv_minor = MCUBOOT_VERSION_MINOR,
281
282 #if defined(MCUBOOT_VERSION_PATCHLEVEL)
283 .iv_revision = MCUBOOT_VERSION_PATCHLEVEL,
284 #else
285 .iv_revision = 0,
286 #endif
287
288 #if defined(MCUBOOT_VERSION_TWEAK)
289 .iv_build_num = MCUBOOT_VERSION_TWEAK,
290 #else
291 .iv_build_num = 0,
292 #endif
293 };
294 #endif
295
296 /* Write out all fields */
297 rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO, BLINFO_MODE,
298 sizeof(mode), &mode);
299
300 if (!rc) {
301 rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
302 BLINFO_SIGNATURE_TYPE,
303 sizeof(signature_type),
304 &signature_type);
305 }
306
307 if (!rc) {
308 rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
309 BLINFO_RECOVERY,
310 sizeof(recovery), &recovery);
311 }
312
313 if (!rc) {
314 rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
315 BLINFO_RUNNING_SLOT,
316 sizeof(slot), (void *)&slot);
317 }
318
319 #if defined(MCUBOOT_VERSION_AVAILABLE)
320 if (!rc) {
321 rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
322 BLINFO_BOOTLOADER_VERSION,
323 sizeof(mcuboot_version),
324 (void *)&mcuboot_version);
325 }
326 #endif
327
328 if (!rc) {
329 rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
330 BLINFO_MAX_APPLICATION_SIZE,
331 sizeof(max_app_size),
332 (void *)&max_app_size);
333 }
334
335 return rc;
336 }
337 #endif /* MCUBOOT_DATA_SHARING_BOOTINFO */
338