Skip to contentSkip to conversation

integrity

PATCH In review Mimi Zohar 3 participants 15 messages Feb 6, 2009 – Mar 9, 2009

Subsystems (10)
lore
Share & tools
lore

Mimi Zohar

author
#0 lore raw

cover integrity

Quoted 10 lines
Quoted 2 lines

The integrity patches are in security-testing-2.6/#next and the auditd patch I just posted to linux-audit. How do you suggest we go forward?

We need to go over the event format and make sure its got everything we need in it. We also need to review the code that touches the audit system and make sure its using the audit API the way we intended. I'd like to do this on the linux-audit mail list so there is a record of it in the audit archives.

Thanks,
-Steve

As per Steve's request, I'm posting the integrity patches here. These patches are dependent on the following TPM patches:

	http://lkml.org/lkml/2009/2/2/162
	http://lkml.org/lkml/2009/2/5/151

The auditd patch was already posted here.

Mimi

James Morris (1):
IMA: fix ima_delete_rules() definition

Mimi Zohar (7):
integrity: IMA hooks
integrity: IMA as an integrity service provider
integrity: IMA display
integrity: IMA policy
integrity: IMA policy open
Integrity: IMA file free imbalance
Integrity: IMA update maintainers

author
#1 lore raw

PATCH 1/8 integrity: IMA hooks

This patch replaces the generic integrity hooks, for which IMA registered itself, with IMA integrity hooks in the appropriate places directly in the fs directory.

---

Documentation/kernel-parameters.txt +1 -0
index a2d8805..7c67b94 100644
@@ -44,6 +44,7 @@ parameter is applicable:
 	FB	The frame buffer device is enabled.
 	HW	Appropriate hardware is enabled.
 	IA-64	IA-64 architecture is enabled.
+	IMA     Integrity measurement architecture is enabled.
 	IOSCHED	More than one I/O scheduler is enabled.
 	IP_PNP	IP DHCP, BOOTP, or RARP is enabled.
 	ISAPNP	ISA PnP code is enabled.
fs/exec.c +10 -0
index 02d2e12..9c789a5 100644
@@ -45,6 +45,7 @@
 #include <linux/proc_fs.h>
 #include <linux/mount.h>
 #include <linux/security.h>
+#include <linux/ima.h>
 #include <linux/syscalls.h>
 #include <linux/tsacct_kern.h>
 #include <linux/cn_proc.h>
@@ -130,6 +131,9 @@ asmlinkage long sys_uselib(const char __user * library)
 	error = vfs_permission(&nd, MAY_READ | MAY_EXEC | MAY_OPEN);
 	if (error)
 		goto exit;
+	error = ima_path_check(&nd.path, MAY_READ | MAY_EXEC | MAY_OPEN);
+	if (error)
+		goto exit;
 
 	file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE);
 	error = PTR_ERR(file);
@@ -683,6 +687,9 @@ struct file *open_exec(const char *name)
 	err = vfs_permission(&nd, MAY_EXEC | MAY_OPEN);
 	if (err)
 		goto out_path_put;
+	err = ima_path_check(&nd.path, MAY_EXEC | MAY_OPEN);
+	if (err)
+		goto out_path_put;
 
 	file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE);
 	if (IS_ERR(file))
@@ -1209,6 +1216,9 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
 	retval = security_bprm_check(bprm);
 	if (retval)
 		return retval;
+	retval = ima_bprm_check(bprm);
+	if (retval)
+		return retval;
 
 	/* kernel module loader fixup */
 	/* so we don't try to load run modprobe in kernel space. */
fs/file_table.c +2 -0
index 0fbcacc..55895cc 100644
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/security.h>
+#include <linux/ima.h>
 #include <linux/eventpoll.h>
 #include <linux/rcupdate.h>
 #include <linux/mount.h>
@@ -276,6 +277,7 @@ void __fput(struct file *file)
 	if (file->f_op && file->f_op->release)
 		file->f_op->release(inode, file);
 	security_file_free(file);
+	ima_file_free(file);
 	if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL))
 		cdev_put(inode->i_cdev);
 	fops_put(file->f_op);
fs/inode.c +17 -7
index 098a244..ed22b14 100644
@@ -17,6 +17,7 @@
 #include <linux/hash.h>
 #include <linux/swap.h>
 #include <linux/security.h>
+#include <linux/ima.h>
 #include <linux/pagemap.h>
 #include <linux/cdev.h>
 #include <linux/bootmem.h>
@@ -144,13 +145,13 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode)
 	inode->i_cdev = NULL;
 	inode->i_rdev = 0;
 	inode->dirtied_when = 0;
-	if (security_inode_alloc(inode)) {
-		if (inode->i_sb->s_op->destroy_inode)
-			inode->i_sb->s_op->destroy_inode(inode);
-		else
-			kmem_cache_free(inode_cachep, (inode));
-		return NULL;
-	}
+
+	if (security_inode_alloc(inode))
+		goto out_free_inode;
+
+	/* allocate and initialize an i_integrity */
+	if (ima_inode_alloc(inode))
+		goto out_free_security;
 
 	spin_lock_init(&inode->i_lock);
 	lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
@@ -186,6 +187,15 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode)
 	inode->i_mapping = mapping;
 
 	return inode;
+
+out_free_security:
+	security_inode_free(inode);
+out_free_inode:
+	if (inode->i_sb->s_op->destroy_inode)
+		inode->i_sb->s_op->destroy_inode(inode);
+	else
+		kmem_cache_free(inode_cachep, (inode));
+	return NULL;
 }
 EXPORT_SYMBOL(inode_init_always);
 
fs/namei.c +8 -0
index af3783f..734f2b5 100644
@@ -24,6 +24,7 @@
 #include <linux/fsnotify.h>
 #include <linux/personality.h>
 #include <linux/security.h>
+#include <linux/ima.h>
 #include <linux/syscalls.h>
 #include <linux/mount.h>
 #include <linux/audit.h>
@@ -860,6 +861,8 @@ static int __link_path_walk(const char *name, struct nameidata *nd)
 		err = exec_permission_lite(inode);
 		if (err == -EAGAIN)
 			err = vfs_permission(nd, MAY_EXEC);
+		if (!err)
+			err = ima_path_check(&nd->path, MAY_EXEC);
  		if (err)
 			break;
 
@@ -1525,6 +1528,11 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
 	error = vfs_permission(nd, acc_mode);
 	if (error)
 		return error;
+
+	error = ima_path_check(&nd->path,
+			       acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC));
+	if (error)
+		return error;
 	/*
 	 * An append-only file must be opened in append mode for writing.
 	 */
include/linux/ima.h new file +44 -0

44 lines not on this page · raw message

mm/mmap.c +4 -0
index d4855a6..c3647f3 100644
@@ -20,6 +20,7 @@
 #include <linux/fs.h>
 #include <linux/personality.h>
 #include <linux/security.h>
+#include <linux/ima.h>
 #include <linux/hugetlb.h>
 #include <linux/profile.h>
 #include <linux/module.h>
@@ -1050,6 +1051,9 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
 	error = security_file_mmap(file, reqprot, prot, flags, addr, 0);
 	if (error)
 		return error;
+	error = ima_file_mmap(file, prot);
+	if (error)
+		return error;
 
 	return mmap_region(file, addr, len, flags, vm_flags, pgoff,
 			   accountable);
Signature · 1 line
1.5.6.6
author
#2 lore raw

PATCH 2/8 integrity: IMA as an integrity service provider

In reply to Mimi Zohar

IMA provides hardware (TPM) based measurement and attestation for file measurements. As the Trusted Computing (TPM) model requires, IMA measures all files before they are accessed in any way (on the integrity_bprm_check, integrity_path_check and integrity_file_mmap hooks), and commits the measurements to the TPM. Once added to the TPM, measurements can not be removed.

In addition, IMA maintains a list of these file measurements, which can be used to validate the aggregate value stored in the TPM. The TPM can sign these measurements, and thus the system can prove, to itself and to a third party, the system's integrity in a way that cannot be circumvented by malicious or compromised software.

- alloc ima_template_entry before calling ima_store_template()
- log ima_add_boot_aggregate() failure
- removed unused IMA_TEMPLATE_NAME_LEN
- replaced hard coded string length with #define name

