|  | 
|  | 1 | +/* | 
|  | 2 | + * SPDX-License-Identifier: Apache-2.0 | 
|  | 3 | + * | 
|  | 4 | + * Copyright (c) 2016-2020 Linaro LTD | 
|  | 5 | + * Copyright (c) 2016-2019 JUUL Labs | 
|  | 6 | + * Copyright (c) 2019-2023 Arm Limited | 
|  | 7 | + * Copyright (c) 2024-2025 Nordic Semiconductor ASA | 
|  | 8 | + * | 
|  | 9 | + * Original license: | 
|  | 10 | + * | 
|  | 11 | + * Licensed to the Apache Software Foundation (ASF) under one | 
|  | 12 | + * or more contributor license agreements.  See the NOTICE file | 
|  | 13 | + * distributed with this work for additional information | 
|  | 14 | + * regarding copyright ownership.  The ASF licenses this file | 
|  | 15 | + * to you under the Apache License, Version 2.0 (the | 
|  | 16 | + * "License"); you may not use this file except in compliance | 
|  | 17 | + * with the License.  You may obtain a copy of the License at | 
|  | 18 | + * | 
|  | 19 | + *  http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 20 | + * | 
|  | 21 | + * Unless required by applicable law or agreed to in writing, | 
|  | 22 | + * software distributed under the License is distributed on an | 
|  | 23 | + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
|  | 24 | + * KIND, either express or implied.  See the License for the | 
|  | 25 | + * specific language governing permissions and limitations | 
|  | 26 | + * under the License. | 
|  | 27 | + */ | 
|  | 28 | + | 
|  | 29 | +/** | 
|  | 30 | + * This file provides an interface to the manifest-based boot loader. | 
|  | 31 | + * Functions defined in this file should only be called while the boot loader is | 
|  | 32 | + * running. | 
|  | 33 | + */ | 
|  | 34 | + | 
|  | 35 | +#include "bootutil_loader.h" | 
|  | 36 | +#include "bootutil/boot_record.h" | 
|  | 37 | +#include "bootutil/boot_hooks.h" | 
|  | 38 | +#ifdef MCUBOOT_ENC_IMAGES | 
|  | 39 | +#include "bootutil/enc_key.h" | 
|  | 40 | +#endif | 
|  | 41 | +#ifdef MCUBOOT_HW_ROLLBACK_PROT | 
|  | 42 | +#include "bootutil/security_cnt.h" | 
|  | 43 | +#endif | 
|  | 44 | +#if defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_OFFSET) || \ | 
|  | 45 | +    defined(MCUBOOT_SWAP_USING_SCRATCH) | 
|  | 46 | +#include "swap_priv.h" | 
|  | 47 | +#endif | 
|  | 48 | +#include "bootutil/bootutil_log.h" | 
|  | 49 | + | 
|  | 50 | +BOOT_LOG_MODULE_DECLARE(mcuboot); | 
|  | 51 | + | 
|  | 52 | +bool | 
|  | 53 | +boot_check_header_erased(struct boot_loader_state *state, int slot) | 
|  | 54 | +{ | 
|  | 55 | +    const struct flash_area *fap = NULL; | 
|  | 56 | +    struct image_header *hdr; | 
|  | 57 | + | 
|  | 58 | +    fap = BOOT_IMG_AREA(state, slot); | 
|  | 59 | +    assert(fap != NULL); | 
|  | 60 | + | 
|  | 61 | +    hdr = boot_img_hdr(state, slot); | 
|  | 62 | +    if (bootutil_buffer_is_erased(fap, &hdr->ih_magic, sizeof(hdr->ih_magic))) { | 
|  | 63 | +        return true; | 
|  | 64 | +    } | 
|  | 65 | + | 
|  | 66 | +    return false; | 
|  | 67 | +} | 
|  | 68 | + | 
|  | 69 | +bool | 
|  | 70 | +boot_check_header_valid(struct boot_loader_state *state, int slot) | 
|  | 71 | +{ | 
|  | 72 | +    const struct flash_area *fap = NULL; | 
|  | 73 | +    struct image_header *hdr; | 
|  | 74 | +    uint32_t size; | 
|  | 75 | + | 
|  | 76 | +    fap = BOOT_IMG_AREA(state, slot); | 
|  | 77 | +    assert(fap != NULL); | 
|  | 78 | + | 
|  | 79 | +    hdr = boot_img_hdr(state, slot); | 
|  | 80 | +    if (hdr->ih_magic != IMAGE_MAGIC) { | 
|  | 81 | +        return false; | 
|  | 82 | +    } | 
|  | 83 | + | 
|  | 84 | +    if (!boot_u32_safe_add(&size, hdr->ih_img_size, hdr->ih_hdr_size)) { | 
|  | 85 | +        return false; | 
|  | 86 | +    } | 
|  | 87 | + | 
|  | 88 | +#ifdef MCUBOOT_DECOMPRESS_IMAGES | 
|  | 89 | +    if (!MUST_DECOMPRESS(fap, BOOT_CURR_IMG(state), hdr)) { | 
|  | 90 | +#else | 
|  | 91 | +    if (1) { | 
|  | 92 | +#endif | 
|  | 93 | +        if (!boot_u32_safe_add(&size, size, hdr->ih_protect_tlv_size)) { | 
|  | 94 | +            return false; | 
|  | 95 | +        } | 
|  | 96 | +    } | 
|  | 97 | + | 
|  | 98 | +    if (size >= flash_area_get_size(fap)) { | 
|  | 99 | +        return false; | 
|  | 100 | +    } | 
|  | 101 | + | 
|  | 102 | +#if !defined(MCUBOOT_ENC_IMAGES) | 
|  | 103 | +    if (IS_ENCRYPTED(hdr)) { | 
|  | 104 | +        return false; | 
|  | 105 | +    } | 
|  | 106 | +#else | 
|  | 107 | +    if ((hdr->ih_flags & IMAGE_F_ENCRYPTED_AES128) && | 
|  | 108 | +        (hdr->ih_flags & IMAGE_F_ENCRYPTED_AES256)) | 
|  | 109 | +    { | 
|  | 110 | +        return false; | 
|  | 111 | +    } | 
|  | 112 | +#endif | 
|  | 113 | + | 
|  | 114 | +#if !defined(MCUBOOT_DECOMPRESS_IMAGES) | 
|  | 115 | +    if (IS_COMPRESSED(hdr)) { | 
|  | 116 | +        return false; | 
|  | 117 | +    } | 
|  | 118 | +#else | 
|  | 119 | +    if ((hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1) && | 
|  | 120 | +        (hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA2)) | 
|  | 121 | +    { | 
|  | 122 | +        return false; | 
|  | 123 | +    } | 
|  | 124 | +#endif | 
|  | 125 | + | 
|  | 126 | +    return true; | 
|  | 127 | +} | 
|  | 128 | + | 
|  | 129 | +int | 
|  | 130 | +boot_read_image_headers(struct boot_loader_state *state, bool require_all, struct boot_status *bs) | 
|  | 131 | +{ | 
|  | 132 | +    int rc; | 
|  | 133 | +    int i; | 
|  | 134 | + | 
|  | 135 | +    for (i = 0; i < BOOT_NUM_SLOTS; i++) { | 
|  | 136 | +        rc = BOOT_HOOK_CALL(boot_read_image_header_hook, BOOT_HOOK_REGULAR, | 
|  | 137 | +                            BOOT_CURR_IMG(state), i, boot_img_hdr(state, i)); | 
|  | 138 | +        if (rc == BOOT_HOOK_REGULAR) | 
|  | 139 | +        { | 
|  | 140 | +            rc = boot_read_image_header(state, i, boot_img_hdr(state, i), bs); | 
|  | 141 | +        } | 
|  | 142 | +        if (rc != 0) { | 
|  | 143 | +            /* If `require_all` is set, fail on any single fail, otherwise | 
|  | 144 | +             * if at least the first slot's header was read successfully, | 
|  | 145 | +             * then the boot loader can attempt a boot. | 
|  | 146 | +             * | 
|  | 147 | +             * Failure to read any headers is a fatal error. | 
|  | 148 | +             */ | 
|  | 149 | +            if (i > 0 && !require_all) { | 
|  | 150 | +                return 0; | 
|  | 151 | +            } else { | 
|  | 152 | +                return rc; | 
|  | 153 | +            } | 
|  | 154 | +        } | 
|  | 155 | +    } | 
|  | 156 | + | 
|  | 157 | +    return 0; | 
|  | 158 | +} | 
|  | 159 | + | 
|  | 160 | +fih_ret | 
|  | 161 | +boot_check_image(struct boot_loader_state *state, struct boot_status *bs, int slot) | 
|  | 162 | +{ | 
|  | 163 | +    TARGET_STATIC uint8_t tmpbuf[BOOT_TMPBUF_SZ]; | 
|  | 164 | +    int rc; | 
|  | 165 | +    FIH_DECLARE(fih_rc, FIH_FAILURE); | 
|  | 166 | +    const struct flash_area *fap = NULL; | 
|  | 167 | +    struct image_header *hdr; | 
|  | 168 | + | 
|  | 169 | +    fap = BOOT_IMG_AREA(state, slot); | 
|  | 170 | +    assert(fap != NULL); | 
|  | 171 | + | 
|  | 172 | +    hdr = boot_img_hdr(state, slot); | 
|  | 173 | + | 
|  | 174 | +    (void)bs; | 
|  | 175 | +    (void)rc; | 
|  | 176 | + | 
|  | 177 | +    /* In the case of ram loading the image has already been decrypted as it is | 
|  | 178 | +     * decrypted when copied in ram | 
|  | 179 | +     */ | 
|  | 180 | +#if defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_RAM_LOAD) | 
|  | 181 | +    if (MUST_DECRYPT(fap, BOOT_CURR_IMG(state), hdr)) { | 
|  | 182 | +        rc = boot_enc_load(state, BOOT_SLOT_SECONDARY, hdr, fap, bs); | 
|  | 183 | +        if (rc < 0) { | 
|  | 184 | +            FIH_RET(fih_rc); | 
|  | 185 | +        } | 
|  | 186 | +        if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC_SLOT(state, BOOT_SLOT_SECONDARY), | 
|  | 187 | +                                        bs->enckey[BOOT_SLOT_SECONDARY])) { | 
|  | 188 | +            FIH_RET(fih_rc); | 
|  | 189 | +        } | 
|  | 190 | +    } | 
|  | 191 | +#endif | 
|  | 192 | + | 
|  | 193 | +    FIH_CALL(bootutil_img_validate, fih_rc, state, hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, | 
|  | 194 | +             NULL, 0, NULL); | 
|  | 195 | + | 
|  | 196 | +    FIH_RET(fih_rc); | 
|  | 197 | +} | 
|  | 198 | + | 
|  | 199 | +int | 
|  | 200 | +boot_compare_version(const struct image_version *ver1, const struct image_version *ver2) | 
|  | 201 | +{ | 
|  | 202 | +#if !defined(MCUBOOT_VERSION_CMP_USE_BUILD_NUMBER) | 
|  | 203 | +    BOOT_LOG_DBG("boot_version_cmp: ver1 %u.%u.%u vs ver2 %u.%u.%u", | 
|  | 204 | +                 (unsigned)ver1->iv_major, (unsigned)ver1->iv_minor, | 
|  | 205 | +                 (unsigned)ver1->iv_revision, (unsigned)ver2->iv_major, | 
|  | 206 | +                 (unsigned)ver2->iv_minor, (unsigned)ver2->iv_revision); | 
|  | 207 | +#else | 
|  | 208 | +    BOOT_LOG_DBG("boot_version_cmp: ver1 %u.%u.%u.%u vs ver2 %u.%u.%u.%u", | 
|  | 209 | +                 (unsigned)ver1->iv_major, (unsigned)ver1->iv_minor, | 
|  | 210 | +                 (unsigned)ver1->iv_revision, (unsigned)ver1->iv_build_num, | 
|  | 211 | +                 (unsigned)ver2->iv_major, (unsigned)ver2->iv_minor, | 
|  | 212 | +                 (unsigned)ver2->iv_revision, (unsigned)ver2->iv_build_num); | 
|  | 213 | +#endif | 
|  | 214 | + | 
|  | 215 | +    if (ver1->iv_major > ver2->iv_major) { | 
|  | 216 | +        return 1; | 
|  | 217 | +    } | 
|  | 218 | +    if (ver1->iv_major < ver2->iv_major) { | 
|  | 219 | +        return -1; | 
|  | 220 | +    } | 
|  | 221 | +    /* The major version numbers are equal, continue comparison. */ | 
|  | 222 | +    if (ver1->iv_minor > ver2->iv_minor) { | 
|  | 223 | +        return 1; | 
|  | 224 | +    } | 
|  | 225 | +    if (ver1->iv_minor < ver2->iv_minor) { | 
|  | 226 | +        return -1; | 
|  | 227 | +    } | 
|  | 228 | +    /* The minor version numbers are equal, continue comparison. */ | 
|  | 229 | +    if (ver1->iv_revision > ver2->iv_revision) { | 
|  | 230 | +        return 1; | 
|  | 231 | +    } | 
|  | 232 | +    if (ver1->iv_revision < ver2->iv_revision) { | 
|  | 233 | +        return -1; | 
|  | 234 | +    } | 
|  | 235 | + | 
|  | 236 | +#if defined(MCUBOOT_VERSION_CMP_USE_BUILD_NUMBER) | 
|  | 237 | +    /* The revisions are equal, continue comparison. */ | 
|  | 238 | +    if (ver1->iv_build_num > ver2->iv_build_num) { | 
|  | 239 | +        return 1; | 
|  | 240 | +    } | 
|  | 241 | +    if (ver1->iv_build_num < ver2->iv_build_num) { | 
|  | 242 | +        return -1; | 
|  | 243 | +    } | 
|  | 244 | +#endif | 
|  | 245 | + | 
|  | 246 | +    return 0; | 
|  | 247 | +} | 
|  | 248 | + | 
|  | 249 | +#ifdef MCUBOOT_HW_ROLLBACK_PROT | 
|  | 250 | +int | 
|  | 251 | +boot_update_security_counter(struct boot_loader_state *state, int slot, int hdr_slot_idx) | 
|  | 252 | +{ | 
|  | 253 | +    const struct flash_area *fap = NULL; | 
|  | 254 | +    uint32_t img_security_cnt; | 
|  | 255 | +    int rc; | 
|  | 256 | + | 
|  | 257 | +    fap = BOOT_IMG_AREA(state, slot); | 
|  | 258 | +    assert(fap != NULL); | 
|  | 259 | + | 
|  | 260 | +    rc = bootutil_get_img_security_cnt(state, hdr_slot_idx, fap, &img_security_cnt); | 
|  | 261 | +    if (rc != 0) { | 
|  | 262 | +        goto done; | 
|  | 263 | +    } | 
|  | 264 | + | 
|  | 265 | +    rc = boot_nv_security_counter_update(BOOT_CURR_IMG(state), img_security_cnt); | 
|  | 266 | +    if (rc != 0) { | 
|  | 267 | +        goto done; | 
|  | 268 | +    } | 
|  | 269 | + | 
|  | 270 | +done: | 
|  | 271 | +    return rc; | 
|  | 272 | +} | 
|  | 273 | +#endif /* MCUBOOT_HW_ROLLBACK_PROT */ | 
|  | 274 | + | 
|  | 275 | +int | 
|  | 276 | +boot_add_shared_data(struct boot_loader_state *state, uint8_t active_slot) | 
|  | 277 | +{ | 
|  | 278 | +#if defined(MCUBOOT_MEASURED_BOOT) || defined(MCUBOOT_DATA_SHARING) | 
|  | 279 | +    int rc; | 
|  | 280 | + | 
|  | 281 | +#ifdef MCUBOOT_MEASURED_BOOT | 
|  | 282 | +    rc = boot_save_boot_status(BOOT_CURR_IMG(state), | 
|  | 283 | +                                boot_img_hdr(state, active_slot), | 
|  | 284 | +                                BOOT_IMG_AREA(state, active_slot)); | 
|  | 285 | +    if (rc != 0) { | 
|  | 286 | +        BOOT_LOG_ERR("Failed to add image data to shared area"); | 
|  | 287 | +        return rc; | 
|  | 288 | +    } | 
|  | 289 | +#endif /* MCUBOOT_MEASURED_BOOT */ | 
|  | 290 | + | 
|  | 291 | +#ifdef MCUBOOT_DATA_SHARING | 
|  | 292 | +    rc = boot_save_shared_data(boot_img_hdr(state, active_slot), | 
|  | 293 | +                                BOOT_IMG_AREA(state, active_slot), | 
|  | 294 | +                                active_slot, boot_get_image_max_sizes()); | 
|  | 295 | +    if (rc != 0) { | 
|  | 296 | +        BOOT_LOG_ERR("Failed to add data to shared memory area."); | 
|  | 297 | +        return rc; | 
|  | 298 | +    } | 
|  | 299 | +#endif /* MCUBOOT_DATA_SHARING */ | 
|  | 300 | + | 
|  | 301 | +    return 0; | 
|  | 302 | + | 
|  | 303 | +#else /* MCUBOOT_MEASURED_BOOT || MCUBOOT_DATA_SHARING */ | 
|  | 304 | +    (void) (state); | 
|  | 305 | +    (void) (active_slot); | 
|  | 306 | + | 
|  | 307 | +    return 0; | 
|  | 308 | +#endif | 
|  | 309 | +} | 
|  | 310 | + | 
|  | 311 | +#if !defined(MCUBOOT_SINGLE_APPLICATION_SLOT_RAM_LOAD) && !defined(MCUBOOT_SINGLE_APPLICATION_SLOT) | 
|  | 312 | +int | 
|  | 313 | +boot_open_all_flash_areas(struct boot_loader_state *state) | 
|  | 314 | +{ | 
|  | 315 | +    size_t slot; | 
|  | 316 | +    int rc = 0; | 
|  | 317 | +    int fa_id; | 
|  | 318 | +    int image_index; | 
|  | 319 | + | 
|  | 320 | +    IMAGES_ITER(BOOT_CURR_IMG(state)) { | 
|  | 321 | +#if BOOT_IMAGE_NUMBER > 1 | 
|  | 322 | +        if (state->img_mask[BOOT_CURR_IMG(state)]) { | 
|  | 323 | +            continue; | 
|  | 324 | +        } | 
|  | 325 | +#endif | 
|  | 326 | +        image_index = BOOT_CURR_IMG(state); | 
|  | 327 | + | 
|  | 328 | +        for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) { | 
|  | 329 | +            fa_id = flash_area_id_from_multi_image_slot(image_index, slot); | 
|  | 330 | +            rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot)); | 
|  | 331 | +            assert(rc == 0); | 
|  | 332 | + | 
|  | 333 | +            if (rc != 0) { | 
|  | 334 | +                BOOT_LOG_ERR("Failed to open flash area ID %d (image %d slot %zu): %d", | 
|  | 335 | +                             fa_id, image_index, slot, rc); | 
|  | 336 | +                goto out; | 
|  | 337 | +            } | 
|  | 338 | +        } | 
|  | 339 | +    } | 
|  | 340 | + | 
|  | 341 | +#if MCUBOOT_SWAP_USING_SCRATCH | 
|  | 342 | +    rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &BOOT_SCRATCH_AREA(state)); | 
|  | 343 | +    assert(rc == 0); | 
|  | 344 | + | 
|  | 345 | +    if (rc != 0) { | 
|  | 346 | +        BOOT_LOG_ERR("Failed to open scratch flash area: %d", rc); | 
|  | 347 | +        goto out; | 
|  | 348 | +    } | 
|  | 349 | +#endif | 
|  | 350 | + | 
|  | 351 | +out: | 
|  | 352 | +    if (rc != 0) { | 
|  | 353 | +        boot_close_all_flash_areas(state); | 
|  | 354 | +    } | 
|  | 355 | + | 
|  | 356 | +    return rc; | 
|  | 357 | +} | 
|  | 358 | + | 
|  | 359 | +void | 
|  | 360 | +boot_close_all_flash_areas(struct boot_loader_state *state) | 
|  | 361 | +{ | 
|  | 362 | +    uint32_t slot; | 
|  | 363 | + | 
|  | 364 | +#if MCUBOOT_SWAP_USING_SCRATCH | 
|  | 365 | +    if (BOOT_SCRATCH_AREA(state) != NULL) { | 
|  | 366 | +        flash_area_close(BOOT_SCRATCH_AREA(state)); | 
|  | 367 | +    } | 
|  | 368 | +#endif | 
|  | 369 | + | 
|  | 370 | +    IMAGES_ITER(BOOT_CURR_IMG(state)) { | 
|  | 371 | +#if BOOT_IMAGE_NUMBER > 1 | 
|  | 372 | +        if (state->img_mask[BOOT_CURR_IMG(state)]) { | 
|  | 373 | +            continue; | 
|  | 374 | +        } | 
|  | 375 | +#endif | 
|  | 376 | +        for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) { | 
|  | 377 | +            if (BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot) != NULL) { | 
|  | 378 | +                flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot)); | 
|  | 379 | +            } | 
|  | 380 | +        } | 
|  | 381 | +    } | 
|  | 382 | +} | 
|  | 383 | +#endif /* !MCUBOOT_SINGLE_APPLICATION_SLOT_RAM_LOAD && !MCUBOOT_SINGLE_APPLICATION_SLOT */ | 
0 commit comments