priv->slots is a NULL-terminated array of pointers, but get_slot()
tests priv->slots[i]->name in its loop condition, dereferencing each
entry before checking it against NULL. When slot_name does not match
any configured slot, the loop reaches the terminator and dereferences
a NULL pointer.

This is reachable from the BOOT_ORDER environment variable: an entry
naming a slot that is not listed in CONFIG_BOOTMETH_RAUC_PARTITIONS
crashes U-Boot in distro_rauc_scan_parts() or distro_rauc_boot().
Since BOOT_ORDER is typically stored in a disk-resident environment
written by the OS, a stray or corrupted value must not crash the
bootloader.

Test the array entry itself before using its name, as
distro_rauc_priv_free() already does. Both callers already handle a
NULL return.

Extend the bootflow_rauc test to scan with a BOOT_ORDER naming an
unconfigured slot. Without this fix the test crashes with SIGSEGV.

Fixes: 7e5c2c782fb9 ("bootstd: Add implementation for bootmeth rauc")
Signed-off-by: Aristo Chen <[email protected]>
---
 boot/bootmeth_rauc.c |  2 +-
 test/boot/bootflow.c | 16 ++++++++++++++++
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/boot/bootmeth_rauc.c b/boot/bootmeth_rauc.c
index d7b0c686ffe..32be641ab54 100644
--- a/boot/bootmeth_rauc.c
+++ b/boot/bootmeth_rauc.c
@@ -71,7 +71,7 @@ static struct distro_rauc_slot *get_slot(struct 
distro_rauc_priv *priv,
 {
        int i;
 
-       for (i = 0; priv->slots[i]->name; i++) {
+       for (i = 0; priv->slots[i]; i++) {
                if (!strcmp(priv->slots[i]->name, slot_name))
                        return priv->slots[i];
        }
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 1cc137c9700..837c5a7a4aa 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -1444,6 +1444,22 @@ static int bootflow_rauc(struct unit_test_state *uts)
 
        ut_assert_console_end();
 
+       /*
+        * Scan with a BOOT_ORDER naming a slot that has no configured
+        * partitions. get_slot() must not crash on the NULL array terminator;
+        * the bootflow just becomes invalid.
+        */
+       ut_assertok(env_set("BOOT_ORDER", "A B rescue"));
+       ut_assertok(run_command("bootflow scan", 0));
+       ut_assert_nextline("No bootflows found; try again with -l");
+       ut_assert_console_end();
+
+       ut_assertok(run_command("bootflow list", 0));
+       ut_assert_skip_to_line("(0 bootflows, 0 valid)");
+       ut_assert_console_end();
+
+       ut_assertok(env_set("BOOT_ORDER", "A B"));
+
        /* Restore the order used by the device tree */
        std->bootdev_order = old_order;
 
-- 
2.43.0

Reply via email to