From 33132ec14676c62167d86cb1efff7c1f5ded107f Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Sun, 21 Mar 2021 22:53:55 -0400 Subject: u-boot: Fix CVE-2021-27097, CVE-2021-27138 Backport fixes for CVE-2021-27097 and CVE-2021-27138 as well as a precursor fdt validation fix that allows using the upstream patches for the CVEs without significant rebasing. Note that the additional upstream changes to add new U-Boot fit image tests have been left out to keep the patch count down. Those tests are currently not used for ptest or oe-selftest, so it is believed their absence should not be problematic. (From OE-Core rev: b6c2df341d7e6da5defca9a5567fdb7212489efa) Signed-off-by: Scott Murray Signed-off-by: Richard Purdie --- .../u-boot/files/CVE-2021-27138-1.patch | 245 +++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 meta/recipes-bsp/u-boot/files/CVE-2021-27138-1.patch (limited to 'meta/recipes-bsp/u-boot/files/CVE-2021-27138-1.patch') diff --git a/meta/recipes-bsp/u-boot/files/CVE-2021-27138-1.patch b/meta/recipes-bsp/u-boot/files/CVE-2021-27138-1.patch new file mode 100644 index 0000000000..562f8151bb --- /dev/null +++ b/meta/recipes-bsp/u-boot/files/CVE-2021-27138-1.patch @@ -0,0 +1,245 @@ +From 79af75f7776fc20b0d7eb6afe1e27c00fdb4b9b4 Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Mon, 15 Feb 2021 17:08:06 -0700 +Subject: [PATCH] fit: Don't allow verification of images with @ nodes + +When searching for a node called 'fred', any unit address appended to the +name is ignored by libfdt, meaning that 'fred' can match 'fred@1'. This +means that we cannot be sure that the node originally intended is the one +that is used. + +Disallow use of nodes with unit addresses. + +Update the forge test also, since it uses @ addresses. + +CVE-2021-27138 + +Signed-off-by: Simon Glass +Reported-by: Bruce Monroe +Reported-by: Arie Haenel +Reported-by: Julien Lenoir + +CVE: CVE-2021-27138 +Upstream-Status: Backport[https://github.com/u-boot/u-boot/commit/79af75f7776fc20b0d7eb6afe1e27c00fdb4b9b4] +Signed-off-by: Scott Murray + +--- + common/image-fit-sig.c | 22 ++++++++++++++++++++-- + common/image-fit.c | 20 +++++++++++++++----- + test/py/tests/test_fit.py | 24 ++++++++++++------------ + test/py/tests/vboot_forge.py | 12 ++++++------ + 4 files changed, 53 insertions(+), 25 deletions(-) + +diff --git a/common/image-fit-sig.c b/common/image-fit-sig.c +index 897e04c7a3..34ebb8edfe 100644 +--- a/common/image-fit-sig.c ++++ b/common/image-fit-sig.c +@@ -149,6 +149,14 @@ static int fit_image_verify_sig(const void *fit, int image_noffset, + fdt_for_each_subnode(noffset, fit, image_noffset) { + const char *name = fit_get_name(fit, noffset, NULL); + ++ /* ++ * We don't support this since libfdt considers names with the ++ * name root but different @ suffix to be equal ++ */ ++ if (strchr(name, '@')) { ++ err_msg = "Node name contains @"; ++ goto error; ++ } + if (!strncmp(name, FIT_SIG_NODENAME, + strlen(FIT_SIG_NODENAME))) { + ret = fit_image_check_sig(fit, noffset, data, +@@ -398,9 +406,10 @@ error: + return -EPERM; + } + +-int fit_config_verify_required_sigs(const void *fit, int conf_noffset, +- const void *sig_blob) ++static int fit_config_verify_required_sigs(const void *fit, int conf_noffset, ++ const void *sig_blob) + { ++ const char *name = fit_get_name(fit, conf_noffset, NULL); + int noffset; + int sig_node; + int verified = 0; +@@ -408,6 +417,15 @@ int fit_config_verify_required_sigs(const void *fit, int conf_noffset, + bool reqd_policy_all = true; + const char *reqd_mode; + ++ /* ++ * We don't support this since libfdt considers names with the ++ * name root but different @ suffix to be equal ++ */ ++ if (strchr(name, '@')) { ++ printf("Configuration node '%s' contains '@'\n", name); ++ return -EPERM; ++ } ++ + /* Work out what we need to verify */ + sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME); + if (sig_node < 0) { +diff --git a/common/image-fit.c b/common/image-fit.c +index adc3e551de..c3dc814115 100644 +--- a/common/image-fit.c ++++ b/common/image-fit.c +@@ -1369,21 +1369,31 @@ error: + */ + int fit_image_verify(const void *fit, int image_noffset) + { ++ const char *name = fit_get_name(fit, image_noffset, NULL); + const void *data; + size_t size; +- int noffset = 0; + char *err_msg = ""; + ++ if (strchr(name, '@')) { ++ /* ++ * We don't support this since libfdt considers names with the ++ * name root but different @ suffix to be equal ++ */ ++ err_msg = "Node name contains @"; ++ goto err; ++ } + /* Get image data and data length */ + if (fit_image_get_data_and_size(fit, image_noffset, &data, &size)) { + err_msg = "Can't get image data/size"; +- printf("error!\n%s for '%s' hash node in '%s' image node\n", +- err_msg, fit_get_name(fit, noffset, NULL), +- fit_get_name(fit, image_noffset, NULL)); +- return 0; ++ goto err; + } + + return fit_image_verify_with_data(fit, image_noffset, data, size); ++ ++err: ++ printf("error!\n%s in '%s' image node\n", err_msg, ++ fit_get_name(fit, image_noffset, NULL)); ++ return 0; + } + + /** +diff --git a/test/py/tests/test_fit.py b/test/py/tests/test_fit.py +index 84b3f95850..6d5b43c3ba 100755 +--- a/test/py/tests/test_fit.py ++++ b/test/py/tests/test_fit.py +@@ -17,7 +17,7 @@ base_its = ''' + #address-cells = <1>; + + images { +- kernel@1 { ++ kernel-1 { + data = /incbin/("%(kernel)s"); + type = "kernel"; + arch = "sandbox"; +@@ -26,7 +26,7 @@ base_its = ''' + load = <0x40000>; + entry = <0x8>; + }; +- kernel@2 { ++ kernel-2 { + data = /incbin/("%(loadables1)s"); + type = "kernel"; + arch = "sandbox"; +@@ -35,19 +35,19 @@ base_its = ''' + %(loadables1_load)s + entry = <0x0>; + }; +- fdt@1 { ++ fdt-1 { + description = "snow"; + data = /incbin/("%(fdt)s"); + type = "flat_dt"; + arch = "sandbox"; + %(fdt_load)s + compression = "%(compression)s"; +- signature@1 { ++ signature-1 { + algo = "sha1,rsa2048"; + key-name-hint = "dev"; + }; + }; +- ramdisk@1 { ++ ramdisk-1 { + description = "snow"; + data = /incbin/("%(ramdisk)s"); + type = "ramdisk"; +@@ -56,7 +56,7 @@ base_its = ''' + %(ramdisk_load)s + compression = "%(compression)s"; + }; +- ramdisk@2 { ++ ramdisk-2 { + description = "snow"; + data = /incbin/("%(loadables2)s"); + type = "ramdisk"; +@@ -67,10 +67,10 @@ base_its = ''' + }; + }; + configurations { +- default = "conf@1"; +- conf@1 { +- kernel = "kernel@1"; +- fdt = "fdt@1"; ++ default = "conf-1"; ++ conf-1 { ++ kernel = "kernel-1"; ++ fdt = "fdt-1"; + %(ramdisk_config)s + %(loadables_config)s + }; +@@ -410,7 +410,7 @@ def test_fit(u_boot_console): + + # Try a ramdisk + with cons.log.section('Kernel + FDT + Ramdisk load'): +- params['ramdisk_config'] = 'ramdisk = "ramdisk@1";' ++ params['ramdisk_config'] = 'ramdisk = "ramdisk-1";' + params['ramdisk_load'] = 'load = <%#x>;' % params['ramdisk_addr'] + fit = make_fit(mkimage, params) + cons.restart_uboot() +@@ -419,7 +419,7 @@ def test_fit(u_boot_console): + + # Configuration with some Loadables + with cons.log.section('Kernel + FDT + Ramdisk load + Loadables'): +- params['loadables_config'] = 'loadables = "kernel@2", "ramdisk@2";' ++ params['loadables_config'] = 'loadables = "kernel-2", "ramdisk-2";' + params['loadables1_load'] = ('load = <%#x>;' % + params['loadables1_addr']) + params['loadables2_load'] = ('load = <%#x>;' % +diff --git a/test/py/tests/vboot_forge.py b/test/py/tests/vboot_forge.py +index 0fb7ef4024..b41105bd0e 100644 +--- a/test/py/tests/vboot_forge.py ++++ b/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) + -- cgit v1.2.3-54-g00ecf