Skip to content

Commit e32483f

Browse files
davidvinczed3zd3z
authored andcommitted
Boot: Add dependency check to multi-image boot
This patch adds the capability to check image dependencies in case of multi-image boot. The dependencies are described with a new type of TLV in the manifest. Change-Id: If45f81a00d4324c881634f50156f9939e1bf8707 Signed-off-by: David Vincze <[email protected]>
1 parent ba3bd60 commit e32483f

File tree

7 files changed

+367
-31
lines changed

7 files changed

+367
-31
lines changed

boot/bootutil/include/bootutil/image.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
* under the License.
1818
*/
1919

20+
/*
21+
* Modifications are Copyright (c) 2019 Arm Limited.
22+
*/
23+
2024
#ifndef H_IMAGE_
2125
#define H_IMAGE_
2226

@@ -76,6 +80,7 @@ struct flash_area;
7680
#define IMAGE_TLV_ED25519 0x24 /* ed25519 of hash output */
7781
#define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */
7882
#define IMAGE_TLV_ENC_KW128 0x31 /* Key encrypted with AES-KW-128 */
83+
#define IMAGE_TLV_DEPENDENCY 0x40 /* Image depends on other image */
7984

8085
struct image_version {
8186
uint8_t iv_major;
@@ -84,16 +89,24 @@ struct image_version {
8489
uint32_t iv_build_num;
8590
};
8691

92+
struct image_dependency {
93+
uint8_t image_id; /* Image index (from 0) */
94+
struct image_version image_min_version; /* Indicates at minimum which
95+
* version of firmware must be
96+
* available to satisfy compliance
97+
*/
98+
};
99+
87100
/** Image header. All fields are in little endian byte order. */
88101
struct image_header {
89102
uint32_t ih_magic;
90103
uint32_t ih_load_addr;
91-
uint16_t ih_hdr_size; /* Size of image header (bytes). */
92-
uint16_t _pad1;
93-
uint32_t ih_img_size; /* Does not include header. */
94-
uint32_t ih_flags; /* IMAGE_F_[...]. */
104+
uint16_t ih_hdr_size; /* Size of image header (bytes). */
105+
uint16_t ih_protect_tlv_size; /* Size of protected TLV area (bytes). */
106+
uint32_t ih_img_size; /* Does not include header. */
107+
uint32_t ih_flags; /* IMAGE_F_[...]. */
95108
struct image_version ih_ver;
96-
uint32_t _pad2;
109+
uint32_t _pad1;
97110
};
98111

99112
/** Image TLV header. All fields in little endian. */

boot/bootutil/src/bootutil_misc.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,3 +741,38 @@ boot_set_confirmed(void)
741741
flash_area_close(fap);
742742
return rc;
743743
}
744+
745+
#if (BOOT_IMAGE_NUMBER > 1)
746+
/**
747+
* Check if the version of the image is not older than required.
748+
*
749+
* @param req Required minimal image version.
750+
* @param ver Version of the image to be checked.
751+
*
752+
* @return 0 if the version is sufficient, nonzero otherwise.
753+
*/
754+
int
755+
boot_is_version_sufficient(struct image_version *req,
756+
struct image_version *ver)
757+
{
758+
if (ver->iv_major > req->iv_major) {
759+
return 0;
760+
}
761+
if (ver->iv_major < req->iv_major) {
762+
return BOOT_EBADVERSION;
763+
}
764+
/* The major version numbers are equal. */
765+
if (ver->iv_minor > req->iv_minor) {
766+
return 0;
767+
}
768+
if (ver->iv_minor < req->iv_minor) {
769+
return BOOT_EBADVERSION;
770+
}
771+
/* The minor version numbers are equal. */
772+
if (ver->iv_revision < req->iv_revision) {
773+
return BOOT_EBADVERSION;
774+
}
775+
776+
return 0;
777+
}
778+
#endif /* BOOT_IMAGE_NUMBER > 1 */

boot/bootutil/src/bootutil_priv.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,14 @@ extern "C" {
4848

4949
struct flash_area;
5050

51-
#define BOOT_EFLASH 1
52-
#define BOOT_EFILE 2
53-
#define BOOT_EBADIMAGE 3
54-
#define BOOT_EBADVECT 4
55-
#define BOOT_EBADSTATUS 5
56-
#define BOOT_ENOMEM 6
57-
#define BOOT_EBADARGS 7
51+
#define BOOT_EFLASH 1
52+
#define BOOT_EFILE 2
53+
#define BOOT_EBADIMAGE 3
54+
#define BOOT_EBADVECT 4
55+
#define BOOT_EBADSTATUS 5
56+
#define BOOT_ENOMEM 6
57+
#define BOOT_EBADARGS 7
58+
#define BOOT_EBADVERSION 8
5859

5960
#define BOOT_TMPBUF_SZ 256
6061

@@ -241,6 +242,10 @@ int boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
241242
const uint8_t *enckey);
242243
int boot_read_enc_key(uint8_t slot, uint8_t *enckey);
243244
#endif
245+
#if (BOOT_IMAGE_NUMBER > 1)
246+
int boot_is_version_sufficient(struct image_version *req,
247+
struct image_version *ver);
248+
#endif
244249

