From: Frieder Schrempf <[email protected]>

The RAUC bootmeth boots a slot by running boot.scr or boot.scr.uimg
from its boot partition. Nothing authenticates this partition, so with
verified boot, whoever can write it can run any U-Boot command, for
example booting an unsigned kernel or changing the kernel command line.
Signing the script does not close this reliably as source skips all
checks if the environment sets verify=no, which RAUC systems must keep
writable for BOOT_ORDER and BOOT_x_LEFT, and it accepts a FIT script
without configurations, whose signature is then only checked against
keys required for images, not configurations.

Add CONFIG_BOOTMETH_RAUC_BOOTCMD to set a command built into U-Boot
that boots the slot instead. It sees the same environment variables as
the boot script. The boot partition then contains nothing that U-Boot
executes, and the code that loads the script is left out of the build.

The option is empty by default, which keeps loading the boot script.

Assisted-by: LLM
Signed-off-by: Frieder Schrempf <[email protected]>
---
 boot/Kconfig                 | 16 ++++++++++++++++
 boot/bootmeth_rauc.c         | 21 ++++++++++++++-------
 doc/develop/bootstd/rauc.rst |  8 ++++++++
 3 files changed, 38 insertions(+), 7 deletions(-)

diff --git a/boot/Kconfig b/boot/Kconfig
index 5f89c9d86fa..b17f735937a 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -981,6 +981,22 @@ config BOOTMETH_RAUC_PART_NAMES
          names. Partition names are only available on GPT, so this rejects
          MBR devices. Leave this empty to not check the names.
 
+config BOOTMETH_RAUC_BOOTCMD
+       string "RAUC built-in boot command"
+       default ""
+       help
+         Sets a command to boot the selected slot, for example
+         "run distro_boot_rauc". It is run instead of loading a boot script
+         from the slot's boot partition, and can use the same environment
+         variables as the boot script, such as distro_bootpart and raucargs.
+
+         As the command is built into U-Boot, the boot partition does not
+         need to contain anything U-Boot executes, which helps with verified
+         boot. If the command runs an environment variable, that variable must
+         not be writable at runtime then, see ENV_WRITEABLE_LIST.
+
+         Leave this empty to load the boot script.
+
 config BOOTMETH_RAUC_DEFAULT_TRIES
        int "RAUC slot default tries"
        default 3
diff --git a/boot/bootmeth_rauc.c b/boot/bootmeth_rauc.c
index ff2e2d48145..dca11500190 100644
--- a/boot/bootmeth_rauc.c
+++ b/boot/bootmeth_rauc.c
@@ -528,10 +528,12 @@ static int distro_rauc_boot(struct udevice *dev, struct 
bootflow *bflow)
        if (ret)
                return log_msg_ret("env", ret);
 
-       /* Load distro boot script */
-       ret = distro_rauc_load_boot_script(bflow, slot);
-       if (ret)
-               return log_msg_ret("load", ret);
+       /* Load distro boot script, unless a built-in command boots the slot */
+       if (!CONFIG_BOOTMETH_RAUC_BOOTCMD[0]) {
+               ret = distro_rauc_load_boot_script(bflow, slot);
+               if (ret)
+                       return log_msg_ret("load", ret);
+       }
 
        log_info("INFO: Booting slot %s, %lu of %d tries left\n",
                 slot->name, active_slot_tries, 
CONFIG_BOOTMETH_RAUC_DEFAULT_TRIES);
@@ -552,9 +554,14 @@ static int distro_rauc_boot(struct udevice *dev, struct 
bootflow *bflow)
        }
        str_free_list(boot_order_list);
 
-       /* Run distro boot script */
-       addr = map_to_sysmem(bflow->buf);
-       ret = cmd_source_script(addr, NULL, NULL);
+       if (CONFIG_BOOTMETH_RAUC_BOOTCMD[0]) {
+               /* Run built-in boot command */
+               ret = run_command(CONFIG_BOOTMETH_RAUC_BOOTCMD, 0);
+       } else {
+               /* Run distro boot script */
+               addr = map_to_sysmem(bflow->buf);
+               ret = cmd_source_script(addr, NULL, NULL);
+       }
        if (ret)
                return log_msg_ret("boot", ret);
 
diff --git a/doc/develop/bootstd/rauc.rst b/doc/develop/bootstd/rauc.rst
index dfbe010a60f..f4e7e02f37f 100644
--- a/doc/develop/bootstd/rauc.rst
+++ b/doc/develop/bootstd/rauc.rst
@@ -44,6 +44,13 @@ The boot script must be located in each boot partition. The 
bootmeth searches
 for ``boot.scr`` first, then ``boot.scr.uimg`` if not found. It will search in
 all directories of the bootstd list of prefixes (``"/", "/boot"`` by default).
 
+Alternatively, ``CONFIG_BOOTMETH_RAUC_BOOTCMD`` sets a command built into
+U-Boot, for example ``run distro_boot_rauc``, which boots the slot instead of a
+boot script. The boot partitions then need no boot script, and the bootmeth
+executes nothing from them. For verified boot, the command must load only
+signed images, and any environment variable it runs must not be writable at
+runtime (see ``CONFIG_ENV_WRITEABLE_LIST``).
+
 When the bootflow is booted, the bootmeth sets these environment variables:
 
 devtype
@@ -63,6 +70,7 @@ raucargs
     kernel command line arguments needed for RAUC to detect the currently 
booted
     slot
 
+The boot script or the boot command can use these variables to boot the slot.
 The script file must be a FIT or a legacy uImage. It is loaded into memory and
 executed.
 

-- 
2.56.0

Reply via email to