Skip to contentSkip to conversation

integrity

PATCH In review Mimi Zohar 4 participants 14 messages Oct 7, 2008 – Oct 10, 2008

Subsystems (12)
lore
Share & tools
lore

Mimi Zohar

author
#0 lore raw

cover integrity

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

- Christoph Hellwig's questioned what is protecting the TPM internal kernel interface from the driver being removed, when it is not builtin. The TPM device should be builtin in order to start collecting measurements at the earliest possible time. When the TPM is not builtin, the internal TPM kernel interface now protects itself from the driver being removed by incrementing the module reference count.

The integrity-TPM-internal-kernel-interface.patch prereqs:
TPM-update-char-dev-BKL-pushdown.patch TPM-num_opens-to-is_open-variable-change.patch TPM-rcu-locking.patch TPM-addition-of-pnp-remove.patch TPM-Fixed-tpm_release-timing.patch

- Discussion on the mailing list questioned the use of special magic values in userspace, concluding these values are already exported to userspace via statfs and their correct/incorrect usage is left up to the userspace application.

- Concern was raised on the lkml mailing list, about adding i_integrity to the inode structure. This patch adds a comment clarifying that i_integrity is only included in the inode if INTEGRITY is configured.

Mimi Zohar (4):
integrity: TPM internel kernel interface
integrity: special fs magic
integrity: Linux Integrity Module(LIM)
integrity: IMA as an integrity service provider

author
#1 lore raw

PATCH 1/4 integrity: TPM internel kernel interface

Based on discussions on the lkml mailing list, the TPM should be built in, but when it is not builtin, 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 fb92836..5b2b526 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
@@ -710,6 +721,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 */
@@ -765,6 +777,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 3491d70..1a08d19 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
maintainer
#2 lore raw

Re: [PATCH 1/4] integrity: TPM internel kernel interface

Quoted 4 lines · Mimi Zohar

Based on discussions on the lkml mailing list, the TPM should be built in, but when it is not builtin, the internal TPM kernel interface did not protect itself from the removal of the TPM driver, while being used.

If the TPM driver should be built in, why is there an option to make it modular?

- James

Signature · 2 lines
James Morris
<[email protected]>
#3 lore raw

Re: [PATCH 1/4] integrity: TPM internel kernel interface

Quoted 11 lines · James Morris
Quoted 4 lines · Mimi Zohar

Based on discussions on the lkml mailing list, the TPM should be built in, but when it is not builtin, the internal TPM kernel interface did not protect itself from the removal of the TPM driver, while being used.

If the TPM driver should be built in, why is there an option to make it modular?

- James

Hi James,

It's recommended that the TPM driver should be built-in when using IMA to make sure it's measuring the system as closely as possible to the start of the boot process, but it's not necessarily true when using it to store keys, for example.

Rajiv

author
#4 lore raw

PATCH 2/4 integrity: special fs magic

In reply to Mimi Zohar

Discussion on the mailing list questioned the use of these magic values in userspace, concluding these values are already exported to userspace via statfs and their correct/incorrect usage is left up to the userspace application.

- Move special fs magic number definitions to magic.h
- Add magic.h include

---

fs/debugfs/inode.c +1 -2
index 08e28c9..3dbe216 100644
@@ -26,8 +26,7 @@
 #include <linux/debugfs.h>
 #include <linux/fsnotify.h>
 #include <linux/string.h>
-
-#define DEBUGFS_MAGIC	0x64626720
+#include <linux/magic.h>
 
 static struct vfsmount *debugfs_mount;
 static int debugfs_mount_count;
include/linux/magic.h +4 -0
index 1fa0c2c..f7f3fdd 100644
@@ -6,6 +6,10 @@
 #define AFS_SUPER_MAGIC                0x5346414F
 #define AUTOFS_SUPER_MAGIC	0x0187
 #define CODA_SUPER_MAGIC	0x73757245
+#define DEBUGFS_MAGIC          0x64626720
+#define SYSFS_MAGIC		0x62656572
+#define SECURITYFS_MAGIC	0x73636673
+#define TMPFS_MAGIC		0x01021994
 #define EFS_SUPER_MAGIC		0x414A53
 #define EXT2_SUPER_MAGIC	0xEF53
 #define EXT3_SUPER_MAGIC	0xEF53
