Skip to contentSkip to conversation

integrity

PATCH In review Mimi Zohar 5 participants 17 messages Nov 13, 2008 – Dec 3, 2008

Subsystems (10)
lore
Share & tools
lore

Mimi Zohar

author
#0 lore raw

cover integrity

The Linux Integrity Module (LIM) Framework provides hooks for modules to perform collection, appraisal, and storage of system integrity measurements. One such module, IMA, collects measurements of file data, maintains this list in the kernel, and if available, stores (extends) the measurements into a hardware TPM. These measurements are collected, appraised, and stored before any access (read or execute) to the data, so that malicious code or data cannot remove or cover up its own measurement, to avoid detection. If the measurements are anchored in a TPM, the TPM can sign the measurements, for proof of integrity to a third party, such as in enterprise client management.

Integrity measurement is complementary to LSM mandatory access control, which can be used to protect the integrity of system files. Integrity measurement policies can take advantage of LSM labels in deciding what to measure and to detect when the protection fails, with hardware strength.

This patch set addresses a couple of concerns raised on the mailing list:

- Uses a radix tree to store integrity information associated with an inode, instead of extending the inode structure.
- Moves hooks out of vfs_permission and file_permission, which are deprecated.
- Fixes the template list locking.
- Updates and clarifies the integrity_audit kernel command line option.

Dave Safford
Mimi Zohar (4):
integrity: TPM internel kernel interface
integrity: Linux Integrity Module(LIM)
integrity: IMA as an integrity service provider
integrity: IMA radix tree

author
#1 lore raw

PATCH 1/4 integrity: TPM internel kernel interface

The internal TPM kernel interface did not protect itself from the removal of the TPM driver, while being used. We continue to protect the tpm_chip_list using the driver_lock as before, and are using an rcu lock to protect readers. The internal TPM kernel interface now protects itself from the driver being removed by incrementing the module reference count.

Resubmitting integrity-tpm-internal-kernel-interface.patch, which was previously Signed-off-by Kylene Hall.
Updated per feedback:

Adds the following support:
- make internal kernel interface to transmit TPM commands global
- adds reading a pcr value
- adds extending a pcr value
- adds lookup the tpm_chip for given chip number and type

---

drivers/char/tpm/tpm.c +137 -3
index 9c47dc4..17d2849 100644
@@ -1,11 +1,12 @@
 /*
- * Copyright (C) 2004 IBM Corporation
+ * Copyright (C) 2004,2007,2008 IBM Corporation
  *
  * Authors:
  * Leendert van Doorn <[email protected]>
  * Dave Safford <[email protected]>
  * Reiner Sailer <[email protected]>
  * Kylene Hall <[email protected]>
+ * Debora Velarde <[email protected]>
  *
  * Maintained by: <[email protected]>
  *
@@ -28,6 +29,14 @@
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
 
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/crypto.h>
+#include <linux/fs.h>
+#include <linux/scatterlist.h>
+#include <linux/rcupdate.h>
+#include <asm/unaligned.h>
 #include "tpm.h"
 
 enum tpm_const {
@@ -50,6 +59,8 @@ enum tpm_duration {
 static LIST_HEAD(tpm_chip_list);
 static DEFINE_SPINLOCK(driver_lock);
 static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
+#define TPM_CHIP_NUM_MASK       0x0000ffff
+#define TPM_CHIP_TYPE_SHIFT     16
 
 /*
  * Array with one entry per ordinal defining the maximum amount
@@ -366,8 +377,7 @@ EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
 /*
  * Internal kernel interface to transmit TPM commands
  */
-static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
-			    size_t bufsiz)
+ssize_t tpm_transmit(struct tpm_chip *chip, char *buf, size_t bufsiz)
 {
 	ssize_t rc;
 	u32 count, ordinal;
@@ -425,6 +435,7 @@ out:
 	mutex_unlock(&chip->tpm_mutex);
 	return rc;
 }
+EXPORT_SYMBOL_GPL(tpm_transmit);
 
 #define TPM_DIGEST_SIZE 20
 #define TPM_ERROR_SIZE 10
@@ -717,6 +728,7 @@ ssize_t tpm_show_temp_deactivated(struct device * dev,
 }
 EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated);
 
+#define READ_PCR_RESULT_SIZE 30
 static const u8 pcrread[] = {
 	0, 193,			/* TPM_TAG_RQU_COMMAND */
 	0, 0, 0, 14,		/* length */
@@ -772,6 +784,128 @@ out:
 }
 EXPORT_SYMBOL_GPL(tpm_show_pcrs);
 
