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_DATA_SHARING_BOOTINFO)
36 static bool saved_bootinfo = false;
37 #endif
38 
39 #if !defined(MCUBOOT_CUSTOM_DATA_SHARING_FUNCTION)
40 /**
41  * @var shared_memory_init_done
42  *
43  * @brief Indicates whether shared memory area was already initialized.
44  *
45  */
46 static bool shared_memory_init_done;
47 
48 /* See in boot_record.h */
49 int
boot_add_data_to_shared_area(uint8_t major_type,uint16_t minor_type,size_t size,const uint8_t * data)50 boot_add_data_to_shared_area(uint8_t        major_type,
51                              uint16_t       minor_type,
52                              size_t         size,
53                              const uint8_t *data)
54 {
55     struct shared_data_tlv_entry tlv_entry = {0};
56     struct shared_boot_data *boot_data;
57     uint16_t boot_data_size;
58     uintptr_t tlv_end, offset;
59 
60     if (data == NULL) {
61         return SHARED_MEMORY_GEN_ERROR;
62     }
63 
64     boot_data = (struct shared_boot_data *)MCUBOOT_SHARED_DATA_BASE;
65 
66     /* Check whether first time to call this function. If does then initialise
67      * shared data area.
68      */
69     if (!shared_memory_init_done) {
70         memset((void *)MCUBOOT_SHARED_DATA_BASE, 0, MCUBOOT_SHARED_DATA_SIZE);
71         boot_data->header.tlv_magic   = SHARED_DATA_TLV_INFO_MAGIC;
72         boot_data->header.tlv_tot_len = SHARED_DATA_HEADER_SIZE;
73         shared_memory_init_done = true;
74     }
75 
76     /* Check whether TLV entry is already added.
77      * Get the boundaries of TLV section
78      */
79     tlv_end = MCUBOOT_SHARED_DATA_BASE + boot_data->header.tlv_tot_len;
80     offset  = MCUBOOT_SHARED_DATA_BASE + SHARED_DATA_HEADER_SIZE;
81 
82     /* Iterates over the TLV section looks for the same entry if found then
83      * returns with error: SHARED_MEMORY_OVERWRITE
84      */
85     while (offset < tlv_end) {
86         /* Create local copy to avoid unaligned access */
87         memcpy(&tlv_entry, (const void *)offset, SHARED_DATA_ENTRY_HEADER_SIZE);
88         if (GET_MAJOR(tlv_entry.tlv_type) == major_type &&
89             GET_MINOR(tlv_entry.tlv_type) == minor_type) {
90             return SHARED_MEMORY_OVERWRITE;
91         }
92 
93         offset += SHARED_DATA_ENTRY_SIZE(tlv_entry.tlv_len);
94     }
95 
96     /* Add TLV entry */
97     tlv_entry.tlv_type = SET_TLV_TYPE(major_type, minor_type);
98     tlv_entry.tlv_len  = size;
99 
100     if (!boot_u16_safe_add(&boot_data_size, boot_data->header.tlv_tot_len,
101                            SHARED_DATA_ENTRY_SIZE(size))) {
102         return SHARED_MEMORY_GEN_ERROR;
103     }
104 
105     /* Verify overflow of shared area */
106     if (boot_data_size > MCUBOOT_SHARED_DATA_SIZE) {
107         return SHARED_MEMORY_OVERFLOW;
108     }
109 
110     offset = tlv_end;
111     memcpy((void *)offset, &tlv_entry, SHARED_DATA_ENTRY_HEADER_SIZE);
112 
113     offset += SHARED_DATA_ENTRY_HEADER_SIZE;
114     memcpy((void *)offset, data, size);
115 
116     boot_data->header.tlv_tot_len += SHARED_DATA_ENTRY_SIZE(size);
117 
118     return SHARED_MEMORY_OK;
119 }
120 #endif /* MCUBOOT_MEASURED_BOOT OR MCUBOOT_DATA_SHARING */
121 #endif /* !MCUBOOT_CUSTOM_DATA_SHARING_FUNCTION */
122 
123 #ifdef MCUBOOT_MEASURED_BOOT
124 /* See in boot_record.h */
125 int
boot_save_boot_status(uint8_t sw_module,const struct image_header * hdr,const struct flash_area * fap)126 boot_save_boot_status(uint8_t sw_module,
127                       const struct image_header *hdr,
128                       const struct flash_area *fap)
129 {
130 
131     struct image_tlv_iter it;
132     uint32_t offset;
133     uint16_t len;
134     uint16_t type;
135     uint16_t ias_minor;
136     size_t record_len = 0;
137     uint8_t image_hash[IMAGE_HASH_SIZE];
138     uint8_t buf[MAX_BOOT_RECORD_SZ];
139     bool boot_record_found = false;
140     bool hash_found = false;
141     int rc;
142 
143     /* Manifest data is concatenated to the end of the image.
144      * It is encoded in TLV format.
145      */
146 #if defined(MCUBOOT_SWAP_USING_OFFSET)
147     it.start_off = 0;
148 #endif
149 
150     rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
151     if (rc) {
152         return -1;
153     }
154 
155     /* Traverse through the TLV area to find the boot record
156      * and image hash TLVs.
157      */
158     while (true) {
159         rc = bootutil_tlv_iter_next(&it, &offset, &len, &type);
160         if (rc < 0) {
161             return -1;
162         } else if (rc > 0) {
163             break;
164         }
165 
166         if (type == IMAGE_TLV_BOOT_RECORD) {
167             if (len > sizeof(buf)) {
168                 return -1;
169             }
170             rc = flash_area_read(fap, offset, buf, len);
171             if (rc) {
172                 return -1;
173             }
174 
175             record_len = len;
176             boot_record_found = true;
177 
178         } else if (type == EXPECTED_HASH_TLV) {
179             /* Get the image's hash value from the manifest section. */
180             if (len > sizeof(image_hash)) {
181                 return -1;
182             }
183             rc = flash_area_read(fap, offset, image_hash, len);
184             if (rc) {
185                 return -1;
186             }
187 
188             hash_found = true;
189 
190             /* The boot record TLV is part of the protected TLV area which is
191              * located before the other parts of the TLV area (including the
192              * image hash) so at this point it is okay to break the loop
193              * as the boot record TLV should have already been found.
194              */
195             break;
196         }
197     }
198 
199     if (!boot_record_found || !hash_found) {
200         return -1;
201     }
202 
203     /* Ensure that we have enough in the record for the hash.  This
204      * prevents an underflow in the calculation below.
205      */
206     if (record_len < sizeof(image_hash)) {
207 	return -1;
208     }
209 
210     /* Update the measurement value (hash of the image) data item in the
211      * boot record. It is always the last item in the structure to make
212      * it easy to calculate its position.
213      * The image hash is computed over the image header, the image itself and
214      * the protected TLV area (which should already include the image hash as
215      * part of the boot record TLV). For this reason this field has been
216      * filled with zeros during the image signing process.
217      */
218     offset = record_len - sizeof(image_hash);
219     /* The size of 'buf' has already been checked when
220      * the BOOT_RECORD TLV was read, it won't overflow.
221      */
222     memcpy(buf + offset, image_hash, sizeof(image_hash));
223 
224     /* Add the CBOR encoded boot record to the shared data area. */
225     ias_minor = SET_IAS_MINOR(sw_module, SW_BOOT_RECORD);
226     rc = boot_add_data_to_shared_area(TLV_MAJOR_IAS,
227                                       ias_minor,
228                                       record_len,
229                                       buf);
230     if (rc != SHARED_MEMORY_OK) {
231         return rc;
232     }
233 
234     return 0;
235 }
236 #endif /* MCUBOOT_MEASURED_BOOT */
237 
238 #ifdef MCUBOOT_DATA_SHARING_BOOTINFO
boot_save_shared_data(const struct image_header * hdr,const struct flash_area * fap,const uint8_t slot,const struct image_max_size * max_app_sizes)239 int boot_save_shared_data(const struct image_header *hdr, const struct flash_area *fap,
240                           const uint8_t slot, const struct image_max_size *max_app_sizes)
241 {
242     int rc;
243 #if !defined(MCUBOOT_SINGLE_APPLICATION_SLOT)
244     uint8_t image = 0;
245 #endif
246 
247 #if defined(MCUBOOT_SINGLE_APPLICATION_SLOT)
248     uint8_t mode = MCUBOOT_MODE_SINGLE_SLOT;
249 #elif defined(MCUBOOT_SWAP_USING_SCRATCH)
250     uint8_t mode = MCUBOOT_MODE_SWAP_USING_SCRATCH;
251 #elif defined(MCUBOOT_OVERWRITE_ONLY)
252     uint8_t mode = MCUBOOT_MODE_UPGRADE_ONLY;
253 #elif defined(MCUBOOT_SWAP_USING_MOVE)
254     uint8_t mode = MCUBOOT_MODE_SWAP_USING_MOVE;
255 #elif defined(MCUBOOT_SWAP_USING_OFFSET)
256     uint8_t mode = MCUBOOT_MODE_SWAP_USING_OFFSET;
257 #elif defined(MCUBOOT_DIRECT_XIP)
258 #if defined(MCUBOOT_DIRECT_XIP_REVERT)
259     uint8_t mode = MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT;
260 #else
261     uint8_t mode = MCUBOOT_MODE_DIRECT_XIP;
262 #endif
263 #elif defined(MCUBOOT_RAM_LOAD)
264     uint8_t mode = MCUBOOT_MODE_RAM_LOAD;
265 #elif defined(MCUBOOT_FIRMWARE_LOADER)
266     uint8_t mode = MCUBOOT_MODE_FIRMWARE_LOADER;
267 #elif defined(MCUBOOT_SINGLE_APPLICATION_SLOT_RAM_LOAD)
268     uint8_t mode = MCUBOOT_MODE_SINGLE_SLOT_RAM_LOAD;
269 #else
270 #error "Unknown mcuboot operating mode"
271 #endif
272 
273 #if defined(MCUBOOT_SIGN_RSA)
274     uint8_t signature_type = MCUBOOT_SIGNATURE_TYPE_RSA;
275 #elif defined(MCUBOOT_SIGN_EC256)
276     uint8_t signature_type = MCUBOOT_SIGNATURE_TYPE_ECDSA_P256;
277 #elif defined(MCUBOOT_SIGN_ED25519)
278     uint8_t signature_type = MCUBOOT_SIGNATURE_TYPE_ED25519;
279 #else
280     uint8_t signature_type = MCUBOOT_SIGNATURE_TYPE_NONE;
281 #endif
282 
283 #if defined(MCUBOOT_SERIAL_RECOVERY)
284     uint8_t recovery = MCUBOOT_RECOVERY_MODE_SERIAL_RECOVERY;
285 #elif defined(MCUBOOT_USB_DFU)
286     uint8_t recovery = MCUBOOT_RECOVERY_MODE_DFU;
287 #else
288     uint8_t recovery = MCUBOOT_RECOVERY_MODE_NONE;
289 #endif
290 
291 #if defined(MCUBOOT_VERSION_AVAILABLE)
292     struct image_version mcuboot_version = {
293         .iv_major = MCUBOOT_VERSION_MAJOR,
294         .iv_minor = MCUBOOT_VERSION_MINOR,
295 
296 #if defined(MCUBOOT_VERSION_PATCHLEVEL)
297         .iv_revision = MCUBOOT_VERSION_PATCHLEVEL,
298 #else
299         .iv_revision = 0,
300 #endif
301 
302 #if defined(MCUBOOT_VERSION_TWEAK)
303         .iv_build_num = MCUBOOT_VERSION_TWEAK,
304 #else
305         .iv_build_num = 0,
306 #endif
307     };
308 #endif
309 
310     if (saved_bootinfo) {
311         /* Boot info has already been saved, nothing to do */
312         return 0;
313     }
314 
315     /* Write out all fields */
316     rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO, BLINFO_MODE,
317                                       sizeof(mode), &mode);
318 
319     if (!rc) {
320         rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
321                                           BLINFO_SIGNATURE_TYPE,
322                                           sizeof(signature_type),
323                                           &signature_type);
324     }
325 
326     if (!rc) {
327         rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
328                                           BLINFO_RECOVERY,
329                                           sizeof(recovery), &recovery);
330     }
331 
332 #if !defined(MCUBOOT_SINGLE_APPLICATION_SLOT)
333     if (!rc) {
334         rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
335                                           BLINFO_RUNNING_SLOT,
336                                           sizeof(slot), (void *)&slot);
337     }
338 #endif
339 
340 #if defined(MCUBOOT_VERSION_AVAILABLE)
341     if (!rc) {
342         rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
343                                           BLINFO_BOOTLOADER_VERSION,
344                                           sizeof(mcuboot_version),
345                                           (void *)&mcuboot_version);
346     }
347 #endif
348 
349 #if !defined(MCUBOOT_SINGLE_APPLICATION_SLOT)
350     while (image < BOOT_IMAGE_NUMBER && !rc) {
351         if (max_app_sizes[image].calculated == true) {
352             rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
353                                               (BLINFO_MAX_APPLICATION_SIZE + image),
354                                               sizeof(max_app_sizes[image].max_size),
355                                               (void *)&max_app_sizes[image].max_size);
356 
357         }
358 
359         ++image;
360     }
361 #endif
362 
363     if (!rc) {
364         saved_bootinfo = true;
365     }
366 
367     return rc;
368 }
369 #endif /* MCUBOOT_DATA_SHARING_BOOTINFO */
370