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

Reply via email to