diff options
author | Tom Rini <trini@konsulko.com> | 2021-02-15 19:19:56 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2021-02-15 22:31:54 -0500 |
commit | b6f4c757959f8850e1299a77c8e5713da78e8ec0 (patch) | |
tree | 2de8580b23f833e100a186448625721d71625521 /common/image-fit.c | |
parent | 6144438fb5c9059dc87cf219bed0c992f70b3509 (diff) | |
parent | 3f04db891a353f4b127ed57279279f851c6b4917 (diff) |
Merge branch '2021-02-15-fix-CVE-2021-27097-CVE-2021-27138'
Fix CVE-2021-27097 and CVE-2021-27138. For more details see
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-27097 and
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-27138
Diffstat (limited to 'common/image-fit.c')
-rw-r--r-- | common/image-fit.c | 126 |
1 files changed, 97 insertions, 29 deletions
diff --git a/common/image-fit.c b/common/image-fit.c index adc3e551de9..28b3d2b1911 100644 --- a/common/image-fit.c +++ b/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 <time.h> @@ -1369,21 +1371,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; } /** @@ -1557,48 +1569,101 @@ int fit_image_check_comp(const void *fit, int noffset, uint8_t comp) } /** - * fit_check_format - sanity check FIT image format - * @fit: pointer to the FIT format image header + * fdt_check_no_at() - Check for nodes whose names contain '@' * - * fit_check_format() runs a basic sanity FIT image verification. - * Routine checks for mandatory properties, nodes, etc. + * This checks the parent node and all subnodes recursively * - * returns: - * 1, on success - * 0, on failure + * @fit: FIT to check + * @parent: Parent node to check + * @return 0 if OK, -EADDRNOTAVAIL is a node has a name containing '@' */ -int fit_check_format(const void *fit) +static int fdt_check_no_at(const void *fit, int parent) { + const char *name; + int node; + int ret; + + name = fdt_get_name(fit, parent, NULL); + if (!name || strchr(name, '@')) + return -EADDRNOTAVAIL; + + fdt_for_each_subnode(node, fit, parent) { + ret = fdt_check_no_at(fit, node); + if (ret) + return ret; + } + + return 0; +} + +int fit_check_format(const void *fit, ulong size) +{ + int ret; + /* A FIT image must be a valid FDT */ - if (fdt_check_header(fit)) { - debug("Wrong FIT format: not a flattened device tree\n"); - return 0; + ret = fdt_check_header(fit); + if (ret) { + log_debug("Wrong FIT format: not a flattened device tree (err=%d)\n", + ret); + return -ENOEXEC; + } + + if (CONFIG_IS_ENABLED(FIT_FULL_CHECK)) { + /* + * If we are not given the size, make do wtih calculating it. + * This is not as secure, so we should consider a flag to + * control this. + */ + if (size == IMAGE_SIZE_INVAL) + size = fdt_totalsize(fit); + ret = fdt_check_full(fit, size); + if (ret) + ret = -EINVAL; + + /* + * U-Boot stopped using unit addressed in 2017. Since libfdt + * can match nodes ignoring any unit address, signature + * verification can see the wrong node if one is inserted with + * the same name as a valid node but with a unit address + * attached. Protect against this by disallowing unit addresses. + */ + if (!ret && CONFIG_IS_ENABLED(FIT_SIGNATURE)) { + ret = fdt_check_no_at(fit, 0); + + if (ret) { + log_debug("FIT check error %d\n", ret); + return ret; + } + } + if (ret) { + log_debug("FIT check error %d\n", ret); + return ret; + } } /* mandatory / node 'description' property */ - if (fdt_getprop(fit, 0, FIT_DESC_PROP, NULL) == NULL) { - debug("Wrong FIT format: no description\n"); - return 0; + if (!fdt_getprop(fit, 0, FIT_DESC_PROP, NULL)) { + log_debug("Wrong FIT format: no description\n"); + return -ENOMSG; } if (IMAGE_ENABLE_TIMESTAMP) { /* mandatory / node 'timestamp' property */ - if (fdt_getprop(fit, 0, FIT_TIMESTAMP_PROP, NULL) == NULL) { - debug("Wrong FIT format: no timestamp\n"); - return 0; + if (!fdt_getprop(fit, 0, FIT_TIMESTAMP_PROP, NULL)) { + log_debug("Wrong FIT format: no timestamp\n"); + 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; + log_debug("Wrong FIT format: no images parent node\n"); + return -ENOENT; } - return 1; + return 0; } - /** * fit_conf_find_compat * @fit: pointer to the FIT format image header @@ -1935,10 +2000,13 @@ 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); - if (!fit_check_format(fit)) { - printf("Bad FIT %s image format!\n", prop_name); + 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) + printf("Signature checking prevents use of unit addresses (@) in nodes\n"); bootstage_error(bootstage_id + BOOTSTAGE_SUB_FORMAT); - return -ENOEXEC; + return ret; } bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT_OK); if (fit_uname) { |