From 91c3e7ff3f0e7c230ef9c3366ff0b985540710c9 Mon Sep 17 00:00:00 2001 From: "yuan.w.hong" Date: Sun, 26 Sep 2021 17:28:35 +0800 Subject: [PATCH] fixed abd9883 from https://gitee.com/openharmony/device_hisilicon_third_party_uboot/pulls/18 fix CVE-2021-27138 CVE-2021-27097 --- .../arch/arm/cpu/armv8/sec_firmware.c | 2 +- u-boot-2020.01/cmd/bootm.c | 6 +-- u-boot-2020.01/cmd/disk.c | 2 +- u-boot-2020.01/cmd/fpga.c | 2 +- u-boot-2020.01/cmd/nand.c | 2 +- u-boot-2020.01/cmd/source.c | 2 +- u-boot-2020.01/cmd/ximg.c | 2 +- u-boot-2020.01/common/image-fdt.c | 2 +- u-boot-2020.01/common/image-fit.c | 34 ++++++---------- u-boot-2020.01/common/splash_source.c | 6 +-- u-boot-2020.01/common/update.c | 2 +- u-boot-2020.01/drivers/fpga/socfpga_arria10.c | 6 +-- u-boot-2020.01/drivers/net/fsl-mc/mc.c | 2 +- .../drivers/net/pfe_eth/pfe_firmware.c | 2 +- u-boot-2020.01/include/image.h | 20 +++++++++- u-boot-2020.01/scripts/dtc/libfdt/fdt_ro.c | 17 ++++++++ u-boot-2020.01/test/py/tests/test_vboot.py | 39 +++++++++++++------ u-boot-2020.01/test/py/tests/vboot_forge.py | 12 +++--- u-boot-2020.01/tools/fit_common.c | 3 +- u-boot-2020.01/tools/fit_image.c | 2 +- 20 files changed, 104 insertions(+), 61 deletions(-) diff --git a/u-boot-2020.01/arch/arm/cpu/armv8/sec_firmware.c b/u-boot-2020.01/arch/arm/cpu/armv8/sec_firmware.c index 95ea57d571..d44ddd37db 100644 --- a/u-boot-2020.01/arch/arm/cpu/armv8/sec_firmware.c +++ b/u-boot-2020.01/arch/arm/cpu/armv8/sec_firmware.c @@ -311,7 +311,7 @@ __weak bool sec_firmware_is_valid(const void *sec_firmware_img) return false; } - if (!fit_check_format(sec_firmware_img)) { + if (fit_check_format(sec_firmware_img, IMAGE_SIZE_INVAL)) { printf("SEC Firmware: Bad firmware image (bad FIT header)\n"); return false; } diff --git a/u-boot-2020.01/cmd/bootm.c b/u-boot-2020.01/cmd/bootm.c index aa87beaf9b..e2a15e99f1 100644 --- a/u-boot-2020.01/cmd/bootm.c +++ b/u-boot-2020.01/cmd/bootm.c @@ -316,7 +316,7 @@ static int image_info(ulong addr) case IMAGE_FORMAT_FIT: puts(" FIT image found\n"); - if (!fit_check_format(hdr)) { + if (fit_check_format(hdr, IMAGE_SIZE_INVAL)) { puts("Bad FIT image format!\n"); unmap_sysmem(hdr); return 1; @@ -393,7 +393,7 @@ static int do_imls_nor(void) #endif #if defined(CONFIG_FIT) case IMAGE_FORMAT_FIT: - if (!fit_check_format(hdr)) + if (fit_check_format(hdr, IMAGE_SIZE_INVAL)) goto next_sector; printf("FIT Image at %08lX:\n", (ulong)hdr); @@ -473,7 +473,7 @@ static int nand_imls_fitimage(struct mtd_info *mtd, int nand_dev, loff_t off, return ret; } - if (!fit_check_format(imgdata)) { + if (fit_check_format(imgdata, IMAGE_SIZE_INVAL)) { free(imgdata); return 0; } diff --git a/u-boot-2020.01/cmd/disk.c b/u-boot-2020.01/cmd/disk.c index 437c175374..68efd849d2 100644 --- a/u-boot-2020.01/cmd/disk.c +++ b/u-boot-2020.01/cmd/disk.c @@ -111,7 +111,7 @@ int common_diskboot(cmd_tbl_t *cmdtp, const char *intf, int argc, /* This cannot be done earlier, * we need complete FIT image in RAM first */ if (genimg_get_format((void *) addr) == IMAGE_FORMAT_FIT) { - if (!fit_check_format(fit_hdr)) { + if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { bootstage_error(BOOTSTAGE_ID_IDE_FIT_READ); puts("** Bad FIT image format\n"); return 1; diff --git a/u-boot-2020.01/cmd/fpga.c b/u-boot-2020.01/cmd/fpga.c index b1c7b5453b..9a1336efee 100644 --- a/u-boot-2020.01/cmd/fpga.c +++ b/u-boot-2020.01/cmd/fpga.c @@ -327,7 +327,7 @@ static int do_fpga_loadmk(cmd_tbl_t *cmdtp, int flag, int argc, return CMD_RET_FAILURE; } - if (!fit_check_format(fit_hdr)) { + if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { puts("Bad FIT image format\n"); return CMD_RET_FAILURE; } diff --git a/u-boot-2020.01/cmd/nand.c b/u-boot-2020.01/cmd/nand.c index 1d30f9a492..1ddf17a711 100644 --- a/u-boot-2020.01/cmd/nand.c +++ b/u-boot-2020.01/cmd/nand.c @@ -1148,7 +1148,7 @@ static int nand_load_image(cmd_tbl_t *cmdtp, struct mtd_info *mtd, #if defined(CONFIG_FIT) /* This cannot be done earlier, we need complete FIT image in RAM first */ if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) { - if (!fit_check_format (fit_hdr)) { + if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { bootstage_error(BOOTSTAGE_ID_NAND_FIT_READ); puts ("** Bad FIT image format\n"); return 1; diff --git a/u-boot-2020.01/cmd/source.c b/u-boot-2020.01/cmd/source.c index 3a51ebf0b6..0f43d2c70c 100644 --- a/u-boot-2020.01/cmd/source.c +++ b/u-boot-2020.01/cmd/source.c @@ -107,7 +107,7 @@ source (ulong addr, const char *fit_uname) #if defined(CONFIG_FIT) case IMAGE_FORMAT_FIT: fit_hdr = buf; - if (!fit_check_format (fit_hdr)) { + if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { puts ("Bad FIT image format\n"); return 1; } diff --git a/u-boot-2020.01/cmd/ximg.c b/u-boot-2020.01/cmd/ximg.c index 22b2037a33..358a06f26b 100644 --- a/u-boot-2020.01/cmd/ximg.c +++ b/u-boot-2020.01/cmd/ximg.c @@ -134,7 +134,7 @@ do_imgextract(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) "at %08lx ...\n", uname, addr); fit_hdr = (const void *)addr; - if (!fit_check_format(fit_hdr)) { + if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { puts("Bad FIT image format\n"); return 1; } diff --git a/u-boot-2020.01/common/image-fdt.c b/u-boot-2020.01/common/image-fdt.c index 48388488d9..d815e42cf9 100644 --- a/u-boot-2020.01/common/image-fdt.c +++ b/u-boot-2020.01/common/image-fdt.c @@ -395,7 +395,7 @@ int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch, */ #if CONFIG_IS_ENABLED(FIT) /* check FDT blob vs FIT blob */ - if (fit_check_format(buf)) { + if (!fit_check_format(buf, IMAGE_SIZE_INVAL)) { ulong load, len; fdt_noffset = boot_get_fdt_fit(images, diff --git a/u-boot-2020.01/common/image-fit.c b/u-boot-2020.01/common/image-fit.c index 35b93ff650..3cebebc4ca 100755 --- a/u-boot-2020.01/common/image-fit.c +++ b/u-boot-2020.01/common/image-fit.c @@ -8,6 +8,8 @@ * Wolfgang Denk, DENX Software Engineering, wd@denx.de. */ +#define LOG_CATEGORY LOGC_BOOT + #ifdef USE_HOSTCC #include "mkimage.h" #include @@ -1583,21 +1585,9 @@ static int fdt_check_no_at(const void *fit, int parent) return 0; } -/** - * fit_check_format - sanity check FIT image format - * @fit: pointer to the FIT format image header - * - * fit_check_format() runs a basic sanity FIT image verification. - * Routine checks for mandatory properties, nodes, etc. - * - * returns: - * 1, on success - * 0, on failure - */ -int fit_check_format(const void *fit) +int fit_check_format(const void *fit, ulong size) { int ret; - ulong size; /* A FIT image must be a valid FDT */ ret = fdt_check_header(fit); @@ -1613,7 +1603,8 @@ int fit_check_format(const void *fit) * This is not as secure, so we should consider a flag to * control this. */ - size = fdt_totalsize(fit); + if (size == IMAGE_SIZE_INVAL) + size = fdt_totalsize(fit); ret = fdt_check_full(fit, size); if (ret) ret = -EINVAL; @@ -1640,29 +1631,28 @@ int fit_check_format(const void *fit) } /* mandatory / node 'description' property */ - if (fdt_getprop(fit, 0, FIT_DESC_PROP, NULL) == NULL) { + if (!fdt_getprop(fit, 0, FIT_DESC_PROP, NULL)) { debug("Wrong FIT format: no description\n"); - return 0; + return -ENOMSG; } if (IMAGE_ENABLE_TIMESTAMP) { /* mandatory / node 'timestamp' property */ - if (fdt_getprop(fit, 0, FIT_TIMESTAMP_PROP, NULL) == NULL) { + if (!fdt_getprop(fit, 0, FIT_TIMESTAMP_PROP, NULL)) { debug("Wrong FIT format: no timestamp\n"); - return 0; + return -ENODATA; } } /* mandatory subimages parent '/images' node */ if (fdt_path_offset(fit, FIT_IMAGES_PATH) < 0) { debug("Wrong FIT format: no images parent node\n"); - return 0; + return -ENOENT; } - return 1; + return 0; } - /** * fit_conf_find_compat * @fit: pointer to the FIT format image header @@ -1992,7 +1982,7 @@ int fit_image_load(bootm_headers_t *images, ulong addr, printf("## Loading %s from FIT Image at %08lx ...\n", prop_name, addr); bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT); - ret = fit_check_format(fit); + ret = fit_check_format(fit, IMAGE_SIZE_INVAL); if (ret) { printf("Bad FIT %s image format! (err=%d)\n", prop_name, ret); if (CONFIG_IS_ENABLED(FIT_SIGNATURE) && ret == -EADDRNOTAVAIL) diff --git a/u-boot-2020.01/common/splash_source.c b/u-boot-2020.01/common/splash_source.c index 2ff15208a7..586223ad98 100644 --- a/u-boot-2020.01/common/splash_source.c +++ b/u-boot-2020.01/common/splash_source.c @@ -335,10 +335,10 @@ static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr) if (res < 0) return res; - res = fit_check_format(fit_header); - if (!res) { + res = fit_check_format(fit_header, IMAGE_SIZE_INVAL); + if (res) { debug("Could not find valid FIT image\n"); - return -EINVAL; + return res; } /* Get the splash image node */ diff --git a/u-boot-2020.01/common/update.c b/u-boot-2020.01/common/update.c index 13b09ab00f..3ce80ec742 100644 --- a/u-boot-2020.01/common/update.c +++ b/u-boot-2020.01/common/update.c @@ -282,7 +282,7 @@ int update_tftp(ulong addr, char *interface, char *devstring) got_update_file: fit = (void *)addr; - if (!fit_check_format((void *)fit)) { + if (fit_check_format((void *)fit, IMAGE_SIZE_INVAL)) { printf("Bad FIT format of the update file, aborting " "auto-update\n"); return 1; diff --git a/u-boot-2020.01/drivers/fpga/socfpga_arria10.c b/u-boot-2020.01/drivers/fpga/socfpga_arria10.c index 5fb9d6a191..282b350caf 100644 --- a/u-boot-2020.01/drivers/fpga/socfpga_arria10.c +++ b/u-boot-2020.01/drivers/fpga/socfpga_arria10.c @@ -563,10 +563,10 @@ static int first_loading_rbf_to_buffer(struct udevice *dev, if (ret < 0) return ret; - ret = fit_check_format(buffer_p); - if (!ret) { + ret = fit_check_format(buffer_p, IMAGE_SIZE_INVAL); + if (ret) { debug("FPGA: No valid FIT image was found.\n"); - return -EBADF; + return ret; } confs_noffset = fdt_path_offset(buffer_p, FIT_CONFS_PATH); diff --git a/u-boot-2020.01/drivers/net/fsl-mc/mc.c b/u-boot-2020.01/drivers/net/fsl-mc/mc.c index ffc408e3a4..d1ceeb3580 100644 --- a/u-boot-2020.01/drivers/net/fsl-mc/mc.c +++ b/u-boot-2020.01/drivers/net/fsl-mc/mc.c @@ -133,7 +133,7 @@ int parse_mc_firmware_fit_image(u64 mc_fw_addr, return -EINVAL; } - if (!fit_check_format(fit_hdr)) { + if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { printf("fsl-mc: ERR: Bad firmware image (bad FIT header)\n"); return -EINVAL; } diff --git a/u-boot-2020.01/drivers/net/pfe_eth/pfe_firmware.c b/u-boot-2020.01/drivers/net/pfe_eth/pfe_firmware.c index e4563f192b..6c3d515f45 100644 --- a/u-boot-2020.01/drivers/net/pfe_eth/pfe_firmware.c +++ b/u-boot-2020.01/drivers/net/pfe_eth/pfe_firmware.c @@ -150,7 +150,7 @@ static int pfe_fit_check(void) return ret; } - if (!fit_check_format(pfe_fit_addr)) { + if (fit_check_format(pfe_fit_addr, IMAGE_SIZE_INVAL)) { printf("PFE Firmware: Bad firmware image (bad FIT header)\n"); ret = -1; return ret; diff --git a/u-boot-2020.01/include/image.h b/u-boot-2020.01/include/image.h index da3b8c3f22..6101cf36a2 100644 --- a/u-boot-2020.01/include/image.h +++ b/u-boot-2020.01/include/image.h @@ -111,6 +111,8 @@ struct fdt_region; #else # define IMAGE_OF_SYSTEM_SETUP 0 #endif +/* An invalid size, meaning that the image size is not known */ +#define IMAGE_SIZE_INVAL (-1UL) enum ih_category { IH_ARCH, @@ -1074,7 +1076,23 @@ int fit_image_check_os(const void *fit, int noffset, uint8_t os); int fit_image_check_arch(const void *fit, int noffset, uint8_t arch); int fit_image_check_type(const void *fit, int noffset, uint8_t type); int fit_image_check_comp(const void *fit, int noffset, uint8_t comp); -int fit_check_format(const void *fit); + +/** + * fit_check_format() - Check that the FIT is valid + * + * This performs various checks on the FIT to make sure it is suitable for + * use, looking for mandatory properties, nodes, etc. + * + * If FIT_FULL_CHECK is enabled, it also runs it through libfdt to make + * sure that there are no strange tags or broken nodes in the FIT. + * + * @fit: pointer to the FIT format image header + * @return 0 if OK, -ENOEXEC if not an FDT file, -EINVAL if the full FDT check + * failed (e.g. due to bad structure), -ENOMSG if the description is + * missing, -ENODATA if the timestamp is missing, -ENOENT if the /images + * path is missing + */ +int fit_check_format(const void *fit, ulong size); int fit_conf_find_compat(const void *fit, const void *fdt); diff --git a/u-boot-2020.01/scripts/dtc/libfdt/fdt_ro.c b/u-boot-2020.01/scripts/dtc/libfdt/fdt_ro.c index e398815485..bc2fa431d0 100644 --- a/u-boot-2020.01/scripts/dtc/libfdt/fdt_ro.c +++ b/u-boot-2020.01/scripts/dtc/libfdt/fdt_ro.c @@ -865,6 +865,7 @@ int fdt_check_full(const void *fdt, size_t bufsize) unsigned depth = 0; const void *prop; const char *propname; + bool expect_end = false; if (bufsize < FDT_V1_SIZE) return -FDT_ERR_TRUNCATED; @@ -885,6 +886,10 @@ int fdt_check_full(const void *fdt, size_t bufsize) if (nextoffset < 0) return nextoffset; + /* If we see two root nodes, something is wrong */ + if (expect_end && tag != FDT_END) + return -FDT_ERR_BADLAYOUT; + switch (tag) { case FDT_NOP: break; @@ -898,12 +903,24 @@ int fdt_check_full(const void *fdt, size_t bufsize) depth++; if (depth > INT_MAX) return -FDT_ERR_BADSTRUCTURE; + + /* The root node must have an empty name */ + if (depth == 1) { + const char *name; + int len; + + name = fdt_get_name(fdt, offset, &len); + if (*name || len) + return -FDT_ERR_BADLAYOUT; + } break; case FDT_END_NODE: if (depth == 0) return -FDT_ERR_BADSTRUCTURE; depth--; + if (depth == 0) + expect_end = true; break; case FDT_PROP: diff --git a/u-boot-2020.01/test/py/tests/test_vboot.py b/u-boot-2020.01/test/py/tests/test_vboot.py index 150b98eef3..88595fb5be 100755 --- a/u-boot-2020.01/test/py/tests/test_vboot.py +++ b/u-boot-2020.01/test/py/tests/test_vboot.py @@ -24,17 +24,24 @@ For configuration verification: Tests run with both SHA1 and SHA256 hashing. """ +import shutil import struct import pytest import u_boot_utils as util import vboot_forge +import vboot_evil TESTDATA = [ - ['sha1', '', False], - ['sha1', '-pss', False], - ['sha256', '', False], - ['sha256', '-pss', False], - ['sha256', '-pss', True], + ['sha1', '', None, False, True], + ['sha1', '', '-E -p 0x10000', False, False], + ['sha1', '-pss', None, False, False], + ['sha1', '-pss', '-E -p 0x10000', False, False], + ['sha256', '', None, False, False], + ['sha256', '', '-E -p 0x10000', False, False], + ['sha256', '-pss', None, False, False], + ['sha256', '-pss', '-E -p 0x10000', False, False], + ['sha256', '-pss', None, True, False], + ['sha256', '-pss', '-E -p 0x10000', True, True], ] @pytest.mark.boardspec('sandbox') @@ -43,8 +50,10 @@ TESTDATA = [ @pytest.mark.requiredtool('fdtget') @pytest.mark.requiredtool('fdtput') @pytest.mark.requiredtool('openssl') -@pytest.mark.parametrize("sha_algo,padding,required", TESTDATA) -def test_vboot(u_boot_console, sha_algo, padding, required): +@pytest.mark.parametrize("sha_algo,padding,sign_options,required,full_test", + TESTDATA) +def test_vboot(u_boot_console, sha_algo, padding, sign_options, required, + full_test): """Test verified boot signing with mkimage and verification with 'bootm'. This works using sandbox only as it needs to update the device tree used @@ -66,7 +75,7 @@ def test_vboot(u_boot_console, sha_algo, padding, required): util.run_and_log(cons, 'dtc %s %s%s -O dtb ' '-o %s%s' % (dtc_args, datadir, dts, tmpdir, dtb)) - def run_bootm(sha_algo, test_type, expect_string, boots): + def run_bootm(sha_algo, test_type, expect_string, boots, fit=None): """Run a 'bootm' command U-Boot. This always starts a fresh U-Boot instance since the device tree may @@ -79,11 +88,14 @@ def test_vboot(u_boot_console, sha_algo, padding, required): use. boots: A boolean that is True if Linux should boot and False if we are expected to not boot + fit: FIT filename to load and verify """ + if not fit: + fit = '%stest.fit' % tmpdir cons.restart_uboot() with cons.log.section('Verified boot %s %s' % (sha_algo, test_type)): output = cons.run_command_list( - ['host load hostfs - 100 %stest.fit' % tmpdir, + ['host load hostfs - 100 %s' % fit, 'fdt addr 100', 'bootm 100']) assert expect_string in ''.join(output) @@ -311,8 +323,13 @@ def test_vboot(u_boot_console, sha_algo, padding, required): create_rsa_pair('prod') # Create a number kernel image with zeroes - with open('%stest-kernel.bin' % tmpdir, 'w') as fd: - fd.write(500 * chr(0)) + with open('%stest-kernel.bin' % tmpdir, 'wb') as fd: + fd.write(500 * b'\0') + + # Create a second kernel image with ones + evil_kernel = '%stest-kernel1.bin' % tmpdir + with open(evil_kernel, 'wb') as fd: + fd.write(500 * b'\x01') try: # We need to use our own device tree file. Remember to restore it diff --git a/u-boot-2020.01/test/py/tests/vboot_forge.py b/u-boot-2020.01/test/py/tests/vboot_forge.py index 0fb7ef4024..b41105bd0e 100644 --- a/u-boot-2020.01/test/py/tests/vboot_forge.py +++ b/u-boot-2020.01/test/py/tests/vboot_forge.py @@ -376,12 +376,12 @@ def manipulate(root, strblock): """ Maliciously manipulates the structure to create a crafted FIT file """ - # locate /images/kernel@1 (frankly, it just expects it to be the first one) + # locate /images/kernel-1 (frankly, it just expects it to be the first one) kernel_node = root[0][0] # clone it to save time filling all the properties fake_kernel = kernel_node.clone() # rename the node - fake_kernel.name = b'kernel@2' + fake_kernel.name = b'kernel-2' # get rid of signatures/hashes fake_kernel.children = [] # NOTE: this simply replaces the first prop... either description or data @@ -391,13 +391,13 @@ def manipulate(root, strblock): root[0].children.append(fake_kernel) # modify the default configuration - root[1].props[0].value = b'conf@2\x00' + root[1].props[0].value = b'conf-2\x00' # clone the first (only?) configuration fake_conf = root[1][0].clone() # rename and change kernel and fdt properties to select the crafted kernel - fake_conf.name = b'conf@2' - fake_conf.props[0].value = b'kernel@2\x00' - fake_conf.props[1].value = b'fdt@1\x00' + fake_conf.name = b'conf-2' + fake_conf.props[0].value = b'kernel-2\x00' + fake_conf.props[1].value = b'fdt-1\x00' # insert the new configuration under /configurations root[1].children.append(fake_conf) diff --git a/u-boot-2020.01/tools/fit_common.c b/u-boot-2020.01/tools/fit_common.c index cdf987d3c1..52b63296f8 100644 --- a/u-boot-2020.01/tools/fit_common.c +++ b/u-boot-2020.01/tools/fit_common.c @@ -26,7 +26,8 @@ int fit_verify_header(unsigned char *ptr, int image_size, struct image_tool_params *params) { - if (fdt_check_header(ptr) != EXIT_SUCCESS || !fit_check_format(ptr)) + if (fdt_check_header(ptr) != EXIT_SUCCESS || + fit_check_format(ptr, IMAGE_SIZE_INVAL)) return EXIT_FAILURE; return EXIT_SUCCESS; diff --git a/u-boot-2020.01/tools/fit_image.c b/u-boot-2020.01/tools/fit_image.c index e6a5ae4c73..999d72a0ad 100644 --- a/u-boot-2020.01/tools/fit_image.c +++ b/u-boot-2020.01/tools/fit_image.c @@ -850,7 +850,7 @@ static int fit_extract_contents(void *ptr, struct image_tool_params *params) /* Indent string is defined in header image.h */ p = IMAGE_INDENT_STRING; - if (!fit_check_format(fit)) { + if (fit_check_format(fit, IMAGE_SIZE_INVAL)) { printf("Bad FIT image format\n"); return -1; } -- Gitee