1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 #include <assert.h>
20 #include <stddef.h>
21 #include <inttypes.h>
22 #include <ctype.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <limits.h>
26
27 #include "sysflash/sysflash.h"
28
29 #include "bootutil/bootutil_log.h"
30
31 #ifdef __ZEPHYR__
32 #include <zephyr/sys/reboot.h>
33 #include <zephyr/sys/byteorder.h>
34 #include <zephyr/sys/__assert.h>
35 #include <zephyr/drivers/flash.h>
36 #include <zephyr/kernel.h>
37 #include <zephyr/sys/crc.h>
38 #include <zephyr/sys/base64.h>
39 #include <hal/hal_flash.h>
40 #elif __ESPRESSIF__
41 #include <bootloader_utility.h>
42 #include <esp_rom_sys.h>
43 #include <esp_crc.h>
44 #include <endian.h>
45 #include <mbedtls/base64.h>
46 #else
47 #include <bsp/bsp.h>
48 #include <hal/hal_system.h>
49 #include <hal/hal_flash.h>
50 #include <os/endian.h>
51 #include <os/os_cputime.h>
52 #include <crc/crc16.h>
53 #include <base64/base64.h>
54 #endif /* __ZEPHYR__ */
55
56 #include <zcbor_decode.h>
57 #include <zcbor_encode.h>
58 #include "zcbor_bulk.h"
59
60 #include <flash_map_backend/flash_map_backend.h>
61 #include <os/os.h>
62 #include <os/os_malloc.h>
63
64 #include <bootutil/image.h>
65 #include <bootutil/bootutil.h>
66
67 #include "boot_serial/boot_serial.h"
68 #include "boot_serial_priv.h"
69 #include "mcuboot_config/mcuboot_config.h"
70 #include "../src/bootutil_priv.h"
71
72 #ifdef MCUBOOT_ENC_IMAGES
73 #include "boot_serial/boot_serial_encryption.h"
74 #endif
75
76 #include "bootutil/boot_hooks.h"
77
78 BOOT_LOG_MODULE_DECLARE(mcuboot);
79
80 #ifndef ARRAY_SIZE
81 #define ARRAY_SIZE ZCBOR_ARRAY_SIZE
82 #endif
83
84 #if defined(MCUBOOT_SHA512)
85 #define IMAGE_HASH_SIZE (64)
86 #define IMAGE_SHA_TLV IMAGE_TLV_SHA512
87 #elif defined(MCUBOOT_SIGN_EC384)
88 #define IMAGE_HASH_SIZE (48)
89 #define IMAGE_SHA_TLV IMAGE_TLV_SHA384
90 #else
91 #define IMAGE_HASH_SIZE (32)
92 #define IMAGE_SHA_TLV IMAGE_TLV_SHA256
93 #endif
94
95 #ifndef MCUBOOT_SERIAL_MAX_RECEIVE_SIZE
96 #define MCUBOOT_SERIAL_MAX_RECEIVE_SIZE 512
97 #endif
98
99 #ifdef MCUBOOT_SERIAL_IMG_GRP_IMAGE_STATE
100 #define BOOT_SERIAL_IMAGE_STATE_SIZE_MAX 48
101 #else
102 #define BOOT_SERIAL_IMAGE_STATE_SIZE_MAX 0
103 #endif
104 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
105 #define BOOT_SERIAL_HASH_SIZE_MAX (IMAGE_HASH_SIZE + 4)
106 #else
107 #define BOOT_SERIAL_HASH_SIZE_MAX 0
108 #endif
109 #ifdef MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO
110 #define BOOT_SERIAL_SLOT_INFO_SIZE_MAX 164
111 #else
112 #define BOOT_SERIAL_SLOT_INFO_SIZE_MAX 0
113 #endif
114
115 #if (128 + BOOT_SERIAL_IMAGE_STATE_SIZE_MAX + BOOT_SERIAL_HASH_SIZE_MAX) > \
116 BOOT_SERIAL_SLOT_INFO_SIZE_MAX
117 #define BOOT_SERIAL_MAX_MESSAGE_SIZE (128 + BOOT_SERIAL_IMAGE_STATE_SIZE_MAX + \
118 BOOT_SERIAL_HASH_SIZE_MAX)
119 #else
120 #define BOOT_SERIAL_MAX_MESSAGE_SIZE BOOT_SERIAL_SLOT_INFO_SIZE_MAX
121 #endif
122
123 #define BOOT_SERIAL_OUT_MAX (BOOT_SERIAL_MAX_MESSAGE_SIZE * BOOT_IMAGE_NUMBER)
124
125 #define BOOT_SERIAL_FRAME_MTU 124 /* 127 - pkt start (2 bytes) and stop (1 byte) */
126
127 /* Number of estimated CBOR elements for responses */
128 #define CBOR_ENTRIES_SLOT_INFO_IMAGE_MAP 4
129 #define CBOR_ENTRIES_SLOT_INFO_SLOTS_MAP 3
130
131 #ifdef __ZEPHYR__
132 /* base64 lib encodes data to null-terminated string */
133 #define BASE64_ENCODE_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1)
134
135 #define CRC16_INITIAL_CRC 0 /* what to seed crc16 with */
136 #define CRC_CITT_POLYMINAL 0x1021
137
138 #define ntohs(x) sys_be16_to_cpu(x)
139 #define htons(x) sys_cpu_to_be16(x)
140 #elif __ESPRESSIF__
141 #define BASE64_ENCODE_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1)
142 #define CRC16_INITIAL_CRC 0 /* what to seed crc16 with */
143
144 #define ntohs(x) be16toh(x)
145 #define htons(x) htobe16(x)
146
147 #define base64_decode mbedtls_base64_decode
148 #define base64_encode mbedtls_base64_encode
149 #endif
150
151 #if (BOOT_IMAGE_NUMBER > 1)
152 #define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
153 #else
154 #define IMAGES_ITER(x)
155 #endif
156
157 #define SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN 1
158 #define BOOT_DIRECT_UPLOAD_SECONDARY_SLOT_ID_REMAINDER 0
159
160 static char in_buf[MCUBOOT_SERIAL_MAX_RECEIVE_SIZE + 1];
161 static char dec_buf[MCUBOOT_SERIAL_MAX_RECEIVE_SIZE + 1];
162 const struct boot_uart_funcs *boot_uf;
163 static struct nmgr_hdr *bs_hdr;
164 static bool bs_entry;
165
166 static char bs_obuf[BOOT_SERIAL_OUT_MAX];
167
168 static void boot_serial_output(void);
169
170 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
171 #ifdef MCUBOOT_SWAP_USING_OFFSET
172 static int boot_serial_get_hash(const struct image_header *hdr,
173 const struct flash_area *fap, uint8_t *hash, uint32_t start_off);
174 #else
175 static int boot_serial_get_hash(const struct image_header *hdr,
176 const struct flash_area *fap, uint8_t *hash);
177 #endif
178 #endif
179
180 static zcbor_state_t cbor_state[2];
181
reset_cbor_state(void)182 void reset_cbor_state(void)
183 {
184 zcbor_new_encode_state(cbor_state, 2, (uint8_t *)bs_obuf,
185 sizeof(bs_obuf), 0);
186 }
187
188 /**
189 * Function that processes MGMT_GROUP_ID_PERUSER mcumgr group and may be
190 * used to process any groups that have not been processed by generic boot
191 * serial implementation.
192 *
193 * @param[in] hdr -- the decoded header of mcumgr message;
194 * @param[in] buffer -- buffer with first mcumgr message;
195 * @param[in] len -- length of of data in buffer;
196 * @param[out] *cs -- object with encoded response.
197 *
198 * @return 0 on success; non-0 error code otherwise.
199 */
200 extern int bs_peruser_system_specific(const struct nmgr_hdr *hdr,
201 const char *buffer,
202 int len, zcbor_state_t *cs);
203
204 #define zcbor_tstr_put_lit_cast(state, string) \
205 zcbor_tstr_encode_ptr(state, (char *)string, sizeof(string) - 1)
206
207 #ifndef MCUBOOT_USE_SNPRINTF
208 /*
209 * Convert version into string without use of snprintf().
210 */
211 static int
u32toa(char * tgt,uint32_t val)212 u32toa(char *tgt, uint32_t val)
213 {
214 char *dst;
215 uint32_t d = 1;
216 uint32_t dgt;
217 int n = 0;
218
219 dst = tgt;
220 while (val / d >= 10) {
221 d *= 10;
222 }
223 while (d) {
224 dgt = val / d;
225 val %= d;
226 d /= 10;
227 if (n || dgt > 0 || d == 0) {
228 *dst++ = dgt + '0';
229 ++n;
230 }
231 }
232 *dst = '\0';
233
234 return dst - tgt;
235 }
236
237 /*
238 * dst has to be able to fit "255.255.65535.4294967295" (25 characters).
239 */
240 static void
bs_list_img_ver(char * dst,int maxlen,struct image_version * ver)241 bs_list_img_ver(char *dst, int maxlen, struct image_version *ver)
242 {
243 int off;
244
245 off = u32toa(dst, ver->iv_major);
246 dst[off++] = '.';
247 off += u32toa(dst + off, ver->iv_minor);
248 dst[off++] = '.';
249 off += u32toa(dst + off, ver->iv_revision);
250
251 if (ver->iv_build_num != 0) {
252 dst[off++] = '.';
253 off += u32toa(dst + off, ver->iv_build_num);
254 }
255 }
256 #else
257 /*
258 * dst has to be able to fit "255.255.65535.4294967295" (25 characters).
259 */
260 static void
bs_list_img_ver(char * dst,int maxlen,struct image_version * ver)261 bs_list_img_ver(char *dst, int maxlen, struct image_version *ver)
262 {
263 int len;
264
265 len = snprintf(dst, maxlen, "%hu.%hu.%hu", (uint16_t)ver->iv_major,
266 (uint16_t)ver->iv_minor, ver->iv_revision);
267
268 if (ver->iv_build_num != 0 && len > 0 && len < maxlen) {
269 snprintf(&dst[len], (maxlen - len), ".%u", ver->iv_build_num);
270 }
271 }
272 #endif /* !MCUBOOT_USE_SNPRINTF */
273
274 /*
275 * List images.
276 */
277 static void
bs_list(char * buf,int len)278 bs_list(char *buf, int len)
279 {
280 struct image_header hdr;
281 uint32_t slot, area_id;
282 const struct flash_area *fap;
283 uint8_t image_index;
284 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
285 uint8_t hash[IMAGE_HASH_SIZE];
286 #endif
287
288 zcbor_map_start_encode(cbor_state, 1);
289 zcbor_tstr_put_lit_cast(cbor_state, "images");
290 zcbor_list_start_encode(cbor_state, 5);
291 image_index = 0;
292 IMAGES_ITER(image_index) {
293 #ifdef MCUBOOT_SERIAL_IMG_GRP_IMAGE_STATE
294 int swap_status = boot_swap_type_multi(image_index);
295 #endif
296
297 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
298 FIH_DECLARE(fih_rc, FIH_FAILURE);
299 int rc;
300 uint8_t tmpbuf[64];
301
302 #ifdef MCUBOOT_SERIAL_IMG_GRP_IMAGE_STATE
303 bool active = false;
304 bool confirmed = false;
305 bool pending = false;
306 bool permanent = false;
307 #endif
308
309 #ifdef MCUBOOT_SWAP_USING_OFFSET
310 uint32_t start_off = 0;
311 #endif
312
313 area_id = flash_area_id_from_multi_image_slot(image_index, slot);
314 if (flash_area_open(area_id, &fap)) {
315 continue;
316 }
317
318 #ifdef MCUBOOT_SWAP_USING_OFFSET
319 if (slot == BOOT_SECONDARY_SLOT && swap_status != BOOT_SWAP_TYPE_REVERT) {
320 uint32_t num_sectors = SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN;
321 struct flash_sector sector_data;
322
323 rc = flash_area_sectors(fap, &num_sectors, §or_data);
324
325 if ((rc != 0 && rc != -ENOMEM) ||
326 num_sectors != SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN) {
327 flash_area_close(fap);
328 continue;
329 }
330
331 start_off = sector_data.fs_size;
332 }
333 #endif
334
335 rc = BOOT_HOOK_CALL(boot_read_image_header_hook,
336 BOOT_HOOK_REGULAR, image_index, slot, &hdr);
337 if (rc == BOOT_HOOK_REGULAR)
338 {
339 #ifdef MCUBOOT_SWAP_USING_OFFSET
340 flash_area_read(fap, start_off, &hdr, sizeof(hdr));
341 #else
342 flash_area_read(fap, 0, &hdr, sizeof(hdr));
343 #endif
344 }
345
346 if (hdr.ih_magic == IMAGE_MAGIC)
347 {
348 BOOT_HOOK_CALL_FIH(boot_image_check_hook,
349 FIH_BOOT_HOOK_REGULAR,
350 fih_rc, image_index, slot);
351 if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR))
352 {
353 #if defined(MCUBOOT_ENC_IMAGES)
354 #if !defined(MCUBOOT_SINGLE_APPLICATION_SLOT)
355 if (IS_ENCRYPTED(&hdr) && MUST_DECRYPT(fap, image_index, &hdr)) {
356 #ifdef MCUBOOT_SWAP_USING_OFFSET
357 FIH_CALL(boot_image_validate_encrypted, fih_rc, fap,
358 &hdr, tmpbuf, sizeof(tmpbuf), start_off);
359 #else
360 FIH_CALL(boot_image_validate_encrypted, fih_rc, fap,
361 &hdr, tmpbuf, sizeof(tmpbuf));
362 #endif
363 } else {
364 #endif
365 if (IS_ENCRYPTED(&hdr)) {
366 /*
367 * There is an image present which has an encrypted flag set but is
368 * not encrypted, therefore remove the flag from the header and run a
369 * normal image validation on it.
370 */
371 hdr.ih_flags &= ~ENCRYPTIONFLAGS;
372 }
373 #endif
374
375 #ifdef MCUBOOT_SWAP_USING_OFFSET
376 FIH_CALL(bootutil_img_validate, fih_rc, NULL, &hdr,
377 fap, tmpbuf, sizeof(tmpbuf), NULL, 0, NULL, start_off);
378 #else
379 FIH_CALL(bootutil_img_validate, fih_rc, NULL, &hdr,
380 fap, tmpbuf, sizeof(tmpbuf), NULL, 0, NULL);
381 #endif
382 #if defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_SINGLE_APPLICATION_SLOT)
383 }
384 #endif
385 }
386 }
387
388 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
389 flash_area_close(fap);
390 continue;
391 }
392
393 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
394 /* Retrieve hash of image for identification */
395 #ifdef MCUBOOT_SWAP_USING_OFFSET
396 rc = boot_serial_get_hash(&hdr, fap, hash, start_off);
397 #else
398 rc = boot_serial_get_hash(&hdr, fap, hash);
399 #endif
400 #endif
401
402 flash_area_close(fap);
403 zcbor_map_start_encode(cbor_state, 20);
404
405 #if (BOOT_IMAGE_NUMBER > 1)
406 zcbor_tstr_put_lit_cast(cbor_state, "image");
407 zcbor_uint32_put(cbor_state, image_index);
408 #endif
409
410 #ifdef MCUBOOT_SERIAL_IMG_GRP_IMAGE_STATE
411 if (swap_status == BOOT_SWAP_TYPE_NONE) {
412 if (slot == BOOT_PRIMARY_SLOT) {
413 confirmed = true;
414 active = true;
415 }
416 } else if (swap_status == BOOT_SWAP_TYPE_TEST) {
417 if (slot == BOOT_PRIMARY_SLOT) {
418 confirmed = true;
419 } else {
420 pending = true;
421 }
422 } else if (swap_status == BOOT_SWAP_TYPE_PERM) {
423 if (slot == BOOT_PRIMARY_SLOT) {
424 confirmed = true;
425 } else {
426 pending = true;
427 permanent = true;
428 }
429 } else if (swap_status == BOOT_SWAP_TYPE_REVERT) {
430 if (slot == BOOT_PRIMARY_SLOT) {
431 active = true;
432 } else {
433 confirmed = true;
434 }
435 }
436
437 if (!(hdr.ih_flags & IMAGE_F_NON_BOOTABLE)) {
438 zcbor_tstr_put_lit_cast(cbor_state, "bootable");
439 zcbor_bool_put(cbor_state, true);
440 }
441
442 if (confirmed) {
443 zcbor_tstr_put_lit_cast(cbor_state, "confirmed");
444 zcbor_bool_put(cbor_state, true);
445 }
446
447 if (active) {
448 zcbor_tstr_put_lit_cast(cbor_state, "active");
449 zcbor_bool_put(cbor_state, true);
450 }
451
452 if (pending) {
453 zcbor_tstr_put_lit_cast(cbor_state, "pending");
454 zcbor_bool_put(cbor_state, true);
455 }
456
457 if (permanent) {
458 zcbor_tstr_put_lit_cast(cbor_state, "permanent");
459 zcbor_bool_put(cbor_state, true);
460 }
461 #endif
462
463 zcbor_tstr_put_lit_cast(cbor_state, "slot");
464 zcbor_uint32_put(cbor_state, slot);
465
466 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
467 if (rc == 0) {
468 zcbor_tstr_put_lit_cast(cbor_state, "hash");
469 zcbor_bstr_encode_ptr(cbor_state, hash, sizeof(hash));
470 }
471 #endif
472
473 zcbor_tstr_put_lit_cast(cbor_state, "version");
474
475 bs_list_img_ver((char *)tmpbuf, sizeof(tmpbuf), &hdr.ih_ver);
476
477 zcbor_tstr_encode_ptr(cbor_state, (char *)tmpbuf, strlen((char *)tmpbuf));
478 zcbor_map_end_encode(cbor_state, 20);
479 }
480 }
481 zcbor_list_end_encode(cbor_state, 5);
482 zcbor_map_end_encode(cbor_state, 1);
483 boot_serial_output();
484 }
485
486 #ifdef MCUBOOT_SERIAL_IMG_GRP_IMAGE_STATE
487 /*
488 * Set image state.
489 */
490 static void
bs_set(char * buf,int len)491 bs_set(char *buf, int len)
492 {
493 /*
494 * Expected data format.
495 * {
496 * "confirm":<true for confirm, false for test>
497 * "hash":<hash of image (OPTIONAL for single image only)>
498 * }
499 */
500 uint8_t image_index = 0;
501 size_t decoded = 0;
502 uint8_t hash[IMAGE_HASH_SIZE];
503 bool confirm = false;
504 struct zcbor_string img_hash = { 0 };
505 bool ok;
506 int rc;
507
508 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
509 bool found = false;
510 #endif
511
512 zcbor_state_t zsd[4];
513 zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1, NULL, 0);
514
515 struct zcbor_map_decode_key_val image_set_state_decode[] = {
516 ZCBOR_MAP_DECODE_KEY_DECODER("confirm", zcbor_bool_decode, &confirm),
517 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
518 ZCBOR_MAP_DECODE_KEY_DECODER("hash", zcbor_bstr_decode, &img_hash),
519 #endif
520 };
521
522 ok = zcbor_map_decode_bulk(zsd, image_set_state_decode, ARRAY_SIZE(image_set_state_decode),
523 &decoded) == 0;
524
525 if (!ok) {
526 rc = MGMT_ERR_EINVAL;
527 goto out;
528 }
529
530 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
531 if ((img_hash.len != sizeof(hash) && img_hash.len != 0) ||
532 (img_hash.len == 0 && BOOT_IMAGE_NUMBER > 1)) {
533 /* Hash is required and was not provided or is invalid size */
534 rc = MGMT_ERR_EINVAL;
535 goto out;
536 }
537
538 if (img_hash.len != 0) {
539 for (image_index = 0; image_index < BOOT_IMAGE_NUMBER; ++image_index) {
540 struct image_header hdr;
541 uint32_t area_id;
542 const struct flash_area *fap;
543 uint8_t tmpbuf[64];
544
545 #ifdef MCUBOOT_SWAP_USING_OFFSET
546 uint32_t num_sectors = SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN;
547 struct flash_sector sector_data;
548 uint32_t start_off = 0;
549 #endif
550
551 area_id = flash_area_id_from_multi_image_slot(image_index, 1);
552 if (flash_area_open(area_id, &fap)) {
553 BOOT_LOG_ERR("Failed to open flash area ID %d", area_id);
554 continue;
555 }
556
557 #ifdef MCUBOOT_SWAP_USING_OFFSET
558 rc = flash_area_sectors(fap, &num_sectors, §or_data);
559
560 if ((rc != 0 && rc != -ENOMEM) ||
561 num_sectors != SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN) {
562 flash_area_close(fap);
563 continue;
564 }
565
566 start_off = sector_data.fs_size;
567 #endif
568
569 rc = BOOT_HOOK_CALL(boot_read_image_header_hook,
570 BOOT_HOOK_REGULAR, image_index, 1, &hdr);
571 if (rc == BOOT_HOOK_REGULAR)
572 {
573 #ifdef MCUBOOT_SWAP_USING_OFFSET
574 flash_area_read(fap, start_off, &hdr, sizeof(hdr));
575 #else
576 flash_area_read(fap, 0, &hdr, sizeof(hdr));
577 #endif
578 }
579
580 if (hdr.ih_magic == IMAGE_MAGIC)
581 {
582 FIH_DECLARE(fih_rc, FIH_FAILURE);
583
584 BOOT_HOOK_CALL_FIH(boot_image_check_hook,
585 FIH_BOOT_HOOK_REGULAR,
586 fih_rc, image_index, 1);
587 if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR))
588 {
589 #ifdef MCUBOOT_ENC_IMAGES
590 if (IS_ENCRYPTED(&hdr)) {
591 #ifdef MCUBOOT_SWAP_USING_OFFSET
592 FIH_CALL(boot_image_validate_encrypted, fih_rc, fap,
593 &hdr, tmpbuf, sizeof(tmpbuf), start_off);
594 #else
595 FIH_CALL(boot_image_validate_encrypted, fih_rc, fap,
596 &hdr, tmpbuf, sizeof(tmpbuf));
597 #endif
598 } else {
599 #endif
600 #ifdef MCUBOOT_SWAP_USING_OFFSET
601 FIH_CALL(bootutil_img_validate, fih_rc, NULL, &hdr,
602 fap, tmpbuf, sizeof(tmpbuf), NULL, 0, NULL, start_off);
603 #else
604 FIH_CALL(bootutil_img_validate, fih_rc, NULL, &hdr,
605 fap, tmpbuf, sizeof(tmpbuf), NULL, 0, NULL);
606 #endif
607 #ifdef MCUBOOT_ENC_IMAGES
608 }
609 #endif
610 }
611
612 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
613 continue;
614 }
615 }
616
617 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
618 /* Retrieve hash of image for identification */
619 #ifdef MCUBOOT_SWAP_USING_OFFSET
620 rc = boot_serial_get_hash(&hdr, fap, hash, start_off);
621 #else
622 rc = boot_serial_get_hash(&hdr, fap, hash);
623 #endif
624 #endif
625 flash_area_close(fap);
626
627 if (rc == 0 && memcmp(hash, img_hash.value, sizeof(hash)) == 0) {
628 /* Hash matches, set this slot for test or confirmation */
629 found = true;
630 break;
631 }
632 }
633
634 if (!found) {
635 /* Image was not found with specified hash */
636 BOOT_LOG_ERR("Did not find image with specified hash");
637 rc = MGMT_ERR_ENOENT;
638 goto out;
639 }
640 }
641 #endif
642
643 rc = boot_set_pending_multi(image_index, confirm);
644
645 out:
646 if (rc == 0) {
647 /* Success - return updated list of images */
648 bs_list(buf, len);
649 } else {
650 /* Error code, only return the error */
651 zcbor_map_start_encode(cbor_state, 10);
652 zcbor_tstr_put_lit_cast(cbor_state, "rc");
653 zcbor_int32_put(cbor_state, rc);
654 zcbor_map_end_encode(cbor_state, 10);
655
656 boot_serial_output();
657 }
658 }
659 #endif
660
661 /*
662 * Send rc code only.
663 */
664 static void
bs_rc_rsp(int rc_code)665 bs_rc_rsp(int rc_code)
666 {
667 zcbor_map_start_encode(cbor_state, 10);
668 zcbor_tstr_put_lit_cast(cbor_state, "rc");
669 zcbor_int32_put(cbor_state, rc_code);
670 zcbor_map_end_encode(cbor_state, 10);
671 boot_serial_output();
672 }
673
674 static void
bs_list_set(uint8_t op,char * buf,int len)675 bs_list_set(uint8_t op, char *buf, int len)
676 {
677 if (op == NMGR_OP_READ) {
678 bs_list(buf, len);
679 } else {
680 #ifdef MCUBOOT_SERIAL_IMG_GRP_IMAGE_STATE
681 bs_set(buf, len);
682 #else
683 bs_rc_rsp(MGMT_ERR_ENOTSUP);
684 #endif
685 }
686 }
687
688 #ifdef MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO
689 static void
bs_slot_info(uint8_t op,char * buf,int len)690 bs_slot_info(uint8_t op, char *buf, int len)
691 {
692 uint32_t slot, area_id;
693 const struct flash_area *fap;
694 uint8_t image_index = 0;
695 int rc;
696 bool ok = true;
697 const struct image_max_size *image_max_sizes;
698
699 if (op != NMGR_OP_READ) {
700 bs_rc_rsp(MGMT_ERR_ENOTSUP);
701 }
702
703 image_max_sizes = boot_get_max_app_size();
704
705 zcbor_map_start_encode(cbor_state, 1);
706 zcbor_tstr_put_lit_cast(cbor_state, "images");
707 zcbor_list_start_encode(cbor_state, MCUBOOT_IMAGE_NUMBER);
708
709 IMAGES_ITER(image_index) {
710 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
711 if (slot == 0) {
712 ok = zcbor_map_start_encode(cbor_state, CBOR_ENTRIES_SLOT_INFO_IMAGE_MAP) &&
713 zcbor_tstr_put_lit(cbor_state, "image") &&
714 zcbor_uint32_put(cbor_state, (uint32_t)image_index) &&
715 zcbor_tstr_put_lit(cbor_state, "slots") &&
716 zcbor_list_start_encode(cbor_state, BOOT_NUM_SLOTS);
717
718 if (!ok) {
719 goto finish;
720 }
721 }
722
723 ok = zcbor_map_start_encode(cbor_state, CBOR_ENTRIES_SLOT_INFO_SLOTS_MAP) &&
724 zcbor_tstr_put_lit(cbor_state, "slot") &&
725 zcbor_uint32_put(cbor_state, slot);
726
727 if (!ok) {
728 goto finish;
729 }
730
731 area_id = flash_area_id_from_multi_image_slot(image_index, slot);
732 rc = flash_area_open(area_id, &fap);
733
734 if (rc) {
735 ok = zcbor_tstr_put_lit(cbor_state, "rc") &&
736 zcbor_int32_put(cbor_state, rc);
737 } else {
738 if (sizeof(fap->fa_size) == sizeof(uint64_t)) {
739 ok = zcbor_tstr_put_lit(cbor_state, "size") &&
740 zcbor_uint64_put(cbor_state, fap->fa_size);
741 } else {
742 ok = zcbor_tstr_put_lit(cbor_state, "size") &&
743 zcbor_uint32_put(cbor_state, fap->fa_size);
744 }
745
746 if (!ok) {
747 flash_area_close(fap);
748 goto finish;
749 }
750
751 /*
752 * Check if we support uploading to this slot and if so, return the
753 * image ID
754 */
755 #if defined(MCUBOOT_SINGLE_APPLICATION_SLOT)
756 ok = zcbor_tstr_put_lit(cbor_state, "upload_image_id") &&
757 zcbor_uint32_put(cbor_state, (image_index + 1));
758 #elif defined(MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD)
759 ok = zcbor_tstr_put_lit(cbor_state, "upload_image_id") &&
760 zcbor_uint32_put(cbor_state, (image_index * 2 + slot + 1));
761 #else
762 if (slot == 1) {
763 ok = zcbor_tstr_put_lit(cbor_state, "upload_image_id") &&
764 zcbor_uint32_put(cbor_state, (image_index * 2 + 1));
765 }
766 #endif
767
768 flash_area_close(fap);
769
770 if (!ok) {
771 goto finish;
772 }
773
774 ok = zcbor_map_end_encode(cbor_state, CBOR_ENTRIES_SLOT_INFO_SLOTS_MAP);
775
776 if (!ok) {
777 goto finish;
778 }
779
780 if (slot == (BOOT_NUM_SLOTS - 1)) {
781 ok = zcbor_list_end_encode(cbor_state, BOOT_NUM_SLOTS);
782
783 if (!ok) {
784 goto finish;
785 }
786
787 if (image_max_sizes[image_index].calculated == true) {
788 ok = zcbor_tstr_put_lit(cbor_state, "max_image_size") &&
789 zcbor_uint32_put(cbor_state,
790 image_max_sizes[image_index].max_size);
791
792 if (!ok) {
793 goto finish;
794 }
795 }
796
797 ok = zcbor_map_end_encode(cbor_state, CBOR_ENTRIES_SLOT_INFO_IMAGE_MAP);
798
799 }
800 }
801
802 if (!ok) {
803 goto finish;
804 }
805 }
806 }
807
808 ok = zcbor_list_end_encode(cbor_state, MCUBOOT_IMAGE_NUMBER) &&
809 zcbor_map_end_encode(cbor_state, 1);
810
811 finish:
812 if (!ok) {
813 reset_cbor_state();
814 bs_rc_rsp(MGMT_ERR_ENOMEM);
815 }
816
817 boot_serial_output();
818 }
819 #endif
820
821 #ifdef MCUBOOT_ERASE_PROGRESSIVELY
822 /** Erases range of flash, aligned to sector size
823 *
824 * Function will erase all sectors withing [start, end] range; it does not check
825 * the @p start for alignment, and it will use @p end to find boundaries of las
826 * sector to erase. Function returns offset of the first byte past the last
827 * erased sector, so basically offset of next sector to be erased if needed.
828 * The function is intended to be called iteratively with previously returned
829 * offset as @p start.
830 *
831 * @param start starting offset, aligned to sector offset;
832 * @param end ending offset, maybe anywhere within sector;
833 *
834 * @retval On success: offset of the first byte past last erased sector;
835 * On failure: -EINVAL.
836 */
erase_range(const struct flash_area * fap,off_t start,off_t end)837 static off_t erase_range(const struct flash_area *fap, off_t start, off_t end)
838 {
839 struct flash_sector sect;
840 size_t size;
841 int rc;
842
843 if (end >= flash_area_get_size(fap)) {
844 return -EINVAL;
845 }
846
847 if (end < start) {
848 return start;
849 }
850
851 if (flash_area_get_sector(fap, end, §)) {
852 return -EINVAL;
853 }
854
855 size = flash_sector_get_off(§) + flash_sector_get_size(§) - start;
856 BOOT_LOG_DBG("Erasing range 0x%jx:0x%jx", (intmax_t)start,
857 (intmax_t)(start + size - 1));
858
859 rc = flash_area_erase(fap, start, size);
860 if (rc != 0) {
861 BOOT_LOG_ERR("Error %d while erasing range", rc);
862 return -EINVAL;
863 }
864
865 return start + size;
866 }
867 #endif
868
869 /*
870 * Image upload request.
871 */
872 static void
bs_upload(char * buf,int len)873 bs_upload(char *buf, int len)
874 {
875 static size_t img_size; /* Total image size, held for duration of upload */
876 static uint32_t curr_off; /* Expected current offset */
877 const uint8_t *img_chunk = NULL; /* Pointer to buffer with received image chunk */
878 size_t img_chunk_len = 0; /* Length of received image chunk */
879 size_t img_chunk_off = SIZE_MAX; /* Offset of image chunk within image */
880 size_t rem_bytes; /* Reminder bytes after aligning chunk write to
881 * to flash alignment */
882 uint32_t img_num_tmp = UINT_MAX; /* Temp variable for image number */
883 static uint32_t img_num = 0;
884 size_t img_size_tmp = SIZE_MAX; /* Temp variable for image size */
885 const struct flash_area *fap = NULL;
886 int rc;
887 struct zcbor_string img_chunk_data = { 0 };
888 size_t decoded = 0;
889 bool ok;
890 #ifdef MCUBOOT_ERASE_PROGRESSIVELY
891 static off_t not_yet_erased = 0; /* Offset of next byte to erase; writes to flash
892 * are done in consecutive manner and erases are done
893 * to allow currently received chunk to be written;
894 * this state variable holds information where last
895 * erase has stopped to let us know whether erase
896 * is needed to be able to write current chunk.
897 */
898 static struct flash_sector status_sector;
899 #endif
900 #ifdef MCUBOOT_SWAP_USING_OFFSET
901 static uint32_t start_off = 0;
902 #endif
903
904 zcbor_state_t zsd[4];
905 zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1, NULL, 0);
906
907 struct zcbor_map_decode_key_val image_upload_decode[] = {
908 ZCBOR_MAP_DECODE_KEY_DECODER("image", zcbor_uint32_decode, &img_num_tmp),
909 ZCBOR_MAP_DECODE_KEY_DECODER("data", zcbor_bstr_decode, &img_chunk_data),
910 ZCBOR_MAP_DECODE_KEY_DECODER("len", zcbor_size_decode, &img_size_tmp),
911 ZCBOR_MAP_DECODE_KEY_DECODER("off", zcbor_size_decode, &img_chunk_off),
912 };
913
914 ok = zcbor_map_decode_bulk(zsd, image_upload_decode, ARRAY_SIZE(image_upload_decode),
915 &decoded) == 0;
916
917 if (!ok) {
918 goto out_invalid_data;
919 }
920
921 img_chunk = img_chunk_data.value;
922 img_chunk_len = img_chunk_data.len;
923
924 /*
925 * Expected data format.
926 * {
927 * "image":<image number in a multi-image set (OPTIONAL)>
928 * "data":<image data>
929 * "len":<image len>
930 * "off":<current offset of image data>
931 * }
932 */
933
934 if (img_chunk_off == SIZE_MAX || img_chunk == NULL) {
935 /*
936 * Offset must be set in every block.
937 */
938 goto out_invalid_data;
939 }
940
941 /* Use image number only from packet with offset == 0. */
942 if (img_chunk_off == 0) {
943 if (img_num_tmp != UINT_MAX) {
944 img_num = img_num_tmp;
945 } else {
946 img_num = 0;
947 }
948 }
949
950 #if !defined(MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD)
951 rc = flash_area_open(flash_area_id_from_multi_image_slot(img_num, 0), &fap);
952 #else
953 rc = flash_area_open(flash_area_id_from_direct_image(img_num), &fap);
954 #endif
955 if (rc) {
956 rc = MGMT_ERR_EINVAL;
957 goto out;
958 }
959
960 if (img_chunk_off == 0) {
961 /* Receiving chunk with 0 offset resets the upload state; this basically
962 * means that upload has started from beginning.
963 */
964 const size_t area_size = flash_area_get_size(fap);
965
966 #ifdef MCUBOOT_SWAP_USING_OFFSET
967 uint32_t num_sectors = SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN;
968 struct flash_sector sector_data;
969 #endif
970
971 curr_off = 0;
972 #ifdef MCUBOOT_ERASE_PROGRESSIVELY
973 /* Get trailer sector information; this is done early because inability to get
974 * that sector information means that upload will not work anyway.
975 * TODO: This is single occurrence issue, it should get detected during tests
976 * and fixed otherwise you are deploying broken mcuboot.
977 */
978 if (flash_area_get_sector(fap, boot_status_off(fap), &status_sector)) {
979 rc = MGMT_ERR_EUNKNOWN;
980 BOOT_LOG_ERR("Unable to determine flash sector of the image trailer");
981 goto out;
982 }
983 #endif
984
985 #if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE)
986 /* We are using swap state at end of flash area to store validation
987 * result. Make sure the user cannot write it from an image to skip validation.
988 */
989 if (img_size_tmp > (area_size - BOOT_MAGIC_SZ)) {
990 goto out_invalid_data;
991 }
992 #else
993 if (img_size_tmp > area_size) {
994 goto out_invalid_data;
995 }
996
997 #endif
998
999 #ifndef MCUBOOT_ERASE_PROGRESSIVELY
1000 /* Non-progressive erase erases entire image slot when first chunk of
1001 * an image is received.
1002 */
1003 rc = flash_area_erase(fap, 0, area_size);
1004 if (rc) {
1005 goto out_invalid_data;
1006 }
1007 #else
1008 not_yet_erased = 0;
1009 #endif
1010
1011 img_size = img_size_tmp;
1012
1013 #ifdef MCUBOOT_SWAP_USING_OFFSET
1014 #ifdef MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD
1015 if (img_num > 0 &&
1016 (img_num % BOOT_NUM_SLOTS) == BOOT_DIRECT_UPLOAD_SECONDARY_SLOT_ID_REMAINDER) {
1017 rc = flash_area_sectors(fap, &num_sectors, §or_data);
1018
1019 if ((rc != 0 && rc != -ENOMEM) ||
1020 num_sectors != SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN) {
1021 rc = MGMT_ERR_ENOENT;
1022 goto out;
1023 }
1024
1025 start_off = sector_data.fs_size;
1026 } else {
1027 start_off = 0;
1028 }
1029 #else
1030 rc = flash_area_sectors(fap, &num_sectors, §or_data);
1031
1032 if ((rc != 0 && rc != -ENOMEM) ||
1033 num_sectors != SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN) {
1034 rc = MGMT_ERR_ENOENT;
1035 goto out;
1036 }
1037
1038 start_off = sector_data.fs_size;
1039 #endif
1040 #endif
1041 } else if (img_chunk_off != curr_off) {
1042 /* If received chunk offset does not match expected one jump, pretend
1043 * success and jump to out; out will respond to client with success
1044 * and request the expected offset, held by curr_off.
1045 */
1046 rc = 0;
1047 goto out;
1048 } else if (curr_off + img_chunk_len > img_size) {
1049 rc = MGMT_ERR_EINVAL;
1050 goto out;
1051 }
1052
1053 #ifdef MCUBOOT_ERASE_PROGRESSIVELY
1054 /* Progressive erase will erase enough flash, aligned to sector size,
1055 * as needed for the current chunk to be written.
1056 */
1057 #ifdef MCUBOOT_SWAP_USING_OFFSET
1058 not_yet_erased = erase_range(fap, not_yet_erased,
1059 curr_off + img_chunk_len - 1 + start_off);
1060 #else
1061 not_yet_erased = erase_range(fap, not_yet_erased,
1062 curr_off + img_chunk_len - 1);
1063 #endif
1064
1065 if (not_yet_erased < 0) {
1066 rc = MGMT_ERR_EINVAL;
1067 goto out;
1068 }
1069 #endif
1070
1071 /* Writes are aligned to flash write alignment, so may drop a few bytes
1072 * from the end of the buffer; we will request these bytes again with
1073 * new buffer by responding with request for offset after the last aligned
1074 * write.
1075 */
1076 rem_bytes = img_chunk_len % flash_area_align(fap);
1077 img_chunk_len -= rem_bytes;
1078
1079 if (curr_off + img_chunk_len + rem_bytes < img_size) {
1080 rem_bytes = 0;
1081 }
1082
1083 BOOT_LOG_DBG("Writing at 0x%x until 0x%x", curr_off, curr_off + (uint32_t)img_chunk_len);
1084 /* Write flash aligned chunk, note that img_chunk_len now holds aligned length */
1085 #if defined(MCUBOOT_SERIAL_UNALIGNED_BUFFER_SIZE) && MCUBOOT_SERIAL_UNALIGNED_BUFFER_SIZE > 0
1086 if (flash_area_align(fap) > 1 &&
1087 (((size_t)img_chunk) & (flash_area_align(fap) - 1)) != 0) {
1088 /* Buffer address incompatible with write address, use buffer to write */
1089 size_t write_size = MCUBOOT_SERIAL_UNALIGNED_BUFFER_SIZE;
1090 uint8_t wbs_aligned[MCUBOOT_SERIAL_UNALIGNED_BUFFER_SIZE];
1091
1092 while (img_chunk_len >= flash_area_align(fap)) {
1093 if (write_size > img_chunk_len) {
1094 write_size = img_chunk_len;
1095 }
1096
1097 memset(wbs_aligned, flash_area_erased_val(fap), sizeof(wbs_aligned));
1098 memcpy(wbs_aligned, img_chunk, write_size);
1099
1100 #ifdef MCUBOOT_SWAP_USING_OFFSET
1101 rc = flash_area_write(fap, curr_off + start_off, wbs_aligned, write_size);
1102 #else
1103 rc = flash_area_write(fap, curr_off, wbs_aligned, write_size);
1104 #endif
1105
1106 if (rc != 0) {
1107 goto out;
1108 }
1109
1110 curr_off += write_size;
1111 img_chunk += write_size;
1112 img_chunk_len -= write_size;
1113 }
1114 } else {
1115 #ifdef MCUBOOT_SWAP_USING_OFFSET
1116 rc = flash_area_write(fap, curr_off + start_off, img_chunk, img_chunk_len);
1117 #else
1118 rc = flash_area_write(fap, curr_off, img_chunk, img_chunk_len);
1119 #endif
1120 }
1121 #else
1122 #ifdef MCUBOOT_SWAP_USING_OFFSET
1123 rc = flash_area_write(fap, curr_off + start_off, img_chunk, img_chunk_len);
1124 #else
1125 rc = flash_area_write(fap, curr_off, img_chunk, img_chunk_len);
1126 #endif
1127 #endif
1128
1129 if (rc == 0 && rem_bytes) {
1130 /* Non-zero rem_bytes means that last chunk needs alignment; the aligned
1131 * part, in the img_chunk_len - rem_bytes count bytes, has already been
1132 * written by the above write, so we are left with the rem_bytes.
1133 */
1134 uint8_t wbs_aligned[BOOT_MAX_ALIGN];
1135
1136 memset(wbs_aligned, flash_area_erased_val(fap), sizeof(wbs_aligned));
1137 memcpy(wbs_aligned, img_chunk + img_chunk_len, rem_bytes);
1138
1139 #ifdef MCUBOOT_SWAP_USING_OFFSET
1140 rc = flash_area_write(fap, curr_off + img_chunk_len + start_off, wbs_aligned,
1141 flash_area_align(fap));
1142 #else
1143 rc = flash_area_write(fap, curr_off + img_chunk_len, wbs_aligned,
1144 flash_area_align(fap));
1145 #endif
1146 }
1147
1148 if (rc == 0) {
1149 curr_off += img_chunk_len + rem_bytes;
1150 if (curr_off == img_size) {
1151 #ifdef MCUBOOT_ERASE_PROGRESSIVELY
1152 /* Assure that sector for image trailer was erased. */
1153 /* Check whether it was erased during previous upload. */
1154 off_t start = flash_sector_get_off(&status_sector);
1155
1156 if (erase_range(fap, start, start) < 0) {
1157 rc = MGMT_ERR_EUNKNOWN;
1158 goto out;
1159 }
1160 #endif
1161 rc = BOOT_HOOK_CALL(boot_serial_uploaded_hook, 0, img_num, fap,
1162 img_size);
1163 if (rc) {
1164 BOOT_LOG_ERR("Error %d post upload hook", rc);
1165 goto out;
1166 }
1167 }
1168 } else {
1169 out_invalid_data:
1170 rc = MGMT_ERR_EINVAL;
1171 }
1172
1173 out:
1174 BOOT_LOG_DBG("RX: 0x%x", rc);
1175 zcbor_map_start_encode(cbor_state, 10);
1176 zcbor_tstr_put_lit_cast(cbor_state, "rc");
1177 zcbor_int32_put(cbor_state, rc);
1178 if (rc == 0) {
1179 zcbor_tstr_put_lit_cast(cbor_state, "off");
1180 zcbor_uint32_put(cbor_state, curr_off);
1181 }
1182 zcbor_map_end_encode(cbor_state, 10);
1183
1184 boot_serial_output();
1185
1186 #ifdef MCUBOOT_ENC_IMAGES
1187 /* Check if this upload was for the primary slot */
1188 #if !defined(MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD)
1189 if (flash_area_id_from_multi_image_slot(img_num, 0) == FLASH_AREA_IMAGE_PRIMARY(0))
1190 #else
1191 if (flash_area_id_from_direct_image(img_num) == FLASH_AREA_IMAGE_PRIMARY(0))
1192 #endif
1193 {
1194 if (curr_off == img_size) {
1195 /* Last sector received, now start a decryption on the image if it is encrypted */
1196 rc = boot_handle_enc_fw(fap);
1197 }
1198 }
1199 #endif
1200
1201 flash_area_close(fap);
1202 }
1203
1204 #ifdef MCUBOOT_BOOT_MGMT_ECHO
1205 static void
bs_echo(char * buf,int len)1206 bs_echo(char *buf, int len)
1207 {
1208 struct zcbor_string value = { 0 };
1209 struct zcbor_string key;
1210 bool ok;
1211 uint32_t rc = MGMT_ERR_EINVAL;
1212
1213 zcbor_state_t zsd[4];
1214 zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1, NULL, 0);
1215
1216 if (!zcbor_map_start_decode(zsd)) {
1217 goto out;
1218 }
1219
1220 do {
1221 ok = zcbor_tstr_decode(zsd, &key);
1222
1223 if (ok) {
1224 if (key.len == 1 && *key.value == 'd') {
1225 ok = zcbor_tstr_decode(zsd, &value);
1226 break;
1227 }
1228
1229 ok = zcbor_any_skip(zsd, NULL);
1230 }
1231 } while (ok);
1232
1233 if (!ok || !zcbor_map_end_decode(zsd)) {
1234 goto out;
1235 }
1236
1237 zcbor_map_start_encode(cbor_state, 10);
1238 zcbor_tstr_put_lit(cbor_state, "r");
1239 if (zcbor_tstr_encode(cbor_state, &value) && zcbor_map_end_encode(cbor_state, 10)) {
1240 boot_serial_output();
1241 return;
1242 } else {
1243 rc = MGMT_ERR_ENOMEM;
1244 }
1245
1246 out:
1247 reset_cbor_state();
1248 bs_rc_rsp(rc);
1249 }
1250 #endif
1251
1252 /*
1253 * Reset, and (presumably) boot to newly uploaded image. Flush console
1254 * before restarting.
1255 */
1256 static void
bs_reset(char * buf,int len)1257 bs_reset(char *buf, int len)
1258 {
1259 int rc = BOOT_HOOK_CALL(boot_reset_request_hook, 0, false);
1260 if (rc == BOOT_RESET_REQUEST_HOOK_BUSY) {
1261 rc = MGMT_ERR_EBUSY;
1262 } else {
1263 /* Currently whatever else is returned it is just converted
1264 * to 0/no error. Boot serial starts accepting "force" parameter
1265 * in command this needs to change.
1266 */
1267 rc = 0;
1268 }
1269 bs_rc_rsp(rc);
1270
1271 if (rc == 0) {
1272 #ifdef __ZEPHYR__
1273 #ifdef CONFIG_MULTITHREADING
1274 k_sleep(K_MSEC(250));
1275 #else
1276 k_busy_wait(250000);
1277 #endif
1278 sys_reboot(SYS_REBOOT_COLD);
1279 #elif __ESPRESSIF__
1280 esp_rom_delay_us(250000);
1281 bootloader_reset();
1282 #else
1283 os_cputime_delay_usecs(250000);
1284 hal_system_reset();
1285 #endif
1286 }
1287 }
1288
1289 /*
1290 * Parse incoming line of input from console.
1291 * Expect newtmgr protocol with serial transport.
1292 */
1293 void
boot_serial_input(char * buf,int len)1294 boot_serial_input(char *buf, int len)
1295 {
1296 struct nmgr_hdr *hdr;
1297
1298 hdr = (struct nmgr_hdr *)buf;
1299 if (len < sizeof(*hdr) ||
1300 (hdr->nh_op != NMGR_OP_READ && hdr->nh_op != NMGR_OP_WRITE) ||
1301 (ntohs(hdr->nh_len) < len - sizeof(*hdr))) {
1302 return;
1303 }
1304 bs_hdr = hdr;
1305 hdr->nh_group = ntohs(hdr->nh_group);
1306
1307 buf += sizeof(*hdr);
1308 len -= sizeof(*hdr);
1309
1310 reset_cbor_state();
1311
1312 /*
1313 * Limited support for commands.
1314 */
1315 if (hdr->nh_group == MGMT_GROUP_ID_IMAGE) {
1316 switch (hdr->nh_id) {
1317 case IMGMGR_NMGR_ID_STATE:
1318 bs_list_set(hdr->nh_op, buf, len);
1319 break;
1320 case IMGMGR_NMGR_ID_UPLOAD:
1321 bs_upload(buf, len);
1322 break;
1323 #ifdef MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO
1324 case IMGMGR_NMGR_ID_SLOT_INFO:
1325 bs_slot_info(hdr->nh_op, buf, len);
1326 break;
1327 #endif
1328 default:
1329 bs_rc_rsp(MGMT_ERR_ENOTSUP);
1330 break;
1331 }
1332 } else if (hdr->nh_group == MGMT_GROUP_ID_DEFAULT) {
1333 switch (hdr->nh_id) {
1334 #ifdef MCUBOOT_BOOT_MGMT_ECHO
1335 case NMGR_ID_ECHO:
1336 bs_echo(buf, len);
1337 break;
1338 #endif
1339 case NMGR_ID_CONS_ECHO_CTRL:
1340 bs_rc_rsp(0);
1341 break;
1342 case NMGR_ID_RESET:
1343 bs_reset(buf, len);
1344 break;
1345 default:
1346 bs_rc_rsp(MGMT_ERR_ENOTSUP);
1347 break;
1348 }
1349 } else if (MCUBOOT_PERUSER_MGMT_GROUP_ENABLED == 1) {
1350 if (bs_peruser_system_specific(hdr, buf, len, cbor_state) == 0) {
1351 boot_serial_output();
1352 }
1353 } else {
1354 bs_rc_rsp(MGMT_ERR_ENOTSUP);
1355 }
1356 #ifdef MCUBOOT_SERIAL_WAIT_FOR_DFU
1357 bs_entry = true;
1358 #endif
1359 }
1360
1361 static void
boot_serial_output(void)1362 boot_serial_output(void)
1363 {
1364 char *data;
1365 int len, out;
1366 uint16_t crc;
1367 uint16_t totlen;
1368 char pkt_cont[2] = { SHELL_NLIP_DATA_START1, SHELL_NLIP_DATA_START2 };
1369 char pkt_start[2] = { SHELL_NLIP_PKT_START1, SHELL_NLIP_PKT_START2 };
1370 char buf[BOOT_SERIAL_OUT_MAX + sizeof(*bs_hdr) + sizeof(crc) + sizeof(totlen)];
1371 char encoded_buf[BASE64_ENCODE_SIZE(sizeof(buf))];
1372
1373 data = bs_obuf;
1374 len = (uintptr_t)cbor_state->payload_mut - (uintptr_t)bs_obuf;
1375
1376 bs_hdr->nh_op++;
1377 bs_hdr->nh_flags = 0;
1378 bs_hdr->nh_len = htons(len);
1379 bs_hdr->nh_group = htons(bs_hdr->nh_group);
1380
1381 #ifdef __ZEPHYR__
1382 crc = crc16_itu_t(CRC16_INITIAL_CRC, (uint8_t *)bs_hdr, sizeof(*bs_hdr));
1383 crc = crc16_itu_t(crc, data, len);
1384 #elif __ESPRESSIF__
1385 /* For ESP32 it was used the CRC API in rom/crc.h */
1386 crc = ~esp_crc16_be(~CRC16_INITIAL_CRC, (uint8_t *)bs_hdr, sizeof(*bs_hdr));
1387 crc = ~esp_crc16_be(~crc, (uint8_t *)data, len);
1388 #else
1389 crc = crc16_ccitt(CRC16_INITIAL_CRC, bs_hdr, sizeof(*bs_hdr));
1390 crc = crc16_ccitt(crc, data, len);
1391 #endif
1392 crc = htons(crc);
1393
1394 totlen = len + sizeof(*bs_hdr) + sizeof(crc);
1395 totlen = htons(totlen);
1396
1397 memcpy(buf, &totlen, sizeof(totlen));
1398 totlen = sizeof(totlen);
1399 memcpy(&buf[totlen], bs_hdr, sizeof(*bs_hdr));
1400 totlen += sizeof(*bs_hdr);
1401 memcpy(&buf[totlen], data, len);
1402 totlen += len;
1403 memcpy(&buf[totlen], &crc, sizeof(crc));
1404 totlen += sizeof(crc);
1405 #ifdef __ZEPHYR__
1406 size_t enc_len;
1407 base64_encode(encoded_buf, sizeof(encoded_buf), &enc_len, buf, totlen);
1408 totlen = enc_len;
1409 #elif __ESPRESSIF__
1410 size_t enc_len;
1411 base64_encode((unsigned char *)encoded_buf, sizeof(encoded_buf), &enc_len, (unsigned char *)buf, totlen);
1412 totlen = enc_len;
1413 #else
1414 totlen = base64_encode(buf, totlen, encoded_buf, 1);
1415 #endif
1416
1417 out = 0;
1418 while (out < totlen) {
1419 if (out == 0) {
1420 boot_uf->write(pkt_start, sizeof(pkt_start));
1421 } else {
1422 boot_uf->write(pkt_cont, sizeof(pkt_cont));
1423 }
1424
1425 len = MIN(BOOT_SERIAL_FRAME_MTU, totlen - out);
1426 boot_uf->write(&encoded_buf[out], len);
1427
1428 out += len;
1429
1430 boot_uf->write("\n", 1);
1431 }
1432
1433 BOOT_LOG_DBG("TX");
1434 }
1435
1436 /*
1437 * Returns 1 if full packet has been received.
1438 */
1439 static int
boot_serial_in_dec(char * in,int inlen,char * out,int * out_off,int maxout)1440 boot_serial_in_dec(char *in, int inlen, char *out, int *out_off, int maxout)
1441 {
1442 size_t rc;
1443 uint16_t crc;
1444 uint16_t len;
1445
1446 #ifdef __ZEPHYR__
1447 int err;
1448 err = base64_decode( &out[*out_off], maxout - *out_off, &rc, in, inlen - 2);
1449 if (err) {
1450 return -1;
1451 }
1452 #elif __ESPRESSIF__
1453 int err;
1454 err = base64_decode((unsigned char *)&out[*out_off], maxout - *out_off, &rc, (unsigned char *)in, inlen);
1455 if (err) {
1456 return -1;
1457 }
1458 #else
1459 if (*out_off + base64_decode_len(in) >= maxout) {
1460 return -1;
1461 }
1462 rc = base64_decode(in, &out[*out_off]);
1463 if (rc < 0) {
1464 return -1;
1465 }
1466 #endif
1467
1468 *out_off += rc;
1469 if (*out_off <= sizeof(uint16_t)) {
1470 return 0;
1471 }
1472
1473 len = ntohs(*(uint16_t *)out);
1474 if (len != *out_off - sizeof(uint16_t)) {
1475 return 0;
1476 }
1477
1478 out += sizeof(uint16_t);
1479 #ifdef __ZEPHYR__
1480 crc = crc16_itu_t(CRC16_INITIAL_CRC, out, len);
1481 #elif __ESPRESSIF__
1482 crc = ~esp_crc16_be(~CRC16_INITIAL_CRC, (uint8_t *)out, len);
1483 #else
1484 crc = crc16_ccitt(CRC16_INITIAL_CRC, out, len);
1485 #endif
1486 if (crc || len <= sizeof(crc)) {
1487 return 0;
1488 }
1489 *out_off -= sizeof(crc);
1490 out[*out_off] = '\0';
1491
1492 return 1;
1493 }
1494
1495 /*
1496 * Task which waits reading console, expecting to get image over
1497 * serial port.
1498 */
1499 static void
boot_serial_read_console(const struct boot_uart_funcs * f,int timeout_in_ms)1500 boot_serial_read_console(const struct boot_uart_funcs *f,int timeout_in_ms)
1501 {
1502 int rc;
1503 int off;
1504 int dec_off = 0;
1505 int full_line;
1506 int max_input;
1507 int elapsed_in_ms = 0;
1508
1509 #ifndef MCUBOOT_SERIAL_WAIT_FOR_DFU
1510 bool allow_idle = true;
1511 #endif
1512
1513 boot_uf = f;
1514 max_input = sizeof(in_buf);
1515
1516 off = 0;
1517 while (timeout_in_ms > 0 || bs_entry) {
1518 /*
1519 * Don't enter CPU idle state here if timeout based serial recovery is
1520 * used as otherwise the boot process hangs forever, waiting for input
1521 * from serial console (if single-thread mode is used).
1522 */
1523 #ifndef MCUBOOT_SERIAL_WAIT_FOR_DFU
1524 if (allow_idle == true) {
1525 MCUBOOT_CPU_IDLE();
1526 allow_idle = false;
1527 }
1528 #endif
1529 MCUBOOT_WATCHDOG_FEED();
1530 #ifdef MCUBOOT_SERIAL_WAIT_FOR_DFU
1531 uint32_t start = k_uptime_get_32();
1532 #endif
1533 rc = f->read(in_buf + off, sizeof(in_buf) - off, &full_line);
1534 if (rc <= 0 && !full_line) {
1535 #ifndef MCUBOOT_SERIAL_WAIT_FOR_DFU
1536 allow_idle = true;
1537 #endif
1538 goto check_timeout;
1539 }
1540 off += rc;
1541 if (!full_line) {
1542 if (off == max_input) {
1543 /*
1544 * Full line, no newline yet. Reset the input buffer.
1545 */
1546 off = 0;
1547 }
1548 goto check_timeout;
1549 }
1550 if (in_buf[0] == SHELL_NLIP_PKT_START1 &&
1551 in_buf[1] == SHELL_NLIP_PKT_START2) {
1552 dec_off = 0;
1553 rc = boot_serial_in_dec(&in_buf[2], off - 2, dec_buf, &dec_off, max_input);
1554 } else if (in_buf[0] == SHELL_NLIP_DATA_START1 &&
1555 in_buf[1] == SHELL_NLIP_DATA_START2) {
1556 rc = boot_serial_in_dec(&in_buf[2], off - 2, dec_buf, &dec_off, max_input);
1557 }
1558
1559 /* serve errors: out of decode memory, or bad encoding */
1560 if (rc == 1) {
1561 boot_serial_input(&dec_buf[2], dec_off - 2);
1562 }
1563 off = 0;
1564 check_timeout:
1565 /* Subtract elapsed time */
1566 #ifdef MCUBOOT_SERIAL_WAIT_FOR_DFU
1567 elapsed_in_ms = (k_uptime_get_32() - start);
1568 #endif
1569 timeout_in_ms -= elapsed_in_ms;
1570 }
1571 }
1572
1573 /*
1574 * Task which waits reading console, expecting to get image over
1575 * serial port.
1576 */
1577 void
boot_serial_start(const struct boot_uart_funcs * f)1578 boot_serial_start(const struct boot_uart_funcs *f)
1579 {
1580 bs_entry = true;
1581 boot_serial_read_console(f,0);
1582 }
1583
1584 #ifdef MCUBOOT_SERIAL_WAIT_FOR_DFU
1585 /*
1586 * Task which waits reading console for a certain amount of timeout.
1587 * If within this timeout no mcumgr command is received, the function is
1588 * returning, else the serial boot is never exited
1589 */
1590 void
boot_serial_check_start(const struct boot_uart_funcs * f,int timeout_in_ms)1591 boot_serial_check_start(const struct boot_uart_funcs *f, int timeout_in_ms)
1592 {
1593 bs_entry = false;
1594 boot_serial_read_console(f,timeout_in_ms);
1595 }
1596 #endif
1597
1598 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
1599 /* Function to find the hash of an image, returns 0 on success. */
1600 #ifdef MCUBOOT_SWAP_USING_OFFSET
boot_serial_get_hash(const struct image_header * hdr,const struct flash_area * fap,uint8_t * hash,uint32_t start_off)1601 static int boot_serial_get_hash(const struct image_header *hdr,
1602 const struct flash_area *fap, uint8_t *hash, uint32_t start_off)
1603 #else
1604 static int boot_serial_get_hash(const struct image_header *hdr,
1605 const struct flash_area *fap, uint8_t *hash)
1606 #endif
1607 {
1608 struct image_tlv_iter it;
1609 uint32_t offset;
1610 uint16_t len;
1611 uint16_t type;
1612 int rc;
1613
1614 /* Manifest data is concatenated to the end of the image.
1615 * It is encoded in TLV format.
1616 */
1617 #if defined(MCUBOOT_SWAP_USING_OFFSET)
1618 it.start_off = start_off;
1619 #endif
1620
1621 rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
1622 if (rc) {
1623 return -1;
1624 }
1625
1626 /* Traverse through the TLV area to find the image hash TLV. */
1627 while (true) {
1628 rc = bootutil_tlv_iter_next(&it, &offset, &len, &type);
1629 if (rc < 0) {
1630 return -1;
1631 } else if (rc > 0) {
1632 break;
1633 }
1634
1635 if (type == IMAGE_SHA_TLV) {
1636 /* Get the image's hash value from the manifest section. */
1637 if (len != IMAGE_HASH_SIZE) {
1638 return -1;
1639 }
1640
1641 rc = flash_area_read(fap, offset, hash, len);
1642 if (rc) {
1643 return -1;
1644 }
1645
1646 return 0;
1647 }
1648 }
1649
1650 return -1;
1651 }
1652 #endif
1653