---

Documentation/kernel-parameters.txt +9 -0
index 7c67b94..31e0c2c 100644
@@ -895,6 +895,15 @@ and is between 256 and 4096 characters. It is defined in the file
 	ihash_entries=	[KNL]
 			Set number of hash buckets for inode cache.
 
+	ima_audit=	[IMA]
+			Format: { "0" | "1" }
+			0 -- integrity auditing messages. (Default)
+			1 -- enable informational integrity auditing messages.
+
+	ima_hash=	[IMA]
+			Formt: { "sha1" | "md5" }
+			default: "sha1"
+
 	in2000=		[HW,SCSI]
 			See header of drivers/scsi/in2000.c.
 
include/linux/audit.h +5 -0
index 26c4f6f..8d1f677 100644
@@ -125,6 +125,11 @@
 #define AUDIT_LAST_KERN_ANOM_MSG    1799
 #define AUDIT_ANOM_PROMISCUOUS      1700 /* Device changed promiscuous mode */
 #define AUDIT_ANOM_ABEND            1701 /* Process ended abnormally */
+#define AUDIT_INTEGRITY_DATA	    1800 /* Data integrity verification */
+#define AUDIT_INTEGRITY_METADATA    1801 /* Metadata integrity verification */
+#define AUDIT_INTEGRITY_STATUS	    1802 /* Integrity enable status */
+#define AUDIT_INTEGRITY_HASH	    1803 /* Integrity HASH type */
+#define AUDIT_INTEGRITY_PCR	    1804 /* PCR invalidation msgs */
 
 #define AUDIT_KERNEL		2000	/* Asynchronous audit record. NOT A REQUEST. */
 
include/linux/ima.h +10 -0
index 4ed1e4d..dcc3664 100644
@@ -12,6 +12,15 @@
 #ifndef _LINUX_IMA_H
 #define _LINUX_IMA_H
 
+#ifdef CONFIG_IMA
+extern int ima_bprm_check(struct linux_binprm *bprm);
+extern int ima_inode_alloc(struct inode *inode);
+extern void ima_inode_free(struct inode *inode);
+extern int ima_path_check(struct path *path, int mask);
+extern void ima_file_free(struct file *file);
+extern int ima_file_mmap(struct file *file, unsigned long prot);
+
+#else
 static inline int ima_bprm_check(struct linux_binprm *bprm)
 {
 	return 0;
@@ -41,4 +50,5 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot)
 {
 	return 0;
 }
+#endif /* CONFIG_IMA_H */
 #endif /* _LINUX_IMA_H */
security/Kconfig +4 -1
index d9f47ce..a79b23f 100644
@@ -55,7 +55,8 @@ config SECURITYFS
 	bool "Enable the securityfs filesystem"
 	help
 	  This will build the securityfs filesystem.  It is currently used by
-	  the TPM bios character driver.  It is not used by SELinux or SMACK.
+	  the TPM bios character driver and IMA, an integrity provider.  It is
+	  not used by SELinux or SMACK.
 
 	  If you are unsure how to answer this question, answer N.
 
@@ -126,5 +127,7 @@ config SECURITY_DEFAULT_MMAP_MIN_ADDR
 source security/selinux/Kconfig
 source security/smack/Kconfig
 
+source security/integrity/ima/Kconfig
+
 endmenu
 
security/Makefile +4 -0
index c05c127..595536c 100644
@@ -17,3 +17,7 @@ obj-$(CONFIG_SECURITY_SELINUX)		+= selinux/built-in.o
 obj-$(CONFIG_SECURITY_SMACK)		+= smack/built-in.o
 obj-$(CONFIG_SECURITY_ROOTPLUG)		+= root_plug.o
 obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
+
+# Object integrity file lists
+subdir-$(CONFIG_IMA)			+= integrity/ima
+obj-$(CONFIG_IMA)			+= integrity/ima/built-in.o
security/integrity/ima/Kconfig new file +49 -0

49 lines not on this page · raw message

security/integrity/ima/Makefile new file +9 -0
new file mode 100644
index 0000000..9d6bf97
@@ -0,0 +1,9 @@
+#
+# Makefile for building Trusted Computing Group's(TCG) runtime Integrity
+# Measurement Architecture(IMA).
+#
+
+obj-$(CONFIG_IMA) += ima.o
+
+ima-y := ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
+	 ima_policy.o ima_iint.o ima_audit.o
security/integrity/ima/ima.h new file +135 -0

135 lines not on this page · raw message

security/integrity/ima/ima_api.c new file +190 -0

190 lines not on this page · raw message

security/integrity/ima/ima_audit.c new file +78 -0

78 lines not on this page · raw message

security/integrity/ima/ima_crypto.c new file +140 -0

140 lines not on this page · raw message

security/integrity/ima/ima_iint.c new file +185 -0

185 lines not on this page · raw message

security/integrity/ima/ima_init.c new file +90 -0

90 lines not on this page · raw message

security/integrity/ima/ima_main.c new file +280 -0

280 lines not on this page · raw message

security/integrity/ima/ima_policy.c new file +126 -0

126 lines not on this page · raw message

security/integrity/ima/ima_queue.c new file +140 -0

140 lines not on this page · raw message

Signature · 1 line
1.5.6.6
#3 lore raw

Re: [PATCH 2/8] integrity: IMA as an integrity service provider

Hi,

Thanks for sending the audit piece to the mail list so we could go over the details without bothering the whole lkml. I have some comments in line below.

Quoted 29 lines · Mimi Zohar
(quoted diff) +0 -0

b/Documentation/kernel-parameters.txt index 7c67b94..31e0c2c 100644

Documentation/kernel-parameters.txt +0 -0
@@ -895,6 +895,15 @@ and is between 256 and 4096 characters. It is defined

in the file ihash_entries= [KNL]

Documentation/kernel-parameters.txt +9 -0
 			Set number of hash buckets for inode cache.
 
+	ima_audit=	[IMA]
+			Format: { "0" | "1" }
+			0 -- integrity auditing messages. (Default)
+			1 -- enable informational integrity auditing messages.
+
+	ima_hash=	[IMA]
+			Formt: { "sha1" | "md5" }
+			default: "sha1"
+
 	in2000=		[HW,SCSI]
 			See header of drivers/scsi/in2000.c.
include/linux/audit.h +0 -0
index 26c4f6f..8d1f677 100644
@@ -125,6 +125,11 @@
 #define AUDIT_LAST_KERN_ANOM_MSG    1799
 #define AUDIT_ANOM_PROMISCUOUS      1700 /* Device changed promiscuous

mode */
#define AUDIT_ANOM_ABEND 1701 /* Process ended abnormally */

include/linux/audit.h

Quoted 2 lines
include/linux/audit.h +2 -0
+#define AUDIT_INTEGRITY_DATA	    1800 /* Data integrity verification */ 
+#define AUDIT_INTEGRITY_METADATA    1801 /* Metadata integrity verification 

*/

include/linux/audit.h line 132

Quoted 3 lines
include/linux/audit.h +3 -0
+#define AUDIT_INTEGRITY_STATUS	    1802 /* Integrity enable status */
+#define AUDIT_INTEGRITY_HASH	    1803 /* Integrity HASH type */
+#define AUDIT_INTEGRITY_PCR	    1804 /* PCR invalidation msgs */

If you are taking this block, I'd like to have the netlink block map around line 39 updated too. Sb something like:

* 1800 - 1899 integrity labels and related events
* 1900 - 1999 future kernel use

Quoted 24 lines

#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */

security/integrity/ima/ima.h new file +15 -0
new file mode 100644
index 0000000..bfa72ed
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <[email protected]>
+ * Mimi Zohar <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima.h
+ *	internal Integrity Measurement Architecture (IMA) definitions
+ */

security/integrity/ima/ima.h line 25

Quoted 10 lines
security/integrity/ima/ima.h new file +10 -0
+
+#ifndef __LINUX_IMA_H
+#define __LINUX_IMA_H
+
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/security.h>
+#include <linux/hash.h>
+#include <linux/tpm.h>
+#include <linux/audit.h>

So why did you include the audit.h file in this header? I don't see where its used for any function prototype.

Quoted 14 lines
(quoted diff) +0 -0

