@@ -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,
@@ -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,
@@ -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);
+}
@@ -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 */
@@ -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) {