Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit da1b0029 authored by Mimi Zohar's avatar Mimi Zohar
Browse files

ima: support new "hash" and "dont_hash" policy actions



The builtin ima_appraise_tcb policy, which is specified on the boot
command line, can be replaced with a custom policy, normally early in
the boot process.  Custom policies can be more restrictive in some ways,
like requiring file signatures, but can be less restrictive in other
ways, like not appraising mutable files.  With a less restrictive policy
in place, files in the builtin policy might not be hashed and labeled
with a security.ima hash.  On reboot, files which should be labeled in
the ima_appraise_tcb are not labeled, possibly preventing the system
from booting properly.

To resolve this problem, this patch extends the existing IMA policy
actions "measure", "dont_measure", "appraise", "dont_appraise", and
"audit" with "hash" and "dont_hash".  The new "hash" action will write
the file hash as security.ima, but without requiring the file to be
appraised as well.

For example, the builtin ima_appraise_tcb policy includes the rule,
"appraise fowner=0".  Adding the "hash fowner=0" rule to a custom
policy, will cause the needed file hashes to be calculated and written
as security.ima xattrs.

Signed-off-by: default avatarMimi Zohar <zohar@linux.vnet.ibm.com>
Signed-off-by: default avatarStefan Berger <stefanb@linux.vnet.ibm.com>
parent 0d73a552
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -17,7 +17,8 @@ Description:

		rule format: action [condition ...]

		action: measure | dont_measure | appraise | dont_appraise | audit
		action: measure | dont_measure | appraise | dont_appraise |
			audit | hash | dont_hash
		condition:= base | lsm  [option]
			base:	[[func=] [mask=] [fsmagic=] [fsuuid=] [uid=]
				[euid=] [fowner=]]
+1 −1
Original line number Diff line number Diff line
@@ -174,7 +174,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
 */
int ima_get_action(struct inode *inode, int mask, enum ima_hooks func, int *pcr)
{
	int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE;
	int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;

	flags &= ima_policy_flag;

+9 −7
Original line number Diff line number Diff line
@@ -46,14 +46,15 @@ bool is_ima_appraise_enabled(void)
/*
 * ima_must_appraise - set appraise flag
 *
 * Return 1 to appraise
 * Return 1 to appraise or hash
 */
int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)
{
	if (!ima_appraise)
		return 0;

	return ima_match_policy(inode, func, mask, IMA_APPRAISE, NULL);
	return ima_match_policy(inode, func, mask, IMA_APPRAISE | IMA_HASH,
				NULL);
}

static int ima_fix_xattr(struct dentry *dentry,
@@ -324,7 +325,8 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
	if (test_bit(IMA_DIGSIG, &iint->atomic_flags))
		return;

	if (iint->ima_file_status != INTEGRITY_PASS)
	if ((iint->ima_file_status != INTEGRITY_PASS) &&
	    !(iint->flags & IMA_HASH))
		return;

	rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo);
@@ -349,19 +351,19 @@ void ima_inode_post_setattr(struct dentry *dentry)
{
	struct inode *inode = d_backing_inode(dentry);
	struct integrity_iint_cache *iint;
	int must_appraise;
	int action;

	if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
	    || !(inode->i_opflags & IOP_XATTR))
		return;

	must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
	if (!must_appraise)
	action = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
	if (!action)
		__vfs_removexattr(dentry, XATTR_NAME_IMA);
	iint = integrity_iint_find(inode);
	if (iint) {
		set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);
		if (!must_appraise)
		if (!action)
			clear_bit(IMA_UPDATE_XATTR, &iint->atomic_flags);
	}
}
+12 −0
Original line number Diff line number Diff line
@@ -243,6 +243,18 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
	if ((action & IMA_MEASURE) && (iint->measured_pcrs & (0x1 << pcr)))
		action ^= IMA_MEASURE;

	/* HASH sets the digital signature and update flags, nothing else */
	if ((action & IMA_HASH) &&
	    !(test_bit(IMA_DIGSIG, &iint->atomic_flags))) {
		xattr_len = ima_read_xattr(file_dentry(file), &xattr_value);
		if ((xattr_value && xattr_len > 2) &&
		    (xattr_value->type == EVM_IMA_XATTR_DIGSIG))
			set_bit(IMA_DIGSIG, &iint->atomic_flags);
		iint->flags |= IMA_HASHED;
		action ^= IMA_HASH;
		set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags);
	}

	/* Nothing to do, just return existing appraised status */
	if (!action) {
		if (must_appraise)
+28 −2
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@
#define APPRAISE	0x0004	/* same as IMA_APPRAISE */
#define DONT_APPRAISE	0x0008
#define AUDIT		0x0040
#define HASH		0x0100
#define DONT_HASH	0x0200

#define INVALID_PCR(a) (((a) < 0) || \
	(a) >= (FIELD_SIZEOF(struct integrity_iint_cache, measured_pcrs) * 8))
@@ -380,8 +382,10 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
		action |= entry->flags & IMA_ACTION_FLAGS;

		action |= entry->action & IMA_DO_MASK;
		if (entry->action & IMA_APPRAISE)
		if (entry->action & IMA_APPRAISE) {
			action |= get_subaction(entry, func);
			action ^= IMA_HASH;
		}

		if (entry->action & IMA_DO_MASK)
			actmask &= ~(entry->action | entry->action << 1);
@@ -521,7 +525,7 @@ enum {
	Opt_err = -1,
	Opt_measure = 1, Opt_dont_measure,
	Opt_appraise, Opt_dont_appraise,
	Opt_audit,
	Opt_audit, Opt_hash, Opt_dont_hash,
	Opt_obj_user, Opt_obj_role, Opt_obj_type,
	Opt_subj_user, Opt_subj_role, Opt_subj_type,
	Opt_func, Opt_mask, Opt_fsmagic,
@@ -538,6 +542,8 @@ static match_table_t policy_tokens = {
	{Opt_appraise, "appraise"},
	{Opt_dont_appraise, "dont_appraise"},
	{Opt_audit, "audit"},
	{Opt_hash, "hash"},
	{Opt_dont_hash, "dont_hash"},
	{Opt_obj_user, "obj_user=%s"},
	{Opt_obj_role, "obj_role=%s"},
	{Opt_obj_type, "obj_type=%s"},
@@ -671,6 +677,22 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)

			entry->action = AUDIT;
			break;
		case Opt_hash:
			ima_log_string(ab, "action", "hash");

			if (entry->action != UNKNOWN)
				result = -EINVAL;

			entry->action = HASH;
			break;
		case Opt_dont_hash:
			ima_log_string(ab, "action", "dont_hash");

			if (entry->action != UNKNOWN)
				result = -EINVAL;

			entry->action = DONT_HASH;
			break;
		case Opt_func:
			ima_log_string(ab, "func", args[0].from);

@@ -1040,6 +1062,10 @@ int ima_policy_show(struct seq_file *m, void *v)
		seq_puts(m, pt(Opt_dont_appraise));
	if (entry->action & AUDIT)
		seq_puts(m, pt(Opt_audit));
	if (entry->action & HASH)
		seq_puts(m, pt(Opt_hash));
	if (entry->action & DONT_HASH)
		seq_puts(m, pt(Opt_dont_hash));

	seq_puts(m, " ");

Loading