b/security/integrity/ima/ima_api.c new file mode 100644 index 0000000..a148a25

security/integrity/ima/ima_api.c new file +8 -0
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ *
+ * Author: Mimi Zohar <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the

security/integrity/ima/ima_api.c line 18

Quoted 10 lines
security/integrity/ima/ima_api.c new file +10 -0
+ * License.
+ *
+ * File: ima_api.c
+ *	Implements must_measure, collect_measurement, store_measurement,
+ *	and store_template.
+ */
+#include <linux/module.h>
+
+#include "ima.h"
+static char *IMA_TEMPLATE_NAME = "ima";

Would this also be a const ?

Quoted 45 lines
(quoted diff) +0 -0

b/security/integrity/ima/ima_audit.c new file mode 100644 index 0000000..8a0f1e2

security/integrity/ima/ima_audit.c new file +39 -0
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity_audit.c
+ * 	Audit calls for the integrity subsystem
+ */
+
+#include <linux/fs.h>
+#include <linux/audit.h>
+#include "ima.h"
+
+static int ima_audit;
+
+#ifdef CONFIG_IMA_AUDIT
+
+/* ima_audit_setup - enable informational auditing messages */
+static int __init ima_audit_setup(char *str)
+{
+	unsigned long audit;
+	int rc;
+	char *op;
+
+	rc = strict_strtoul(str, 0, &audit);
+	if (rc || audit > 1)
+		printk(KERN_INFO "ima: invalid ima_audit value\n");
+	else
+		ima_audit = audit;
+	op = ima_audit ? "ima_audit_enabled" : "ima_audit_not_enabled";
+	integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, NULL, op, 0, 0);
+	return 1;
+}
+__setup("ima_audit=", ima_audit_setup);
+#endif
+

security/integrity/ima/ima_audit.c line 49

Quoted 10 lines
security/integrity/ima/ima_audit.c new file +10 -0
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+			 const unsigned char *fname, const char *op,
+			 const char *cause, int result, int audit_info)
+{
+	struct audit_buffer *ab;
+
+	if (!ima_audit && audit_info == 1) /* Skip informational messages */
+		return;
+
+	ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);

Is this a standalone event or would it be an auxiliary record added to a syscall record? IOW, if I have a watch on the same file as was being measured, would the event have the same serial number?

security/integrity/ima/ima_audit.c line 50

Quoted 1 line
security/integrity/ima/ima_audit.c new file +1 -0
+	audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u",

The word "integrity:" can be deleted. All the events will have it in the event type.

security/integrity/ima/ima_audit.c line 52

Quoted 2 lines
security/integrity/ima/ima_audit.c new file +2 -0
+			 current->pid, current->cred->uid,
+			 audit_get_loginuid(current));

After logging the auid, we now require logging ses=%u for sessionid, use audit_get_sessionid() for the value. This is something that has come up in the last year, but we have it in all events now so that if someone logs in multiple times, we know which session it originated in.

If you are depending on a syscall record, it will record much of what's recorded here for itself and you won't need this much. If you wanted this to be standalone, I think the call to audit_ log_start has NULL as the first param so that it cannot be associated with a syscall.

Quoted 14 lines
security/integrity/ima/ima_audit.c new file +14 -0
+	audit_log_task_context(ab);
+	switch (audit_msgno) {
+	case AUDIT_INTEGRITY_DATA:
+	case AUDIT_INTEGRITY_METADATA:
+	case AUDIT_INTEGRITY_PCR:
+		audit_log_format(ab, " op=%s cause=%s", op, cause);
+		break;
+	case AUDIT_INTEGRITY_HASH:
+		audit_log_format(ab, " op=%s hash=%s", op, cause);
+		break;
+	case AUDIT_INTEGRITY_STATUS:
+	default:
+		audit_log_format(ab, " op=%s", op);
+	}

security/integrity/ima/ima_audit.c line 76

Quoted 10 lines
security/integrity/ima/ima_audit.c new file +10 -0
+	audit_log_format(ab, " comm=");
+	audit_log_untrustedstring(ab, current->comm);
+	if (fname) {
+		audit_log_format(ab, " name=");
+		audit_log_untrustedstring(ab, fname);
+	}
+	if (inode)
+		audit_log_format(ab, " dev=%s ino=%lu",
+				 inode->i_sb->s_id, inode->i_ino);
+	audit_log_format(ab, " res=%d", result);

Note that result should only be 0 (success) or 1 (failure). I saw earlier that a result was getting set to -ENOMEM.

Quoted 23 lines
security/integrity/ima/ima_audit.c new file +2 -0
+	audit_log_end(ab);
+}
(quoted diff) +0 -0

b/security/integrity/ima/ima_init.c new file mode 100644 index 0000000..e0f02e3

security/integrity/ima/ima_init.c new file +13 -0
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer      <[email protected]>
+ * Leendert van Doorn <[email protected]>
+ * Mimi Zohar         <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *

security/integrity/ima/ima_init.c line 23

Quoted 10 lines
security/integrity/ima/ima_init.c new file +10 -0
+ * File: ima_init.c
+ *             initialization and cleanup functions
+ */
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/err.h>
+#include "ima.h"
+
+/* name for boot aggregate entry */
+static char *boot_aggregate_name = "boot_aggregate";

const ?

Quoted 13 lines
security/integrity/ima/ima_init.c new file +13 -0
+int ima_used_chip;
+
+/* Add the boot aggregate to the IMA measurement list and extend
+ * the PCR register.
+ *
+ * Calculate the boot aggregate, a SHA1 over tpm registers 0-7,
+ * assuming a TPM chip exists, and zeroes if the TPM chip does not
+ * exist.  Add the boot aggregate measurement to the measurement
+ * list and extend the PCR register.
+ *
+ * If a tpm chip does not exist, indicate the core root of trust is
+ * not hardware based by invalidating the aggregate PCR value.
+ * (The aggregate PCR value is invalidated by adding one value to

security/integrity/ima/ima_init.c line 46

Quoted 10 lines
security/integrity/ima/ima_init.c new file +10 -0
+ * the measurement list and extending the aggregate PCR value with
+ * a different value.) Violations add a zero entry to the measurement
+ * list and extend the aggregate PCR value with ff...ff's.
+ */
+static void ima_add_boot_aggregate(void)
+{
+	struct ima_template_entry *entry;
+	const char *op = "add_boot_aggregate";
+	const char *audit_cause = "ENOMEM";
+	int result = -ENOMEM;

You can't send the audit system this value.

Quoted 5 lines
security/integrity/ima/ima_init.c new file +5 -0
+	int violation = 1;
+
+	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		goto err_out;

security/integrity/ima/ima_init.c line 61

Quoted 10 lines
security/integrity/ima/ima_init.c new file +10 -0
+
+	memset(&entry->template, 0, sizeof(entry->template));
+	strncpy(entry->template.file_name, boot_aggregate_name,
+		IMA_EVENT_NAME_LEN_MAX);
+	if (ima_used_chip) {
+		violation = 0;
+		result = ima_calc_boot_aggregate(entry->template.digest);
+		if (result < 0) {
+			audit_cause = "hashing_error";
+			kfree(entry);

You may want "!!result" so that its changed to a 1 for failure. Or maybe you want to do that in integrity_audit_msg so you only have 1 place to change it.

Quoted 24 lines
security/integrity/ima/ima_init.c new file +12 -0
+			goto err_out;
+		}
+	}
+	result = ima_store_template(entry, violation, NULL);
+	if (result < 0)
+		kfree(entry);
+	return;
+err_out:
+	integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op,
+			    audit_cause, result, 0);
+}
+
(quoted diff) +0 -0

b/security/integrity/ima/ima_policy.c new file mode 100644 index 0000000..7c3d1ff

security/integrity/ima/ima_policy.c new file +5 -0
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify

security/integrity/ima/ima_policy.c line 15

Quoted 10 lines
security/integrity/ima/ima_policy.c new file +10 -0
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * ima_policy.c
+ * 	- initialize default measure policy rules
+ *
+ */
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/audit.h>

Is audit.h really needed here?

I guess the main concern is the value of the result field.

-Steve

author
#4 lore raw

Re: [PATCH 2/8] integrity: IMA as an integrity service provider

Quoted 4 lines · Steve Grubb