245250
/*
246251
* Accessors for the contents of struct boot_loader_state.

boot/bootutil/src/image_validate.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
* under the License.
1818
*/
1919

20+
/*
21+
* Modifications are Copyright (c) 2019 Arm Limited.
22+
*/
23+
2024
#include <assert.h>
2125
#include <stddef.h>
2226
#include <inttypes.h>
@@ -78,12 +82,20 @@ bootutil_img_hash(struct image_header *hdr, const struct flash_area *fap,
7882
}
7983
#endif
8084

81-
/*
82-
* Hash is computed over image header and image itself. No TLV is
83-
* included ATM.
84-
*/
85+
/* Hash is computed over image header and image itself. */
8586
hdr_size = hdr->ih_hdr_size;
8687
size = hdr->ih_img_size + hdr_size;
88+
89+
#if (MCUBOOT_IMAGE_NUMBER > 1)
90+
/* If dependency TLVs are present then the TLV info header and the
91+
* dependency TLVs are also protected and have to be included in the hash
92+
* calculation.
93+
*/
94+
if (hdr->ih_protect_tlv_size != 0) {
95+
size += hdr->ih_protect_tlv_size;
96+
}
97+
#endif
98+
8799
for (off = 0; off < size; off += blk_sz) {
88100
blk_sz = size - off;
89101
if (blk_sz > tmp_buf_sz) {
@@ -212,7 +224,6 @@ bootutil_img_validate(struct image_header *hdr, const struct flash_area *fap,
212224
}
213225

214226
/* The TLVs come after the image. */
215-
/* After image there are TLVs. */
216227
off = hdr->ih_img_size + hdr->ih_hdr_size;
217228

218229
rc = flash_area_read(fap, off, &info, sizeof(info));

boot/bootutil/src/loader.c

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,6 +1608,198 @@ boot_set_image_ok(void)
16081608
}
16091609
#endif /* !MCUBOOT_OVERWRITE_ONLY */
16101610

1611+
#if (BOOT_IMAGE_NUMBER > 1)
1612+
/**
1613+
* Check the image dependency whether it is satisfied and modify
1614+
* the swap type if necessary.
1615+
*
1616+
* @param dep Image dependency which has to be verified.
1617+
*
1618+
* @return 0 on success; nonzero on failure.
1619+
*/
1620+
static int
1621+
boot_verify_single_dependency(struct image_dependency *dep)
1622+
{
1623+
struct image_version *dep_version;
1624+
size_t dep_slot;
1625+
int rc;
1626+
1627+
/* Determine the source of the image which is the subject of
1628+
* the dependency and get it's version. */
1629+
dep_slot = (boot_data.swap_type[dep->image_id] != BOOT_SWAP_TYPE_NONE) ?
1630+
BOOT_SECONDARY_SLOT : BOOT_PRIMARY_SLOT;
1631+
dep_version = &boot_data.imgs[dep->image_id][dep_slot].hdr.ih_ver;
1632+
1633+
rc = boot_is_version_sufficient(&dep->image_min_version, dep_version);
1634+
if (rc != 0) {
1635+
/* Dependency not satisfied.
1636+
* Modify the swap type to decrease the version number of the image
1637+
* (which will be located in the primary slot after the boot process),
1638+
* consequently the number of unsatisfied dependencies will be
1639+
* decreased or remain the same.
1640+
*/
1641+
switch (BOOT_SWAP_TYPE(&boot_data)) {
1642+
case BOOT_SWAP_TYPE_TEST:
1643+
case BOOT_SWAP_TYPE_PERM:
1644+
BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
1645+
break;
1646+
case BOOT_SWAP_TYPE_NONE:
1647+
BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_REVERT;
1648+
break;
1649+
default:
1650+
break;
1651+
}
1652+
}
1653+
1654+
return rc;
1655+
}
1656+
1657+
/**
1658+
* Read all dependency TLVs of an image from the flash and verify
1659+
* one after another to see if they are all satisfied.
1660+
*
1661+
* @param slot Image slot number.
1662+
*
1663+
* @return 0 on success; nonzero on failure.
1664+
*/
1665+
static int
1666+
boot_verify_all_dependency(uint32_t slot)
1667+
{
1668+
const struct flash_area *fap;
1669+
struct image_header *hdr;
1670+
struct image_tlv_info info;
1671+
struct image_tlv tlv;
1672+
struct image_dependency dep;
1673+
uint32_t off;
1674+
uint32_t end;
1675+
bool dep_tlvs_found = false;
1676+
int rc;
1677+
1678+
rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap);
1679+
if (rc != 0) {
1680+
rc = BOOT_EFLASH;
1681+
goto done;
1682+
}
1683+
1684+
hdr = boot_img_hdr(&boot_data, slot);
1685+
/* The TLVs come after the image. */
1686+
off = hdr->ih_hdr_size + hdr->ih_img_size;
1687+
1688+
/* The TLV area always starts with an image_tlv_info structure. */
1689+
rc = flash_area_read(fap, off, &info, sizeof(info));
1690+
if (rc != 0) {
1691+
rc = BOOT_EFLASH;
1692+
goto done;
1693+
}
1694+
1695+
if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
1696+
rc = BOOT_EBADIMAGE;
1697+
goto done;
1698+
}
1699+
end = off + info.it_tlv_tot;
1700+
off += sizeof(info);
1701+
1702+
/* Traverse through all of the TLVs to find the dependency TLVs. */
1703+
for (; off < end; off += sizeof(tlv) + tlv.it_len) {
1704+
rc = flash_area_read(fap, off, &tlv, sizeof(tlv));
1705+
if (rc != 0) {
1706+
rc = BOOT_EFLASH;
1707+
goto done;
1708+
}
1709+
1710+
if (tlv.it_type == IMAGE_TLV_DEPENDENCY) {
1711+
if (!dep_tlvs_found) {
1712+
dep_tlvs_found = true;
1713+
}
1714+
1715+
if (tlv.it_len != sizeof(dep)) {
1716+
rc = BOOT_EBADIMAGE;
1717+
goto done;
1718+
}
1719+
1720+
rc = flash_area_read(fap, off + sizeof(tlv), &dep, tlv.it_len);
1721+
if (rc != 0) {
1722+
rc = BOOT_EFLASH;
1723+
goto done;
1724+
}
1725+
1726+
/* Verify dependency and modify the swap type if not satisfied. */
1727+
rc = boot_verify_single_dependency(&dep);
1728+
if (rc != 0) {
1729+
/* Dependency not satisfied. */
1730+
goto done;
1731+
}
1732+
1733+
/* Dependency satisfied, no action needed.
1734+
* Continue with the next TLV entry.
1735+
*/
1736+
} else if (dep_tlvs_found) {
1737+
/* The dependency TLVs are contiguous in the TLV area. If a
1738+
* dependency had already been found and the last read TLV
1739+
* has a different type then there are no more dependency TLVs.
1740+
* The search can be finished.
1741+
*/
1742+
break;
1743+
}
1744+
}
1745+
1746+
done:
1747+
flash_area_close(fap);
1748+
return rc;
1749+
}
1750+
1751+
/**
1752+
* Verify whether the image dependencies in the TLV area are
1753+
* all satisfied and modify the swap type if necessary.
1754+
*
1755+
* @return 0 if all dependencies are satisfied,
1756+
* nonzero otherwise.
1757+
*/
1758+
static int
1759+
boot_verify_single_image_dependency(void)
1760+
{
1761+
size_t slot;
1762+
1763+
/* Determine the source of the dependency TLVs. Those dependencies have to
1764+
* be checked which belong to the image that will be located in the primary
1765+
* slot after the firmware update process.
1766+
*/
1767+
if (BOOT_SWAP_TYPE(&boot_data) != BOOT_SWAP_TYPE_NONE &&
1768+
BOOT_SWAP_TYPE(&boot_data) != BOOT_SWAP_TYPE_FAIL) {
1769+
slot = BOOT_SECONDARY_SLOT;
1770+
} else {
1771+
slot = BOOT_PRIMARY_SLOT;
1772+
}
1773+
1774+
return boot_verify_all_dependency(slot);
1775+
}
1776+
1777+
/**
1778+
* Iterate over all the images and verify whether the image dependencies in the
1779+
* TLV area are all satisfied and update the related swap type if necessary.
1780+
*/
1781+
static void
1782+
boot_verify_all_image_dependency(void)
1783+
{
1784+
current_image = 0;
1785+
int rc;
1786+
1787+
while (current_image < BOOT_IMAGE_NUMBER) {
1788+
rc = boot_verify_single_image_dependency();
1789+
if ( rc == 0) {
1790+
/* All dependencies've been satisfied, continue with next image. */
1791+
current_image++;
1792+
} else if (rc == BOOT_EBADVERSION) {
1793+
/* Dependency check needs to be restarted. */
1794+
current_image = 0;
1795+
} else {
1796+
/* Other error happened, images are inconsistent */
1797+
return;
1798+
}
1799+
}
1800+
}
1801+
#endif /* (BOOT_IMAGE_NUMBER > 1) */
1802+
16111803
/**
16121804
* Performs a clean (not aborted) image update.
16131805
*
@@ -1966,6 +2158,13 @@ boot_go(struct boot_rsp *rsp)
19662158
boot_prepare_image_for_update(&bs);
19672159
}
19682160

2161+
#if (BOOT_IMAGE_NUMBER > 1)
2162+
/* Iterate over all the images and verify whether the image dependencies
2163+
* are all satisfied and update swap type if necessary.
2164+
*/
2165+
boot_verify_all_image_dependency();
2166+
#endif
2167+
19692168
/* Iterate over all the images. At this point there are no aborted swaps
19702169
* and the swap types are determined for each image. By the end of the loop
19712170
* all required update operations will have been finished.

0 commit comments

Comments
 (0)