blob: f9059aad29f38aeb50c6213ee40200fbfb279aae [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"
Fabio Utzig7ebb7c22017-04-26 10:59:31 -030038#include "bootutil/bootutil_log.h"
Raef Colese8fe6cf2020-05-26 13:07:40 +010039#include "bootutil/fault_injection_hardening.h"
Fabio Utzigba829042018-09-18 08:29:34 -030040#ifdef MCUBOOT_ENC_IMAGES
41#include "bootutil/enc_key.h"
42#endif
Fabio Utzig7ebb7c22017-04-26 10:59:31 -030043
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020044#ifdef MCUBOOT_SWAP_USING_STATUS
45#include "swap_status.h"
46#endif
47
48#include "mcuboot_config/mcuboot_config.h"
49
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +010050MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
51
Fabio Utzig10ee6482019-08-01 12:04:52 -030052/* Currently only used by imgmgr */
Christopher Collins92ea77f2016-12-12 15:59:26 -080053int boot_current_slot;
54
Raef Colese8fe6cf2020-05-26 13:07:40 +010055/**
56 * @brief Determine if the data at two memory addresses is equal
57 *
58 * @param s1 The first memory region to compare.
59 * @param s2 The second memory region to compare.
60 * @param n The amount of bytes to compare.
61 *
62 * @note This function does not comply with the specification of memcmp,
63 * so should not be considered a drop-in replacement. It has no
64 * constant time execution. The point is to make sure that all the
65 * bytes are compared and detect if loop was abused and some cycles
66 * was skipped due to fault injection.
67 *
68 * @return FIH_SUCCESS if memory regions are equal, otherwise FIH_FAILURE
69 */
70#ifdef MCUBOOT_FIH_PROFILE_OFF
71inline
72fih_int boot_fih_memequal(const void *s1, const void *s2, size_t n)
73{
74 return memcmp(s1, s2, n);
75}
76#else
77fih_int boot_fih_memequal(const void *s1, const void *s2, size_t n)
78{
79 size_t i;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030080 const volatile uint8_t *s1_p = (const uint8_t*) s1;
81 const volatile uint8_t *s2_p = (const uint8_t*) s2;
Raef Colese8fe6cf2020-05-26 13:07:40 +010082 fih_int ret = FIH_FAILURE;
83
84 for (i = 0; i < n; i++) {
85 if (s1_p[i] != s2_p[i]) {
86 goto out;
87 }
88 }
89 if (i == n) {
90 ret = FIH_SUCCESS;
91 }
92
93out:
94 FIH_RET(ret);
95}
96#endif
97
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030098/*
99 * Amount of space used to save information required when doing a swap,
100 * or while a swap is under progress, but not the status of sector swap
101 * progress itself.
102 */
103static inline uint32_t
104boot_trailer_info_sz(void)
105{
106 return (
107#ifdef MCUBOOT_ENC_IMAGES
108 /* encryption keys */
109 #ifdef MCUBOOT_SWAP_SAVE_ENCTLV
110 BOOT_ENC_TLV_ALIGN_SIZE * 2 +
111# else
112 BOOT_ENC_KEY_ALIGN_SIZE * 2 +
113# endif
114#endif
115 /* swap_type + copy_done + image_ok + swap_size */
116 BOOT_MAX_ALIGN * 4 +
117 BOOT_MAGIC_ALIGN_SIZE
118 );
119}
120
121/*
122 * Amount of space used to maintain progress information for a single swap
123 * operation.
124 */
125static inline uint32_t
126boot_status_entry_sz(uint32_t min_write_sz)
127{
128 return BOOT_STATUS_STATE_COUNT * min_write_sz;
129}
130
Christopher Collins92ea77f2016-12-12 15:59:26 -0800131uint32_t
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300132boot_status_sz(uint32_t min_write_sz)
133{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300134 return BOOT_STATUS_MAX_ENTRIES * boot_status_entry_sz(min_write_sz);
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300135}
136
137uint32_t
David Brownab449182019-11-15 09:32:52 -0700138boot_trailer_sz(uint32_t min_write_sz)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800139{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300140 return boot_status_sz(min_write_sz) + boot_trailer_info_sz();
Christopher Collins92ea77f2016-12-12 15:59:26 -0800141}
142
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300143#if !defined(MCUBOOT_SWAP_USING_STATUS) && defined(MCUBOOT_SWAP_USING_SCRATCH)
144/*
145 * Similar to `boot_trailer_sz` but this function returns the space used to
146 * store status in the scratch partition. The scratch partition only stores
147 * status during the swap of the last sector from primary/secondary (which
148 * is the first swap operation) and thus only requires space for one swap.
149 */
150static uint32_t
151boot_scratch_trailer_sz(uint32_t min_write_sz)
152{
153 return boot_status_entry_sz(min_write_sz) + boot_trailer_info_sz();
154}
155#endif
156
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400157int
Fabio Utzigb0f04732019-07-31 09:49:19 -0300158boot_status_entries(int image_index, const struct flash_area *fap)
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400159{
Fabio Utzig12d59162019-11-28 10:01:59 -0300160#if MCUBOOT_SWAP_USING_SCRATCH
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300161 if (flash_area_get_id(fap) == FLASH_AREA_IMAGE_SCRATCH) {
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400162 return BOOT_STATUS_STATE_COUNT;
Fabio Utzig12d59162019-11-28 10:01:59 -0300163 } else
164#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300165 if (flash_area_get_id(fap) == FLASH_AREA_IMAGE_PRIMARY(image_index) ||
166 flash_area_get_id(fap) == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
David Vinczeb75c12a2019-03-22 14:58:33 +0100167 return BOOT_STATUS_STATE_COUNT * BOOT_STATUS_MAX_ENTRIES;
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400168 }
Fabio Utzig9d160092019-08-09 07:46:34 -0300169 return -1;
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400170}
171
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200172#ifndef MCUBOOT_SWAP_USING_STATUS
Christopher Collins92ea77f2016-12-12 15:59:26 -0800173uint32_t
174boot_status_off(const struct flash_area *fap)
175{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300176 uint32_t off_from_end;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300177 uint32_t elem_sz;
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300178
179 elem_sz = flash_area_align(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300180 assert(elem_sz != 0u);
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300181
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300182#if MCUBOOT_SWAP_USING_SCRATCH
183 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
184 off_from_end = boot_scratch_trailer_sz(elem_sz);
185 } else {
186#endif
187 off_from_end = boot_trailer_sz(elem_sz);
188#if MCUBOOT_SWAP_USING_SCRATCH
189 }
190#endif
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300191
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300192 assert(off_from_end <= flash_area_get_size(fap));
193 return flash_area_get_size(fap) - off_from_end;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800194}
195
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300196static uint32_t
197boot_magic_decode(const uint8_t *magic)
198{
199 if (memcmp(magic, BOOT_IMG_MAGIC, BOOT_MAGIC_SZ) == 0) {
200 return BOOT_MAGIC_GOOD;
201 }
202 return BOOT_MAGIC_BAD;
203}
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000204
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300205static inline uint32_t
206boot_magic_off(const struct flash_area *fap)
207{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300208 return flash_area_get_size(fap) - BOOT_MAGIC_SZ;
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300209}
210
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200211
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300212static inline uint32_t
213boot_image_ok_off(const struct flash_area *fap)
214{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300215 return ALIGN_DOWN(boot_magic_off(fap) - BOOT_MAX_ALIGN, BOOT_MAX_ALIGN);
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300216}
217
218static inline uint32_t
219boot_copy_done_off(const struct flash_area *fap)
220{
221 return boot_image_ok_off(fap) - BOOT_MAX_ALIGN;
222}
223
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300224static inline uint32_t
Fabio Utzig46490722017-09-04 15:34:32 -0300225boot_swap_size_off(const struct flash_area *fap)
226{
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300227 return boot_swap_info_off(fap) - BOOT_MAX_ALIGN;
Fabio Utzig46490722017-09-04 15:34:32 -0300228}
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200229#endif /* !MCUBOOT_SWAP_USING_STATUS */
Fabio Utzig46490722017-09-04 15:34:32 -0300230
Fabio Utzigba829042018-09-18 08:29:34 -0300231#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300232static inline uint32_t
Fabio Utzigba829042018-09-18 08:29:34 -0300233boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
234{
Fabio Utzig4741c452019-12-19 15:32:41 -0300235#if MCUBOOT_SWAP_SAVE_ENCTLV
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300236 return boot_swap_size_off(fap) - (((uint32_t)slot + 1U) * BOOT_ENC_TLV_ALIGN_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300237#else
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300238 return boot_swap_size_off(fap) - (((uint32_t)slot + 1U) * BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300239#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300240}
241#endif
242
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200243#ifndef MCUBOOT_SWAP_USING_STATUS
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300244/**
245 * This functions tries to locate the status area after an aborted swap,
246 * by looking for the magic in the possible locations.
247 *
Sam Bristowd0ca0ff2019-10-30 20:51:35 +1300248 * If the magic is successfully found, a flash_area * is returned and it
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300249 * is the responsibility of the called to close it.
250 *
251 * @returns 0 on success, -1 on errors
252 */
253static int
254boot_find_status(int image_index, const struct flash_area **fap)
255{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300256 uint8_t magic[BOOT_MAGIC_SZ];
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300257 uint32_t off;
258 uint8_t areas[2] = {
Fabio Utzig12d59162019-11-28 10:01:59 -0300259#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300260 FLASH_AREA_IMAGE_SCRATCH,
Fabio Utzig12d59162019-11-28 10:01:59 -0300261#endif
Fabio Utzig3c446072019-11-22 12:48:26 -0300262 FLASH_AREA_IMAGE_PRIMARY(image_index),
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300263 };
264 unsigned int i;
265 int rc;
266
267 /*
268 * In the middle a swap, tries to locate the area that is currently
269 * storing a valid magic, first on the primary slot, then on scratch.
270 * Both "slots" can end up being temporary storage for a swap and it
271 * is assumed that if magic is valid then other metadata is too,
272 * because magic is always written in the last step.
273 */
274
275 for (i = 0; i < sizeof(areas) / sizeof(areas[0]); i++) {
276 rc = flash_area_open(areas[i], fap);
277 if (rc != 0) {
278 return rc;
279 }
280
281 off = boot_magic_off(*fap);
282 rc = flash_area_read(*fap, off, magic, BOOT_MAGIC_SZ);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300283 flash_area_close(*fap);
284
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300285 if (rc != 0) {
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300286 return rc;
287 }
288
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300289 if (BOOT_MAGIC_GOOD == boot_magic_decode(magic)) {
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300290 return 0;
291 }
292
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300293 }
294
295 /* If we got here, no magic was found */
296 return -1;
297}
298
Christopher Collins92ea77f2016-12-12 15:59:26 -0800299int
Fabio Utzigb0f04732019-07-31 09:49:19 -0300300boot_read_swap_size(int image_index, uint32_t *swap_size)
Fabio Utzig46490722017-09-04 15:34:32 -0300301{
Fabio Utzig46490722017-09-04 15:34:32 -0300302 uint32_t off;
303 const struct flash_area *fap;
304 int rc;
305
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300306 rc = boot_find_status(image_index, &fap);
307 if (rc == 0) {
308 off = boot_swap_size_off(fap);
309 rc = flash_area_read(fap, off, swap_size, sizeof *swap_size);
Fabio Utzig46490722017-09-04 15:34:32 -0300310 flash_area_close(fap);
Fabio Utzig46490722017-09-04 15:34:32 -0300311 }
312
Fabio Utzig46490722017-09-04 15:34:32 -0300313 return rc;
314}
315
Fabio Utzigba829042018-09-18 08:29:34 -0300316#ifdef MCUBOOT_ENC_IMAGES
317int
Fabio Utzig4741c452019-12-19 15:32:41 -0300318boot_read_enc_key(int image_index, uint8_t slot, struct boot_status *bs)
Fabio Utzigba829042018-09-18 08:29:34 -0300319{
Fabio Utzigba829042018-09-18 08:29:34 -0300320 uint32_t off;
321 const struct flash_area *fap;
322 int rc;
323
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300324 rc = boot_find_status(image_index, &fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300325 if (0 == rc) {
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300326 off = boot_enc_key_off(fap, slot);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300327#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300328 uint8_t aes_iv[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200329
Fabio Utzig4741c452019-12-19 15:32:41 -0300330 rc = flash_area_read(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300331 if (0 == rc) {
332 /* Only try to decrypt initialized TLV metadata */
333 if (!bootutil_buffer_is_filled(bs->enctlv[slot],
334 BOOT_UNINITIALIZED_TLV_FILL,
335 BOOT_ENC_TLV_ALIGN_SIZE)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200336 rc = boot_enc_decrypt(bs->enctlv[slot], bs->enckey[slot], 0, aes_iv);
Fabio Utzig4741c452019-12-19 15:32:41 -0300337 }
338 }
339#else
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300340 rc = flash_area_read(fap, off, bs->enckey[slot], BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300341#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300342 flash_area_close(fap);
Fabio Utzigba829042018-09-18 08:29:34 -0300343 }
344
Fabio Utzigba829042018-09-18 08:29:34 -0300345 return rc;
346}
347#endif
Fabio Utzig46490722017-09-04 15:34:32 -0300348
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200349#endif /* !MCUBOOT_SWAP_USING_STATUS */
350
Christopher Collins92ea77f2016-12-12 15:59:26 -0800351int
Fabio Utzig2473ac02017-05-02 12:45:02 -0300352boot_write_copy_done(const struct flash_area *fap)
353{
Christopher Collinsa1c12042019-05-23 14:00:28 -0700354 uint32_t off;
355
356 off = boot_copy_done_off(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300357 BOOT_LOG_DBG("writing copy_done; fa_id=%u off=0x%" PRIx32
358 " (0x%" PRIx32 ")", (unsigned)flash_area_get_id(fap),
359 off, flash_area_get_off(fap) + off);
Fabio Utzig1a1ec172019-08-09 10:21:43 -0300360 return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
Fabio Utzig2473ac02017-05-02 12:45:02 -0300361}
362
363int
Fabio Utzig46490722017-09-04 15:34:32 -0300364boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size)
365{
366 uint32_t off;
Fabio Utzig46490722017-09-04 15:34:32 -0300367
368 off = boot_swap_size_off(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300369 BOOT_LOG_DBG("writing swap_size; fa_id=%u off=0x%" PRIx32
370 " (0x%" PRIx32 ")", (unsigned)flash_area_get_id(fap),
371 off, flash_area_get_off(fap) + off);
Fabio Utzig1a1ec172019-08-09 10:21:43 -0300372 return boot_write_trailer(fap, off, (const uint8_t *) &swap_size, 4);
Fabio Utzig46490722017-09-04 15:34:32 -0300373}
374
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200375#ifndef MCUBOOT_SWAP_USING_STATUS
376
Fabio Utzigba829042018-09-18 08:29:34 -0300377#ifdef MCUBOOT_ENC_IMAGES
378int
Fabio Utzig4741c452019-12-19 15:32:41 -0300379boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
380 const struct boot_status *bs)
Fabio Utzigba829042018-09-18 08:29:34 -0300381{
382 uint32_t off;
383 int rc;
384
385 off = boot_enc_key_off(fap, slot);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300386 BOOT_LOG_DBG("writing enc_key; fa_id=%u off=0x%" PRIx32
387 " (0x%" PRIx32 ")", (unsigned)flash_area_get_id(fap),
388 off, flash_area_get_off(fap) + off);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300389#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
Fabio Utzig4741c452019-12-19 15:32:41 -0300390 rc = flash_area_write(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
391#else
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300392 rc = flash_area_write(fap, off, bs->enckey[slot], BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300393#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300394 if (rc != 0) {
395 return BOOT_EFLASH;
396 }
397
398 return 0;
399}
400#endif
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200401
402#endif /* !MCUBOOT_SWAP_USING_STATUS */