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

Reply via email to