Version in base suite: 2025.01-3 Base version: u-boot_2025.01-3 Target version: u-boot_2025.01-3+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/u/u-boot/u-boot_2025.01-3.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/u/u-boot/u-boot_2025.01-3+deb13u1.dsc changelog | 10 + patches/CVE-2024-42040.patch | 48 +++++ patches/CVE-2026-46728-1.patch | 51 +++++ patches/CVE-2026-46728-2.patch | 369 +++++++++++++++++++++++++++++++++++++++++ patches/CVE-2026-46728-3.patch | 134 ++++++++++++++ patches/series | 10 - 6 files changed, 616 insertions(+), 6 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp1tam8qjr/u-boot_2025.01-3.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp1tam8qjr/u-boot_2025.01-3+deb13u1.dsc: no acceptable signature found diff -Nru u-boot-2025.01/debian/changelog u-boot-2025.01/debian/changelog --- u-boot-2025.01/debian/changelog 2025-04-08 23:07:41.000000000 +0000 +++ u-boot-2025.01/debian/changelog 2026-06-24 09:07:15.000000000 +0000 @@ -1,3 +1,13 @@ +u-boot (2025.01-3+deb13u1) trixie; urgency=medium + + * Non-maintainer upload by the LTS Team. + * CVE-2024-42040: buffer overread vulnerability in the DHCP implementation. + (Closes: #1081557) + * CVE-2026-46728: mishandles use of unit addresses in a FIT. + (Closes: #1136954) + + -- Andreas Henriksson Wed, 24 Jun 2026 11:07:15 +0200 + u-boot (2025.01-3) unstable; urgency=medium [ Marek Vasut ] diff -Nru u-boot-2025.01/debian/patches/CVE-2024-42040.patch u-boot-2025.01/debian/patches/CVE-2024-42040.patch --- u-boot-2025.01/debian/patches/CVE-2024-42040.patch 1970-01-01 00:00:00.000000000 +0000 +++ u-boot-2025.01/debian/patches/CVE-2024-42040.patch 2026-06-24 09:05:18.000000000 +0000 @@ -0,0 +1,48 @@ +From: Paul HENRYS +Date: Thu, 9 Oct 2025 17:43:28 +0200 +Subject: net: bootp: Prevent buffer overflow to avoid leaking the RAM content + +CVE-2024-42040 describes a possible buffer overflow when calling +bootp_process_vendor() in bootp_handler() since the total length +of the packet is passed to bootp_process_vendor() without being +reduced to len-(offsetof(struct bootp_hdr,bp_vend)+4). + +The packet length is also checked against its minimum size to avoid +reading data from struct bootp_hdr outside of the packet length. + +Signed-off-by: Paul HENRYS +Signed-off-by: Philippe Reynes +(cherry picked from commit 81e5708cc2c865df606e49aed5415adb2a662171) +--- + net/bootp.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/net/bootp.c b/net/bootp.c +index afd5b48..14be99e 100644 +--- a/net/bootp.c ++++ b/net/bootp.c +@@ -361,6 +361,14 @@ static void bootp_handler(uchar *pkt, unsigned dest, struct in_addr sip, + debug("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%zu)\n", + src, dest, len, sizeof(struct bootp_hdr)); + ++ /* Check the minimum size of a BOOTP packet is respected. ++ * A BOOTP packet is between 300 bytes and 576 bytes big ++ */ ++ if (len < offsetof(struct bootp_hdr, bp_vend) + 64) { ++ printf("Error: got an invalid BOOTP packet (len=%u)\n", len); ++ return; ++ } ++ + bp = (struct bootp_hdr *)pkt; + + /* Filter out pkts we don't want */ +@@ -378,7 +386,8 @@ static void bootp_handler(uchar *pkt, unsigned dest, struct in_addr sip, + + /* Retrieve extended information (we must parse the vendor area) */ + if (net_read_u32((u32 *)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC)) +- bootp_process_vendor((uchar *)&bp->bp_vend[4], len); ++ bootp_process_vendor((uchar *)&bp->bp_vend[4], len - ++ (offsetof(struct bootp_hdr, bp_vend) + 4)); + + net_set_timeout_handler(0, (thand_f *)0); + bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP, "bootp_stop"); diff -Nru u-boot-2025.01/debian/patches/CVE-2026-46728-1.patch u-boot-2025.01/debian/patches/CVE-2026-46728-1.patch --- u-boot-2025.01/debian/patches/CVE-2026-46728-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ u-boot-2025.01/debian/patches/CVE-2026-46728-1.patch 2026-06-24 09:05:18.000000000 +0000 @@ -0,0 +1,51 @@ +From: Quentin Schulz +Date: Wed, 3 Dec 2025 17:19:34 +0100 +Subject: boot/fit: declare (and use) new constant for conf's compatible prop + +Fit conf node may have a compatible property[1] which stores the root +compatible of the first blob in the fdt property of the node. This can +be used to automatically select the proper conf node based on the +compatible from the running U-Boot (matching the former's compatible +with the latter)[2]. + +This adds (and uses) this constant for FIT node parsing. + +Note that this property may also appear in fpga image nodes[3] but that +isn't done in this commit. + +[1] https://fitspec.osfw.foundation/#optional-properties compatible paragraph +[2] https://fitspec.osfw.foundation/#select-a-configuration-to-boot +[3] https://fitspec.osfw.foundation/#images-node 2.3.2 Conditionally mandatory property + +Signed-off-by: Quentin Schulz +(cherry picked from commit 3059eb0c27dd1b4a40a06bda4a47e10246185aca) +--- + boot/image-fit.c | 2 +- + include/image.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/boot/image-fit.c b/boot/image-fit.c +index 7d56f0b..af98ccd 100644 +--- a/boot/image-fit.c ++++ b/boot/image-fit.c +@@ -1756,7 +1756,7 @@ int fit_conf_find_compat(const void *fit, const void *fdt) + continue; + + /* If there's a compat property in the config node, use that. */ +- if (fdt_getprop(fit, noffset, "compatible", NULL)) { ++ if (fdt_getprop(fit, noffset, FIT_COMPAT_PROP, NULL)) { + fdt = fit; /* search in FIT image */ + compat_noffset = noffset; /* search under config node */ + } else { /* Otherwise extract it from the kernel FDT. */ +diff --git a/include/image.h b/include/image.h +index c52fced..52b26ed 100644 +--- a/include/image.h ++++ b/include/image.h +@@ -1102,6 +1102,7 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size, + #define FIT_STANDALONE_PROP "standalone" + #define FIT_SCRIPT_PROP "script" + #define FIT_PHASE_PROP "phase" ++#define FIT_COMPAT_PROP "compatible" + + #define FIT_MAX_HASH_LEN HASH_MAX_DIGEST_SIZE + diff -Nru u-boot-2025.01/debian/patches/CVE-2026-46728-2.patch u-boot-2025.01/debian/patches/CVE-2026-46728-2.patch --- u-boot-2025.01/debian/patches/CVE-2026-46728-2.patch 1970-01-01 00:00:00.000000000 +0000 +++ u-boot-2025.01/debian/patches/CVE-2026-46728-2.patch 2026-06-24 09:05:18.000000000 +0000 @@ -0,0 +1,369 @@ +From: Simon Glass +Date: Thu, 5 Mar 2026 18:20:09 -0700 +Subject: boot: Add fit_config_get_hash_list() to build signed node list + +The hashed-nodes property in a FIT signature node lists which FDT paths +are included in the signature hash. It is intended as a hint so should +not be used for verification. + +Add a function to build the node list from scratch by iterating the +configuration's image references. Skip properties known not to be image +references. For each image, collect the path plus all hash and cipher +subnodes. + +Use the new function in fit_config_check_sig() instead of reading +'hashed-nodes'. + +Update the test_vboot kernel@ test case: fit_check_sign now catches the +attack at signature-verification time (the @-suffixed node is hashed +instead of the real one, causing a mismatch) rather than at +fit_check_format() time. + +Update the docs to cover this. The FIT spec can be updated separately. + +Signed-off-by: Simon Glass +Closes: https://lore.kernel.org/u-boot/20260302220937.3682128-1-trini@konsulko.com/ +Reported-by: Apple Security Engineering and Architecture (SEAR) +Tested-by: Tom Rini +(cherry picked from commit 2092322b31cc8b1f8c9e2e238d1043ae0637b241) +--- + boot/image-fit-sig.c | 227 +++++++++++++++++++++++++++++++++++--------- + doc/usage/fit/signature.rst | 19 ++-- + test/py/tests/test_vboot.py | 10 +- + 3 files changed, 202 insertions(+), 54 deletions(-) + +diff --git a/boot/image-fit-sig.c b/boot/image-fit-sig.c +index a121de6..62a016a 100644 +--- a/boot/image-fit-sig.c ++++ b/boot/image-fit-sig.c +@@ -18,6 +18,7 @@ DECLARE_GLOBAL_DATA_PTR; + #include + + #define IMAGE_MAX_HASHED_NODES 100 ++#define FIT_MAX_HASH_PATH_BUF 4096 + + /** + * fit_region_make_list() - Make a list of image regions +@@ -224,6 +225,179 @@ int fit_image_verify_required_sigs(const void *fit, int image_noffset, + return 0; + } + ++/** ++ * fit_config_add_hash() - Add hash nodes for one image to the node list ++ * ++ * Adds the image path, all its hash-* subnode paths, and its cipher ++ * subnode path (if present) to the packed buffer. ++ * ++ * @fit: FIT blob ++ * @image_noffset: Image node offset (e.g. /images/kernel-1) ++ * @node_inc: Array of path pointers to fill ++ * @count: Pointer to current count (updated on return) ++ * @max_nodes: Maximum entries in @node_inc ++ * @buf: Buffer for packed path strings ++ * @buf_used: Pointer to bytes used in @buf (updated on return) ++ * @buf_len: Total size of @buf ++ * Return: 0 on success, -ve on error ++ */ ++static int fit_config_add_hash(const void *fit, int image_noffset, ++ char **node_inc, int *count, int max_nodes, ++ char *buf, int *buf_used, int buf_len) ++{ ++ int noffset, hash_count, ret, len; ++ ++ if (*count >= max_nodes) ++ return -ENOSPC; ++ ++ ret = fdt_get_path(fit, image_noffset, buf + *buf_used, ++ buf_len - *buf_used); ++ if (ret < 0) ++ return -ENOENT; ++ len = strlen(buf + *buf_used) + 1; ++ node_inc[(*count)++] = buf + *buf_used; ++ *buf_used += len; ++ ++ /* Add all this image's hash subnodes */ ++ hash_count = 0; ++ for (noffset = fdt_first_subnode(fit, image_noffset); ++ noffset >= 0; ++ noffset = fdt_next_subnode(fit, noffset)) { ++ const char *name = fit_get_name(fit, noffset, NULL); ++ ++ if (strncmp(name, FIT_HASH_NODENAME, ++ strlen(FIT_HASH_NODENAME))) ++ continue; ++ if (*count >= max_nodes) ++ return -ENOSPC; ++ ret = fdt_get_path(fit, noffset, buf + *buf_used, ++ buf_len - *buf_used); ++ if (ret < 0) ++ return -ENOENT; ++ len = strlen(buf + *buf_used) + 1; ++ node_inc[(*count)++] = buf + *buf_used; ++ *buf_used += len; ++ hash_count++; ++ } ++ ++ if (!hash_count) { ++ printf("No hash nodes in image '%s'\n", ++ fdt_get_name(fit, image_noffset, NULL)); ++ return -ENOMSG; ++ } ++ ++ /* Add this image's cipher node if present */ ++ noffset = fdt_subnode_offset(fit, image_noffset, FIT_CIPHER_NODENAME); ++ if (noffset != -FDT_ERR_NOTFOUND) { ++ if (noffset < 0) ++ return -EIO; ++ if (*count >= max_nodes) ++ return -ENOSPC; ++ ret = fdt_get_path(fit, noffset, buf + *buf_used, ++ buf_len - *buf_used); ++ if (ret < 0) ++ return -ENOENT; ++ len = strlen(buf + *buf_used) + 1; ++ node_inc[(*count)++] = buf + *buf_used; ++ *buf_used += len; ++ } ++ ++ return 0; ++} ++ ++/** ++ * fit_config_get_hash_list() - Build the list of nodes to hash ++ * ++ * Works through every image referenced by the configuration and collects the ++ * node paths: root + config + all referenced images with their hash and ++ * cipher subnodes. ++ * ++ * Properties known not to be image references (description, compatible, ++ * default, load-only) are skipped, so any new image type is covered by default. ++ * ++ * @fit: FIT blob ++ * @conf_noffset: Configuration node offset ++ * @node_inc: Array to fill with path string pointers ++ * @max_nodes: Size of @node_inc array ++ * @buf: Buffer for packed null-terminated path strings ++ * @buf_len: Size of @buf ++ * Return: number of entries in @node_inc, or -ve on error ++ */ ++static int fit_config_get_hash_list(const void *fit, int conf_noffset, ++ char **node_inc, int max_nodes, ++ char *buf, int buf_len) ++{ ++ const char *conf_name; ++ int image_count; ++ int prop_offset; ++ int used = 0; ++ int count = 0; ++ int ret, len; ++ ++ conf_name = fit_get_name(fit, conf_noffset, NULL); ++ ++ /* Always include the root node and the configuration node */ ++ if (max_nodes < 2) ++ return -ENOSPC; ++ ++ len = 2; /* "/" + nul */ ++ if (len > buf_len) ++ return -ENOSPC; ++ strcpy(buf, "/"); ++ node_inc[count++] = buf; ++ used += len; ++ ++ len = snprintf(buf + used, buf_len - used, "%s/%s", FIT_CONFS_PATH, ++ conf_name) + 1; ++ if (used + len > buf_len) ++ return -ENOSPC; ++ node_inc[count++] = buf + used; ++ used += len; ++ ++ /* Process each image referenced by the config */ ++ image_count = 0; ++ fdt_for_each_property_offset(prop_offset, fit, conf_noffset) { ++ const char *prop_name; ++ int img_count, i; ++ ++ fdt_getprop_by_offset(fit, prop_offset, &prop_name, NULL); ++ if (!prop_name) ++ continue; ++ ++ /* Skip properties that are not image references */ ++ if (!strcmp(prop_name, FIT_DESC_PROP) || ++ !strcmp(prop_name, FIT_COMPAT_PROP) || ++ !strcmp(prop_name, FIT_DEFAULT_PROP)) ++ continue; ++ ++ img_count = fdt_stringlist_count(fit, conf_noffset, prop_name); ++ for (i = 0; i < img_count; i++) { ++ int noffset; ++ ++ noffset = fit_conf_get_prop_node_index(fit, ++ conf_noffset, ++ prop_name, i); ++ if (noffset < 0) ++ continue; ++ ++ ret = fit_config_add_hash(fit, noffset, node_inc, ++ &count, max_nodes, buf, &used, ++ buf_len); ++ if (ret < 0) ++ return ret; ++ ++ image_count++; ++ } ++ } ++ ++ if (!image_count) { ++ printf("No images in config '%s'\n", conf_name); ++ return -ENOMSG; ++ } ++ ++ return count; ++} ++ + /** + * fit_config_check_sig() - Check the signature of a config + * +@@ -264,20 +438,16 @@ static int fit_config_check_sig(const void *fit, int noffset, int conf_noffset, + FIT_DATA_POSITION_PROP, + FIT_DATA_OFFSET_PROP, + }; +- +- const char *prop, *end, *name; ++ char *node_inc[IMAGE_MAX_HASHED_NODES]; ++ char hash_buf[FIT_MAX_HASH_PATH_BUF]; + struct image_sign_info info; + const uint32_t *strings; +- const char *config_name; + uint8_t *fit_value; + int fit_value_len; +- bool found_config; + int max_regions; +- int i, prop_len; + char path[200]; + int count; + +- config_name = fit_get_name(fit, conf_noffset, NULL); + debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, key_blob, + fit_get_name(fit, noffset, NULL), + fit_get_name(key_blob, required_keynode, NULL)); +@@ -292,45 +462,12 @@ static int fit_config_check_sig(const void *fit, int noffset, int conf_noffset, + return -1; + } + +- /* Count the number of strings in the property */ +- prop = fdt_getprop(fit, noffset, "hashed-nodes", &prop_len); +- end = prop ? prop + prop_len : prop; +- for (name = prop, count = 0; name < end; name++) +- if (!*name) +- count++; +- if (!count) { +- *err_msgp = "Can't get hashed-nodes property"; +- return -1; +- } +- +- if (prop && prop_len > 0 && prop[prop_len - 1] != '\0') { +- *err_msgp = "hashed-nodes property must be null-terminated"; +- return -1; +- } +- +- /* Add a sanity check here since we are using the stack */ +- if (count > IMAGE_MAX_HASHED_NODES) { +- *err_msgp = "Number of hashed nodes exceeds maximum"; +- return -1; +- } +- +- /* Create a list of node names from those strings */ +- char *node_inc[count]; +- +- debug("Hash nodes (%d):\n", count); +- found_config = false; +- for (name = prop, i = 0; name < end; name += strlen(name) + 1, i++) { +- debug(" '%s'\n", name); +- node_inc[i] = (char *)name; +- if (!strncmp(FIT_CONFS_PATH, name, strlen(FIT_CONFS_PATH)) && +- name[sizeof(FIT_CONFS_PATH) - 1] == '/' && +- !strcmp(name + sizeof(FIT_CONFS_PATH), config_name)) { +- debug(" (found config node %s)", config_name); +- found_config = true; +- } +- } +- if (!found_config) { +- *err_msgp = "Selected config not in hashed nodes"; ++ /* Build the node list from the config, ignoring hashed-nodes */ ++ count = fit_config_get_hash_list(fit, conf_noffset, ++ node_inc, IMAGE_MAX_HASHED_NODES, ++ hash_buf, sizeof(hash_buf)); ++ if (count < 0) { ++ *err_msgp = "Failed to build hash node list"; + return -1; + } + +diff --git a/doc/usage/fit/signature.rst b/doc/usage/fit/signature.rst +index b868dcb..e8465d8 100644 +--- a/doc/usage/fit/signature.rst ++++ b/doc/usage/fit/signature.rst +@@ -353,20 +353,27 @@ meantime. + Details + ------- + The signature node contains a property ('hashed-nodes') which lists all the +-nodes that the signature was made over. The image is walked in order and each +-tag processed as follows: ++nodes that the signature was made over. The signer (mkimage) writes this ++property as a record of what was included in the hash. During verification, ++however, U-Boot does not read 'hashed-nodes'. Instead it rebuilds the node ++list from the configuration's own image references (kernel, fdt, ramdisk, ++etc.), since 'hashed-nodes' is not itself covered by the signature. The ++rebuilt list always includes the root node, the configuration node, each ++referenced image node and its hash/cipher subnodes. ++ ++The image is walked in order and each tag processed as follows: + + DTB_BEGIN_NODE + The tag and the following name are included in the signature +- if the node or its parent are present in 'hashed-nodes' ++ if the node or its parent are present in the node list + + DTB_END_NODE + The tag is included in the signature if the node or its parent +- are present in 'hashed-nodes' ++ are present in the node list + + DTB_PROPERTY + The tag, the length word, the offset in the string table, and +- the data are all included if the current node is present in 'hashed-nodes' ++ the data are all included if the current node is present in the node list + and the property name is not 'data'. + + DTB_END +@@ -374,7 +381,7 @@ DTB_END + + DTB_NOP + The tag is included in the signature if the current node is present +- in 'hashed-nodes' ++ in the node list + + In addition, the signature contains a property 'hashed-strings' which contains + the offset and length in the string table of the strings that are to be +diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py +index 7e0e8e4..47ca359 100644 +--- a/test/py/tests/test_vboot.py ++++ b/test/py/tests/test_vboot.py +@@ -362,10 +362,14 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, + shutil.copyfile(fit, efit) + vboot_evil.add_evil_node(fit, efit, evil_kernel, 'kernel@') + +- msg = 'Signature checking prevents use of unit addresses (@) in nodes' +- util.run_and_log_expect_exception( ++ # fit_check_sign catches this via signature mismatch (the @ ++ # node is hashed instead of the real one) ++ utils.run_and_log_expect_exception( + cons, [fit_check_sign, '-f', efit, '-k', dtb], +- 1, msg) ++ 1, 'Failed to verify required signature') ++ ++ # bootm catches it earlier, at fit_check_format() time ++ msg = 'Signature checking prevents use of unit addresses (@) in nodes' + run_bootm(sha_algo, 'evil kernel@', msg, False, efit) + + # Create a new properly signed fit and replace header bytes diff -Nru u-boot-2025.01/debian/patches/CVE-2026-46728-3.patch u-boot-2025.01/debian/patches/CVE-2026-46728-3.patch --- u-boot-2025.01/debian/patches/CVE-2026-46728-3.patch 1970-01-01 00:00:00.000000000 +0000 +++ u-boot-2025.01/debian/patches/CVE-2026-46728-3.patch 2026-06-24 09:06:59.000000000 +0000 @@ -0,0 +1,134 @@ +From: Tom Rini +Date: Wed, 18 Mar 2026 11:02:33 -0600 +Subject: tests: FIT: Add "clone" image attack image test + +Related to the problem resolved with commit 2092322b31cc ("boot: Add +fit_config_get_hash_list() to build signed node list"), add a testcase +for the problem as well. + +Reported-by: Apple Security Engineering and Architecture (SEAR) +Signed-off-by: Tom Rini +(cherry picked from commit a22e9e1b8ec7c96664072d7e629e811c318fb92a) +--- + test/py/tests/test_vboot.py | 10 +++++++ + test/py/tests/vboot_evil.py | 65 +++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 75 insertions(+) + +diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py +index 47ca359..f6919df 100644 +--- a/test/py/tests/test_vboot.py ++++ b/test/py/tests/test_vboot.py +@@ -372,6 +372,16 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, + msg = 'Signature checking prevents use of unit addresses (@) in nodes' + run_bootm(sha_algo, 'evil kernel@', msg, False, efit) + ++ # Try doing a clone of the images ++ efit = '%stest.evilclone.fit' % tmpdir ++ shutil.copyfile(fit, efit) ++ vboot_evil.add_evil_node(fit, efit, evil_kernel, 'clone') ++ ++ utils.run_and_log_expect_exception( ++ cons, [fit_check_sign, '-f', efit, '-k', dtb], ++ 1, 'Failed to verify required signature') ++ run_bootm(sha_algo, 'evil clone', 'Bad Data Hash', False, efit) ++ + # Create a new properly signed fit and replace header bytes + make_fit('sign-configs-%s%s.its' % (sha_algo, padding), cons, mkimage, dtc_args, datadir, fit) + sign_fit(sha_algo, sign_options) +diff --git a/test/py/tests/vboot_evil.py b/test/py/tests/vboot_evil.py +index e2b0cd6..5720631 100644 +--- a/test/py/tests/vboot_evil.py ++++ b/test/py/tests/vboot_evil.py +@@ -14,6 +14,7 @@ FDT_END = 0x9 + + FAKE_ROOT_ATTACK = 0 + KERNEL_AT = 1 ++IMAGE_CLONE = 2 + + MAGIC = 0xd00dfeed + +@@ -274,6 +275,66 @@ def get_prop_value(dt_struct, dt_strings, prop_path): + + return tag_data + ++def image_clone_attack(dt_struct, dt_strings, kernel_content, kernel_hash): ++ # retrieve the default configuration name ++ default_conf_name = get_prop_value( ++ dt_struct, dt_strings, '/configurations/default') ++ default_conf_name = str(default_conf_name[:-1], 'utf-8') ++ ++ conf_path = '/configurations/' + default_conf_name ++ ++ # fetch the loaded kernel name from the default configuration ++ loaded_kernel = get_prop_value(dt_struct, dt_strings, conf_path + '/kernel') ++ ++ loaded_kernel = str(loaded_kernel[:-1], 'utf-8') ++ ++ # since this is the last child in images! ++ loaded_fdt_name = get_prop_value(dt_struct, dt_strings, conf_path + '/fdt') ++ ++ loaded_fdt_name = str(loaded_fdt_name[:-1], 'utf-8') ++ ++ # determine boundaries of the images ++ (img_node_start, img_node_end) = (determine_offset( ++ dt_struct, dt_strings, '/images')) ++ if img_node_start is None and img_node_end is None: ++ print('Fatal error, unable to find images node') ++ sys.exit() ++ ++ # copy the images node ++ img_node_copy = dt_struct[img_node_start:img_node_end] ++ ++ # create an additional empty node ++ empty_node = struct.pack('>I', FDT_BEGIN_NODE) + b"EMPTYNO\0" + struct.pack('>I', FDT_END_NODE) ++ # right before the end, we add it! ++ img_node_copy = img_node_copy[:-4] + empty_node + img_node_copy[-4:] ++ ++ # insert the copy inside the tree ++ dt_struct = dt_struct[:img_node_end-4] + \ ++ img_node_copy + empty_node + dt_struct[img_node_end-4:] ++ ++ # change the content of the kernel being loaded ++ dt_struct = change_property_value( ++ dt_struct, dt_strings, '/images/' + loaded_kernel + '/data', kernel_content) ++ ++ # change the content of the kernel being loaded ++ dt_struct = change_property_value( ++ dt_struct, dt_strings, '/images/' + loaded_kernel + '/hash-1/value', kernel_hash) ++ ++ # finally, the main bug: change the hashed nodes to use the images clone instead! ++ hashed_nodes: bytes = get_prop_value(dt_struct, dt_strings, conf_path + '/signature/hashed-nodes') ++ print(f"got hashed nodes: {hashed_nodes}") ++ nodes = hashed_nodes.split(b"\0") ++ patched_nodes = [] ++ for node in nodes: ++ new_node = node ++ if node.startswith(b"/images/"): ++ # reparent the node ++ new_node = b"/images" + node ++ patched_nodes.append(new_node) ++ hashed_nodes = b"\0".join(patched_nodes) ++ dt_struct = change_property_value( ++ dt_struct, dt_strings, conf_path + '/signature/hashed-nodes', hashed_nodes) ++ return dt_struct + + def kernel_at_attack(dt_struct, dt_strings, kernel_content, kernel_hash): + """Conduct the kernel@ attack +@@ -419,6 +480,8 @@ def add_evil_node(in_fname, out_fname, kernel_fname, attack): + attack = FAKE_ROOT_ATTACK + elif attack == 'kernel@': + attack = KERNEL_AT ++ elif attack == 'clone': ++ attack = IMAGE_CLONE + else: + raise ValueError('Unknown attack name!') + +@@ -455,6 +518,8 @@ def add_evil_node(in_fname, out_fname, kernel_fname, attack): + elif attack == KERNEL_AT: + dt_struct = kernel_at_attack(dt_struct, dt_strings, kernel_content, + hash_digest) ++ elif attack == IMAGE_CLONE: ++ dt_struct = image_clone_attack(dt_struct, dt_strings, kernel_content, hash_digest) + + # now rebuild the new file + size_dt_strings = len(dt_strings) diff -Nru u-boot-2025.01/debian/patches/series u-boot-2025.01/debian/patches/series --- u-boot-2025.01/debian/patches/series 2025-03-18 07:16:11.000000000 +0000 +++ u-boot-2025.01/debian/patches/series 2026-06-24 09:05:43.000000000 +0000 @@ -1,13 +1,11 @@ arndale/board-spl-rule.diff - test-imagetools-test-fixes - exynos/0001-arm-config-fix-default-console-only-to-specify-the-d.patch - disable-fit-image-tests - qemu/efi-secure-boot.patch - Makefile-Use-relative-paths-for-debugging-symbols.patch - sitara/Don-t-attempt-to-build-final-firmware-images.patch +CVE-2024-42040.patch +CVE-2026-46728-1.patch +CVE-2026-46728-2.patch +CVE-2026-46728-3.patch