Anti rollback protection is required when there is a need to retire
previous versions of FIT images due to security flaws in them.
Currently U-Boot Verified boot does not have rollback protection to
protect against known security flaws.

This change adds anti-rollback protection for FIT images.

Signed-off-by: Thirupathaiah Annapureddy <thir...@linux.microsoft.com>
---
 Kconfig                |  9 +++++
 common/image-fit-sig.c | 79 ++++++++++++++++++++++++++++++++++++++++++
 common/image-fit.c     | 24 +++++++++++++
 include/image.h        | 23 ++++++++++++
 4 files changed, 135 insertions(+)

diff --git a/Kconfig b/Kconfig
index 883e3f71d0..3959a6592c 100644
--- a/Kconfig
+++ b/Kconfig
@@ -533,6 +533,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
+         Enable this to activate anti-rollback protection. This is required
+         when a platform needs to retire previous versions of FIT images due to
+         security flaws in in them.
+
 config FIT_VERBOSE
        bool "Show verbose messages when FIT images fail"
        help
diff --git a/common/image-fit-sig.c b/common/image-fit-sig.c
index cc1967109e..5103508894 100644
--- a/common/image-fit-sig.c
+++ b/common/image-fit-sig.c
@@ -78,6 +78,35 @@ 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)
+{
+       uint8_t type;
+       uint32_t image_arbvn;
+       uint32_t plat_arbvn = 0;
+       int ret;
+
+       ret = fit_image_get_arbvn(fit, image_noffset, &image_arbvn);
+       if (ret)
+               return 0;
+
+       ret = fit_image_get_type(fit, image_noffset, &type);
+       if (ret)
+               return 0;
+
+       ret = board_get_arbvn(type, &plat_arbvn);
+
+       if (image_arbvn < plat_arbvn) {
+               return -EPERM;
+       } else if (image_arbvn > plat_arbvn) {
+               ret = board_set_arbvn(type, image_arbvn);
+               return ret;
+       }
+
+       return 0;
+}
+#endif
+
 static int fit_image_setup_verify(struct image_sign_info *info,
                                  const void *fit, int noffset,
                                  int required_keynode, char **err_msgp)
@@ -181,6 +210,14 @@ static int fit_image_verify_sig(const void *fit, int 
image_noffset,
                goto error;
        }
 
+#if !defined(USE_HOSTCC)
+       if (IMAGE_ENABLE_ARBP && verified) {
+               ret = fit_image_verify_arbvn(fit, image_noffset);
+               if (ret)
+                       verified = 0;
+       }
+#endif
+
        return verified ? 0 : -EPERM;
 
 error:
@@ -370,6 +407,40 @@ static int fit_config_check_sig(const void *fit, int 
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);
+               if (image_noffset < 0)
+                       return -ENOENT;
+
+               ret = fit_image_verify_arbvn(fit, image_noffset);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+#endif
+
 static int fit_config_verify_sig(const void *fit, int conf_noffset,
                                 const void *sig_blob, int sig_offset)
 {
@@ -401,6 +472,14 @@ static int fit_config_verify_sig(const void *fit, int 
conf_noffset,
                goto error;
        }
 
+#if !defined(USE_HOSTCC)
+       if (IMAGE_ENABLE_ARBP && verified) {
+               ret = fit_config_verify_arbvn(fit, conf_noffset, noffset);
+               if (ret)
+                       verified = 0;
+       }
+#endif
+
        if (verified)
                return 0;
 
diff --git a/common/image-fit.c b/common/image-fit.c
index d54eff9033..97029853b9 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -1025,6 +1025,30 @@ int fit_image_get_data_and_size(const void *fit, int 
noffset,
        return ret;
 }
 
+/**
+ * Get 'arbvn' property from a given image node.
+ *
+ * @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, uint32_t *arbvn)
+{
+       const fdt32_t *val;
+
+       val = fdt_getprop(fit, noffset, FIT_ARBVN_PROP, NULL);
+       if (!val)
+               return -ENOENT;
+
+       *arbvn = fdt32_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 9a5a87dbf8..72a963cf27 100644
--- a/include/image.h
+++ b/include/image.h
@@ -1005,6 +1005,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"
@@ -1085,6 +1086,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, uint32_t *arbvn);
 
 int fit_image_hash_get_algo(const void *fit, int noffset, char **algo);
 int fit_image_hash_get_value(const void *fit, int noffset, uint8_t **value,
@@ -1186,6 +1188,7 @@ int calculate_hash(const void *data, int data_len, const 
char *algo,
  * device
  */
 #if defined(USE_HOSTCC)
+# define IMAGE_ENABLE_ARBP     0
 # if defined(CONFIG_FIT_SIGNATURE)
 #  define IMAGE_ENABLE_SIGN    1
 #  define IMAGE_ENABLE_VERIFY  1
@@ -1200,6 +1203,7 @@ int calculate_hash(const void *data, int data_len, const 
char *algo,
 # define IMAGE_ENABLE_SIGN     0
 # define IMAGE_ENABLE_VERIFY           CONFIG_IS_ENABLED(RSA_VERIFY)
 # define FIT_IMAGE_ENABLE_VERIFY       CONFIG_IS_ENABLED(FIT_SIGNATURE)
+# define IMAGE_ENABLE_ARBP             CONFIG_IS_ENABLED(FIT_ARBP)
 #endif
 
 #if IMAGE_ENABLE_FIT
@@ -1544,6 +1548,25 @@ int board_fit_config_name_match(const char *name);
 void board_fit_image_post_process(void **p_image, size_t *p_size);
 #endif /* CONFIG_SPL_FIT_IMAGE_POST_PROCESS */
 
+#if defined(CONFIG_FIT_ARBP)
+/**
+ * board_get_arbvn() - get the arbvn stored in the platform secure storage.
+ *
+ * @ih_type: image type
+ * @arbvn: pointer to the arbvn
+ * @return 0 if upon successful retrieval, non-zero upon failure.
+ */
+int board_get_arbvn(uint8_t ih_type, uint32_t *arbvn);
+/**
+ * board_set_arbvn() - set the arbvn stored in the platform secure storage.
+ *
+ * @ih_type: image type
+ * @arbvn: new arbvn value to store in the platform secure storage.
+ * @return 0 if stored successfully, non-zero upon failure.
+ */
+int board_set_arbvn(uint8_t ih_type, uint32_t arbvn);
+#endif /* CONFIG_FIT_ARBP */
+
 #define FDT_ERROR      ((ulong)(-1))
 
 ulong fdt_getprop_u32(const void *fdt, int node, const char *prop);
-- 
2.25.2

Reply via email to