diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 337b3b76b28d..865137dfcf22 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -381,7 +381,8 @@ void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
 			   const unsigned char *filename,
 			   struct evm_ima_xattr_data *xattr_value,
 			   int xattr_len, const struct modsig *modsig, int pcr,
-			   struct ima_template_desc *template_desc);
+			   struct ima_template_desc *template_desc,
+			   u64 allowed_usage);
 int process_buffer_measurement(struct mnt_idmap *idmap,
 			       struct inode *inode, const void *buf, int size,
 			       const char *eventname, enum ima_hooks func,
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index f0a1ce10afe8..0bbe19e33584 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -345,7 +345,8 @@ void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
 			   const unsigned char *filename,
 			   struct evm_ima_xattr_data *xattr_value,
 			   int xattr_len, const struct modsig *modsig, int pcr,
-			   struct ima_template_desc *template_desc)
+			   struct ima_template_desc *template_desc,
+			   u64 allowed_usage)
 {
 	static const char op[] = "add_template_measure";
 	static const char audit_cause[] = "ENOMEM";
@@ -369,6 +370,18 @@ void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
 	if (iint->measured_pcrs & (0x1 << pcr) && !modsig)
 		return;
 
+	/*
+	 * If digest cache usage was authorized with the IMA policy, the digest
+	 * list the digest cache was populated from was measured, and the file
+	 * digest was found in the digest cache, mark the file as successfully
+	 * measured.
+	 */
+	if (allowed_usage & IMA_DIGEST_CACHE_MEASURE_DATA) {
+		iint->flags |= IMA_MEASURED;
+		iint->measured_pcrs |= (0x1 << pcr);
+		return;
+	}
+
 	result = ima_alloc_init_template(&event_data, &entry, template_desc);
 	if (result < 0) {
 		integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
diff --git a/security/integrity/ima/ima_digest_cache.c b/security/integrity/ima/ima_digest_cache.c
index 0b0fd26cc0d7..013c69f265d8 100644
--- a/security/integrity/ima/ima_digest_cache.c
+++ b/security/integrity/ima/ima_digest_cache.c
@@ -43,3 +43,50 @@ void ima_digest_cache_store_allowed_usage(struct file *file,
 		pr_debug("Cannot set verification mask for %s, ret: %d, ignoring\n",
 			 file_dentry(file)->d_name.name, rc);
 }
+
+/**
+ * ima_digest_cache_update_allowed_usage - Update digest cache allowed usage
+ * @file: Digest list file descriptor
+ * @iint: Inode integrity metadata
+ * @allowed_usage: Digest cache allowed usage to update
+ *
+ * Update the digest cache allowed usage obtained from the IMA policy. First,
+ * retrieve the digest cache for the passed inode, and do a lookup of the
+ * calculated digest. If the digest is found, update the digest cache allowed
+ * usage with the allowed usage from integrity metadata flags, previously stored
+ * in the digest cache itself with ima_digest_cache_store_allowed_usage().
+ */
+void ima_digest_cache_update_allowed_usage(struct file *file,
+					   struct ima_iint_cache *iint,
+					   u64 *allowed_usage)
+{
+	struct digest_cache *digest_cache, *found_cache;
+	u64 *iint_allowed_usage;
+	digest_cache_found_t found;
+
+	digest_cache = digest_cache_get(file_dentry(file));
+	if (!digest_cache) {
+		*allowed_usage = 0;
+		return;
+	}
+
+	found = digest_cache_lookup(file_dentry(file), digest_cache,
+				    iint->ima_hash->digest,
+				    iint->ima_hash->algo);
+	if (!found) {
+		*allowed_usage = 0;
+		goto out;
+	}
+
+	/* AND what is allowed by the policy, and what IMA verified. */
+	found_cache = digest_cache_from_found_t(found);
+	iint_allowed_usage = digest_cache_verif_get(found_cache, "ima");
+	if (!iint_allowed_usage) {
+		*allowed_usage = 0;
+		goto out;
+	}
+
+	*allowed_usage &= *iint_allowed_usage;
+out:
+	digest_cache_put(digest_cache);
+}
diff --git a/security/integrity/ima/ima_digest_cache.h b/security/integrity/ima/ima_digest_cache.h
index f2534a01bb18..cb47c15e975d 100644
--- a/security/integrity/ima/ima_digest_cache.h
+++ b/security/integrity/ima/ima_digest_cache.h
@@ -12,10 +12,19 @@
 #ifdef CONFIG_SECURITY_DIGEST_CACHE
 void ima_digest_cache_store_allowed_usage(struct file *file,
 					  struct ima_iint_cache *iint);
+void ima_digest_cache_update_allowed_usage(struct file *file,
+					   struct ima_iint_cache *iint,
+					   u64 *allowed_usage);
 #else
 static inline void
 ima_digest_cache_store_allowed_usage(struct file *file,
 				     struct ima_iint_cache *iint)
 { }
 
+static inline void
+ima_digest_cache_update_allowed_usage(struct file *file,
+				      struct ima_iint_cache *iint,
+				      u64 *allowed_usage)
+{ }
+
 #endif /* CONFIG_SECURITY_DIGEST_CACHE */
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 7c968cdb5678..0ff5de9bef70 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -223,6 +223,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
 	bool violation_check;
 	enum hash_algo hash_algo;
 	unsigned int allowed_algos = 0;
+	u64 digest_cache_usage = 0;
 
 	if (!ima_policy_flag || !S_ISREG(inode->i_mode))
 		return 0;
@@ -233,7 +234,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
 	 */
 	action = ima_get_action(file_mnt_idmap(file), inode, cred, secid,
 				mask, func, &pcr, &template_desc, NULL,
-				&allowed_algos, NULL);
+				&allowed_algos, &digest_cache_usage);
 	violation_check = ((func == FILE_CHECK || func == MMAP_CHECK ||
 			    func == MMAP_CHECK_REQPROT) &&
 			   (ima_policy_flag & IMA_MEASURE));
@@ -364,10 +365,19 @@ static int process_measurement(struct file *file, const struct cred *cred,
 	if (!pathbuf)	/* ima_rdwr_violation possibly pre-fetched */
 		pathname = ima_d_path(&file->f_path, &pathbuf, filename);
 
+	/*
+	 * For now we don't support nested verification with digest caches.
+	 * Since we allow IMA policy rules without func=, we have to enforce
+	 * this restriction here.
+	 */
+	if (rc == 0 && digest_cache_usage && func != DIGEST_LIST_CHECK)
+		ima_digest_cache_update_allowed_usage(file, iint,
+						      &digest_cache_usage);
+
 	if (action & IMA_MEASURE)
 		ima_store_measurement(iint, file, pathname,
 				      xattr_value, xattr_len, modsig, pcr,
-				      template_desc);
+				      template_desc, digest_cache_usage);
 	if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) {
 		rc = ima_check_blacklist(iint, modsig, pcr);
 		if (rc != -EPERM) {
