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

seanedmond
2023-08-12T00:29:16Z

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

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

Images with an anti-rollback counter value "arbvn" 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@linux.microsoft.com>
---
boot/Kconfig | 9 +++++
boot/image-fit-sig.c | 89 ++++++++++++++++++++++++++++++++++++++++++++
boot/image-fit.c | 23 ++++++++++++
include/image.h | 4 ++
4 files changed, 125 insertions(+)

diff --git a/boot/Kconfig b/boot/Kconfig
index e8fb03b801..e08c274b7c 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_ARBP
+ 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..bf3b81a3a3 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 <dm-security.h>
DECLARE_GLOBAL_DATA_PTR;
#endif /* !USE_HOSTCC*/
#include <fdt_region.h>
@@ -63,6 +65,39 @@ struct image_region *fit_region_make_list(const void *fit,
return region;
}

+#if !defined(USE_HOSTCC)
+static int fit_image_verify_arbvn(const void *fit, int image_noffset)
+{
+ u64 image_arbvn;
+ u64 plat_arbvn = 0ULL;
+ struct udevice *dev;
+ int ret;
+
+ ret = fit_image_get_arbvn(fit, image_noffset, &image_arbvn);
+ if (ret)
+ return 0;
+
+ ret = uclass_first_device_err(UCLASS_SECURITY, &dev);
+ if (ret)
+ return -ENODEV;
+
+ ret = dm_security_arbvn_get(dev, &plat_arbvn);
+ if (ret)
+ return -EIO;
+
+ if (image_arbvn < plat_arbvn) {
+ return -EPERM;
+ } else if (image_arbvn > plat_arbvn) {
+ ret = dm_security_arbvn_set(dev, image_arbvn);
+ printf(" Updating OS anti-rollback to %llu from %llu\n",
+ image_arbvn, plat_arbvn);
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
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 +210,16 @@ static int fit_image_verify_sig(const void *fit, int image_noffset,
goto error;
}

+#if !defined(USE_HOSTCC)
+ if (FIT_IMAGE_ENABLE_ARBP && verified) {
+ ret = fit_image_verify_arbvn(fit, image_noffset);
+ if (ret) {
+ err_msg = "Anti-rollback verification failed";
+ goto error;
+ }
+ }
+#endif
+
return verified ? 0 : -EPERM;

error:
@@ -385,6 +430,40 @@ static int fit_config_check_sig(const void *fit, int noffset, int conf_noffset,
return 0;
}

+#if !defined(USE_HOSTCC)
+static int fit_config_verify_arbvn(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_arbvn(fit, image_noffset);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
/**
* fit_config_verify_key() - Verify that a configuration is signed with a key
*
@@ -444,6 +523,16 @@ static int fit_config_verify_key(const void *fit, int conf_noffset,
goto error;
}

+#if !defined(USE_HOSTCC)
+ if (FIT_IMAGE_ENABLE_ARBP && verified) {
+ ret = fit_config_verify_arbvn(fit, conf_noffset, noffset);
+ if (ret) {
+ err_msg = "Anti-rollback verification failed";
+ goto error;
+ }
+ }
+#endif
+
if (verified)
return 0;

diff --git a/boot/image-fit.c b/boot/image-fit.c
index 3cc556b727..d4e324752a 100644
--- a/boot/image-fit.c
+++ b/boot/image-fit.c
@@ -1084,6 +1084,29 @@ int fit_image_get_data_and_size(const void *fit, int noffset,
return ret;
}

+/**
+ * fit_image_get_arbvn - get anti-rollback counter
+ * @fit: pointer to the FIT image header
+ * @noffset: component image node offset
+ * @arbvn: holds the arbvn property value
+ *
+ * returns:
+ * 0, on success
+ * -ENOENT if the property could not be found
+ */
+int fit_image_get_arbvn(const void *fit, int noffset, uint64_t *arbvn)
+{
+ const fdt64_t *val;
+
+ val = fdt_getprop(fit, noffset, FIT_ARBVN_PROP, NULL);
+ if (!val)
+ return -ENOENT;
+
+ *arbvn = 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..497772fb4b 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_ARBVN_PROP "arbvn"

/* 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_arbvn(const void *fit, int noffset, uint64_t *arbvn);

/**
* 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_ARBP 0
# if defined(CONFIG_FIT_SIGNATURE)
# define IMAGE_ENABLE_SIGN 1
# define FIT_IMAGE_ENABLE_VERIFY 1
@@ -1400,6 +1403,7 @@ int calculate_hash(const void *data, int data_len, const char *algo,
#else
# define IMAGE_ENABLE_SIGN 0
# define FIT_IMAGE_ENABLE_VERIFY CONFIG_IS_ENABLED(FIT_SIGNATURE)
+# define FIT_IMAGE_ENABLE_ARBP CONFIG_IS_ENABLED(FIT_ARBP)
#endif

#ifdef USE_HOSTCC
--
2.40.0