Hi,

Thanks for sending the audit piece to the mail list so we could go over the details without bothering the whole lkml. I have some comments in line below.

Definitely preferable.

Quoted 40 lines · Mimi Zohar
Quoted 29 lines
(quoted diff) +0 -0

b/Documentation/kernel-parameters.txt index 7c67b94..31e0c2c 100644

Documentation/kernel-parameters.txt +0 -0
@@ -895,6 +895,15 @@ and is between 256 and 4096 characters. It is defined

in the file ihash_entries= [KNL]

Documentation/kernel-parameters.txt +9 -0
 			Set number of hash buckets for inode cache.
 
+	ima_audit=	[IMA]
+			Format: { "0" | "1" }
+			0 -- integrity auditing messages. (Default)
+			1 -- enable informational integrity auditing messages.
+
+	ima_hash=	[IMA]
+			Formt: { "sha1" | "md5" }
+			default: "sha1"
+
 	in2000=		[HW,SCSI]
 			See header of drivers/scsi/in2000.c.
include/linux/audit.h +0 -0
index 26c4f6f..8d1f677 100644
@@ -125,6 +125,11 @@
 #define AUDIT_LAST_KERN_ANOM_MSG    1799
 #define AUDIT_ANOM_PROMISCUOUS      1700 /* Device changed promiscuous

mode */
#define AUDIT_ANOM_ABEND 1701 /* Process ended abnormally */

include/linux/audit.h

Quoted 2 lines
include/linux/audit.h +2 -0
+#define AUDIT_INTEGRITY_DATA	    1800 /* Data integrity verification */ 
+#define AUDIT_INTEGRITY_METADATA    1801 /* Metadata integrity verification 

*/

include/linux/audit.h line 132

Quoted 3 lines
include/linux/audit.h +3 -0
+#define AUDIT_INTEGRITY_STATUS	    1802 /* Integrity enable status */
+#define AUDIT_INTEGRITY_HASH	    1803 /* Integrity HASH type */
+#define AUDIT_INTEGRITY_PCR	    1804 /* PCR invalidation msgs */

If you are taking this block, I'd like to have the netlink block map around line 39 updated too. Sb something like:

Quoted 4 lines

* 1800 - 1899 integrity labels and related events
* 1900 - 1999 future kernel use

Quoted 1 line

#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */

ok

Quoted 26 lines
Quoted 26 lines
security/integrity/ima/ima.h new file +20 -0
new file mode 100644
index 0000000..bfa72ed
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <[email protected]>
+ * Mimi Zohar <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima.h
+ *	internal Integrity Measurement Architecture (IMA) definitions
+ */
+
+#ifndef __LINUX_IMA_H
+#define __LINUX_IMA_H
+
+#include <linux/types.h>
Quoted 8 lines

security/integrity/ima/ima.h line 25

Quoted 5 lines
security/integrity/ima/ima.h new file +5 -0
+#include <linux/crypto.h>
+#include <linux/security.h>
+#include <linux/hash.h>
+#include <linux/tpm.h>
+#include <linux/audit.h>

So why did you include the audit.h file in this header? I don't see where its used for any function prototype.

IMA measures files based on policy, which can be described in terms of LSM specific labels using security_audit_rule_init/match.

Quoted 18 lines
Quoted 18 lines
(quoted diff) +0 -0

b/security/integrity/ima/ima_api.c new file mode 100644 index 0000000..a148a25

security/integrity/ima/ima_api.c new file +12 -0
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ *
+ * Author: Mimi Zohar <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima_api.c
+ *	Implements must_measure, collect_measurement, store_measurement,
Quoted 8 lines

security/integrity/ima/ima_api.c line 18

Quoted 6 lines
security/integrity/ima/ima_api.c new file +6 -0
+ *	and store_template.
+ */
+#include <linux/module.h>
+
+#include "ima.h"
+static char *IMA_TEMPLATE_NAME = "ima";

Would this also be a const ?

yes

Quoted 51 lines
Quoted 51 lines
(quoted diff) +0 -0

b/security/integrity/ima/ima_audit.c new file mode 100644 index 0000000..8a0f1e2

security/integrity/ima/ima_audit.c new file +45 -0
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity_audit.c
+ * 	Audit calls for the integrity subsystem
+ */
+
+#include <linux/fs.h>
+#include <linux/audit.h>
+#include "ima.h"
+
+static int ima_audit;
+
+#ifdef CONFIG_IMA_AUDIT
+
+/* ima_audit_setup - enable informational auditing messages */
+static int __init ima_audit_setup(char *str)
+{
+	unsigned long audit;
+	int rc;
+	char *op;
+
+	rc = strict_strtoul(str, 0, &audit);
+	if (rc || audit > 1)
+		printk(KERN_INFO "ima: invalid ima_audit value\n");
+	else
+		ima_audit = audit;
+	op = ima_audit ? "ima_audit_enabled" : "ima_audit_not_enabled";
+	integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, NULL, op, 0, 0);
+	return 1;
+}
+__setup("ima_audit=", ima_audit_setup);
+#endif
+
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+			 const unsigned char *fname, const char *op,
+			 const char *cause, int result, int audit_info)
+{
+	struct audit_buffer *ab;
+
Quoted 8 lines

security/integrity/ima/ima_audit.c line 49

Quoted 4 lines
security/integrity/ima/ima_audit.c new file +4 -0
+	if (!ima_audit && audit_info == 1) /* Skip informational messages */
+		return;
+
+	ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);

Is this a standalone event or would it be an auxiliary record added to a syscall record? IOW, if I have a watch on the same file as was being measured, would the event have the same serial number?

Having it as an auxiliary record to syscall seems appropriate. There seems to be different behavior if you stop auditd and if it isn't enabled at boot. In the former case the syscall message still goes to /var/log/messages, while in the latter case it doesn't.

Quoted 6 lines

security/integrity/ima/ima_audit.c line 50

Quoted 1 line
security/integrity/ima/ima_audit.c new file +1 -0
+	audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u",

The word "integrity:" can be deleted. All the events will have it in the event type.

Quoted 7 lines

security/integrity/ima/ima_audit.c line 52

Quoted 2 lines
security/integrity/ima/ima_audit.c new file +2 -0
+			 current->pid, current->cred->uid,
+			 audit_get_loginuid(current));

After logging the auid, we now require logging ses=%u for sessionid, use audit_get_sessionid() for the value. This is something that has come up in the last year, but we have it in all events now so that if someone logs in multiple times, we know which session it originated in.

ok

Quoted 4 lines

If you are depending on a syscall record, it will record much of what's recorded here for itself and you won't need this much. If you wanted this to be standalone, I think the call to audit_ log_start has NULL as the first param so that it cannot be associated with a syscall.

yes that works. Some of the messages don't need the syscall info, like in ima_parse_rules().

Quoted 11 lines
Quoted 11 lines
security/integrity/ima/ima_audit.c new file +11 -0
+	audit_log_task_context(ab);
+	switch (audit_msgno) {
+	case AUDIT_INTEGRITY_DATA:
+	case AUDIT_INTEGRITY_METADATA:
+	case AUDIT_INTEGRITY_PCR:
+		audit_log_format(ab, " op=%s cause=%s", op, cause);
+		break;
+	case AUDIT_INTEGRITY_HASH:
+		audit_log_format(ab, " op=%s hash=%s", op, cause);
+		break;
+	case AUDIT_INTEGRITY_STATUS:
Quoted 8 lines

security/integrity/ima/ima_audit.c line 71

Quoted 8 lines
security/integrity/ima/ima_audit.c new file +8 -0
+	default:
+		audit_log_format(ab, " op=%s", op);
+	}
+	audit_log_format(ab, " comm=");
+	audit_log_untrustedstring(ab, current->comm);
+	if (fname) {
+		audit_log_format(ab, " name=");
+		audit_log_untrustedstring(ab, fname);

Sure would be nice to be able to print the full pathname.

Quoted 8 lines

security/integrity/ima/ima_audit.c line 76

Quoted 5 lines
security/integrity/ima/ima_audit.c new file +5 -0
+	}
+	if (inode)
+		audit_log_format(ab, " dev=%s ino=%lu",
+				 inode->i_sb->s_id, inode->i_ino);
+	audit_log_format(ab, " res=%d", result);

