ima: audit log hashes
This adds an 'audit' policy action which audit logs file measurements.
Changelog v6:
- use new action flag handling (Dmitry Kasatkin).
- removed whitespace (Mimi)
Changelog v5:
- use audit_log_untrustedstring.
Changelog v4:
- cleanup digest -> hash conversion.
- use filename rather than d_path in ima_audit_measurement.
Changelog v3:
- Use newly exported audit_log_task_info for logging pid/ppid/uid/etc.
- Update the ima_policy ABI documentation.
Changelog v2:
- Use 'audit' action rather than 'measure_and_audit' to permit
auditing in the absence of measuring..
Changelog v1:
- Initial posting.
Signed-off-by: Peter Moody <pmoody@google.com>
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 48aa0d4..8180add 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -114,6 +114,8 @@
struct file *file);
void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
const unsigned char *filename);
+void ima_audit_measurement(struct integrity_iint_cache *iint,
+ const unsigned char *filename);
int ima_store_template(struct ima_template_entry *entry, int violation,
struct inode *inode);
void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show);
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index f0d60e7..b356884 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -114,7 +114,7 @@
*/
int ima_get_action(struct inode *inode, int mask, int function)
{
- int flags = IMA_MEASURE | IMA_APPRAISE;
+ int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE;
if (!ima_appraise)
flags &= ~IMA_APPRAISE;
@@ -207,3 +207,33 @@
if (result < 0)
kfree(entry);
}
+
+void ima_audit_measurement(struct integrity_iint_cache *iint,
+ const unsigned char *filename)
+{
+ struct audit_buffer *ab;
+ char hash[(IMA_DIGEST_SIZE * 2) + 1];
+ int i;
+
+ if (iint->flags & IMA_AUDITED)
+ return;
+
+ for (i = 0; i < IMA_DIGEST_SIZE; i++)
+ hex_byte_pack(hash + (i * 2), iint->ima_xattr.digest[i]);
+ hash[i * 2] = '\0';
+
+ ab = audit_log_start(current->audit_context, GFP_KERNEL,
+ AUDIT_INTEGRITY_RULE);
+ if (!ab)
+ return;
+
+ audit_log_format(ab, "file=");
+ audit_log_untrustedstring(ab, filename);
+ audit_log_format(ab, " hash=");
+ audit_log_untrustedstring(ab, hash);
+
+ audit_log_task_info(ab, current);
+ audit_log_end(ab);
+
+ iint->flags |= IMA_AUDITED;
+}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 5da08b7..73c9a26 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -156,8 +156,8 @@
if (!ima_initialized || !S_ISREG(inode->i_mode))
return 0;
- /* Determine if in appraise/measurement policy,
- * returns IMA_MEASURE, IMA_APPRAISE bitmask. */
+ /* Determine if in appraise/audit/measurement policy,
+ * returns IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT bitmask. */
action = ima_get_action(inode, mask, function);
if (!action)
return 0;
@@ -171,7 +171,8 @@
goto out;
/* Determine if already appraised/measured based on bitmask
- * (IMA_MEASURE, IMA_MEASURED, IMA_APPRAISE, IMA_APPRAISED) */
+ * (IMA_MEASURE, IMA_MEASURED, IMA_APPRAISE, IMA_APPRAISED,
+ * IMA_AUDIT, IMA_AUDITED) */
iint->flags |= action;
action &= ~((iint->flags & IMA_DONE_MASK) >> 1);
@@ -202,6 +203,8 @@
if (action & IMA_APPRAISE)
rc = ima_appraise_measurement(iint, file,
!pathname ? filename : pathname);
+ if (action & IMA_AUDIT)
+ ima_audit_measurement(iint, !pathname ? filename : pathname);
kfree(pathbuf);
out:
mutex_unlock(&inode->i_mutex);
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index f46f685..cda9031 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -31,6 +31,7 @@
#define DONT_MEASURE 0x0002
#define APPRAISE 0x0004 /* same as IMA_APPRAISE */
#define DONT_APPRAISE 0x0008
+#define AUDIT 0x0040
#define MAX_LSM_RULES 6
enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
@@ -277,6 +278,7 @@
Opt_err = -1,
Opt_measure = 1, Opt_dont_measure,
Opt_appraise, Opt_dont_appraise,
+ Opt_audit,
Opt_obj_user, Opt_obj_role, Opt_obj_type,
Opt_subj_user, Opt_subj_role, Opt_subj_type,
Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner
@@ -287,6 +289,7 @@
{Opt_dont_measure, "dont_measure"},
{Opt_appraise, "appraise"},
{Opt_dont_appraise, "dont_appraise"},
+ {Opt_audit, "audit"},
{Opt_obj_user, "obj_user=%s"},
{Opt_obj_role, "obj_role=%s"},
{Opt_obj_type, "obj_type=%s"},
@@ -379,6 +382,14 @@
entry->action = DONT_APPRAISE;
break;
+ case Opt_audit:
+ ima_log_string(ab, "action", "audit");
+
+ if (entry->action != UNKNOWN)
+ result = -EINVAL;
+
+ entry->action = AUDIT;
+ break;
case Opt_func:
ima_log_string(ab, "func", args[0].from);
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 564ba7d..403ba31 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -22,12 +22,15 @@
#define IMA_APPRAISED 0x0008
/*#define IMA_COLLECT 0x0010 do not use this flag */
#define IMA_COLLECTED 0x0020
+#define IMA_AUDIT 0x0040
+#define IMA_AUDITED 0x0080
/* iint cache flags */
#define IMA_DIGSIG 0x0100
-#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE)
-#define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_COLLECTED)
+#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT)
+#define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED \
+ | IMA_COLLECTED)
enum evm_ima_xattr_type {
IMA_XATTR_DIGEST = 0x01,