[PATCH 3/8] common: Add OS anti-rollback validation using rollback devices

seanedmond at linux.microsoft.com seanedmond at linux.microsoft.com
Tue Sep 12 11:47:26 CEST 2023


From: Stephen Carlson <stcarlso at linux.microsoft.com>

New config CONFIG_ROLLBACK_CHECK to enable enforcement of OS anti-rollback
counter during image loading.

Images with an anti-rollback counter value "rollback" declared in the FDT
will be compared against the current device anti-rollback counter value,
and older images will not pass signature validation. If the image is
newer, the device anti-rollback counter value will be updated.

Signed-off-by: Stephen Carlson <stcarlso at linux.microsoft.com>
Signed-off-by: Sean Edmond <seanedmond at microsoft.com>
---
 boot/Kconfig         |  9 +++++
 boot/image-fit-sig.c | 92 ++++++++++++++++++++++++++++++++++++++++++++
 boot/image-fit.c     | 31 +++++++++++++++
 include/image.h      |  6 ++-
 4 files changed, 137 insertions(+), 1 deletion(-)

diff --git a/boot/Kconfig b/boot/Kconfig
index e8fb03b801..9180a1c8dc 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -103,6 +103,15 @@ config FIT_CIPHER
 	  Enable the feature of data ciphering/unciphering in the tool mkimage
 	  and in the u-boot support of the FIT image.
 
+config FIT_ROLLBACK_CHECK
+	bool "Enable Anti rollback version check for FIT images"
+	depends on FIT_SIGNATURE
+	default n
+	help
+	  Enables FIT image anti-rollback protection. This feature is required
+	  when a platform needs to retire previous versions of FIT images due to
+	  security flaws and prevent devices from being reverted to them.
+
 config FIT_VERBOSE
 	bool "Show verbose messages when FIT images fail"
 	depends on FIT
diff --git a/boot/image-fit-sig.c b/boot/image-fit-sig.c
index 12369896fe..91eaf4baa8 100644
--- a/boot/image-fit-sig.c
+++ b/boot/image-fit-sig.c
@@ -11,6 +11,8 @@
 #include <log.h>
 #include <malloc.h>
 #include <asm/global_data.h>
+#include <dm.h>
+#include <rollback.h>
 DECLARE_GLOBAL_DATA_PTR;
 #endif /* !USE_HOSTCC*/
 #include <fdt_region.h>
@@ -63,6 +65,44 @@ struct image_region *fit_region_make_list(const void *fit,
 	return region;
 }
 