Note that result should only be 0 (success) or 1 (failure). I saw earlier that a result was getting set to -ENOMEM.

ok.

Quoted 27 lines
Quoted 27 lines
security/integrity/ima/ima_audit.c new file +2 -0
+	audit_log_end(ab);
+}
(quoted diff) +0 -0

b/security/integrity/ima/ima_init.c new file mode 100644 index 0000000..e0f02e3

security/integrity/ima/ima_init.c new file +17 -0
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer      <[email protected]>
+ * Leendert van Doorn <[email protected]>
+ * Mimi Zohar         <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima_init.c
+ *             initialization and cleanup functions
+ */
+#include <linux/module.h>
Quoted 8 lines

security/integrity/ima/ima_init.c line 23

Quoted 6 lines
security/integrity/ima/ima_init.c new file +6 -0
+#include <linux/scatterlist.h>
+#include <linux/err.h>
+#include "ima.h"
+
+/* name for boot aggregate entry */
+static char *boot_aggregate_name = "boot_aggregate";

const ?

yes

Quoted 17 lines
Quoted 17 lines
security/integrity/ima/ima_init.c new file +17 -0
+int ima_used_chip;
+
+/* Add the boot aggregate to the IMA measurement list and extend
+ * the PCR register.
+ *
+ * Calculate the boot aggregate, a SHA1 over tpm registers 0-7,
+ * assuming a TPM chip exists, and zeroes if the TPM chip does not
+ * exist.  Add the boot aggregate measurement to the measurement
+ * list and extend the PCR register.
+ *
+ * If a tpm chip does not exist, indicate the core root of trust is
+ * not hardware based by invalidating the aggregate PCR value.
+ * (The aggregate PCR value is invalidated by adding one value to
+ * the measurement list and extending the aggregate PCR value with
+ * a different value.) Violations add a zero entry to the measurement
+ * list and extend the aggregate PCR value with ff...ff's.
+ */
Quoted 8 lines

security/integrity/ima/ima_init.c line 46

Quoted 6 lines
security/integrity/ima/ima_init.c new file +6 -0
+static void ima_add_boot_aggregate(void)
+{
+	struct ima_template_entry *entry;
+	const char *op = "add_boot_aggregate";
+	const char *audit_cause = "ENOMEM";
+	int result = -ENOMEM;

You can't send the audit system this value.

ok.

Quoted 48 lines
Quoted 6 lines
security/integrity/ima/ima_init.c new file +5 -0
+	int violation = 1;
+
+	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		goto err_out;

security/integrity/ima/ima_init.c line 61

Quoted 10 lines
security/integrity/ima/ima_init.c new file +10 -0
+
+	memset(&entry->template, 0, sizeof(entry->template));
+	strncpy(entry->template.file_name, boot_aggregate_name,
+		IMA_EVENT_NAME_LEN_MAX);
+	if (ima_used_chip) {
+		violation = 0;
+		result = ima_calc_boot_aggregate(entry->template.digest);
+		if (result < 0) {
+			audit_cause = "hashing_error";
+			kfree(entry);

You may want "!!result" so that its changed to a 1 for failure. Or maybe you want to do that in integrity_audit_msg so you only have 1 place to change it.

Quoted 28 lines
security/integrity/ima/ima_init.c new file +12 -0
+			goto err_out;
+		}
+	}
+	result = ima_store_template(entry, violation, NULL);
+	if (result < 0)
+		kfree(entry);
+	return;
+err_out:
+	integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op,
+			    audit_cause, result, 0);
+}
+
(quoted diff) +0 -0

b/security/integrity/ima/ima_policy.c new file mode 100644 index 0000000..7c3d1ff

security/integrity/ima/ima_policy.c new file +9 -0
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * ima_policy.c
Quoted 8 lines

security/integrity/ima/ima_policy.c line 15

Quoted 6 lines
security/integrity/ima/ima_policy.c new file +6 -0
+ * 	- initialize default measure policy rules
+ *
+ */
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/audit.h>

Is audit.h really needed here?

As it is already defined in ima.h, it isn't needed here.

Quoted 3 lines

I guess the main concern is the value of the result field.

-Steve

Ok.

Mimi

#5 lore raw

Re: [PATCH 2/8] integrity: IMA as an integrity service provider

Quoted 21 lines · Mimi Zohar
Quoted 12 lines
Quoted 12 lines
(quoted diff) +0 -0

b/security/integrity/ima/ima_audit.c new file mode 100644 index 0000000..8a0f1e2

security/integrity/ima/ima_audit.c new file +7 -0
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+			 const unsigned char *fname, const char *op,
+			 const char *cause, int result, int audit_info)
+{
+	struct audit_buffer *ab;
+
+	if (!ima_audit && audit_info == 1) /* Skip informational messages */
Quoted 8 lines
Quoted 4 lines
security/integrity/ima/ima_audit.c new file +3 -0
+		return;
+
+	ab = audit_log_start(current->audit_context, GFP_KERNEL,

audit_msgno);

Is this a standalone event or would it be an auxiliary record added to a syscall record? IOW, if I have a watch on the same file as was being measured, would the event have the same serial number?

Quoted 1 line

Having it as an auxiliary record to syscall seems appropriate.

OK. There are are three options then.

1) The first is to just supplement the syscall record whether its there or not. This is kind of what AVCs do. In that case, everything you are logging is fine.
2) Change the audit event really be an auxiliary record that is output at syscall exit only if an audit event has triggered the event. This is more like what the PATH, CWD, or EXECVE records do.
3) The last approach is to cause a syscall audit record to be emitted. This is what the MAC_STATUS does. For this case and #2 above, we could shorten the data collected since the syscall record duplicates many fields.

Quoted 3 lines

There seems to be different behavior if you stop auditd and if it isn't enabled at boot. In the former case the syscall message still goes to /var/log/messages, while in the latter case it doesn't.

It all depends on if the audit system is enabled. If its enabled, events go to either the daemon or syslog. If the audit system is not enabled, then the admin didn't want any notification.

Quoted 7 lines
Quoted 4 lines

If you are depending on a syscall record, it will record much of what's recorded here for itself and you won't need this much. If you wanted this to be standalone, I think the call to audit_ log_start has NULL as the first param so that it cannot be associated with a syscall.

yes that works. Some of the messages don't need the syscall info, like in ima_parse_rules().

The perhaps you want 2 logging functions? Or maybe pass something to the function that determines if it should be related to an existing event or its entirely async.

Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
security/integrity/ima/ima_audit.c new file +13 -0
+	audit_log_task_context(ab);
+	switch (audit_msgno) {
+	case AUDIT_INTEGRITY_DATA:
+	case AUDIT_INTEGRITY_METADATA:
+	case AUDIT_INTEGRITY_PCR:
+		audit_log_format(ab, " op=%s cause=%s", op, cause);
+		break;
+	case AUDIT_INTEGRITY_HASH:
+		audit_log_format(ab, " op=%s hash=%s", op, cause);
+		break;
+	case AUDIT_INTEGRITY_STATUS:
+	default:
+		audit_log_format(ab, " op=%s", op);
Quoted 8 lines
Quoted 6 lines

security/integrity/ima/ima_audit.c line 71

Quoted 6 lines
security/integrity/ima/ima_audit.c new file +6 -0
+	}
+	audit_log_format(ab, " comm=");
+	audit_log_untrustedstring(ab, current->comm);
+	if (fname) {
+		audit_log_format(ab, " name=");
+		audit_log_untrustedstring(ab, fname);

Sure would be nice to be able to print the full pathname.

There is an AUDIT_PATH record that should have the whole path. Its an auxiliary record emitted with the syscall.

Maybe we should talk a little about when the different events would be emitted. Would it be just on creation of the hash? Would it be just on a miscompare? IOW, how many records are likely to be created during a typical session?

Thanks,
-Steve

author
#6 lore raw

Re: [PATCH 2/8] integrity: IMA as an integrity service provider

Quoted 26 lines · Steve Grubb
Quoted 21 lines · Mimi Zohar
Quoted 12 lines
Quoted 12 lines
(quoted diff) +0 -0

b/security/integrity/ima/ima_audit.c new file mode 100644 index 0000000..8a0f1e2

security/integrity/ima/ima_audit.c new file +7 -0
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+			 const unsigned char *fname, const char *op,
+			 const char *cause, int result, int audit_info)
+{
+	struct audit_buffer *ab;
+
+	if (!ima_audit && audit_info == 1) /* Skip informational messages */
Quoted 8 lines
Quoted 4 lines
security/integrity/ima/ima_audit.c new file +3 -0
+		return;
+
+	ab = audit_log_start(current->audit_context, GFP_KERNEL,

audit_msgno);

Is this a standalone event or would it be an auxiliary record added to a syscall record? IOW, if I have a watch on the same file as was being measured, would the event have the same serial number?

Quoted 1 line

Having it as an auxiliary record to syscall seems appropriate.

OK. There are are three options then.

Quoted 9 lines

1) The first is to just supplement the syscall record whether its there or not. This is kind of what AVCs do. In that case, everything you are logging is fine.
2) Change the audit event really be an auxiliary record that is output at syscall exit only if an audit event has triggered the event. This is more like what the PATH, CWD, or EXECVE records do.
3) The last approach is to cause a syscall audit record to be emitted. This is what the MAC_STATUS does. For this case and #2 above, we could shorten the data collected since the syscall record duplicates many fields.

