@@ -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=]]
@@ -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;
@@ -46,14 +46,14 @@ 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,
@@ -343,22 +343,25 @@ 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);
+ action = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
iint = integrity_iint_find(inode);
if (iint) {
iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED |
+ IMA_HASH | IMA_HASHED |
IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK |
IMA_ACTION_RULE_FLAGS);
- if (must_appraise)
+ if (action & IMA_APPRAISE)
iint->flags |= IMA_APPRAISE;
+ if (action & IMA_HASH)
+ iint->flags |= IMA_HASH;
}
- if (!must_appraise)
+ if (!action)
__vfs_removexattr(dentry, XATTR_NAME_IMA);
}
@@ -126,15 +126,17 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
return;
inode_lock(inode);
- if (atomic_read(&inode->i_writecount) == 1) {
- if ((iint->version != inode->i_version) ||
- (iint->flags & IMA_NEW_FILE)) {
- iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
- iint->measured_pcrs = 0;
- if (iint->flags & IMA_APPRAISE)
- ima_update_xattr(iint, file);
- }
+ if (atomic_read(&inode->i_writecount) != 1)
+ goto out;
+
+ if ((iint->version != inode->i_version) ||
+ (iint->flags & IMA_NEW_FILE)) {
+ iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
+ iint->measured_pcrs = 0;
+ if (iint->flags & IMA_APPRAISE || iint->flags & IMA_HASH)
+ ima_update_xattr(iint, file);
}
+out:
inode_unlock(inode);
}
@@ -223,6 +225,16 @@ 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 just sets the digital signature flag, nothing else */
+ if ((action & IMA_HASH) && !(iint->flags & IMA_DIGSIG)) {
+ xattr_len = ima_read_xattr(file->f_path.dentry, &xattr_value);
+ if ((xattr_value && xattr_len > 2) &&
+ (xattr_value->type == EVM_IMA_XATTR_DIGSIG))
+ iint->flags |= IMA_DIGSIG;
+ iint->flags |= IMA_HASHED;
+ action ^= IMA_HASH;
+ }
+
/* Nothing to do, just return existing appraised status */
if (!action) {
if (must_appraise)
@@ -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, " ");
@@ -25,6 +25,8 @@
#define IMA_COLLECTED 0x00000020
#define IMA_AUDIT 0x00000040
#define IMA_AUDITED 0x00000080
+#define IMA_HASH 0x00000100
+#define IMA_HASHED 0x00000200
/* iint cache flags */
#define IMA_ACTION_FLAGS 0xff000000
@@ -36,19 +38,20 @@
#define EVM_IMMUTABLE_DIGSIG 0x10000000
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
- IMA_APPRAISE_SUBMASK)
+ IMA_HASH | IMA_APPRAISE_SUBMASK)
#define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED | \
- IMA_COLLECTED | IMA_APPRAISED_SUBMASK)
+ IMA_HASHED | IMA_COLLECTED | \
+ IMA_APPRAISED_SUBMASK)
/* iint subaction appraise cache flags */
-#define IMA_FILE_APPRAISE 0x00000100
-#define IMA_FILE_APPRAISED 0x00000200
-#define IMA_MMAP_APPRAISE 0x00000400
-#define IMA_MMAP_APPRAISED 0x00000800
-#define IMA_BPRM_APPRAISE 0x00001000
-#define IMA_BPRM_APPRAISED 0x00002000
-#define IMA_READ_APPRAISE 0x00004000
-#define IMA_READ_APPRAISED 0x00008000
+#define IMA_FILE_APPRAISE 0x00001000
+#define IMA_FILE_APPRAISED 0x00002000
+#define IMA_MMAP_APPRAISE 0x00004000
+#define IMA_MMAP_APPRAISED 0x00008000
+#define IMA_BPRM_APPRAISE 0x00010000
+#define IMA_BPRM_APPRAISED 0x00020000
+#define IMA_READ_APPRAISE 0x00040000
+#define IMA_READ_APPRAISED 0x00080000
#define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \
IMA_BPRM_APPRAISE | IMA_READ_APPRAISE)
#define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \