blob: f0b4a5d1c315e930943ced47d6da25eeb6a1958d [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
Carlos Falgueras GarcĂ­aa4b4b0f2021-06-22 10:00:22 +020044BOOT_LOG_MODULE_DECLARE(mcuboot);
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +010045
Fabio Utzig10ee6482019-08-01 12:04:52 -030046/* Currently only used by imgmgr */
Christopher Collins92ea77f2016-12-12 15:59:26 -080047int boot_current_slot;
48
Andrzej Puzdrowskif573b392020-11-10 14:35:15 +010049extern const uint32_t boot_img_magic[];
Christopher Collins92ea77f2016-12-12 15:59:26 -080050
Hovland, Sigvart1d96f362018-09-25 13:23:42 +020051#define BOOT_MAGIC_ARR_SZ \
52 (sizeof boot_img_magic / sizeof boot_img_magic[0])
53
Raef Colese8fe6cf2020-05-26 13:07:40 +010054/**
55 * @brief Determine if the data at two memory addresses is equal
56 *
57 * @param s1 The first memory region to compare.
58 * @param s2 The second memory region to compare.
59 * @param n The amount of bytes to compare.
60 *
61 * @note This function does not comply with the specification of memcmp,
62 * so should not be considered a drop-in replacement. It has no
63 * constant time execution. The point is to make sure that all the
64 * bytes are compared and detect if loop was abused and some cycles
65 * was skipped due to fault injection.
66 *
67 * @return FIH_SUCCESS if memory regions are equal, otherwise FIH_FAILURE
68 */
69#ifdef MCUBOOT_FIH_PROFILE_OFF
70inline
71fih_int boot_fih_memequal(const void *s1, const void *s2, size_t n)
72{
73 return memcmp(s1, s2, n);
74}
75#else
76fih_int boot_fih_memequal(const void *s1, const void *s2, size_t n)
77{
78 size_t i;
79 uint8_t *s1_p = (uint8_t*) s1;
80 uint8_t *s2_p = (uint8_t*) s2;
81 fih_int ret = FIH_FAILURE;
82
83 for (i = 0; i < n; i++) {
84 if (s1_p[i] != s2_p[i]) {
85 goto out;
86 }
87 }
88 if (i == n) {
89 ret = FIH_SUCCESS;
90 }
91
92out:
93 FIH_RET(ret);
94}
95#endif
96
Fabio Utzig152cca02021-12-14 22:16:37 -030097/*
98 * Amount of space used to save information required when doing a swap,
99 * or while a swap is under progress, but not the status of sector swap
100 * progress itself.
101 */
102static inline uint32_t
103boot_trailer_info_sz(void)
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300104{
Fabio Utzig152cca02021-12-14 22:16:37 -0300105 return (
Fabio Utzigba829042018-09-18 08:29:34 -0300106#ifdef MCUBOOT_ENC_IMAGES
107 /* encryption keys */
Fabio Utzig4741c452019-12-19 15:32:41 -0300108# if MCUBOOT_SWAP_SAVE_ENCTLV
109 BOOT_ENC_TLV_ALIGN_SIZE * 2 +
110# else
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000111 BOOT_ENC_KEY_ALIGN_SIZE * 2 +
Fabio Utzig4741c452019-12-19 15:32:41 -0300112# endif
Fabio Utzigba829042018-09-18 08:29:34 -0300113#endif
Christopher Collins2adef702019-05-22 14:37:31 -0700114 /* swap_type + copy_done + image_ok + swap_size */
115 BOOT_MAX_ALIGN * 4 +
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000116 BOOT_MAGIC_ALIGN_SIZE
Fabio Utzig152cca02021-12-14 22:16:37 -0300117 );
Christopher Collins92ea77f2016-12-12 15:59:26 -0800118}
119
Fabio Utzig152cca02021-12-14 22:16:37 -0300120/*
121 * Amount of space used to maintain progress information for a single swap
122 * operation.
123 */
124static inline uint32_t
125boot_status_entry_sz(uint32_t min_write_sz)
126{
127 return BOOT_STATUS_STATE_COUNT * min_write_sz;
128}
129
130uint32_t
131boot_status_sz(uint32_t min_write_sz)
132{
133 return BOOT_STATUS_MAX_ENTRIES * boot_status_entry_sz(min_write_sz);
134}
135
136uint32_t
137boot_trailer_sz(uint32_t min_write_sz)
138{
139 return boot_status_sz(min_write_sz) + boot_trailer_info_sz();
140}
141
142#if MCUBOOT_SWAP_USING_SCRATCH
143/*
144 * Similar to `boot_trailer_sz` but this function returns the space used to
145 * store status in the scratch partition. The scratch partition only stores
146 * status during the swap of the last sector from primary/secondary (which
147 * is the first swap operation) and thus only requires space for one swap.
148 */
149static uint32_t
150boot_scratch_trailer_sz(uint32_t min_write_sz)
151{
152 return boot_status_entry_sz(min_write_sz) + boot_trailer_info_sz();
153}
154#endif
155
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400156int
Fabio Utzigb0f04732019-07-31 09:49:19 -0300157boot_status_entries(int image_index, const struct flash_area *fap)
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400158{
Fabio Utzig12d59162019-11-28 10:01:59 -0300159#if MCUBOOT_SWAP_USING_SCRATCH
Dominik Ermel260ae092021-04-23 05:38:45 +0000160 if (flash_area_get_id(fap) == FLASH_AREA_IMAGE_SCRATCH) {
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400161 return BOOT_STATUS_STATE_COUNT;
Fabio Utzig12d59162019-11-28 10:01:59 -0300162 } else
163#endif
Dominik Ermel260ae092021-04-23 05:38:45 +0000164 if (flash_area_get_id(fap) == FLASH_AREA_IMAGE_PRIMARY(image_index) ||
165 flash_area_get_id(fap) == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
David Vinczeb75c12a2019-03-22 14:58:33 +0100166 return BOOT_STATUS_STATE_COUNT * BOOT_STATUS_MAX_ENTRIES;
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400167 }
Fabio Utzig9d160092019-08-09 07:46:34 -0300168 return -1;
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400169}
170
Christopher Collins92ea77f2016-12-12 15:59:26 -0800171uint32_t
172boot_status_off(const struct flash_area *fap)
173{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300174 uint32_t off_from_end;
175 uint8_t elem_sz;
176
177 elem_sz = flash_area_align(fap);
178
Fabio Utzig152cca02021-12-14 22:16:37 -0300179#if MCUBOOT_SWAP_USING_SCRATCH
180 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
181 off_from_end = boot_scratch_trailer_sz(elem_sz);
182 } else {
183#endif
184 off_from_end = boot_trailer_sz(elem_sz);
185#if MCUBOOT_SWAP_USING_SCRATCH
186 }
187#endif
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300188
Dominik Ermel260ae092021-04-23 05:38:45 +0000189 assert(off_from_end <= flash_area_get_size(fap));
190 return flash_area_get_size(fap) - off_from_end;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800191}
192
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000193static int
194boot_magic_decode(const uint32_t *magic)
195{
196 if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
197 return BOOT_MAGIC_GOOD;
198 }
199 return BOOT_MAGIC_BAD;
200}
201
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300202static inline uint32_t
203boot_magic_off(const struct flash_area *fap)
204{
Dominik Ermel260ae092021-04-23 05:38:45 +0000205 return flash_area_get_size(fap) - BOOT_MAGIC_SZ;
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300206}
207
208static inline uint32_t
209boot_image_ok_off(const struct flash_area *fap)
210{
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000211 return ALIGN_DOWN(boot_magic_off(fap) - BOOT_MAX_ALIGN, BOOT_MAX_ALIGN);
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300212}
213
214static inline uint32_t
215boot_copy_done_off(const struct flash_area *fap)
216{
217 return boot_image_ok_off(fap) - BOOT_MAX_ALIGN;
218}
219
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300220static inline uint32_t
Fabio Utzig46490722017-09-04 15:34:32 -0300221boot_swap_size_off(const struct flash_area *fap)
222{
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300223 return boot_swap_info_off(fap) - BOOT_MAX_ALIGN;
Fabio Utzig46490722017-09-04 15:34:32 -0300224}
225
Fabio Utzigba829042018-09-18 08:29:34 -0300226#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300227static inline uint32_t
Fabio Utzigba829042018-09-18 08:29:34 -0300228boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
229{
Fabio Utzig4741c452019-12-19 15:32:41 -0300230#if MCUBOOT_SWAP_SAVE_ENCTLV
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000231 return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_TLV_ALIGN_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300232#else
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000233 return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300234#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300235}
236#endif
237
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300238/**
239 * This functions tries to locate the status area after an aborted swap,
240 * by looking for the magic in the possible locations.
241 *
Sam Bristowd0ca0ff2019-10-30 20:51:35 +1300242 * If the magic is successfully found, a flash_area * is returned and it
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300243 * is the responsibility of the called to close it.
244 *
245 * @returns 0 on success, -1 on errors
246 */
247static int
248boot_find_status(int image_index, const struct flash_area **fap)
249{
250 uint32_t magic[BOOT_MAGIC_ARR_SZ];
251 uint32_t off;
252 uint8_t areas[2] = {
Fabio Utzig12d59162019-11-28 10:01:59 -0300253#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300254 FLASH_AREA_IMAGE_SCRATCH,
Fabio Utzig12d59162019-11-28 10:01:59 -0300255#endif
Fabio Utzig3c446072019-11-22 12:48:26 -0300256 FLASH_AREA_IMAGE_PRIMARY(image_index),
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300257 };
258 unsigned int i;
259 int rc;
260
261 /*
262 * In the middle a swap, tries to locate the area that is currently
263 * storing a valid magic, first on the primary slot, then on scratch.
264 * Both "slots" can end up being temporary storage for a swap and it
265 * is assumed that if magic is valid then other metadata is too,
266 * because magic is always written in the last step.
267 */
268
269 for (i = 0; i < sizeof(areas) / sizeof(areas[0]); i++) {
270 rc = flash_area_open(areas[i], fap);
271 if (rc != 0) {
272 return rc;
273 }
274
275 off = boot_magic_off(*fap);
276 rc = flash_area_read(*fap, off, magic, BOOT_MAGIC_SZ);
Dominik Ermelec6dac52021-10-22 14:55:37 +0000277 flash_area_close(*fap);
278
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300279 if (rc != 0) {
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300280 return rc;
281 }
282
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000283 if (BOOT_MAGIC_GOOD == boot_magic_decode(magic)) {
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300284 return 0;
285 }
286
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300287 }
288
289 /* If we got here, no magic was found */
290 return -1;
291}
292
Christopher Collins92ea77f2016-12-12 15:59:26 -0800293int
Fabio Utzigb0f04732019-07-31 09:49:19 -0300294boot_read_swap_size(int image_index, uint32_t *swap_size)
Fabio Utzig46490722017-09-04 15:34:32 -0300295{
Fabio Utzig46490722017-09-04 15:34:32 -0300296 uint32_t off;
297 const struct flash_area *fap;
298 int rc;
299
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300300 rc = boot_find_status(image_index, &fap);
301 if (rc == 0) {
302 off = boot_swap_size_off(fap);
303 rc = flash_area_read(fap, off, swap_size, sizeof *swap_size);
Fabio Utzig46490722017-09-04 15:34:32 -0300304 flash_area_close(fap);
Fabio Utzig46490722017-09-04 15:34:32 -0300305 }
306
Fabio Utzig46490722017-09-04 15:34:32 -0300307 return rc;
308}
309
Fabio Utzigba829042018-09-18 08:29:34 -0300310#ifdef MCUBOOT_ENC_IMAGES
311int
Fabio Utzig4741c452019-12-19 15:32:41 -0300312boot_read_enc_key(int image_index, uint8_t slot, struct boot_status *bs)
Fabio Utzigba829042018-09-18 08:29:34 -0300313{
Fabio Utzigba829042018-09-18 08:29:34 -0300314 uint32_t off;
315 const struct flash_area *fap;
Fabio Utzig4741c452019-12-19 15:32:41 -0300316#if MCUBOOT_SWAP_SAVE_ENCTLV
317 int i;
318#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300319 int rc;
320
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300321 rc = boot_find_status(image_index, &fap);
322 if (rc == 0) {
323 off = boot_enc_key_off(fap, slot);
Fabio Utzig4741c452019-12-19 15:32:41 -0300324#if MCUBOOT_SWAP_SAVE_ENCTLV
325 rc = flash_area_read(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
326 if (rc == 0) {
327 for (i = 0; i < BOOT_ENC_TLV_ALIGN_SIZE; i++) {
328 if (bs->enctlv[slot][i] != 0xff) {
329 break;
330 }
331 }
332 /* Only try to decrypt non-erased TLV metadata */
333 if (i != BOOT_ENC_TLV_ALIGN_SIZE) {
334 rc = boot_enc_decrypt(bs->enctlv[slot], bs->enckey[slot]);
335 }
336 }
337#else
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000338 rc = flash_area_read(fap, off, bs->enckey[slot], BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300339#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300340 flash_area_close(fap);
Fabio Utzigba829042018-09-18 08:29:34 -0300341 }
342
Fabio Utzigba829042018-09-18 08:29:34 -0300343 return rc;
344}
345#endif
Fabio Utzig46490722017-09-04 15:34:32 -0300346
Christopher Collins92ea77f2016-12-12 15:59:26 -0800347int
Fabio Utzig2473ac02017-05-02 12:45:02 -0300348boot_write_copy_done(const struct flash_area *fap)
349{
Christopher Collinsa1c12042019-05-23 14:00:28 -0700350 uint32_t off;
351
352 off = boot_copy_done_off(fap);
Ben McCrea4c0ee952019-08-28 09:13:24 -0700353 BOOT_LOG_DBG("writing copy_done; fa_id=%d off=0x%lx (0x%lx)",
Dominik Ermel260ae092021-04-23 05:38:45 +0000354 flash_area_get_id(fap), (unsigned long)off,
355 (unsigned long)(flash_area_get_off(fap) + off));
Fabio Utzig1a1ec172019-08-09 10:21:43 -0300356 return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
Fabio Utzig2473ac02017-05-02 12:45:02 -0300357}
358
359int
Fabio Utzig46490722017-09-04 15:34:32 -0300360boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size)
361{
362 uint32_t off;
Fabio Utzig46490722017-09-04 15:34:32 -0300363
364 off = boot_swap_size_off(fap);
Ben McCrea4c0ee952019-08-28 09:13:24 -0700365 BOOT_LOG_DBG("writing swap_size; fa_id=%d off=0x%lx (0x%lx)",
Dominik Ermel260ae092021-04-23 05:38:45 +0000366 flash_area_get_id(fap), (unsigned long)off,
367 (unsigned long)flash_area_get_off(fap) + off);
Fabio Utzig1a1ec172019-08-09 10:21:43 -0300368 return boot_write_trailer(fap, off, (const uint8_t *) &swap_size, 4);
Fabio Utzig46490722017-09-04 15:34:32 -0300369}
370
Fabio Utzigba829042018-09-18 08:29:34 -0300371#ifdef MCUBOOT_ENC_IMAGES
372int
Fabio Utzig4741c452019-12-19 15:32:41 -0300373boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
374 const struct boot_status *bs)
Fabio Utzigba829042018-09-18 08:29:34 -0300375{
376 uint32_t off;
377 int rc;
378
379 off = boot_enc_key_off(fap, slot);
Fabio Utzig5e6ea222019-12-10 09:49:59 -0300380 BOOT_LOG_DBG("writing enc_key; fa_id=%d off=0x%lx (0x%lx)",
Dominik Ermel260ae092021-04-23 05:38:45 +0000381 flash_area_get_id(fap), (unsigned long)off,
382 (unsigned long)flash_area_get_off(fap) + off);
Fabio Utzig4741c452019-12-19 15:32:41 -0300383#if MCUBOOT_SWAP_SAVE_ENCTLV
384 rc = flash_area_write(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
385#else
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000386 rc = flash_area_write(fap, off, bs->enckey[slot], BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300387#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300388 if (rc != 0) {
389 return BOOT_EFLASH;
390 }
391
392 return 0;
393}
394#endif