1 /*
2  * SPDX-License-Identifier: Apache-2.0
3  *
4  * Copyright (c) 2020 Arm Limited
5  * Copyright (c) 2020-2023 Nordic Semiconductor ASA
6  */
7 
8 #include <assert.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/devicetree.h>
11 #include <zephyr/drivers/gpio.h>
12 #include "bootutil/image.h"
13 #include "bootutil_priv.h"
14 #include "bootutil/bootutil_log.h"
15 #include "bootutil/bootutil_public.h"
16 #include "bootutil/fault_injection_hardening.h"
17 
18 #include "io/io.h"
19 #include "mcuboot_config/mcuboot_config.h"
20 
21 BOOT_LOG_MODULE_DECLARE(mcuboot);
22 
23 /* Variables passed outside of unit via poiters. */
24 static const struct flash_area *_fa_p;
25 static struct image_header _hdr = { 0 };
26 
27 #if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT) || defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE)
28 /**
29  * Validate hash of a primary boot image.
30  *
31  * @param[in]	fa_p	flash area pointer
32  * @param[in]	hdr	boot image header pointer
33  *
34  * @return		FIH_SUCCESS on success, error code otherwise
35  */
36 fih_ret
boot_image_validate(const struct flash_area * fa_p,struct image_header * hdr)37 boot_image_validate(const struct flash_area *fa_p,
38                     struct image_header *hdr)
39 {
40     static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
41     FIH_DECLARE(fih_rc, FIH_FAILURE);
42 
43     /* NOTE: The first argument to boot_image_validate, for enc_state pointer,
44      * is allowed to be NULL only because the single image loader compiles
45      * with BOOT_IMAGE_NUMBER == 1, which excludes the code that uses
46      * the pointer from compilation.
47      */
48     /* Validate hash */
49     if (IS_ENCRYPTED(hdr))
50     {
51         /* Clear the encrypted flag we didn't supply a key
52          * This flag could be set if there was a decryption in place
53          * was performed. We will try to validate the image, and if still
54          * encrypted the validation will fail, and go in panic mode
55          */
56         hdr->ih_flags &= ~(ENCRYPTIONFLAGS);
57     }
58     FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, hdr, fa_p, tmpbuf,
59              BOOT_TMPBUF_SZ, NULL, 0, NULL);
60 
61     FIH_RET(fih_rc);
62 }
63 #endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT || MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE*/
64 
65 #if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE)
66 inline static fih_ret
boot_image_validate_once(const struct flash_area * fa_p,struct image_header * hdr)67 boot_image_validate_once(const struct flash_area *fa_p,
68                     struct image_header *hdr)
69 {
70     static struct boot_swap_state state;
71     int rc;
72     FIH_DECLARE(fih_rc, FIH_FAILURE);
73 
74     memset(&state, 0, sizeof(struct boot_swap_state));
75     rc = boot_read_swap_state(fa_p, &state);
76     if (rc != 0)
77         FIH_RET(FIH_FAILURE);
78     if (state.magic != BOOT_MAGIC_GOOD
79             || state.image_ok != BOOT_FLAG_SET) {
80         /* At least validate the image once */
81         FIH_CALL(boot_image_validate, fih_rc, fa_p, hdr);
82         if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
83             FIH_RET(FIH_FAILURE);
84         }
85         if (state.magic != BOOT_MAGIC_GOOD) {
86             rc = boot_write_magic(fa_p);
87             if (rc != 0)
88                 FIH_RET(FIH_FAILURE);
89         }
90         rc = boot_write_image_ok(fa_p);
91         if (rc != 0)
92             FIH_RET(FIH_FAILURE);
93     }
94     FIH_RET(FIH_SUCCESS);
95 }
96 #endif
97 
98 /**
99  * Validates that an image in a slot is OK to boot.
100  *
101  * @param[in]	slot	Slot number to check
102  * @param[out]	rsp	Parameters for booting image, on success
103  *
104  * @return		FIH_SUCCESS on success; non-zero on failure.
105  */
validate_image_slot(int slot,struct boot_rsp * rsp)106 static fih_ret validate_image_slot(int slot, struct boot_rsp *rsp)
107 {
108     int rc = -1;
109     FIH_DECLARE(fih_rc, FIH_FAILURE);
110 
111     rc = flash_area_open(slot, &_fa_p);
112     assert(rc == 0);
113 
114     rc = boot_image_load_header(_fa_p, &_hdr);
115     if (rc != 0) {
116         goto other;
117     }
118 
119 #ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
120     FIH_CALL(boot_image_validate, fih_rc, _fa_p, &_hdr);
121     if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
122         goto other;
123     }
124 #elif defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE)
125     FIH_CALL(boot_image_validate_once, fih_rc, _fa_p, &_hdr);
126     if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
127         goto other;
128     }
129 #else
130     fih_rc = FIH_SUCCESS;
131 #endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */
132 
133     rsp->br_flash_dev_id = flash_area_get_device_id(_fa_p);
134     rsp->br_image_off = flash_area_get_off(_fa_p);
135     rsp->br_hdr = &_hdr;
136 
137 other:
138     flash_area_close(_fa_p);
139 
140     FIH_RET(fih_rc);
141 }
142 
143 /**
144  * Gather information on image and prepare for booting. Will boot from main
145  * image if none of the enabled entrance modes for the firmware loader are set,
146  * otherwise will boot the firmware loader. Note: firmware loader must be a
147  * valid signed image with the same signing key as the application image.
148  *
149  * @param[out]	rsp	Parameters for booting image, on success
150  *
151  * @return		FIH_SUCCESS on success; non-zero on failure.
152  */
153 fih_ret
boot_go(struct boot_rsp * rsp)154 boot_go(struct boot_rsp *rsp)
155 {
156     bool boot_firmware_loader = false;
157     FIH_DECLARE(fih_rc, FIH_FAILURE);
158 
159 #ifdef CONFIG_BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO
160     if (io_detect_pin() &&
161             !io_boot_skip_serial_recovery()) {
162         boot_firmware_loader = true;
163     }
164 #endif
165 
166 #ifdef CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET
167     if (io_detect_pin_reset()) {
168         boot_firmware_loader = true;
169     }
170 #endif
171 
172 #ifdef CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE
173     if (io_detect_boot_mode()) {
174         boot_firmware_loader = true;
175     }
176 #endif
177 
178     /* Check if firmware loader button is pressed. TODO: check all entrance methods */
179     if (boot_firmware_loader == true) {
180         FIH_CALL(validate_image_slot, fih_rc, FLASH_AREA_IMAGE_SECONDARY(0), rsp);
181 
182         if (FIH_EQ(fih_rc, FIH_SUCCESS)) {
183             FIH_RET(fih_rc);
184         }
185     }
186 
187     FIH_CALL(validate_image_slot, fih_rc, FLASH_AREA_IMAGE_PRIMARY(0), rsp);
188 
189 #ifdef CONFIG_BOOT_FIRMWARE_LOADER_NO_APPLICATION
190     if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
191         FIH_CALL(validate_image_slot, fih_rc, FLASH_AREA_IMAGE_SECONDARY(0), rsp);
192     }
193 #endif
194 
195     FIH_RET(fih_rc);
196 }
197