Commit 5244bba6 authored by Roberto Sassu's avatar Roberto Sassu Committed by Zheng Zengkai
Browse files

ima: Prevent usage of digest lists not measured or appraised



hulk inclusion
category: feature
feature: IMA Digest Lists extension
bugzilla: 46797

-------------------------------------------------

Loading a digest list affects the behavior of IMA for subsequent
operations. For example, if the digest of a file is found in a loaded
digest list, the file won't be added to the measurement list (with PCR 11).
If an administrator loaded the digest list before the IMA policy, he could
hide from verifiers the fact that files in that digest list were accessed.

To avoid this situation, this patch prevents usage of digest lists for an
IMA submodule if that submodule didn't process it. If a digest list wasn't
measured, the digest of measured files will not be searched in the digest
list and regular measurement will be performed. The same mechanism applies
for appraisal.

Signed-off-by: default avatarRoberto Sassu <roberto.sassu@huawei.com>
Signed-off-by: default avatarTianxing Zhang <zhangtianxing3@huawei.com>
Reviewed-by: default avatarJason Yan <yanaijie@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent 4bc4c4ca
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ extern int ima_extra_slots __ro_after_init;
extern int ima_appraise;
extern struct tpm_chip *ima_tpm_chip;
extern const char boot_aggregate_name[];
extern int ima_digest_list_actions;

/* IMA event related data */
struct ima_event_data {
+48 −0
Original line number Diff line number Diff line
@@ -113,6 +113,9 @@ int ima_parse_compact_list(loff_t size, void *buf, int op)
	size_t digest_len;
	int ret = 0, i;

	if (!(ima_digest_list_actions & ima_policy_flag))
		return -EACCES;

	while (bufp < bufendp) {
		if (bufp + sizeof(*hdr) > bufendp) {
			pr_err("compact list, invalid data\n");
@@ -174,3 +177,48 @@ int ima_parse_compact_list(loff_t size, void *buf, int op)

	return bufp - buf;
}

/***************************
 * Digest list usage check *
 ***************************/
void ima_check_measured_appraised(struct file *file)
{
	struct integrity_iint_cache *iint;

	if (!ima_digest_list_actions)
		return;

	iint = integrity_iint_find(file_inode(file));
	if (!iint) {
		pr_err("%s not processed, disabling digest lists lookup\n",
		       file_dentry(file)->d_name.name);
		ima_digest_list_actions = 0;
		return;
	}

	mutex_lock(&iint->mutex);
	if ((ima_digest_list_actions & IMA_MEASURE) &&
	    !(iint->flags & IMA_MEASURED)) {
		pr_err("%s not measured, disabling digest lists lookup "
		       "for measurement\n", file_dentry(file)->d_name.name);
		ima_digest_list_actions &= ~IMA_MEASURE;
	}

	if ((ima_digest_list_actions & IMA_APPRAISE) &&
	    (!(iint->flags & IMA_APPRAISED) ||
	    !test_bit(IMA_DIGSIG, &iint->atomic_flags))) {
		pr_err("%s not appraised, disabling digest lists lookup "
		       "for appraisal\n", file_dentry(file)->d_name.name);
		ima_digest_list_actions &= ~IMA_APPRAISE;
	}

	mutex_unlock(&iint->mutex);
}

struct ima_digest *ima_digest_allow(struct ima_digest *digest, int action)
{
	if (!(ima_digest_list_actions & action))
		return NULL;

	return digest;
}
+4 −0
Original line number Diff line number Diff line
@@ -23,10 +23,14 @@
extern struct ima_h_table ima_digests_htable;

int ima_parse_compact_list(loff_t size, void *buf, int op);
void ima_check_measured_appraised(struct file *file);
#else
static inline int ima_parse_compact_list(loff_t size, void *buf, int op)
{
	return -EOPNOTSUPP;
}
static inline void ima_check_measured_appraised(struct file *file)
{
}
#endif /*CONFIG_IMA_DIGEST_LIST*/
#endif /*LINUX_IMA_DIGEST_LIST_H*/
+4 −0
Original line number Diff line number Diff line
@@ -36,6 +36,10 @@ int ima_appraise;
#endif

int ima_hash_algo = HASH_ALGO_SHA1;

/* Actions (measure/appraisal) for which digest lists can be used */
int ima_digest_list_actions;

static int hash_setup_done;

static struct notifier_block ima_lsm_policy_notifier = {