FIT verification can follow malformed metadata or external-data offsets beyond a buffer whose size is known to the caller.
Pass the known buffer size to fit_check_format() so FIT_FULL_CHECK validates the complete structure against the actual buffer. Reject external data in all subimages of known-size FITs before verification, even when verify is disabled. Keep these checks in the shared parser so filesystem and raw-partition scripts receive the same protection. Leave unknown-size FIT handling unchanged. Add C regression coverage with verification enabled and disabled, plus source coverage. Clear verify even when a test helper assertion fails. Signed-off-by: He Yong <[email protected]> --- Changes in v3: - Replace the legacy parser changes with shared known-size FIT validation. - Reject external data before verification and cover both verify settings. boot/image-board.c | 19 +++++++- test/boot/image.c | 118 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) diff --git a/boot/image-board.c b/boot/image-board.c index 7602f5bfaaa..15a79aa513e 100644 --- a/boot/image-board.c +++ b/boot/image-board.c @@ -1043,11 +1043,28 @@ int image_locate_script(void *buf, int size, const char *fit_uname, goto exit_image_format; } else { fit_hdr = buf; - if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { + if (fit_check_format(fit_hdr, + size ? size : IMAGE_SIZE_INVAL)) { puts("Bad FIT image format\n"); return 1; } + if (size) { + int images, node; + + /* Reject external data before any verification reads. */ + images = fdt_path_offset(fit_hdr, FIT_IMAGES_PATH); + fdt_for_each_subnode(node, fit_hdr, images) { + if (fdt_getprop(fit_hdr, node, + FIT_DATA_OFFSET_PROP, NULL) || + fdt_getprop(fit_hdr, node, + FIT_DATA_POSITION_PROP, NULL)) { + puts("External FIT script data is not supported\n"); + return 1; + } + } + } + if (!fit_uname) { /* If confname is empty, use the default */ if (confname && *confname) diff --git a/test/boot/image.c b/test/boot/image.c index 2c6d9dcbc22..17b1a4055da 100644 --- a/test/boot/image.c +++ b/test/boot/image.c @@ -6,7 +6,11 @@ * Written by Simon Glass <[email protected]> */ +#include <command.h> +#include <env.h> #include <image.h> +#include <mapmem.h> +#include <u-boot/crc.h> #include <test/ut.h> #include <linux/libfdt.h> #include "bootstd_common.h" @@ -100,3 +104,117 @@ static int test_image_phase(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(test_image_phase, 0); + +/* Known-size FITs must be structurally valid and contain all their data. */ +static int check_fit_script_bounds(struct unit_test_state *uts) +{ + static const char script[] = "true"; + static const char * const external_props[] = { + FIT_DATA_OFFSET_PROP, FIT_DATA_POSITION_PROP, + }; + char fit[1024] __aligned(8), bad[1024] __aligned(8); + const void *expected; + char *data; + uint len; + int images, node, confs, conf, hash, size, i; + + ut_assertok(fdt_create_empty_tree(fit, sizeof(fit))); + ut_assertok(fdt_setprop_string(fit, 0, FIT_DESC_PROP, "Script test")); + ut_assertok(fdt_setprop_u32(fit, 0, FIT_TIMESTAMP_PROP, 0)); + images = fdt_add_subnode(fit, 0, "images"); + ut_assert(images >= 0); + ut_assertok(fdt_setprop_string(fit, images, FIT_DEFAULT_PROP, "script")); + node = fdt_add_subnode(fit, images, "script"); + ut_assert(node >= 0); + ut_assertok(fdt_setprop_string(fit, node, FIT_TYPE_PROP, "script")); + ut_assertok(fdt_setprop(fit, node, FIT_DATA_PROP, script, sizeof(script))); + hash = fdt_add_subnode(fit, node, "hash"); + ut_assert(hash >= 0); + ut_assertok(fdt_setprop_string(fit, hash, FIT_ALGO_PROP, "crc32")); + ut_assertok(fdt_setprop_u32(fit, hash, FIT_VALUE_PROP, + crc32(0, (const u8 *)script, sizeof(script)))); + confs = fdt_add_subnode(fit, 0, "configurations"); + ut_assert(confs >= 0); + ut_assertok(fdt_setprop_string(fit, confs, FIT_DEFAULT_PROP, "conf")); + conf = fdt_add_subnode(fit, confs, "conf"); + ut_assert(conf >= 0); + ut_assertok(fdt_setprop_string(fit, conf, FIT_SCRIPT_PROP, "script")); + ut_assertok(fdt_pack(fit)); + size = fdt_totalsize(fit); + node = fdt_path_offset(fit, "/images/script"); + ut_assert(node >= 0); + expected = fdt_getprop(fit, node, FIT_DATA_PROP, NULL); + ut_assertnonnull(expected); + + /* Exercise configuration lookup, direct image lookup and source. */ + ut_assertok(image_locate_script(fit, size, NULL, NULL, &data, &len)); + ut_asserteq(sizeof(script), len); + ut_asserteq_ptr(expected, data); + ut_assertok(image_locate_script(fit, size, "script", NULL, &data, &len)); + ut_assertok(cmd_source_script(map_to_sysmem(fit), NULL, NULL)); + + /* Structural validation follows fit_check_format() configuration. */ + if (CONFIG_IS_ENABLED(FIT_FULL_CHECK)) { + ut_asserteq(1, image_locate_script(fit, sizeof(struct fdt_header) - 1, + NULL, NULL, &data, &len)); + ut_asserteq(1, image_locate_script(fit, sizeof(struct fdt_header), + NULL, NULL, &data, &len)); + ut_asserteq(1, image_locate_script(fit, size - 1, NULL, NULL, + &data, &len)); + + memcpy(bad, fit, size); + fdt_set_totalsize(bad, sizeof(bad) + 1); + ut_asserteq(1, image_locate_script(bad, sizeof(bad), NULL, NULL, + &data, &len)); + + /* A valid header does not imply a valid structure block. */ + memcpy(bad, fit, size); + *(fdt32_t *)(bad + fdt_off_dt_struct(bad)) = cpu_to_fdt32(0xffffffff); + ut_assertok(fdt_check_header(bad)); + ut_asserteq(1, image_locate_script(bad, size, NULL, NULL, &data, &len)); + } + + for (i = 0; i < ARRAY_SIZE(external_props); i++) { + ut_assertok(fdt_open_into(fit, bad, sizeof(bad))); + node = fdt_path_offset(bad, "/images/script"); + ut_assert(node >= 0); + ut_assertok(fdt_delprop(bad, node, FIT_DATA_PROP)); + ut_assertok(fdt_setprop_u32(bad, node, external_props[i], + 0xfffffffc)); + ut_assertok(fdt_setprop_u32(bad, node, FIT_DATA_SIZE_PROP, + sizeof(script))); + ut_asserteq(1, image_locate_script(bad, sizeof(bad), NULL, + NULL, &data, &len)); + + /* Reject external data even in an unselected image. */ + ut_assertok(fdt_open_into(fit, bad, sizeof(bad))); + images = fdt_path_offset(bad, FIT_IMAGES_PATH); + ut_assert(images >= 0); + node = fdt_add_subnode(bad, images, "external"); + ut_assert(node >= 0); + ut_assertok(fdt_setprop_u32(bad, node, external_props[i], + 0xfffffffc)); + ut_asserteq(1, image_locate_script(bad, sizeof(bad), NULL, + NULL, &data, &len)); + } + + return 0; +} + +static int image_fit_script_bounds(struct unit_test_state *uts) +{ + int ret, verify; + + if (!IS_ENABLED(CONFIG_FIT)) + return -EAGAIN; + + for (verify = 0; verify < 2; verify++) { + ut_assertok(env_set("verify", verify ? "yes" : "no")); + ret = check_fit_script_bounds(uts); + ut_assertok(env_set("verify", NULL)); + ut_assertok(ret); + } + + return 0; +} +BOOTSTD_TEST(image_fit_script_bounds, 0); -- 2.43.0
