blob: fa5406d9d7077ae3a6cea6f83444a2b8e89bae5e [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
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +010044MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
45
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
Christopher Collins92ea77f2016-12-12 15:59:26 -080097uint32_t
Fabio Utzig3fbbdac2019-12-19 15:18:23 -030098boot_status_sz(uint32_t min_write_sz)
99{
100 return /* state for all sectors */
101 BOOT_STATUS_MAX_ENTRIES * BOOT_STATUS_STATE_COUNT * min_write_sz;
102}
103
104uint32_t
David Brownab449182019-11-15 09:32:52 -0700105boot_trailer_sz(uint32_t min_write_sz)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800106{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300107 return /* state for all sectors */
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300108 boot_status_sz(min_write_sz) +
Fabio Utzigba829042018-09-18 08:29:34 -0300109#ifdef MCUBOOT_ENC_IMAGES
110 /* encryption keys */
Fabio Utzig4741c452019-12-19 15:32:41 -0300111# if MCUBOOT_SWAP_SAVE_ENCTLV
112 BOOT_ENC_TLV_ALIGN_SIZE * 2 +
113# else
Fabio Utzigba829042018-09-18 08:29:34 -0300114 BOOT_ENC_KEY_SIZE * 2 +
Fabio Utzig4741c452019-12-19 15:32:41 -0300115# endif
Fabio Utzigba829042018-09-18 08:29:34 -0300116#endif
Christopher Collins2adef702019-05-22 14:37:31 -0700117 /* swap_type + copy_done + image_ok + swap_size */
118 BOOT_MAX_ALIGN * 4 +
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300119 BOOT_MAGIC_SZ;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800120}
121
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400122int
Fabio Utzigb0f04732019-07-31 09:49:19 -0300123boot_status_entries(int image_index, const struct flash_area *fap)
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400124{
Fabio Utzig12d59162019-11-28 10:01:59 -0300125#if MCUBOOT_SWAP_USING_SCRATCH
David Vinczeb75c12a2019-03-22 14:58:33 +0100126 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400127 return BOOT_STATUS_STATE_COUNT;
Fabio Utzig12d59162019-11-28 10:01:59 -0300128 } else
129#endif
130 if (fap->fa_id == FLASH_AREA_IMAGE_PRIMARY(image_index) ||
Fabio Utzigb0f04732019-07-31 09:49:19 -0300131 fap->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
David Vinczeb75c12a2019-03-22 14:58:33 +0100132 return BOOT_STATUS_STATE_COUNT * BOOT_STATUS_MAX_ENTRIES;
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400133 }
Fabio Utzig9d160092019-08-09 07:46:34 -0300134 return -1;
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400135}
136
Christopher Collins92ea77f2016-12-12 15:59:26 -0800137uint32_t
138boot_status_off(const struct flash_area *fap)
139{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300140 uint32_t off_from_end;
141 uint8_t elem_sz;
142
143 elem_sz = flash_area_align(fap);
144
Christopher Collins2adef702019-05-22 14:37:31 -0700145 off_from_end = boot_trailer_sz(elem_sz);
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300146
147 assert(off_from_end <= fap->fa_size);
148 return fap->fa_size - off_from_end;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800149}
150
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300151static inline uint32_t
152boot_magic_off(const struct flash_area *fap)
153{
154 return fap->fa_size - BOOT_MAGIC_SZ;
155}
156
157static inline uint32_t
158boot_image_ok_off(const struct flash_area *fap)
159{
160 return boot_magic_off(fap) - BOOT_MAX_ALIGN;
161}
162
163static inline uint32_t
164boot_copy_done_off(const struct flash_area *fap)
165{
166 return boot_image_ok_off(fap) - BOOT_MAX_ALIGN;
167}
168
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300169static inline uint32_t
Fabio Utzig46490722017-09-04 15:34:32 -0300170boot_swap_size_off(const struct flash_area *fap)
171{
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300172 return boot_swap_info_off(fap) - BOOT_MAX_ALIGN;
Fabio Utzig46490722017-09-04 15:34:32 -0300173}
174
Fabio Utzigba829042018-09-18 08:29:34 -0300175#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300176static inline uint32_t
Fabio Utzigba829042018-09-18 08:29:34 -0300177boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
178{
Fabio Utzig4741c452019-12-19 15:32:41 -0300179#if MCUBOOT_SWAP_SAVE_ENCTLV
180 return boot_swap_size_off(fap) - ((slot + 1) *
181 ((((BOOT_ENC_TLV_SIZE - 1) / BOOT_MAX_ALIGN) + 1) * BOOT_MAX_ALIGN));
182#else
Fabio Utzig4e8113b2019-08-09 09:11:18 -0300183 return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300184#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300185}
186#endif
187
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300188/**
189 * This functions tries to locate the status area after an aborted swap,
190 * by looking for the magic in the possible locations.
191 *
Sam Bristowd0ca0ff2019-10-30 20:51:35 +1300192 * If the magic is successfully found, a flash_area * is returned and it
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300193 * is the responsibility of the called to close it.
194 *
195 * @returns 0 on success, -1 on errors
196 */
197static int
198boot_find_status(int image_index, const struct flash_area **fap)
199{
200 uint32_t magic[BOOT_MAGIC_ARR_SZ];
201 uint32_t off;
202 uint8_t areas[2] = {
Fabio Utzig12d59162019-11-28 10:01:59 -0300203#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300204 FLASH_AREA_IMAGE_SCRATCH,
Fabio Utzig12d59162019-11-28 10:01:59 -0300205#endif
Fabio Utzig3c446072019-11-22 12:48:26 -0300206 FLASH_AREA_IMAGE_PRIMARY(image_index),
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300207 };
208 unsigned int i;
209 int rc;
210
211 /*
212 * In the middle a swap, tries to locate the area that is currently
213 * storing a valid magic, first on the primary slot, then on scratch.
214 * Both "slots" can end up being temporary storage for a swap and it
215 * is assumed that if magic is valid then other metadata is too,
216 * because magic is always written in the last step.
217 */
218
219 for (i = 0; i < sizeof(areas) / sizeof(areas[0]); i++) {
220 rc = flash_area_open(areas[i], fap);
221 if (rc != 0) {
222 return rc;
223 }
224
225 off = boot_magic_off(*fap);
226 rc = flash_area_read(*fap, off, magic, BOOT_MAGIC_SZ);
227 if (rc != 0) {
228 flash_area_close(*fap);
229 return rc;
230 }
231
232 if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
233 return 0;
234 }
235
236 flash_area_close(*fap);
237 }
238
239 /* If we got here, no magic was found */
240 return -1;
241}
242
Christopher Collins92ea77f2016-12-12 15:59:26 -0800243int
Fabio Utzigb0f04732019-07-31 09:49:19 -0300244boot_read_swap_size(int image_index, uint32_t *swap_size)
Fabio Utzig46490722017-09-04 15:34:32 -0300245{
Fabio Utzig46490722017-09-04 15:34:32 -0300246 uint32_t off;
247 const struct flash_area *fap;
248 int rc;
249
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300250 rc = boot_find_status(image_index, &fap);
251 if (rc == 0) {
252 off = boot_swap_size_off(fap);
253 rc = flash_area_read(fap, off, swap_size, sizeof *swap_size);
Fabio Utzig46490722017-09-04 15:34:32 -0300254 flash_area_close(fap);
Fabio Utzig46490722017-09-04 15:34:32 -0300255 }
256
Fabio Utzig46490722017-09-04 15:34:32 -0300257 return rc;
258}
259
Fabio Utzigba829042018-09-18 08:29:34 -0300260#ifdef MCUBOOT_ENC_IMAGES
261int
Fabio Utzig4741c452019-12-19 15:32:41 -0300262boot_read_enc_key(int image_index, uint8_t slot, struct boot_status *bs)
Fabio Utzigba829042018-09-18 08:29:34 -0300263{
Fabio Utzigba829042018-09-18 08:29:34 -0300264 uint32_t off;
265 const struct flash_area *fap;
Fabio Utzig4741c452019-12-19 15:32:41 -0300266#if MCUBOOT_SWAP_SAVE_ENCTLV
267 int i;
268#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300269 int rc;
270
Fabio Utzigdf0cc502019-08-09 09:10:41 -0300271 rc = boot_find_status(image_index, &fap);
272 if (rc == 0) {
273 off = boot_enc_key_off(fap, slot);
Fabio Utzig4741c452019-12-19 15:32:41 -0300274#if MCUBOOT_SWAP_SAVE_ENCTLV
275 rc = flash_area_read(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
276 if (rc == 0) {
277 for (i = 0; i < BOOT_ENC_TLV_ALIGN_SIZE; i++) {
278 if (bs->enctlv[slot][i] != 0xff) {
279 break;
280 }
281 }
282 /* Only try to decrypt non-erased TLV metadata */
283 if (i != BOOT_ENC_TLV_ALIGN_SIZE) {
284 rc = boot_enc_decrypt(bs->enctlv[slot], bs->enckey[slot]);
285 }
286 }
287#else
288 rc = flash_area_read(fap, off, bs->enckey[slot], BOOT_ENC_KEY_SIZE);
289#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300290 flash_area_close(fap);
Fabio Utzigba829042018-09-18 08:29:34 -0300291 }
292
Fabio Utzigba829042018-09-18 08:29:34 -0300293 return rc;
294}
295#endif
Fabio Utzig46490722017-09-04 15:34:32 -0300296
Fabio Utzig1a1ec172019-08-09 10:21:43 -0300297/**
298 * Write trailer data; status bytes, swap_size, etc
299 *
300 * @returns 0 on success, != 0 on error.
301 */
Fabio Utzig2473ac02017-05-02 12:45:02 -0300302static int
Fabio Utzig1a1ec172019-08-09 10:21:43 -0300303boot_write_trailer(const struct flash_area *fap, uint32_t off,
304 const uint8_t *inbuf, uint8_t inlen)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800305{
Fabio Utzig644b8d42017-04-20 07:56:05 -0300306 uint8_t buf[BOOT_MAX_ALIGN];
David Brown9d725462017-01-23 15:50:58 -0700307 uint8_t align;
Fabio Utzig39000012018-07-30 12:40:20 -0300308 uint8_t erased_val;
Christopher Collinsa1c12042019-05-23 14:00:28 -0700309 int rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800310
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +0200311 align = flash_area_align(fap);
Fabio Utzig1a1ec172019-08-09 10:21:43 -0300312 if (inlen > BOOT_MAX_ALIGN || align > BOOT_MAX_ALIGN) {
313 return -1;
314 }
Fabio Utzig39000012018-07-30 12:40:20 -0300315 erased_val = flash_area_erased_val(fap);
Fabio Utzig1a1ec172019-08-09 10:21:43 -0300316 if (align < inlen) {
317 align = inlen;
318 }
319 memcpy(buf, inbuf, inlen);
320 memset(&buf[inlen], erased_val, align - inlen);
David Brown9d725462017-01-23 15:50:58 -0700321
322 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800323 if (rc != 0) {
324 return BOOT_EFLASH;
325 }
326
327 return 0;
328}
329
Fabio Utzig1a1ec172019-08-09 10:21:43 -0300330static int
331boot_write_trailer_flag(const struct flash_area *fap, uint32_t off,
332 uint8_t flag_val)
333{
334 const uint8_t buf[1] = { flag_val };
335 return boot_write_trailer(fap, off, buf, 1);
336}
337
Christopher Collins92ea77f2016-12-12 15:59:26 -0800338int
Fabio Utzig2473ac02017-05-02 12:45:02 -0300339boot_write_copy_done(const struct flash_area *fap)
340{
Christopher Collinsa1c12042019-05-23 14:00:28 -0700341 uint32_t off;
342
343 off = boot_copy_done_off(fap);
Ben McCrea4c0ee952019-08-28 09:13:24 -0700344 BOOT_LOG_DBG("writing copy_done; fa_id=%d off=0x%lx (0x%lx)",
Marti Bolivar99ec3832019-09-12 21:21:26 -0600345 fap->fa_id, (unsigned long)off,
346 (unsigned long)(fap->fa_off + off));
Fabio Utzig1a1ec172019-08-09 10:21:43 -0300347 return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
Fabio Utzig2473ac02017-05-02 12:45:02 -0300348}
349
350int
Fabio Utzig46490722017-09-04 15:34:32 -0300351boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size)
352{
353 uint32_t off;
Fabio Utzig46490722017-09-04 15:34:32 -0300354
355 off = boot_swap_size_off(fap);
Ben McCrea4c0ee952019-08-28 09:13:24 -0700356 BOOT_LOG_DBG("writing swap_size; fa_id=%d off=0x%lx (0x%lx)",
Marti Bolivar99ec3832019-09-12 21:21:26 -0600357 fap->fa_id, (unsigned long)off,
358 (unsigned long)fap->fa_off + off);
Fabio Utzig1a1ec172019-08-09 10:21:43 -0300359 return boot_write_trailer(fap, off, (const uint8_t *) &swap_size, 4);
Fabio Utzig46490722017-09-04 15:34:32 -0300360}
361
Fabio Utzigba829042018-09-18 08:29:34 -0300362#ifdef MCUBOOT_ENC_IMAGES
363int
Fabio Utzig4741c452019-12-19 15:32:41 -0300364boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
365 const struct boot_status *bs)
Fabio Utzigba829042018-09-18 08:29:34 -0300366{
367 uint32_t off;
368 int rc;
369
370 off = boot_enc_key_off(fap, slot);
Fabio Utzig5e6ea222019-12-10 09:49:59 -0300371 BOOT_LOG_DBG("writing enc_key; fa_id=%d off=0x%lx (0x%lx)",
372 fap->fa_id, (unsigned long)off,
373 (unsigned long)fap->fa_off + off);
Fabio Utzig4741c452019-12-19 15:32:41 -0300374#if MCUBOOT_SWAP_SAVE_ENCTLV
375 rc = flash_area_write(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
376#else
377 rc = flash_area_write(fap, off, bs->enckey[slot], BOOT_ENC_KEY_SIZE);
378#endif
Fabio Utzigba829042018-09-18 08:29:34 -0300379 if (rc != 0) {
380 return BOOT_EFLASH;
381 }
382
383 return 0;
384}
385#endif