mm/shmem.c +1 -3
index c1e5a3b..c4e63c4 100644
@@ -50,14 +50,12 @@
 #include <linux/migrate.h>
 #include <linux/highmem.h>
 #include <linux/seq_file.h>
+#include <linux/magic.h>
 
 #include <asm/uaccess.h>
 #include <asm/div64.h>
 #include <asm/pgtable.h>
 
-/* This magic number is used in glibc for posix shared memory */
-#define TMPFS_MAGIC	0x01021994
-
 #define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long))
 #define ENTRIES_PER_PAGEPAGE (ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)
 #define BLOCKS_PER_PAGE  (PAGE_CACHE_SIZE/512)
security/inode.c +1 -2
index acc6cf0..b66df8e 100644
@@ -20,8 +20,7 @@
 #include <linux/init.h>
 #include <linux/namei.h>
 #include <linux/security.h>
-
-#define SECURITYFS_MAGIC	0x73636673
+#include <linux/magic.h>
 
 static struct vfsmount *mount;
 static int mount_count;
Signature · 1 line
1.5.5.1
#5 lore raw

Re: [PATCH 2/4] integrity: special fs magic

Quoted 7 lines · Mimi Zohar

Discussion on the mailing list questioned the use of these magic values in userspace, concluding these values are already exported to userspace via statfs and their correct/incorrect usage is left up to the userspace application.

- Move special fs magic number definitions to magic.h
- Add magic.h include

This should be patch 1, and we can put in in ASAP even if the rest needs some more work.

author
#6 lore raw

Re: [PATCH 2/4] integrity: special fs magic

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

Discussion on the mailing list questioned the use of these magic values in userspace, concluding these values are already exported to userspace via statfs and their correct/incorrect usage is left up to the userspace application.

Quoted 6 lines
Quoted 2 lines

- Move special fs magic number definitions to magic.h
- Add magic.h include

This should be patch 1, and we can put in in ASAP even if the rest needs some more work.

The ordering of the first and second patches is interchangeable without requiring any patch changes.

Mimi

author
#7 lore raw

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

In reply to Mimi Zohar

Concern was raised on the lkml mailing list, about adding i_integrity to the inode structure. This patch adds a comment clarifying that i_integrity is only included in the inode if INTEGRITY is configured.

This version resolves the merge issues resulting from the removal of the nameidata parameter to inode_permission().
- Moved the integrity_inode_permission() call from inode_permission() to vfs_inode_permission() and file_inode_permission().
- Replaced the inode and nameidata parameters with file and path parameters to integrity_inode_permission().

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:
inode_permission, 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 e7bea3e..8a30e55 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.
@@ -878,6 +879,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 -- disable integrity auditing messages.
+                        1 -- enable integrity auditing messages. (Default)
+
 	inttest=	[IA64]
 
 	iommu=		[x86]
fs/exec.c +4 -0
index 32993be..ec00043 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>
@@ -1204,6 +1205,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 f45a449..8ba48aa 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>
@@ -272,6 +273,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);
@@ -343,6 +345,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 +15 -7
index b6726f6..424de21 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,13 +144,12 @@ 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))
+			goto out_free_inode;
 
 		spin_lock_init(&inode->i_lock);
 		lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
@@ -184,12 +184,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 +17 -2
index 4ea63ed..cd952b2 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>
@@ -289,7 +290,14 @@ int inode_permission(struct inode *inode, int mask)
  */
 int vfs_permission(struct nameidata *nd, int mask)
 {
-	return inode_permission(nd->path.dentry->d_inode, mask);
+	int retval;
+
+	retval = inode_permission(nd->path.dentry->d_inode, mask);
+	if (retval)
+		return retval;
+	return integrity_inode_permission(NULL, &nd->path,
+					  mask & (MAY_READ | MAY_WRITE |
+						  MAY_EXEC));
 }
 
 /**
@@ -306,7 +314,14 @@ int vfs_permission(struct nameidata *nd, int mask)
  */
 int file_permission(struct file *file, int mask)
 {
-	return inode_permission(file->f_path.dentry->d_inode, mask);
+	int retval;
+
+	retval = inode_permission(file->f_path.dentry->d_inode, mask);
+	if (retval)
+		return retval;
+	return integrity_inode_permission(file, NULL,
+					  mask & (MAY_READ | MAY_WRITE |
+						  MAY_EXEC));
 }
 
 /*
include/linux/audit.h +8 -0
index 6272a39..90e8c38 100644
@@ -123,6 +123,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. */
 
