distro_rauc_read_bootflow() stores priv in bflow->bootmeth_priv before
calling distro_rauc_scan_parts(). If the scan fails, the error path
frees priv via distro_rauc_priv_free() but leaves bflow->bootmeth_priv
pointing at the freed memory.
With 'bootflow scan -a', failed bootflows are stored in the bootstd
list, so the stale pointer is kept. The next scan (or any other
bootflow removal) calls bootflow_free(), which frees bootmeth_priv
again. On sandbox, dlmalloc catches the double free:
common/dlmalloc.c:816: do_check_inuse_chunk: Assertion `inuse(p)' failed.
The scan can fail this way whenever no slot has a valid filesystem, or
when BOOT_ORDER names an unknown slot.
Clear bflow->bootmeth_priv after freeing, as bootmeth_android already
does. Extend the bootflow_rauc test to run a failing scan with -a and
then rescan.
Fixes: 284855320282 ("bootstd: rauc: Free memory during error handling")
Signed-off-by: Aristo Chen <[email protected]>
---
boot/bootmeth_rauc.c | 1 +
test/boot/bootflow.c | 13 +++++++++++++
2 files changed, 14 insertions(+)
diff --git a/boot/bootmeth_rauc.c b/boot/bootmeth_rauc.c
index 32be641ab54..3e76eabe2fb 100644
--- a/boot/bootmeth_rauc.c
+++ b/boot/bootmeth_rauc.c
@@ -239,6 +239,7 @@ static int distro_rauc_read_bootflow(struct udevice *dev,
struct bootflow *bflow
rauc_read_bootflow_err:
distro_rauc_priv_free(priv);
+ bflow->bootmeth_priv = NULL;
free(boot_order_copy);
free(partitions);
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 837c5a7a4aa..8fa8835c20c 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -1458,6 +1458,19 @@ static int bootflow_rauc(struct unit_test_state *uts)
ut_assert_skip_to_line("(0 bootflows, 0 valid)");
ut_assert_console_end();
+ /*
+ * A failed scan with -a stores the failed bootflows; the next scan
+ * removes them, freeing bootmeth_priv. This used to double free the
+ * RAUC private data.
+ */
+ ut_assertok(run_command("bootflow scan -a", 0));
+ ut_assert_nextline("No bootflows found; try again with -l");
+ ut_assert_console_end();
+
+ ut_assertok(run_command("bootflow scan", 0));
+ ut_assert_nextline("No bootflows found; try again with -l");
+ ut_assert_console_end();
+
ut_assertok(env_set("BOOT_ORDER", "A B"));
/* Restore the order used by the device tree */
--
2.43.0