/* * Given offset in flash area, fill in rest of the fcb_entry, and crc8 over * the data. */ int fcb_elem_crc8(struct fcb *fcb, struct fcb_entry *loc, uint8_t *c8p) { uint8_t tmp_str[FCB_TMP_BUF_SZ]; int cnt; int blk_sz; uint8_t crc8; uint16_t len; uint32_t off; uint32_t end; int rc; if (loc->fe_elem_off + 2 > loc->fe_area->fa_size) { return FCB_ERR_NOVAR; } rc = flash_area_read(loc->fe_area, loc->fe_elem_off, tmp_str, 2); if (rc) { return FCB_ERR_FLASH; } cnt = fcb_get_len(tmp_str, &len); if (cnt < 0) { return cnt; } loc->fe_data_off = loc->fe_elem_off + fcb_len_in_flash(fcb, cnt); loc->fe_data_len = len; crc8 = crc8_init(); crc8 = crc8_calc(crc8, tmp_str, cnt); off = loc->fe_data_off; end = loc->fe_data_off + len; for (; off < end; off += blk_sz) { blk_sz = end - off; if (blk_sz > sizeof(tmp_str)) { blk_sz = sizeof(tmp_str); } rc = flash_area_read(loc->fe_area, off, tmp_str, blk_sz); if (rc) { return FCB_ERR_FLASH; } crc8 = crc8_calc(crc8, tmp_str, blk_sz); } *c8p = crc8; return 0; }
/** * Deletes the main image version number from the boot vector. * This must be called by the app to confirm that it is ok to keep booting * to this image. * * @return 0 on success; nonzero on failure. */ int boot_vect_write_main(void) { const struct flash_area *fap; uint32_t off; int rc; uint8_t val; /* * Write to slot 0. */ rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap); if (rc) { return rc; } off = fap->fa_size - sizeof(struct boot_img_trailer); off += (sizeof(uint32_t) + sizeof(uint8_t)); rc = flash_area_read(fap, off, &val, sizeof(val)); if (!rc && val == 0xff) { val = 0; rc = flash_area_write(fap, off, &val, sizeof(val)); } return rc; }
/* * Read version from image header from flash area 'area_id'. * Returns -1 if area is not readable. * Returns 0 if image in slot is ok, and version string is valid. * Returns 1 if there is not a full image. * Returns 2 if slot is empty. */ int imgr_read_ver(int area_id, struct image_version *ver) { struct image_header hdr; int rc; const struct flash_area *fa; rc = flash_area_open(area_id, &fa); if (rc) { return -1; } rc = flash_area_read(fa, 0, &hdr, sizeof(hdr)); if (rc) { return -1; } memset(ver, 0xff, sizeof(*ver)); if (hdr.ih_magic == 0x96f3b83c) { memcpy(ver, &hdr.ih_ver, sizeof(*ver)); rc = 0; } else { rc = 1; } flash_area_close(fa); return rc; }
int imgr_core_list(struct nmgr_jbuf *njb) { const struct flash_area *fa; struct coredump_header hdr; struct json_encoder *enc; struct json_value jv; int rc; rc = flash_area_open(FLASH_AREA_CORE, &fa); if (rc) { rc = NMGR_ERR_EINVAL; } else { rc = flash_area_read(fa, 0, &hdr, sizeof(hdr)); if (rc != 0) { rc = NMGR_ERR_EINVAL; } else if (hdr.ch_magic != COREDUMP_MAGIC) { rc = NMGR_ERR_ENOENT; } else { rc = 0; } } enc = &njb->njb_enc; json_encode_object_start(enc); JSON_VALUE_INT(&jv, rc); json_encode_object_entry(enc, "rc", &jv); json_encode_object_finish(enc); return 0; }
void boot_test_util_copy_area(int from_area_idx, int to_area_idx) { const struct flash_area *from_area_desc; const struct flash_area *to_area_desc; void *buf; int rc; from_area_desc = boot_test_area_descs + from_area_idx; to_area_desc = boot_test_area_descs + to_area_idx; TEST_ASSERT(from_area_desc->fa_size == to_area_desc->fa_size); buf = malloc(from_area_desc->fa_size); TEST_ASSERT(buf != NULL); rc = flash_area_read(from_area_desc, 0, buf, from_area_desc->fa_size); TEST_ASSERT(rc == 0); rc = flash_area_erase(to_area_desc, 0, to_area_desc->fa_size); TEST_ASSERT(rc == 0); rc = flash_area_write(to_area_desc, 0, buf, to_area_desc->fa_size); TEST_ASSERT(rc == 0); free(buf); }
void boot_test_util_swap_areas(int area_idx1, int area_idx2) { const struct flash_area *area_desc1; const struct flash_area *area_desc2; uint32_t size; void *buf1; void *buf2; int rc; area_desc1 = boot_test_area_descs + area_idx1; area_desc2 = boot_test_area_descs + area_idx2; TEST_ASSERT(area_desc1->fa_size == area_desc2->fa_size); buf1 = malloc(area_desc1->fa_size); TEST_ASSERT(buf1 != NULL); buf2 = malloc(area_desc2->fa_size); TEST_ASSERT(buf2 != NULL); rc = flash_area_read(area_desc1, 0, buf1, area_desc1->fa_size); TEST_ASSERT(rc == 0); rc = flash_area_read(area_desc2, 0, buf2, area_desc2->fa_size); TEST_ASSERT(rc == 0); rc = flash_area_erase(area_desc1, 0, area_desc1->fa_size); TEST_ASSERT(rc == 0); rc = flash_area_erase(area_desc2, 0, area_desc2->fa_size); TEST_ASSERT(rc == 0); size = boot_test_util_area_write_size(area_idx1, 0, area_desc1->fa_size); rc = flash_area_write(area_desc1, 0, buf2, size); TEST_ASSERT(rc == 0); size = boot_test_util_area_write_size(area_idx2, 0, area_desc2->fa_size); rc = flash_area_write(area_desc2, 0, buf1, size); TEST_ASSERT(rc == 0); free(buf1); free(buf2); }
/* * Read the image trailer from a given slot. */ static int boot_vect_read_img_trailer(int slot, struct boot_img_trailer *bit) { int rc; const struct flash_area *fap; uint32_t off; rc = flash_area_open(slot, &fap); if (rc) { return rc; } off = fap->fa_size - sizeof(struct boot_img_trailer); rc = flash_area_read(fap, off, bit, sizeof(*bit)); flash_area_close(fap); return rc; }
/* * Compute SHA256 over the image. */ static int bootutil_img_hash(struct image_header *hdr, const struct flash_area *fap, uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *hash_result, uint8_t *seed, int seed_len) { mbedtls_sha256_context sha256_ctx; uint32_t blk_sz; uint32_t size; uint32_t off; int rc; mbedtls_sha256_init(&sha256_ctx); mbedtls_sha256_starts(&sha256_ctx, 0); /* in some cases (split image) the hash is seeded with data from * the loader image */ if(seed && (seed_len > 0)) { mbedtls_sha256_update(&sha256_ctx, seed, seed_len); } size = hdr->ih_img_size + hdr->ih_hdr_size; /* * Hash is computed over image header and image itself. No TLV is * included ATM. */ size = hdr->ih_img_size + hdr->ih_hdr_size; for (off = 0; off < size; off += blk_sz) { /* Pet the watchdog, in case it is still enabled after a soft reset. */ hal_watchdog_tickle(); blk_sz = size - off; if (blk_sz > tmp_buf_sz) { blk_sz = tmp_buf_sz; } rc = flash_area_read(fap, off, tmp_buf, blk_sz); if (rc) { return rc; } mbedtls_sha256_update(&sha256_ctx, tmp_buf, blk_sz); } mbedtls_sha256_finish(&sha256_ctx, hash_result); return 0; }
static int log_fcb_read(struct log *log, void *dptr, void *buf, uint16_t offset, uint16_t len) { struct fcb_entry *loc; int rc; loc = (struct fcb_entry *)dptr; if (offset + len > loc->fe_data_len) { len = loc->fe_data_len - offset; } rc = flash_area_read(loc->fe_area, loc->fe_data_off + offset, buf, len); if (rc == 0) { return len; } else { return 0; } }
int fcb_test_data_walk_cb(struct fcb_entry *loc, void *arg) { uint16_t len; uint8_t test_data[128]; int rc; int i; int *var_cnt = (int *)arg; len = loc->fe_data_len; TEST_ASSERT(len == *var_cnt); rc = flash_area_read(loc->fe_area, loc->fe_data_off, test_data, len); TEST_ASSERT(rc == 0); for (i = 0; i < len; i++) { TEST_ASSERT(test_data[i] == fcb_test_append_data(len, i)); } (*var_cnt)++; return 0; }
int fcb_elem_info(struct fcb *fcb, struct fcb_entry *loc) { int rc; uint8_t crc8; uint8_t fl_crc8; uint32_t off; rc = fcb_elem_crc8(fcb, loc, &crc8); if (rc) { return rc; } off = loc->fe_data_off + fcb_len_in_flash(fcb, loc->fe_data_len); rc = flash_area_read(loc->fe_area, off, &fl_crc8, sizeof(fl_crc8)); if (rc) { return FCB_ERR_FLASH; } if (fl_crc8 != crc8) { return FCB_ERR_CRC; } return 0; }
int imgr_core_list(struct mgmt_cbuf *cb) { const struct flash_area *fa; struct coredump_header hdr; int rc; rc = flash_area_open(MYNEWT_VAL(COREDUMP_FLASH_AREA), &fa); if (rc) { rc = MGMT_ERR_EINVAL; } else { rc = flash_area_read(fa, 0, &hdr, sizeof(hdr)); if (rc != 0) { rc = MGMT_ERR_EINVAL; } else if (hdr.ch_magic != COREDUMP_MAGIC) { rc = MGMT_ERR_ENOENT; } else { rc = 0; } } mgmt_cbuf_setoerr(cb, rc); return 0; }
/* * Verify the integrity of the image. * Return non-zero if image could not be validated/does not validate. */ int bootutil_img_validate(struct image_header *hdr, const struct flash_area *fap, uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *seed, int seed_len, uint8_t *out_hash) { uint32_t off; uint32_t size; uint32_t sha_off = 0; #if MYNEWT_VAL(BOOTUTIL_SIGN_RSA) || MYNEWT_VAL(BOOTUTIL_SIGN_EC) || \ MYNEWT_VAL(BOOTUTIL_SIGN_EC256) uint32_t sig_off = 0; uint32_t sig_len = 0; #endif struct image_tlv tlv; uint8_t buf[256]; uint8_t hash[32]; int rc; #if MYNEWT_VAL(BOOTUTIL_SIGN_RSA) if ((hdr->ih_flags & IMAGE_F_PKCS15_RSA2048_SHA256) == 0) { return -1; } #endif #if MYNEWT_VAL(BOOTUTIL_SIGN_EC) if ((hdr->ih_flags & IMAGE_F_ECDSA224_SHA256) == 0) { return -1; } #endif #if MYNEWT_VAL(BOOTUTIL_SIGN_EC256) if ((hdr->ih_flags & IMAGE_F_ECDSA256_SHA256) == 0) { return -1; } #endif if ((hdr->ih_flags & IMAGE_F_SHA256) == 0) { return -1; } rc = bootutil_img_hash(hdr, fap, tmp_buf, tmp_buf_sz, hash, seed, seed_len); if (rc) { return rc; } if (out_hash) { memcpy(out_hash, hash, 32); } /* After image there are TLVs. */ off = hdr->ih_img_size + hdr->ih_hdr_size; size = off + hdr->ih_tlv_size; for (; off < size; off += sizeof(tlv) + tlv.it_len) { rc = flash_area_read(fap, off, &tlv, sizeof tlv); if (rc) { return rc; } if (tlv.it_type == IMAGE_TLV_SHA256) { if (tlv.it_len != sizeof(hash)) { return -1; } sha_off = off + sizeof(tlv); } #if MYNEWT_VAL(BOOTUTIL_SIGN_RSA) if (tlv.it_type == IMAGE_TLV_RSA2048) { if (tlv.it_len != 256) { /* 2048 bits */ return -1; } sig_off = off + sizeof(tlv); sig_len = tlv.it_len; } #endif #if MYNEWT_VAL(BOOTUTIL_SIGN_EC) if (tlv.it_type == IMAGE_TLV_ECDSA224) { if (tlv.it_len < 64) { /* oids + 2 * 28 bytes */ return -1; } sig_off = off + sizeof(tlv); sig_len = tlv.it_len; } #endif #if MYNEWT_VAL(BOOTUTIL_SIGN_EC256) if (tlv.it_type == IMAGE_TLV_ECDSA256) { if (tlv.it_len < 72) { /* oids + 2 * 32 bytes */ return -1; } sig_off = off + sizeof(tlv); sig_len = tlv.it_len; } #endif } if (hdr->ih_flags & IMAGE_F_SHA256) { if (!sha_off) { /* * Header said there should be hash TLV, no TLV found. */ return -1; } rc = flash_area_read(fap, sha_off, buf, sizeof hash); if (rc) { return rc; } if (memcmp(hash, buf, sizeof(hash))) { return -1; } } #if MYNEWT_VAL(BOOTUTIL_SIGN_RSA) || MYNEWT_VAL(BOOTUTIL_SIGN_EC) || \ MYNEWT_VAL(BOOTUTIL_SIGN_EC256) if (!sig_off) { /* * Header said there should be PKCS1.v5 signature, no TLV * found. */ return -1; } rc = flash_area_read(fap, sig_off, buf, sig_len); if (rc) { return -1; } if (hdr->ih_key_id >= bootutil_key_cnt) { return -1; } rc = bootutil_verify_sig(hash, sizeof(hash), buf, sig_len, hdr->ih_key_id); if (rc) { return -1; } #endif return 0; }
void coredump_dump(void *regs, int regs_sz) { struct coredump_header hdr; struct coredump_tlv tlv; const struct flash_area *fa; struct image_version ver; const struct bsp_mem_dump *mem, *cur; int area_cnt, i; uint8_t hash[IMGMGR_HASH_LEN]; uint32_t off; uint32_t area_off, area_end; if (coredump_disabled) { return; } if (flash_area_open(FLASH_AREA_CORE, &fa)) { return; } if (flash_area_read(fa, 0, &hdr, sizeof(hdr))) { return; } if (hdr.ch_magic == COREDUMP_MAGIC) { /* * Don't override corefile. */ return; } if (flash_area_erase(fa, 0, fa->fa_size)) { return; } /* * First put in data, followed by the header. */ tlv.ct_type = COREDUMP_TLV_REGS; tlv._pad = 0; tlv.ct_len = regs_sz; tlv.ct_off = 0; off = sizeof(hdr); dump_core_tlv(fa, &off, &tlv, regs); if (imgr_read_info(bsp_imgr_current_slot(), &ver, hash) == 0) { tlv.ct_type = COREDUMP_TLV_IMAGE; tlv.ct_len = IMGMGR_HASH_LEN; dump_core_tlv(fa, &off, &tlv, hash); } mem = bsp_core_dump(&area_cnt); for (i = 0; i < area_cnt; i++) { cur = &mem[i]; area_off = (uint32_t)cur->bmd_start; area_end = area_off + cur->bmd_size; while (area_off < area_end) { tlv.ct_type = COREDUMP_TLV_MEM; if (cur->bmd_size > USHRT_MAX) { tlv.ct_len = SHRT_MAX + 1; } else { tlv.ct_len = cur->bmd_size; } tlv.ct_off = area_off; dump_core_tlv(fa, &off, &tlv, (void *)area_off); area_off += tlv.ct_len; } } hdr.ch_magic = COREDUMP_MAGIC; hdr.ch_size = off; flash_area_write(fa, 0, &hdr, sizeof(hdr)); }
/* * Read version and build hash from image located slot "image_slot". Note: * this is a slot index, not a flash area ID. * * @param image_slot * @param ver (optional) * @param hash (optional) * @param flags * * Returns -1 if area is not readable. * Returns 0 if image in slot is ok, and version string is valid. * Returns 1 if there is not a full image. * Returns 2 if slot is empty. XXXX not there yet */ int imgr_read_info(int image_slot, struct image_version *ver, uint8_t *hash, uint32_t *flags) { struct image_header *hdr; struct image_tlv *tlv; int rc = -1; int rc2; const struct flash_area *fa; uint8_t data[sizeof(struct image_header)]; uint32_t data_off, data_end; int area_id; area_id = flash_area_id_from_image_slot(image_slot); hdr = (struct image_header *)data; rc2 = flash_area_open(area_id, &fa); if (rc2) { return -1; } rc2 = flash_area_read(fa, 0, hdr, sizeof(*hdr)); if (rc2) { goto end; } if (ver != NULL) { memset(ver, 0xff, sizeof(*ver)); if (hdr->ih_magic == IMAGE_MAGIC) { memcpy(ver, &hdr->ih_ver, sizeof(*ver)); } else if (hdr->ih_magic == 0xffffffff) { rc = 2; goto end; } else { rc = 1; goto end; } } if(flags) { *flags = hdr->ih_flags; } /* * Build ID is in a TLV after the image. */ data_off = hdr->ih_hdr_size + hdr->ih_img_size; data_end = data_off + hdr->ih_tlv_size; if (data_end > fa->fa_size) { rc = 1; goto end; } tlv = (struct image_tlv *)data; while (data_off + sizeof(*tlv) <= data_end) { rc2 = flash_area_read(fa, data_off, tlv, sizeof(*tlv)); if (rc2) { goto end; } if (tlv->it_type == 0xff && tlv->it_len == 0xffff) { break; } if (tlv->it_type != IMAGE_TLV_SHA256 || tlv->it_len != IMGMGR_HASH_LEN) { data_off += sizeof(*tlv) + tlv->it_len; continue; } data_off += sizeof(*tlv); if (hash) { if (data_off + IMGMGR_HASH_LEN > data_end) { goto end; } rc2 = flash_area_read(fa, data_off, hash, IMGMGR_HASH_LEN); if (rc2) { goto end; } } rc = 0; goto end; } rc = 1; end: flash_area_close(fa); return rc; }