+/*
+ * tpm_chip_lookup - return tpm_chip for given chip number and type
+ *
+ * Must be called with rcu_read_lock.
+ */
+static struct tpm_chip *tpm_chip_lookup(int chip_num, int chip_typ)
+{
+	struct tpm_chip *pos;
+	int rc;
+
+	list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
+		rc = (chip_num == TPM_ANY_NUM || pos->dev_num == chip_num)
+		    && (chip_typ == TPM_ANY_TYPE);
+		if (rc)
+			return pos;
+	}
+	return NULL;
+}
+
+/**
+ * tpm_pcr_read - read a pcr value
+ * @chip_id: 	tpm chip identifier
+ * 		Upper 2 bytes: ANY, HW_ONLY or SW_ONLY
+ * 		Lower 2 bytes: tpm idx # or AN&
+ * @pcr_idx:	pcr idx to retrieve
+ * @res_buf: 	TPM_PCR value
+ * 		size of res_buf is 20 bytes (or NULL if you don't care)
+ *
+ * The TPM driver should be built-in, but for whatever reason it
+ * isn't, protect against the chip disappearing, by incrementing
+ * the module usage count.
+ */
+int tpm_pcr_read(u32 chip_id, int pcr_idx, u8 *res_buf)
+{
+	u8 data[READ_PCR_RESULT_SIZE];
+	int rc;
+	__be32 index;
+	int chip_num = chip_id & TPM_CHIP_NUM_MASK;
+	struct tpm_chip *chip;
+
+	rcu_read_lock();
+	chip = tpm_chip_lookup(chip_num, chip_id >> TPM_CHIP_TYPE_SHIFT);
+	if (chip == NULL) {
+		rcu_read_unlock();
+		return -ENODEV;
+	}
+	if (!try_module_get(chip->dev->driver->owner)) {
+		rcu_read_unlock();
+		return -ENODEV;
+	}
+	rcu_read_unlock();
+
+	BUILD_BUG_ON(sizeof(pcrread) > READ_PCR_RESULT_SIZE);
+	memcpy(data, pcrread, sizeof(pcrread));
+	index = cpu_to_be32(pcr_idx);
+	memcpy(data + 10, &index, 4);
+	rc = tpm_transmit(chip, data, sizeof(data));
+	if (rc > 0)
+		rc = get_unaligned_be32((__be32 *) (data + 6));
+
+	if (rc == 0 && res_buf)
+		memcpy(res_buf, data + 10, TPM_DIGEST_SIZE);
+
+	module_put(chip->dev->driver->owner);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(tpm_pcr_read);
+
+#define EXTEND_PCR_SIZE 34
+static const u8 pcrextend[] = {
+	0, 193,			/* TPM_TAG_RQU_COMMAND */
+	0, 0, 0, 34,		/* length */
+	0, 0, 0, 20,		/* TPM_ORD_Extend */
+	0, 0, 0, 0		/* PCR index */
+};
+
+/**
+ * tpm_pcr_extend - extend pcr value with hash
+ * @chip_id: 	tpm chip identifier
+ * 		Upper 2 bytes: ANY, HW_ONLY or SW_ONLY
+ * 		Lower 2 bytes: tpm idx # or AN&
+ * @pcr_idx:	pcr idx to extend
+ * @hash: 	hash value used to extend pcr value
+ *
+ * The TPM driver should be built-in, but for whatever reason it
+ * isn't, protect against the chip disappearing, by incrementing
+ * the module usage count.
+ */
+int tpm_pcr_extend(u32 chip_id, int pcr_idx, const u8 *hash)
+{
+	u8 data[EXTEND_PCR_SIZE];
+	int rc;
+	__be32 index;
+	int chip_num = chip_id & TPM_CHIP_NUM_MASK;
+	struct tpm_chip *chip;
+
+	rcu_read_lock();
+	chip = tpm_chip_lookup(chip_num, chip_id >> TPM_CHIP_TYPE_SHIFT);
+	if (chip == NULL) {
+		rcu_read_unlock();
+		return -ENODEV;
+	}
+	if (!try_module_get(chip->dev->driver->owner)) {
+		rcu_read_unlock();
+		return -ENODEV;
+	}
+	rcu_read_unlock();
+
+	BUILD_BUG_ON(sizeof(pcrextend) > EXTEND_PCR_SIZE);
+	memcpy(data, pcrextend, sizeof(pcrextend));
+	index = cpu_to_be32(pcr_idx);
+	memcpy(data + 10, &index, 4);
+	memcpy(data + 14, hash, TPM_DIGEST_SIZE);
+	rc = tpm_transmit(chip, data, sizeof(data));
+	if (rc > 0)
+		rc = get_unaligned_be32((__be32 *) (data + 6));
+
+	module_put(chip->dev->driver->owner);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(tpm_pcr_extend);
+
 #define  READ_PUBEK_RESULT_SIZE 314
 static const u8 readpubek[] = {
 	0, 193,			/* TPM_TAG_RQU_COMMAND */
drivers/char/tpm/tpm.h +3 -1
index 8e30df4..e0ffddb 100644
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004 IBM Corporation
+ * Copyright (C) 2004, 2007, 2008 IBM Corporation
  *
  * Authors:
  * Leendert van Doorn <[email protected]>
@@ -26,6 +26,7 @@
 #include <linux/miscdevice.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/tpm.h>
 
 enum tpm_timeout {
 	TPM_TIMEOUT = 5,	/* msecs */
@@ -128,6 +129,7 @@ extern void tpm_get_timeouts(struct tpm_chip *);
 extern void tpm_gen_interrupt(struct tpm_chip *);
 extern void tpm_continue_selftest(struct tpm_chip *);
 extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
+ssize_t tpm_transmit(struct tpm_chip *chip, char *buf, size_t bufsiz);
 extern struct tpm_chip* tpm_register_hardware(struct device *,
 				 const struct tpm_vendor_specific *);
 extern int tpm_open(struct inode *, struct file *);
drivers/char/tpm/tpm_tis.c +3 -0
index 717af7a..bc26116 100644
@@ -642,6 +642,9 @@ static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev)
 
 static struct pnp_driver tis_pnp_driver = {
 	.name = "tpm_tis",
+	.driver = {
+		.owner = THIS_MODULE,
+	},
 	.id_table = tpm_pnp_tbl,
 	.probe = tpm_tis_pnp_init,
 	.suspend = tpm_tis_pnp_suspend,
include/linux/tpm.h new file +49 -0

49 lines not on this page · raw message

Signature · 1 line
1.5.5.1
author
#2 lore raw

PATCH 2/4 integrity: Linux Integrity Module(LIM)

In reply to Mimi Zohar

This version resolves the merge issues resulting from the removal of the nameidata parameter to inode_permission(), by moving the integrity_inode_permission() call from inode_permission() to may_open(), and renaming the hook to integrity_nameidata_check(). The nameidata is needed in order to open and read the file, so that the file can be hashed(a cryptographically strong checksum.)

This patch also fixes the template locking, preventing the template from being freed while being used.

This patch is a redesign of the integrity framework, which address a number of issues, including
- generalizing the measurement API beyond just inode measurements.
- separation of the measurement into distinct collection, appraisal, and commitment phases, for greater flexibility.

Extended Verification Module(EVM) and the Integrity Measurement Architecture(IMA) were originally implemented as an LSM module. Based on discussions on the LSM mailing list, a decision was made that the LSM hooks should only be used to enforce mandatory access control decisions and a new set of hooks should be defined specifically for integrity.

EVM/IMA was limited to verifying and measuring a file's (i.e. an inode) integrity and the metadata associated with it. Current research is looking into other types of integrity measurements. (i.e. "Linux kernel integrity measurement using contextual inspection", by Peter A. Loscocco, Perry W. Wilson, J. Aaron Pendergrass, C. Durward McDonell,
http://doi.acm.org/10.1145/1314354.1314362). As a result, a requirement of the new integrity framework is support for different types of integrity measurements.
This patch provides an integrity framework(api and hooks) and placement of the integrity hooks in the appropriate places in the fs directory. Collecting, appraising, and storing of file and other types of integrity data is supported. Multiple integrity templates, which implement the integrity API, may register themselves. For now, only a single integrity provider can register itself for the integrity hooks. (Support for multiple providers registering themselves for the integrity hooks would require some form of stacking.)

The six integrity hooks are:
nameidata_check_integrity, inode_alloc_integrity, inode_free_integrity, bprm_check_integrity, file_free_integrity, file_mmap

The five integrity API calls provided are:
integrity_must_measure, integrity_collect_measurement, integrity_appraise_measurement, integrity_store_measurement, and integrity_display_template.

The type of integrity data being collected, appraised, stored, or displayed is template dependent.

(Details on the calls and their exact arguments are in linux/integrity.h, included in the patch.)

---

Documentation/kernel-parameters.txt +6 -0
index 784443a..6d4d675 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.
+	INTEGRITY Integrity support 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.
@@ -911,6 +912,11 @@ and is between 256 and 4096 characters. It is defined in the file
 	inport.irq=	[HW] Inport (ATI XL and Microsoft) busmouse driver
 			Format: <irq>
 
+	integrity_audit= [INTEGRITY]
+                        Format: { "0" | "1" }
+                        0 -- integrity auditing messages. (Default)
+                        1 -- enable informational integrity auditing messages.
+
 	inttest=	[IA64]
 
 	iommu=		[x86]
fs/exec.c +7 -0
index 4e834f1..9abcaea 100644
@@ -45,6 +45,7 @@
 #include <linux/proc_fs.h>
 #include <linux/mount.h>
 #include <linux/security.h>
+#include <linux/integrity.h>
 #include <linux/syscalls.h>
 #include <linux/tsacct_kern.h>
 #include <linux/cn_proc.h>
@@ -129,6 +130,9 @@ asmlinkage long sys_uselib(const char __user * library)
 	error = vfs_permission(&nd, MAY_READ | MAY_EXEC | MAY_OPEN);
 	if (error)
 		goto exit;
+	error = integrity_nameidata_check(&nd, MAY_READ | MAY_EXEC | MAY_OPEN);
+	if (error)
+		goto exit;
 
 	file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE);
 	error = PTR_ERR(file);
@@ -1199,6 +1203,9 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
 	retval = security_bprm_check(bprm);
 	if (retval)
 		return retval;
+	retval = integrity_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 +3 -0
index 5ad0eca..74b30ba 100644
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/security.h>
+#include <linux/integrity.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);
+	integrity_file_free(file);
 	if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL))
 		cdev_put(inode->i_cdev);
 	fops_put(file->f_op);
@@ -347,6 +349,7 @@ void put_filp(struct file *file)
 {
 	if (atomic_long_dec_and_test(&file->f_count)) {
 		security_file_free(file);
+		integrity_file_free(file);
 		file_kill(file);
 		file_free(file);
 	}
fs/inode.c +16 -6
index 0487ddb..bc2c3a5 100644
@@ -17,6 +17,7 @@
 #include <linux/hash.h>
 #include <linux/swap.h>
 #include <linux/security.h>
+#include <linux/integrity.h>
 #include <linux/pagemap.h>
 #include <linux/cdev.h>
 #include <linux/bootmem.h>
@@ -143,12 +144,13 @@ static struct inode *alloc_inode(struct super_block *sb)
 		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, attach and initialize an i_integrity */
+		if (integrity_inode_alloc(inode)) {
+			security_inode_free(inode);
+			goto out_free_inode;
 		}
 
 		spin_lock_init(&inode->i_lock);
@@ -185,12 +187,20 @@ static struct inode *alloc_inode(struct super_block *sb)
 		inode->i_mapping = mapping;
 	}
 	return 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;
 }
 
 void destroy_inode(struct inode *inode) 
 {
 	BUG_ON(inode_has_buffers(inode));
 	security_inode_free(inode);
+	integrity_inode_free(inode);
 	if (inode->i_sb->s_op->destroy_inode)
 		inode->i_sb->s_op->destroy_inode(inode);
 	else
fs/namei.c +6 -0
index 09ce58e..bae619c 100644
@@ -24,6 +24,7 @@
 #include <linux/fsnotify.h>
 #include <linux/personality.h>
 #include <linux/security.h>
+#include <linux/integrity.h>
 #include <linux/syscalls.h>
 #include <linux/mount.h>
 #include <linux/audit.h>
@@ -1523,6 +1524,11 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
 	error = vfs_permission(nd, acc_mode);
 	if (error)
 		return error;
+
+	error = integrity_nameidata_check(nd, 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/audit.h +8 -0
index 6fbebac..0f6b57e 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. */
 
@@ -442,6 +447,8 @@ extern int  audit_set_loginuid(struct task_struct *task, uid_t loginuid);
 #define audit_get_loginuid(t) ((t)->loginuid)
 #define audit_get_sessionid(t) ((t)->sessionid)
 extern void audit_log_task_context(struct audit_buffer *ab);
+extern void audit_log_inode_context(struct audit_buffer *ab,
+				    struct inode *inode);
 extern int __audit_ipc_obj(struct kern_ipc_perm *ipcp);
 extern int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
 extern int audit_bprm(struct linux_binprm *bprm);
@@ -554,6 +561,7 @@ extern int audit_signals;
 #define audit_get_loginuid(t) (-1)
 #define audit_get_sessionid(t) (-1)
 #define audit_log_task_context(b) do { ; } while (0)
+#define audit_log_inode_context(b, a) do {  } while (0)
 #define audit_ipc_obj(i) ({ 0; })
 #define audit_ipc_set_perm(q,u,g,m) ({ 0; })
 #define audit_bprm(p) ({ 0; })
include/linux/fs.h +3 -0
index 0dcdd94..bc6460c 100644
@@ -683,6 +683,9 @@ struct inode {
 #ifdef CONFIG_SECURITY
 	void			*i_security;
 #endif
+#ifdef CONFIG_INTEGRITY
+	void			*i_integrity;
+#endif
 	void			*i_private; /* fs or device private pointer */
 };
 
include/linux/integrity.h new file +166 -0

166 lines not on this page · raw message

mm/mmap.c +4 -0
index de14ac2..9d74949 100644
@@ -20,6 +20,7 @@
 #include <linux/fs.h>
 #include <linux/personality.h>
 #include <linux/security.h>
+#include <linux/integrity.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 = integrity_file_mmap(file, prot);
+	if (error)
+		return error;
 
 	return mmap_region(file, addr, len, flags, vm_flags, pgoff,
 			   accountable);
security/Kconfig +2 -0
index d9f47ce..4c602be 100644
@@ -126,5 +126,7 @@ config SECURITY_DEFAULT_MMAP_MIN_ADDR
 source security/selinux/Kconfig
 source security/smack/Kconfig
 
+source security/integrity/Kconfig
+
 endmenu
 
security/Makefile +4 -0
index c05c127..db9efb5 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_INTEGRITY)		+= integrity
+obj-$(CONFIG_INTEGRITY)			+= integrity/built-in.o
security/integrity/Kconfig new file +24 -0
new file mode 100644
index 0000000..7dcb50e
@@ -0,0 +1,24 @@
+#
+# Integrity configuration
+#
+
+config INTEGRITY
+	bool "Enable different integrity models"
+	help
+	  This allows you to choose different integrity modules to be
+	  configured into your kernel. Integrity models can collect,
+	  verify, and record measurements, such as of a file's data
+	  and metadata before it is read or executed.
+
+	  If you are unsure how to answer this question, answer N.
+
+config INTEGRITY_AUDIT
+	bool "Integrity audit boot parameter"
+	depends on INTEGRITY
+	default n
+	help
+          This option adds a kernel parameter 'integrity_audit', which
+	  allows informational integrity auditing messages to be enabled
+	  at boot.  If this option is selected, informational integrity
+	  auditing messages can be enabled with 'integrity_audit=1' on
+	  the kernel command line.
security/integrity/Makefile new file +6 -0
new file mode 100644
index 0000000..a6e1405
@@ -0,0 +1,6 @@
+#
+# Makefile for the kernel integrity code
+#
+
+# Object file lists
+obj-$(CONFIG_INTEGRITY) += integrity.o integrity_audit.o
security/integrity/integrity.c new file +315 -0

315 lines not on this page · raw message

security/integrity/integrity.h new file +34 -0
new file mode 100644
index 0000000..2335b1a
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#define TEMPLATE_NAME_LEN_MAX 12
+struct template_list_entry {
+	struct list_head template;
+	char template_name[TEMPLATE_NAME_LEN_MAX + 1];
+	const struct template_operations *template_ops;
+	atomic_t refcount;
+};
+
+static inline void tget(struct template_list_entry *entry)
+{
+	if (!entry)
+		return;
+	atomic_inc(&entry->refcount);
+}
+
+static inline void tput(struct template_list_entry *entry)
+{
+	if (!entry)
+		return;
+	if (atomic_dec_and_test(&entry->refcount))
+		kfree(entry);
+}
+
+extern int integrity_find_template(const char *,
+				   struct template_list_entry **entry);
security/integrity/integrity_audit.c new file +79 -0

79 lines not on this page · raw message

Signature · 1 line
1.5.5.1
maintainer
#3 lore raw

Re: [PATCH 2/4] integrity: Linux Integrity Module(LIM)

Quoted 59 lines · On Wed, 12 Nov 2008 22:47:12 -0500 Mimi Zohar <[email protected]> wrote:

This version resolves the merge issues resulting from the removal of the nameidata parameter to inode_permission(), by moving the integrity_inode_permission() call from inode_permission() to may_open(), and renaming the hook to integrity_nameidata_check(). The nameidata is needed in order to open and read the file, so that the file can be hashed(a cryptographically strong checksum.)

This patch also fixes the template locking, preventing the template from being freed while being used.

This patch is a redesign of the integrity framework, which address a number of issues, including
- generalizing the measurement API beyond just inode measurements.
- separation of the measurement into distinct collection, appraisal, and commitment phases, for greater flexibility.

Extended Verification Module(EVM) and the Integrity Measurement Architecture(IMA) were originally implemented as an LSM module. Based on discussions on the LSM mailing list, a decision was made that the LSM hooks should only be used to enforce mandatory access control decisions and a new set of hooks should be defined specifically for integrity.

EVM/IMA was limited to verifying and measuring a file's (i.e. an inode) integrity and the metadata associated with it. Current research is looking into other types of integrity measurements. (i.e. "Linux kernel integrity measurement using contextual inspection", by Peter A. Loscocco, Perry W. Wilson, J. Aaron Pendergrass, C. Durward McDonell,
http://doi.acm.org/10.1145/1314354.1314362). As a result, a requirement of the new integrity framework is support for different types of integrity measurements.
This patch provides an integrity framework(api and hooks) and placement of the integrity hooks in the appropriate places in the fs directory. Collecting, appraising, and storing of file and other types of integrity data is supported. Multiple integrity templates, which implement the integrity API, may register themselves. For now, only a single integrity provider can register itself for the integrity hooks. (Support for multiple providers registering themselves for the integrity hooks would require some form of stacking.)

The six integrity hooks are:
nameidata_check_integrity, inode_alloc_integrity, inode_free_integrity, bprm_check_integrity, file_free_integrity, file_mmap

The five integrity API calls provided are:
integrity_must_measure, integrity_collect_measurement, integrity_appraise_measurement, integrity_store_measurement, and integrity_display_template.

The type of integrity data being collected, appraised, stored, or displayed is template dependent.

...

security/integrity/integrity.c new file +4 -0
+int integrity_register_template(const char *template_name,
+				const struct template_operations *template_ops)
+{
+	int template_len;

security/integrity/integrity.c line 86

Quoted 10 lines
security/integrity/integrity.c new file +10 -0
+	struct template_list_entry *entry;
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+	INIT_LIST_HEAD(&entry->template);
+
+	atomic_set(&entry->refcount, 1);
+	template_len = strlen(template_name);
+	if (template_len > TEMPLATE_NAME_LEN_MAX) {

It would be much neater to perform this check before running kzalloc().

Quoted 5 lines
security/integrity/integrity.c new file +5 -0
+		kfree(entry);
+		return -EINVAL;
+	}
+	strcpy(entry->template_name, template_name);
+	entry->template_ops = template_ops;

security/integrity/integrity.c line 101

Quoted 10 lines
security/integrity/integrity.c new file +10 -0
+
+	mutex_lock(&integrity_templates_mutex);
+	list_add_rcu(&entry->template, &integrity_templates);
+	mutex_unlock(&integrity_templates_mutex);
+	synchronize_rcu();
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(integrity_register_template);

someone forgot to run checkpatch.

Quoted 7 lines

...

security/integrity/integrity.h new file +4 -0
+static inline void tget(struct template_list_entry *entry)
+{
+	if (!entry)
+		return;

security/integrity/integrity.h line 31

Quoted 10 lines
security/integrity/integrity.h new file +10 -0
+	atomic_inc(&entry->refcount);
+}
+
+static inline void tput(struct template_list_entry *entry)
+{
+	if (!entry)
+		return;
+	if (atomic_dec_and_test(&entry->refcount))
+		kfree(entry);
+}

Do these _really_ need to test for a NULL pointer? It's an extra test-n-branch in many fastpaths. It would be better to avoid doing this here, if poss.

author
#4 lore raw

Re: [PATCH 2/4] integrity: Linux Integrity Module(LIM)

Quoted 58 lines · Andrew Morton
Quoted 55 lines · On Wed, 12 Nov 2008 22:47:12 -0500 Mimi Zohar <[email protected]> wrote:

This version resolves the merge issues resulting from the removal of the nameidata parameter to inode_permission(), by moving the integrity_inode_permission() call from inode_permission() to may_open(), and renaming the hook to integrity_nameidata_check(). The nameidata is needed in order to open and read the file, so that the file can be hashed(a cryptographically strong checksum.)

This patch also fixes the template locking, preventing the template from being freed while being used.

This patch is a redesign of the integrity framework, which address a number of issues, including
- generalizing the measurement API beyond just inode measurements.
- separation of the measurement into distinct collection, appraisal, and commitment phases, for greater flexibility.

Extended Verification Module(EVM) and the Integrity Measurement Architecture(IMA) were originally implemented as an LSM module. Based on discussions on the LSM mailing list, a decision was made that the LSM hooks should only be used to enforce mandatory access control decisions and a new set of hooks should be defined specifically for integrity.

EVM/IMA was limited to verifying and measuring a file's (i.e. an inode) integrity and the metadata associated with it. Current research is looking into other types of integrity measurements. (i.e. "Linux kernel integrity measurement using contextual inspection", by Peter A. Loscocco, Perry W. Wilson, J. Aaron Pendergrass, C. Durward McDonell,
http://doi.acm.org/10.1145/1314354.1314362). As a result, a requirement of the new integrity framework is support for different types of integrity measurements.
This patch provides an integrity framework(api and hooks) and placement of the integrity hooks in the appropriate places in the fs directory. Collecting, appraising, and storing of file and other types of integrity data is supported. Multiple integrity templates, which implement the integrity API, may register themselves. For now, only a single integrity provider can register itself for the integrity hooks. (Support for multiple providers registering themselves for the integrity hooks would require some form of stacking.)

The six integrity hooks are:
nameidata_check_integrity, inode_alloc_integrity, inode_free_integrity, bprm_check_integrity, file_free_integrity, file_mmap

The five integrity API calls provided are:
integrity_must_measure, integrity_collect_measurement, integrity_appraise_measurement, integrity_store_measurement, and integrity_display_template.

The type of integrity data being collected, appraised, stored, or displayed is template dependent.

...

Quoted 16 lines
Quoted 4 lines
security/integrity/integrity.c new file +4 -0
+int integrity_register_template(const char *template_name,
+				const struct template_operations *template_ops)
+{
+	int template_len;

security/integrity/integrity.c line 86

Quoted 10 lines
security/integrity/integrity.c new file +10 -0
+	struct template_list_entry *entry;
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+	INIT_LIST_HEAD(&entry->template);
+
+	atomic_set(&entry->refcount, 1);
+	template_len = strlen(template_name);
+	if (template_len > TEMPLATE_NAME_LEN_MAX) {

It would be much neater to perform this check before running kzalloc().

Yes, will be moved in next patch set.

Quoted 9 lines
Quoted 9 lines
security/integrity/integrity.c new file +9 -0
+		kfree(entry);
+		return -EINVAL;
+	}
+	strcpy(entry->template_name, template_name);
+	entry->template_ops = template_ops;
+
+	mutex_lock(&integrity_templates_mutex);
+	list_add_rcu(&entry->template, &integrity_templates);
+	mutex_unlock(&integrity_templates_mutex);
Quoted 8 lines

security/integrity/integrity.c line 101

Quoted 6 lines
security/integrity/integrity.c new file +6 -0
+	synchronize_rcu();
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(integrity_register_template);

someone forgot to run checkpatch.

There's a couple of things like this where Lindent "fixes", and then checkpatch complains. In this case though, Lindent has been fixed. :-)

Quoted 13 lines
Quoted 13 lines

...

security/integrity/integrity.h new file +10 -0
+static inline void tget(struct template_list_entry *entry)
+{
+	if (!entry)
+		return;
+	atomic_inc(&entry->refcount);
+}
+
+static inline void tput(struct template_list_entry *entry)
+{
+	if (!entry)
Quoted 8 lines

security/integrity/integrity.h line 31

Quoted 4 lines
security/integrity/integrity.h new file +4 -0
+		return;
+	if (atomic_dec_and_test(&entry->refcount))
+		kfree(entry);
+}

Do these _really_ need to test for a NULL pointer? It's an extra test-n-branch in many fastpaths. It would be better to avoid doing this here, if poss.

Cleaned up the callers to avoid requiring the extra test.

Mimi

#5 lore raw

Re: [PATCH 2/4] integrity: Linux Integrity Module(LIM)

In reply to Mimi Zohar
Quoted 4 lines · Mimi Zohar

This version resolves the merge issues resulting from the removal of the nameidata parameter to inode_permission(), by moving the integrity_inode_permission() call from inode_permission() to may_open(), and renaming the hook to integrity_nameidata_check().

Still neither a good parameter nor a good name. If you look at fsdevel you'll see that a patch for the next merged window is already out and in Al's to be applied queue that removes the nameidata there. A strcut path and maybe the MAY_ lookup flags should be enough for you, and a integrity_path_check also sounds like it really does what you want.

Also please merge the last radix tree patch into this one so tat it's possible to review the code that actually goes in instead of replacing a large part of it in a follow-up patch.

author
#6 lore raw

Re: [PATCH 2/4] integrity: Linux Integrity Module(LIM)

Quoted 6 lines · Christoph Hellwig
Quoted 4 lines · Mimi Zohar

This version resolves the merge issues resulting from the removal of the nameidata parameter to inode_permission(), by moving the integrity_inode_permission() call from inode_permission() to may_open(), and renaming the hook to integrity_nameidata_check().

Quoted 6 lines

Still neither a good parameter nor a good name. If you look at fsdevel you'll see that a patch for the next merged window is already out and in Al's to be applied queue that removes the nameidata there. A strcut path and maybe the MAY_ lookup flags should be enough for you, and a integrity_path_check also sounds like it really does what you want.

Ok. So, instead of integrity_nameidata_check(nd, flags), call it integrity_path_check(path, flags).

Perhaps I'm looking at the wrong vfs tree, but I don't see the changes. Where is fsdevel?

Quoted 3 lines

Also please merge the last radix tree patch into this one so tat it's possible to review the code that actually goes in instead of replacing a large part of it in a follow-up patch.

np

Mimi

#7 lore raw

Re: [PATCH 2/4] integrity: Linux Integrity Module(LIM)

Quoted 2 lines · Mimi Zohar

Ok. So, instead of integrity_nameidata_check(nd, flags), call it integrity_path_check(path, flags).

Yeah.

Quoted 2 lines

Perhaps I'm looking at the wrong vfs tree, but I don't see the changes. Where is fsdevel?

linux-fsdevel@vger. But the patch actually went to lkml, "[PATCH] pass a struct path * to may_open". Note that the plan is to reduce availability of strut nameidata to a minimum outside of the core path lookup functionality - so relying on it is not a good idea.

author
#8 lore raw

PATCH 3/4 integrity: IMA as an integrity service provider

In reply to Mimi Zohar

This is a re-release of Integrity Measurement Architecture(IMA) as an independent Linunx Integrity Module(LIM) service provider.

As a LIM integrity provider, IMA implements the new LIM must_measure(), collect_measurement(), store_measurement(), and display_template() API calls. The store_measurement() call supports two types of data, IMA (i.e. file data) and generic template data.

IMA provides hardware (TPM) based measurement and attestation for both files and other types of template measurements. As the Trusted Computing (TPM) model requires, IMA measures all files before they are accessed in any way (on the bprm_check_integrity, nameidata_check_integrity, file_mmap hooks), and commits the measurements to the TPM. In addition, IMA maintains a list of these hash values, which can be used to validate the aggregate PCR value. The TPM can sign these measurements, and thus the system can prove to itself and to a third party these measurements in a way that cannot be circumvented by malicious or compromised software.

When store_measurement() is called for the IMA type of data, the file measurement and the file name hint are used to form an IMA template. IMA then calculates the IMA template measurement(hash) and submits it to the TPM chip for inclusion in one of the chip's Platform Configuration Registers (PCR).

When store_measurement() is called for generic template data, IMA calculates the measurement(hash) of the template data, and submits the template measurement to the TPM chip for inclusion in one of the chip's Platform Configuration Registers(PCR).

In order to view the contents of template data through securityfs, the template_display() function must be defined in the registered template_operations. In the case of the IMA template, the list of file names and files hashes submitted can be viewed through securityfs.

As mentioned above, IMA maintains a list of hash values of executables and other sensitive system files loaded into the run-time of the system. Our work has shown that requests for integrity appraisal and measurement need to be based on knowledge of the filesystem, requiring the system to either be labeled with integrity data or depend on the existent LSM security labels. The previous set of integrity patches modified the LSM modules to be integrity context aware, meaning that the LSM modules made integrity data/metadata appraisal and measurement API calls based on an understanding of the LSM security labels. Both of the LSM maintainers felt that the changes were too intrusive and that integrity enforcement should be made by the integrity provider, not the LSM module.

To address these concerns, Stephen Smalley suggested using the security_audit_rule_match(), renamed to security_filter_rule_match(), to define LSM specific integrity measurement policy rules, in lieu of modifying the LSM modules. In the current set of patches, the integrity API calls can be made either by IMA, based on an LSM specific integrity policy, or by an integrity context aware LSM.

---

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
Documentation/kernel-parameters.txt +5 -0
index 6d4d675..bc49a4a 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.
 	INTEGRITY Integrity support is enabled.
 	IOSCHED	More than one I/O scheduler is enabled.
 	IP_PNP	IP DHCP, BOOTP, or RARP is enabled.
@@ -895,6 +896,10 @@ 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_hash=	[IMA] runtime ability to define hash crypto algorithm.
+			Format: { "MD5" | "SHA1" }
+			Default is "SHA1".
+
 	in2000=		[HW,SCSI]
 			See header of drivers/scsi/in2000.c.
 
include/linux/ima.h new file +46 -0

46 lines not on this page · raw message

security/integrity/Kconfig +2 -0
index 7dcb50e..0daee7c 100644
@@ -22,3 +22,5 @@ config INTEGRITY_AUDIT
 	  at boot.  If this option is selected, informational integrity
 	  auditing messages can be enabled with 'integrity_audit=1' on
 	  the kernel command line.
+
+source security/integrity/ima/Kconfig
security/integrity/Makefile +1 -0
index a6e1405..107dafd 100644
@@ -4,3 +4,4 @@
 
 # Object file lists
 obj-$(CONFIG_INTEGRITY) += integrity.o integrity_audit.o
+obj-$(CONFIG_IMA) += ima/
security/integrity/ima/Kconfig new file +47 -0

47 lines not on this page · raw message

security/integrity/ima/Makefile new file +9 -0
new file mode 100644
index 0000000..f3aced4
@@ -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_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
+	 ima_policy.o
security/integrity/ima/ima.h new file +174 -0

174 lines not on this page · raw message

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

375 lines not on this page · raw message

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

153 lines not on this page · raw message

security/integrity/ima/ima_fs.c new file +478 -0

478 lines not on this page · raw message

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

105 lines not on this page · raw message

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

353 lines not on this page · raw message

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

334 lines not on this page · raw message

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

124 lines not on this page · raw message

Signature · 1 line
1.5.5.1
maintainer
#9 lore raw

Re: [PATCH 3/4] integrity: IMA as an integrity service provider

Quoted 55 lines · On Wed, 12 Nov 2008 22:47:13 -0500 Mimi Zohar <[email protected]> wrote:

This is a re-release of Integrity Measurement Architecture(IMA) as an independent Linunx Integrity Module(LIM) service provider.

As a LIM integrity provider, IMA implements the new LIM must_measure(), collect_measurement(), store_measurement(), and display_template() API calls. The store_measurement() call supports two types of data, IMA (i.e. file data) and generic template data.

IMA provides hardware (TPM) based measurement and attestation for both files and other types of template measurements. As the Trusted Computing (TPM) model requires, IMA measures all files before they are accessed in any way (on the bprm_check_integrity, nameidata_check_integrity, file_mmap hooks), and commits the measurements to the TPM. In addition, IMA maintains a list of these hash values, which can be used to validate the aggregate PCR value. The TPM can sign these measurements, and thus the system can prove to itself and to a third party these measurements in a way that cannot be circumvented by malicious or compromised software.

When store_measurement() is called for the IMA type of data, the file measurement and the file name hint are used to form an IMA template. IMA then calculates the IMA template measurement(hash) and submits it to the TPM chip for inclusion in one of the chip's Platform Configuration Registers (PCR).

When store_measurement() is called for generic template data, IMA calculates the measurement(hash) of the template data, and submits the template measurement to the TPM chip for inclusion in one of the chip's Platform Configuration Registers(PCR).

In order to view the contents of template data through securityfs, the template_display() function must be defined in the registered template_operations. In the case of the IMA template, the list of file names and files hashes submitted can be viewed through securityfs.

As mentioned above, IMA maintains a list of hash values of executables and other sensitive system files loaded into the run-time of the system. Our work has shown that requests for integrity appraisal and measurement need to be based on knowledge of the filesystem, requiring the system to either be labeled with integrity data or depend on the existent LSM security labels. The previous set of integrity patches modified the LSM modules to be integrity context aware, meaning that the LSM modules made integrity data/metadata appraisal and measurement API calls based on an understanding of the LSM security labels. Both of the LSM maintainers felt that the changes were too intrusive and that integrity enforcement should be made by the integrity provider, not the LSM module.

To address these concerns, Stephen Smalley suggested using the security_audit_rule_match(), renamed to security_filter_rule_match(), to define LSM specific integrity measurement policy rules, in lieu of modifying the LSM modules. In the current set of patches, the integrity API calls can be made either by IMA, based on an LSM specific integrity policy, or by an integrity context aware LSM.

...

security/integrity/ima/ima_init.c line 35

Quoted 9 lines
security/integrity/ima/ima_init.c new file +9 -0
+static void ima_add_boot_aggregate(void)
+{
+	/* cumulative sha1 over tpm registers 0-7 */
+	struct ima_measure_entry *entry;
+	size_t count;
+	int err;
+
+	/* create new entry for boot aggregate */
+	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);

This uses GFP_ATOMIC, but crypto_alloc_hash() (called later) uses GFP_KERNEL.

If this _had_ to be GFP_ATOMIC then you have a bug.

Otherwise, please use the much more reliable GFP_KERNEL here.

author
#10 lore raw

Re: [PATCH 3/4] integrity: IMA as an integrity service provider

Quoted 71 lines · Andrew Morton
Quoted 55 lines · On Wed, 12 Nov 2008 22:47:13 -0500 Mimi Zohar <[email protected]> wrote:

This is a re-release of Integrity Measurement Architecture(IMA) as an independent Linunx Integrity Module(LIM) service provider.

As a LIM integrity provider, IMA implements the new LIM must_measure(), collect_measurement(), store_measurement(), and display_template() API calls. The store_measurement() call supports two types of data, IMA (i.e. file data) and generic template data.

IMA provides hardware (TPM) based measurement and attestation for both files and other types of template measurements. As the Trusted Computing (TPM) model requires, IMA measures all files before they are accessed in any way (on the bprm_check_integrity, nameidata_check_integrity, file_mmap hooks), and commits the measurements to the TPM. In addition, IMA maintains a list of these hash values, which can be used to validate the aggregate PCR value. The TPM can sign these measurements, and thus the system can prove to itself and to a third party these measurements in a way that cannot be circumvented by malicious or compromised software.

When store_measurement() is called for the IMA type of data, the file measurement and the file name hint are used to form an IMA template. IMA then calculates the IMA template measurement(hash) and submits it to the TPM chip for inclusion in one of the chip's Platform Configuration Registers (PCR).

When store_measurement() is called for generic template data, IMA calculates the measurement(hash) of the template data, and submits the template measurement to the TPM chip for inclusion in one of the chip's Platform Configuration Registers(PCR).

In order to view the contents of template data through securityfs, the template_display() function must be defined in the registered template_operations. In the case of the IMA template, the list of file names and files hashes submitted can be viewed through securityfs.

As mentioned above, IMA maintains a list of hash values of executables and other sensitive system files loaded into the run-time of the system. Our work has shown that requests for integrity appraisal and measurement need to be based on knowledge of the filesystem, requiring the system to either be labeled with integrity data or depend on the existent LSM security labels. The previous set of integrity patches modified the LSM modules to be integrity context aware, meaning that the LSM modules made integrity data/metadata appraisal and measurement API calls based on an understanding of the LSM security labels. Both of the LSM maintainers felt that the changes were too intrusive and that integrity enforcement should be made by the integrity provider, not the LSM module.

To address these concerns, Stephen Smalley suggested using the security_audit_rule_match(), renamed to security_filter_rule_match(), to define LSM specific integrity measurement policy rules, in lieu of modifying the LSM modules. In the current set of patches, the integrity API calls can be made either by IMA, based on an LSM specific integrity policy, or by an integrity context aware LSM.

...

security/integrity/ima/ima_init.c line 35

Quoted 9 lines
security/integrity/ima/ima_init.c new file +9 -0
+static void ima_add_boot_aggregate(void)
+{
+	/* cumulative sha1 over tpm registers 0-7 */
+	struct ima_measure_entry *entry;
+	size_t count;
+	int err;
+
+	/* create new entry for boot aggregate */
+	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);

This uses GFP_ATOMIC, but crypto_alloc_hash() (called later) uses GFP_KERNEL.

Quoted 1 line

If this _had_ to be GFP_ATOMIC then you have a bug.

Sorry, thought I fixed this.

Quoted 1 line

Otherwise, please use the much more reliable GFP_KERNEL here.

author
#11 lore raw

PATCH 4/4 integrity: IMA radix tree

In reply to Mimi Zohar

This version stores integrity information associated with an inode in a radix tree in order to avoid bloating the in memory inode. As entries can not be added to the radix tree at security_initcall, this version removes the dual stage initialization. Allocating and freeing the memory continues to be done at inode_alloc and file_free, respectively, except for inodes created before late_initcall.

---

include/linux/fs.h +0 -3
index bc6460c..0dcdd94 100644
@@ -683,9 +683,6 @@ struct inode {
 #ifdef CONFIG_SECURITY
 	void			*i_security;
 #endif
-#ifdef CONFIG_INTEGRITY
-	void			*i_integrity;
-#endif
 	void			*i_private; /* fs or device private pointer */
 };
 
security/integrity/ima/Makefile +1 -1
index f3aced4..959ae66 100644
@@ -6,4 +6,4 @@
 obj-$(CONFIG_IMA) += ima.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_policy.o ima_iint.o
security/integrity/ima/ima.h +26 -2
index 9a24305..09a5e1a 100644
@@ -92,7 +92,6 @@ void ima_store_measurement(void *d);
 void ima_template_show(struct seq_file *m, void *e,
 		       enum integrity_show_type show);
 
-
 /*
  * used to protect h_table and sha_table
  */
@@ -109,7 +108,7 @@ extern struct ima_h_table ima_htable;
 
 static inline unsigned long IMA_HASH_KEY(u8 *digest)
 {
-	 return(hash_long(*digest, IMA_HASH_BITS));
+	return (hash_long(*digest, IMA_HASH_BITS));
 }
 
 /* TPM "Glue" definitions */
@@ -145,11 +144,36 @@ struct ima_iint_cache {
 	u8 hmac[IMA_DIGEST_SIZE];
 	u8 digest[IMA_DIGEST_SIZE];
 	struct mutex mutex;
+	atomic_t refcount;
 };
 #define IMA_IINT_INIT		1
 #define IMA_MUST_MEASURE	2
 #define IMA_MEASURED		4
 
+void ima_iint_init(void);
+struct ima_iint_cache * ima_iint_lookup(struct inode *inode);
+int ima_iint_insert(struct inode *inode);
+void ima_iint_delete(struct inode *inode);
+
+static inline void iint_get(struct ima_iint_cache *iint)
+{
+	atomic_inc(&iint->refcount);
+}
+
+/*
+ * When iint->refcounter goes to 0, free iint.
+ *
+ * When inode_alloc_integrity starts at late_initcall,
+ * iint can be NULl.
+ */
+static inline void iint_put(struct ima_iint_cache *iint)
+{
+	if (!iint)
+		return;
+	if (atomic_dec_and_test(&iint->refcount))
+		kfree(iint);
+}
+
 /* LSM based policy rules require audit */
 #ifdef CONFIG_IMA_LSM_RULES
 
security/integrity/ima/ima_api.c +49 -4

90 lines not on this page · raw message

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

68 lines not on this page · raw message

security/integrity/ima/ima_main.c +21 -41

134 lines not on this page · raw message

Signature · 1 line
1.5.5.1
maintainer
#12 lore raw

Re: [PATCH 4/4] integrity: IMA radix tree

Quoted 14 lines · On Wed, 12 Nov 2008 22:47:14 -0500 Mimi Zohar <[email protected]> wrote:

This version stores integrity information associated with an inode in a radix tree in order to avoid bloating the in memory inode. As entries can not be added to the radix tree at security_initcall, this version removes the dual stage initialization. Allocating and freeing the memory continues to be done at inode_alloc and file_free, respectively, except for inodes created before late_initcall.

---

include/linux/fs.h +0 -0
index bc6460c..0dcdd94 100644

include/linux/fs.h struct inode { · line 688

Quoted 6 lines
include/linux/fs.h +0 -3
@@ -683,9 +683,6 @@ struct inode {
 #ifdef CONFIG_SECURITY
 	void			*i_security;
 #endif
-#ifdef CONFIG_INTEGRITY
-	void			*i_integrity;
-#endif

ah, I was going to ask about that..

Quoted 26 lines
include/linux/fs.h +0 -0
 	void			*i_private; /* fs or device private pointer */
 };
 
security/integrity/ima/Makefile +1 -1
index f3aced4..959ae66 100644
@@ -6,4 +6,4 @@
 obj-$(CONFIG_IMA) += ima.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_policy.o ima_iint.o
security/integrity/ima/ima.h +0 -1
index 9a24305..09a5e1a 100644
@@ -92,7 +92,6 @@ void ima_store_measurement(void *d);
 void ima_template_show(struct seq_file *m, void *e,
 		       enum integrity_show_type show);
 
-
 /*
  * used to protect h_table and sha_table
  */

security/integrity/ima/ima.h extern struct ima_h_table ima_htable; · line 111

Quoted 5 lines
security/integrity/ima/ima.h +1 -1
@@ -109,7 +108,7 @@ extern struct ima_h_table ima_htable;
 
 static inline unsigned long IMA_HASH_KEY(u8 *digest)
 {
-	 return(hash_long(*digest, IMA_HASH_BITS));
+	return (hash_long(*digest, IMA_HASH_BITS));

And I _did_ ask about that ;)

Quoted 5 lines
security/integrity/ima/ima.h +0 -0
 }
 
 /* TPM "Glue" definitions */
@@ -145,11 +144,36 @@ struct ima_iint_cache {
 	u8 hmac[IMA_DIGEST_SIZE];

security/integrity/ima/ima.h struct ima_iint_cache { · line 154

Quoted 10 lines
security/integrity/ima/ima.h +3 -0
 	u8 digest[IMA_DIGEST_SIZE];
 	struct mutex mutex;
+	atomic_t refcount;
 };
 #define IMA_IINT_INIT		1
 #define IMA_MUST_MEASURE	2
 #define IMA_MEASURED		4
 
+void ima_iint_init(void);
+struct ima_iint_cache * ima_iint_lookup(struct inode *inode);

checkpatch...

Quoted 23 lines

...

security/integrity/ima/ima_iint.c new file +17 -0
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ *
+ * Authors:
+ * 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_iint.c
+ *             cache integrity information associated with an inode
+ *             using a radix tree.
+ */
+#include <linux/module.h>
+#include <linux/spinlock.h>

security/integrity/ima/ima_iint.c line 27

Quoted 10 lines
security/integrity/ima/ima_iint.c new file +10 -0
+#include <linux/radix-tree.h>
+#include "ima.h"
+
+static struct radix_tree_root ima_iint_store;
+DEFINE_SPINLOCK(ima_iint_lock);
+
+void ima_iint_init(void)
+{
+	INIT_RADIX_TREE(&ima_iint_store, GFP_ATOMIC);
+}

Use the RADIX_TREE() macro, then remove this function.

author
#13 lore raw

Re: [PATCH 4/4] integrity: IMA radix tree

Quoted 10 lines · Andrew Morton
Quoted 7 lines · On Wed, 12 Nov 2008 22:47:14 -0500 Mimi Zohar <[email protected]> wrote:

This version stores integrity information associated with an inode in a radix tree in order to avoid bloating the in memory inode. As entries can not be added to the radix tree at security_initcall, this version removes the dual stage initialization. Allocating and freeing the memory continues to be done at inode_alloc and file_free, respectively, except for inodes created before late_initcall.

Quoted 15 lines

include/linux/fs.h struct inode { · line 688

Quoted 13 lines

---

include/linux/fs.h +0 -3
index bc6460c..0dcdd94 100644
@@ -683,9 +683,6 @@ struct inode {
 #ifdef CONFIG_SECURITY
 	void			*i_security;
 #endif
-#ifdef CONFIG_INTEGRITY
-	void			*i_integrity;
-#endif

ah, I was going to ask about that..

Hm, perhaps posting as a separate patch was not such a good idea.

Quoted 27 lines
Quoted 27 lines
include/linux/fs.h +0 -0
 	void			*i_private; /* fs or device private pointer */
 };
 
security/integrity/ima/Makefile +1 -1
index f3aced4..959ae66 100644
@@ -6,4 +6,4 @@
 obj-$(CONFIG_IMA) += ima.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_policy.o ima_iint.o
security/integrity/ima/ima.h +0 -1
index 9a24305..09a5e1a 100644
@@ -92,7 +92,6 @@ void ima_store_measurement(void *d);
 void ima_template_show(struct seq_file *m, void *e,
 		       enum integrity_show_type show);
 
-
 /*
  * used to protect h_table and sha_table
  */
@@ -109,7 +108,7 @@ extern struct ima_h_table ima_htable;
 
Quoted 6 lines

security/integrity/ima/ima.h extern struct ima_h_table ima_htable; · line 111

Quoted 4 lines
security/integrity/ima/ima.h +1 -1
 static inline unsigned long IMA_HASH_KEY(u8 *digest)
 {
-	 return(hash_long(*digest, IMA_HASH_BITS));
+	return (hash_long(*digest, IMA_HASH_BITS));

And I _did_ ask about that ;)

Definitely better now.

Quoted 44 lines
Quoted 5 lines
security/integrity/ima/ima.h +0 -0
 }
 
 /* TPM "Glue" definitions */
@@ -145,11 +144,36 @@ struct ima_iint_cache {
 	u8 hmac[IMA_DIGEST_SIZE];

security/integrity/ima/ima.h struct ima_iint_cache { · line 154

Quoted 10 lines
security/integrity/ima/ima.h +3 -0
 	u8 digest[IMA_DIGEST_SIZE];
 	struct mutex mutex;
+	atomic_t refcount;
 };
 #define IMA_IINT_INIT		1
 #define IMA_MUST_MEASURE	2
 #define IMA_MEASURED		4
 
+void ima_iint_init(void);
+struct ima_iint_cache * ima_iint_lookup(struct inode *inode);

checkpatch...

Quoted 27 lines

...

security/integrity/ima/ima_iint.c new file +21 -0
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ *
+ * Authors:
+ * 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_iint.c
+ *             cache integrity information associated with an inode
+ *             using a radix tree.
+ */
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/radix-tree.h>
+#include "ima.h"
+
+static struct radix_tree_root ima_iint_store;
Quoted 8 lines

security/integrity/ima/ima_iint.c line 27

Quoted 6 lines
security/integrity/ima/ima_iint.c new file +6 -0
+DEFINE_SPINLOCK(ima_iint_lock);
+
+void ima_iint_init(void)
+{
+	INIT_RADIX_TREE(&ima_iint_store, GFP_ATOMIC);
+}

Use the RADIX_TREE() macro, then remove this function.

Done. Will be in next patch set.

Mimi

maintainer
#14 lore raw
In reply to Mimi Zohar
Quoted 13 lines · On Wed, 12 Nov 2008 22:47:10 -0500 Mimi Zohar <[email protected]> wrote:

The Linux Integrity Module (LIM) Framework provides hooks for modules to perform collection, appraisal, and storage of system integrity measurements. One such module, IMA, collects measurements of file data, maintains this list in the kernel, and if available, stores (extends) the measurements into a hardware TPM. These measurements are collected, appraised, and stored before any access (read or execute) to the data, so that malicious code or data cannot remove or cover up its own measurement, to avoid detection. If the measurements are anchored in a TPM, the TPM can sign the measurements, for proof of integrity to a third party, such as in enterprise client management.

Quoted 5 lines

Integrity measurement is complementary to LSM mandatory access control, which can be used to protect the integrity of system files. Integrity measurement policies can take advantage of LSM labels in deciding what to measure and to detect when the protection fails, with hardware strength.

This all looks quite mergeable to me, although I am far from being an expert on security things.

One thing which I cannot say, and which is quite important: how useful will all of this be to our users? Are people asking for it? Are people likely to enable and use it? Are they even likely to understand it? ;) Are any large/important customers asking for it? Are distros likely to enable and support it?

etc?

#15 lore raw
Quoted 5 lines · Andrew Morton
Quoted 2 lines · On Wed, 12 Nov 2008 22:47:10 -0500 Mimi Zohar <[email protected]> wrote:

The Linux Integrity Module (LIM) Framework provides hooks
...

Quoted 8 lines

This all looks quite mergeable to me, although I am far from being an expert on security things.

One thing which I cannot say, and which is quite important: how useful will all of this be to our users? Are people asking for it? Are people likely to enable and use it? Are they even likely to understand it? ;) Are any large/important customers asking for it? Are distros likely to enable and support it?

LIM/IMA's maintenance of a TPM hardware anchored file measurement list is fundamental to the Trusted Computing Group's standards efforts. Several projects have implemented the TNC (Trusted Network Connect) and PTS (Platform Trust Services) standards (see below). There are three demo packaged distros which have integrated these apps, two of which are government funded (EU and US), with definite customer interest. We are working with the RHEL team to provide a supported, patched kernel for HAP. All of these so far have used the old LSM based IMA, and have asked for a supported, upstreamed implementation, with the ability to work with SELinux.

Standards
http://www.trustedcomputinggroup.org

TNC/PTS Projects:
http://tnc.inform.fh-hannover.de/wiki/index.php/Main_Page (server)
http://sourceforge.net/projects/libtnc (library)
http://hostap.epitest.fi/wpa_supplicant/wpa_supplicant (client)
http://sourceforge.jp/projects/openpts (client and server)

Test Distros:
http://unit.aist.go.jp/itri/knoppix/index-en.html (trusted Knoppix)
http://www.nsa.gov/ia/industry/HAP/ (US)
http://www.opentc.net (EU)

maintainer
#16 lore raw
In reply to Andrew Morton
Quoted 2 lines · Andrew Morton

One thing which I cannot say, and which is quite important: how useful will all of this be to our users? Are people asking for it?

Apparently, some government users are, and there's a DoD decree which requires new equipment to include TPM hardware where possible:

http://iase.disa.mil/policy-guidance/dod-dar-tpm-decree07-03-07.pdf

This is to support encryption of data at rest, and for "device authentication" (requiring remote attestation of system integrity).

It's not clear to me yet how compelling this will be for general-case users.

Quoted 4 lines

Are
people likely to enable and use it? Are they even likely to understand it? ;) Are any large/important customers asking for it? Are distros likely to enable and support it?

I believe that TPM is in "tech preview" in RHEL 5.2, and that there is a desire to integrate it more fully with the OS via TCG software such as
Trousers: http://trousers.sourceforge.net/

- James

Signature · 2 lines
James Morris
<[email protected]>