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.

The option is empty by default, which keeps loading the boot script.
As for the partitions, the bootmeth keeps the command in its platform
data, so that tests can set it at runtime.

Assisted-by: LLM
Signed-off-by: Frieder Schrempf <[email protected]>
---
Changes in v2:
- Keep the command in the platform data of the bootmeth, so that tests
  can change it at runtime, and always build the boot script code
  (Simon)
---
 boot/Kconfig                 | 16 ++++++++++++++++
 boot/bootmeth_rauc.c         | 23 ++++++++++++++++-------
 doc/develop/bootstd/rauc.rst |  8 ++++++++
 include/bootmeth_rauc.h      |  3 +++
 4 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/boot/Kconfig b/boot/Kconfig
index 072108db64a..27640817068 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -976,6 +976,22 @@ config BOOTMETH_RAUC_PARTITIONS
          partition names, this also rejects MBR devices. A value consisting
          only of digits is always taken as an index.
 
+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 acf9413591b..4f4927d5cd1 100644
--- a/boot/bootmeth_rauc.c
+++ b/boot/bootmeth_rauc.c
@@ -527,6 +527,7 @@ static const struct distro_rauc_slot 
*find_active_slot(struct distro_rauc_priv *
 
 static int distro_rauc_boot(struct udevice *dev, struct bootflow *bflow)
 {
+       const struct distro_rauc_plat *rplat = dev_get_plat(dev);
        struct blk_desc *desc;
        struct distro_rauc_priv *priv;
        const struct distro_rauc_slot *slot;
@@ -575,10 +576,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 (!*rplat->bootcmd) {
+               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);
@@ -599,9 +602,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 (*rplat->bootcmd) {
+               /* Run built-in boot command */
+               ret = run_command(rplat->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);
 
@@ -619,6 +627,7 @@ static int distro_rauc_bootmeth_bind(struct udevice *dev)
        plat->desc = "RAUC distro boot from MMC";
        plat->flags = BOOTMETHF_ANY_PART;
        rplat->partitions = CONFIG_BOOTMETH_RAUC_PARTITIONS;
+       rplat->bootcmd = CONFIG_BOOTMETH_RAUC_BOOTCMD;
 
        return 0;
 }
diff --git a/doc/develop/bootstd/rauc.rst b/doc/develop/bootstd/rauc.rst
index eee8d103fb9..247ae474f0f 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.
 
diff --git a/include/bootmeth_rauc.h b/include/bootmeth_rauc.h
index 0faeab192d4..88b17f10235 100644
--- a/include/bootmeth_rauc.h
+++ b/include/bootmeth_rauc.h
@@ -14,9 +14,12 @@
  *
  * @partitions: Boot and root partitions of each slot, given by number or
  *     by name, see CONFIG_BOOTMETH_RAUC_PARTITIONS
+ * @bootcmd: Command to boot the selected slot, see
+ *     CONFIG_BOOTMETH_RAUC_BOOTCMD. Empty to run the boot script instead
  */
 struct distro_rauc_plat {
        const char *partitions;
+       const char *bootcmd;
 };
 
 #endif

-- 
2.56.0

Reply via email to