blob: b81764058b4737bc7eae26a83a54af610e2253e5 [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
Andrzej Puzdrowskif573b392020-11-10 14:35:15 +010055extern const uint32_t boot_img_magic[];
Christopher Collins92ea77f2016-12-12 15:59:26 -080056
Hovland, Sigvart1d96f362018-09-25 13:23:42 +020057#define BOOT_MAGIC_ARR_SZ \
58 (sizeof boot_img_magic / sizeof boot_img_magic[0])
59
Raef Colese8fe6cf2020-05-26 13:07:40 +010060/**
61 * @brief Determine if the data at two memory addresses is equal
62 *
63 * @param s1 The first memory region to compare.
64 * @param s2 The second memory region to compare.
65 * @param n The amount of bytes to compare.
66 *
67 * @note This function does not comply with the specification of memcmp,
68 * so should not be considered a drop-in replacement. It has no
69 * constant time execution. The point is to make sure that all the
70 * bytes are compared and detect if loop was abused and some cycles
71 * was skipped due to fault injection.
72 *
73 * @return FIH_SUCCESS if memory regions are equal, otherwise FIH_FAILURE
74 */
75#ifdef MCUBOOT_FIH_PROFILE_OFF
76inline
77fih_int boot_fih_memequal(const void *s1, const void *s2, size_t n)
78{
79 return memcmp(s1, s2, n);
80}
81#else
82fih_int boot_fih_memequal(const void *s1, const void *s2, size_t n)
83{
84 size_t i;
85 uint8_t *s1_p = (uint8_t*) s1;
86 uint8_t *s2_p = (uint8_t*) s2;
87 fih_int ret = FIH_FAILURE;
88
89 for (i = 0; i < n; i++) {
90 if (s1_p[i] != s2_p[i]) {
91 goto out;
92 }
93 }
94 if (i == n) {
95 ret = FIH_SUCCESS;
96 }
97
98out:
99 FIH_RET(ret);
100}
101#endif
102
Christopher Collins92ea77f2016-12-12 15:59:26 -0800103uint32_t
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300104boot_status_sz(uint32_t min_write_sz)
105{
106 return /* state for all sectors */
107 BOOT_STATUS_MAX_ENTRIES * BOOT_STATUS_STATE_COUNT * min_write_sz;
108}
109
110uint32_t
David Brownab449182019-11-15 09:32:52 -0700111boot_trailer_sz(uint32_t min_write_sz)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800112{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300113 return /* state for all sectors */
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300114 boot_status_sz(min_write_sz) +
Fabio Utzigba829042018-09-18 08:29:34 -0300115#ifdef MCUBOOT_ENC_IMAGES
116 /* encryption keys */
Fabio Utzig4741c452019-12-19 15:32:41 -0300117# if MCUBOOT_SWAP_SAVE_ENCTLV
118 BOOT_ENC_TLV_ALIGN_SIZE * 2 +
119# else
Fabio Utzigba829042018-09-18 08:29:34 -0300120 BOOT_ENC_KEY_SIZE * 2 +
Fabio Utzig4741c452019-12-19 15:32:41 -0300121# endif
Fabio Utzigba829042018-09-18 08:29:34 -0300122#endif
Christopher Collins2adef702019-05-22 14:37:31 -0700123 /* swap_type + copy_done + image_ok + swap_size */
124 BOOT_MAX_ALIGN * 4 +
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300125 BOOT_MAGIC_SZ;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800126}
127
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400128int
Fabio Utzigb0f04732019-07-31 09:49:19 -0300129boot_status_entries(int image_index, const struct flash_area *fap)
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400130{
Fabio Utzig12d59162019-11-28 10:01:59 -0300131#if MCUBOOT_SWAP_USING_SCRATCH
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300132 if (flash_area_get_id(fap) == FLASH_AREA_IMAGE_SCRATCH) {
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400133 return BOOT_STATUS_STATE_COUNT;
Fabio Utzig12d59162019-11-28 10:01:59 -0300134 } else
135#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300136 if (flash_area_get_id(fap) == FLASH_AREA_IMAGE_PRIMARY(image_index) ||
137 flash_area_get_id(fap) == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
David Vinczeb75c12a2019-03-22 14:58:33 +0100138 return BOOT_STATUS_STATE_COUNT * BOOT_STATUS_MAX_ENTRIES;
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400139 }
Fabio Utzig9d160092019-08-09 07:46:34 -0300140 return -1;
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400141}
142
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200143#ifndef MCUBOOT_SWAP_USING_STATUS
Christopher Collins92ea77f2016-12-12 15:59:26 -0800144uint32_t
145boot_status_off(const struct flash_area *fap)
146{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300147 uint32_t off_from_end;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300148 size_t elem_sz;
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300149
150 elem_sz = flash_area_align(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300151 assert(elem_sz != 0u);
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300152
Christopher Collins2adef702019-05-22 14:37:31 -0700153 off_from_end = boot_trailer_sz(elem_sz);
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300154
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300155 assert(off_from_end <= flash_area_get_size(fap));
156 return flash_area_get_size(fap) - off_from_end;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800157}
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200158#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800159
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000160#ifndef MCUBOOT_SWAP_USING_STATUS
161
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300162static inline uint32_t
163boot_magic_off(const struct flash_area *fap)
164{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300165 return flash_area_get_size(fap) - BOOT_MAGIC_SZ;
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300166}
167
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200168
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300169static inline uint32_t
170boot_image_ok_off(const struct flash_area *fap)
171{
172 return boot_magic_off(fap) - BOOT_MAX_ALIGN;
173}
174
175static inline uint32_t
176boot_copy_done_off(const struct flash_area *fap)
177{
178 return boot_image_ok_off(fap) - BOOT_MAX_ALIGN;
179}
180
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300181static inline uint32_t
Fabio Utzig46490722017-09-04 15:34:32 -0300182boot_swap_size_off(const struct flash_area *fap)
183{
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300184 return boot_swap_info_off(fap) - BOOT_MAX_ALIGN;
Fabio Utzig46490722017-09-04 15:34:32 -0300185}
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200186#endif /* !MCUBOOT_SWAP_USING_STATUS */
Fabio Utzig46490722017-09-04 15:34:32 -0300187
Fabio Utzigba829042018-09-18 08:29:34 -0300188#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300189static inline uint32_t
Fabio Utzigba829042018-09-18 08:29:34 -0300190boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
191{
Fabio Utzig4741c452019-12-19 15:32:41 -0300192#if MCUBOOT_SWAP_SAVE_ENCTLV
193 return boot_swap_size_off(fap) - ((slot + 1) *
194 ((((BOOT_ENC_TLV_SIZE - 1) / BOOT_MAX_ALIGN) + 1) * BOOT_MAX_ALIGN));
195#else
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300196 return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300197#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300198}
199#endif
200
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200201#ifndef MCUBOOT_SWAP_USING_STATUS
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300202/**
203 * This functions tries to locate the status area after an aborted swap,
204 * by looking for the magic in the possible locations.
205 *
Sam Bristowd0ca0ff2019-10-30 20:51:35 +1300206 * If the magic is successfully found, a flash_area * is returned and it
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300207 * is the responsibility of the called to close it.
208 *
209 * @returns 0 on success, -1 on errors
210 */
211static int
212boot_find_status(int image_index, const struct flash_area **fap)
213{
214 uint32_t magic[BOOT_MAGIC_ARR_SZ];
215 uint32_t off;
216 uint8_t areas[2] = {
Fabio Utzig12d59162019-11-28 10:01:59 -0300217#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300218 FLASH_AREA_IMAGE_SCRATCH,
Fabio Utzig12d59162019-11-28 10:01:59 -0300219#endif
Fabio Utzig3c446072019-11-22 12:48:26 -0300220 FLASH_AREA_IMAGE_PRIMARY(image_index),
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300221 };
222 unsigned int i;
223 int rc;
224
225 /*
226 * In the middle a swap, tries to locate the area that is currently
227 * storing a valid magic, first on the primary slot, then on scratch.
228 * Both "slots" can end up being temporary storage for a swap and it
229 * is assumed that if magic is valid then other metadata is too,
230 * because magic is always written in the last step.
231 */
232
233 for (i = 0; i < sizeof(areas) / sizeof(areas[0]); i++) {
234 rc = flash_area_open(areas[i], fap);
235 if (rc != 0) {
236 return rc;
237 }
238
239 off = boot_magic_off(*fap);
240 rc = flash_area_read(*fap, off, magic, BOOT_MAGIC_SZ);
241 if (rc != 0) {
242 flash_area_close(*fap);
243 return rc;
244 }
245
246 if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
247 return 0;
248 }
249
250 flash_area_close(*fap);
251 }
252
253 /* If we got here, no magic was found */
254 return -1;
255}
256
Christopher Collins92ea77f2016-12-12 15:59:26 -0800257int
Fabio Utzigb0f04732019-07-31 09:49:19 -0300258boot_read_swap_size(int image_index, uint32_t *swap_size)
Fabio Utzig46490722017-09-04 15:34:32 -0300259{
Fabio Utzig46490722017-09-04 15:34:32 -0300260 uint32_t off;
261 const struct flash_area *fap;
262 int rc;
263
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300264 rc = boot_find_status(image_index, &fap);
265 if (rc == 0) {
266 off = boot_swap_size_off(fap);
267 rc = flash_area_read(fap, off, swap_size, sizeof *swap_size);
Fabio Utzig46490722017-09-04 15:34:32 -0300268 flash_area_close(fap);
Fabio Utzig46490722017-09-04 15:34:32 -0300269 }
270
Fabio Utzig46490722017-09-04 15:34:32 -0300271 return rc;
272}
273
Fabio Utzigba829042018-09-18 08:29:34 -0300274#ifdef MCUBOOT_ENC_IMAGES
275int
Fabio Utzig4741c452019-12-19 15:32:41 -0300276boot_read_enc_key(int image_index, uint8_t slot, struct boot_status *bs)
Fabio Utzigba829042018-09-18 08:29:34 -0300277{
Fabio Utzigba829042018-09-18 08:29:34 -0300278 uint32_t off;
279 const struct flash_area *fap;
280 int rc;
281
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300282 rc = boot_find_status(image_index, &fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300283 if (0 == rc) {
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300284 off = boot_enc_key_off(fap, slot);
Fabio Utzig4741c452019-12-19 15:32:41 -0300285#if MCUBOOT_SWAP_SAVE_ENCTLV
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300286 uint8_t aes_iv[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200287
Fabio Utzig4741c452019-12-19 15:32:41 -0300288 rc = flash_area_read(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300289 if (0 == rc) {
290 /* Only try to decrypt initialized TLV metadata */
291 if (!bootutil_buffer_is_filled(bs->enctlv[slot],
292 BOOT_UNINITIALIZED_TLV_FILL,
293 BOOT_ENC_TLV_ALIGN_SIZE)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200294 rc = boot_enc_decrypt(bs->enctlv[slot], bs->enckey[slot], 0, aes_iv);
Fabio Utzig4741c452019-12-19 15:32:41 -0300295 }
296 }
297#else
298 rc = flash_area_read(fap, off, bs->enckey[slot], BOOT_ENC_KEY_SIZE);
299#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
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200307#endif /* !MCUBOOT_SWAP_USING_STATUS */
308
Christopher Collins92ea77f2016-12-12 15:59:26 -0800309int
Fabio Utzig2473ac02017-05-02 12:45:02 -0300310boot_write_copy_done(const struct flash_area *fap)
311{
Christopher Collinsa1c12042019-05-23 14:00:28 -0700312 uint32_t off;
313
314 off = boot_copy_done_off(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300315 BOOT_LOG_DBG("writing copy_done; fa_id=%u off=0x%" PRIx32
316 " (0x%" PRIx32 ")", (unsigned)flash_area_get_id(fap),
317 off, flash_area_get_off(fap) + off);
Fabio Utzig1a1ec172019-08-09 10:21:43 -0300318 return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
Fabio Utzig2473ac02017-05-02 12:45:02 -0300319}
320
321int
Fabio Utzig46490722017-09-04 15:34:32 -0300322boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size)
323{
324 uint32_t off;
Fabio Utzig46490722017-09-04 15:34:32 -0300325
326 off = boot_swap_size_off(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300327 BOOT_LOG_DBG("writing swap_size; fa_id=%u off=0x%" PRIx32
328 " (0x%" PRIx32 ")", (unsigned)flash_area_get_id(fap),
329 off, flash_area_get_off(fap) + off);
Fabio Utzig1a1ec172019-08-09 10:21:43 -0300330 return boot_write_trailer(fap, off, (const uint8_t *) &swap_size, 4);
Fabio Utzig46490722017-09-04 15:34:32 -0300331}
332
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200333#ifndef MCUBOOT_SWAP_USING_STATUS
334
Fabio Utzigba829042018-09-18 08:29:34 -0300335#ifdef MCUBOOT_ENC_IMAGES
336int
Fabio Utzig4741c452019-12-19 15:32:41 -0300337boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
338 const struct boot_status *bs)
Fabio Utzigba829042018-09-18 08:29:34 -0300339{
340 uint32_t off;
341 int rc;
342
343 off = boot_enc_key_off(fap, slot);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300344 BOOT_LOG_DBG("writing enc_key; fa_id=%u off=0x%" PRIx32
345 " (0x%" PRIx32 ")", (unsigned)flash_area_get_id(fap),
346 off, flash_area_get_off(fap) + off);
Fabio Utzig4741c452019-12-19 15:32:41 -0300347#if MCUBOOT_SWAP_SAVE_ENCTLV
348 rc = flash_area_write(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
349#else
350 rc = flash_area_write(fap, off, bs->enckey[slot], BOOT_ENC_KEY_SIZE);
351#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300352 if (rc != 0) {
353 return BOOT_EFLASH;
354 }
355
356 return 0;
357}
358#endif
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200359
360#endif /* !MCUBOOT_SWAP_USING_STATUS */