Seems like the first option is applicable here.

Quoted 13 lines
Quoted 3 lines

There seems to be different behavior if you stop auditd and if it isn't enabled at boot. In the former case the syscall message still goes to /var/log/messages, while in the latter case it doesn't.

It all depends on if the audit system is enabled. If its enabled, events go to either the daemon or syslog. If the audit system is not enabled, then the admin didn't want any notification.

Quoted 5 lines
Quoted 4 lines

If you are depending on a syscall record, it will record much of what's recorded here for itself and you won't need this much. If you wanted this to be standalone, I think the call to audit_ log_start has NULL as the first param so that it cannot be associated with a syscall.

Quoted 6 lines
Quoted 2 lines

yes that works. Some of the messages don't need the syscall info, like in ima_parse_rules().

The perhaps you want 2 logging functions? Or maybe pass something to the function that determines if it should be related to an existing event or its entirely async.

Ok, I've added a new integrity audit message type for policy rules. The individual policy rules don't require the syscall information. If the policy contains an invalid rule, in addition to the auditing the policy rule, audit integrity status and syscall messages are emitted.

Quoted 22 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
security/integrity/ima/ima_audit.c new file +13 -0
+	audit_log_task_context(ab);
+	switch (audit_msgno) {
+	case AUDIT_INTEGRITY_DATA:
+	case AUDIT_INTEGRITY_METADATA:
+	case AUDIT_INTEGRITY_PCR:
+		audit_log_format(ab, " op=%s cause=%s", op, cause);
+		break;
+	case AUDIT_INTEGRITY_HASH:
+		audit_log_format(ab, " op=%s hash=%s", op, cause);
+		break;
+	case AUDIT_INTEGRITY_STATUS:
+	default:
+		audit_log_format(ab, " op=%s", op);
Quoted 8 lines
Quoted 6 lines

security/integrity/ima/ima_audit.c line 71

Quoted 6 lines
security/integrity/ima/ima_audit.c new file +6 -0
+	}
+	audit_log_format(ab, " comm=");
+	audit_log_untrustedstring(ab, current->comm);
+	if (fname) {
+		audit_log_format(ab, " name=");
+		audit_log_untrustedstring(ab, fname);

Sure would be nice to be able to print the full pathname.

Quoted 2 lines

There is an AUDIT_PATH record that should have the whole path. Its an auxiliary record emitted with the syscall.

Yes, I'm seeing them now. I had forgotten to add a auditctl syscall rule. Thanks.

Quoted 7 lines

Maybe we should talk a little about when the different events would be emitted. Would it be just on creation of the hash? Would it be just on a miscompare? IOW, how many records are likely to be created during a typical session?

Thanks,
-Steve

IMA measures files, maintains a list of these measurements, and extends the PCR. These measurements are not audited, only failure to calculate the measurement, add an entry to the measurement list, or extend the PCR is audited.

Other audit messages include, runtime kernel options, updating the measurement policy, and measurement violations. The measurement violations are caused either by opening a file for write, that is already open for read (ToMToU), or by opening a file for read, that is already open for write (open_writer). The number of these errors is application dependent.

Mimi

maintainer
#7 lore raw

Re: [PATCH 2/8] integrity: IMA as an integrity service provider

In reply to Mimi Zohar

I'm very slow to the game, I know, but today was the first kernel that I built from linux-next with IMA on. I have a comment, and hopefully more to come....

Quoted 9 lines · Mimi Zohar
security/integrity/ima/ima_audit.c new file +9 -0
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+                        const unsigned char *fname, const char *op,
+                        const char *cause, int result, int audit_info)
+{
+       struct audit_buffer *ab;
+
+       if (!ima_audit && audit_info == 1) /* Skip informational messages */
+               return;
+

security/integrity/ima/ima_audit.c line 58

Quoted 10 lines
security/integrity/ima/ima_audit.c new file +10 -0
+       ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
+       audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u",
+                        current->pid, current->cred->uid,
+                        audit_get_loginuid(current));
+       audit_log_task_context(ab);
+       switch (audit_msgno) {
+       case AUDIT_INTEGRITY_DATA:
+       case AUDIT_INTEGRITY_METADATA:
+       case AUDIT_INTEGRITY_PCR:
+               audit_log_format(ab, " op=%s cause=%s", op, cause);

There are cases where (at least) cause can be a multiword string. These should be using audit_log_string() instead of %s. I'm starting to frown on %s in audit log more and more heavily these days, actually I don't think I should let any more users of %s in at all. If you want I'll go through and change all of these, but I want to make sure that you will be ok with multiword string being either "" or translated. An example of the problem I see would be in say ima_update_policy() where you have const char *cause = "already exists"; Currently that record will get emitted like:

blah cause=already exists blah

which screws up parsers. It should be:

blah cause="already exists" blah

make sense?

Quoted 19 lines
security/integrity/ima/ima_audit.c new file +19 -0
+               break;
+       case AUDIT_INTEGRITY_HASH:
+               audit_log_format(ab, " op=%s hash=%s", op, cause);
+               break;
+       case AUDIT_INTEGRITY_STATUS:
+       default:
+               audit_log_format(ab, " op=%s", op);
+       }
+       audit_log_format(ab, " comm=");
+       audit_log_untrustedstring(ab, current->comm);
+       if (fname) {
+               audit_log_format(ab, " name=");
+               audit_log_untrustedstring(ab, fname);
+       }
+       if (inode)
+               audit_log_format(ab, " dev=%s ino=%lu",
+                                inode->i_sb->s_id, inode->i_ino);
+       audit_log_format(ab, " res=%d", result);
+       audit_log_end(ab);
author
#8 lore raw

Re: [PATCH 2/8] integrity: IMA as an integrity service provider

Quoted 3 lines · Eric Paris

I'm very slow to the game, I know, but today was the first kernel that I built from linux-next with IMA on. I have a comment, and hopefully more to come....

np