+static int fit_image_verify_rollback(const void *fit, int image_noffset)
+{
+#if !defined(USE_HOSTCC)
+	u64 image_rollback;
+	u64 plat_rollback = 0ULL;
+	struct udevice *dev;
+	int ret;
+
+	ret = fit_image_get_rollback(fit, image_noffset, &image_rollback);
+
+	/* If the FIT doesn't contain the rollback property, assume an
+	 * anti-rollback version number of 0.  This ensures failure
+	 * if the platform anti-rollback version number is non-zero
+	 */
+	if (ret)
+		image_rollback = 0;
+
+	ret = uclass_first_device_err(UCLASS_ROLLBACK, &dev);
+	if (ret)
+		return ret;
+
+	ret = rollback_idx_get(dev, &plat_rollback);
+	if (ret)
+		return -EIO;
+
+	if (image_rollback < plat_rollback) {
+		return -EPERM;
+	} else if (image_rollback > plat_rollback) {
+		ret = rollback_idx_set(dev, image_rollback);
+		printf(" Updating OS anti-rollback to %llu from %llu\n",
+		       image_rollback, plat_rollback);
+		return ret;
+	}
+#endif
+
+	return 0;
+}
+
 static int fit_image_setup_verify(struct image_sign_info *info,
 				  const void *fit, int noffset,
 				  const void *key_blob, int required_keynode,
@@ -175,6 +215,16 @@ static int fit_image_verify_sig(const void *fit, int image_noffset,
 		goto error;
 	}
 
+	if (!tools_build()) {
+		if (FIT_IMAGE_ENABLE_ROLLBACK_CHECK && verified) {
+			ret = fit_image_verify_rollback(fit, image_noffset);
+			if (ret) {
+				err_msg = "Anti-rollback verification failed";
+				goto error;
+			}
+		}
+	}
+
 	return verified ? 0 : -EPERM;
 
 error:
@@ -385,6 +435,38 @@ static int fit_config_check_sig(const void *fit, int noffset, int conf_noffset,
 	return 0;
 }
 
+static int fit_config_verify_rollback(const void *fit, int conf_noffset,
+				      int sig_offset)
+{
+	static const char default_list[] = FIT_KERNEL_PROP "\0"
+			FIT_FDT_PROP;
+	int ret, len;
+	const char *prop, *iname, *end;
+	int image_noffset;
+
+	/* If there is "sign-images" property, use that */
+	prop = fdt_getprop(fit, sig_offset, "sign-images", &len);
+	if (!prop) {
+		prop = default_list;
+		len = sizeof(default_list);
+	}
+
+	/* Locate the images */
+	end = prop + len;
+	for (iname = prop; iname < end; iname += strlen(iname) + 1) {
+		image_noffset = fit_conf_get_prop_node(fit, conf_noffset,
+						       iname, IH_PHASE_NONE);
+		if (image_noffset < 0)
+			return -ENOENT;
+
+		ret = fit_image_verify_rollback(fit, image_noffset);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 /**
  * fit_config_verify_key() - Verify that a configuration is signed with a key
  *
@@ -444,6 +526,16 @@ static int fit_config_verify_key(const void *fit, int conf_noffset,
 		goto error;
 	}
 
+	if (!tools_build()) {
+		if (FIT_IMAGE_ENABLE_ROLLBACK_CHECK && verified) {
+			ret = fit_config_verify_rollback(fit, conf_noffset, noffset);
+			if (ret) {
+				err_msg = "Anti-rollback verification failed";
+				goto error;
+			}
+		}
+	}
+
 	if (verified)
 		return 0;
 
diff --git a/boot/image-fit.c b/boot/image-fit.c
index 3cc556b727..510cb51cd5 100644
--- a/boot/image-fit.c
+++ b/boot/image-fit.c
@@ -1084,6 +1084,37 @@ int fit_image_get_data_and_size(const void *fit, int noffset,
 	return ret;
 }
 
+/**
+ * fit_image_get_rollback - get anti-rollback counter
+ * @fit: pointer to the FIT image header
+ * @noffset: component image node offset
+ * @rollback: holds the rollback property value
+ *
+ * returns:
+ *     0, on success
+ *     -ENOENT if the property could not be found
+ */
+int fit_image_get_rollback(const void *fit, int noffset, uint64_t *rollback)
+{
+	const fdt64_t *val;
+	int len;
+
+	val = fdt_getprop(fit, noffset, FIT_ROLLBACK_PROP, &len);
+
+	if (!val) {
+		printf("error! Can't find property %s in FIT\n", FIT_ROLLBACK_PROP);
+		return -ENOENT;
+	}
+	if (len != sizeof(uint64_t)) {
+		printf("Property %s must be 64-bits\n", FIT_ROLLBACK_PROP);
+		return -ENOENT;
+	}
+
+	*rollback = fdt64_to_cpu(*val);
+
+	return 0;
+}
+
 /**
  * fit_image_hash_get_algo - get hash algorithm name
  * @fit: pointer to the FIT format image header
diff --git a/include/image.h b/include/image.h
index 01a6787d21..3283cd7717 100644
--- a/include/image.h
+++ b/include/image.h
@@ -1024,6 +1024,7 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
 #define FIT_COMP_PROP		"compression"
 #define FIT_ENTRY_PROP		"entry"
 #define FIT_LOAD_PROP		"load"
+#define FIT_ROLLBACK_PROP	"rollback"
 
 /* configuration node */
 #define FIT_KERNEL_PROP		"kernel"
@@ -1105,6 +1106,7 @@ int fit_image_get_data_size_unciphered(const void *fit, int noffset,
 				       size_t *data_size);
 int fit_image_get_data_and_size(const void *fit, int noffset,
 				const void **data, size_t *size);
+int fit_image_get_rollback(const void *fit, int noffset, uint64_t *rollback_idx);
 
 /**
  * fit_get_data_node() - Get verified image data for an image
@@ -1389,6 +1391,7 @@ int calculate_hash(const void *data, int data_len, const char *algo,
  * device
  */
 #if defined(USE_HOSTCC)
+# define FIT_IMAGE_ENABLE_ROLLBACK_CHECK	0
 # if defined(CONFIG_FIT_SIGNATURE)
 #  define IMAGE_ENABLE_SIGN	1
 #  define FIT_IMAGE_ENABLE_VERIFY	1
@@ -1399,7 +1402,8 @@ int calculate_hash(const void *data, int data_len, const char *algo,
 # endif
 #else
 # define IMAGE_ENABLE_SIGN	0
-# define FIT_IMAGE_ENABLE_VERIFY	CONFIG_IS_ENABLED(FIT_SIGNATURE)
+# define FIT_IMAGE_ENABLE_VERIFY		CONFIG_IS_ENABLED(FIT_SIGNATURE)
+# define FIT_IMAGE_ENABLE_ROLLBACK_CHECK	CONFIG_IS_ENABLED(FIT_ROLLBACK_CHECK)
 #endif
 
 #ifdef USE_HOSTCC
-- 
2.40.0



More information about the U-Boot mailing list