blob: c715bb848fb6a609ffc88b2284c1b97f90f5099b [file] [log] [blame]
Christopher Collins92ea77f2016-12-12 15:59:26 -08001/*
David Brownaac71112020-02-03 16:13:42 -07002 * SPDX-License-Identifier: Apache-2.0
3 *
4 * Copyright (c) 2017-2019 Linaro LTD
5 * Copyright (c) 2016-2019 JUUL Labs
Raef Colese8fe6cf2020-05-26 13:07:40 +01006 * Copyright (c) 2019-2020 Arm Limited
David Brownaac71112020-02-03 16:13:42 -07007 *
8 * Original license:
9 *
Christopher Collins92ea77f2016-12-12 15:59:26 -080010 * Licensed to the Apache Software Foundation (ASF) under one
11 * or more contributor license agreements. See the NOTICE file
12 * distributed with this work for additional information
13 * regarding copyright ownership. The ASF licenses this file
14 * to you under the Apache License, Version 2.0 (the
15 * "License"); you may not use this file except in compliance
16 * with the License. You may obtain a copy of the License at
17 *
18 * http://www.apache.org/licenses/LICENSE-2.0
19 *
20 * Unless required by applicable law or agreed to in writing,
21 * software distributed under the License is distributed on an
22 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
23 * KIND, either express or implied. See the License for the
24 * specific language governing permissions and limitations
25 * under the License.
26 */
27
Christopher Collins92ea77f2016-12-12 15:59:26 -080028#include <string.h>
29#include <inttypes.h>
Fabio Utziga0bc9b52017-06-28 09:19:55 -030030#include <stddef.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080031
Christopher Collins92ea77f2016-12-12 15:59:26 -080032#include "sysflash/sysflash.h"
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +020033#include "flash_map_backend/flash_map_backend.h"
34
Christopher Collins92ea77f2016-12-12 15:59:26 -080035#include "bootutil/image.h"
36#include "bootutil/bootutil.h"
37#include "bootutil_priv.h"
Dominik Ermel23a7a2e2023-02-10 11:15:17 +000038#include "bootutil_misc.h"
Fabio Utzig7ebb7c22017-04-26 10:59:31 -030039#include "bootutil/bootutil_log.h"
Raef Colese8fe6cf2020-05-26 13:07:40 +010040#include "bootutil/fault_injection_hardening.h"
Fabio Utzigba829042018-09-18 08:29:34 -030041#ifdef MCUBOOT_ENC_IMAGES
42#include "bootutil/enc_key.h"
43#endif
Fabio Utzig7ebb7c22017-04-26 10:59:31 -030044
Carlos Falgueras GarcĂ­aa4b4b0f2021-06-22 10:00:22 +020045BOOT_LOG_MODULE_DECLARE(mcuboot);
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +010046
Fabio Utzig10ee6482019-08-01 12:04:52 -030047/* Currently only used by imgmgr */
Christopher Collins92ea77f2016-12-12 15:59:26 -080048int boot_current_slot;
49
Raef Colese8fe6cf2020-05-26 13:07:40 +010050/**
51 * @brief Determine if the data at two memory addresses is equal
52 *
53 * @param s1 The first memory region to compare.
54 * @param s2 The second memory region to compare.
55 * @param n The amount of bytes to compare.
56 *
57 * @note This function does not comply with the specification of memcmp,
58 * so should not be considered a drop-in replacement. It has no
59 * constant time execution. The point is to make sure that all the
60 * bytes are compared and detect if loop was abused and some cycles
61 * was skipped due to fault injection.
62 *
63 * @return FIH_SUCCESS if memory regions are equal, otherwise FIH_FAILURE
64 */
65#ifdef MCUBOOT_FIH_PROFILE_OFF
66inline
Michael Grand5047f032022-11-24 16:49:56 +010067fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n)
Raef Colese8fe6cf2020-05-26 13:07:40 +010068{
69 return memcmp(s1, s2, n);
70}
71#else
Michael Grand5047f032022-11-24 16:49:56 +010072fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n)
Raef Colese8fe6cf2020-05-26 13:07:40 +010073{
74 size_t i;
75 uint8_t *s1_p = (uint8_t*) s1;
76 uint8_t *s2_p = (uint8_t*) s2;
Michael Grand5047f032022-11-24 16:49:56 +010077 FIH_DECLARE(ret, FIH_FAILURE);
Raef Colese8fe6cf2020-05-26 13:07:40 +010078
79 for (i = 0; i < n; i++) {
80 if (s1_p[i] != s2_p[i]) {
81 goto out;
82 }
83 }
84 if (i == n) {
85 ret = FIH_SUCCESS;
86 }
87
88out:
89 FIH_RET(ret);
90}
91#endif
92
Fabio Utzig152cca02021-12-14 22:16:37 -030093/*
94 * Amount of space used to save information required when doing a swap,
95 * or while a swap is under progress, but not the status of sector swap
96 * progress itself.
97 */
98static inline uint32_t
99boot_trailer_info_sz(void)
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300100{
Fabio Utzig152cca02021-12-14 22:16:37 -0300101 return (
Fabio Utzigba829042018-09-18 08:29:34 -0300102#ifdef MCUBOOT_ENC_IMAGES
103 /* encryption keys */
Fabio Utzig4741c452019-12-19 15:32:41 -0300104# if MCUBOOT_SWAP_SAVE_ENCTLV
105 BOOT_ENC_TLV_ALIGN_SIZE * 2 +
106# else
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000107 BOOT_ENC_KEY_ALIGN_SIZE * 2 +
Fabio Utzig4741c452019-12-19 15:32:41 -0300108# endif
Fabio Utzigba829042018-09-18 08:29:34 -0300109#endif
Christopher Collins2adef702019-05-22 14:37:31 -0700110 /* swap_type + copy_done + image_ok + swap_size */
111 BOOT_MAX_ALIGN * 4 +
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000112 BOOT_MAGIC_ALIGN_SIZE
Fabio Utzig152cca02021-12-14 22:16:37 -0300113 );
Christopher Collins92ea77f2016-12-12 15:59:26 -0800114}
115
Fabio Utzig152cca02021-12-14 22:16:37 -0300116/*
117 * Amount of space used to maintain progress information for a single swap
118 * operation.
119 */
120static inline uint32_t
121boot_status_entry_sz(uint32_t min_write_sz)
122{
123 return BOOT_STATUS_STATE_COUNT * min_write_sz;
124}
125
126uint32_t
127boot_status_sz(uint32_t min_write_sz)
128{
129 return BOOT_STATUS_MAX_ENTRIES * boot_status_entry_sz(min_write_sz);
130}
131
132uint32_t
133boot_trailer_sz(uint32_t min_write_sz)
134{
135 return boot_status_sz(min_write_sz) + boot_trailer_info_sz();
136}
137
138#if MCUBOOT_SWAP_USING_SCRATCH
139/*
140 * Similar to `boot_trailer_sz` but this function returns the space used to
141 * store status in the scratch partition. The scratch partition only stores
142 * status during the swap of the last sector from primary/secondary (which
143 * is the first swap operation) and thus only requires space for one swap.
144 */
145static uint32_t
146boot_scratch_trailer_sz(uint32_t min_write_sz)
147{
148 return boot_status_entry_sz(min_write_sz) + boot_trailer_info_sz();
149}
150#endif
151
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400152int
Fabio Utzigb0f04732019-07-31 09:49:19 -0300153boot_status_entries(int image_index, const struct flash_area *fap)
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400154{
Fabio Utzig12d59162019-11-28 10:01:59 -0300155#if MCUBOOT_SWAP_USING_SCRATCH
Dominik Ermel260ae092021-04-23 05:38:45 +0000156 if (flash_area_get_id(fap) == FLASH_AREA_IMAGE_SCRATCH) {
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400157 return BOOT_STATUS_STATE_COUNT;
Fabio Utzig12d59162019-11-28 10:01:59 -0300158 } else
159#endif
Dominik Ermel260ae092021-04-23 05:38:45 +0000160 if (flash_area_get_id(fap) == FLASH_AREA_IMAGE_PRIMARY(image_index) ||
161 flash_area_get_id(fap) == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
David Vinczeb75c12a2019-03-22 14:58:33 +0100162 return BOOT_STATUS_STATE_COUNT * BOOT_STATUS_MAX_ENTRIES;
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400163 }
Fabio Utzig9d160092019-08-09 07:46:34 -0300164 return -1;
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400165}
166
Christopher Collins92ea77f2016-12-12 15:59:26 -0800167uint32_t
168boot_status_off(const struct flash_area *fap)
169{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300170 uint32_t off_from_end;
Gustavo Henrique Nihei4aa286d2021-11-24 14:54:56 -0300171 uint32_t elem_sz;
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300172
173 elem_sz = flash_area_align(fap);
174
Fabio Utzig152cca02021-12-14 22:16:37 -0300175#if MCUBOOT_SWAP_USING_SCRATCH
176 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
177 off_from_end = boot_scratch_trailer_sz(elem_sz);
178 } else {
179#endif
180 off_from_end = boot_trailer_sz(elem_sz);
181#if MCUBOOT_SWAP_USING_SCRATCH
182 }
183#endif
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300184
Dominik Ermel260ae092021-04-23 05:38:45 +0000185 assert(off_from_end <= flash_area_get_size(fap));
186 return flash_area_get_size(fap) - off_from_end;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800187}
188
Fabio Utzigba829042018-09-18 08:29:34 -0300189#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300190static inline uint32_t
Fabio Utzigba829042018-09-18 08:29:34 -0300191boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
192{
Fabio Utzig4741c452019-12-19 15:32:41 -0300193#if MCUBOOT_SWAP_SAVE_ENCTLV
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000194 return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_TLV_ALIGN_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300195#else
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000196 return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300197#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300198}
199#endif
200
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300201/**
202 * This functions tries to locate the status area after an aborted swap,
203 * by looking for the magic in the possible locations.
204 *
Sam Bristowd0ca0ff2019-10-30 20:51:35 +1300205 * If the magic is successfully found, a flash_area * is returned and it
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300206 * is the responsibility of the called to close it.
207 *
208 * @returns 0 on success, -1 on errors
209 */
210static int
211boot_find_status(int image_index, const struct flash_area **fap)
212{
Dominik Ermelc68a6002023-02-10 12:37:39 +0000213 uint8_t areas[] = {
Fabio Utzig12d59162019-11-28 10:01:59 -0300214#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300215 FLASH_AREA_IMAGE_SCRATCH,
Fabio Utzig12d59162019-11-28 10:01:59 -0300216#endif
Fabio Utzig3c446072019-11-22 12:48:26 -0300217 FLASH_AREA_IMAGE_PRIMARY(image_index),
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300218 };
219 unsigned int i;
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300220
221 /*
222 * In the middle a swap, tries to locate the area that is currently
223 * storing a valid magic, first on the primary slot, then on scratch.
224 * Both "slots" can end up being temporary storage for a swap and it
225 * is assumed that if magic is valid then other metadata is too,
226 * because magic is always written in the last step.
227 */
228
229 for (i = 0; i < sizeof(areas) / sizeof(areas[0]); i++) {
Dominik Ermelc68a6002023-02-10 12:37:39 +0000230 uint8_t magic[BOOT_MAGIC_SZ];
231
232 if (flash_area_open(areas[i], fap)) {
233 break;
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300234 }
235
Dominik Ermelc68a6002023-02-10 12:37:39 +0000236 if (flash_area_read(*fap, boot_magic_off(*fap), magic, BOOT_MAGIC_SZ)) {
237 flash_area_close(*fap);
238 break;
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300239 }
240
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000241 if (BOOT_MAGIC_GOOD == boot_magic_decode(magic)) {
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300242 return 0;
243 }
244
Dominik Ermelc68a6002023-02-10 12:37:39 +0000245 flash_area_close(*fap);
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300246 }
247
248 /* If we got here, no magic was found */
Dominik Ermelc68a6002023-02-10 12:37:39 +0000249 fap = NULL;
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300250 return -1;
251}
252
Christopher Collins92ea77f2016-12-12 15:59:26 -0800253int
Fabio Utzigb0f04732019-07-31 09:49:19 -0300254boot_read_swap_size(int image_index, uint32_t *swap_size)
Fabio Utzig46490722017-09-04 15:34:32 -0300255{
Fabio Utzig46490722017-09-04 15:34:32 -0300256 uint32_t off;
257 const struct flash_area *fap;
258 int rc;
259
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300260 rc = boot_find_status(image_index, &fap);
261 if (rc == 0) {
262 off = boot_swap_size_off(fap);
263 rc = flash_area_read(fap, off, swap_size, sizeof *swap_size);
Fabio Utzig46490722017-09-04 15:34:32 -0300264 flash_area_close(fap);
Fabio Utzig46490722017-09-04 15:34:32 -0300265 }
266
Fabio Utzig46490722017-09-04 15:34:32 -0300267 return rc;
268}
269
Fabio Utzigba829042018-09-18 08:29:34 -0300270#ifdef MCUBOOT_ENC_IMAGES
271int
Fabio Utzig4741c452019-12-19 15:32:41 -0300272boot_read_enc_key(int image_index, uint8_t slot, struct boot_status *bs)
Fabio Utzigba829042018-09-18 08:29:34 -0300273{
Fabio Utzigba829042018-09-18 08:29:34 -0300274 uint32_t off;
275 const struct flash_area *fap;
Fabio Utzig4741c452019-12-19 15:32:41 -0300276#if MCUBOOT_SWAP_SAVE_ENCTLV
277 int i;
278#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300279 int rc;
280
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300281 rc = boot_find_status(image_index, &fap);
282 if (rc == 0) {
283 off = boot_enc_key_off(fap, slot);
Fabio Utzig4741c452019-12-19 15:32:41 -0300284#if MCUBOOT_SWAP_SAVE_ENCTLV
285 rc = flash_area_read(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
286 if (rc == 0) {
287 for (i = 0; i < BOOT_ENC_TLV_ALIGN_SIZE; i++) {
288 if (bs->enctlv[slot][i] != 0xff) {
289 break;
290 }
291 }
292 /* Only try to decrypt non-erased TLV metadata */
293 if (i != BOOT_ENC_TLV_ALIGN_SIZE) {
294 rc = boot_enc_decrypt(bs->enctlv[slot], bs->enckey[slot]);
295 }
296 }
297#else
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000298 rc = flash_area_read(fap, off, bs->enckey[slot], BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300299#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300300 flash_area_close(fap);
Fabio Utzigba829042018-09-18 08:29:34 -0300301 }
302
Fabio Utzigba829042018-09-18 08:29:34 -0300303 return rc;
304}
305#endif
Fabio Utzig46490722017-09-04 15:34:32 -0300306
Christopher Collins92ea77f2016-12-12 15:59:26 -0800307int
Fabio Utzig2473ac02017-05-02 12:45:02 -0300308boot_write_copy_done(const struct flash_area *fap)
309{
Christopher Collinsa1c12042019-05-23 14:00:28 -0700310 uint32_t off;
311
312 off = boot_copy_done_off(fap);
Ben McCrea4c0ee952019-08-28 09:13:24 -0700313 BOOT_LOG_DBG("writing copy_done; fa_id=%d off=0x%lx (0x%lx)",
Dominik Ermel260ae092021-04-23 05:38:45 +0000314 flash_area_get_id(fap), (unsigned long)off,
315 (unsigned long)(flash_area_get_off(fap) + off));
Fabio Utzig1a1ec172019-08-09 10:21:43 -0300316 return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
Fabio Utzig2473ac02017-05-02 12:45:02 -0300317}
318
319int
Fabio Utzig46490722017-09-04 15:34:32 -0300320boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size)
321{
322 uint32_t off;
Fabio Utzig46490722017-09-04 15:34:32 -0300323
324 off = boot_swap_size_off(fap);
Ben McCrea4c0ee952019-08-28 09:13:24 -0700325 BOOT_LOG_DBG("writing swap_size; fa_id=%d off=0x%lx (0x%lx)",
Dominik Ermel260ae092021-04-23 05:38:45 +0000326 flash_area_get_id(fap), (unsigned long)off,
327 (unsigned long)flash_area_get_off(fap) + off);
Fabio Utzig1a1ec172019-08-09 10:21:43 -0300328 return boot_write_trailer(fap, off, (const uint8_t *) &swap_size, 4);
Fabio Utzig46490722017-09-04 15:34:32 -0300329}
330
Fabio Utzigba829042018-09-18 08:29:34 -0300331#ifdef MCUBOOT_ENC_IMAGES
332int
Fabio Utzig4741c452019-12-19 15:32:41 -0300333boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
334 const struct boot_status *bs)
Fabio Utzigba829042018-09-18 08:29:34 -0300335{
336 uint32_t off;
337 int rc;
338
339 off = boot_enc_key_off(fap, slot);
Fabio Utzig5e6ea222019-12-10 09:49:59 -0300340 BOOT_LOG_DBG("writing enc_key; fa_id=%d off=0x%lx (0x%lx)",
Dominik Ermel260ae092021-04-23 05:38:45 +0000341 flash_area_get_id(fap), (unsigned long)off,
342 (unsigned long)flash_area_get_off(fap) + off);
Fabio Utzig4741c452019-12-19 15:32:41 -0300343#if MCUBOOT_SWAP_SAVE_ENCTLV
344 rc = flash_area_write(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
345#else
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000346 rc = flash_area_write(fap, off, bs->enckey[slot], BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300347#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300348 if (rc != 0) {
349 return BOOT_EFLASH;
350 }
351
352 return 0;
353}
354#endif
Andrzej Puzdrowski334b6a62022-01-21 16:59:18 +0100355
356uint32_t bootutil_max_image_size(const struct flash_area *fap)
357{
Dominik Ermeld5460792022-12-21 16:05:34 +0000358#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SINGLE_APPLICATION_SLOT)
Andrzej Puzdrowski334b6a62022-01-21 16:59:18 +0100359 return boot_status_off(fap);
360#elif defined(MCUBOOT_SWAP_USING_MOVE)
361 struct flash_sector sector;
362 /* get the last sector offset */
363 int rc = flash_area_sector_from_off(boot_status_off(fap), &sector);
364 if (rc) {
365 BOOT_LOG_ERR("Unable to determine flash sector of the image trailer");
366 return 0; /* Returning of zero here should cause any check which uses
367 * this value to fail.
368 */
369 }
370 return flash_sector_get_off(&sector);
371#elif defined(MCUBOOT_OVERWRITE_ONLY)
372 return boot_swap_info_off(fap);
373#elif defined(MCUBOOT_DIRECT_XIP)
374 return boot_swap_info_off(fap);
375#elif defined(MCUBOOT_RAM_LOAD)
376 return boot_swap_info_off(fap);
377#endif
378}