Quoted 31 lines · Mimi Zohar
Quoted 9 lines
security/integrity/ima/ima_audit.c new file +9 -0
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+                        const unsigned char *fname, const char *op,
+                        const char *cause, int result, int audit_info)
+{
+       struct audit_buffer *ab;
+
+       if (!ima_audit && audit_info == 1) /* Skip informational messages */
+               return;
+

security/integrity/ima/ima_audit.c line 58

Quoted 10 lines
security/integrity/ima/ima_audit.c new file +10 -0
+       ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
+       audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u",
+                        current->pid, current->cred->uid,
+                        audit_get_loginuid(current));
+       audit_log_task_context(ab);
+       switch (audit_msgno) {
+       case AUDIT_INTEGRITY_DATA:
+       case AUDIT_INTEGRITY_METADATA:
+       case AUDIT_INTEGRITY_PCR:
+               audit_log_format(ab, " op=%s cause=%s", op, cause);

There are cases where (at least) cause can be a multiword string. These should be using audit_log_string() instead of %s. I'm starting to frown on %s in audit log more and more heavily these days, actually I don't think I should let any more users of %s in at all. If you want I'll go through and change all of these, but I want to make sure that you will be ok with multiword string being either "" or translated. An example of the problem I see would be in say ima_update_policy() where you have const char *cause = "already exists"; Currently that record will get emitted like:

Quoted 7 lines

blah cause=already exists blah

which screws up parsers. It should be:

blah cause="already exists" blah

make sense?

Oops, that should have been hyphenated, like "open_writers" below, but quoting it, and "open writers", definitely makes more sense.

type=INTEGRITY_PCR msg=audit(1235867814.206:6): integrity: pid=2089 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:initrc_t:s0 op=invalid_pcr cause=open_writers comm="update-reader.c" name="sh-thd-1235847728" dev=sda6 ino=1635223 res=0

Quoted 4 lines
Quoted 3 lines
security/integrity/ima/ima_audit.c new file +3 -0
+               break;
+       case AUDIT_INTEGRITY_HASH:
+               audit_log_format(ab, " op=%s hash=%s", op, cause);
Quoted 16 lines
Quoted 6 lines
security/integrity/ima/ima_audit.c new file +6 -0
+               break;
+       case AUDIT_INTEGRITY_STATUS:
+       default:
+               audit_log_format(ab, " op=%s", op);
+       }
+       audit_log_format(ab, " comm=");

security/integrity/ima/ima_audit.c line 77

Quoted 10 lines
security/integrity/ima/ima_audit.c new file +10 -0
+       audit_log_untrustedstring(ab, current->comm);
+       if (fname) {
+               audit_log_format(ab, " name=");
+               audit_log_untrustedstring(ab, fname);
+       }
+       if (inode)
+               audit_log_format(ab, " dev=%s ino=%lu",
+                                inode->i_sb->s_id, inode->i_ino);
+       audit_log_format(ab, " res=%d", result);
+       audit_log_end(ab);

Thanks,

Mimi

author
#9 lore raw

PATCH 3/8 integrity: IMA display

In reply to Mimi Zohar

Make the measurement lists available through securityfs.
- removed test for NULL return code from securityfs_create_file/dir

---

security/integrity/ima/Makefile +1 -1
index 9d6bf97..787c4cb 100644
@@ -5,5 +5,5 @@
 
 obj-$(CONFIG_IMA) += ima.o
 
-ima-y := ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
+ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
 	 ima_policy.o ima_iint.o ima_audit.o
security/integrity/ima/ima.h +5 -0
index bfa72ed..9c280cc 100644
@@ -67,6 +67,9 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
 /* Internal IMA function definitions */
 void ima_iintcache_init(void);
 int ima_init(void);
+void ima_cleanup(void);
+int ima_fs_init(void);
+void ima_fs_cleanup(void);
 int ima_add_template_entry(struct ima_template_entry *entry, int violation,
 			   const char *op, struct inode *inode);
 int ima_calc_hash(struct file *file, char *digest);
@@ -115,6 +118,8 @@ void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
 			   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);
 
 /* radix tree calls to lookup, insert, delete
  * integrity data associated with an inode.
security/integrity/ima/ima_fs.c new file +296 -0

296 lines not on this page · raw message

security/integrity/ima/ima_init.c +7 -1
index e0f02e3..cf227db 100644
@@ -86,5 +86,11 @@ int ima_init(void)
 
 	ima_add_boot_aggregate();	/* boot aggregate must be first entry */
 	ima_init_policy();
-	return 0;
+
+	return ima_fs_init();
+}
+
+void __exit ima_cleanup(void)
+{
+	ima_fs_cleanup();
 }
security/integrity/ima/ima_main.c +5 -0
index 53cee4c..871e356 100644
@@ -274,6 +274,11 @@ static int __init init_ima(void)
 	return error;
 }
 
+static void __exit cleanup_ima(void)
+{
+	ima_cleanup();
+}
+
 late_initcall(init_ima);	/* Start IMA after the TPM is available */
 
 MODULE_DESCRIPTION("Integrity Measurement Architecture");
Signature · 1 line
1.5.6.6
author
#10 lore raw

PATCH 4/8 integrity: IMA policy

In reply to Mimi Zohar

Support for a user loadable policy through securityfs with support for LSM specific policy data.
- free invalid rule in ima_parse_add_rule()

---

Documentation/ABI/testing/ima_policy new file +61 -0
new file mode 100644
index 0000000..6434f0d
@@ -0,0 +1,61 @@
+What:		security/ima/policy
+Date:		May 2008
+Contact:	Mimi Zohar <[email protected]>
+Description:
+		The Trusted Computing Group(TCG) runtime Integrity
+		Measurement Architecture(IMA) maintains a list of hash
+		values of executables and other sensitive system files
+		loaded into the run-time of this system.  At runtime,
+		the policy can be constrained based on LSM specific data.
+		Policies are loaded into the securityfs file ima/policy
+		by opening the file, writing the rules one at a time and
+		then closing the file.  The new policy takes effect after
+		the file ima/policy is closed.
+
+		rule format: action [condition ...]
+
+		action: measure | dont_measure
+		condition:= base | lsm
+			base:	[[func=] [mask=] [fsmagic=] [uid=]]
+			lsm:	[[subj_user=] [subj_role=] [subj_type=]
+				 [obj_user=] [obj_role=] [obj_type=]]
+
+		base: 	func:= [BPRM_CHECK][FILE_MMAP][INODE_PERMISSION]
+			mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
+			fsmagic:= hex value
+			uid:= decimal value
+		lsm:  	are LSM specific
+
+		default policy:
+			# PROC_SUPER_MAGIC
+			dont_measure fsmagic=0x9fa0
+			# SYSFS_MAGIC
+			dont_measure fsmagic=0x62656572
+			# DEBUGFS_MAGIC
+			dont_measure fsmagic=0x64626720
+			# TMPFS_MAGIC
+			dont_measure fsmagic=0x01021994
+			# SECURITYFS_MAGIC
+			dont_measure fsmagic=0x73636673
+
+			measure func=BPRM_CHECK
+			measure func=FILE_MMAP mask=MAY_EXEC
+			measure func=INODE_PERM mask=MAY_READ uid=0
+
+		The default policy measures all executables in bprm_check,
+		all files mmapped executable in file_mmap, and all files
+		open for read by root in inode_permission.
+
+		Examples of LSM specific definitions:
+
+		SELinux:
+			# SELINUX_MAGIC
+			dont_measure fsmagic=0xF97CFF8C
+
+			dont_measure obj_type=var_log_t
+			dont_measure obj_type=auditd_log_t
+			measure subj_user=system_u func=INODE_PERM mask=MAY_READ
+			measure subj_role=system_r func=INODE_PERM mask=MAY_READ
+
+		Smack:
+			measure subj_user=_ func=INODE_PERM mask=MAY_READ
security/integrity/ima/Kconfig +6 -0
index 2a761c8..3d2b6ee 100644
@@ -47,3 +47,9 @@ config IMA_AUDIT
 	  auditing messages can be enabled with 'ima_audit=1' on
 	  the kernel command line.
 
+config IMA_LSM_RULES
+	bool
+	depends on IMA && (SECURITY_SELINUX || SECURITY_SMACK)
+	default y
+	help
+	  Disabling this option will disregard LSM based policy rules
security/integrity/ima/ima.h +24 -0
index 9c280cc..42706b5 100644
@@ -137,4 +137,28 @@ enum ima_hooks { PATH_CHECK = 1, FILE_MMAP, BPRM_CHECK };
 int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask);
 void ima_init_policy(void);
 void ima_update_policy(void);
+int ima_parse_add_rule(char *);
+void ima_delete_rules(void);
+
+/* LSM based policy rules require audit */
+#ifdef CONFIG_IMA_LSM_RULES
+
+#define security_filter_rule_init security_audit_rule_init
+#define security_filter_rule_match security_audit_rule_match
+
+#else
+
+static inline int security_filter_rule_init(u32 field, u32 op, char *rulestr,
+					    void **lsmrule)
+{
+	return -EINVAL;
+}
+
+static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
+					     void *lsmrule,
+					     struct audit_context *actx)
+{
+	return -EINVAL;
+}
+#endif /* CONFIG_IMA_LSM_RULES */
 #endif
security/integrity/ima/ima_fs.c +66 -1

