From f66a85d95d60061103c737254bf9c8338d8d220c Mon Sep 17 00:00:00 2001
From: Rogerio Guerra Borin <rogerio.borin@toradex.com>
Date: Wed, 26 Jun 2024 16:08:52 -0300
Subject: [PATCH 2/5] toradex: integrate bootm protection (downstream)

Integrate the protection to the bootm command to only allow booting
from FIT images. With the proper configuration of U-Boot (enabling FIT
signing) one can ensure only signed FIT images can be booted when the
hardening is enabled at runtime.

Upstream-Status: Inappropriate [TorizonCore specific]

Signed-off-by: Rogerio Guerra Borin <rogerio.borin@toradex.com>
---
 Kconfig      |  7 ++++++
 boot/bootm.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 70 insertions(+), 1 deletion(-)

diff --git a/Kconfig b/Kconfig
index badab0318d6..258de43d449 100644
--- a/Kconfig
+++ b/Kconfig
@@ -746,6 +746,7 @@ source "tools/Kconfig"
 config TDX_SECBOOT_HARDENING
 	bool "Toradex Secure Boot hardening"
 	select TDX_CMD_WHITELIST
+	select TDX_BOOTM_PROTECTION
 	help
 	  This causes the Secure Boot hardening features added by Toradex
 	  to be built into U-Boot, including:
@@ -770,3 +771,9 @@ config TDX_CMD_WHITELIST
 	bool
 	help
 	  Enable the command white-listing feature provided by Toradex.
+
+config TDX_BOOTM_PROTECTION
+	bool
+	help
+	  Enable the protection in bootm to prevent execution of unsigned
+	  images.
diff --git a/boot/bootm.c b/boot/bootm.c
index d071537d692..b38182dd887 100644
--- a/boot/bootm.c
+++ b/boot/bootm.c
@@ -34,6 +34,7 @@
 
 #include <bootm.h>
 #include <image.h>
+#include <tdx-harden.h>
 
 #define MAX_CMDLINE_SIZE	SZ_4K
 
@@ -125,6 +126,7 @@ static int boot_get_kernel(const char *addr_fit, struct bootm_headers *images,
 	struct legacy_img_hdr	*hdr;
 #endif
 	ulong		img_addr;
+	int		fmt;
 	const void *buf;
 	const char *fit_uname_config = NULL, *fit_uname_kernel = NULL;
 #if CONFIG_IS_ENABLED(FIT)
@@ -146,7 +148,45 @@ static int boot_get_kernel(const char *addr_fit, struct bootm_headers *images,
 	/* check image type, for FIT images get FIT kernel node */
 	*os_data = *os_len = 0;
 	buf = map_sysmem(img_addr, 0);
-	switch (genimg_get_format(buf)) {
+	fmt = genimg_get_format(buf);
+
+#if CONFIG_IS_ENABLED(TDX_BOOTM_PROTECTION)
+	if (tdx_hardening_enabled()) {
+		/* hardening enabled at runtime. */
+		if (fmt != IMAGE_FORMAT_FIT) {
+			/* accept FIT images only. */
+			puts("ERROR: can't boot from non-FIT images with "
+			     "hardening enabled.\n");
+			return -EPROTOTYPE;
+		}
+
+		/*
+		 * For TorizonCore we expect a configuration to be always passed
+		 * by the boot script; at the CLI level this means the usage
+		 * syntax would be this one:
+		 *
+		 * bootm [<addr1>]#<conf>[#<extra-conf[#...]]
+		 *
+		 * Since one can easily bypass the signature checks by directly
+		 * specifying the kernel/ramdisk/fdt, here we enforce the above
+		 * usage where a <conf> name is passed in which case the
+		 * signature validation is performed for the configuration
+		 * (which then covers the images). This is done by requiring
+		 * 'fit_uname_config' to be non-null. As an extra caution, we
+		 * also enforce variable 'fit_uname_kernel' not to be null to
+		 * prevent the use where a kernel image is specified directly,
+		 * i.e. not via a configuration.
+		 *
+		 */
+		if ((fit_uname_config == NULL) || (fit_uname_kernel != NULL)) {
+			puts("ERROR: bootm only accepts booting from a "
+			     "configuration when hardening is enabled.\n");
+			return -EPROTOTYPE;
+		}
+	}
+#endif
+
+	switch (fmt) {
 #if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
 	case IMAGE_FORMAT_LEGACY:
 		printf("## Booting kernel from Legacy Image at %08lx ...\n",
@@ -259,7 +299,29 @@ static inline void boot_start_lmb(struct bootm_headers *images) { }
 static int bootm_start(void)
 {
 	memset((void *)&images, 0, sizeof(images));
+
+#if CONFIG_IS_ENABLED(TDX_BOOTM_PROTECTION)
+	/*
+	 * When the "bootm" protection is enabled at build-time, FIT signature
+	 * verification is supposed to follow the status of the hardening. For
+	 * this, we assume CONFIG_FIT_SIGNATURE is set and here we set the
+	 * value of the "verify" field to match the status of the hardening.
+	 * With this we have:
+	 *
+	 * - If hardening is enabled => validate/enforce correct signature.
+	 * - If hardening is disabled => do not check signature.
+	 *
+	 * The logic above should be appropriate for allowing a bootloader
+	 * binary to be altered between non-secure and secure modes. Notice
+	 * that when this "bootm" protection is enabled the environment
+	 * variable "verify" is no longer used at the moment.
+	 *
+	 * TODO: Consider adding "verify" as part of the logic.
+	 */
+	images.verify = tdx_hardening_enabled();
+#else
 	images.verify = env_get_yesno("verify");
+#endif
 
 	boot_start_lmb(&images);
 
-- 
2.25.1