@@ -440,6 +445,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);
@@ -520,6 +527,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 580b513..342922f 100644
@@ -680,6 +680,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 +182 -0

182 lines not on this page · raw message

mm/mmap.c +4 -0
index 245c3d6..c8b03c1 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>
@@ -1046,6 +1047,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 5592939..61453fa 100644
@@ -4,6 +4,8 @@
 
 menu "Security options"
 
+source security/integrity/Kconfig
+
 config KEYS
 	bool "Enable access key retention support"
 	help
security/Makefile +4 -0
index f654260..b8132c9 100644
@@ -16,3 +16,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..3c29050
@@ -0,0 +1,24 @@
+#
+# Integrity configuration
+#
+
+menu "Integrity options"
+
+config INTEGRITY
+	bool "Enable different integrity models"
+	help
+	  This allows you to choose different integrity modules to be
+	  configured into your kernel.
+
+	  If you are unsure how to answer this question, answer N.
+
+config INTEGRITY_AUDIT
+	bool "Integrity audit boot parameter"
+	depends on INTEGRITY
+	default y
+	help
+	  This option adds a kernel parameter 'integrity_audit', which
+	  allows integrity auditing to be disabled at boot.  If this
+	  option is selected, integrity auditing can be disabled with
+	  'integrity_audit=0' on the kernel command line.
+endmenu
security/integrity/Makefile new file +6 -0
new file mode 100644
index 0000000..c9fb803
@@ -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 +308 -0

308 lines not on this page · raw message

security/integrity/integrity_audit.c new file +79 -0

79 lines not on this page · raw message

Signature · 1 line
1.5.5.1
author
#8 lore raw

PATCH 4/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.

This version addresses the merge issues resulting from the removal of the nameidata parameter to inode_permission().
- The parameter changes to integrity_inode_permission() are reflected here in this patch.

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, file_mmap and inode_permission 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 +60 -0
new file mode 100644
index 0000000..c9ab220
@@ -0,0 +1,60 @@
+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 security/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 security/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
+			# SELINUX_MAGIC
+			dont_measure fsmagic=0xF97CFF8C
+
+			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:
+			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 8a30e55..b6d7946 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.
@@ -862,6 +863,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 -3
index 3c29050..28b44e3 100644
@@ -2,8 +2,6 @@
 # Integrity configuration
 #
 
-menu "Integrity options"
-
 config INTEGRITY
 	bool "Enable different integrity models"
 	help
@@ -21,4 +19,5 @@ config INTEGRITY_AUDIT
 	  allows integrity auditing to be disabled at boot.  If this
 	  option is selected, integrity auditing can be disabled with
 	  'integrity_audit=0' on the kernel command line.
-endmenu
+
+source security/integrity/ima/Kconfig
security/integrity/Makefile +2 -0
index c9fb803..8eb7a4a 100644
@@ -4,3 +4,5 @@
 
 # Object file lists
 obj-$(CONFIG_INTEGRITY)			+= integrity.o integrity_audit.o
+
+obj-$(CONFIG_IMA)			+= ima/
security/integrity/ima/Kconfig new file +48 -0

48 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 +170 -0

170 lines not on this page · raw message

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

348 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 +471 -0

471 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 +354 -0

354 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
In reply to Mimi Zohar
Quoted 6 lines · Mimi Zohar

The integrity-TPM-internal-kernel-interface.patch prereqs:
TPM-update-char-dev-BKL-pushdown.patch TPM-num_opens-to-is_open-variable-change.patch TPM-rcu-locking.patch TPM-addition-of-pnp-remove.patch TPM-Fixed-tpm_release-timing.patch

Where are these patches?

i.e. are they in a tree? If so, which one? If not, they need to be posted in this series.

- James

Signature · 2 lines
James Morris
<[email protected]>
author
#10 lore raw
Quoted 9 lines · James Morris
Quoted 6 lines · Mimi Zohar

The integrity-TPM-internal-kernel-interface.patch prereqs:
TPM-update-char-dev-BKL-pushdown.patch TPM-num_opens-to-is_open-variable-change.patch TPM-rcu-locking.patch TPM-addition-of-pnp-remove.patch TPM-Fixed-tpm_release-timing.patch

Quoted 8 lines

Where are these patches?

i.e. are they in a tree? If so, which one? If not, they need to be posted in this series.