103 lines not on this page · raw message

security/integrity/ima/ima_policy.c +290 -3

343 lines not on this page · raw message

Signature · 1 line
1.5.6.6
author
#11 lore raw

PATCH 5/8 integrity: IMA policy open

In reply to Mimi Zohar

Sequentialize access to the policy file
- permit multiple attempts to replace default policy with a valid policy

---

security/integrity/ima/ima_fs.c +16 -1
index 95ef1ca..573780c 100644
@@ -277,16 +277,30 @@ static struct dentry *runtime_measurements_count;
 static struct dentry *violations;
 static struct dentry *ima_policy;
 
+static atomic_t policy_opencount = ATOMIC_INIT(1);
+/*
+ * ima_open_policy: sequentialize access to the policy file
+ */
+int ima_open_policy(struct inode * inode, struct file * filp)
+{
+	if (atomic_dec_and_test(&policy_opencount))
+		return 0;
+	return -EBUSY;
+}
+
 /*
  * ima_release_policy - start using the new measure policy rules.
  *
  * Initially, ima_measure points to the default policy rules, now
- * point to the new policy rules, and remove the securityfs policy file.
+ * point to the new policy rules, and remove the securityfs policy file,
+ * assuming a valid policy.
  */
 static int ima_release_policy(struct inode *inode, struct file *file)
 {
 	if (!valid_policy) {
 		ima_delete_rules();
+		valid_policy = 1;
+		atomic_set(&policy_opencount, 1);
 		return 0;
 	}
 	ima_update_policy();
@@ -296,6 +310,7 @@ static int ima_release_policy(struct inode *inode, struct file *file)
 }
 
 static struct file_operations ima_measure_policy_ops = {
+	.open = ima_open_policy,
 	.write = ima_write_policy,
 	.release = ima_release_policy
 };
Signature · 1 line
1.5.6.6
author
#12 lore raw

PATCH 6/8 Integrity: IMA file free imbalance

In reply to Mimi Zohar

The number of calls to ima_path_check()/ima_file_free() should be balanced. An extra call to fput(), indicates the file could have been accessed without first being measured.

Although f_count is incremented/decremented in places other than fget/fput, like fget_light/fput_light and get_file, the current task must already hold a file refcnt. The call to __fput() is delayed until the refcnt becomes 0, resulting in ima_file_free() flagging any changes.

- add hook to increment opencount for IPC shared memory(SYSV), shmat files, and /dev/zero
- moved NULL iint test in opencount_get()

---

include/linux/ima.h +6 -0
index dcc3664..6db30a3 100644
@@ -19,6 +19,7 @@ extern void ima_inode_free(struct inode *inode);
 extern int ima_path_check(struct path *path, int mask);
 extern void ima_file_free(struct file *file);
 extern int ima_file_mmap(struct file *file, unsigned long prot);
+extern void ima_shm_check(struct file *file);
 
 #else
 static inline int ima_bprm_check(struct linux_binprm *bprm)
@@ -50,5 +51,10 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot)
 {
 	return 0;
 }
+
+static inline void ima_shm_check(struct file *file)
+{
+	return;
+}
 #endif /* CONFIG_IMA_H */
 #endif /* _LINUX_IMA_H */
ipc/shm.c +3 -0
index 38a0557..d39bd76 100644
@@ -39,6 +39,7 @@
 #include <linux/nsproxy.h>
 #include <linux/mount.h>
 #include <linux/ipc_namespace.h>
+#include <linux/ima.h>
 
 #include <asm/uaccess.h>
 
@@ -381,6 +382,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
 	error = PTR_ERR(file);
 	if (IS_ERR(file))
 		goto no_file;
+	ima_shm_check(file);
 
 	id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
 	if (id < 0) {
@@ -888,6 +890,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
 	file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations);
 	if (!file)
 		goto out_free;
+	ima_shm_check(file);
 
 	file->private_data = sfd;
 	file->f_mapping = shp->shm_file->f_mapping;
mm/shmem.c +2 -0
index f1b0d48..dd5588f 100644
@@ -51,6 +51,7 @@
 #include <linux/highmem.h>
 #include <linux/seq_file.h>
 #include <linux/magic.h>
+#include <linux/ima.h>
 
 #include <asm/uaccess.h>
 #include <asm/div64.h>
@@ -2600,6 +2601,7 @@ int shmem_zero_setup(struct vm_area_struct *vma)
 	if (IS_ERR(file))
 		return PTR_ERR(file);
 
+	ima_shm_check(file);
 	if (vma->vm_file)
 		fput(vma->vm_file);
 	vma->vm_file = file;
security/integrity/ima/ima.h +2 -0
index 42706b5..e3c16a2 100644
@@ -97,6 +97,7 @@ static inline unsigned long ima_hash_key(u8 *digest)
 
 /* iint cache flags */
 #define IMA_MEASURED		1
+#define IMA_IINT_DUMP_STACK	512
 
 /* integrity data associated with an inode */
 struct ima_iint_cache {
@@ -106,6 +107,7 @@ struct ima_iint_cache {
 	struct mutex mutex;	/* protects: version, flags, digest */
 	long readcount;		/* measured files readcount */
 	long writecount;	/* measured files writecount */
+	long opencount;		/* opens reference count */
 	struct kref refcount;	/* ima_iint_cache reference count */
 	struct rcu_head rcu;
 };
security/integrity/ima/ima_iint.c +17 -0
index 750db3c..1f035e8 100644
@@ -126,6 +126,7 @@ struct ima_iint_cache *ima_iint_find_insert_get(struct inode *inode)
 
 	return iint;
 }
+EXPORT_SYMBOL_GPL(ima_iint_find_insert_get);
 
 /* iint_free - called when the iint refcount goes to zero */
 void iint_free(struct kref *kref)
@@ -134,6 +135,21 @@ void iint_free(struct kref *kref)
 						   refcount);
 	iint->version = 0;
 	iint->flags = 0UL;
+	if (iint->readcount != 0) {
+		printk(KERN_INFO "%s: readcount: %ld\n", __FUNCTION__,
+		       iint->readcount);
+		iint->readcount = 0;
+	}
+	if (iint->writecount != 0) {
+		printk(KERN_INFO "%s: writecount: %ld\n", __FUNCTION__,
+		       iint->writecount);
+		iint->writecount = 0;
+	}
+	if (iint->opencount != 0) {
+		printk(KERN_INFO "%s: opencount: %ld\n", __FUNCTION__,
+		       iint->opencount);
+		iint->opencount = 0;
+	}
 	kref_set(&iint->refcount, 1);
 	kmem_cache_free(iint_cache, iint);
 }
@@ -174,6 +190,7 @@ static void init_once(void *foo)
 	mutex_init(&iint->mutex);
 	iint->readcount = 0;
 	iint->writecount = 0;
+	iint->opencount = 0;
 	kref_set(&iint->refcount, 1);
 }
 
security/integrity/ima/ima_main.c +42 -0

72 lines not on this page · raw message

Signature · 1 line
1.5.6.6
author
#13 lore raw

PATCH 7/8 Integrity: IMA update maintainers

In reply to Mimi Zohar

---

MAINTAINERS +5 -0
index 6bd7d47..12fc280 100644
@@ -2175,6 +2175,11 @@ M:	[email protected]
 L:	[email protected]
 S:	Maintained
 
+INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
+P:	Mimi Zohar
+M:	[email protected]
+S:	Supported
+
 IMS TWINTURBO FRAMEBUFFER DRIVER
 L:	[email protected] (moderated for non-subscribers)
 S:	Orphan
Signature · 1 line
1.5.6.6
author
#14 lore raw

PATCH 8/8 IMA: fix ima_delete_rules() definition

In reply to Mimi Zohar

From: James Morris <[email protected]>

Fix ima_delete_rules() definition so sparse doesn't complain.

---

security/integrity/ima/ima_policy.c +1 -1
index bd45360..23810e0 100644
@@ -400,7 +400,7 @@ int ima_parse_add_rule(char *rule)
 }
 
 /* ima_delete_rules called to cleanup invalid policy */
-void ima_delete_rules()
+void ima_delete_rules(void)
 {
 	struct ima_measure_rule_entry *entry, *tmp;
 
Signature · 1 line
1.5.6.6