[PATCH v1 6/7] bootstd: Free abandoned bootflows while scanning

Aristo Chen via U-Boot <[email protected]>
Newsgroups gmane.comp.boot-loaders.u-boot
Message-ID <20260813155617.184928-7-aristo.chen__12100.2382644051$1786643983$gmane$org@canonical.com>
bootflow_scan_first()/bootflow_scan_next() try each candidate
(bootdev, method, partition) in turn. When a candidate fails and is
not returned to the caller (no BOOTFLOWIF_ALL), the bootflow is simply
abandoned: the next candidate's bootflow_init() memsets the struct,
orphaning everything the failed attempt allocated, starting with the
name allocated in bootdev_find_in_blk().

Each failed candidate therefore leaks its allocations on every scan.
A single failing 'bootflow scan' on a sandbox MMC with a RAUC A/B
layout leaks about 1 KB across ~30 abandoned candidates, and scans can
be retried indefinitely from the U-Boot prompt.

Free the bootflow when it failed and is not passed back to the caller.

Add a check to the bootflow_rauc test that repeating a failing scan
does not change the number of allocated bytes. Together with the
previous RAUC fixes this makes the failed-scan path leak-free.

Fixes: a8f5be178db5 ("bootstd: Add support for bootflows")
Signed-off-by: Aristo Chen <[email protected]>
---
 boot/bootflow.c      | 2 ++
 test/boot/bootflow.c | 8 ++++++++
 2 files changed, 10 insertions(+)

diff --git a/boot/bootflow.c b/boot/bootflow.c
index d8a4a81a838..7ee940460af 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -580,6 +580,7 @@ int bootflow_scan_first(struct udevice *dev, const char *label,
 			if (iter->flags & BOOTFLOWIF_ALL)
 				return log_msg_ret("all", ret);
 		}
+		bootflow_free(bflow);
 		iter->err = ret;
 		ret = bootflow_scan_next(iter, bflow);
 		if (ret)
@@ -614,6 +615,7 @@ int bootflow_scan_next(struct bootflow_iter *iter, struct bootflow *bflow)
 				if (iter->flags & BOOTFLOWIF_ALL)
 					return log_msg_ret("all", ret);
 			}
+			bootflow_free(bflow);
 		} else {
 			log_debug("incr failed, err=%d\n", ret);
 			iter->err = ret;
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 8fa8835c20c..ef4638ec700 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -1403,6 +1403,7 @@ static int bootflow_rauc(struct unit_test_state *uts)
 	struct udevice *bootstd;
 	static const char *order[] = {NULL, NULL};
 	const char **old_order;
+	ulong mem_start;
 	ofnode root;
 	ofnode node;
 
@@ -1458,6 +1459,13 @@ static int bootflow_rauc(struct unit_test_state *uts)
 	ut_assert_skip_to_line("(0 bootflows, 0 valid)");
 	ut_assert_console_end();
 
+	/* Repeating the failed scan must not leak memory */
+	mem_start = ut_check_delta(0);
+	ut_assertok(run_command("bootflow scan", 0));
+	ut_assert_nextline("No bootflows found; try again with -l");
+	ut_assert_console_end();
+	ut_asserteq(0, ut_check_delta(mem_start));
+
 	/*
 	 * A failed scan with -a stores the failed bootflows; the next scan
 	 * removes them, freeing bootmeth_priv. This used to double free the
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.