- James

The TPM patches have not, as yet, been picked up.

These TPM patches are base TPM changes, not really related to the integrity patches and certainly not dependent them. However the reverse is not true. The integrity-tpm-internal-kernel-interface patch is dependent on, at least, the TPM-rcu-locking patch.

Mimi

maintainer
#11 lore raw
Quoted 17 lines · Mimi Zohar
Quoted 16 lines · James Morris
Quoted 6 lines · Mimi Zohar

The integrity-TPM-internal-kernel-interface.patch prereqs:
TPM-update-char-dev-BKL-pushdown.patch TPM-num_opens-to-is_open-variable-change.patch TPM-rcu-locking.patch TPM-addition-of-pnp-remove.patch TPM-Fixed-tpm_release-timing.patch

Where are these patches?

i.e. are they in a tree? If so, which one? If not, they need to be posted in this series.

Quoted 8 lines
Quoted 1 line

- James

The TPM patches have not, as yet, been picked up.

These TPM patches are base TPM changes, not really related to the integrity patches and certainly not dependent them. However the reverse is not true. The integrity-tpm-internal-kernel-interface patch is dependent on, at least, the TPM-rcu-locking patch.

Please repost the TPM patches, then.

Signature · 2 lines
James Morris
<[email protected]>
author
#12 lore raw
Quoted 21 lines · James Morris
Quoted 19 lines · Mimi Zohar
Quoted 17 lines · James Morris
Quoted 6 lines · Mimi Zohar

The integrity-TPM-internal-kernel-interface.patch prereqs:
TPM-update-char-dev-BKL-pushdown.patch TPM-num_opens-to-is_open-variable-change.patch TPM-rcu-locking.patch TPM-addition-of-pnp-remove.patch TPM-Fixed-tpm_release-timing.patch

Where are these patches?

i.e. are they in a tree? If so, which one? If not, they need to be posted in this series.

- James

Quoted 8 lines
Quoted 6 lines

The TPM patches have not, as yet, been picked up.

These TPM patches are base TPM changes, not really related to the integrity patches and certainly not dependent them. However the reverse is not true. The integrity-tpm-internal-kernel-interface patch is dependent on, at least, the TPM-rcu-locking patch.

Please repost the TPM patches, then.

The TPM patches were just added to the -mm tree (10/8 18:45 EDT), available from http://userweb.kernel.org/~akpm/mmotm/.

Mimi

maintainer
#13 lore raw
Quoted 9 lines · Mimi Zohar
Quoted 6 lines
Quoted 4 lines

These TPM patches are base TPM changes, not really related to the integrity patches and certainly not dependent them. However the reverse is not true. The integrity-tpm-internal-kernel-interface patch is dependent on, at least, the TPM-rcu-locking patch.

Please repost the TPM patches, then.

The TPM patches were just added to the -mm tree (10/8 18:45 EDT), available from http://userweb.kernel.org/~akpm/mmotm/.

I've added the prereq patches to
git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6#next

Please test it, and base your next version of the integrity patches on that branch. Generally, if your patches depend on some other patches, you need to coordinate to ensure the prerequisite patches are either in the tree you're aiming for, or post them as part of the patchset.

Note that there are some interesting sparse warnings for the TPM code (not arising from the above):

drivers/char/tpm/tpm.c:493:10: error: bad constant expression drivers/char/tpm/tpm.c:500:32: error: cannot size expression drivers/char/tpm/tpm.c:507:10: error: bad constant expression drivers/char/tpm/tpm.c:515:32: error: cannot size expression drivers/char/tpm/tpm.c:547:32: error: cannot size expression
CHECK drivers/char/tpm/tpm_atmel.c
CHECK drivers/char/tpm/tpm_infineon.c
drivers/char/tpm/tpm_bios.c:412:7: warning: incorrect type in assignment (different address spaces)
drivers/char/tpm/tpm_bios.c:412:7: expected struct acpi_table_header *virt
drivers/char/tpm/tpm_bios.c:412:7: got void [noderef] <asn:2>*
drivers/char/tpm/tpm_bios.c:416:23: warning: incorrect type in argument 1 (different address spaces)
drivers/char/tpm/tpm_bios.c:416:23: expected void [noderef] <asn:2>*logical_address
drivers/char/tpm/tpm_bios.c:416:23: got struct acpi_table_header *virt

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