From d9f554b62440de542c482fecf9374e8da3ea3602 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Sun, 3 Jul 2022 12:48:06 +0200 Subject: pci: Add checks to prevent config space overflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PCIe config space has address range 0-4095. So do not allow reading from addresses outside of this range. Lot of U-Boot drivers do not expect that passed value is not in this range. PCI DM read function is extended to fill read value to all ones or zeros when it fails as U-Boot callers ignores return value. Calling U-Boot command 'pci display.b 0.0.0 0 0x2000' now stops printing config space at the end (before 0x1000 address). Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- cmd/pci.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'cmd') diff --git a/cmd/pci.c b/cmd/pci.c index a99e8f8ad6..6258699fec 100644 --- a/cmd/pci.c +++ b/cmd/pci.c @@ -358,6 +358,9 @@ static int pci_cfg_display(struct udevice *dev, ulong addr, if (length == 0) length = 0x40 / byte_size; /* Standard PCI config space */ + if (addr >= 4096) + return 1; + /* Print the lines. * once, and all accesses are with the specified bus width. */ @@ -378,7 +381,10 @@ static int pci_cfg_display(struct udevice *dev, ulong addr, rc = 1; break; } - } while (nbytes > 0); + } while (nbytes > 0 && addr < 4096); + + if (rc == 0 && nbytes > 0) + return 1; return (rc); } @@ -390,6 +396,9 @@ static int pci_cfg_modify(struct udevice *dev, ulong addr, ulong size, int nbytes; ulong val; + if (addr >= 4096) + return 1; + /* Print the address, followed by value. Then accept input for * the next value. A non-converted value exits. */ @@ -427,7 +436,10 @@ static int pci_cfg_modify(struct udevice *dev, ulong addr, ulong size, addr += size; } } - } while (nbytes); + } while (nbytes && addr < 4096); + + if (nbytes) + return 1; return 0; } -- cgit v1.2.3 From a7091f3f8c859a29ad63b94952472bd93d60488c Mon Sep 17 00:00:00 2001 From: Sergei Antonov Date: Sun, 21 Aug 2022 16:45:08 +0300 Subject: dm: core: fix a typo in help text Signed-off-by: Sergei Antonov Reviewed-by: Simon Glass --- cmd/dm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cmd') diff --git a/cmd/dm.c b/cmd/dm.c index eb40f0865f..218be85795 100644 --- a/cmd/dm.c +++ b/cmd/dm.c @@ -87,7 +87,7 @@ static char dm_help_text[] = "dm drivers Dump list of drivers with uclass and instances\n" DM_MEM_HELP "dm static Dump list of drivers with static platform data\n" - "dn tree Dump tree of driver model devices ('*' = activated)\n" + "dm tree Dump tree of driver model devices ('*' = activated)\n" "dm uclass Dump list of instances for each uclass" ; #endif -- cgit v1.2.3 From 2d74226f2c6ed5b758c97865bef7e42c9f389437 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 23 Aug 2022 10:14:05 -0700 Subject: vbe: Enable command only with BOOTSTD_FULL Avoid enabling this command by default. This saves about 1KB of code space. Signed-off-by: Simon Glass Reviewed-by: Ilias Apalodimas --- cmd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cmd') diff --git a/cmd/Kconfig b/cmd/Kconfig index 211ebe9c87..8ea064b8d2 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -333,7 +333,7 @@ config BOOTM_RTEMS config CMD_VBE bool "vbe - Verified Boot for Embedded" depends on BOOTMETH_VBE - default y + default y if BOOTSTD_FULL help Provides various subcommands related to VBE, such as listing the available methods, looking at the state and changing which method -- cgit v1.2.3 From 1aa9a04ff687b8d55b0fb68ae2a688c8705665cc Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 26 Aug 2022 23:15:55 +0200 Subject: Revert "i2c: fix stack buffer overflow vulnerability in i2c md command" This reverts commit 8f8c04bf1ebbd2f72f1643e7ad9617dafa6e5409. The commit is largely wrong and breaks most of i2c command functionality. The problem described in the aforementioned commit commit message is valid, however the commit itself does many more changes unrelated to fixing that one problem it describes. Those extra changes, namely the handling of i2c device address length as unsigned instead of signed integer, breaks the expectation that address length may be negative value. The negative value is used by DM to indicate that address length of device does not change. The actual bug documented in commit 8f8c04bf1ebbd2f72f1643e7ad9617dafa6e5409 can be fixed by extra sanitization in separate patch. Signed-off-by: Marek Vasut Cc: Heiko Schocher Cc: Nicolas Iooss Cc: Simon Glass Cc: Tim Harvey Reviewed-by: Simon Glass --- cmd/i2c.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'cmd') diff --git a/cmd/i2c.c b/cmd/i2c.c index bd04b14024..9050b2b8d2 100644 --- a/cmd/i2c.c +++ b/cmd/i2c.c @@ -200,10 +200,10 @@ void i2c_init_board(void) * * Returns the address length. */ -static uint get_alen(char *arg, uint default_len) +static uint get_alen(char *arg, int default_len) { - uint j; - uint alen; + int j; + int alen; alen = default_len; for (j = 0; j < 8; j++) { @@ -247,7 +247,7 @@ static int do_i2c_read(struct cmd_tbl *cmdtp, int flag, int argc, { uint chip; uint devaddr, length; - uint alen; + int alen; u_char *memaddr; int ret; #if CONFIG_IS_ENABLED(DM_I2C) @@ -301,7 +301,7 @@ static int do_i2c_write(struct cmd_tbl *cmdtp, int flag, int argc, { uint chip; uint devaddr, length; - uint alen; + int alen; u_char *memaddr; int ret; #if CONFIG_IS_ENABLED(DM_I2C) @@ -469,8 +469,8 @@ static int do_i2c_md(struct cmd_tbl *cmdtp, int flag, int argc, { uint chip; uint addr, length; - uint alen; - uint j, nbytes, linebytes; + int alen; + int j, nbytes, linebytes; int ret; #if CONFIG_IS_ENABLED(DM_I2C) struct udevice *dev; @@ -589,9 +589,9 @@ static int do_i2c_mw(struct cmd_tbl *cmdtp, int flag, int argc, { uint chip; ulong addr; - uint alen; + int alen; uchar byte; - uint count; + int count; int ret; #if CONFIG_IS_ENABLED(DM_I2C) struct udevice *dev; @@ -676,8 +676,8 @@ static int do_i2c_crc(struct cmd_tbl *cmdtp, int flag, int argc, { uint chip; ulong addr; - uint alen; - uint count; + int alen; + int count; uchar byte; ulong crc; ulong err; @@ -985,7 +985,7 @@ static int do_i2c_loop(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { uint chip; - uint alen; + int alen; uint addr; uint length; u_char bytes[16]; -- cgit v1.2.3 From e4573fef7701afc2df22924ce0a445b923475afc Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 26 Aug 2022 23:15:56 +0200 Subject: i2c: fix stack buffer overflow vulnerability in i2c md command This reinstates fix from commit 8f8c04bf1ebb ("i2c: fix stack buffer overflow vulnerability in i2c md command") without the changes unrelated to the actual fix. Avoid the underflow by setting only nbytes and linebytes as unsigned integers. Signed-off-by: Marek Vasut Cc: Heiko Schocher Cc: Nicolas Iooss Cc: Simon Glass Cc: Tim Harvey Acked-by: Tim Harvey --- cmd/i2c.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'cmd') diff --git a/cmd/i2c.c b/cmd/i2c.c index 9050b2b8d2..e196a73efa 100644 --- a/cmd/i2c.c +++ b/cmd/i2c.c @@ -470,7 +470,8 @@ static int do_i2c_md(struct cmd_tbl *cmdtp, int flag, int argc, uint chip; uint addr, length; int alen; - int j, nbytes, linebytes; + int j; + uint nbytes, linebytes; int ret; #if CONFIG_IS_ENABLED(DM_I2C) struct udevice *dev; -- cgit v1.2.3 From 88de6c512758f9705a14965ab97f11b463f3fa7c Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 27 Aug 2022 04:17:28 +0100 Subject: image-fit: don't set compression if it can't be read fit_image_get_comp() should not set value -1 in case it can't read the compression node. Instead, leave the value untouched in that case as it can be absent and a default value previously defined by the caller of fit_image_get_comp() should be used. As a result the warning message WARNING: 'compression' nodes for ramdisks are deprecated, please fix your .its file! no longer shows if the compression node is actually absent. Signed-off-by: Daniel Golle Reviewed-by: Simon Glass --- boot/bootm.c | 6 ++---- boot/image-fit.c | 3 +-- cmd/ximg.c | 7 ++----- 3 files changed, 5 insertions(+), 11 deletions(-) (limited to 'cmd') diff --git a/boot/bootm.c b/boot/bootm.c index 63c79a9cfc..29c067fae7 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -1024,10 +1024,8 @@ static int bootm_host_load_image(const void *fit, int req_image_type, return -EINVAL; } - if (fit_image_get_comp(fit, noffset, &image_comp)) { - puts("Can't get image compression!\n"); - return -EINVAL; - } + if (fit_image_get_comp(fit, noffset, &image_comp)) + image_comp = IH_COMP_NONE; /* Allow the image to expand by a factor of 4, should be safe */ buf_size = (1 << 20) + len * 4; diff --git a/boot/image-fit.c b/boot/image-fit.c index df3e5df883..21dbd05118 100644 --- a/boot/image-fit.c +++ b/boot/image-fit.c @@ -477,7 +477,7 @@ void fit_print_contents(const void *fit) void fit_image_print(const void *fit, int image_noffset, const char *p) { char *desc; - uint8_t type, arch, os, comp; + uint8_t type, arch, os, comp = IH_COMP_NONE; size_t size; ulong load, entry; const void *data; @@ -794,7 +794,6 @@ int fit_image_get_comp(const void *fit, int noffset, uint8_t *comp) data = fdt_getprop(fit, noffset, FIT_COMP_PROP, &len); if (data == NULL) { fit_get_debug(fit, noffset, FIT_COMP_PROP, len); - *comp = -1; return -1; } diff --git a/cmd/ximg.c b/cmd/ximg.c index 65ba41320a..f84141ff45 100644 --- a/cmd/ximg.c +++ b/cmd/ximg.c @@ -171,11 +171,8 @@ do_imgextract(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) return 1; } - if (fit_image_get_comp(fit_hdr, noffset, &comp)) { - puts("Could not find script subimage " - "compression type\n"); - return 1; - } + if (fit_image_get_comp(fit_hdr, noffset, &comp)) + comp = IH_COMP_NONE; data = (ulong)fit_data; len = (ulong)fit_len; -- cgit v1.2.3 From a557d258c6be49ec1253947a227189de149971df Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 30 Aug 2022 21:05:32 -0600 Subject: tpm: Require a digest source when extending the PCR This feature is used for measured boot, so we can add a log entry to the TCPA with some information about where the digest comes from. It is not currently supported in the TPM drivers, but add it to the API so that code which expects it can signal its request. Signed-off-by: Simon Glass Reviewed-by: Ilias Apalodimas Signed-off-by: Ilias Apalodimas --- cmd/tpm-v1.c | 3 ++- cmd/tpm_test.c | 5 +++-- include/tpm_api.h | 8 +++++--- lib/tpm-v2.c | 2 ++ lib/tpm_api.c | 10 ++++++---- 5 files changed, 18 insertions(+), 10 deletions(-) (limited to 'cmd') diff --git a/cmd/tpm-v1.c b/cmd/tpm-v1.c index bf238a9f2e..0efb079b0a 100644 --- a/cmd/tpm-v1.c +++ b/cmd/tpm-v1.c @@ -131,7 +131,8 @@ static int do_tpm_extend(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_FAILURE; } - rc = tpm_pcr_extend(dev, index, in_digest, out_digest); + rc = tpm_pcr_extend(dev, index, in_digest, sizeof(in_digest), + out_digest, "cmd"); if (!rc) { puts("PCR value after execution of the command:\n"); print_byte_string(out_digest, sizeof(out_digest)); diff --git a/cmd/tpm_test.c b/cmd/tpm_test.c index a3ccb12f53..b35eae81dc 100644 --- a/cmd/tpm_test.c +++ b/cmd/tpm_test.c @@ -91,7 +91,8 @@ static int test_early_extend(struct udevice *dev) tpm_init(dev); TPM_CHECK(tpm_startup(dev, TPM_ST_CLEAR)); TPM_CHECK(tpm_continue_self_test(dev)); - TPM_CHECK(tpm_pcr_extend(dev, 1, value_in, value_out)); + TPM_CHECK(tpm_pcr_extend(dev, 1, value_in, sizeof(value_in), value_out, + "test")); printf("done\n"); return 0; } @@ -438,7 +439,7 @@ static int test_timing(struct udevice *dev) 100); TTPM_CHECK(tpm_nv_read_value(dev, INDEX0, (uint8_t *)&x, sizeof(x)), 100); - TTPM_CHECK(tpm_pcr_extend(dev, 0, in, out), 200); + TTPM_CHECK(tpm_pcr_extend(dev, 0, in, sizeof(in), out, "test"), 200); TTPM_CHECK(tpm_set_global_lock(dev), 50); TTPM_CHECK(tpm_tsc_physical_presence(dev, PHYS_PRESENCE), 100); printf("done\n"); diff --git a/include/tpm_api.h b/include/tpm_api.h index 11aa14eb79..8979d9d6df 100644 --- a/include/tpm_api.h +++ b/include/tpm_api.h @@ -81,14 +81,16 @@ u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data, * * @param dev TPM device * @param index index of the PCR - * @param in_digest 160-bit value representing the event to be + * @param in_digest 160/256-bit value representing the event to be * recorded - * @param out_digest 160-bit PCR value after execution of the + * @param size size of digest in bytes + * @param out_digest 160/256-bit PCR value after execution of the * command + * @param name digest source, used for log output * Return: return code of the operation */ u32 tpm_pcr_extend(struct udevice *dev, u32 index, const void *in_digest, - void *out_digest); + uint size, void *out_digest, const char *name); /** * Issue a TPM_PCRRead command. diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 1bf627853a..6058f2e1e4 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -157,6 +157,8 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm, }; int ret; + if (!digest) + return -EINVAL; /* * Fill the command structure starting from the first buffer: * - the digest diff --git a/lib/tpm_api.c b/lib/tpm_api.c index 032f383ca0..7e8df8795e 100644 --- a/lib/tpm_api.c +++ b/lib/tpm_api.c @@ -140,15 +140,17 @@ u32 tpm_write_lock(struct udevice *dev, u32 index) } u32 tpm_pcr_extend(struct udevice *dev, u32 index, const void *in_digest, - void *out_digest) + uint size, void *out_digest, const char *name) { - if (tpm_is_v1(dev)) + if (tpm_is_v1(dev)) { return tpm1_extend(dev, index, in_digest, out_digest); - else if (tpm_is_v2(dev)) + } else if (tpm_is_v2(dev)) { return tpm2_pcr_extend(dev, index, TPM2_ALG_SHA256, in_digest, TPM2_DIGEST_LEN); - else + /* @name is ignored as we do not support the TPM log here */ + } else { return -ENOSYS; + } } u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count) -- cgit v1.2.3 From 3bb4db4c3883c66ee0bbf152e9ba1d2504fa8c9f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 30 Aug 2022 21:05:36 -0600 Subject: tpm: Allow reporting the internal state It is useful to read information about the current TPM state, where supported, e.g. for debugging purposes when verified boot fails. Add support for this to the TPM interface as well as Cr50. Add a simple sandbox test. Signed-off-by: Simon Glass Reviewed-by: Ilias Apalodimas Signed-off-by: Ilias Apalodimas --- cmd/tpm-common.c | 20 ++++++++++++++++++++ cmd/tpm-user-utils.h | 2 ++ cmd/tpm-v2.c | 3 +++ drivers/tpm/tpm-uclass.c | 10 ++++++++++ drivers/tpm/tpm2_tis_sandbox.c | 11 +++++++++++ include/tpm-common.h | 20 ++++++++++++++++++++ test/dm/Makefile | 1 + test/dm/tpm.c | 34 ++++++++++++++++++++++++++++++++++ 8 files changed, 101 insertions(+) create mode 100644 test/dm/tpm.c (limited to 'cmd') diff --git a/cmd/tpm-common.c b/cmd/tpm-common.c index 47adaffd18..d0c63cadf4 100644 --- a/cmd/tpm-common.c +++ b/cmd/tpm-common.c @@ -333,6 +333,26 @@ int do_tpm_info(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) return 0; } +int do_tpm_report_state(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + char buf[80]; + int rc; + + rc = get_tpm(&dev); + if (rc) + return rc; + rc = tpm_report_state(dev, buf, sizeof(buf)); + if (rc < 0) { + printf("Couldn't get TPM state (%d)\n", rc); + return CMD_RET_FAILURE; + } + printf("%s\n", buf); + + return 0; +} + int do_tpm_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct udevice *dev; diff --git a/cmd/tpm-user-utils.h b/cmd/tpm-user-utils.h index 358ddff576..de4a934aab 100644 --- a/cmd/tpm-user-utils.h +++ b/cmd/tpm-user-utils.h @@ -21,6 +21,8 @@ int do_tpm_device(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_tpm_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_tpm_info(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); +int do_tpm_report_state(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); int do_tpm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); #endif /* __TPM_USER_UTILS_H */ diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c index 4ea5f9f094..d93b83ada9 100644 --- a/cmd/tpm-v2.c +++ b/cmd/tpm-v2.c @@ -359,6 +359,7 @@ static int do_tpm_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag, static struct cmd_tbl tpm2_commands[] = { U_BOOT_CMD_MKENT(device, 0, 1, do_tpm_device, "", ""), U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""), + U_BOOT_CMD_MKENT(state, 0, 1, do_tpm_report_state, "", ""), U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""), U_BOOT_CMD_MKENT(startup, 0, 1, do_tpm2_startup, "", ""), U_BOOT_CMD_MKENT(self_test, 0, 1, do_tpm2_self_test, "", ""), @@ -389,6 +390,8 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command", " Show all devices or set the specified device\n" "info\n" " Show information about the TPM.\n" +"state\n" +" Show internal state from the TPM (if available)\n" "init\n" " Initialize the software stack. Always the first command to issue.\n" "startup \n" diff --git a/drivers/tpm/tpm-uclass.c b/drivers/tpm/tpm-uclass.c index 0eb35f50c4..5ff0cd3958 100644 --- a/drivers/tpm/tpm-uclass.c +++ b/drivers/tpm/tpm-uclass.c @@ -49,6 +49,16 @@ int tpm_get_desc(struct udevice *dev, char *buf, int size) return ops->get_desc(dev, buf, size); } +int tpm_report_state(struct udevice *dev, char *buf, int size) +{ + struct tpm_ops *ops = tpm_get_ops(dev); + + if (!ops->report_state) + return -ENOSYS; + + return ops->report_state(dev, buf, size); +} + /* Returns max number of milliseconds to wait */ static ulong tpm_tis_i2c_calc_ordinal_duration(struct tpm_chip_priv *priv, u32 ordinal) diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c index c26f5d35ab..dd94bdc31f 100644 --- a/drivers/tpm/tpm2_tis_sandbox.c +++ b/drivers/tpm/tpm2_tis_sandbox.c @@ -795,6 +795,16 @@ static int sandbox_tpm2_get_desc(struct udevice *dev, char *buf, int size) return snprintf(buf, size, "Sandbox TPM2.x"); } +static int sandbox_tpm2_report_state(struct udevice *dev, char *buf, int size) +{ + struct sandbox_tpm2 *priv = dev_get_priv(dev); + + if (size < 40) + return -ENOSPC; + + return snprintf(buf, size, "init_done=%d", priv->init_done); +} + static int sandbox_tpm2_open(struct udevice *dev) { struct sandbox_tpm2 *tpm = dev_get_priv(dev); @@ -834,6 +844,7 @@ static const struct tpm_ops sandbox_tpm2_ops = { .open = sandbox_tpm2_open, .close = sandbox_tpm2_close, .get_desc = sandbox_tpm2_get_desc, + .report_state = sandbox_tpm2_report_state, .xfer = sandbox_tpm2_xfer, }; diff --git a/include/tpm-common.h b/include/tpm-common.h index a28629e701..b2c5404430 100644 --- a/include/tpm-common.h +++ b/include/tpm-common.h @@ -119,6 +119,16 @@ struct tpm_ops { */ int (*get_desc)(struct udevice *dev, char *buf, int size); + /** + * report_state() - Collect information about the current TPM state + * + * @dev: Device to check + * @buf: Buffer to put the string + * @size: Maximum size of buffer + * Return: return code of the operation (0 = success) + */ + int (*report_state)(struct udevice *dev, char *buf, int size); + /** * send() - send data to the TPM * @@ -234,6 +244,16 @@ u32 tpm_clear_and_reenable(struct udevice *dev); */ int tpm_get_desc(struct udevice *dev, char *buf, int size); +/** + * tpm_report_state() - Collect information about the current TPM state + * + * @dev: Device to check + * @buf: Buffer to put the string + * @size: Maximum size of buffer + * Return: return code of the operation (0 = success) + */ +int tpm_report_state(struct udevice *dev, char *buf, int size); + /** * tpm_xfer() - send data to the TPM and get response * diff --git a/test/dm/Makefile b/test/dm/Makefile index 52fe178a82..7543df8823 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -107,6 +107,7 @@ obj-$(CONFIG_SYSINFO_GPIO) += sysinfo-gpio.o obj-$(CONFIG_UT_DM) += tag.o obj-$(CONFIG_TEE) += tee.o obj-$(CONFIG_TIMER) += timer.o +obj-$(CONFIG_TPM_V2) += tpm.o obj-$(CONFIG_DM_USB) += usb.o obj-$(CONFIG_DM_VIDEO) += video.o ifeq ($(CONFIG_VIRTIO_SANDBOX),y) diff --git a/test/dm/tpm.c b/test/dm/tpm.c new file mode 100644 index 0000000000..0b46f79959 --- /dev/null +++ b/test/dm/tpm.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2022 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include + +/* Basic test of the TPM uclass */ +static int dm_test_tpm(struct unit_test_state *uts) +{ + struct udevice *dev; + char buf[50]; + + /* check probe success */ + ut_assertok(uclass_first_device_err(UCLASS_TPM, &dev)); + ut_assert(tpm_is_v2(dev)); + + ut_assert(tpm_report_state(dev, buf, sizeof(buf))); + ut_asserteq_str("init_done=0", buf); + + ut_assertok(tpm_init(dev)); + + ut_assert(tpm_report_state(dev, buf, sizeof(buf))); + ut_asserteq_str("init_done=1", buf); + + return 0; +} +DM_TEST(dm_test_tpm, UT_TESTF_SCAN_FDT); -- cgit v1.2.3 From aa8aa48b4c32fafaf2c393b4a937b0b35668943e Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 14 Aug 2022 21:57:14 +0200 Subject: cmd/sbi: format KVM version Format the KVM implementation number in a human readable form. With the patch output of the sbi command for Linux 5.19.1 looks like: => sbi SBI 0.3 KVM 5.19.1 Machine: Vendor ID 0 Architecture ID 7005c Implementation ID 7005c Extensions: SBI Base Functionality Timer Extension IPI Extension RFENCE Extension Hart State Management Extension System Reset Extension Signed-off-by: Heinrich Schuchardt Reviewed-by: Leo Yu-Chi Liang --- cmd/riscv/sbi.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'cmd') diff --git a/cmd/riscv/sbi.c b/cmd/riscv/sbi.c index ee11e0f88e..522f502435 100644 --- a/cmd/riscv/sbi.c +++ b/cmd/riscv/sbi.c @@ -68,11 +68,21 @@ static int do_sbi(struct cmd_tbl *cmdtp, int flag, int argc, ret = sbi_get_impl_version(&vers); if (ret < 0) break; - if (impl_id == 1) + switch (impl_id) { + case 1: /* OpenSBI */ printf("%ld.%ld", vers >> 16, vers & 0xffff); - else + break; + case 3: /* KVM */ + printf("%ld.%ld.%ld", + vers >> 16, + (vers >> 8) & 0xff, + vers & 0xff); + break; + default: printf("0x%lx", vers); + break; + } break; } } -- cgit v1.2.3 From 7b42bde075c9cec85aa200d2e093d3b2b5641d94 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 16 Aug 2022 11:16:05 -0400 Subject: cmd: fpga: Convert to use fit_get_data_node This converts the FIT loading process of the fpga command to use fit_get_data_node. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass Signed-off-by: Peng Fan --- cmd/fpga.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) (limited to 'cmd') diff --git a/cmd/fpga.c b/cmd/fpga.c index c4651dd403..9cf7651d8c 100644 --- a/cmd/fpga.c +++ b/cmd/fpga.c @@ -322,7 +322,7 @@ static int do_fpga_loadmk(struct cmd_tbl *cmdtp, int flag, int argc, case IMAGE_FORMAT_FIT: { const void *fit_hdr = (const void *)fpga_data; - int noffset; + int err; const void *fit_data; if (!fit_uname) { @@ -335,23 +335,11 @@ static int do_fpga_loadmk(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_FAILURE; } - /* get fpga component image node offset */ - noffset = fit_image_get_node(fit_hdr, fit_uname); - if (noffset < 0) { - printf("Can't find '%s' FIT subimage\n", fit_uname); - return CMD_RET_FAILURE; - } - - /* verify integrity */ - if (!fit_image_verify(fit_hdr, noffset)) { - puts("Bad Data Hash\n"); - return CMD_RET_FAILURE; - } - - /* get fpga subimage/external data address and length */ - if (fit_image_get_data_and_size(fit_hdr, noffset, - &fit_data, &data_size)) { - puts("Fpga subimage data not found\n"); + err = fit_get_data_node(fit_hdr, fit_uname, &fit_data, + &data_size); + if (err) { + printf("Could not load '%s' subimage (err %d)\n", + fit_uname, err); return CMD_RET_FAILURE; } -- cgit v1.2.3 From 5f46c6eba59bc3bd29f0641628891c443930e477 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 3 Sep 2022 12:21:09 +0000 Subject: cmd: fix tftpput command Calling tftpput with less than 2 arguments must lead to a failure. If tftpput is called with two arguments, these are the address and the size of the file to be transferred. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- cmd/net.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 24 deletions(-) (limited to 'cmd') diff --git a/cmd/net.c b/cmd/net.c index 3619c843d8..527ac84553 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -189,30 +189,49 @@ static void netboot_update_env(void) #endif } -static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, - char *const argv[]) +/** + * parse_addr_size() - parse address and size arguments for tftpput + * + * @argv: command line arguments + * Return: 0 on success + */ +static int parse_addr_size(char * const argv[]) { - char *s; - char *end; - int rcode = 0; - int size; - ulong addr; - - net_boot_file_name_explicit = false; + if (strict_strtoul(argv[1], 16, &image_save_addr) < 0 || + strict_strtoul(argv[2], 16, &image_save_size) < 0) { + printf("Invalid address/size\n"); + return CMD_RET_USAGE; + } + return 0; +} - /* pre-set image_load_addr */ - s = env_get("loadaddr"); - if (s != NULL) - image_load_addr = hextoul(s, NULL); +/** + * parse_args() - parse command line arguments + * + * @proto: command prototype + * @argc: number of arguments + * @argv: command line arguments + * Return: 0 on success + */ +static int parse_args(enum proto_t proto, int argc, char *const argv[]) +{ + ulong addr; + char *end; switch (argc) { case 1: + if (CONFIG_IS_ENABLED(CMD_TFTPPUT) && proto == TFTPPUT) + return 1; + /* refresh bootfile name from env */ copy_filename(net_boot_file_name, env_get("bootfile"), sizeof(net_boot_file_name)); break; - case 2: /* + case 2: + if (CONFIG_IS_ENABLED(CMD_TFTPPUT) && proto == TFTPPUT) + return 1; + /* * Only one arg - accept two forms: * Just load address, or just boot file name. The latter * form must be written in a format which can not be @@ -232,29 +251,52 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, break; case 3: - image_load_addr = hextoul(argv[1], NULL); - net_boot_file_name_explicit = true; - copy_filename(net_boot_file_name, argv[2], - sizeof(net_boot_file_name)); - + if (CONFIG_IS_ENABLED(CMD_TFTPPUT) && proto == TFTPPUT) { + if (parse_addr_size(argv)) + return 1; + } else { + image_load_addr = hextoul(argv[1], NULL); + net_boot_file_name_explicit = true; + copy_filename(net_boot_file_name, argv[2], + sizeof(net_boot_file_name)); + } break; #ifdef CONFIG_CMD_TFTPPUT case 4: - if (strict_strtoul(argv[1], 16, &image_save_addr) < 0 || - strict_strtoul(argv[2], 16, &image_save_size) < 0) { - printf("Invalid address/size\n"); - return CMD_RET_USAGE; - } + if (parse_addr_size(argv)) + return 1; net_boot_file_name_explicit = true; copy_filename(net_boot_file_name, argv[3], sizeof(net_boot_file_name)); break; #endif default: + return 1; + } + return 0; +} + +static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, + char *const argv[]) +{ + char *s; + int rcode = 0; + int size; + + net_boot_file_name_explicit = false; + *net_boot_file_name = '\0'; + + /* pre-set image_load_addr */ + s = env_get("loadaddr"); + if (s != NULL) + image_load_addr = hextoul(s, NULL); + + if (parse_args(proto, argc, argv)) { bootstage_error(BOOTSTAGE_ID_NET_START); return CMD_RET_USAGE; } + bootstage_mark(BOOTSTAGE_ID_NET_START); size = net_loop(proto); -- cgit v1.2.3 From 651031ef7c47f2efb2cec11c18eb9aa2020e0815 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 4 Sep 2022 09:08:11 +0200 Subject: cmd: correct short text for tftpboot The command's name is a misnomer. The command loads a file but does not run (boot) it. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- cmd/Kconfig | 2 +- cmd/net.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'cmd') diff --git a/cmd/Kconfig b/cmd/Kconfig index 8ea064b8d2..0e0be94f41 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1719,7 +1719,7 @@ config CMD_TFTPBOOT bool "tftpboot" default y help - tftpboot - boot image via network using TFTP protocol + tftpboot - load file via network using TFTP protocol config CMD_TFTPPUT bool "tftp put" diff --git a/cmd/net.c b/cmd/net.c index 527ac84553..46f8c87b69 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -46,7 +46,7 @@ int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) U_BOOT_CMD( tftpboot, 3, 1, do_tftpb, - "boot image via network using TFTP protocol", + "load file via network using TFTP protocol", "[loadAddress] [[hostIPaddr:]bootfilename]" ); #endif -- cgit v1.2.3 From 5a0653493307796e63227d78e40651096c1ca23a Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 23 Aug 2022 14:52:23 +0200 Subject: cmd: mvebu/bubt: Check for A38x image data checksum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently for A38x image is checked only header checksum. So check also for image data checksum to prevent flashing broken image. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- cmd/mvebu/bubt.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'cmd') diff --git a/cmd/mvebu/bubt.c b/cmd/mvebu/bubt.c index 2136af6416..a97e5ce38a 100644 --- a/cmd/mvebu/bubt.c +++ b/cmd/mvebu/bubt.c @@ -688,9 +688,25 @@ static uint8_t image_checksum8(const void *start, size_t len) return csum; } +static uint32_t image_checksum32(const void *start, size_t len) +{ + u32 csum = 0; + const u32 *p = start; + + while (len) { + csum += *p; + ++p; + len -= sizeof(u32); + } + + return csum; +} + static int check_image_header(void) { u8 checksum; + u32 checksum32, exp_checksum32; + u32 offset, size; const struct a38x_main_hdr_v1 *hdr = (struct a38x_main_hdr_v1 *)get_load_addr(); const size_t image_size = a38x_header_size(hdr); @@ -701,11 +717,39 @@ static int check_image_header(void) checksum = image_checksum8(hdr, image_size); checksum -= hdr->checksum; if (checksum != hdr->checksum) { - printf("Error: Bad A38x image checksum. 0x%x != 0x%x\n", + printf("Error: Bad A38x image header checksum. 0x%x != 0x%x\n", checksum, hdr->checksum); return -ENOEXEC; } + offset = le32_to_cpu(hdr->srcaddr); + size = le32_to_cpu(hdr->blocksize); + + if (hdr->blockid == 0x78) { /* SATA id */ + if (offset < 1) { + printf("Error: Bad A38x image srcaddr.\n"); + return -ENOEXEC; + } + offset -= 1; + offset *= 512; + } + + if (hdr->blockid == 0xAE) /* SDIO id */ + offset *= 512; + + if (offset % 4 != 0 || size < 4 || size % 4 != 0) { + printf("Error: Bad A38x image blocksize.\n"); + return -ENOEXEC; + } + + checksum32 = image_checksum32((u8 *)hdr + offset, size - 4); + exp_checksum32 = *(u32 *)((u8 *)hdr + offset + size - 4); + if (checksum32 != exp_checksum32) { + printf("Error: Bad A38x image data checksum. 0x%08x != 0x%08x\n", + checksum32, exp_checksum32); + return -ENOEXEC; + } + printf("Image checksum...OK!\n"); return 0; } -- cgit v1.2.3 From f7b0bbca2b6257c50d4e087322602593a0f279cf Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 23 Aug 2022 14:52:24 +0200 Subject: cmd: mvebu/bubt: Check for A38x/A37xx OTP secure bits and secure boot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For obvious reasons BootROMS rejects unsigned images when secure boot is enabled in OTP secure bits. So check for OPT secure bits and do not allow flashing unsigned images when secure boot is enabled. Access to OTP via U-Boot fuse API is currently implemented only for A38x and A37xx SoCs. Additionally Armada 3700 BootROM rejects signed trusted image when secure boot is not enabled in OTP. So add also check for this case. On the other hand Armada 38x BootROM acceps images with secure boot header when secure boot is not enabled in OTP. OTP secure bits may have burned also boot device source. Check it also and reject flashing images to target storage which does not match OTP. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- cmd/mvebu/Kconfig | 1 + cmd/mvebu/bubt.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 121 insertions(+), 8 deletions(-) (limited to 'cmd') diff --git a/cmd/mvebu/Kconfig b/cmd/mvebu/Kconfig index 120397d6d4..9ec3aa983a 100644 --- a/cmd/mvebu/Kconfig +++ b/cmd/mvebu/Kconfig @@ -5,6 +5,7 @@ config CMD_MVEBU_BUBT bool "bubt" select SHA256 if ARMADA_3700 select SHA512 if ARMADA_3700 + select MVEBU_EFUSE if ARMADA_38X || ARMADA_3700 help bubt - Burn a u-boot image to flash For details about bubt command please see the documentation diff --git a/cmd/mvebu/bubt.c b/cmd/mvebu/bubt.c index a97e5ce38a..7e6e47f40d 100644 --- a/cmd/mvebu/bubt.c +++ b/cmd/mvebu/bubt.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include @@ -121,6 +123,17 @@ struct a38x_main_hdr_v1 { u8 checksum; /* 0x1F */ }; +/* + * Header for the optional headers, version 1 (Armada 370/XP/375/38x/39x) + */ +struct a38x_opt_hdr_v1 { + u8 headertype; + u8 headersz_msb; + u16 headersz_lsb; + u8 data[0]; +}; +#define A38X_OPT_HDR_V1_SECURE_TYPE 0x1 + struct a38x_boot_mode { unsigned int id; const char *name; @@ -753,6 +766,38 @@ static int check_image_header(void) printf("Image checksum...OK!\n"); return 0; } + +#if defined(CONFIG_ARMADA_38X) +static int a38x_image_is_secure(const struct a38x_main_hdr_v1 *hdr) +{ + u32 image_size = a38x_header_size(hdr); + struct a38x_opt_hdr_v1 *ohdr; + u32 ohdr_size; + + if (hdr->version != 1) + return 0; + + if (!hdr->ext) + return 0; + + ohdr = (struct a38x_opt_hdr_v1 *)(hdr + 1); + do { + if (ohdr->headertype == A38X_OPT_HDR_V1_SECURE_TYPE) + return 1; + + ohdr_size = (ohdr->headersz_msb << 16) | le16_to_cpu(ohdr->headersz_lsb); + + if (!*((u8 *)ohdr + ohdr_size - 4)) + break; + + ohdr = (struct a38x_opt_hdr_v1 *)((u8 *)ohdr + ohdr_size); + if ((u8 *)ohdr >= (u8 *)hdr + image_size) + break; + } while (1); + + return 0; +} +#endif #else /* Not ARMADA? */ static int check_image_header(void) { @@ -761,20 +806,60 @@ static int check_image_header(void) } #endif +#if defined(CONFIG_ARMADA_3700) || defined(CONFIG_ARMADA_32BIT) +static u64 fuse_read_u64(u32 bank) +{ + u32 val[2]; + int ret; + + ret = fuse_read(bank, 0, &val[0]); + if (ret < 0) + return -1; + + ret = fuse_read(bank, 1, &val[1]); + if (ret < 0) + return -1; + + return ((u64)val[1] << 32) | val[0]; +} +#endif + +#if defined(CONFIG_ARMADA_3700) +static inline u8 maj3(u8 val) +{ + /* return majority vote of 3 bits */ + return ((val & 0x7) == 3 || (val & 0x7) > 4) ? 1 : 0; +} +#endif + static int bubt_check_boot_mode(const struct bubt_dev *dst) { #if defined(CONFIG_ARMADA_3700) || defined(CONFIG_ARMADA_32BIT) - int mode; + int mode, secure_mode; #if defined(CONFIG_ARMADA_3700) const struct tim_boot_flash_sign *boot_modes = tim_boot_flash_signs; const struct common_tim_data *hdr = (struct common_tim_data *)get_load_addr(); u32 id = hdr->boot_flash_sign; + int is_secure = hdr->trusted != 0; + u64 otp_secure_bits = fuse_read_u64(1); + int otp_secure_boot = ((maj3(otp_secure_bits >> 0) << 0) | + (maj3(otp_secure_bits >> 4) << 1)) == 2; + unsigned int otp_boot_device = (maj3(otp_secure_bits >> 48) << 0) | + (maj3(otp_secure_bits >> 52) << 1) | + (maj3(otp_secure_bits >> 56) << 2) | + (maj3(otp_secure_bits >> 60) << 3); #elif defined(CONFIG_ARMADA_32BIT) const struct a38x_boot_mode *boot_modes = a38x_boot_modes; const struct a38x_main_hdr_v1 *hdr = (struct a38x_main_hdr_v1 *)get_load_addr(); u32 id = hdr->blockid; +#if defined(CONFIG_ARMADA_38X) + int is_secure = a38x_image_is_secure(hdr); + u64 otp_secure_bits = fuse_read_u64(EFUSE_LINE_SECURE_BOOT); + int otp_secure_boot = otp_secure_bits & 0x1; + unsigned int otp_boot_device = (otp_secure_bits >> 8) & 0x7; +#endif #endif for (mode = 0; boot_modes[mode].name; mode++) { @@ -787,15 +872,42 @@ static int bubt_check_boot_mode(const struct bubt_dev *dst) return -ENOEXEC; } - if (strcmp(boot_modes[mode].name, dst->name) == 0) - return 0; + if (strcmp(boot_modes[mode].name, dst->name) != 0) { + printf("Error: image meant to be booted from \"%s\", not \"%s\"!\n", + boot_modes[mode].name, dst->name); + return -ENOEXEC; + } - printf("Error: image meant to be booted from \"%s\", not \"%s\"!\n", - boot_modes[mode].name, dst->name); - return -ENOEXEC; -#else - return 0; +#if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ARMADA_3700) + if (otp_secure_bits == (u64)-1) { + printf("Error: cannot read OTP secure bits\n"); + return -ENOEXEC; + } else { + if (otp_secure_boot && !is_secure) { + printf("Error: secure boot is enabled in OTP but image does not have secure boot header!\n"); + return -ENOEXEC; + } else if (!otp_secure_boot && is_secure) { +#if defined(CONFIG_ARMADA_3700) + /* + * Armada 3700 BootROM rejects trusted image when secure boot is not enabled. + * Armada 385 BootROM accepts image with secure boot header also when secure boot is not enabled. + */ + printf("Error: secure boot is disabled in OTP but image has secure boot header!\n"); + return -ENOEXEC; #endif + } else if (otp_boot_device && otp_boot_device != id) { + for (secure_mode = 0; boot_modes[secure_mode].name; secure_mode++) { + if (boot_modes[secure_mode].id == otp_boot_device) + break; + } + printf("Error: boot source is set to \"%s\" in OTP but image is for \"%s\"!\n", + boot_modes[secure_mode].name ?: "unknown", dst->name); + return -ENOEXEC; + } + } +#endif +#endif + return 0; } static int bubt_verify(const struct bubt_dev *dst) -- cgit v1.2.3