public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/5] integrity: TPM cleanup
       [not found] <20080707192529.489789904@linux.vnet.ibm.com>
@ 2008-07-07 21:56 ` Mimi Zohar
  2008-07-08  1:33   ` James Morris
  2008-07-15 23:13   ` James Morris
  2008-07-07 21:56 ` [PATCH 2/5] integrity: TPM internel kernel interface Mimi Zohar
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 20+ messages in thread
From: Mimi Zohar @ 2008-07-07 21:56 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm, safford, serue, sailer, zohar, debora, srajiv

This patchset contains 5 patches.
	Patch 1/5 integrity: TPM cleanup (scripts/Lindent and other)
	Patch 2/5 integrity: TPM internal kernel interface
	Patch 3/5 integrity: special fs magic
	Patch 4/5 integrity: Linux Integrity Module(LIM)
	Patch 5/5 integrity: IMA as an integrity service provider
 
Signed-off-by: Debora Velarde <dvelarde@us.ibm.com>
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
---
Index: linux-2.6.26-rc9-git1/drivers/char/tpm/tpm.c
===================================================================
--- linux-2.6.26-rc9-git1.orig/drivers/char/tpm/tpm.c
+++ linux-2.6.26-rc9-git1/drivers/char/tpm/tpm.c
@@ -6,6 +6,7 @@
  * Dave Safford <safford@watson.ibm.com>
  * Reiner Sailer <sailer@watson.ibm.com>
  * Kylene Hall <kjhall@us.ibm.com>
+ * Debora Velarde <dvelarde@us.ibm.com>
  *
  * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  *
@@ -321,7 +322,7 @@ static const u8 tpm_ordinal_duration[TPM
 
 static void user_reader_timeout(unsigned long ptr)
 {
-	struct tpm_chip *chip = (struct tpm_chip *) ptr;
+	struct tpm_chip *chip = (struct tpm_chip *)ptr;
 
 	schedule_work(&chip->work);
 }
@@ -337,10 +338,9 @@ static void timeout_work(struct work_str
 }
 
 /*
- * Returns max number of jiffies to wait
+ * tpm_calc_ordinal_duration - returns max number of jiffies to wait
  */
-unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
-					   u32 ordinal)
+unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
 {
 	int duration_idx = TPM_UNDEFINED;
 	int duration = 0;
@@ -363,7 +363,7 @@ unsigned long tpm_calc_ordinal_duration(
 EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
 
 /*
- * Internal kernel interface to transmit TPM commands
+ * tpm_transmit - internal kernel interface to transmit TPM commands
  */
 static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 			    size_t bufsiz)
@@ -385,8 +385,7 @@ static ssize_t tpm_transmit(struct tpm_c
 	mutex_lock(&chip->tpm_mutex);
 
 	if ((rc = chip->vendor.send(chip, (u8 *) buf, count)) < 0) {
-		dev_err(chip->dev,
-			"tpm_transmit: tpm_send: error %zd\n", rc);
+		dev_err(chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc);
 		goto out;
 	}
 
@@ -418,8 +417,7 @@ static ssize_t tpm_transmit(struct tpm_c
 out_recv:
 	rc = chip->vendor.recv(chip, (u8 *) buf, bufsiz);
 	if (rc < 0)
-		dev_err(chip->dev,
-			"tpm_transmit: tpm_recv: error %zd\n", rc);
+		dev_err(chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc);
 out:
 	mutex_unlock(&chip->tpm_mutex);
 	return rc;
@@ -477,7 +475,7 @@ static ssize_t transmit_cmd(struct tpm_c
 	int err;
 
 	len = tpm_transmit(chip, data, len);
-	if (len <  0)
+	if (len < 0)
 		return len;
 	if (len == TPM_ERROR_SIZE) {
 		err = be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)));
@@ -497,7 +495,7 @@ void tpm_gen_interrupt(struct tpm_chip *
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attempting to determine the timeouts");
+			  "attempting to determine the timeouts");
 }
 EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
 
@@ -512,7 +510,7 @@ void tpm_get_timeouts(struct tpm_chip *c
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attempting to determine the timeouts");
+			  "attempting to determine the timeouts");
 	if (rc)
 		goto duration;
 
@@ -544,7 +542,7 @@ duration:
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_DURATION;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attempting to determine the durations");
+			  "attempting to determine the durations");
 	if (rc)
 		return;
 
@@ -570,17 +568,20 @@ EXPORT_SYMBOL_GPL(tpm_get_timeouts);
 void tpm_continue_selftest(struct tpm_chip *chip)
 {
 	u8 data[] = {
-		0, 193,			/* TPM_TAG_RQU_COMMAND */
-		0, 0, 0, 10,		/* length */
-		0, 0, 0, 83,		/* TPM_ORD_GetCapability */
+		0, 193,		/* TPM_TAG_RQU_COMMAND */
+		0, 0, 0, 10,	/* length */
+		0, 0, 0, 83,	/* TPM_ORD_GetCapability */
 	};
 
 	tpm_transmit(chip, data, sizeof(data));
 }
 EXPORT_SYMBOL_GPL(tpm_continue_selftest);
 
-ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
-			char *buf)
+/*
+ * tpm_show_enabled - determine the permanent disabled state
+ */
+ssize_t tpm_show_enabled(struct device *dev, struct device_attribute *attr,
+			 char *buf)
 {
 	u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 35)];
 	ssize_t rc;
@@ -594,14 +595,17 @@ ssize_t tpm_show_enabled(struct device *
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attemtping to determine the permanent state");
+			  "attemtping to determine the permanent state");
 	if (rc)
 		return 0;
 	return sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_DISABLE_IDX]);
 }
 EXPORT_SYMBOL_GPL(tpm_show_enabled);
 
-ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr,
+/*
+ * tpm_show_active - determine the permanent inactive state
+ */
+ssize_t tpm_show_active(struct device *dev, struct device_attribute *attr,
 			char *buf)
 {
 	u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 35)];
@@ -616,15 +620,18 @@ ssize_t tpm_show_active(struct device * 
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attemtping to determine the permanent state");
+			  "attemtping to determine the permanent state");
 	if (rc)
 		return 0;
 	return sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]);
 }
 EXPORT_SYMBOL_GPL(tpm_show_active);
 
-ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr,
-			char *buf)
+/*
+ * tpm_show_owned - determine the owner state
+ */
+ssize_t tpm_show_owned(struct device *dev, struct device_attribute *attr,
+		       char *buf)
 {
 	u8 data[sizeof(tpm_cap)];
 	ssize_t rc;
@@ -638,15 +645,18 @@ ssize_t tpm_show_owned(struct device * d
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attempting to determine the owner state");
+			  "attempting to determine the owner state");
 	if (rc)
 		return 0;
 	return sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]);
 }
 EXPORT_SYMBOL_GPL(tpm_show_owned);
 
-ssize_t tpm_show_temp_deactivated(struct device * dev,
-				struct device_attribute * attr, char *buf)
+/*
+ * tpm_show_temp_deactivated - determine the temporary inactive state
+ */
+ssize_t tpm_show_temp_deactivated(struct device *dev,
+				  struct device_attribute *attr, char *buf)
 {
 	u8 data[sizeof(tpm_cap)];
 	ssize_t rc;
@@ -660,13 +670,14 @@ ssize_t tpm_show_temp_deactivated(struct
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attempting to determine the temporary state");
+			  "attempting to determine the temporary state");
 	if (rc)
 		return 0;
 	return sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]);
 }
 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 */
@@ -677,7 +688,8 @@ static const u8 pcrread[] = {
 ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
 		      char *buf)
 {
-	u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(pcrread)), 30)];
+	u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(pcrread)),
+		      READ_PCR_RESULT_SIZE)];
 	ssize_t rc;
 	int i, j, num_pcrs;
 	__be32 index;
@@ -692,7 +704,7 @@ ssize_t tpm_show_pcrs(struct device *dev
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attempting to determine the number of PCRS");
+			  "attempting to determine the number of PCRS");
 	if (rc)
 		return 0;
 
@@ -702,7 +714,7 @@ ssize_t tpm_show_pcrs(struct device *dev
 		index = cpu_to_be32(i);
 		memcpy(data + 10, &index, 4);
 		rc = transmit_cmd(chip, data, sizeof(data),
-				"attempting to read a PCR");
+				  "attempting to read a PCR");
 		if (rc)
 			goto out;
 		str += sprintf(str, "PCR-%02d: ", i);
@@ -722,6 +734,9 @@ static const u8 readpubek[] = {
 	0, 0, 0, 124,		/* TPM_ORD_ReadPubek */
 };
 
+/*
+ * tpm_show_pubek - returns the tpm's public endorcement key
+ */
 ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
 		       char *buf)
 {
@@ -741,13 +756,13 @@ ssize_t tpm_show_pubek(struct device *de
 	memcpy(data, readpubek, sizeof(readpubek));
 
 	err = transmit_cmd(chip, data, READ_PUBEK_RESULT_SIZE,
-			"attempting to read the PUBEK");
+			   "attempting to read the PUBEK");
 	if (err)
 		goto out;
 
 	/* 
 	   ignore header 10 bytes
-	   algorithm 32 bits (1 == RSA )
+	   algorithm 32 bits (1 == RSA)
 	   encscheme 16 bits
 	   sigscheme 16 bits
 	   parameters (RSA 12->bytes: keybit, #primes, expbit)  
@@ -756,17 +771,16 @@ ssize_t tpm_show_pubek(struct device *de
 	   ignore checksum 20 bytes
 	 */
 
-	str +=
-	    sprintf(str,
-		    "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
-		    "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X"
-		    " %02X %02X %02X %02X %02X %02X %02X %02X\n"
-		    "Modulus length: %d\nModulus: \n",
-		    data[10], data[11], data[12], data[13], data[14],
-		    data[15], data[16], data[17], data[22], data[23],
-		    data[24], data[25], data[26], data[27], data[28],
-		    data[29], data[30], data[31], data[32], data[33],
-		    be32_to_cpu(*((__be32 *) (data + 34))));
+	str += sprintf(str,
+		       "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
+		       "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X"
+		       " %02X %02X %02X %02X %02X %02X %02X %02X\n"
+		       "Modulus length: %d\nModulus: \n",
+		       data[10], data[11], data[12], data[13], data[14],
+		       data[15], data[16], data[17], data[22], data[23],
+		       data[24], data[25], data[26], data[27], data[28],
+		       data[29], data[30], data[31], data[32], data[33],
+		       be32_to_cpu(*((__be32 *) (data + 34))));
 
 	for (i = 0; i < 256; i++) {
 		str += sprintf(str, "%02X ", data[i + 38]);
@@ -791,10 +805,14 @@ static const u8 cap_version[] = {
 	0, 0, 0, 0
 };
 
+/*
+ * tpm_show_caps - returns the manufacturer and chip version
+ */
 ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
 		      char *buf)
 {
-	u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)];
+	u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap),
+			       ARRAY_SIZE(cap_version)), 30)];
 	ssize_t rc;
 	char *str = buf;
 
@@ -807,34 +825,39 @@ ssize_t tpm_show_caps(struct device *dev
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attempting to determine the manufacturer");
+			  "attempting to determine the manufacturer");
 	if (rc)
 		return 0;
 
 	str += sprintf(str, "Manufacturer: 0x%x\n",
-		       be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))));
+		       be32_to_cpu(*((__be32 *) (data +
+						 TPM_GET_CAP_RET_UINT32_1_IDX))));
 
 	memcpy(data, cap_version, sizeof(cap_version));
 	data[CAP_VERSION_IDX] = CAP_VERSION_1_1;
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attempting to determine the 1.1 version");
+			  "attempting to determine the 1.1 version");
 	if (rc)
 		goto out;
 
 	str += sprintf(str,
 		       "TCG version: %d.%d\nFirmware version: %d.%d\n",
-		       (int) data[14], (int) data[15], (int) data[16],
-		       (int) data[17]);
+		       (int)data[14], (int)data[15], (int)data[16],
+		       (int)data[17]);
 
 out:
 	return str - buf;
 }
 EXPORT_SYMBOL_GPL(tpm_show_caps);
 
-ssize_t tpm_show_caps_1_2(struct device * dev,
-			  struct device_attribute * attr, char *buf)
+/*
+ * tpm_show_caps_1_2 - returns the manufacturer and chip 1.2 version
+ */
+ssize_t tpm_show_caps_1_2(struct device *dev,
+			  struct device_attribute *attr, char *buf)
 {
-	u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)];
+	u8 data[max_t
+		(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)];
 	ssize_t len;
 	char *str = buf;
 
@@ -846,8 +869,8 @@ ssize_t tpm_show_caps_1_2(struct device 
 	data[TPM_CAP_IDX] = TPM_CAP_PROP;
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;
 
-	if ((len = tpm_transmit(chip, data, sizeof(data))) <=
-	    TPM_ERROR_SIZE) {
+	len = tpm_transmit(chip, data, sizeof(data));
+	if (len <= TPM_ERROR_SIZE) {
 		dev_dbg(chip->dev, "A TPM error (%d) occurred "
 			"attempting to determine the manufacturer\n",
 			be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
@@ -855,30 +878,33 @@ ssize_t tpm_show_caps_1_2(struct device 
 	}
 
 	str += sprintf(str, "Manufacturer: 0x%x\n",
-		       be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))));
+		       be32_to_cpu(*((__be32 *) (data +
+						 TPM_GET_CAP_RET_UINT32_1_IDX))));
 
 	memcpy(data, cap_version, sizeof(cap_version));
 	data[CAP_VERSION_IDX] = CAP_VERSION_1_2;
 
-	if ((len = tpm_transmit(chip, data, sizeof(data))) <=
-	    TPM_ERROR_SIZE) {
+	len = tpm_transmit(chip, data, sizeof(data));
+	if (len <= TPM_ERROR_SIZE) {
 		dev_err(chip->dev, "A TPM error (%d) occurred "
 			"attempting to determine the 1.2 version\n",
 			be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
 		goto out;
 	}
-	str += sprintf(str,
-		       "TCG version: %d.%d\nFirmware version: %d.%d\n",
-		       (int) data[16], (int) data[17], (int) data[18],
-		       (int) data[19]);
+	str += sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n",
+		       (int)data[16], (int)data[17], (int)data[18],
+		       (int)data[19]);
 
 out:
 	return str - buf;
 }
 EXPORT_SYMBOL_GPL(tpm_show_caps_1_2);
 
+/*
+ * tpm_store_cancel - cancel the current tpm operation
+ */
 ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
-			const char *buf, size_t count)
+			 const char *buf, size_t count)
 {
 	struct tpm_chip *chip = dev_get_drvdata(dev);
 	if (chip == NULL)
@@ -973,8 +999,7 @@ ssize_t tpm_write(struct file *file, con
 	if (in_size > TPM_BUFSIZE)
 		in_size = TPM_BUFSIZE;
 
-	if (copy_from_user
-	    (chip->data_buffer, (void __user *) buf, in_size)) {
+	if (copy_from_user(chip->data_buffer, (void __user *)buf, in_size)) {
 		mutex_unlock(&chip->buffer_mutex);
 		return -EFAULT;
 	}
@@ -1104,8 +1129,8 @@ static void tpm_dev_release(struct devic
  * upon errant exit from this function specific probe function should call
  * pci_disable_device
  */
-struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific
-				       *entry)
+struct tpm_chip *tpm_register_hardware(struct device *dev,
+				       const struct tpm_vendor_specific *entry)
 {
 #define DEVNAME_SIZE 7
 
@@ -1129,7 +1154,7 @@ struct tpm_chip *tpm_register_hardware(s
 	INIT_WORK(&chip->work, timeout_work);
 
 	setup_timer(&chip->user_read_timer, user_reader_timeout,
-			(unsigned long)chip);
+		    (unsigned long)chip);
 
 	memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific));
 
@@ -1158,8 +1183,7 @@ struct tpm_chip *tpm_register_hardware(s
 	if (misc_register(&chip->vendor.miscdev)) {
 		dev_err(chip->dev,
 			"unable to misc_register %s, minor %d\n",
-			chip->vendor.miscdev.name,
-			chip->vendor.miscdev.minor);
+			chip->vendor.miscdev.name, chip->vendor.miscdev.minor);
 		put_device(chip->dev);
 		return NULL;
 	}

-- 


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 2/5] integrity: TPM internel kernel interface
       [not found] <20080707192529.489789904@linux.vnet.ibm.com>
  2008-07-07 21:56 ` [PATCH 1/5] integrity: TPM cleanup Mimi Zohar
@ 2008-07-07 21:56 ` Mimi Zohar
  2008-07-07 21:56 ` [PATCH 3/5] integrity: special fs magic Mimi Zohar
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 20+ messages in thread
From: Mimi Zohar @ 2008-07-07 21:56 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm, safford, serue, sailer, zohar, debora, srajiv

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

Signed-off-by: Debora Velarde <debora@linux.vnet.ibm.com>
---
Index: linux-2.6.26-rc9-git1/drivers/char/tpm/tpm.c
===================================================================
--- linux-2.6.26-rc9-git1.orig/drivers/char/tpm/tpm.c
+++ linux-2.6.26-rc9-git1/drivers/char/tpm/tpm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004 IBM Corporation
+ * Copyright (C) 2004,2007,2008 IBM Corporation
  *
  * Authors:
  * Leendert van Doorn <leendert@watson.ibm.com>
@@ -27,6 +27,13 @@
 #include <linux/poll.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.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 <asm/unaligned.h>
 
 #include "tpm.h"
 
@@ -50,6 +57,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
@@ -365,8 +374,7 @@ EXPORT_SYMBOL_GPL(tpm_calc_ordinal_durat
 /*
  * tpm_transmit - 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;
@@ -422,6 +430,7 @@ out:
 	mutex_unlock(&chip->tpm_mutex);
 	return rc;
 }
+EXPORT_SYMBOL_GPL(tpm_transmit);
 
 #define TPM_DIGEST_SIZE 20
 #define TPM_ERROR_SIZE 10
@@ -727,6 +736,102 @@ out:
 }
 EXPORT_SYMBOL_GPL(tpm_show_pcrs);
 
+/*
+ * tpm_chip_lookup - return tpm_chip for given chip number and type
+ */
+static struct tpm_chip *tpm_chip_lookup(int chip_num, int chip_typ)
+{
+	struct tpm_chip *pos;
+
+	spin_lock(&driver_lock);
+	list_for_each_entry(pos, &tpm_chip_list, list) {
+		if ((chip_num == TPM_ANY_NUM || pos->dev_num == chip_num)
+		    && (chip_typ == TPM_ANY_TYPE)) {
+			spin_unlock(&driver_lock);
+			return pos;
+		}
+	}
+
+	spin_unlock(&driver_lock);
+	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)
+ */
+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;
+
+	chip = tpm_chip_lookup(chip_num, chip_id >> TPM_CHIP_TYPE_SHIFT);
+	if (chip == NULL)
+		return -ENODEV;
+	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);
+
+	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
+ */
+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;
+
+	chip = tpm_chip_lookup(chip_num, chip_id >> TPM_CHIP_TYPE_SHIFT);
+	if (chip == NULL)
+		return -ENODEV;
+
+	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));
+	return rc;
+}
+EXPORT_SYMBOL_GPL(tpm_pcr_extend);
+
 #define  READ_PUBEK_RESULT_SIZE 314
 static const u8 readpubek[] = {
 	0, 193,			/* TPM_TAG_RQU_COMMAND */
Index: linux-2.6.26-rc9-git1/drivers/char/tpm/tpm.h
===================================================================
--- linux-2.6.26-rc9-git1.orig/drivers/char/tpm/tpm.h
+++ linux-2.6.26-rc9-git1/drivers/char/tpm/tpm.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004 IBM Corporation
+ * Copyright (C) 2004, 2007 IBM Corporation
  *
  * Authors:
  * Leendert van Doorn <leendert@watson.ibm.com>
@@ -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_
 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 *);
Index: linux-2.6.26-rc9-git1/include/linux/tpm.h
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/include/linux/tpm.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2004,2007 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Dave Safford <safford@watson.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ * Debora Velarde <dvelarde@us.ibm.com>
+ *
+ * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org
+ *
+ * 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.
+ *
+ */
+#ifndef __LINUX_TPM_H__
+#define __LINUX_TPM_H__
+
+#define PCI_DEVICE_ID_AMD_8111_LPC    0x7468
+
+/*
+ * Chip type is one of these values in the upper two bytes of chip_id
+ */
+enum tpm_chip_type {
+	TPM_HW_TYPE = 0x0,
+	TPM_SW_TYPE = 0x1,
+	TPM_ANY_TYPE = 0xFFFF,
+};
+
+/*
+ * Chip num is this value or a valid tpm idx in lower two bytes of chip_id
+ */
+enum tpm_chip_num {
+	TPM_ANY_NUM = 0xFFFF,
+};
+
+
+#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
+
+extern int tpm_pcr_read(u32 chip_id, int pcr_idx, u8 *res_buf);
+extern int tpm_pcr_extend(u32 chip_id, int pcr_idx, const u8 *hash);
+#endif
+#endif

-- 


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 3/5] integrity: special fs magic
       [not found] <20080707192529.489789904@linux.vnet.ibm.com>
  2008-07-07 21:56 ` [PATCH 1/5] integrity: TPM cleanup Mimi Zohar
  2008-07-07 21:56 ` [PATCH 2/5] integrity: TPM internel kernel interface Mimi Zohar
@ 2008-07-07 21:56 ` Mimi Zohar
  2008-07-07 21:57 ` [PATCH 4/5] integrity: Linux Integrity Module(LIM) Mimi Zohar
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 20+ messages in thread
From: Mimi Zohar @ 2008-07-07 21:56 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm, safford, serue, sailer, zohar

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

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
---
Index: linux-2.6.26-rc9-git1/mm/shmem.c
===================================================================
--- linux-2.6.26-rc9-git1.orig/mm/shmem.c
+++ linux-2.6.26-rc9-git1/mm/shmem.c
@@ -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)
Index: linux-2.6.26-rc9-git1/security/inode.c
===================================================================
--- linux-2.6.26-rc9-git1.orig/security/inode.c
+++ linux-2.6.26-rc9-git1/security/inode.c
@@ -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;
Index: linux-2.6.26-rc9-git1/include/linux/magic.h
===================================================================
--- linux-2.6.26-rc9-git1.orig/include/linux/magic.h
+++ linux-2.6.26-rc9-git1/include/linux/magic.h
@@ -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
Index: linux-2.6.26-rc9-git1/fs/debugfs/inode.c
===================================================================
--- linux-2.6.26-rc9-git1.orig/fs/debugfs/inode.c
+++ linux-2.6.26-rc9-git1/fs/debugfs/inode.c
@@ -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;

-- 


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 4/5] integrity: Linux Integrity Module(LIM)
       [not found] <20080707192529.489789904@linux.vnet.ibm.com>
                   ` (2 preceding siblings ...)
  2008-07-07 21:56 ` [PATCH 3/5] integrity: special fs magic Mimi Zohar
@ 2008-07-07 21:57 ` Mimi Zohar
  2008-07-08  1:31   ` James Morris
  2008-07-07 21:57 ` [PATCH 5/5] integrity: IMA as an integrity service provider Mimi Zohar
  2008-07-07 22:03 ` LTP IMA path Mimi Zohar
  5 siblings, 1 reply; 20+ messages in thread
From: Mimi Zohar @ 2008-07-07 21:57 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm, safford, serue, sailer, zohar

This patch is a redesign of the integrity framework, which addresses 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.)

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
---
Index: linux-2.6.26-rc9-git1/include/linux/integrity.h
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/include/linux/integrity.h
@@ -0,0 +1,195 @@
+/*
+ * integrity.h
+ *
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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.
+ */
+
+#ifndef _LINUX_INTEGRITY_H
+#define _LINUX_INTEGRITY_H
+
+#include <linux/fs.h>
+#include <linux/audit.h>
+
+#ifdef CONFIG_INTEGRITY
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+			const unsigned char *fname, char *op,
+			char *cause, int result);
+
+/*
+ * Integrity API calls:
+ *
+ * @collect_measurement:
+ *	Collect template specific measurement data.
+ *	@data contains template specific data used for collecting the
+ *	measurement.
+ * 	Return 0 if operation was successful.
+ *
+ * @appraise_measurement:
+ *	Appraise the integrity of the template specific measurement data.
+ *	@data contains template specific data used for appraising the
+ *	measurement.
+ * 	Return 0 if operation was successful.
+ *
+ * @store_measurement:
+ *	Store the template specific data.
+ *	@data contains template specific data used for storing the
+ *	measurement.
+ *
+ * @must_measure:
+ *	Measurement decision based on an integrity policy.
+ *	@data contains template specific data used for making policy
+ * 	decision.
+ * 	Return 0 if operation was successful.
+ *
+ * @display_template:
+ *	Display template specific data.
+ *
+ */
+
+enum integrity_show_type { INTEGRITY_SHOW_BINARY, INTEGRITY_SHOW_ASCII};
+
+struct template_operations {
+	int (*collect_measurement)(void *);
+	int (*appraise_measurement)(void *);
+	void (*store_measurement)(void *);
+	int (*must_measure)(void *);
+	void (*display_template)(struct seq_file *m, void *,
+				 enum integrity_show_type);
+};
+extern int integrity_register_template(const char *template_name,
+					const struct template_operations *ops);
+extern int integrity_unregister_template(const char *template_name);
+extern int integrity_find_template(const char *,
+				   const struct template_operations **ops);
+
+/*
+ * Integrity hooks:
+ *
+ * @bprm_check_integrity:
+ * 	This hook mediates the point when a search for a binary handler	will
+ * 	begin.  At this point, the OS protects against an executable file,
+ * 	already open for write, from being executed; and an executable file
+ * 	already open for execute, from being modified. So we can be certain
+ *	that any measurements(collect, appraise, store) done here are of
+ * 	the file being executed.
+ * 	@bprm contains the linux_binprm structure.
+ *	Return 0 if the hook is successful and permission is granted.
+ *
+ * @inode_alloc_integrity:
+ *	Allocate and attach an integrity structure to @inode->i_integrity.  The
+ * 	i_integrity field is initialized to NULL when the inode structure is
+ * 	allocated.
+ * 	@inode contains the inode structure.
+ * 	Return 0 if operation was successful.
+ *
+ * @inode_free_integrity:
+ *	@inode contains the inode structure.
+ * 	Deallocate the inode integrity structure and set @inode->i_integrity to
+ * 	NULL.
+ *
+ * @inode_permission:
+ *	This hook is called by the existing Linux permission function, when
+ * 	a file is opened (as well as many other operations).  At this point,
+ *	measurements of files open for read(collect, appraise, store) can
+ * 	be made.
+ *	@inode contains the inode structure to check.
+ *	@mask contains the permission mask.
+ *      @nd contains the nameidata (may be NULL).
+ *
+ * @file_free_integrity:
+ *	Update the integrity xattr value as necessary.
+ * 	*file contains the file structure being closed.
+ *
+ * @file_mmap :
+ *	Measurement(collect, appraise, store) of files mmaped for EXEC,
+ *	could be measured at this point.
+ *	@file contains the file structure for file to map (may be NULL).
+ *	@reqprot contains the protection requested by the application.
+ *	@prot contains the protection that will be applied by the kernel.
+ *	@flags contains the operational flags.
+ *	Return 0 if permission is granted.
+ */
+
+enum lim_hooks {INODE_PERMISSION = 1, FILE_MMAP, BPRM_CHECK };
+
+struct integrity_operations {
+	int (*bprm_check_integrity) (struct linux_binprm *bprm);
+	int (*inode_alloc_integrity) (struct inode *inode);
+	void (*inode_free_integrity) (struct inode *inode);
+	int (*inode_permission) (struct inode *inode, int mask,
+				struct nameidata *nd);
+	void (*file_free_integrity) (struct file *file);
+	int (*file_mmap) (struct file *file,
+			  unsigned long reqprot, unsigned long prot,
+			  unsigned long flags, unsigned long addr,
+			  unsigned long addr_only);
+};
+extern int register_integrity(const struct integrity_operations *ops);
+extern int unregister_integrity(const struct integrity_operations *ops);
+
+/* global variables */
+extern const struct integrity_operations *integrity_ops;
+
+
+int integrity_collect_measurement(const char *template_name, void *data);
+int integrity_appraise_measurement(const char *template_name, void *data);
+int integrity_must_measure(const char *template_name, void *data);
+int integrity_store_measurement(const char *template_name, void *data);
+
+int integrity_bprm_check(struct linux_binprm *bprm);
+int integrity_inode_alloc(struct inode *inode);
+void integrity_inode_free(struct inode *inode);
+int integrity_inode_permission(struct inode *inode, int mask,
+				struct nameidata *nd);
+void integrity_file_free(struct file *file);
+int integrity_file_mmap(struct file *file,
+			  unsigned long reqprot, unsigned long prot,
+			  unsigned long flags, unsigned long addr,
+			  unsigned long addr_only);
+#else
+
+static inline int integrity_bprm_check(struct linux_binprm *bprm)
+{
+	return 0;
+}
+
+static inline int integrity_inode_alloc(struct inode *inode)
+{
+	return 0;
+}
+
+static inline void integrity_inode_free(struct inode *inode)
+{
+	return;
+}
+
+static inline int integrity_inode_permission(struct inode *inode, int mask,
+				struct nameidata *nd)
+{
+	return 0;
+}
+
+static inline int integrity_file_permission(struct file *file, int mask)
+{
+	return 0;
+}
+
+static inline void integrity_file_free(struct file *file)
+{
+	return;
+}
+
+static inline int integrity_file_mmap(struct file *file,
+			  unsigned long reqprot, unsigned long prot,
+			  unsigned long flags, unsigned long addr,
+			  unsigned long addr_only)
+{
+	return 0;
+}
+#endif
+#endif
Index: linux-2.6.26-rc9-git1/security/integrity/integrity.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/security/integrity/integrity.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2006,2007,2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity.c
+ * 	register integrity subsystem
+ * 	register integrity template
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/integrity.h>
+
+const struct integrity_operations *integrity_ops;
+EXPORT_SYMBOL(integrity_ops);
+
+#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;
+};
+static LIST_HEAD(integrity_templates);
+static DEFINE_MUTEX(integrity_templates_mutex);
+
+/**
+ * register_integrity - registers an integrity framework with the kernel
+ * @ops: a pointer to the struct security_options that is to be registered
+ *
+ * Perhaps in the future integrity module stacking will be necessary, but
+ * for the time being, this function permits only one integrity module to
+ * register itself with the kernel integrity subsystem.
+ *
+ * If another integrity module is already registered, an error code is
+ * returned. On success 0 is returned.
+ */
+int register_integrity(const struct integrity_operations *ops)
+{
+	if (integrity_ops != NULL)
+		return -EAGAIN;
+	integrity_ops = ops;
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(register_integrity);
+
+/**
+ * unregister_integrity - unregisters an integrity framework from the kernel
+ * @ops: a pointer to the struct security_options that is to be registered
+ *
+ * Returns 0 on success, -EINVAL on failure.
+ */
+int unregister_integrity(const struct integrity_operations *ops)
+{
+	if (ops != integrity_ops)
+		return -EINVAL;
+
+	integrity_ops = NULL;
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(unregister_integrity);
+
+/**
+ * integrity_register_template - registers an integrity template with the kernel
+ * @template_name: a pointer to a string containing the template name.
+ * @template_ops: a pointer to the template functions
+ *
+ * Register a set of functions to collect, appraise, store, and display
+ * a template measurement, and a means to decide whether to do them.
+ * Unlike integrity modules, any number of templates may be registered.
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int integrity_register_template(const char *template_name,
+				const struct template_operations *template_ops)
+{
+	int template_len;
+	struct template_list_entry *entry;
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+	INIT_LIST_HEAD(&entry->template);
+
+	template_len = strlen(template_name);
+	if (template_len > TEMPLATE_NAME_LEN_MAX)
+		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);
+	synchronize_rcu();
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(integrity_register_template);
+
+/**
+ * integrity_unregister_template: unregister a template
+ * @template_name: a pointer to a string containing the template name.
+ *
+ * Returns 0 on success, -EINVAL on failure.
+ */
+int integrity_unregister_template(const char *template_name)
+{
+	struct template_list_entry *entry;
+
+	mutex_lock(&integrity_templates_mutex);
+	list_for_each_entry(entry, &integrity_templates, template) {
+		if (strncmp(entry->template_name, template_name,
+			    strlen(entry->template_name)) == 0) {
+			list_del_rcu(&entry->template);
+			mutex_unlock(&integrity_templates_mutex);
+			synchronize_rcu();
+			kfree(entry);
+			return 0;
+		}
+	}
+	mutex_unlock(&integrity_templates_mutex);
+	return -EINVAL;
+}
+
+EXPORT_SYMBOL_GPL(integrity_unregister_template);
+
+/**
+ * integrity_find_template - search the integrity_templates list
+ * @template_name: a pointer to a string containing the template name.
+ * @template_ops: a pointer to the template functions
+ *
+ * Called with an rcu_read_lock
+ * Returns 0 on success, -EINVAL on failure.
+ */
+int integrity_find_template(const char *template_name,
+			    const struct template_operations **template_ops)
+{
+	struct template_list_entry *entry;
+
+	list_for_each_entry_rcu(entry, &integrity_templates, template) {
+		if (strncmp(entry->template_name, template_name,
+			    strlen(entry->template_name)) == 0) {
+			*template_ops = entry->template_ops;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+EXPORT_SYMBOL_GPL(integrity_find_template);
+
+/* Start of the integrity API calls */
+
+/**
+ * integrity_collect_measurement - collect template specific measurement
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int integrity_collect_measurement(const char *template_name, void *data)
+{
+	const struct template_operations *template_ops;
+	int rc;
+
+	rcu_read_lock();
+	rc = integrity_find_template(template_name, &template_ops);
+	if (rc == 0)
+		rc = template_ops->collect_measurement(data);
+	rcu_read_unlock();
+	return rc;
+}
+
+EXPORT_SYMBOL_GPL(integrity_collect_measurement);
+
+/**
+ * integrity_appraise_measurement - appraise template specific measurement
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Returns 0 on success, an error code on failure
+ */
+int integrity_appraise_measurement(const char *template_name, void *data)
+{
+	const struct template_operations *template_ops;
+	int rc;
+
+	rcu_read_lock();
+	rc = integrity_find_template(template_name, &template_ops);
+	if (rc == 0)
+		rc = template_ops->appraise_measurement(data);
+	rcu_read_unlock();
+	return rc;
+}
+
+EXPORT_SYMBOL_GPL(integrity_appraise_measurement);
+
+/**
+ * integrity_store_measurement - store template specific measurement
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Store template specific integrity measurement.
+ */
+int integrity_store_measurement(const char *template_name, void *data)
+{
+	const struct template_operations *template_ops;
+	int rc;
+
+	rcu_read_lock();
+	rc = integrity_find_template(template_name, &template_ops);
+	if (rc == 0)
+		template_ops->store_measurement(data);
+	rcu_read_unlock();
+	return rc;
+}
+
+EXPORT_SYMBOL_GPL(integrity_store_measurement);
+
+/**
+ * integrity_must_measure - measure decision based on template policy
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int integrity_must_measure(const char *template_name, void *data)
+{
+	const struct template_operations *template_ops;
+	int rc;
+
+	rcu_read_lock();
+	rc = integrity_find_template(template_name, &template_ops);
+	if (rc == 0)
+		rc = template_ops->must_measure(data);
+	rcu_read_unlock();
+	return rc;
+}
+
+EXPORT_SYMBOL_GPL(integrity_must_measure);
+
+/* Start of the integrity Hooks */
+
+/* Hook used to measure executable file integrity. */
+int integrity_bprm_check(struct linux_binprm *bprm)
+{
+	int rc = 0;
+
+	if (integrity_ops && integrity_ops->bprm_check_integrity)
+		rc = integrity_ops->bprm_check_integrity(bprm);
+	return rc;
+}
+
+/* Allocate, attach and initialize an inode's i_integrity. */
+int integrity_inode_alloc(struct inode *inode)
+{
+	int rc = 0;
+
+	if (integrity_ops && integrity_ops->inode_alloc_integrity)
+		rc = integrity_ops->inode_alloc_integrity(inode);
+	return rc;
+}
+
+/* Hook used to free an inode's i_integrity structure. */
+void integrity_inode_free(struct inode *inode)
+{
+	if (integrity_ops && integrity_ops->inode_free_integrity)
+		integrity_ops->inode_free_integrity(inode);
+}
+
+/* Hook used to measure a file's integrity. */
+int integrity_inode_permission(struct inode *inode, int mask,
+			       struct nameidata *nd)
+{
+	int rc = 0;
+
+	if (integrity_ops && integrity_ops->inode_permission)
+		rc = integrity_ops->inode_permission(inode, mask, nd);
+	return rc;
+}
+
+/* Hook used to update i_integrity data and integrity xattr values
+ * as necessary.
+ */
+void integrity_file_free(struct file *file)
+{
+	if (integrity_ops && integrity_ops->file_free_integrity)
+		integrity_ops->file_free_integrity(file);
+}
+
+/* Hook used to measure integrity of an mmapped file */
+int integrity_file_mmap(struct file *file, unsigned long reqprot,
+			unsigned long prot, unsigned long flags,
+			unsigned long addr, unsigned long addr_only)
+{
+	int rc = 0;
+
+	if (integrity_ops && integrity_ops->file_mmap)
+		rc = integrity_ops->file_mmap(file, reqprot, prot,
+					      flags, addr, addr_only);
+	return rc;
+}
Index: linux-2.6.26-rc9-git1/fs/file_table.c
===================================================================
--- linux-2.6.26-rc9-git1.orig/fs/file_table.c
+++ linux-2.6.26-rc9-git1/fs/file_table.c
@@ -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_dec_and_test(&file->f_count)) {
 		security_file_free(file);
+		integrity_file_free(file);
 		file_kill(file);
 		file_free(file);
 	}
Index: linux-2.6.26-rc9-git1/fs/inode.c
===================================================================
--- linux-2.6.26-rc9-git1.orig/fs/inode.c
+++ linux-2.6.26-rc9-git1/fs/inode.c
@@ -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>
@@ -151,6 +152,15 @@ static struct inode *alloc_inode(struct 
 			return NULL;
 		}
 
+		/* allocate, attach and initialize an i_integrity */
+		if (integrity_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;
+		}
+
 		spin_lock_init(&inode->i_lock);
 		lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
 
@@ -190,6 +200,7 @@ 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
Index: linux-2.6.26-rc9-git1/include/linux/fs.h
===================================================================
--- linux-2.6.26-rc9-git1.orig/include/linux/fs.h
+++ linux-2.6.26-rc9-git1/include/linux/fs.h
@@ -654,6 +654,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 */
 };
 
Index: linux-2.6.26-rc9-git1/include/linux/audit.h
===================================================================
--- linux-2.6.26-rc9-git1.orig/include/linux/audit.h
+++ linux-2.6.26-rc9-git1/include/linux/audit.h
@@ -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. */
 
@@ -441,6 +446,8 @@ extern int  audit_set_loginuid(struct ta
 #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);
@@ -521,6 +528,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; })
Index: linux-2.6.26-rc9-git1/security/integrity/integrity_audit.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/security/integrity/integrity_audit.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity_audit.c
+ * 	Audit calls for the integrity subsystem
+ */
+
+#include <linux/audit.h>
+#include <linux/fs.h>
+#include <linux/integrity.h>
+
+static int integrity_audit = 1;
+
+#ifdef CONFIG_INTEGRITY_AUDIT
+static int __init integrity_audit_setup(char *str)
+{
+	ulong audit;
+	int rc;
+	char *op;
+
+	rc = strict_strtoul(str, 10, &audit);
+	if (rc < 0 || audit > 1)
+		printk(KERN_INFO "integrity: invalid integrity_audit value\n");
+	else
+		integrity_audit = audit;
+
+	op = integrity_audit ? "integrity_audit_enabled" :
+	    "integrity_audit_not_enabled";
+	integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, NULL, op, 0);
+	return 1;
+}
+
+__setup("integrity_audit=", integrity_audit_setup);
+#endif
+
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+			 const unsigned char *fname, char *op,
+			 char *cause, int result)
+{
+	struct audit_buffer *ab;
+
+	if (!integrity_audit && result == 1)
+		return;
+
+	ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
+	audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u",
+			 current->pid, current->uid,
+			 audit_get_loginuid(current));
+	audit_log_task_context(ab);
+	switch (audit_msgno) {
+	case AUDIT_INTEGRITY_DATA:
+	case AUDIT_INTEGRITY_METADATA:
+	case AUDIT_INTEGRITY_PCR:
+		audit_log_format(ab, " op=%s cause=%s", op, cause);
+		break;
+	case AUDIT_INTEGRITY_HASH:
+		audit_log_format(ab, " op=%s hash=%s", op, cause);
+		break;
+	case AUDIT_INTEGRITY_STATUS:
+	default:
+		audit_log_format(ab, " op=%s", op);
+	}
+	audit_log_format(ab, " comm=");
+	audit_log_untrustedstring(ab, current->comm);
+	if (fname) {
+		audit_log_format(ab, " name=");
+		audit_log_untrustedstring(ab, fname);
+	}
+	if (inode)
+		audit_log_format(ab, " dev=%s ino=%lu",
+				 inode->i_sb->s_id, inode->i_ino);
+	audit_log_format(ab, " res=%d", result);
+	audit_log_end(ab);
+}
Index: linux-2.6.26-rc9-git1/Documentation/kernel-parameters.txt
===================================================================
--- linux-2.6.26-rc9-git1.orig/Documentation/kernel-parameters.txt
+++ linux-2.6.26-rc9-git1/Documentation/kernel-parameters.txt
@@ -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.
@@ -821,6 +822,11 @@ and is between 256 and 4096 characters. 
 	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]
Index: linux-2.6.26-rc9-git1/security/integrity/Makefile
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/security/integrity/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the kernel integrity code
+#
+
+# Object file lists
+obj-$(CONFIG_INTEGRITY)			+= integrity.o integrity_audit.o
Index: linux-2.6.26-rc9-git1/security/integrity/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/security/integrity/Kconfig
@@ -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
Index: linux-2.6.26-rc9-git1/security/Kconfig
===================================================================
--- linux-2.6.26-rc9-git1.orig/security/Kconfig
+++ linux-2.6.26-rc9-git1/security/Kconfig
@@ -4,6 +4,8 @@
 
 menu "Security options"
 
+source security/integrity/Kconfig
+
 config KEYS
 	bool "Enable access key retention support"
 	help
Index: linux-2.6.26-rc9-git1/fs/exec.c
===================================================================
--- linux-2.6.26-rc9-git1.orig/fs/exec.c
+++ linux-2.6.26-rc9-git1/fs/exec.c
@@ -46,6 +46,7 @@
 #include <linux/ptrace.h>
 #include <linux/mount.h>
 #include <linux/security.h>
+#include <linux/integrity.h>
 #include <linux/syscalls.h>
 #include <linux/rmap.h>
 #include <linux/tsacct_kern.h>
@@ -1197,6 +1198,9 @@ int search_binary_handler(struct linux_b
 	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. */
Index: linux-2.6.26-rc9-git1/fs/namei.c
===================================================================
--- linux-2.6.26-rc9-git1.orig/fs/namei.c
+++ linux-2.6.26-rc9-git1/fs/namei.c
@@ -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>
@@ -286,7 +287,10 @@ int permission(struct inode *inode, int 
 	if (retval)
 		return retval;
 
-	return security_inode_permission(inode, mask, nd);
+	retval = security_inode_permission(inode, mask, nd);
+	if (retval)
+		return retval;
+	return integrity_inode_permission(inode, mask, nd);
 }
 
 /**
@@ -462,6 +466,7 @@ static struct dentry * cached_lookup(str
 static int exec_permission_lite(struct inode *inode,
 				       struct nameidata *nd)
 {
+	int retval;
 	umode_t	mode = inode->i_mode;
 
 	if (inode->i_op && inode->i_op->permission)
@@ -486,7 +491,10 @@ static int exec_permission_lite(struct i
 
 	return -EACCES;
 ok:
-	return security_inode_permission(inode, MAY_EXEC, nd);
+	retval =  security_inode_permission(inode, MAY_EXEC, nd);
+	if (retval)
+		return retval;
+	return integrity_inode_permission(inode, MAY_EXEC, nd);
 }
 
 /*
Index: linux-2.6.26-rc9-git1/mm/mmap.c
===================================================================
--- linux-2.6.26-rc9-git1.orig/mm/mmap.c
+++ linux-2.6.26-rc9-git1/mm/mmap.c
@@ -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>
@@ -1042,6 +1043,9 @@ unsigned long do_mmap_pgoff(struct file 
 	error = security_file_mmap(file, reqprot, prot, flags, addr, 0);
 	if (error)
 		return error;
+	error = integrity_file_mmap(file, reqprot, prot, flags, addr, 0);
+	if (error)
+		return error;
 
 	return mmap_region(file, addr, len, flags, vm_flags, pgoff,
 			   accountable);
Index: linux-2.6.26-rc9-git1/security/Makefile
===================================================================
--- linux-2.6.26-rc9-git1.orig/security/Makefile
+++ linux-2.6.26-rc9-git1/security/Makefile
@@ -19,3 +19,7 @@ obj-$(CONFIG_SECURITY_SMACK)		+= commonc
 obj-$(CONFIG_SECURITY_CAPABILITIES)	+= commoncap.o capability.o
 obj-$(CONFIG_SECURITY_ROOTPLUG)		+= commoncap.o 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

-- 


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 5/5] integrity: IMA as an integrity service provider
       [not found] <20080707192529.489789904@linux.vnet.ibm.com>
                   ` (3 preceding siblings ...)
  2008-07-07 21:57 ` [PATCH 4/5] integrity: Linux Integrity Module(LIM) Mimi Zohar
@ 2008-07-07 21:57 ` Mimi Zohar
  2008-07-07 22:03 ` LTP IMA path Mimi Zohar
  5 siblings, 0 replies; 20+ messages in thread
From: Mimi Zohar @ 2008-07-07 21:57 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm, safford, serue, sailer, zohar

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

This version addresses a number of issues discussed on LKML, including:
- Added Documentation/ABI/testing/ima_policy which describes loading
  the IMA measurement policy.
- Added policy support for magic numbers and removed them from
  skip_measurement().
- Added policy support for LSM obj_type.
- Replaced using .i_mtime to detect when a file has been modified
  with .i_version. This requires the filesystem to be mounted with
  iversion.  (Requires iversion mount support.)
- Added const for integrity_template_operations.
- Removed integrity_fixup_ops(), to make integrity_operations const too.
- Removed ima_fixup_inodes() by registering the integrity_ops early in
  security_initcall(), but waiting to start IMA in late_initcall(), until
  after the TPM is available.
- Removed CONFIG_IMA_BOOTPARAM and CONFIG_IMA_BOOTPARAM_VALUE.
- Replaced,as appropriate, all GFP_ATOMICs with GFP_KERNEL.

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. 

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
---
Index: linux-2.6.26-rc9-git1/Documentation/ABI/testing/ima_policy
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/Documentation/ABI/testing/ima_policy
@@ -0,0 +1,55 @@
+What:		security/ima/policy
+Date:		May 2008
+Contact:	Mimi Zohar <zohar@us.ibm.com>
+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=]]
+			lsm:	[[subj=] [obj=] [type=]]
+
+		base: 	func:= [BPRM_CHECK][FILE_MMAP][INODE_PERMISSION]
+			mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
+			fsmagic:= hex 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
+
+		The default policy measures all executables in bprm_check,
+		all files mmapped executable in file_mmap, and all files
+		open for read in inode_permission.
+
+		Examples of LSM specific definitions:
+
+		SELinux:
+			dont_measure type=var_log_t
+			dont_measure type=auditd_log_t
+			measure subj=system_u func=INODE_PERM mask=MAY_READ
+
+		Smack:
+			measure subj=_ func=INODE_PERM mask=MAY_READ
Index: linux-2.6.26-rc9-git1/security/integrity/ima/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/security/integrity/ima/Kconfig
@@ -0,0 +1,41 @@
+#
+# IBM Integrity Measurement Architecture
+#
+
+config IMA
+	bool "Integrity Measurement Architecture(IMA)"
+	depends on INTEGRITY
+	depends on ACPI
+	select CRYPTO
+	select CRYPTO_HMAC
+	select CRYPTO_MD5
+	select CRYPTO_SHA1
+	select TCG_TPM
+	select TCG_TIS
+	help
+	  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.  If your system
+	  has a TPM chip, then IMA also maintains an aggregate
+	  integrity value over this list inside the TPM hardware.
+	  These measurements and the aggregate (signed inside the
+	  TPM) can be retrieved and presented to remote parties to
+	  establish system properties. If unsure, say N.
+
+config IMA_MEASURE_PCR_IDX
+	int "PCR for Aggregate (8<= Index <= 14)"
+	depends on IMA
+	range 8 14
+	default 10
+	help
+	  IMA_MEASURE_PCR_IDX determines the TPM PCR register index
+	  that IMA uses to maintain the integrity aggregate of the
+	  measurement list.  If unsure, use the default 10.
+
+config IMA_BASE_HOOKS
+	bool "IMA base hooks"
+	depends on IMA
+	default n
+	help
+	  Enable this option to allow the LSM module to enforce integrity.
Index: linux-2.6.26-rc9-git1/security/integrity/ima/Makefile
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/security/integrity/ima/Makefile
@@ -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
Index: linux-2.6.26-rc9-git1/security/integrity/ima/ima_main.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/security/integrity/ima/ima_main.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Serge Hallyn <serue@us.ibm.com>
+ * Kylene Hall <kylene@us.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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_main.c
+ *             implements the IMA LIM hooks
+ */
+#include <linux/module.h>
+#include <linux/integrity.h>
+#include <linux/magic.h>
+#include <linux/writeback.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/audit.h>
+#include <linux/ima.h>
+#include <linux/mman.h>
+
+#include "ima.h"
+
+static bool ima_initialized = false;
+char *ima_hash = "sha1";
+static int __init hash_setup(char *str)
+{
+	char *op = "setup";
+	char *hash = "sha1";
+
+	if (strncmp(str, "md5", 3) == 0) {
+		op = "setup";
+		hash = "md5";
+		ima_hash = str;
+	} else if (strncmp(str, "sha1", 4) != 0) {
+		op = "hash_setup";
+		hash = "invalid_hash_type";
+	}
+	integrity_audit_msg(AUDIT_INTEGRITY_HASH, NULL, NULL, op, hash, 0);
+	return 1;
+}
+
+__setup("ima_hash=", hash_setup);
+
+/* For use when the LSM module makes LIM API calls */
+#ifdef CONFIG_IMA_BASE_HOOKS
+static int ima_base_hooks = 1;
+#else
+static int ima_base_hooks;
+#endif
+
+/*
+ * Setup the data structure used for the IMA LIM API calls.
+ */
+void ima_fixup_argsdata(struct ima_args_data *data,
+			struct inode *inode, struct dentry *dentry,
+			struct file *file, struct nameidata *nd, int mask,
+			int function)
+{
+	data->inode = inode;
+	data->dentry = dentry;
+	data->file = file;
+	data->nd = nd;
+	data->mask = mask;
+	data->function = function;
+
+	if (file && file->f_dentry) {
+		if (!dentry)
+			data->dentry = dentry = file->f_dentry;
+	}
+	if (nd && nd->path.dentry) {
+		if (!dentry)
+			data->dentry = dentry = nd->path.dentry;
+	}
+	if (dentry && dentry->d_inode) {
+		if (!inode)
+			data->inode = inode = dentry->d_inode;
+	}
+
+	return;
+}
+
+/**
+ * ima_file_free - called on close
+ * @file: pointer to file being closed
+ *
+ * Flag files that changed, based on i_version.
+ */
+static void ima_file_free(struct file *file)
+{
+	struct inode *inode = NULL;
+	struct ima_iint_cache *iint;
+
+	if (!file->f_dentry)	/* can be NULL */
+		return;
+
+	inode = file->f_dentry->d_inode;
+	if (S_ISDIR(inode->i_mode))
+		return;
+	if ((file->f_mode & FMODE_WRITE) &&
+	    (atomic_read(&inode->i_writecount) == 1)) {
+		iint = inode->i_integrity;
+		mutex_lock(&iint->mutex);
+		if (iint->version != inode->i_version)
+			iint->measured = 0;
+		mutex_unlock(&iint->mutex);
+	}
+}
+
+/**
+ * ima_alloc_integrity - allocate and attach an integrity structure
+ * @inode: the inode structure
+ *
+ * Returns 0 on success, -ENOMEM on failure
+ */
+static int ima_inode_alloc_integrity(struct inode *inode)
+{
+	struct ima_iint_cache *iint;
+
+	iint = kzalloc(sizeof(*iint), GFP_KERNEL);
+	if (!iint)
+		return -ENOMEM;
+
+	mutex_init(&iint->mutex);
+	inode->i_integrity = iint;
+	iint->version = inode->i_version;
+	return 0;
+}
+
+/**
+ * ima_inode_free_integrity - free the integrity structure
+ * @inode: the inode structure
+ */
+static void ima_inode_free_integrity(struct inode *inode)
+{
+	struct ima_iint_cache *iint = inode->i_integrity;
+
+	if (iint) {
+		inode->i_integrity = NULL;
+		kfree(iint);
+	}
+}
+
+/**
+ * ima_inode_permission - based on policy, collect/store measurement.
+ * @inode: pointer to the inode to be measured
+ * @mask: contains MAY_READ, MAY_WRITE, MAY_APPEND or MAY_EXECUTE
+ * @nd: pointer to a nameidata
+ *
+ * Measure the file associated with the inode, if the
+ * file is open for read and the results of the call to
+ * ima_must_measure() require the file to be measured.
+ *
+ * Invalidate the PCR:
+ * 	- Opening a file for write when already open for read,
+ *	  results in a time of measure, time of use (ToMToU) error.
+ *	- Opening a file for read when already open for write,
+ * 	  could result in a file measurement error.
+ *
+ * Return 0 on success, an error code on failure.
+ * (Based on the results of appraise_measurement().)
+ */
+static int ima_inode_permission(struct inode *inode, int mask,
+				struct nameidata *nd)
+{
+	struct ima_data idata;
+	struct ima_args_data *data = &idata.data.args;
+
+	if (!ima_initialized)
+		return 0;
+
+	memset(&idata, 0, sizeof idata);
+	ima_fixup_argsdata(data, inode, NULL, NULL, nd, mask, INODE_PERMISSION);
+
+	/* The file name is not required, but only a hint. */
+	if (nd)
+		data->filename = (!nd->path.dentry->d_name.name) ?
+		    (char *)nd->path.dentry->d_iname :
+		    (char *)nd->path.dentry->d_name.name;
+
+	/* Invalidate PCR, if a measured file is already open for read */
+	if ((mask == MAY_WRITE) || (mask == MAY_APPEND)) {
+		int mask_sav = data->mask;
+		int rc;
+
+		data->mask = MAY_READ;
+		rc = ima_must_measure(&idata);
+		if (!rc) {
+			if (atomic_read(&(data->dentry->d_count)) - 1 >
+			    atomic_read(&(inode->i_writecount)))
+				ima_add_violation(inode, data->filename,
+						  "invalid_pcr", "ToMToU");
+		}
+		data->mask = mask_sav;
+		goto out;
+	}
+
+	/* measure executables later */
+	if (mask & MAY_READ) {
+		int rc;
+
+		rc = ima_must_measure(&idata);
+		if (!rc) {
+			/* Invalidate PCR, if a measured file is
+			 * already open for write.
+			 */
+			if (atomic_read(&(inode->i_writecount)) > 0)
+				ima_add_violation(inode, data->filename,
+						  "invalid_pcr",
+						  "open_writers");
+
+			idata.type = IMA_DATA;
+			rc = ima_collect_measurement(&idata);
+			if (!rc)
+				ima_store_measurement(&idata);
+		}
+	}
+out:
+	return 0;
+}
+
+/**
+ * ima_file_mmap - based on policy, collect/store measurement.
+ * @inode: pointer to the inode to be measured
+ * @mask: contains MAY_READ, MAY_WRITE, MAY_APPEND or MAY_EXECUTE
+ * @nd: pointer to a nameidata
+ *
+ * Measure files being mmapped executable based on the ima_must_measure()
+ * policy decision.
+ *
+ * Return 0 on success, an error code on failure.
+ * (Based on the results of appraise_measurement().)
+ */
+static int ima_file_mmap(struct file *file, unsigned long reqprot,
+			 unsigned long prot, unsigned long flags,
+			 unsigned long addr, unsigned long addr_only)
+{
+	struct ima_data idata;
+	struct ima_args_data *data = &idata.data.args;
+	int rc = 0;
+
+	if (!ima_initialized)
+		return 0;
+	if (!file || !file->f_dentry)
+		return rc;
+	if (!(prot & VM_EXEC))
+		return rc;
+
+	ima_fixup_argsdata(data, NULL, NULL, file, NULL, MAY_EXEC, FILE_MMAP);
+	data->filename = (file->f_dentry->d_name.name) ?
+	    (char *)file->f_dentry->d_iname :
+	    (char *)file->f_dentry->d_name.name;
+
+	rc = ima_must_measure(&idata);
+	if (!rc) {
+		idata.type = IMA_DATA;
+		rc = ima_collect_measurement(&idata);
+		if (!rc)
+			ima_store_measurement(&idata);
+	}
+	return 0;
+}
+
+/**
+ * ima_bprm_check_integrity - based on policy, collect/store measurement.
+ * @bprm: contains the linux_binprm structure
+ *
+ * The OS protects against an executable file, already open for write,
+ * from being executed in deny_write_access() and an executable file,
+ * already open for execute, from being modified in get_write_access().
+ * So we can be certain that what we verify and measure here is actually
+ * what is being executed.
+ *
+ * Return 0 on success, an error code on failure.
+ * (Based on the results of appraise_measurement().)
+ */
+static int ima_bprm_check_integrity(struct linux_binprm *bprm)
+{
+	struct ima_data idata;
+	struct ima_args_data *data = &idata.data.args;
+	int rc = 0;
+
+	if (!ima_initialized)
+		return 0;
+	ima_fixup_argsdata(data, NULL, NULL, bprm->file, NULL, MAY_EXEC,
+			   BPRM_CHECK);
+	data->filename = bprm->filename;
+
+	rc = ima_must_measure(&idata);
+	if (!rc) {
+		idata.type = IMA_DATA;
+		rc = ima_collect_measurement(&idata);
+		if (!rc)
+			ima_store_measurement(&idata);
+	}
+	return 0;
+}
+
+static const struct integrity_operations ima_integrity_ops = {
+	.bprm_check_integrity = ima_bprm_check_integrity,
+	.inode_permission = ima_inode_permission,
+	.inode_alloc_integrity = ima_inode_alloc_integrity,
+	.inode_free_integrity = ima_inode_free_integrity,
+	.file_free_integrity = ima_file_free,
+	.file_mmap = ima_file_mmap,
+};
+
+static const struct integrity_operations ima_base_ops = {
+	.inode_alloc_integrity = ima_inode_alloc_integrity,
+	.inode_free_integrity = ima_inode_free_integrity,
+	.file_free_integrity = ima_file_free,
+};
+
+/* Register the integrity ops early so that i_integrity is
+ * allocated at inode initialization.
+ */
+static int __init init_ops(void)
+{
+	int error;
+
+	if (ima_base_hooks)
+		error = register_integrity(&ima_base_ops);
+	else
+		error = register_integrity(&ima_integrity_ops);
+	return error;
+}
+
+/* After the TPM is available, start IMA
+ */
+static int __init init_ima(void)
+{
+	int error;
+
+	error = ima_init();
+	if (error)
+		goto out;
+	ima_initialized = true;
+	integrity_register_template("ima", &ima_template_ops);
+out:
+	return error;
+}
+
+static void __exit cleanup_ima(void)
+{
+	integrity_unregister_template("ima");
+	unregister_integrity(&ima_integrity_ops);
+	ima_cleanup();
+}
+
+security_initcall(init_ops);	/* Register the integrity ops early */
+late_initcall(init_ima);	/* Start IMA after the TPM is available */
+module_exit(cleanup_ima);
+
+MODULE_DESCRIPTION("Integrity Measurement Architecture");
+MODULE_LICENSE("GPL");
Index: linux-2.6.26-rc9-git1/security/integrity/ima/ima_init.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/security/integrity/ima/ima_init.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer      <sailer@watson.ibm.com>
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Mimi Zohar         <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima_init.c
+ *             initialization and cleanup functions
+ */
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include "ima.h"
+
+/* name for boot aggregate entry */
+static char *boot_aggregate_name = "boot_aggregate";
+static const char version[] = "v7.6 02/27/2007";
+
+int ima_used_chip;
+
+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);
+	if (entry == NULL) {
+		ima_add_violation(NULL, boot_aggregate_name,
+				  "add_measure", "ENOMEM");
+		return;
+	}
+	count = strlen(boot_aggregate_name);
+	if (count > IMA_EVENT_NAME_LEN_MAX)
+		count = IMA_EVENT_NAME_LEN_MAX;
+	memcpy(entry->template_name, boot_aggregate_name, count);
+	entry->template_name[count] = '\0';
+	if (ima_used_chip) {
+		int i;
+		u8 pcr_i[20];
+		struct hash_desc desc;
+		struct crypto_hash *tfm;
+		struct scatterlist sg;
+
+		tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
+		if (!tfm || IS_ERR(tfm)) {
+			kfree(entry);
+			ima_error("error initializing digest.\n");
+			return;
+		}
+		desc.tfm = tfm;
+		desc.flags = 0;
+		crypto_hash_init(&desc);
+
+		for (i = 0; i < 8; i++) {
+			ima_pcrread(i, pcr_i, sizeof(pcr_i));
+			/* now accumulate with current aggregate */
+			sg_init_one(&sg, (u8 *) pcr_i, 20);
+			crypto_hash_update(&desc, &sg, 20);
+		}
+		crypto_hash_final(&desc, entry->digest);
+		crypto_free_hash(tfm);
+	} else
+		memset(entry->digest, 0xff, 20);
+
+	/* now add measurement; if TPM bypassed, we have a ff..ff entry */
+	err = ima_add_measure_entry(entry, 0);
+	if (err < 0) {
+		kfree(entry);
+		ima_add_violation(NULL, boot_aggregate_name,
+				  "add_measure", " ");
+	}
+}
+
+int ima_init(void)
+{
+	int rc;
+
+	ima_used_chip = 0;
+	rc = tpm_pcr_read(IMA_TPM, 0, NULL);
+	if (rc == 0)
+		ima_used_chip = 1;
+
+	if (!ima_used_chip)
+		ima_info("No TPM chip found(rc = %d), activating TPM-bypass!\n",
+			 rc);
+
+	ima_create_htable();	/* for measurements */
+	ima_add_boot_aggregate();	/* boot aggregate must be first entry */
+
+	return ima_fs_init();
+}
+
+void __exit ima_cleanup(void)
+{
+	ima_fs_cleanup();
+}
Index: linux-2.6.26-rc9-git1/security/integrity/ima/ima_api.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/security/integrity/ima/ima_api.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ *
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima_api.c
+ *            - implements the LIM API
+ */
+#include <linux/module.h>
+#include <linux/integrity.h>
+#include <linux/magic.h>
+#include <linux/writeback.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/audit.h>
+#include <linux/ima.h>
+
+#include "ima.h"
+
+const struct template_operations ima_template_ops = {
+	.must_measure = ima_must_measure,
+	.collect_measurement = ima_collect_measurement,
+	.store_measurement = ima_store_measurement,
+	.display_template = ima_template_show
+};
+
+/**
+ * mode_setup - for compatability with non-template IMA versions
+ * @str: is pointer to a string
+ */
+int ima_template_mode = 1;
+static int __init mode_setup(char *str)
+{
+	if (strncmp(str, "ima", 3) == 0)
+		ima_template_mode = 0;
+	if (strncmp(str, "template", 7) == 0)
+		ima_template_mode = 1;
+	ima_info("template_mode %s \n",
+	       	  ima_template_mode ? "template" : "ima");
+	return 1;
+}
+
+__setup("ima_mode=", mode_setup);
+
+/**
+ * ima_digest_cpy - copy the hash in the IMA template structure to a digest
+ * @template_name: string containing the name of the template (i.e. "ima")
+ * @template: pointer to template structure
+ * @digest: pointer to the digest
+ *
+ * Returns 0 on success, error code otherwise
+ */
+static int ima_digest_cpy(char *template_name, void *template, u8 *digest)
+{
+	int rc, result = 0;
+	struct ima_inode_measure_entry *inode_template =
+	    (struct ima_inode_measure_entry *)template;
+
+	rc = strcmp(template_name, "ima");
+	if (rc == 0)
+		memcpy(digest, inode_template->digest,
+		       sizeof inode_template->digest);
+	else
+		result = -ENODATA;
+	return result;
+}
+
+/**
+ * ima_store_template_measure - collect and protect template measurements
+ * @template_name: string containing the name of the template (i.e. "ima")
+ * @template_len: length of the template data
+ * @template: actual template data
+ * @violation: invalidate pcr measurement indication
+ * @audit_cause: string containing the audit failure cause
+ *
+ * Calculate the hash of a template entry, add the template entry
+ * to an ordered list of measurement entries maintained inside the kernel,
+ * and also update the aggregate integrity value (maintained inside the
+ * configured TPM PCR) over the hashes of the current list of measurement
+ * entries.
+ *
+ * Applications retrieve the current kernel-held measurement list through
+ * the securityfs entries in /sys/kernel/security/ima. The signed aggregate
+ * TPM PCR (called quote) can be retrieved using a TPM user space library
+ * and is used to validate the measurement list.
+ *
+ * Returns 0 on success, error code otherwise
+ */
+static int ima_store_template_measure(char *template_name, int template_len,
+				      char *template, int violation,
+				      char **audit_cause)
+{
+	struct ima_measure_entry *entry;
+	u8 digest[IMA_DIGEST_SIZE];
+	struct ima_queue_entry *qe;
+	int count, result = 0;
+
+	memset(digest, 0, IMA_DIGEST_SIZE);
+	if (!violation) {
+		int rc = -ENODATA;
+
+		if (!ima_template_mode)
+			rc = ima_digest_cpy(template_name, template, digest);
+		if (rc < 0)
+			result = ima_calc_template_hash(template_len, template,
+							digest);
+
+		/* hash exists already? */
+		qe = ima_lookup_digest_entry(digest);
+		if (qe) {
+			*audit_cause = "hash_exists";
+			result = -EEXIST;
+			goto out;
+		}
+	}
+
+	/* create new entry and add to measurement list */
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry) {
+		*audit_cause = "ENOMEM";
+		result = -ENOMEM;
+		goto out;
+	}
+
+	entry->template = kzalloc(template_len, GFP_KERNEL);
+	if (!entry->template) {
+		*audit_cause = "ENOMEM";
+		result = -ENOMEM;
+		goto out;
+	}
+	if (!template_name) {
+		*audit_cause = "null_template_name";
+		count = 1;
+	} else {
+		count = strlen(template_name);
+		if (count > IMA_EVENT_NAME_LEN_MAX)
+			count = IMA_EVENT_NAME_LEN_MAX;
+		memcpy(entry->template_name, template_name, count);
+	}
+	entry->template_name[count] = '\0';
+	entry->template_len = template_len;
+	memcpy(entry->template, template, template_len);
+	memcpy(entry->digest, digest, IMA_DIGEST_SIZE);
+
+	result = ima_add_measure_entry(entry, violation);
+	if (result < 0)
+		kfree(entry);
+out:
+	return result;
+}
+
+/**
+ * ima_store_inode_measure - create and store an inode template measurement
+ * @name: ascii file name associated with the measurement hash
+ * @hash_len: length of hash value in bytes (16 for MD5, 20 for SHA1)
+ * @hash: actual hash value pre-calculated
+ *
+ * Returns 0 on success, error code otherwise
+ */
+static int ima_store_inode_measure(struct inode *inode,
+				   const unsigned char *name,
+				   int hash_len, char *hash, int violation)
+{
+	struct ima_inode_measure_entry measure_entry, *entry = &measure_entry;
+	int result;
+	int namelen;
+	char *op = "add_measure";
+	char *cause = " ";
+
+	memset(entry, 0, sizeof *entry);
+	if (!violation)
+		memcpy(entry->digest, hash, hash_len > IMA_DIGEST_SIZE ?
+		       IMA_DIGEST_SIZE : hash_len);
+	if (name) {
+		namelen = strlen(name);
+		memcpy(entry->file_name, name, namelen > IMA_EVENT_NAME_LEN_MAX
+		       ? IMA_EVENT_NAME_LEN_MAX : namelen);
+		entry->file_name[namelen] = '\0';
+	}
+	result = ima_store_template_measure("ima", sizeof *entry, (char *)entry,
+					    violation, &cause);
+	if (result < 0)
+		integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
+				    name, op, cause, result);
+	return result;
+}
+
+/**
+ * ima_add_violation - add violation to measurement list.
+ * @inode: inode associated with the violation
+ * @fname: name associated with the inode
+ * @op: string pointer to audit operation (i.e. "invalid_pcr", "add_measure")
+ * @cause: string pointer to reason for violation (i.e. "ToMToU")
+ *
+ * Violations are flagged in the measurement list with zero hash values.
+ * By extending the PCR with 0xFF's instead of with zeroes, the PCR
+ * value is invalidated.
+ */
+void ima_add_violation(struct inode *inode, const unsigned char *fname,
+		       char *op, char *cause)
+{
+	int result;
+
+	/* can overflow, only indicator */
+	atomic_inc(&ima_htable.violations);
+
+	result = ima_store_inode_measure(inode, fname, 0, NULL, 1);
+	integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, fname, op,
+			    cause, result);
+}
+
+/**
+ * skip_measurement - measure only regular files, skip everything else.
+ * @inode: inode being measured
+ * @mask: contains the permission mask
+ *
+ * Quick sanity check to make sure that only regular files opened
+ * for read-only or execute are measured.
+ *
+ * Return 1 to skip measure, 0 to measure
+ */
+static int skip_measurement(struct inode *inode, int mask)
+{
+	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+		return 1;	/* can't measure */
+
+	if (special_file(inode->i_mode) || S_ISLNK(inode->i_mode))
+		return 1;	/* don't measure */
+
+	if (S_ISREG(inode->i_mode))
+		return 0;	/* measure */
+	return 1;		/* don't measure */
+}
+
+/**
+ * ima_must_measure - measure decision based on policy.
+ * @template_data: pointer to struct ima_data containing ima_args_data
+ *
+ * The policy is defined in terms of keypairs:
+ * 		subj=, obj=, type=, func=, mask=, fsmagic=
+ *	subj,obj, and type: are LSM specific.
+ * 	func: INODE_PERMISSION | BPRM_CHECK | FILE_MMAP
+ * 	mask: contains the permission mask
+ *	fsmagic: hex value
+ *
+ * Return 0 to measure. For matching a DONT_MEASURE policy, no policy,
+ * or other error, return an error code.
+*/
+int ima_must_measure(void *template_data)
+{
+	struct ima_data *idata = (struct ima_data *)template_data;
+	struct ima_args_data *data = &idata->data.args;
+	int rc;
+
+	if ((data->mask & MAY_WRITE) || (data->mask & MAY_APPEND))
+		return -EPERM;
+
+	if (skip_measurement(data->inode, data->mask))
+		return -EPERM;
+
+	rc = ima_match_policy(data->inode, data->function, data->mask);
+	if (rc)
+		return 0;
+	return -EACCES;
+}
+
+/**
+ * ima_collect_measurement - collect file measurements and store in the inode
+ * @template_data: pointer to struct ima_data containing ima_args_data
+ *
+ * Return 0 on success, error code otherwise
+ */
+int ima_collect_measurement(void *template_data)
+{
+	struct ima_iint_cache *iint;
+	struct ima_data *idata = (struct ima_data *)template_data;
+	struct ima_args_data *data = &idata->data.args;
+	struct inode *inode = data->inode;
+	struct dentry *dentry = data->dentry;
+	struct nameidata *nd = data->nd;
+	struct file *file = data->file;
+	int result = 0;
+
+	if (idata->type != IMA_DATA)
+		return -EPERM;
+
+	if (!inode || !dentry)
+		return -EINVAL;
+
+	iint = inode->i_integrity;
+	mutex_lock(&iint->mutex);
+	if (!iint->measured) {
+		memset(iint->digest, 0, IMA_DIGEST_SIZE);
+		result = ima_calc_hash(dentry, file, nd, iint->digest);
+	} else
+		result = -EEXIST;
+	mutex_unlock(&iint->mutex);
+	return result;
+}
+
+/**
+ * ima_store_measurement - store file and template measurements
+ * @template_data: pointer to struct ima_data containing ima_args_data,
+ * used to create an IMA template, or a template.
+ *
+ * For file measurements, first create an IMA template and then store it.
+ * For all other types of template measurements, just store it.
+ */
+void ima_store_measurement(void *template_data)
+{
+	struct ima_data *idata = (struct ima_data *)template_data;
+	int result;
+	char *op = "add_template_measure";
+	char *cause = "";
+
+	if (idata->type == IMA_DATA) {
+		struct ima_args_data *data = &idata->data.args;
+		struct ima_iint_cache *iint;
+
+		iint = data->inode->i_integrity;
+		mutex_lock(&iint->mutex);
+		if (iint->measured) {
+			mutex_unlock(&iint->mutex);
+			return;
+		}
+		result = ima_store_inode_measure(data->inode, data->filename,
+						 IMA_DIGEST_SIZE, iint->digest,
+						 0);
+		if (!result || result == -EEXIST) {
+			iint->measured = 1;
+			iint->version = data->inode->i_version;
+		}
+		mutex_unlock(&iint->mutex);
+	} else if (idata->type == IMA_TEMPLATE) {
+		struct ima_store_data *template = (struct ima_store_data *)
+		    &idata->data.template;
+
+		result = ima_store_template_measure(template->name,
+						    template->len,
+						    template->data, 0, &cause);
+		if (result < 0)
+			integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL,
+					    template->name, op, cause, result);
+	}
+}
Index: linux-2.6.26-rc9-git1/security/integrity/ima/ima.h
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/security/integrity/ima/ima.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima.h
+ *	internal ima definitions
+ */
+
+#ifndef __LINUX_IMA_H
+#define __LINUX_IMA_H
+
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/security.h>
+#include <linux/integrity.h>
+#include <linux/hash.h>
+#include <linux/tpm.h>
+
+#define ima_printk(level, format, arg...)		\
+	printk(level "ima (%s): " format, __func__, ## arg)
+
+#define ima_error(format, arg...)	\
+	ima_printk(KERN_ERR, format, ## arg)
+
+#define ima_info(format, arg...)	\
+	ima_printk(KERN_INFO, format, ## arg)
+
+/* digest size for IMA, fits SHA1 or MD5 */
+#define IMA_DIGEST_SIZE		20
+#define IMA_EVENT_NAME_LEN_MAX	255
+
+#define IMA_HASH_BITS 9
+#define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS)
+
+/* set during initialization */
+extern int ima_used_chip;
+extern char *ima_hash;
+
+struct ima_measure_entry {
+	u8 digest[IMA_DIGEST_SIZE];	/* sha1 or md5 measurement hash */
+	char template_name[IMA_EVENT_NAME_LEN_MAX + 1];	/* name + \0 */
+	int template_len;
+	char *template;
+};
+
+struct ima_queue_entry {
+	struct hlist_node hnext;	/* place in hash collision list */
+	struct list_head later;		/* place in ima_measurements list */
+	struct ima_measure_entry *entry;
+};
+extern struct list_head ima_measurements;	/* list of all measurements */
+
+/* declarations */
+extern int ima_template_mode;
+extern const struct template_operations ima_template_ops;
+
+/* Internal IMA function definitions */
+int ima_init(void);
+void ima_cleanup(void);
+int ima_fs_init(void);
+void ima_fs_cleanup(void);
+void ima_create_htable(void);
+int ima_add_measure_entry(struct ima_measure_entry *entry, int violation);
+struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest);
+int ima_calc_hash(struct dentry *dentry, struct file *file,
+			struct nameidata *, char *digest);
+int ima_calc_template_hash(int template_len, char *template, char *digest);
+void ima_add_violation(struct inode *inode, const unsigned char *fname,
+			char *op, char *cause);
+
+enum ima_action {DONT_MEASURE, MEASURE};
+int ima_match_policy(struct inode *inode, enum lim_hooks func, int mask);
+int ima_add_rule(int, char *, char *, char *, char *, char *, char *);
+void ima_init_policy(void);
+void ima_update_policy(void);
+
+
+/* LIM API function definitions */
+int ima_must_measure(void *d);
+int ima_collect_measurement(void *d);
+int ima_appraise_measurement(void *d);
+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
+ */
+extern spinlock_t ima_queue_lock;
+
+struct ima_h_table {
+	atomic_t len;		/* number of stored measurements in the list */
+	atomic_long_t violations;
+	unsigned int max_htable_size;
+	struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE];
+	atomic_t queue_len[IMA_MEASURE_HTABLE_SIZE];
+};
+extern struct ima_h_table ima_htable;
+
+static inline unsigned long IMA_HASH_KEY(u8 *digest)
+{
+	 return(hash_ptr(digest, IMA_HASH_BITS));
+}
+
+/* TPM "Glue" definitions */
+
+#define IMA_TPM ((((u32)TPM_ANY_TYPE)<<16) | (u32)TPM_ANY_NUM)
+static inline void ima_extend(const u8 *hash)
+{
+	if (!ima_used_chip)
+		return;
+
+	if (tpm_pcr_extend(IMA_TPM, CONFIG_IMA_MEASURE_PCR_IDX, hash) != 0)
+		ima_error("Error Communicating to TPM chip\n");
+}
+
+static inline void ima_pcrread(int idx, u8 *pcr, int pcr_size)
+{
+	if (!ima_used_chip)
+		return;
+
+	if (tpm_pcr_read(IMA_TPM, idx, pcr) != 0)
+		ima_error("Error Communicating to TPM chip\n");
+}
+
+struct ima_inode_measure_entry {
+	u8 digest[IMA_DIGEST_SIZE];	/* sha1/md5 measurement hash */
+	char file_name[IMA_EVENT_NAME_LEN_MAX + 1];	/* name + \0 */
+};
+
+/* inode integrity data */
+struct ima_iint_cache {
+	u64 		version;
+	int 		measured;
+	u8 		hmac[IMA_DIGEST_SIZE];
+	u8 		digest[IMA_DIGEST_SIZE];
+	struct mutex mutex;
+};
+#endif
Index: linux-2.6.26-rc9-git1/security/integrity/ima/ima_crypto.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/security/integrity/ima/ima_crypto.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zohar@us.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * 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_crypto.c
+ * 	Calculate a file's or a template's hash.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/crypto.h>
+#include <linux/mm.h>
+#include <linux/mount.h>
+#include <linux/scatterlist.h>
+#include "ima.h"
+
+/*
+ * Calculate the file hash, using an open file descriptor if available.
+ */
+static int update_file_hash(struct dentry *dentry, struct file *f,
+			    struct nameidata *nd, struct hash_desc *desc)
+{
+	struct file *file = f;
+	struct scatterlist sg[1];
+	loff_t i_size;
+	int rc = 0;
+	char *rbuf;
+	int offset = 0;
+
+	if (!file) {
+		struct dentry *de = dget(dentry);
+		struct vfsmount *mnt = mntget(nd->path.mnt);
+		if (!de || !mnt) {
+			rc = -EINVAL;
+			goto err_out;
+		}
+		file = dentry_open(de, mnt, O_RDONLY);
+		if (IS_ERR(file)) {
+			ima_info("%s dentry_open failed\n", de->d_name.name);
+			rc = PTR_ERR(file);
+			file = NULL;
+		}
+err_out:
+		if (!file) {
+			dput(de);
+			mntput(mnt);
+			goto out;
+		}
+	}
+
+	if (!file->f_dentry || !file->f_dentry->d_inode) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!rbuf) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	i_size = i_size_read(file->f_dentry->d_inode);
+	while (offset < i_size) {
+		int rbuf_len;
+
+		rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE);
+		if (rbuf_len < 0) {
+			rc = rbuf_len;
+			break;
+		}
+		offset += rbuf_len;
+		sg_set_buf(sg, rbuf, rbuf_len);
+
+		rc = crypto_hash_update(desc, sg, rbuf_len);
+		if (rc)
+			break;
+	}
+	kfree(rbuf);
+out:
+	if (file && !f)
+		fput(file);	/* clean up dentry_open() */
+	return rc;
+}
+
+/*
+ * Calculate the MD5/SHA1 digest
+ */
+int ima_calc_hash(struct dentry *dentry, struct file *file,
+		  struct nameidata *nd, char *digest)
+{
+	struct hash_desc desc;
+	int rc;
+
+	if (!dentry && !file)
+		return -EINVAL;
+
+	desc.tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(desc.tfm)) {
+		ima_info("failed to load %s transform: %ld\n",
+			 ima_hash, PTR_ERR(desc.tfm));
+		rc = PTR_ERR(desc.tfm);
+		return rc;
+	}
+	desc.flags = 0;
+	rc = crypto_hash_init(&desc);
+	if (rc)
+		goto out;
+
+	rc = update_file_hash(dentry, file, nd, &desc);
+	if (!rc)
+		rc = crypto_hash_final(&desc, digest);
+out:
+	crypto_free_hash(desc.tfm);
+	return rc;
+}
+
+/*
+ * Calculate the hash of a given template
+ */
+int ima_calc_template_hash(int template_len, char *template, char *digest)
+{
+	struct hash_desc desc;
+	struct scatterlist sg[1];
+	int rc;
+
+	desc.tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(desc.tfm)) {
+		ima_info("failed to load %s transform: %ld\n",
+			 ima_hash, PTR_ERR(desc.tfm));
+		rc = PTR_ERR(desc.tfm);
+		return rc;
+	}
+	desc.flags = 0;
+	rc = crypto_hash_init(&desc);
+	if (rc)
+		goto out;
+
+	sg_set_buf(sg, template, template_len);
+	rc = crypto_hash_update(&desc, sg, template_len);
+	if (!rc)
+		rc = crypto_hash_final(&desc, digest);
+out:
+	crypto_free_hash(desc.tfm);
+	return rc;
+}
Index: linux-2.6.26-rc9-git1/security/integrity/ima/ima_fs.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/security/integrity/ima/ima_fs.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Kylene Hall <kjhall@us.ibm.com>
+ * Reiner Sailer <sailer@us.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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_fs.c
+ *	implemenents security file system for reporting
+ *	current measurement list and IMA statistics
+ */
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/integrity.h>
+
+#include "ima.h"
+
+#define TMPBUFLEN 12
+static ssize_t ima_show_htable_value(char __user *buf, size_t count,
+				     loff_t *ppos, atomic_t *val)
+{
+	char tmpbuf[TMPBUFLEN];
+	ssize_t len;
+
+	len = scnprintf(tmpbuf, TMPBUFLEN, "%i\n", atomic_read(val));
+	return simple_read_from_buffer(buf, count, ppos, tmpbuf, len);
+}
+
+static ssize_t ima_show_htable_violations(struct file *filp,
+					  char __user *buf,
+					  size_t count, loff_t *ppos)
+{
+	return ima_show_htable_value(buf, count, ppos, &ima_htable.violations);
+}
+
+static struct file_operations ima_htable_violations_ops = {
+	.read = ima_show_htable_violations
+};
+
+static ssize_t ima_show_measurements_count(struct file *filp,
+					   char __user *buf,
+					   size_t count, loff_t *ppos)
+{
+	return ima_show_htable_value(buf, count, ppos, &ima_htable.len);
+
+}
+
+static struct file_operations ima_measurements_count_ops = {
+	.read = ima_show_measurements_count
+};
+
+/* returns pointer to hlist_node */
+static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
+{
+	struct list_head *lpos;
+	loff_t l = *pos;
+	/* we need a lock since pos could point beyond last element */
+	rcu_read_lock();
+	list_for_each_rcu(lpos, &ima_measurements) {
+		if (!l--) {
+			rcu_read_unlock();
+			return lpos;
+		}
+	}
+	rcu_read_unlock();
+	return NULL;
+}
+
+static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	/* lock protects when reading beyond last element
+	 * against concurrent list-extension */
+	struct list_head *lpos = (struct list_head *)v;
+
+	rcu_read_lock();
+	lpos = rcu_dereference(lpos->next);
+	rcu_read_unlock();
+	(*pos)++;
+
+	return (lpos == &ima_measurements) ? NULL : lpos;
+}
+
+static void ima_measurements_stop(struct seq_file *m, void *v)
+{
+}
+
+/* print format:
+ *       32bit-le=pcr#
+ *       char[20]=template digest
+ *       32bit-le=template size
+ *       32bit-le=template name size
+ *       eventdata[n] = template name
+ *
+ */
+static int ima_measurements_show(struct seq_file *m, void *v)
+{
+	/* the list never shrinks, so we don't need a lock here */
+	struct list_head *lpos = v;
+	struct ima_queue_entry *qe;
+	struct ima_measure_entry *e;
+	struct ima_inode_measure_entry *entry;
+	const struct template_operations *template_ops;
+	int templatename_len;
+	int i;
+	u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX;
+	char data[4];
+
+	/* get entry */
+	qe = list_entry(lpos, struct ima_queue_entry, later);
+	e = qe->entry;
+	if (e == NULL)
+		return -1;
+
+	/*
+	 * 1st: PCRIndex
+	 * PCR used is always the same (config option) in
+	 * little-endian format
+	 */
+	memcpy(data, &pcr, 4);
+	for (i = 0; i < 4; i++)
+		seq_putc(m, data[i]);
+
+	/* 2nd: template digest */
+	for (i = 0; i < 20; i++)
+		seq_putc(m, e->digest[i]);
+
+	/* 3rd: template name size */
+	templatename_len = strlen(e->template_name);
+	if (templatename_len > IMA_EVENT_NAME_LEN_MAX)
+		templatename_len = IMA_EVENT_NAME_LEN_MAX;
+
+	memcpy(data, &templatename_len, 4);
+	for (i = 0; i < 4; i++)
+		seq_putc(m, data[i]);
+
+	/* 4th:  template name  */
+	for (i = 0; i < templatename_len; i++)
+		seq_putc(m, e->template_name[i]);
+
+	/* 5th:  template dependent */
+	entry = (struct ima_inode_measure_entry *)e->template;
+	if (integrity_find_template(e->template_name, &template_ops) == 0)
+		template_ops->display_template(m, entry, INTEGRITY_SHOW_BINARY);
+	else
+		seq_printf(m, " \n");
+	return 0;
+}
+
+static struct seq_operations ima_measurments_seqops = {
+	.start = ima_measurements_start,
+	.next = ima_measurements_next,
+	.stop = ima_measurements_stop,
+	.show = ima_measurements_show
+};
+
+static int ima_measurements_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &ima_measurments_seqops);
+}
+
+static struct file_operations ima_measurements_ops = {
+	.open = ima_measurements_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+void ima_template_show(struct seq_file *m, void *e,
+		       enum integrity_show_type show)
+{
+	struct ima_inode_measure_entry *entry =
+	    (struct ima_inode_measure_entry *)e;
+	int filename_len;
+	char data[4];
+	int i;
+
+	/* Display file digest */
+	if (ima_template_mode)
+		for (i = 0; i < 20; i++) {
+			switch (show) {
+			case INTEGRITY_SHOW_ASCII:
+				seq_printf(m, "%02x", entry->digest[i]);
+				break;
+			case INTEGRITY_SHOW_BINARY:
+				seq_putc(m, entry->digest[i]);
+			default:
+				break;
+			}
+		}
+
+	switch (show) {
+	case INTEGRITY_SHOW_ASCII:
+		seq_printf(m, " %s\n", entry->file_name);
+		break;
+	case INTEGRITY_SHOW_BINARY:
+		filename_len = strlen(entry->file_name);
+		if (filename_len > IMA_EVENT_NAME_LEN_MAX)
+			filename_len = IMA_EVENT_NAME_LEN_MAX;
+
+		memcpy(data, &filename_len, 4);
+		for (i = 0; i < 4; i++)
+			seq_putc(m, data[i]);
+		for (i = 0; i < filename_len; i++)
+			seq_putc(m, entry->file_name[i]);
+	default:
+		break;
+	}
+}
+
+/* print in ascii */
+static int ima_ascii_measurements_show(struct seq_file *m, void *v)
+{
+	/* the list never shrinks, so we don't need a lock here */
+	struct list_head *lpos = v;
+	struct ima_queue_entry *qe;
+	struct ima_measure_entry *e;
+	struct ima_inode_measure_entry *entry;
+	const struct template_operations *template_ops;
+	int i;
+
+	/* get entry */
+	qe = list_entry(lpos, struct ima_queue_entry, later);
+	e = qe->entry;
+	if (e == NULL)
+		return -1;
+
+	/* 1st: PCR used (config option) */
+	seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX);
+
+	/* 2nd: SHA1 template hash */
+	for (i = 0; i < 20; i++)
+		seq_printf(m, "%02x", e->digest[i]);
+
+	/* 3th:  template name */
+	seq_printf(m, " %s ", e->template_name);
+
+	/* 4th:  filename <= max + \'0' delimiter */
+	entry = (struct ima_inode_measure_entry *)e->template;
+	if (integrity_find_template(e->template_name, &template_ops) == 0)
+		template_ops->display_template(m, entry, INTEGRITY_SHOW_ASCII);
+	else
+		seq_printf(m, " \n");
+
+	return 0;
+}
+
+static struct seq_operations ima_ascii_measurements_seqops = {
+	.start = ima_measurements_start,
+	.next = ima_measurements_next,
+	.stop = ima_measurements_stop,
+	.show = ima_ascii_measurements_show
+};
+
+static int ima_ascii_measurements_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &ima_ascii_measurements_seqops);
+}
+
+static struct file_operations ima_ascii_measurements_ops = {
+	.open = ima_ascii_measurements_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static char *get_tag(char *bufStart, char *bufEnd, char delimiter, int *taglen)
+{
+	char *bufp = bufStart;
+	char *tag;
+
+	/* Get start of tag */
+	while (bufp < bufEnd) {
+		if (*bufp == ' ')	/* skip blanks */
+			while ((*bufp == ' ') && (bufp++ < bufEnd)) ;
+		else if (*bufp == '#') {	/* skip comment */
+			while ((*bufp != '\n') && (bufp++ < bufEnd)) ;
+			bufp++;
+		} else if (*bufp == '\n')	/* skip newline */
+			bufp++;
+		else if (*bufp == '\t')	/* skip tabs */
+			bufp++;
+		else
+			break;
+	}
+	if (bufp < bufEnd)
+		tag = bufp;
+	else
+		return NULL;
+
+	/* Get tag */
+	*taglen = 0;
+	while ((bufp < bufEnd) && (*taglen == 0)) {
+		if ((*bufp == delimiter) || (*bufp == '\n')) {
+			*taglen = bufp - tag;
+			*bufp = '\0';
+		}
+		bufp++;
+	}
+	if (*taglen == 0)	/* Didn't find end delimiter */
+		tag = NULL;
+	return tag;
+}
+
+static ssize_t ima_write_policy(struct file *file, const char __user *buf,
+				size_t buflen, loff_t *ppos)
+{
+	size_t rc = 0, datalen;
+	int action = 0;
+	char *data, *datap, *dataend;
+	char *subj = NULL, *obj = NULL, *type = NULL;
+	char *func = NULL, *mask = NULL, *fsmagic = NULL;
+	int err = 0;
+	char *tag;
+	int taglen, i;
+
+	datalen = buflen > 4095 ? 4095 : buflen;
+	data = kmalloc(datalen + 1, GFP_KERNEL);
+	if (!data)
+		rc = -ENOMEM;
+
+	if (copy_from_user(data, buf, datalen)) {
+		kfree(data);
+		return -EFAULT;
+	}
+
+	rc = datalen;
+	*(data + datalen) = ' ';
+
+	datap = data;
+	dataend = data + datalen;
+
+	if (strncmp(datap, "measure", 7) == 0) {
+		datap += 8;
+		action = 1;
+	} else if (strncmp(datap, "dont_measure", 12) == 0)
+		datap += 13;
+	else			/* bad format */
+		goto out;
+
+	for (i = 0; i < 6; i++) {
+		tag = get_tag(datap, dataend, ' ', &taglen);
+		if (!tag)
+			break;
+		if (strncmp(tag, "obj=", 4) == 0)
+			obj = tag + 4;
+		else if (strncmp(tag, "subj=", 5) == 0)
+			subj = tag + 5;
+		else if (strncmp(tag, "type=", 5) == 0)
+			type = tag + 5;
+		else if (strncmp(tag, "func=", 5) == 0)
+			func = tag + 5;
+		else if (strncmp(tag, "mask=", 5) == 0)
+			mask = tag + 5;
+		else if (strncmp(tag, "fsmagic=", 8) == 0)
+			fsmagic = tag + 8;
+		else {		/* bad format */
+			err = 1;
+			break;
+		}
+		datap += taglen + 1;
+	}
+
+	if (!err) {
+		ima_info("%s %s %s %s %s %s %s\n",
+			 action ? "measure " : "dont_measure",
+			 subj, obj, type, func, mask, fsmagic);
+		ima_add_rule(action, subj, obj, type, func, mask, fsmagic);
+	}
+out:
+	if (!data)
+		kfree(data);
+	return rc;
+}
+
+static struct dentry *ima_dir;
+static struct dentry *binary_runtime_measurements;
+static struct dentry *ascii_runtime_measurements;
+static struct dentry *runtime_measurements_count;
+static struct dentry *violations;
+static struct dentry *ima_policy;
+
+static int ima_release_policy(struct inode *inode, struct file *file)
+{
+	ima_update_policy();
+	securityfs_remove(ima_policy);
+	ima_policy = NULL;
+	return 0;
+}
+
+static struct file_operations ima_measure_policy_ops = {
+	.write = ima_write_policy,
+	.release = ima_release_policy
+};
+
+int ima_fs_init(void)
+{
+	ima_dir = securityfs_create_dir("ima", NULL);
+	if (!ima_dir || IS_ERR(ima_dir))
+		return -1;
+
+	binary_runtime_measurements =
+	    securityfs_create_file("binary_runtime_measurements",
+				   S_IRUSR | S_IRGRP, ima_dir, NULL,
+				   &ima_measurements_ops);
+	if (!binary_runtime_measurements || IS_ERR(binary_runtime_measurements))
+		goto out;
+
+	ascii_runtime_measurements =
+	    securityfs_create_file("ascii_runtime_measurements",
+				   S_IRUSR | S_IRGRP, ima_dir, NULL,
+				   &ima_ascii_measurements_ops);
+	if (!ascii_runtime_measurements || IS_ERR(ascii_runtime_measurements))
+		goto out;
+
+	runtime_measurements_count =
+	    securityfs_create_file("runtime_measurements_count",
+				   S_IRUSR | S_IRGRP, ima_dir, NULL,
+				   &ima_measurements_count_ops);
+	if (!runtime_measurements_count || IS_ERR(runtime_measurements_count))
+		goto out;
+
+	violations =
+	    securityfs_create_file("violations", S_IRUSR | S_IRGRP,
+				   ima_dir, NULL, &ima_htable_violations_ops);
+	if (!violations || IS_ERR(violations))
+		goto out;
+
+	ima_policy = securityfs_create_file("policy",
+					    S_IRUSR | S_IRGRP | S_IWUSR,
+					    ima_dir, NULL,
+					    &ima_measure_policy_ops);
+	ima_init_policy();
+	return 0;
+
+out:
+	securityfs_remove(runtime_measurements_count);
+	securityfs_remove(ascii_runtime_measurements);
+	securityfs_remove(binary_runtime_measurements);
+	securityfs_remove(ima_dir);
+	securityfs_remove(ima_policy);
+	return -1;
+}
+
+void __exit ima_fs_cleanup(void)
+{
+	securityfs_remove(violations);
+	securityfs_remove(runtime_measurements_count);
+	securityfs_remove(ascii_runtime_measurements);
+	securityfs_remove(binary_runtime_measurements);
+	securityfs_remove(ima_dir);
+	securityfs_remove(ima_policy);
+}
Index: linux-2.6.26-rc9-git1/security/integrity/ima/ima_queue.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/security/integrity/ima/ima_queue.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Serge Hallyn <serue@us.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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_queue.c
+ *       implements queues that store IMA measurements and
+ *       maintains aggregate over the stored measurements
+ *       in the pre-configured TPM PCR (if available)
+ *       The measurement list is append-only. No entry is
+ *       ever removed or changed during the boot-cycle.
+ */
+#include <linux/module.h>
+
+#include "ima.h"
+
+struct list_head ima_measurements;	/* list of all measurements */
+struct ima_h_table ima_htable;	/* key: inode (before secure-hashing a file) */
+
+/* mutex protects atomicity of extending measurement list
+ * and extending the TPM PCR aggregate. Since tpm_extend can take
+ * long (and the tpm driver uses a mutex), we can't use the spinlock.
+ */
+static DEFINE_MUTEX(ima_extend_list_mutex);
+
+void ima_create_htable(void)
+{
+	int i;
+
+	INIT_LIST_HEAD(&ima_measurements);
+	atomic_set(&ima_htable.len, 0);
+	atomic_set(&ima_htable.violations, 0);
+	ima_htable.max_htable_size = IMA_MEASURE_HTABLE_SIZE;
+
+	for (i = 0; i < ima_htable.max_htable_size; i++) {
+		INIT_HLIST_HEAD(&ima_htable.queue[i]);
+		atomic_set(&ima_htable.queue_len[i], 0);
+	}
+}
+
+struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value)
+{
+	struct ima_queue_entry *qe, *ret = NULL;
+	unsigned int key;
+	struct hlist_node *pos;
+
+	key = IMA_HASH_KEY(digest_value);
+	rcu_read_lock();
+	hlist_for_each_entry_rcu(qe, pos, &ima_htable.queue[key], hnext) {
+		if (memcmp(qe->entry->digest, digest_value, 20) == 0) {
+			ret = qe;
+			break;
+		}
+	}
+	rcu_read_unlock();
+	return ret;
+}
+
+/* Called with mutex held */
+static int ima_add_digest_entry(struct ima_measure_entry *entry)
+{
+	struct ima_queue_entry *qe;
+	unsigned int key;
+
+	key = IMA_HASH_KEY(entry->digest);
+	qe = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (qe == NULL) {
+		ima_error("OUT OF MEMORY ERROR creating queue entry.\n");
+		return -ENOMEM;
+	}
+	qe->entry = entry;
+
+	hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]);
+	atomic_inc(&ima_htable.queue_len[key]);
+	return 0;
+}
+
+int ima_add_measure_entry(struct ima_measure_entry *entry, int violation)
+{
+	struct ima_queue_entry *qe;
+	int error = 0;
+
+	mutex_lock(&ima_extend_list_mutex);
+	if (!violation) {
+		if (ima_lookup_digest_entry(entry->digest)) {
+			error = -EEXIST;
+			goto out;
+		}
+	}
+	qe = kmalloc(sizeof(struct ima_queue_entry), GFP_KERNEL);
+	if (qe == NULL) {
+		ima_error("OUT OF MEMORY in %s.\n", __func__);
+		error = -ENOMEM;
+		goto out;
+	}
+	qe->entry = entry;
+
+	INIT_LIST_HEAD(&qe->later);
+	list_add_tail_rcu(&qe->later, &ima_measurements);
+
+	atomic_inc(&ima_htable.len);
+	if (ima_add_digest_entry(entry)) {
+		error = -ENOMEM;
+		goto out;
+	}
+	if (violation) {	/* Replace 0x00 with 0xFF */
+		u8 digest[IMA_DIGEST_SIZE];
+
+		memset(digest, 0xff, sizeof digest);
+		ima_extend(digest);
+	} else
+		ima_extend(entry->digest);
+out:
+	mutex_unlock(&ima_extend_list_mutex);
+	return error;
+}
Index: linux-2.6.26-rc9-git1/security/integrity/ima/ima_policy.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/security/integrity/ima/ima_policy.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * ima_policy.c
+ * 	- initialize default measure policy rules
+	- load a policy ruleset
+ *
+ */
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/audit.h>
+#include <linux/security.h>
+#include <linux/integrity.h>
+#include <linux/magic.h>
+
+#include "ima.h"
+
+#define security_filter_rule_init security_audit_rule_init
+#define security_filter_rule_match security_audit_rule_match
+
+struct ima_measure_rule_entry {
+	struct list_head list;
+	int action;
+	void *lsm_obj_rule;
+	void *lsm_subj_rule;
+	void *lsm_type_rule;
+	enum lim_hooks func;
+	int mask;
+	ulong fsmagic;
+};
+
+/* Without LSM specific knowledge, default policy can only
+ * be written in terms of .action, .func, .mask and .fsmagic.
+ */
+static struct ima_measure_rule_entry default_rules[] = {
+	{.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC},
+	{.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC},
+	{.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC},
+	{.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC},
+	{.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC},
+	{.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC},
+	{.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC},
+	{.action = MEASURE,.func = INODE_PERMISSION,.mask = MAY_READ},
+};
+
+static struct list_head measure_default_rules;
+static struct list_head measure_policy_rules;
+static struct list_head *ima_measure;
+
+static DEFINE_MUTEX(ima_measure_mutex);
+
+/**
+ * ima_match_rules - determine whether an inode matches the measure rule.
+ * @rule: a pointer to a rule
+ * @inode: a pointer to an inode
+ * @func: LIM hook identifier
+ * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ *
+ * Returns true on rule match, false on failure.
+ */
+static bool ima_match_rules(struct ima_measure_rule_entry *rule,
+			   struct inode *inode, enum lim_hooks func, int mask)
+{
+	if (rule->func && rule->func != func)
+		return false;
+	if (rule->mask && rule->mask != mask)
+		return false;
+	if (rule->fsmagic && rule->fsmagic != inode->i_sb->s_magic)
+		return false;
+	if (rule->lsm_subj_rule) {
+		struct task_struct *tsk = current;
+		u32 sid;
+		int rc;
+
+		security_task_getsecid(tsk, &sid);
+		rc = security_filter_rule_match(sid, AUDIT_SUBJ_USER,
+						AUDIT_EQUAL,
+						rule->lsm_subj_rule, NULL);
+		if (!rc)
+			return false;
+	}
+	if (rule->lsm_obj_rule) {
+		u32 osid;
+		int rc;
+
+		security_inode_getsecid(inode, &osid);
+		rc = security_filter_rule_match(osid, AUDIT_OBJ_USER,
+						AUDIT_EQUAL,
+						rule->lsm_obj_rule, NULL);
+		if (!rc)
+			return false;
+	}
+	if (rule->lsm_type_rule) {
+		u32 osid;
+		int rc;
+
+		security_inode_getsecid(inode, &osid);
+		rc = security_filter_rule_match(osid, AUDIT_OBJ_TYPE,
+						AUDIT_EQUAL,
+						rule->lsm_type_rule, NULL);
+		if (!rc)
+			return false;
+	}
+	return true;
+}
+
+/**
+ * ima_match_policy - decision based on LSM and other conditions
+ * @inode: pointer to an inode
+ * @func: IMA hook identifier
+ * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ *
+ * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
+ * conditions. Returns rule action on rule match, 0 on failure.
+ */
+int ima_match_policy(struct inode *inode, enum lim_hooks func, int mask)
+{
+	struct ima_measure_rule_entry *entry;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(entry, ima_measure, list) {
+		bool rc;
+
+		rc = ima_match_rules(entry, inode, func, mask);
+		if (rc) {
+			rcu_read_unlock();
+			return entry->action;
+		}
+	}
+	rcu_read_unlock();
+	return 0;
+}
+
+/**
+ * ima_init_policy - initialize the default and policy measure rules.
+ */
+void ima_init_policy(void)
+{
+	int i;
+
+	INIT_LIST_HEAD(&measure_default_rules);
+	for (i = 0; i < ARRAY_SIZE(default_rules); i++)
+		list_add_tail(&default_rules[i].list, &measure_default_rules);
+	ima_measure = &measure_default_rules;
+
+	INIT_LIST_HEAD(&measure_policy_rules);
+}
+
+/**
+ * ima_update_policy - update default_rules with new measure rules
+ *
+ * Wait to update the default rules with a complete new set of measure rules.
+ */
+void ima_update_policy(void)
+{
+	char *op = "policy_update";
+	char *cause = "already exists";
+	int result = 1;
+
+	if (ima_measure == &measure_default_rules) {
+		ima_measure = &measure_policy_rules;
+		cause = "complete";
+		result = 0;
+	}
+	integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
+			    NULL, op, cause, result);
+}
+
+/**
+ * ima_add_rule - add ima measure rules
+ * @action: integer 1 indicating MEASURE, 0 indicating DONT_MEASURE
+ * @subj: pointer to an LSM subject value
+ * @obj:  pointer to an LSM object value
+ * @type:  pointer to an LSM object type value
+ * @func: LIM hook identifier
+ * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ * @fsmagic: fs magic hex value string
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int ima_add_rule(int action, char *subj, char *obj, char *type,
+		 char *func, char *mask, char *fsmagic)
+{
+	struct ima_measure_rule_entry *entry;
+	int result = 0;
+
+	/* Prevent installed policy from changing */
+	if (ima_measure != &measure_default_rules) {
+		integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
+				    NULL, "policy_update", "already exists", 1);
+		return -EACCES;
+	}
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	INIT_LIST_HEAD(&entry->list);
+	if (action < 0 || action > 1)
+		result = -EINVAL;
+	else
+		entry->action = action;
+	if (!result && subj)
+		result = security_filter_rule_init(AUDIT_SUBJ_USER, AUDIT_EQUAL,
+						   subj, &entry->lsm_subj_rule);
+	if (!result && obj)
+		result = security_filter_rule_init(AUDIT_OBJ_USER, AUDIT_EQUAL,
+						   obj, &entry->lsm_obj_rule);
+	if (!result && type)
+		result = security_filter_rule_init(AUDIT_OBJ_TYPE, AUDIT_EQUAL,
+						   obj, &entry->lsm_obj_rule);
+	if (!result && func) {
+		if (strcmp(func, "INODE_PERMISSION") == 0)
+			entry->func = INODE_PERMISSION;
+		else if (strcmp(func, "FILE_MMAP") == 0)
+			entry->func = FILE_MMAP;
+		else if (strcmp(func, "BPRM_CHECK") == 0)
+			entry->func = BPRM_CHECK;
+		else
+			result = -EINVAL;
+	}
+	if (!result && mask) {
+		if (strcmp(mask, "MAY_EXEC") == 0)
+			entry->mask = MAY_EXEC;
+		else if (strcmp(mask, "MAY_WRITE") == 0)
+			entry->mask = MAY_WRITE;
+		else if (strcmp(mask, "MAY_READ") == 0)
+			entry->mask = MAY_READ;
+		else if (strcmp(mask, "MAY_APPEND") == 0)
+			entry->mask = MAY_APPEND;
+		else
+			result = -EINVAL;
+	}
+	if (!result && fsmagic) {
+		int rc;
+
+		rc = strict_strtoul(fsmagic, 16, &entry->fsmagic);
+		if (rc)
+			result = -EINVAL;
+	}
+	if (!result) {
+		mutex_lock(&ima_measure_mutex);
+		list_add_tail(&entry->list, &measure_policy_rules);
+		mutex_unlock(&ima_measure_mutex);
+	}
+	return result;
+}
Index: linux-2.6.26-rc9-git1/Documentation/kernel-parameters.txt
===================================================================
--- linux-2.6.26-rc9-git1.orig/Documentation/kernel-parameters.txt
+++ linux-2.6.26-rc9-git1/Documentation/kernel-parameters.txt
@@ -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.
@@ -805,6 +806,10 @@ and is between 256 and 4096 characters. 
 	ihash_entries=	[KNL]
 			Set number of hash buckets for inode cache.
 
+	ima_hash=	[IMA] runtime ability to define hash crypto alg.
+			Format: { "MD5" | "SHA1" }
+			Default is "SHA1".
+
 	in2000=		[HW,SCSI]
 			See header of drivers/scsi/in2000.c.
 
Index: linux-2.6.26-rc9-git1/include/linux/ima.h
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9-git1/include/linux/ima.h
@@ -0,0 +1,48 @@
+/*
+ * ima.h
+ *
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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.
+ */
+
+#ifndef _LINUX_IMA_H
+#define _LINUX_IMA_H
+
+/* IMA LIM Data */
+enum ima_type { IMA_DATA, IMA_METADATA, IMA_TEMPLATE };
+
+struct ima_args_data {
+	const char	*filename;
+	struct inode 	*inode;
+	struct dentry 	*dentry;
+	struct nameidata 	*nd;
+	struct file 	*file;
+	enum lim_hooks	function;
+	u32		osid;
+	int 		mask;
+};
+
+struct ima_store_data {
+	char 		*name;
+	int 		len;
+	char 		*data;
+	int  		violation;
+};
+
+struct ima_data {
+	enum ima_type 	type;
+	union {
+		struct ima_args_data 	args;
+		struct ima_store_data	template;
+	} data;
+};
+
+void ima_fixup_argsdata(struct ima_args_data *data,
+			struct inode *inode, struct dentry *dentry,
+			struct file *file, struct nameidata *nd, int mask,
+			int function);
+#endif
Index: linux-2.6.26-rc9-git1/security/integrity/Makefile
===================================================================
--- linux-2.6.26-rc9-git1.orig/security/integrity/Makefile
+++ linux-2.6.26-rc9-git1/security/integrity/Makefile
@@ -4,3 +4,5 @@
 
 # Object file lists
 obj-$(CONFIG_INTEGRITY)			+= integrity.o integrity_audit.o
+
+obj-$(CONFIG_IMA)			+= ima/
Index: linux-2.6.26-rc9-git1/security/integrity/Kconfig
===================================================================
--- linux-2.6.26-rc9-git1.orig/security/integrity/Kconfig
+++ linux-2.6.26-rc9-git1/security/integrity/Kconfig
@@ -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

-- 


^ permalink raw reply	[flat|nested] 20+ messages in thread

* LTP IMA path
       [not found] <20080707192529.489789904@linux.vnet.ibm.com>
                   ` (4 preceding siblings ...)
  2008-07-07 21:57 ` [PATCH 5/5] integrity: IMA as an integrity service provider Mimi Zohar
@ 2008-07-07 22:03 ` Mimi Zohar
  5 siblings, 0 replies; 20+ messages in thread
From: Mimi Zohar @ 2008-07-07 22:03 UTC (permalink / raw)
  To: linux-kernel; +Cc: tosubrata, safford, serue, sailer, zohar

This LTP patch tests the LIM/IMA functionality.

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
---
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/README
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/README
@@ -0,0 +1,50 @@
+These testcases test the Integrity Measurement Architecture(IMA).
+
+Requirements
+------------
+In order for all of the tests in the testsuite to complete successfully:
+	- A kernel with Linux Integrity Module(LIM), IMA, KALLSYMS,
+	  TPM support and TPM driver builtin is required.
+	- The testsuite must be executed with root priveleges so that it
+	  can access securityfs files, such as: security/ima/policy and
+	  security/ima/ascii_runtime_measurement.
+	- securityfs must be mounted.  The tests assume that it is mounted
+	  as /sys/kernel/security.
+	- For the re-measurement test, the filesystem, from where these
+	  testcases are run, must be mounted with i_version.
+
+Dependency
+----------
+The testsuite is dependent on the default policy being enabled, which
+measures all executables, all files mmapped for execute and all files
+open for read. Once the default policy has been replaced, the IMA
+measurement and re-measurement tests will fail, as well as the test to
+load a new policy. (A measurement policy may only be loaded once per
+boot.)
+
+Running the Testsuite
+---------------------
+From the ../ltp-base-<version>/testcases/kernel/security/integrity/ima
+directory, as root compile the IMA testsuite tools, by executing make.  To
+run the testsuite, from the same directory, on the command line execute:
+	sh ./ima_test.sh.
+
+The testsuite results are sent to standard output for viewing.
+
+Running Individual Testcases
+----------------------------
+Individual testcases may be run by executing shell scripts found in
+the ../ltp-base-<version>/testcases/kernel/security/integrity/ima subdirecties.
+However, understanding the results of the individual testcases is
+dependent on the execution context.  For example, executing
+load_policy.sh should return zero the first time it is executed, but
+subsequently, should return a non-zero value. Both are valid values,
+depending on the execution context. The same is true for measuring
+and re-measuring a file.  Before the test measure policy is loaded,
+the measure and re-measure scripts should return zero.
+
+System State after running the Testsuite
+----------------------------------------
+After running the testsuite, the system is running with the test
+measurement policy.  A reboot is required to install a different
+integrity measurement policy.
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/Makefile
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/Makefile
@@ -0,0 +1,13 @@
+SUBDIRS = tpm kmem tools
+
+all:
+	@set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i ; done
+
+install:
+	@set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i install ; done
+
+clean:
+	@set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i clean ; done
+	rm -rf tmp
+	rm -rf measure/tmp
+
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/ima_test.sh
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/ima_test.sh
@@ -0,0 +1,175 @@
+#!/bin/bash
+# Copyright (C) 2008 IBM Corporation
+# Author: Mimi Zohar <zohar@us.ibm.com>
+#
+# 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.
+
+# The default policy on boot measures all executables, all
+# mmapped executable files, and all files open for read.
+#
+# test 1: verify TPM is enabled.
+# test 2: verify creating and reading a new file causes a new
+# 	  measurement to be added to the IMA measurement list.
+# test 3: verify modifying and reading the new file causes a new
+# 	  measurement to be added to the IMA measurement list.
+# test 4: verify ability to load a new measurement policy
+# test 5: verify new policy does not add a measurement to the
+#	  IMA measurement list for files open for read.
+# test 6: verify inability to load subsequent measurement policy.
+# test 7: verify template hash value for ima entry is correct.
+# test 8: verify ima calculated aggregate pcr value or matches actual pcr value.
+# test 9: verify kmem-template hash
+
+# We have only one chance per boot for all of the tests in the testsuite
+# to succeed. So make sure we have everything we need, before starting
+# the tests.
+
+testid="IMA Test Conf:"
+# Must be root
+id=`id -u`
+if [ $id != 0 ]; then
+	echo "$testid Cannot execute test, must be running as root"
+	exit -1
+fi
+
+# securityfs must be enabled and mounted
+SECURITYFS=`mount | grep securityfs`
+if [ $? == 1 ]; then
+	SECURITYFS=/sys/kernel/security
+	`mount -t securityfs securityfs $SECURITYFS`
+	if [ $? == 1 ]; then
+		echo "$testid Cannot execute test as securityfs not" \
+		     " enabled in kernel"
+		exit -1
+	fi
+fi
+SECURITYFS=`echo $SECURITYFS |  sed 's/securityfs on //' | sed 's/ type .*//'`
+
+# IMA must be configured in the kernel
+IMA_DIR=$SECURITYFS/ima
+if [ ! -d $IMA_DIR ]; then
+	echo "$testid Cannot execute test as IMA not enabled in kernel"
+	exit -1
+fi
+
+# KALLSYMS must be configured in the kernel
+KALLSYMS=/proc/kallsyms
+if [ ! -f $KALLSYMS ]; then
+	echo "$testid Cannot execute kmem test as" \
+	     "KALLSYMS not enabled in kernel"
+	exit -1
+fi
+
+
+# test 1:
+testid="IMA Test 1:"
+PCRS_PATH=`find /sys/devices/ | grep pcrs`
+if [ $? -eq 0 ]; then
+	if [ ! -f $PCRS_PATH ]; then
+		echo "$testid failed - TPM not enabled"
+		echo "(Assuming sysfs is mounted as /sys.)"
+		exit -1
+	else
+		echo "$testid succeeded - TPM enabled"
+	fi
+else
+	echo "$testid failed - TPM not enabled"
+	echo "(Assuming sysfs is mounted as /sys.)"
+fi
+
+# test 2:
+testid="IMA Test 2:"
+chmod a+x ./measure/read_measure.sh
+./measure/read_measure.sh "$testid"
+if [ $? -eq 0 ]; then
+	echo "$testid success - file measured"
+else
+	echo "$testid failed - file not measured"
+fi
+
+# test 3:
+testid="IMA Test 3:"
+chmod a+x ./measure/re-measure.sh
+./measure/re-measure.sh "$testid"
+if [ $? -eq 0 ]; then
+	echo "$testid success - modified file measured"
+else
+	echo "$testid failed - modified file not measured. "
+	echo "(Make sure filesystem is mounted with iversion.)"
+fi
+
+# test 4:
+testid="IMA Test 4:"
+cd loadpolicy
+chmod a+x ./load_policy.sh
+./load_policy.sh "$testid"
+if [ $? -eq 0 ]; then
+	echo "$testid success - loaded policy"
+else
+	echo "$testid failed - loading policy(permitted once per boot)"
+fi
+
+# test 5:
+testid="IMA Test 5:"
+cd ../measure
+# make sure that date has changed for measurement test
+sleep 1
+./read_measure.sh "$testid"
+if [ $? -eq 0 ]; then
+	echo "$testid failed - shouldn't have measured the file"
+	echo "(Verify loaded correct ima measurement policy.)"
+else
+	echo "$testid succeeded - didn't measure the file"
+fi
+
+# test 6:
+testid="IMA Test 6:"
+cd ../loadpolicy
+./load_policy.sh "$testid"
+if [ $? -eq 0 ]; then
+	echo "$testid failed - shouldn't have loaded a policy"
+else
+	echo "$testid succeeded - didn't load a policy"
+fi
+
+# test 7:
+testid="IMA Test 7:"
+cd ../tpm
+chmod a+x ./ima_measure
+./ima_measure --validate > /dev/null
+if [ $? -eq 0 ]; then
+	echo "$testid succeeded - verified ima template hash values."
+else
+	echo "$testid failed - errors in verifying ima template hash values."
+fi
+
+# test 8:
+testid="IMA Test 8:"
+aggregate_pcr=`./ima_measure --validate` > /dev/null
+cat $PCRS_PATH | while read line ; do
+	if [ "${line:0:6}" == "PCR-10" ] ; then
+		if [ "${line:8:67}" == "${aggregate_pcr:0:59}" ] ; then
+			echo "$testid succeeded - aggregate pcr value"\
+				"matches real pcr value."
+		else
+			echo "$testid failed - aggregate pcr value does"\
+				"not match real pcr value."
+			echo 'aggregate_pcr: ' $aggregate_pcr
+			echo 'real pcr: ' $line
+		fi
+	fi
+done
+
+# test 9:
+testid="IMA Test 9:"
+cd ../kmem
+chmod a+x ./kmem-test.sh
+./kmem-test.sh
+if [ $? -eq 0 ]; then
+	echo "$testid succeeded - verified kmem template measurement"
+else
+	echo "$testid: failed - kmem template measurement "
+fi
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/loadpolicy/load_policy.sh
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/loadpolicy/load_policy.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+
+# Copyright (C) 2008 IBM Corporation
+# Author: Mimi Zohar <zohar@us.ibm.com>
+#
+# 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.
+
+# Load a policy 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.
+
+verbose=0
+if [ $# == 1 ]; then
+	msg_prefix="     $1"
+elif [ $# == 0 ]; then
+	verbose=1
+fi
+
+SECURITYFS=`mount | grep securityfs`
+SECURITYFS=`echo $SECURITYFS |  sed 's/securityfs on //' | sed 's/ type .*//'`
+IMA_POLICY=$SECURITYFS/ima/policy
+
+# LSM specific policy
+LSM_POLICY=./measure.selinux
+#LSM_POLICY=./measure.smack
+
+if [ ! -f $LSM_POLICY ]; then
+	if [ $verbose == 1 ] ; then
+		echo "$msg_prefix LSM specific policy does not exist"
+	fi
+	exit -1
+fi
+
+if [ ! -f $IMA_POLICY ]; then
+	if [ $verbose == 1 ] ; then
+		echo "$msg_prefix security/ima/policy does not exist"
+	fi
+	exit -1
+fi
+
+exec 4>$IMA_POLICY
+if [ $? != 0 ]; then
+	if [ $verbose == 1 ] ; then
+		echo "$msg_prefix open failed: security/ima/policy"
+	fi
+	exit -1
+else
+	cat $LSM_POLICY | while read line ; do
+		if [ "${line:0:1}" != "#" ] ; then
+			echo $line >&4
+		fi
+	done
+	if [ $verbose == 1 ] ; then
+		echo "$msg_prefix security/ima/policy updated"
+	fi
+fi
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/loadpolicy/measure.selinux
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/loadpolicy/measure.selinux
@@ -0,0 +1,18 @@
+#
+# Integrity measure 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 obj=user_u func=INODE_PERMISSION mask=MAY_READ
+#measure subj=system_u func=INODE_PERMISSION mask=MAY_READ
+#measure func=INODE_PERMISSION mask=MAY_READ
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/measure/re-measure.sh
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/measure/re-measure.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+# Copyright (C) 2008 IBM Corporation
+# Author: Mimi Zohar <zohar@us.ibm.com>
+#
+# 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.
+
+verbose=0
+if [ $# == 1 ]; then
+	msg_prefix="     $1"
+elif [ $# == 0 ]; then
+	verbose=1
+fi
+
+# Create and read a file
+# Check if the file was measured (i.e. contained in the ascii measurement list.)
+
+mkdir -p tmp
+echo `date` '- modifying file causes hash to change' >> tmp/test.txt
+cat tmp/test.txt > /dev/null
+cat /sys/kernel/security/ima/ascii_runtime_measurements > tmp/imalog
+
+# calculate and search for sha1sum of tmp/test.txt in tmp/imalog
+hash=`cat tmp/test.txt | sha1sum | sed 's/  -//'`
+if [ $verbose == 1 ] ; then
+	echo "$msg_prefix hash: $hash"
+fi
+`grep $hash tmp/imalog > /dev/null`
+if [ $? == 0 ]; then
+	if [ $verbose == 1 ] ; then
+		echo "        TPM ascii measurement list contains sha1sum"
+	fi
+	exit 0
+else
+	if [ $verbose == 1 ] ; then
+		echo "        TPM ascii measurement list does not contain"\
+		     "sha1sum"
+	fi
+	exit -1
+fi
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/measure/read_measure.sh
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/measure/read_measure.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+# Copyright (C) 2008 IBM Corporation
+# Author: Mimi Zohar <zohar@us.ibm.com>
+#
+# 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.
+
+verbose=0
+if [ $# == 1 ]; then
+	msg_prefix="     $1"
+elif [ $# == 0 ]; then
+	verbose=1
+fi
+
+# Create and read a file
+# Check if the file was measured (i.e. contained in the ascii measurement list.)
+
+mkdir -p tmp
+echo `date` '- changing date causes changing hash value' > tmp/test.txt
+cat tmp/test.txt > /dev/null
+cat /sys/kernel/security/ima/ascii_runtime_measurements > tmp/imalog
+
+# calculate and search for sha1sum of tmp/test.txt in tmp/imalog
+hash=`cat tmp/test.txt | sha1sum | sed 's/  -//'`
+if [ $verbose == 1 ] ; then
+	echo "$msg_prefix hash: " $hash
+fi
+`grep $hash tmp/imalog > /dev/null`
+if [ $? == 0 ]; then
+	if [ $verbose == 1 ] ; then
+		echo "$msg_prefix TPM ascii measurement list contains sha1sum"
+	fi
+	exit 0
+else
+	if [ $verbose == 1 ] ; then
+		echo "$msg_prefix TPM ascii measurement list does not"\
+		     "contain sha1sum"
+	fi
+	exit -1
+fi
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/tools/Makefile
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/tools/Makefile
@@ -0,0 +1,9 @@
+TARGETS := hex2bin
+
+all: $(TARGETS)
+
+hex2bin: hex2bin.c
+	$(CC) $(CFLAGS) $(LDFLAGS) -o hex2bin hex2bin.c
+
+clean:
+	rm -f hex2bin hex2bin.o
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/tools/hex2bin.c
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/tools/hex2bin.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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.
+ *
+ * hex2bin.c
+ *	- convert a hex string to binary
+ */
+#include <stdio.h>
+#include <stdlib.h>
+
+main()
+{
+	char *line = NULL;
+	ssize_t len, line_len = 0;
+	int h, i = 0;
+
+	len = getline(&line, &line_len, stdin);
+	for (i = 0; i < len; i += 2)  {
+		sscanf(line + i, "%2x", &h);
+		putchar(h);
+	}
+	free(line);
+}
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/tpm/Makefile
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/tpm/Makefile
@@ -0,0 +1,9 @@
+TARGETS := ima_measure
+
+all: $(TARGETS)
+
+ima_measure: ima_measure.c
+	$(CC) $(CFLAGS) $(LDFLAGS) -o ima_measure ima_measure.c -lcrypto
+
+clean:
+	rm -f ima_measure ima_measure.o
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/tpm/ima_measure.c
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/tpm/ima_measure.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) International Business Machines  Corp., 2008
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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_measure.c
+ *
+ * Calculate the aggregate-pcr value based on the IMA runtime binary
+ * measurements.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <openssl/sha.h>
+
+#define TCG_EVENT_NAME_LEN_MAX	255
+#define MAX_EVENT_SIZE 500
+
+static int failed_count = 0;	/* number of template verifications failed */
+static int verify_template_hash = 1;
+static int verbose = 0;
+static int validate = 0;
+
+#define print_info(format, arg...) \
+	if (verbose) \
+		printf(format, ##arg)
+
+static u_int8_t pcr[SHA_DIGEST_LENGTH];	/* simulates the PCR aggregate */
+static u_int8_t zero[SHA_DIGEST_LENGTH];
+static u_int8_t fox[SHA_DIGEST_LENGTH];
+struct template {
+	u_int32_t pcr;
+	u_int8_t tdigest[SHA_DIGEST_LENGTH];	/* template digest */
+	u_int32_t tlen;				/* template name size */
+};
+
+struct ima_inode_measure_entry {
+        u_int8_t digest[SHA_DIGEST_LENGTH];	/* sha1 measurement hash */
+       	char file_name[TCG_EVENT_NAME_LEN_MAX + 1];	/*name + \0*/
+};
+
+/* print sha1 aggregate over the template measurements */
+static int display_pcr()
+{
+	int i;
+
+	print_info("PCRAggr (re-calculated):");
+	for (i = 0; i < 20; i++)
+		printf("%02X ", pcr[i] & 0xff);
+	print_info(".\n");
+}
+
+static void print_digest(u_int8_t *digest)
+{
+	int i;
+
+	for (i = 0; i < 20; i++)
+		print_info("%02X", (*(digest + i) & 0xff));
+}
+
+/*
+ * Calculate the template hash of an ima entry
+ * and compare it with the actual template hash value.
+ */
+static int verify_ima_tdigest(struct template *tdata,
+			struct ima_inode_measure_entry *ima)
+{
+	int rc;
+	SHA_CTX tmp;
+	u_int8_t digest[SHA_DIGEST_LENGTH];
+
+	/* Calc template hash for an ima entry */
+	SHA1_Init(&tmp);
+	SHA1_Update(&tmp, ima, sizeof *ima);
+	SHA1_Final(digest, &tmp);
+
+	rc = memcmp(digest, tdata->tdigest, sizeof digest);
+	if (rc) {
+		int i;
+
+		print_info("%s: template hash not valid\n", ima->file_name);
+		print_info("\t should be:");
+		print_digest(digest);
+		print_info("\n\t        is:");
+		print_digest(tdata->tdigest);
+		print_info("\n");
+	}
+	return rc;
+}
+
+int process_event(int num, unsigned char *event, int len)
+{
+	int i;
+	char tname[TCG_EVENT_NAME_LEN_MAX + 1];	/* template_name */
+	u_int32_t tname_len;	/* template name length */
+	struct template *tdata;
+
+	tdata = (struct template *)event;
+
+	print_info("%3d %03u %d", num, tdata->pcr, tdata->tlen);
+	if (tdata->tlen > TCG_EVENT_NAME_LEN_MAX) {
+		printf("ERROR: event name too long!\n");
+		exit(1);
+	}
+	memset(tname, 0, TCG_EVENT_NAME_LEN_MAX);
+	memcpy(&tname, &tdata->tlen +1, tdata->tlen);
+	print_digest(tdata->tdigest);
+	print_info(" %s ", (char *)(tname));
+
+	if (strcmp(tname, "boot_aggregate") == 0) {
+		print_info("\n");
+		return (sizeof *tdata + tdata->tlen + 2) /* separator */ ;
+	} else if (strcmp(tname, "ima") == 0) {
+		struct event_data {
+			u_int8_t digest[SHA_DIGEST_LENGTH];
+			int len;		/* file_name length */
+        		char file_name[TCG_EVENT_NAME_LEN_MAX + 1];/*name + \0*/
+		} *data;
+
+		data = (struct event_data *)((void *)tdata
+				+ sizeof *tdata + tdata->tlen);
+		print_digest(data->digest);
+		data->file_name[data->len] = 0x00;
+		print_info(" %s\n", data->file_name);
+
+		if (validate && (memcmp(fox, tdata->tdigest, sizeof fox) != 0)){
+			struct ima_inode_measure_entry entry;
+
+			memset(&entry, 0, sizeof entry);
+			memcpy(&entry.digest, data->digest, 20);
+			strncpy(entry.file_name, data->file_name, data->len);
+			failed_count += verify_ima_tdigest(tdata, &entry);
+		}
+		return (sizeof *tdata  + tdata->tlen + sizeof data->digest
+				+ data->len + 4); /* null separator */
+	} else if (strcmp(tname, "kmem") == 0) {
+		struct event_data {
+			u_int8_t digest[SHA_DIGEST_LENGTH];
+			int len;		/* file_name length */
+        		char file_name[TCG_EVENT_NAME_LEN_MAX + 1];/*name + \0*/
+		} *data;
+
+		data = (struct event_data *)((void *)tdata
+				+ sizeof *tdata + tdata->tlen);
+		print_digest(data->digest);
+		return (sizeof *tdata  + tdata->tlen + sizeof data->digest
+				+ data->len + 4); /* null separator */
+	}
+}
+
+int simulate_extend_pcr(u_int8_t digest[SHA_DIGEST_LENGTH])
+{
+	SHA_CTX c;
+
+	/* Extend simulated PCR with new template digest */
+	SHA1_Init(&c);
+	SHA1_Update(&c, pcr, SHA_DIGEST_LENGTH);
+	if (validate) {
+		if (memcmp(digest, zero, 20) == 0)
+			memset(digest, 0xFF, 20);
+	}
+	SHA1_Update(&c, digest, 20);
+	SHA1_Final(pcr, &c);
+}
+
+/*
+ * ima_measurements.c - calculate the aggregate-pcr value based on
+ * the IMA runtime binary measurements.
+ *
+ * format: ima_measurement [--validate] [--verify] [--verbose]
+ *
+ * --validate: forces validation of the aggregrate pcr value
+ * 	     for an invalidated PCR. Replace all entries in the
+ * 	     runtime binary measurement list with 0x00 hash values,
+ * 	     which indicate the PCR was invalidated, either for
+ * 	     "a time of measure, time of use"(ToMToU) error, or a
+ *	     file open for read was already open for write, with
+ * 	     0xFF's hash value, when calculating the aggregate
+ *	     pcr value.
+ *
+ * --verify: for all IMA template entries in the runtime binary
+ * 	     measurement list, calculate the template hash value
+ * 	     and compare it with the actual template hash value.
+ *	     Return the number of incorrect hash measurements.
+ *
+ * --verbose: For all entries in the runtime binary measurement
+ *	     list, display the generic template information. In
+ * 	     addition, for IMA and KMEM templates, display template
+ * 	     specific information.
+ *
+ * template info:  list #, PCR-register #, template hash, template name
+ *	IMA info:  IMA hash, filename hint
+ * 	KMEM info: memory hash, reference name
+ *
+ * Ouput: displays the aggregate-pcr value
+ * Return code: if verification enabled, returns number of verification
+ * 		errors.
+ */
+int main(int argc, char *argv[])
+{
+	int i, fd, count = 0, len;
+	unsigned char event[MAX_EVENT_SIZE];
+	SHA_CTX c;
+	int remaining = 0;
+	struct template *tdata;
+
+	memset(pcr, 0, SHA_DIGEST_LENGTH);	/* initial PCR content 0..0 */
+	memset(zero, 0, SHA_DIGEST_LENGTH);
+	memset(fox, 0xff, SHA_DIGEST_LENGTH);
+
+	for (i = 1; i < argc; i++) {
+		if (strncmp(argv[i], "--validate", 5) == 0)
+			validate = 1;
+		if (strncmp(argv[i], "--verbose", 6) == 0)
+			verbose = 1;
+		if (strncmp(argv[i], "--verify", 6) == 0)
+			verify_template_hash = 1;
+	}
+
+
+	fd = open("/sys/kernel/security/ima/binary_runtime_measurements",
+		  O_RDONLY);
+	if (fd < 0) {
+		perror("Unable to open file\n");
+		return 1;
+	}
+	print_info( "### PCR HASH                                  " \
+		 	"TEMPLATE-NAME\n");
+
+	while ((len = read(fd, event + remaining, MAX_EVENT_SIZE - remaining))
+			|| remaining) {
+		if (len < 0) {
+			perror("Error reading from file.\n");
+			break;
+		}
+		len += remaining;
+		tdata = (struct template *)event;
+
+		simulate_extend_pcr(tdata->tdigest);
+		remaining = len - process_event(count++, event, len);
+
+		/* copy rest to buffer start */
+		memcpy(event, event + len - remaining, remaining);
+
+	}
+	close(fd);
+
+	display_pcr();
+	return failed_count;
+}
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/kmem/Makefile
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/kmem/Makefile
@@ -0,0 +1,26 @@
+#
+# Makefile for kernel module
+#
+ifneq ($(KERNELRELEASE),)
+obj-m	+= kmem-template.o
+EXTRA_CFLAGS += -I$(PWD) -O
+
+else
+KDIR		 := /lib/modules/$(shell uname -r)/build
+#KDIR		 := /lib/modules/2.6.26-rc8-git3/build
+PWD		 := $(shell pwd)
+
+default:
+		 $(MAKE) -C $(KDIR) M=$(PWD) modules
+endif
+
+
+clean :
+	rm -rf .tmp_versions
+	@find $(KBUILD_EXTMOD) $(RCS_FIND_IGNORE) \
+		\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
+		-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
+		-o -name '*.symvers' -o -name '*.markers' \
+		-o -name '*.order' \) \
+		-type f -print | xargs rm -f
+
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/kmem/kmem-template.c
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/kmem/kmem-template.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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.
+ *
+ * kmem-template.c
+ * 	- defines a kernel memory template
+ * 	- reads from security/kmem-template "name length address"
+ * 	- collects and stores measurement from address for length bytes
+ *	- security/kmem-template returns last memory read
+ */
+
+#include <asm/uaccess.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <linux/notifier.h>
+#include <linux/security.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/proc_fs.h>
+#include <linux/security.h>
+#include <linux/integrity.h>
+#include <linux/ima.h>
+
+#define MY_NAME THIS_MODULE->name
+#define IMA_DIGEST_SIZE		20
+
+static int __init init_kmem_template(void);
+static void __exit cleanup_kmem_template(void);
+
+static unsigned char *lastbuf;
+static int lastbuf_len;
+
+struct kmem_data {
+	char name[25];
+	char *buf;
+	int buflen;
+	u8 digest[IMA_DIGEST_SIZE];
+};
+
+int calc_hash(int buflen, char *buf, char *digest)
+{
+	struct crypto_hash *tfm;
+	struct hash_desc desc;
+	struct scatterlist sg[1];
+	int error, result = 0;
+
+	tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm)) {
+		printk(KERN_INFO "%s: failed to load %s transform: %ld\n",
+		       __func__, "sha1", PTR_ERR(tfm));
+		return -ENOSYS;
+	}
+	desc.tfm = tfm;
+	desc.flags = 0;
+	error = crypto_hash_init(&desc);
+	if (error) {
+		result = -EINVAL;
+		goto out;
+	}
+
+	sg_set_buf(sg, buf, buflen);
+	result = crypto_hash_update(&desc, sg, buflen);
+	if (!result) {
+		error = crypto_hash_final(&desc, digest);
+		if (error)
+			result = -EINVAL;
+	}
+
+out:
+	crypto_free_hash(tfm);
+	return result;
+}
+
+static int kmem_collect_measurement(void *d)
+{
+	struct kmem_data *data = (struct kmem_data *)d;
+
+	memset(data->digest, 0, sizeof data->digest);
+	calc_hash(data->buflen, data->buf, data->digest);
+	return 0;
+}
+
+/* Transform local kmem data to store data */
+void kmem_store_measurement(void *d)
+{
+	struct kmem_data *data = (struct kmem_data *)d;
+	struct ima_data idata;
+	struct ima_store_data *template = &idata.data.template;
+
+	idata.type = IMA_TEMPLATE;
+	template->name = "kmem";
+	template->len = sizeof *data;
+	template->data = (char *)data;
+	template->violation = 0;
+	integrity_store_measurement("ima", (void *)&idata);
+	return;
+}
+
+static void kmem_template_show(struct seq_file *m, void *e,
+			       enum integrity_show_type show)
+{
+	struct kmem_data *data = (struct kmem_data *)e;
+	int filename_len;
+	char len[4];
+	int i;
+
+	for (i = 0; i < 20; i++) {
+		switch (show) {
+		case INTEGRITY_SHOW_ASCII:
+			seq_printf(m, "%02x", data->digest[i]);
+			break;
+		case INTEGRITY_SHOW_BINARY:
+			seq_putc(m, data->digest[i]);
+		default:
+			break;
+		}
+	}
+
+	switch (show) {
+	case INTEGRITY_SHOW_ASCII:
+		seq_printf(m, " %s %d \n", data->name, data->buflen);
+		break;
+	case INTEGRITY_SHOW_BINARY:
+		filename_len = strlen(data->name);
+		memcpy(len, &filename_len, 4);
+		for (i = 0; i < 4; i++)
+			seq_putc(m, len[i]);
+		for (i = 0; i < strlen(data->name); i++)
+			seq_putc(m, data->name[i]);
+	default:
+		break;
+	}
+}
+
+static struct template_operations kmem_ops = {
+	.collect_measurement = kmem_collect_measurement,
+	.store_measurement = kmem_store_measurement,
+	.display_template = kmem_template_show
+};
+
+static int kmem_add_measure(char *name, unsigned int buflen, unsigned int addr)
+{
+	struct kmem_data data;
+	int rc;
+
+	strncpy(data.name, name, sizeof data.name);
+	data.buflen = buflen;
+	data.buf = (char *)addr;
+	rc = integrity_collect_measurement("kmem", &data);
+	if (!rc) {
+		integrity_store_measurement("kmem", &data);
+		if (data.buflen > lastbuf_len)
+			kfree(lastbuf);
+		lastbuf = kzalloc(data.buflen, GFP_KERNEL);
+		if (lastbuf) {
+			lastbuf_len = data.buflen;
+			memcpy(lastbuf, data.buf, lastbuf_len);
+		}
+	}
+	return rc;
+}
+
+static ssize_t kmem_write_template(struct file *file, const char __user *buf,
+				   size_t buflen, loff_t *ppos)
+{
+	char *data;
+	char name[26];
+	size_t result = 0, datalen;
+	int rc;
+	unsigned int addr, len;
+
+	datalen = buflen > 256 ? 256 : buflen;
+	data = kzalloc(datalen + 1, GFP_KERNEL);
+	if (!data)
+		result = -ENOMEM;
+
+	if (copy_from_user(data, buf, datalen)) {
+		result = -EFAULT;
+		goto out;
+	}
+	result = datalen;
+
+	rc = sscanf(data, "%25s %d %x ", name, &len, &addr);
+	if (rc == 3)
+		kmem_add_measure(name, len, addr);
+	else {
+		printk(KERN_INFO "kmem: error parsing request."
+		       "(format: name length address)\n");
+		result = -EINVAL;
+	}
+out:
+	if (!data)
+		kfree(data);
+	return result;
+}
+
+static ssize_t kmem_read_template(struct file *filp, char __user *buf,
+				  size_t count, loff_t *ppos)
+{
+	unsigned char *tmp_buf;
+	int len;
+
+	if (!lastbuf)
+		return -EINVAL;
+
+	tmp_buf = kzalloc(2 * lastbuf_len, GFP_KERNEL);
+	if (!tmp_buf)
+		return -ENOMEM;
+
+	for (len = 0; len < lastbuf_len; len++)
+		sprintf((tmp_buf + len + len), "%02x", *(lastbuf + len));
+	return simple_read_from_buffer(buf, count, ppos, tmp_buf, len + len);
+}
+
+const static struct file_operations kmem_template_ops = {
+	.write = kmem_write_template,
+	.read = kmem_read_template
+};
+
+static struct dentry *kmem_template;
+
+static int __init init_kmem_template(void)
+{
+
+	printk(KERN_INFO "%s: \n", __func__);
+	integrity_register_template("kmem", &kmem_ops);
+
+	kmem_template = securityfs_create_file("kmem-template",
+					       S_IRUSR | S_IRGRP | S_IWUSR,
+					       NULL, NULL, &kmem_template_ops);
+	return 0;
+}
+
+static void __exit cleanup_kmem_template(void)
+{
+	printk(KERN_INFO "%s\n", __FUNCTION__);
+	integrity_unregister_template("kmem");
+
+	securityfs_remove(kmem_template);
+}
+
+module_init(init_kmem_template);
+module_exit(cleanup_kmem_template);
+
+MODULE_LICENSE("GPL");
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/kmem/kmem-test.sh
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/kmem/kmem-test.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# Copyright (C) 2008 IBM Corporation
+# Author: Mimi Zohar <zohar@us.ibm.com>
+#
+# 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.
+
+# Load kmem-template, if not already loaded
+# Collect and store memory measurement
+# Verify the memory measurement contained in the ascii measurement list.
+
+lsmod | grep kmem_template > /dev/null
+if [ $? != 0 ]; then
+	insmod ./kmem-template.ko
+fi
+
+if [ ! -f /proc/kallsyms ]; then
+	echo 'kernel built without CONFIG_KALLSYMS'
+	exit 1
+fi
+proc_root=`cat /proc/kallsyms | grep 'D proc_root' | sed 's/ .*//'`
+echo 'proc_root 84' $proc_root > /sys/kernel/security/kmem-template
+
+# calculate and search for kmem hash in the ascii measurement list
+hash=`cat /sys/kernel/security/kmem-template | ../tools/hex2bin | sha1sum | sed 's/  -//'`
+`grep $hash /sys/kernel/security/ima/ascii_runtime_measurements > /dev/null`
+exit $?


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/5] integrity: Linux Integrity Module(LIM)
  2008-07-07 21:57 ` [PATCH 4/5] integrity: Linux Integrity Module(LIM) Mimi Zohar
@ 2008-07-08  1:31   ` James Morris
  2008-07-08 12:04     ` Mimi Zohar
  0 siblings, 1 reply; 20+ messages in thread
From: James Morris @ 2008-07-08  1:31 UTC (permalink / raw)
  To: Mimi Zohar; +Cc: linux-kernel, akpm, safford, serue, sailer, zohar

On Mon, 7 Jul 2008, Mimi Zohar wrote:

> (Details on the calls and their exact arguments are in linux/integrity.h,
> included in the patch.)
> 
> Signed-off-by: Mimi Zohar <zohar@us.ibm.com>

Please summarize what's changed in this patch since the last posting.  



- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/5] integrity: TPM cleanup
  2008-07-07 21:56 ` [PATCH 1/5] integrity: TPM cleanup Mimi Zohar
@ 2008-07-08  1:33   ` James Morris
  2008-07-08 12:01     ` Mimi Zohar
  2008-07-15 23:13   ` James Morris
  1 sibling, 1 reply; 20+ messages in thread
From: James Morris @ 2008-07-08  1:33 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: linux-kernel, akpm, safford, serue, sailer, zohar, debora, srajiv

On Mon, 7 Jul 2008, Mimi Zohar wrote:

> This patchset contains 5 patches.
> 	Patch 1/5 integrity: TPM cleanup (scripts/Lindent and other)
> 	Patch 2/5 integrity: TPM internal kernel interface
> 	Patch 3/5 integrity: special fs magic

I've previously reviewed and added "Reviewed-by:" lines for the above.

If the patches have not changed significantly, would you please ensure 
that the Reviewed-by/Acked-by/Signed-off lines are captured with them for 
subsequent postings ?

If the patches have changed and you've dropped these lines, please note 
what has changed.

It's also a good idea to cc people who have reviewed previous versions or 
postings of the patches when you repost them.


- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/5] integrity: TPM cleanup
  2008-07-08  1:33   ` James Morris
@ 2008-07-08 12:01     ` Mimi Zohar
  0 siblings, 0 replies; 20+ messages in thread
From: Mimi Zohar @ 2008-07-08 12:01 UTC (permalink / raw)
  To: James Morris
  Cc: linux-kernel, akpm, safford, serue, sailer, zohar, debora, srajiv


On Tue, 2008-07-08 at 11:33 +1000, James Morris wrote: 
> On Mon, 7 Jul 2008, Mimi Zohar wrote:
> 
> > This patchset contains 5 patches.
> > 	Patch 1/5 integrity: TPM cleanup (scripts/Lindent and other)
> > 	Patch 2/5 integrity: TPM internal kernel interface
> > 	Patch 3/5 integrity: special fs magic
> 
> I've previously reviewed and added "Reviewed-by:" lines for the above.
> 
> If the patches have not changed significantly, would you please ensure 
> that the Reviewed-by/Acked-by/Signed-off lines are captured with them for 
> subsequent postings ?
> 
> If the patches have changed and you've dropped these lines, please note 
> what has changed.
> 
> It's also a good idea to cc people who have reviewed previous versions or 
> postings of the patches when you repost them.
> 
> 
> - James

No, nothing has changed in the first 3 patches, except for removing 
the [RFC] in the Subject line. Thank you for pointing out the need to
capture the Reviewed-by/Acked-by/Signed-off lines and copying the reviewers.  
Will do in the future.

Mimi


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/5] integrity: Linux Integrity Module(LIM)
  2008-07-08  1:31   ` James Morris
@ 2008-07-08 12:04     ` Mimi Zohar
  0 siblings, 0 replies; 20+ messages in thread
From: Mimi Zohar @ 2008-07-08 12:04 UTC (permalink / raw)
  To: James Morris; +Cc: linux-kernel, akpm, safford, serue, sailer, zohar


On Tue, 2008-07-08 at 11:31 +1000, James Morris wrote: 
> On Mon, 7 Jul 2008, Mimi Zohar wrote:
> 
> > (Details on the calls and their exact arguments are in linux/integrity.h,
> > included in the patch.)
> > 
> > Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
> 
> Please summarize what's changed in this patch since the last posting.  
> 
> 
> 
> - James

Based on your suggestions, 
- LIST_HEAD is used to initialize integrity_templates.
- register_template simply rejects an attempt to register a new
template, instead of truncating the name, when the template_name is
too long.
- integrity_find_template() now returns 0 on success and -EINVAL,
instead of 1, on failure, simplifying the callers code.

Mimi


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/5] integrity: TPM cleanup
  2008-07-07 21:56 ` [PATCH 1/5] integrity: TPM cleanup Mimi Zohar
  2008-07-08  1:33   ` James Morris
@ 2008-07-15 23:13   ` James Morris
  2008-07-16 20:04     ` Mimi Zohar
                       ` (5 more replies)
  1 sibling, 6 replies; 20+ messages in thread
From: James Morris @ 2008-07-15 23:13 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: linux-kernel, akpm, safford, serue, sailer, zohar, debora, srajiv

On Mon, 7 Jul 2008, Mimi Zohar wrote:

> This patchset contains 5 patches.
> 	Patch 1/5 integrity: TPM cleanup (scripts/Lindent and other)
> 	Patch 2/5 integrity: TPM internal kernel interface
> 	Patch 3/5 integrity: special fs magic
> 	Patch 4/5 integrity: Linux Integrity Module(LIM)
> 	Patch 5/5 integrity: IMA as an integrity service provider
>  
> Signed-off-by: Debora Velarde <dvelarde@us.ibm.com>
> Signed-off-by: Mimi Zohar <zohar@us.ibm.com>

There's been no further comments on this patchset and it's had quite a lot 
of review.  Do you feel it's ready for merging upstream?

If you wish, I can apply this to the security-testing tree which will feed 
into linux-next and then 2.6.27.  (Generating a new patchset against 
recent Linus would likely be best).


- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/5] integrity: TPM cleanup
  2008-07-15 23:13   ` James Morris
@ 2008-07-16 20:04     ` Mimi Zohar
  2008-07-16 20:04     ` [Patch 1/5]integrity: " Mimi Zohar
                       ` (4 subsequent siblings)
  5 siblings, 0 replies; 20+ messages in thread
From: Mimi Zohar @ 2008-07-16 20:04 UTC (permalink / raw)
  To: James Morris
  Cc: linux-kernel, akpm, safford, serue, sailer, zohar, debora, srajiv

On Wed, 2008-07-16 at 09:13 +1000, James Morris wrote: 
> On Mon, 7 Jul 2008, Mimi Zohar wrote:
> 
> > This patchset contains 5 patches.
> > 	Patch 1/5 integrity: TPM cleanup (scripts/Lindent and other)
> > 	Patch 2/5 integrity: TPM internal kernel interface
> > 	Patch 3/5 integrity: special fs magic
> > 	Patch 4/5 integrity: Linux Integrity Module(LIM)
> > 	Patch 5/5 integrity: IMA as an integrity service provider
> >  
> > Signed-off-by: Debora Velarde <dvelarde@us.ibm.com>
> > Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
> 
> There's been no further comments on this patchset and it's had quite a lot 
> of review.  Do you feel it's ready for merging upstream?

Yes, definitely!

> If you wish, I can apply this to the security-testing tree which will feed 
> into linux-next and then 2.6.27.  (Generating a new patchset against 
> recent Linus would likely be best).

Thank you, that would be wonderful.  I'll post a new patchset against 
the 2.6.26-git3.

Thanks!

Mimi


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [Patch 1/5]integrity: TPM cleanup
  2008-07-15 23:13   ` James Morris
  2008-07-16 20:04     ` Mimi Zohar
@ 2008-07-16 20:04     ` Mimi Zohar
  2008-07-16 20:05     ` [Patch 2/5]integrity: TPM internel kernel interface Mimi Zohar
                       ` (3 subsequent siblings)
  5 siblings, 0 replies; 20+ messages in thread
From: Mimi Zohar @ 2008-07-16 20:04 UTC (permalink / raw)
  To: James Morris
  Cc: linux-kernel, akpm, safford, serue, sailer, zohar, debora, srajiv

This patchset contains 5 patches.
	Patch 1/5 integrity: TPM cleanup (scripts/Lindent and other)
	Patch 2/5 integrity: TPM internal kernel interface
	Patch 3/5 integrity: special fs magic
	Patch 4/5 integrity: Linux Integrity Module(LIM)
	Patch 5/5 integrity: IMA as an integrity service provider
 
Signed-off-by: Debora Velarde <dvelarde@us.ibm.com>
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>

Reviewed-by: James Morris <jmorris@namei.org>
---
Index: linux-2.6.26-git3/drivers/char/tpm/tpm.c
===================================================================
--- linux-2.6.26-git3.orig/drivers/char/tpm/tpm.c
+++ linux-2.6.26-git3/drivers/char/tpm/tpm.c
@@ -6,6 +6,7 @@
  * Dave Safford <safford@watson.ibm.com>
  * Reiner Sailer <sailer@watson.ibm.com>
  * Kylene Hall <kjhall@us.ibm.com>
+ * Debora Velarde <dvelarde@us.ibm.com>
  *
  * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  *
@@ -322,7 +323,7 @@ static const u8 tpm_ordinal_duration[TPM
 
 static void user_reader_timeout(unsigned long ptr)
 {
-	struct tpm_chip *chip = (struct tpm_chip *) ptr;
+	struct tpm_chip *chip = (struct tpm_chip *)ptr;
 
 	schedule_work(&chip->work);
 }
@@ -338,10 +339,9 @@ static void timeout_work(struct work_str
 }
 
 /*
- * Returns max number of jiffies to wait
+ * tpm_calc_ordinal_duration - returns max number of jiffies to wait
  */
-unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
-					   u32 ordinal)
+unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
 {
 	int duration_idx = TPM_UNDEFINED;
 	int duration = 0;
@@ -364,7 +364,7 @@ unsigned long tpm_calc_ordinal_duration(
 EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
 
 /*
- * Internal kernel interface to transmit TPM commands
+ * tpm_transmit - internal kernel interface to transmit TPM commands
  */
 static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 			    size_t bufsiz)
@@ -386,8 +386,7 @@ static ssize_t tpm_transmit(struct tpm_c
 	mutex_lock(&chip->tpm_mutex);
 
 	if ((rc = chip->vendor.send(chip, (u8 *) buf, count)) < 0) {
-		dev_err(chip->dev,
-			"tpm_transmit: tpm_send: error %zd\n", rc);
+		dev_err(chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc);
 		goto out;
 	}
 
@@ -419,8 +418,7 @@ static ssize_t tpm_transmit(struct tpm_c
 out_recv:
 	rc = chip->vendor.recv(chip, (u8 *) buf, bufsiz);
 	if (rc < 0)
-		dev_err(chip->dev,
-			"tpm_transmit: tpm_recv: error %zd\n", rc);
+		dev_err(chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc);
 out:
 	mutex_unlock(&chip->tpm_mutex);
 	return rc;
@@ -478,7 +476,7 @@ static ssize_t transmit_cmd(struct tpm_c
 	int err;
 
 	len = tpm_transmit(chip, data, len);
-	if (len <  0)
+	if (len < 0)
 		return len;
 	if (len == TPM_ERROR_SIZE) {
 		err = be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)));
@@ -498,7 +496,7 @@ void tpm_gen_interrupt(struct tpm_chip *
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attempting to determine the timeouts");
+			  "attempting to determine the timeouts");
 }
 EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
 
@@ -513,7 +511,7 @@ void tpm_get_timeouts(struct tpm_chip *c
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attempting to determine the timeouts");
+			  "attempting to determine the timeouts");
 	if (rc)
 		goto duration;
 
@@ -545,7 +543,7 @@ duration:
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_DURATION;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attempting to determine the durations");
+			  "attempting to determine the durations");
 	if (rc)
 		return;
 
@@ -571,17 +569,20 @@ EXPORT_SYMBOL_GPL(tpm_get_timeouts);
 void tpm_continue_selftest(struct tpm_chip *chip)
 {
 	u8 data[] = {
-		0, 193,			/* TPM_TAG_RQU_COMMAND */
-		0, 0, 0, 10,		/* length */
-		0, 0, 0, 83,		/* TPM_ORD_GetCapability */
+		0, 193,		/* TPM_TAG_RQU_COMMAND */
+		0, 0, 0, 10,	/* length */
+		0, 0, 0, 83,	/* TPM_ORD_GetCapability */
 	};
 
 	tpm_transmit(chip, data, sizeof(data));
 }
 EXPORT_SYMBOL_GPL(tpm_continue_selftest);
 
-ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
-			char *buf)
+/*
+ * tpm_show_enabled - determine the permanent disabled state
+ */
+ssize_t tpm_show_enabled(struct device *dev, struct device_attribute *attr,
+			 char *buf)
 {
 	u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 35)];
 	ssize_t rc;
@@ -595,14 +596,17 @@ ssize_t tpm_show_enabled(struct device *
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attemtping to determine the permanent state");
+			  "attemtping to determine the permanent state");
 	if (rc)
 		return 0;
 	return sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_DISABLE_IDX]);
 }
 EXPORT_SYMBOL_GPL(tpm_show_enabled);
 
-ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr,
+/*
+ * tpm_show_active - determine the permanent inactive state
+ */
+ssize_t tpm_show_active(struct device *dev, struct device_attribute *attr,
 			char *buf)
 {
 	u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 35)];
@@ -617,15 +621,18 @@ ssize_t tpm_show_active(struct device * 
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attemtping to determine the permanent state");
+			  "attemtping to determine the permanent state");
 	if (rc)
 		return 0;
 	return sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]);
 }
 EXPORT_SYMBOL_GPL(tpm_show_active);
 
-ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr,
-			char *buf)
+/*
+ * tpm_show_owned - determine the owner state
+ */
+ssize_t tpm_show_owned(struct device *dev, struct device_attribute *attr,
+		       char *buf)
 {
 	u8 data[sizeof(tpm_cap)];
 	ssize_t rc;
@@ -639,15 +646,18 @@ ssize_t tpm_show_owned(struct device * d
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attempting to determine the owner state");
+			  "attempting to determine the owner state");
 	if (rc)
 		return 0;
 	return sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]);
 }
 EXPORT_SYMBOL_GPL(tpm_show_owned);
 
-ssize_t tpm_show_temp_deactivated(struct device * dev,
-				struct device_attribute * attr, char *buf)
+/*
+ * tpm_show_temp_deactivated - determine the temporary inactive state
+ */
+ssize_t tpm_show_temp_deactivated(struct device *dev,
+				  struct device_attribute *attr, char *buf)
 {
 	u8 data[sizeof(tpm_cap)];
 	ssize_t rc;
@@ -661,13 +671,14 @@ ssize_t tpm_show_temp_deactivated(struct
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attempting to determine the temporary state");
+			  "attempting to determine the temporary state");
 	if (rc)
 		return 0;
 	return sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]);
 }
 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 */
@@ -678,7 +689,8 @@ static const u8 pcrread[] = {
 ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
 		      char *buf)
 {
-	u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(pcrread)), 30)];
+	u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(pcrread)),
+		      READ_PCR_RESULT_SIZE)];
 	ssize_t rc;
 	int i, j, num_pcrs;
 	__be32 index;
@@ -693,7 +705,7 @@ ssize_t tpm_show_pcrs(struct device *dev
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attempting to determine the number of PCRS");
+			  "attempting to determine the number of PCRS");
 	if (rc)
 		return 0;
 
@@ -703,7 +715,7 @@ ssize_t tpm_show_pcrs(struct device *dev
 		index = cpu_to_be32(i);
 		memcpy(data + 10, &index, 4);
 		rc = transmit_cmd(chip, data, sizeof(data),
-				"attempting to read a PCR");
+				  "attempting to read a PCR");
 		if (rc)
 			goto out;
 		str += sprintf(str, "PCR-%02d: ", i);
@@ -723,6 +735,9 @@ static const u8 readpubek[] = {
 	0, 0, 0, 124,		/* TPM_ORD_ReadPubek */
 };
 
+/*
+ * tpm_show_pubek - returns the tpm's public endorcement key
+ */
 ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
 		       char *buf)
 {
@@ -742,13 +757,13 @@ ssize_t tpm_show_pubek(struct device *de
 	memcpy(data, readpubek, sizeof(readpubek));
 
 	err = transmit_cmd(chip, data, READ_PUBEK_RESULT_SIZE,
-			"attempting to read the PUBEK");
+			   "attempting to read the PUBEK");
 	if (err)
 		goto out;
 
 	/* 
 	   ignore header 10 bytes
-	   algorithm 32 bits (1 == RSA )
+	   algorithm 32 bits (1 == RSA)
 	   encscheme 16 bits
 	   sigscheme 16 bits
 	   parameters (RSA 12->bytes: keybit, #primes, expbit)  
@@ -757,17 +772,16 @@ ssize_t tpm_show_pubek(struct device *de
 	   ignore checksum 20 bytes
 	 */
 
-	str +=
-	    sprintf(str,
-		    "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
-		    "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X"
-		    " %02X %02X %02X %02X %02X %02X %02X %02X\n"
-		    "Modulus length: %d\nModulus: \n",
-		    data[10], data[11], data[12], data[13], data[14],
-		    data[15], data[16], data[17], data[22], data[23],
-		    data[24], data[25], data[26], data[27], data[28],
-		    data[29], data[30], data[31], data[32], data[33],
-		    be32_to_cpu(*((__be32 *) (data + 34))));
+	str += sprintf(str,
+		       "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
+		       "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X"
+		       " %02X %02X %02X %02X %02X %02X %02X %02X\n"
+		       "Modulus length: %d\nModulus: \n",
+		       data[10], data[11], data[12], data[13], data[14],
+		       data[15], data[16], data[17], data[22], data[23],
+		       data[24], data[25], data[26], data[27], data[28],
+		       data[29], data[30], data[31], data[32], data[33],
+		       be32_to_cpu(*((__be32 *) (data + 34))));
 
 	for (i = 0; i < 256; i++) {
 		str += sprintf(str, "%02X ", data[i + 38]);
@@ -792,10 +806,14 @@ static const u8 cap_version[] = {
 	0, 0, 0, 0
 };
 
+/*
+ * tpm_show_caps - returns the manufacturer and chip version
+ */
 ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
 		      char *buf)
 {
-	u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)];
+	u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap),
+			       ARRAY_SIZE(cap_version)), 30)];
 	ssize_t rc;
 	char *str = buf;
 
@@ -808,34 +826,39 @@ ssize_t tpm_show_caps(struct device *dev
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;
 
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attempting to determine the manufacturer");
+			  "attempting to determine the manufacturer");
 	if (rc)
 		return 0;
 
 	str += sprintf(str, "Manufacturer: 0x%x\n",
-		       be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))));
+		       be32_to_cpu(*((__be32 *) (data +
+						 TPM_GET_CAP_RET_UINT32_1_IDX))));
 
 	memcpy(data, cap_version, sizeof(cap_version));
 	data[CAP_VERSION_IDX] = CAP_VERSION_1_1;
 	rc = transmit_cmd(chip, data, sizeof(data),
-			"attempting to determine the 1.1 version");
+			  "attempting to determine the 1.1 version");
 	if (rc)
 		goto out;
 
 	str += sprintf(str,
 		       "TCG version: %d.%d\nFirmware version: %d.%d\n",
-		       (int) data[14], (int) data[15], (int) data[16],
-		       (int) data[17]);
+		       (int)data[14], (int)data[15], (int)data[16],
+		       (int)data[17]);
 
 out:
 	return str - buf;
 }
 EXPORT_SYMBOL_GPL(tpm_show_caps);
 
-ssize_t tpm_show_caps_1_2(struct device * dev,
-			  struct device_attribute * attr, char *buf)
+/*
+ * tpm_show_caps_1_2 - returns the manufacturer and chip 1.2 version
+ */
+ssize_t tpm_show_caps_1_2(struct device *dev,
+			  struct device_attribute *attr, char *buf)
 {
-	u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)];
+	u8 data[max_t
+		(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)];
 	ssize_t len;
 	char *str = buf;
 
@@ -847,8 +870,8 @@ ssize_t tpm_show_caps_1_2(struct device 
 	data[TPM_CAP_IDX] = TPM_CAP_PROP;
 	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;
 
-	if ((len = tpm_transmit(chip, data, sizeof(data))) <=
-	    TPM_ERROR_SIZE) {
+	len = tpm_transmit(chip, data, sizeof(data));
+	if (len <= TPM_ERROR_SIZE) {
 		dev_dbg(chip->dev, "A TPM error (%d) occurred "
 			"attempting to determine the manufacturer\n",
 			be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
@@ -856,30 +879,33 @@ ssize_t tpm_show_caps_1_2(struct device 
 	}
 
 	str += sprintf(str, "Manufacturer: 0x%x\n",
-		       be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))));
+		       be32_to_cpu(*((__be32 *) (data +
+						 TPM_GET_CAP_RET_UINT32_1_IDX))));
 
 	memcpy(data, cap_version, sizeof(cap_version));
 	data[CAP_VERSION_IDX] = CAP_VERSION_1_2;
 
-	if ((len = tpm_transmit(chip, data, sizeof(data))) <=
-	    TPM_ERROR_SIZE) {
+	len = tpm_transmit(chip, data, sizeof(data));
+	if (len <= TPM_ERROR_SIZE) {
 		dev_err(chip->dev, "A TPM error (%d) occurred "
 			"attempting to determine the 1.2 version\n",
 			be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
 		goto out;
 	}
-	str += sprintf(str,
-		       "TCG version: %d.%d\nFirmware version: %d.%d\n",
-		       (int) data[16], (int) data[17], (int) data[18],
-		       (int) data[19]);
+	str += sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n",
+		       (int)data[16], (int)data[17], (int)data[18],
+		       (int)data[19]);
 
 out:
 	return str - buf;
 }
 EXPORT_SYMBOL_GPL(tpm_show_caps_1_2);
 
+/*
+ * tpm_store_cancel - cancel the current tpm operation
+ */
 ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
-			const char *buf, size_t count)
+			 const char *buf, size_t count)
 {
 	struct tpm_chip *chip = dev_get_drvdata(dev);
 	if (chip == NULL)
@@ -978,8 +1004,7 @@ ssize_t tpm_write(struct file *file, con
 	if (in_size > TPM_BUFSIZE)
 		in_size = TPM_BUFSIZE;
 
-	if (copy_from_user
-	    (chip->data_buffer, (void __user *) buf, in_size)) {
+	if (copy_from_user(chip->data_buffer, (void __user *)buf, in_size)) {
 		mutex_unlock(&chip->buffer_mutex);
 		return -EFAULT;
 	}
@@ -1109,8 +1134,8 @@ static void tpm_dev_release(struct devic
  * upon errant exit from this function specific probe function should call
  * pci_disable_device
  */
-struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific
-				       *entry)
+struct tpm_chip *tpm_register_hardware(struct device *dev,
+				       const struct tpm_vendor_specific *entry)
 {
 #define DEVNAME_SIZE 7
 
@@ -1134,7 +1159,7 @@ struct tpm_chip *tpm_register_hardware(s
 	INIT_WORK(&chip->work, timeout_work);
 
 	setup_timer(&chip->user_read_timer, user_reader_timeout,
-			(unsigned long)chip);
+		    (unsigned long)chip);
 
 	memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific));
 
@@ -1163,8 +1188,7 @@ struct tpm_chip *tpm_register_hardware(s
 	if (misc_register(&chip->vendor.miscdev)) {
 		dev_err(chip->dev,
 			"unable to misc_register %s, minor %d\n",
-			chip->vendor.miscdev.name,
-			chip->vendor.miscdev.minor);
+			chip->vendor.miscdev.name, chip->vendor.miscdev.minor);
 		put_device(chip->dev);
 		return NULL;
 	}



^ permalink raw reply	[flat|nested] 20+ messages in thread

* [Patch 2/5]integrity: TPM internel kernel interface
  2008-07-15 23:13   ` James Morris
  2008-07-16 20:04     ` Mimi Zohar
  2008-07-16 20:04     ` [Patch 1/5]integrity: " Mimi Zohar
@ 2008-07-16 20:05     ` Mimi Zohar
  2008-07-16 20:05     ` [Patch 3/5] integrity: special fs magic Mimi Zohar
                       ` (2 subsequent siblings)
  5 siblings, 0 replies; 20+ messages in thread
From: Mimi Zohar @ 2008-07-16 20:05 UTC (permalink / raw)
  To: James Morris
  Cc: linux-kernel, akpm, safford, serue, sailer, zohar, debora, srajiv

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

Signed-off-by: Debora Velarde <debora@linux.vnet.ibm.com>

Reviewed-by: James Morris <jmorris@namei.org>
---
Index: linux-2.6.26-git3/drivers/char/tpm/tpm.c
===================================================================
--- linux-2.6.26-git3.orig/drivers/char/tpm/tpm.c
+++ linux-2.6.26-git3/drivers/char/tpm/tpm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004 IBM Corporation
+ * Copyright (C) 2004,2007,2008 IBM Corporation
  *
  * Authors:
  * Leendert van Doorn <leendert@watson.ibm.com>
@@ -29,6 +29,13 @@
 #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 <asm/unaligned.h>
 #include "tpm.h"
 
 enum tpm_const {
@@ -51,6 +58,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 +375,7 @@ EXPORT_SYMBOL_GPL(tpm_calc_ordinal_durat
 /*
  * tpm_transmit - 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;
@@ -423,6 +431,7 @@ out:
 	mutex_unlock(&chip->tpm_mutex);
 	return rc;
 }
+EXPORT_SYMBOL_GPL(tpm_transmit);
 
 #define TPM_DIGEST_SIZE 20
 #define TPM_ERROR_SIZE 10
@@ -728,6 +737,102 @@ out:
 }
 EXPORT_SYMBOL_GPL(tpm_show_pcrs);
 
+/*
+ * tpm_chip_lookup - return tpm_chip for given chip number and type
+ */
+static struct tpm_chip *tpm_chip_lookup(int chip_num, int chip_typ)
+{
+	struct tpm_chip *pos;
+
+	spin_lock(&driver_lock);
+	list_for_each_entry(pos, &tpm_chip_list, list) {
+		if ((chip_num == TPM_ANY_NUM || pos->dev_num == chip_num)
+		    && (chip_typ == TPM_ANY_TYPE)) {
+			spin_unlock(&driver_lock);
+			return pos;
+		}
+	}
+
+	spin_unlock(&driver_lock);
+	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)
+ */
+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;
+
+	chip = tpm_chip_lookup(chip_num, chip_id >> TPM_CHIP_TYPE_SHIFT);
+	if (chip == NULL)
+		return -ENODEV;
+	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);
+
+	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
+ */
+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;
+
+	chip = tpm_chip_lookup(chip_num, chip_id >> TPM_CHIP_TYPE_SHIFT);
+	if (chip == NULL)
+		return -ENODEV;
+
+	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));
+	return rc;
+}
+EXPORT_SYMBOL_GPL(tpm_pcr_extend);
+
 #define  READ_PUBEK_RESULT_SIZE 314
 static const u8 readpubek[] = {
 	0, 193,			/* TPM_TAG_RQU_COMMAND */
Index: linux-2.6.26-git3/drivers/char/tpm/tpm.h
===================================================================
--- linux-2.6.26-git3.orig/drivers/char/tpm/tpm.h
+++ linux-2.6.26-git3/drivers/char/tpm/tpm.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004 IBM Corporation
+ * Copyright (C) 2004, 2007 IBM Corporation
  *
  * Authors:
  * Leendert van Doorn <leendert@watson.ibm.com>
@@ -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_
 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 *);
Index: linux-2.6.26-git3/include/linux/tpm.h
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/include/linux/tpm.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2004,2007 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Dave Safford <safford@watson.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ * Debora Velarde <dvelarde@us.ibm.com>
+ *
+ * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org
+ *
+ * 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.
+ *
+ */
+#ifndef __LINUX_TPM_H__
+#define __LINUX_TPM_H__
+
+#define PCI_DEVICE_ID_AMD_8111_LPC    0x7468
+
+/*
+ * Chip type is one of these values in the upper two bytes of chip_id
+ */
+enum tpm_chip_type {
+	TPM_HW_TYPE = 0x0,
+	TPM_SW_TYPE = 0x1,
+	TPM_ANY_TYPE = 0xFFFF,
+};
+
+/*
+ * Chip num is this value or a valid tpm idx in lower two bytes of chip_id
+ */
+enum tpm_chip_num {
+	TPM_ANY_NUM = 0xFFFF,
+};
+
+
+#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
+
+extern int tpm_pcr_read(u32 chip_id, int pcr_idx, u8 *res_buf);
+extern int tpm_pcr_extend(u32 chip_id, int pcr_idx, const u8 *hash);
+#endif
+#endif



^ permalink raw reply	[flat|nested] 20+ messages in thread

* [Patch 3/5] integrity: special fs magic
  2008-07-15 23:13   ` James Morris
                       ` (2 preceding siblings ...)
  2008-07-16 20:05     ` [Patch 2/5]integrity: TPM internel kernel interface Mimi Zohar
@ 2008-07-16 20:05     ` Mimi Zohar
  2008-07-16 20:05     ` [PATCH 4/5]integrity: Linux Integrity Module(LIM) Mimi Zohar
  2008-07-16 20:05     ` [Patch 5/5]integrity: IMA as an integrity service provider Mimi Zohar
  5 siblings, 0 replies; 20+ messages in thread
From: Mimi Zohar @ 2008-07-16 20:05 UTC (permalink / raw)
  To: James Morris
  Cc: linux-kernel, akpm, safford, serue, sailer, zohar, debora, srajiv

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

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>

Reviewed-by: James Morris <jmorris@namei.org>
---
Index: linux-2.6.26-git3/mm/shmem.c
===================================================================
--- linux-2.6.26-git3.orig/mm/shmem.c
+++ linux-2.6.26-git3/mm/shmem.c
@@ -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)
Index: linux-2.6.26-git3/security/inode.c
===================================================================
--- linux-2.6.26-git3.orig/security/inode.c
+++ linux-2.6.26-git3/security/inode.c
@@ -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;
Index: linux-2.6.26-git3/include/linux/magic.h
===================================================================
--- linux-2.6.26-git3.orig/include/linux/magic.h
+++ linux-2.6.26-git3/include/linux/magic.h
@@ -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
Index: linux-2.6.26-git3/fs/debugfs/inode.c
===================================================================
--- linux-2.6.26-git3.orig/fs/debugfs/inode.c
+++ linux-2.6.26-git3/fs/debugfs/inode.c
@@ -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;



^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 4/5]integrity: Linux Integrity Module(LIM)
  2008-07-15 23:13   ` James Morris
                       ` (3 preceding siblings ...)
  2008-07-16 20:05     ` [Patch 3/5] integrity: special fs magic Mimi Zohar
@ 2008-07-16 20:05     ` Mimi Zohar
  2008-07-16 20:05     ` [Patch 5/5]integrity: IMA as an integrity service provider Mimi Zohar
  5 siblings, 0 replies; 20+ messages in thread
From: Mimi Zohar @ 2008-07-16 20:05 UTC (permalink / raw)
  To: James Morris
  Cc: linux-kernel, akpm, safford, serue, sailer, zohar, debora, srajiv

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.)

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
---
Index: linux-2.6.26-git3/include/linux/integrity.h
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/include/linux/integrity.h
@@ -0,0 +1,195 @@
+/*
+ * integrity.h
+ *
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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.
+ */
+
+#ifndef _LINUX_INTEGRITY_H
+#define _LINUX_INTEGRITY_H
+
+#include <linux/fs.h>
+#include <linux/audit.h>
+
+#ifdef CONFIG_INTEGRITY
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+			const unsigned char *fname, char *op,
+			char *cause, int result);
+
+/*
+ * Integrity API calls:
+ *
+ * @collect_measurement:
+ *	Collect template specific measurement data.
+ *	@data contains template specific data used for collecting the
+ *	measurement.
+ * 	Return 0 if operation was successful.
+ *
+ * @appraise_measurement:
+ *	Appraise the integrity of the template specific measurement data.
+ *	@data contains template specific data used for appraising the
+ *	measurement.
+ * 	Return 0 if operation was successful.
+ *
+ * @store_measurement:
+ *	Store the template specific data.
+ *	@data contains template specific data used for storing the
+ *	measurement.
+ *
+ * @must_measure:
+ *	Measurement decision based on an integrity policy.
+ *	@data contains template specific data used for making policy
+ * 	decision.
+ * 	Return 0 if operation was successful.
+ *
+ * @display_template:
+ *	Display template specific data.
+ *
+ */
+
+enum integrity_show_type { INTEGRITY_SHOW_BINARY, INTEGRITY_SHOW_ASCII};
+
+struct template_operations {
+	int (*collect_measurement)(void *);
+	int (*appraise_measurement)(void *);
+	void (*store_measurement)(void *);
+	int (*must_measure)(void *);
+	void (*display_template)(struct seq_file *m, void *,
+				 enum integrity_show_type);
+};
+extern int integrity_register_template(const char *template_name,
+					const struct template_operations *ops);
+extern int integrity_unregister_template(const char *template_name);
+extern int integrity_find_template(const char *,
+				   const struct template_operations **ops);
+
+/*
+ * Integrity hooks:
+ *
+ * @bprm_check_integrity:
+ * 	This hook mediates the point when a search for a binary handler	will
+ * 	begin.  At this point, the OS protects against an executable file,
+ * 	already open for write, from being executed; and an executable file
+ * 	already open for execute, from being modified. So we can be certain
+ *	that any measurements(collect, appraise, store) done here are of
+ * 	the file being executed.
+ * 	@bprm contains the linux_binprm structure.
+ *	Return 0 if the hook is successful and permission is granted.
+ *
+ * @inode_alloc_integrity:
+ *	Allocate and attach an integrity structure to @inode->i_integrity.  The
+ * 	i_integrity field is initialized to NULL when the inode structure is
+ * 	allocated.
+ * 	@inode contains the inode structure.
+ * 	Return 0 if operation was successful.
+ *
+ * @inode_free_integrity:
+ *	@inode contains the inode structure.
+ * 	Deallocate the inode integrity structure and set @inode->i_integrity to
+ * 	NULL.
+ *
+ * @inode_permission:
+ *	This hook is called by the existing Linux permission function, when
+ * 	a file is opened (as well as many other operations).  At this point,
+ *	measurements of files open for read(collect, appraise, store) can
+ * 	be made.
+ *	@inode contains the inode structure to check.
+ *	@mask contains the permission mask.
+ *      @nd contains the nameidata (may be NULL).
+ *
+ * @file_free_integrity:
+ *	Update the integrity xattr value as necessary.
+ * 	*file contains the file structure being closed.
+ *
+ * @file_mmap :
+ *	Measurement(collect, appraise, store) of files mmaped for EXEC,
+ *	could be measured at this point.
+ *	@file contains the file structure for file to map (may be NULL).
+ *	@reqprot contains the protection requested by the application.
+ *	@prot contains the protection that will be applied by the kernel.
+ *	@flags contains the operational flags.
+ *	Return 0 if permission is granted.
+ */
+
+enum lim_hooks {INODE_PERMISSION = 1, FILE_MMAP, BPRM_CHECK };
+
+struct integrity_operations {
+	int (*bprm_check_integrity) (struct linux_binprm *bprm);
+	int (*inode_alloc_integrity) (struct inode *inode);
+	void (*inode_free_integrity) (struct inode *inode);
+	int (*inode_permission) (struct inode *inode, int mask,
+				struct nameidata *nd);
+	void (*file_free_integrity) (struct file *file);
+	int (*file_mmap) (struct file *file,
+			  unsigned long reqprot, unsigned long prot,
+			  unsigned long flags, unsigned long addr,
+			  unsigned long addr_only);
+};
+extern int register_integrity(const struct integrity_operations *ops);
+extern int unregister_integrity(const struct integrity_operations *ops);
+
+/* global variables */
+extern const struct integrity_operations *integrity_ops;
+
+
+int integrity_collect_measurement(const char *template_name, void *data);
+int integrity_appraise_measurement(const char *template_name, void *data);
+int integrity_must_measure(const char *template_name, void *data);
+int integrity_store_measurement(const char *template_name, void *data);
+
+int integrity_bprm_check(struct linux_binprm *bprm);
+int integrity_inode_alloc(struct inode *inode);
+void integrity_inode_free(struct inode *inode);
+int integrity_inode_permission(struct inode *inode, int mask,
+				struct nameidata *nd);
+void integrity_file_free(struct file *file);
+int integrity_file_mmap(struct file *file,
+			  unsigned long reqprot, unsigned long prot,
+			  unsigned long flags, unsigned long addr,
+			  unsigned long addr_only);
+#else
+
+static inline int integrity_bprm_check(struct linux_binprm *bprm)
+{
+	return 0;
+}
+
+static inline int integrity_inode_alloc(struct inode *inode)
+{
+	return 0;
+}
+
+static inline void integrity_inode_free(struct inode *inode)
+{
+	return;
+}
+
+static inline int integrity_inode_permission(struct inode *inode, int mask,
+				struct nameidata *nd)
+{
+	return 0;
+}
+
+static inline int integrity_file_permission(struct file *file, int mask)
+{
+	return 0;
+}
+
+static inline void integrity_file_free(struct file *file)
+{
+	return;
+}
+
+static inline int integrity_file_mmap(struct file *file,
+			  unsigned long reqprot, unsigned long prot,
+			  unsigned long flags, unsigned long addr,
+			  unsigned long addr_only)
+{
+	return 0;
+}
+#endif
+#endif
Index: linux-2.6.26-git3/security/integrity/integrity.c
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/integrity.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2006,2007,2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity.c
+ * 	register integrity subsystem
+ * 	register integrity template
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/integrity.h>
+
+const struct integrity_operations *integrity_ops;
+EXPORT_SYMBOL(integrity_ops);
+
+#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;
+};
+static LIST_HEAD(integrity_templates);
+static DEFINE_MUTEX(integrity_templates_mutex);
+
+/**
+ * register_integrity - registers an integrity framework with the kernel
+ * @ops: a pointer to the struct security_options that is to be registered
+ *
+ * Perhaps in the future integrity module stacking will be necessary, but
+ * for the time being, this function permits only one integrity module to
+ * register itself with the kernel integrity subsystem.
+ *
+ * If another integrity module is already registered, an error code is
+ * returned. On success 0 is returned.
+ */
+int register_integrity(const struct integrity_operations *ops)
+{
+	if (integrity_ops != NULL)
+		return -EAGAIN;
+	integrity_ops = ops;
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(register_integrity);
+
+/**
+ * unregister_integrity - unregisters an integrity framework from the kernel
+ * @ops: a pointer to the struct security_options that is to be registered
+ *
+ * Returns 0 on success, -EINVAL on failure.
+ */
+int unregister_integrity(const struct integrity_operations *ops)
+{
+	if (ops != integrity_ops)
+		return -EINVAL;
+
+	integrity_ops = NULL;
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(unregister_integrity);
+
+/**
+ * integrity_register_template - registers an integrity template with the kernel
+ * @template_name: a pointer to a string containing the template name.
+ * @template_ops: a pointer to the template functions
+ *
+ * Register a set of functions to collect, appraise, store, and display
+ * a template measurement, and a means to decide whether to do them.
+ * Unlike integrity modules, any number of templates may be registered.
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int integrity_register_template(const char *template_name,
+				const struct template_operations *template_ops)
+{
+	int template_len;
+	struct template_list_entry *entry;
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+	INIT_LIST_HEAD(&entry->template);
+
+	template_len = strlen(template_name);
+	if (template_len > TEMPLATE_NAME_LEN_MAX)
+		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);
+	synchronize_rcu();
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(integrity_register_template);
+
+/**
+ * integrity_unregister_template: unregister a template
+ * @template_name: a pointer to a string containing the template name.
+ *
+ * Returns 0 on success, -EINVAL on failure.
+ */
+int integrity_unregister_template(const char *template_name)
+{
+	struct template_list_entry *entry;
+
+	mutex_lock(&integrity_templates_mutex);
+	list_for_each_entry(entry, &integrity_templates, template) {
+		if (strncmp(entry->template_name, template_name,
+			    strlen(entry->template_name)) == 0) {
+			list_del_rcu(&entry->template);
+			mutex_unlock(&integrity_templates_mutex);
+			synchronize_rcu();
+			kfree(entry);
+			return 0;
+		}
+	}
+	mutex_unlock(&integrity_templates_mutex);
+	return -EINVAL;
+}
+
+EXPORT_SYMBOL_GPL(integrity_unregister_template);
+
+/**
+ * integrity_find_template - search the integrity_templates list
+ * @template_name: a pointer to a string containing the template name.
+ * @template_ops: a pointer to the template functions
+ *
+ * Called with an rcu_read_lock
+ * Returns 0 on success, -EINVAL on failure.
+ */
+int integrity_find_template(const char *template_name,
+			    const struct template_operations **template_ops)
+{
+	struct template_list_entry *entry;
+
+	list_for_each_entry_rcu(entry, &integrity_templates, template) {
+		if (strncmp(entry->template_name, template_name,
+			    strlen(entry->template_name)) == 0) {
+			*template_ops = entry->template_ops;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+EXPORT_SYMBOL_GPL(integrity_find_template);
+
+/* Start of the integrity API calls */
+
+/**
+ * integrity_collect_measurement - collect template specific measurement
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int integrity_collect_measurement(const char *template_name, void *data)
+{
+	const struct template_operations *template_ops;
+	int rc;
+
+	rcu_read_lock();
+	rc = integrity_find_template(template_name, &template_ops);
+	if (rc == 0)
+		rc = template_ops->collect_measurement(data);
+	rcu_read_unlock();
+	return rc;
+}
+
+EXPORT_SYMBOL_GPL(integrity_collect_measurement);
+
+/**
+ * integrity_appraise_measurement - appraise template specific measurement
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Returns 0 on success, an error code on failure
+ */
+int integrity_appraise_measurement(const char *template_name, void *data)
+{
+	const struct template_operations *template_ops;
+	int rc;
+
+	rcu_read_lock();
+	rc = integrity_find_template(template_name, &template_ops);
+	if (rc == 0)
+		rc = template_ops->appraise_measurement(data);
+	rcu_read_unlock();
+	return rc;
+}
+
+EXPORT_SYMBOL_GPL(integrity_appraise_measurement);
+
+/**
+ * integrity_store_measurement - store template specific measurement
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Store template specific integrity measurement.
+ */
+int integrity_store_measurement(const char *template_name, void *data)
+{
+	const struct template_operations *template_ops;
+	int rc;
+
+	rcu_read_lock();
+	rc = integrity_find_template(template_name, &template_ops);
+	if (rc == 0)
+		template_ops->store_measurement(data);
+	rcu_read_unlock();
+	return rc;
+}
+
+EXPORT_SYMBOL_GPL(integrity_store_measurement);
+
+/**
+ * integrity_must_measure - measure decision based on template policy
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int integrity_must_measure(const char *template_name, void *data)
+{
+	const struct template_operations *template_ops;
+	int rc;
+
+	rcu_read_lock();
+	rc = integrity_find_template(template_name, &template_ops);
+	if (rc == 0)
+		rc = template_ops->must_measure(data);
+	rcu_read_unlock();
+	return rc;
+}
+
+EXPORT_SYMBOL_GPL(integrity_must_measure);
+
+/* Start of the integrity Hooks */
+
+/* Hook used to measure executable file integrity. */
+int integrity_bprm_check(struct linux_binprm *bprm)
+{
+	int rc = 0;
+
+	if (integrity_ops && integrity_ops->bprm_check_integrity)
+		rc = integrity_ops->bprm_check_integrity(bprm);
+	return rc;
+}
+
+/* Allocate, attach and initialize an inode's i_integrity. */
+int integrity_inode_alloc(struct inode *inode)
+{
+	int rc = 0;
+
+	if (integrity_ops && integrity_ops->inode_alloc_integrity)
+		rc = integrity_ops->inode_alloc_integrity(inode);
+	return rc;
+}
+
+/* Hook used to free an inode's i_integrity structure. */
+void integrity_inode_free(struct inode *inode)
+{
+	if (integrity_ops && integrity_ops->inode_free_integrity)
+		integrity_ops->inode_free_integrity(inode);
+}
+
+/* Hook used to measure a file's integrity. */
+int integrity_inode_permission(struct inode *inode, int mask,
+			       struct nameidata *nd)
+{
+	int rc = 0;
+
+	if (integrity_ops && integrity_ops->inode_permission)
+		rc = integrity_ops->inode_permission(inode, mask, nd);
+	return rc;
+}
+
+/* Hook used to update i_integrity data and integrity xattr values
+ * as necessary.
+ */
+void integrity_file_free(struct file *file)
+{
+	if (integrity_ops && integrity_ops->file_free_integrity)
+		integrity_ops->file_free_integrity(file);
+}
+
+/* Hook used to measure integrity of an mmapped file */
+int integrity_file_mmap(struct file *file, unsigned long reqprot,
+			unsigned long prot, unsigned long flags,
+			unsigned long addr, unsigned long addr_only)
+{
+	int rc = 0;
+
+	if (integrity_ops && integrity_ops->file_mmap)
+		rc = integrity_ops->file_mmap(file, reqprot, prot,
+					      flags, addr, addr_only);
+	return rc;
+}
Index: linux-2.6.26-git3/fs/file_table.c
===================================================================
--- linux-2.6.26-git3.orig/fs/file_table.c
+++ linux-2.6.26-git3/fs/file_table.c
@@ -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_dec_and_test(&file->f_count)) {
 		security_file_free(file);
+		integrity_file_free(file);
 		file_kill(file);
 		file_free(file);
 	}
Index: linux-2.6.26-git3/fs/inode.c
===================================================================
--- linux-2.6.26-git3.orig/fs/inode.c
+++ linux-2.6.26-git3/fs/inode.c
@@ -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>
@@ -151,6 +152,15 @@ static struct inode *alloc_inode(struct 
 			return NULL;
 		}
 
+		/* allocate, attach and initialize an i_integrity */
+		if (integrity_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;
+		}
+
 		spin_lock_init(&inode->i_lock);
 		lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
 
@@ -190,6 +200,7 @@ 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
Index: linux-2.6.26-git3/include/linux/fs.h
===================================================================
--- linux-2.6.26-git3.orig/include/linux/fs.h
+++ linux-2.6.26-git3/include/linux/fs.h
@@ -654,6 +654,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 */
 };
 
Index: linux-2.6.26-git3/include/linux/audit.h
===================================================================
--- linux-2.6.26-git3.orig/include/linux/audit.h
+++ linux-2.6.26-git3/include/linux/audit.h
@@ -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. */
 
@@ -441,6 +446,8 @@ extern int  audit_set_loginuid(struct ta
 #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);
@@ -521,6 +528,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; })
Index: linux-2.6.26-git3/security/integrity/integrity_audit.c
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/integrity_audit.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity_audit.c
+ * 	Audit calls for the integrity subsystem
+ */
+
+#include <linux/audit.h>
+#include <linux/fs.h>
+#include <linux/integrity.h>
+
+static int integrity_audit = 1;
+
+#ifdef CONFIG_INTEGRITY_AUDIT
+static int __init integrity_audit_setup(char *str)
+{
+	ulong audit;
+	int rc;
+	char *op;
+
+	rc = strict_strtoul(str, 10, &audit);
+	if (rc < 0 || audit > 1)
+		printk(KERN_INFO "integrity: invalid integrity_audit value\n");
+	else
+		integrity_audit = audit;
+
+	op = integrity_audit ? "integrity_audit_enabled" :
+	    "integrity_audit_not_enabled";
+	integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, NULL, op, 0);
+	return 1;
+}
+
+__setup("integrity_audit=", integrity_audit_setup);
+#endif
+
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+			 const unsigned char *fname, char *op,
+			 char *cause, int result)
+{
+	struct audit_buffer *ab;
+
+	if (!integrity_audit && result == 1)
+		return;
+
+	ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
+	audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u",
+			 current->pid, current->uid,
+			 audit_get_loginuid(current));
+	audit_log_task_context(ab);
+	switch (audit_msgno) {
+	case AUDIT_INTEGRITY_DATA:
+	case AUDIT_INTEGRITY_METADATA:
+	case AUDIT_INTEGRITY_PCR:
+		audit_log_format(ab, " op=%s cause=%s", op, cause);
+		break;
+	case AUDIT_INTEGRITY_HASH:
+		audit_log_format(ab, " op=%s hash=%s", op, cause);
+		break;
+	case AUDIT_INTEGRITY_STATUS:
+	default:
+		audit_log_format(ab, " op=%s", op);
+	}
+	audit_log_format(ab, " comm=");
+	audit_log_untrustedstring(ab, current->comm);
+	if (fname) {
+		audit_log_format(ab, " name=");
+		audit_log_untrustedstring(ab, fname);
+	}
+	if (inode)
+		audit_log_format(ab, " dev=%s ino=%lu",
+				 inode->i_sb->s_id, inode->i_ino);
+	audit_log_format(ab, " res=%d", result);
+	audit_log_end(ab);
+}
Index: linux-2.6.26-git3/Documentation/kernel-parameters.txt
===================================================================
--- linux-2.6.26-git3.orig/Documentation/kernel-parameters.txt
+++ linux-2.6.26-git3/Documentation/kernel-parameters.txt
@@ -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.
@@ -854,6 +855,11 @@ and is between 256 and 4096 characters. 
 	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]
Index: linux-2.6.26-git3/security/integrity/Makefile
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the kernel integrity code
+#
+
+# Object file lists
+obj-$(CONFIG_INTEGRITY)			+= integrity.o integrity_audit.o
Index: linux-2.6.26-git3/security/integrity/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/Kconfig
@@ -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
Index: linux-2.6.26-git3/security/Kconfig
===================================================================
--- linux-2.6.26-git3.orig/security/Kconfig
+++ linux-2.6.26-git3/security/Kconfig
@@ -4,6 +4,8 @@
 
 menu "Security options"
 
+source security/integrity/Kconfig
+
 config KEYS
 	bool "Enable access key retention support"
 	help
Index: linux-2.6.26-git3/fs/exec.c
===================================================================
--- linux-2.6.26-git3.orig/fs/exec.c
+++ linux-2.6.26-git3/fs/exec.c
@@ -46,6 +46,7 @@
 #include <linux/ptrace.h>
 #include <linux/mount.h>
 #include <linux/security.h>
+#include <linux/integrity.h>
 #include <linux/syscalls.h>
 #include <linux/rmap.h>
 #include <linux/tsacct_kern.h>
@@ -1197,6 +1198,9 @@ int search_binary_handler(struct linux_b
 	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. */
Index: linux-2.6.26-git3/fs/namei.c
===================================================================
--- linux-2.6.26-git3.orig/fs/namei.c
+++ linux-2.6.26-git3/fs/namei.c
@@ -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>
@@ -286,7 +287,10 @@ int permission(struct inode *inode, int 
 	if (retval)
 		return retval;
 
-	return security_inode_permission(inode, mask, nd);
+	retval = security_inode_permission(inode, mask, nd);
+	if (retval)
+		return retval;
+	return integrity_inode_permission(inode, mask, nd);
 }
 
 /**
@@ -462,6 +466,7 @@ static struct dentry * cached_lookup(str
 static int exec_permission_lite(struct inode *inode,
 				       struct nameidata *nd)
 {
+	int retval;
 	umode_t	mode = inode->i_mode;
 
 	if (inode->i_op && inode->i_op->permission)
@@ -486,7 +491,10 @@ static int exec_permission_lite(struct i
 
 	return -EACCES;
 ok:
-	return security_inode_permission(inode, MAY_EXEC, nd);
+	retval =  security_inode_permission(inode, MAY_EXEC, nd);
+	if (retval)
+		return retval;
+	return integrity_inode_permission(inode, MAY_EXEC, nd);
 }
 
 /*
Index: linux-2.6.26-git3/mm/mmap.c
===================================================================
--- linux-2.6.26-git3.orig/mm/mmap.c
+++ linux-2.6.26-git3/mm/mmap.c
@@ -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>
@@ -1043,6 +1044,9 @@ unsigned long do_mmap_pgoff(struct file 
 	error = security_file_mmap(file, reqprot, prot, flags, addr, 0);
 	if (error)
 		return error;
+	error = integrity_file_mmap(file, reqprot, prot, flags, addr, 0);
+	if (error)
+		return error;
 
 	return mmap_region(file, addr, len, flags, vm_flags, pgoff,
 			   accountable);
Index: linux-2.6.26-git3/security/Makefile
===================================================================
--- linux-2.6.26-git3.orig/security/Makefile
+++ linux-2.6.26-git3/security/Makefile
@@ -16,3 +16,7 @@ obj-$(CONFIG_SECURITY_SELINUX)		+= selin
 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



^ permalink raw reply	[flat|nested] 20+ messages in thread

* [Patch 5/5]integrity: IMA as an integrity service provider
  2008-07-15 23:13   ` James Morris
                       ` (4 preceding siblings ...)
  2008-07-16 20:05     ` [PATCH 4/5]integrity: Linux Integrity Module(LIM) Mimi Zohar
@ 2008-07-16 20:05     ` Mimi Zohar
  2008-07-16 23:56       ` James Morris
  5 siblings, 1 reply; 20+ messages in thread
From: Mimi Zohar @ 2008-07-16 20:05 UTC (permalink / raw)
  To: James Morris
  Cc: linux-kernel, akpm, safford, serue, sailer, zohar, debora, srajiv

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

This version addresses a number of issues discussed on LKML, including:
- Added Documentation/ABI/testing/ima_policy which describes loading
  the IMA measurement policy.
- Added policy support for magic numbers and removed them from
  skip_measurement().
- Added policy support for LSM obj_type.
- Replaced using .i_mtime to detect when a file has been modified
  with .i_version. This requires the filesystem to be mounted with
  iversion.  (Requires iversion mount support.)
- Added const for integrity_template_operations.
- Removed integrity_fixup_ops(), to make integrity_operations const too.
- Removed ima_fixup_inodes() by registering the integrity_ops early in
  security_initcall(), but waiting to start IMA in late_initcall(), until
  after the TPM is available.
- Removed CONFIG_IMA_BOOTPARAM and CONFIG_IMA_BOOTPARAM_VALUE.
- Replaced,as appropriate, all GFP_ATOMICs with GFP_KERNEL.

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. 

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
---
Index: linux-2.6.26-git3/Documentation/ABI/testing/ima_policy
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/Documentation/ABI/testing/ima_policy
@@ -0,0 +1,55 @@
+What:		security/ima/policy
+Date:		May 2008
+Contact:	Mimi Zohar <zohar@us.ibm.com>
+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=]]
+			lsm:	[[subj=] [obj=] [type=]]
+
+		base: 	func:= [BPRM_CHECK][FILE_MMAP][INODE_PERMISSION]
+			mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
+			fsmagic:= hex 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
+
+		The default policy measures all executables in bprm_check,
+		all files mmapped executable in file_mmap, and all files
+		open for read in inode_permission.
+
+		Examples of LSM specific definitions:
+
+		SELinux:
+			dont_measure type=var_log_t
+			dont_measure type=auditd_log_t
+			measure subj=system_u func=INODE_PERM mask=MAY_READ
+
+		Smack:
+			measure subj=_ func=INODE_PERM mask=MAY_READ
Index: linux-2.6.26-git3/security/integrity/ima/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/Kconfig
@@ -0,0 +1,41 @@
+#
+# IBM Integrity Measurement Architecture
+#
+
+config IMA
+	bool "Integrity Measurement Architecture(IMA)"
+	depends on INTEGRITY
+	depends on ACPI
+	select CRYPTO
+	select CRYPTO_HMAC
+	select CRYPTO_MD5
+	select CRYPTO_SHA1
+	select TCG_TPM
+	select TCG_TIS
+	help
+	  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.  If your system
+	  has a TPM chip, then IMA also maintains an aggregate
+	  integrity value over this list inside the TPM hardware.
+	  These measurements and the aggregate (signed inside the
+	  TPM) can be retrieved and presented to remote parties to
+	  establish system properties. If unsure, say N.
+
+config IMA_MEASURE_PCR_IDX
+	int "PCR for Aggregate (8<= Index <= 14)"
+	depends on IMA
+	range 8 14
+	default 10
+	help
+	  IMA_MEASURE_PCR_IDX determines the TPM PCR register index
+	  that IMA uses to maintain the integrity aggregate of the
+	  measurement list.  If unsure, use the default 10.
+
+config IMA_BASE_HOOKS
+	bool "IMA base hooks"
+	depends on IMA
+	default n
+	help
+	  Enable this option to allow the LSM module to enforce integrity.
Index: linux-2.6.26-git3/security/integrity/ima/Makefile
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/Makefile
@@ -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
Index: linux-2.6.26-git3/security/integrity/ima/ima_main.c
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/ima_main.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Serge Hallyn <serue@us.ibm.com>
+ * Kylene Hall <kylene@us.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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_main.c
+ *             implements the IMA LIM hooks
+ */
+#include <linux/module.h>
+#include <linux/integrity.h>
+#include <linux/magic.h>
+#include <linux/writeback.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/audit.h>
+#include <linux/ima.h>
+#include <linux/mman.h>
+
+#include "ima.h"
+
+static bool ima_initialized = false;
+char *ima_hash = "sha1";
+static int __init hash_setup(char *str)
+{
+	char *op = "setup";
+	char *hash = "sha1";
+
+	if (strncmp(str, "md5", 3) == 0) {
+		op = "setup";
+		hash = "md5";
+		ima_hash = str;
+	} else if (strncmp(str, "sha1", 4) != 0) {
+		op = "hash_setup";
+		hash = "invalid_hash_type";
+	}
+	integrity_audit_msg(AUDIT_INTEGRITY_HASH, NULL, NULL, op, hash, 0);
+	return 1;
+}
+
+__setup("ima_hash=", hash_setup);
+
+/* For use when the LSM module makes LIM API calls */
+#ifdef CONFIG_IMA_BASE_HOOKS
+static int ima_base_hooks = 1;
+#else
+static int ima_base_hooks;
+#endif
+
+/*
+ * Setup the data structure used for the IMA LIM API calls.
+ */
+void ima_fixup_argsdata(struct ima_args_data *data,
+			struct inode *inode, struct dentry *dentry,
+			struct file *file, struct nameidata *nd, int mask,
+			int function)
+{
+	data->inode = inode;
+	data->dentry = dentry;
+	data->file = file;
+	data->nd = nd;
+	data->mask = mask;
+	data->function = function;
+
+	if (file && file->f_dentry) {
+		if (!dentry)
+			data->dentry = dentry = file->f_dentry;
+	}
+	if (nd && nd->path.dentry) {
+		if (!dentry)
+			data->dentry = dentry = nd->path.dentry;
+	}
+	if (dentry && dentry->d_inode) {
+		if (!inode)
+			data->inode = inode = dentry->d_inode;
+	}
+
+	return;
+}
+
+/**
+ * ima_file_free - called on close
+ * @file: pointer to file being closed
+ *
+ * Flag files that changed, based on i_version.
+ */
+static void ima_file_free(struct file *file)
+{
+	struct inode *inode = NULL;
+	struct ima_iint_cache *iint;
+
+	if (!file->f_dentry)	/* can be NULL */
+		return;
+
+	inode = file->f_dentry->d_inode;
+	if (S_ISDIR(inode->i_mode))
+		return;
+	if ((file->f_mode & FMODE_WRITE) &&
+	    (atomic_read(&inode->i_writecount) == 1)) {
+		iint = inode->i_integrity;
+		mutex_lock(&iint->mutex);
+		if (iint->version != inode->i_version)
+			iint->measured = 0;
+		mutex_unlock(&iint->mutex);
+	}
+}
+
+/**
+ * ima_alloc_integrity - allocate and attach an integrity structure
+ * @inode: the inode structure
+ *
+ * Returns 0 on success, -ENOMEM on failure
+ */
+static int ima_inode_alloc_integrity(struct inode *inode)
+{
+	struct ima_iint_cache *iint;
+
+	iint = kzalloc(sizeof(*iint), GFP_KERNEL);
+	if (!iint)
+		return -ENOMEM;
+
+	mutex_init(&iint->mutex);
+	inode->i_integrity = iint;
+	iint->version = inode->i_version;
+	return 0;
+}
+
+/**
+ * ima_inode_free_integrity - free the integrity structure
+ * @inode: the inode structure
+ */
+static void ima_inode_free_integrity(struct inode *inode)
+{
+	struct ima_iint_cache *iint = inode->i_integrity;
+
+	if (iint) {
+		inode->i_integrity = NULL;
+		kfree(iint);
+	}
+}
+
+/**
+ * ima_inode_permission - based on policy, collect/store measurement.
+ * @inode: pointer to the inode to be measured
+ * @mask: contains MAY_READ, MAY_WRITE, MAY_APPEND or MAY_EXECUTE
+ * @nd: pointer to a nameidata
+ *
+ * Measure the file associated with the inode, if the
+ * file is open for read and the results of the call to
+ * ima_must_measure() require the file to be measured.
+ *
+ * Invalidate the PCR:
+ * 	- Opening a file for write when already open for read,
+ *	  results in a time of measure, time of use (ToMToU) error.
+ *	- Opening a file for read when already open for write,
+ * 	  could result in a file measurement error.
+ *
+ * Return 0 on success, an error code on failure.
+ * (Based on the results of appraise_measurement().)
+ */
+static int ima_inode_permission(struct inode *inode, int mask,
+				struct nameidata *nd)
+{
+	struct ima_data idata;
+	struct ima_args_data *data = &idata.data.args;
+
+	if (!ima_initialized)
+		return 0;
+
+	memset(&idata, 0, sizeof idata);
+	ima_fixup_argsdata(data, inode, NULL, NULL, nd, mask, INODE_PERMISSION);
+
+	/* The file name is not required, but only a hint. */
+	if (nd)
+		data->filename = (!nd->path.dentry->d_name.name) ?
+		    (char *)nd->path.dentry->d_iname :
+		    (char *)nd->path.dentry->d_name.name;
+
+	/* Invalidate PCR, if a measured file is already open for read */
+	if ((mask == MAY_WRITE) || (mask == MAY_APPEND)) {
+		int mask_sav = data->mask;
+		int rc;
+
+		data->mask = MAY_READ;
+		rc = ima_must_measure(&idata);
+		if (!rc) {
+			if (atomic_read(&(data->dentry->d_count)) - 1 >
+			    atomic_read(&(inode->i_writecount)))
+				ima_add_violation(inode, data->filename,
+						  "invalid_pcr", "ToMToU");
+		}
+		data->mask = mask_sav;
+		goto out;
+	}
+
+	/* measure executables later */
+	if (mask & MAY_READ) {
+		int rc;
+
+		rc = ima_must_measure(&idata);
+		if (!rc) {
+			/* Invalidate PCR, if a measured file is
+			 * already open for write.
+			 */
+			if (atomic_read(&(inode->i_writecount)) > 0)
+				ima_add_violation(inode, data->filename,
+						  "invalid_pcr",
+						  "open_writers");
+
+			idata.type = IMA_DATA;
+			rc = ima_collect_measurement(&idata);
+			if (!rc)
+				ima_store_measurement(&idata);
+		}
+	}
+out:
+	return 0;
+}
+
+/**
+ * ima_file_mmap - based on policy, collect/store measurement.
+ * @inode: pointer to the inode to be measured
+ * @mask: contains MAY_READ, MAY_WRITE, MAY_APPEND or MAY_EXECUTE
+ * @nd: pointer to a nameidata
+ *
+ * Measure files being mmapped executable based on the ima_must_measure()
+ * policy decision.
+ *
+ * Return 0 on success, an error code on failure.
+ * (Based on the results of appraise_measurement().)
+ */
+static int ima_file_mmap(struct file *file, unsigned long reqprot,
+			 unsigned long prot, unsigned long flags,
+			 unsigned long addr, unsigned long addr_only)
+{
+	struct ima_data idata;
+	struct ima_args_data *data = &idata.data.args;
+	int rc = 0;
+
+	if (!ima_initialized)
+		return 0;
+	if (!file || !file->f_dentry)
+		return rc;
+	if (!(prot & VM_EXEC))
+		return rc;
+
+	ima_fixup_argsdata(data, NULL, NULL, file, NULL, MAY_EXEC, FILE_MMAP);
+	data->filename = (file->f_dentry->d_name.name) ?
+	    (char *)file->f_dentry->d_iname :
+	    (char *)file->f_dentry->d_name.name;
+
+	rc = ima_must_measure(&idata);
+	if (!rc) {
+		idata.type = IMA_DATA;
+		rc = ima_collect_measurement(&idata);
+		if (!rc)
+			ima_store_measurement(&idata);
+	}
+	return 0;
+}
+
+/**
+ * ima_bprm_check_integrity - based on policy, collect/store measurement.
+ * @bprm: contains the linux_binprm structure
+ *
+ * The OS protects against an executable file, already open for write,
+ * from being executed in deny_write_access() and an executable file,
+ * already open for execute, from being modified in get_write_access().
+ * So we can be certain that what we verify and measure here is actually
+ * what is being executed.
+ *
+ * Return 0 on success, an error code on failure.
+ * (Based on the results of appraise_measurement().)
+ */
+static int ima_bprm_check_integrity(struct linux_binprm *bprm)
+{
+	struct ima_data idata;
+	struct ima_args_data *data = &idata.data.args;
+	int rc = 0;
+
+	if (!ima_initialized)
+		return 0;
+	ima_fixup_argsdata(data, NULL, NULL, bprm->file, NULL, MAY_EXEC,
+			   BPRM_CHECK);
+	data->filename = bprm->filename;
+
+	rc = ima_must_measure(&idata);
+	if (!rc) {
+		idata.type = IMA_DATA;
+		rc = ima_collect_measurement(&idata);
+		if (!rc)
+			ima_store_measurement(&idata);
+	}
+	return 0;
+}
+
+static const struct integrity_operations ima_integrity_ops = {
+	.bprm_check_integrity = ima_bprm_check_integrity,
+	.inode_permission = ima_inode_permission,
+	.inode_alloc_integrity = ima_inode_alloc_integrity,
+	.inode_free_integrity = ima_inode_free_integrity,
+	.file_free_integrity = ima_file_free,
+	.file_mmap = ima_file_mmap,
+};
+
+static const struct integrity_operations ima_base_ops = {
+	.inode_alloc_integrity = ima_inode_alloc_integrity,
+	.inode_free_integrity = ima_inode_free_integrity,
+	.file_free_integrity = ima_file_free,
+};
+
+/* Register the integrity ops early so that i_integrity is
+ * allocated at inode initialization.
+ */
+static int __init init_ops(void)
+{
+	int error;
+
+	if (ima_base_hooks)
+		error = register_integrity(&ima_base_ops);
+	else
+		error = register_integrity(&ima_integrity_ops);
+	return error;
+}
+
+/* After the TPM is available, start IMA
+ */
+static int __init init_ima(void)
+{
+	int error;
+
+	error = ima_init();
+	if (error)
+		goto out;
+	ima_initialized = true;
+	integrity_register_template("ima", &ima_template_ops);
+out:
+	return error;
+}
+
+static void __exit cleanup_ima(void)
+{
+	integrity_unregister_template("ima");
+	unregister_integrity(&ima_integrity_ops);
+	ima_cleanup();
+}
+
+security_initcall(init_ops);	/* Register the integrity ops early */
+late_initcall(init_ima);	/* Start IMA after the TPM is available */
+module_exit(cleanup_ima);
+
+MODULE_DESCRIPTION("Integrity Measurement Architecture");
+MODULE_LICENSE("GPL");
Index: linux-2.6.26-git3/security/integrity/ima/ima_init.c
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/ima_init.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer      <sailer@watson.ibm.com>
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Mimi Zohar         <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima_init.c
+ *             initialization and cleanup functions
+ */
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include "ima.h"
+
+/* name for boot aggregate entry */
+static char *boot_aggregate_name = "boot_aggregate";
+static const char version[] = "v7.6 02/27/2007";
+
+int ima_used_chip;
+
+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);
+	if (entry == NULL) {
+		ima_add_violation(NULL, boot_aggregate_name,
+				  "add_measure", "ENOMEM");
+		return;
+	}
+	count = strlen(boot_aggregate_name);
+	if (count > IMA_EVENT_NAME_LEN_MAX)
+		count = IMA_EVENT_NAME_LEN_MAX;
+	memcpy(entry->template_name, boot_aggregate_name, count);
+	entry->template_name[count] = '\0';
+	if (ima_used_chip) {
+		int i;
+		u8 pcr_i[20];
+		struct hash_desc desc;
+		struct crypto_hash *tfm;
+		struct scatterlist sg;
+
+		tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
+		if (!tfm || IS_ERR(tfm)) {
+			kfree(entry);
+			ima_error("error initializing digest.\n");
+			return;
+		}
+		desc.tfm = tfm;
+		desc.flags = 0;
+		crypto_hash_init(&desc);
+
+		for (i = 0; i < 8; i++) {
+			ima_pcrread(i, pcr_i, sizeof(pcr_i));
+			/* now accumulate with current aggregate */
+			sg_init_one(&sg, (u8 *) pcr_i, 20);
+			crypto_hash_update(&desc, &sg, 20);
+		}
+		crypto_hash_final(&desc, entry->digest);
+		crypto_free_hash(tfm);
+	} else
+		memset(entry->digest, 0xff, 20);
+
+	/* now add measurement; if TPM bypassed, we have a ff..ff entry */
+	err = ima_add_measure_entry(entry, 0);
+	if (err < 0) {
+		kfree(entry);
+		ima_add_violation(NULL, boot_aggregate_name,
+				  "add_measure", " ");
+	}
+}
+
+int ima_init(void)
+{
+	int rc;
+
+	ima_used_chip = 0;
+	rc = tpm_pcr_read(IMA_TPM, 0, NULL);
+	if (rc == 0)
+		ima_used_chip = 1;
+
+	if (!ima_used_chip)
+		ima_info("No TPM chip found(rc = %d), activating TPM-bypass!\n",
+			 rc);
+
+	ima_create_htable();	/* for measurements */
+	ima_add_boot_aggregate();	/* boot aggregate must be first entry */
+
+	return ima_fs_init();
+}
+
+void __exit ima_cleanup(void)
+{
+	ima_fs_cleanup();
+}
Index: linux-2.6.26-git3/security/integrity/ima/ima_api.c
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/ima_api.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ *
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima_api.c
+ *            - implements the LIM API
+ */
+#include <linux/module.h>
+#include <linux/integrity.h>
+#include <linux/magic.h>
+#include <linux/writeback.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/audit.h>
+#include <linux/ima.h>
+
+#include "ima.h"
+
+const struct template_operations ima_template_ops = {
+	.must_measure = ima_must_measure,
+	.collect_measurement = ima_collect_measurement,
+	.store_measurement = ima_store_measurement,
+	.display_template = ima_template_show
+};
+
+/**
+ * mode_setup - for compatability with non-template IMA versions
+ * @str: is pointer to a string
+ */
+int ima_template_mode = 1;
+static int __init mode_setup(char *str)
+{
+	if (strncmp(str, "ima", 3) == 0)
+		ima_template_mode = 0;
+	if (strncmp(str, "template", 7) == 0)
+		ima_template_mode = 1;
+	ima_info("template_mode %s \n",
+	       	  ima_template_mode ? "template" : "ima");
+	return 1;
+}
+
+__setup("ima_mode=", mode_setup);
+
+/**
+ * ima_digest_cpy - copy the hash in the IMA template structure to a digest
+ * @template_name: string containing the name of the template (i.e. "ima")
+ * @template: pointer to template structure
+ * @digest: pointer to the digest
+ *
+ * Returns 0 on success, error code otherwise
+ */
+static int ima_digest_cpy(char *template_name, void *template, u8 *digest)
+{
+	int rc, result = 0;
+	struct ima_inode_measure_entry *inode_template =
+	    (struct ima_inode_measure_entry *)template;
+
+	rc = strcmp(template_name, "ima");
+	if (rc == 0)
+		memcpy(digest, inode_template->digest,
+		       sizeof inode_template->digest);
+	else
+		result = -ENODATA;
+	return result;
+}
+
+/**
+ * ima_store_template_measure - collect and protect template measurements
+ * @template_name: string containing the name of the template (i.e. "ima")
+ * @template_len: length of the template data
+ * @template: actual template data
+ * @violation: invalidate pcr measurement indication
+ * @audit_cause: string containing the audit failure cause
+ *
+ * Calculate the hash of a template entry, add the template entry
+ * to an ordered list of measurement entries maintained inside the kernel,
+ * and also update the aggregate integrity value (maintained inside the
+ * configured TPM PCR) over the hashes of the current list of measurement
+ * entries.
+ *
+ * Applications retrieve the current kernel-held measurement list through
+ * the securityfs entries in /sys/kernel/security/ima. The signed aggregate
+ * TPM PCR (called quote) can be retrieved using a TPM user space library
+ * and is used to validate the measurement list.
+ *
+ * Returns 0 on success, error code otherwise
+ */
+static int ima_store_template_measure(char *template_name, int template_len,
+				      char *template, int violation,
+				      char **audit_cause)
+{
+	struct ima_measure_entry *entry;
+	u8 digest[IMA_DIGEST_SIZE];
+	struct ima_queue_entry *qe;
+	int count, result = 0;
+
+	memset(digest, 0, IMA_DIGEST_SIZE);
+	if (!violation) {
+		int rc = -ENODATA;
+
+		if (!ima_template_mode)
+			rc = ima_digest_cpy(template_name, template, digest);
+		if (rc < 0)
+			result = ima_calc_template_hash(template_len, template,
+							digest);
+
+		/* hash exists already? */
+		qe = ima_lookup_digest_entry(digest);
+		if (qe) {
+			*audit_cause = "hash_exists";
+			result = -EEXIST;
+			goto out;
+		}
+	}
+
+	/* create new entry and add to measurement list */
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry) {
+		*audit_cause = "ENOMEM";
+		result = -ENOMEM;
+		goto out;
+	}
+
+	entry->template = kzalloc(template_len, GFP_KERNEL);
+	if (!entry->template) {
+		*audit_cause = "ENOMEM";
+		result = -ENOMEM;
+		goto out;
+	}
+	if (!template_name) {
+		*audit_cause = "null_template_name";
+		count = 1;
+	} else {
+		count = strlen(template_name);
+		if (count > IMA_EVENT_NAME_LEN_MAX)
+			count = IMA_EVENT_NAME_LEN_MAX;
+		memcpy(entry->template_name, template_name, count);
+	}
+	entry->template_name[count] = '\0';
+	entry->template_len = template_len;
+	memcpy(entry->template, template, template_len);
+	memcpy(entry->digest, digest, IMA_DIGEST_SIZE);
+
+	result = ima_add_measure_entry(entry, violation);
+	if (result < 0)
+		kfree(entry);
+out:
+	return result;
+}
+
+/**
+ * ima_store_inode_measure - create and store an inode template measurement
+ * @name: ascii file name associated with the measurement hash
+ * @hash_len: length of hash value in bytes (16 for MD5, 20 for SHA1)
+ * @hash: actual hash value pre-calculated
+ *
+ * Returns 0 on success, error code otherwise
+ */
+static int ima_store_inode_measure(struct inode *inode,
+				   const unsigned char *name,
+				   int hash_len, char *hash, int violation)
+{
+	struct ima_inode_measure_entry measure_entry, *entry = &measure_entry;
+	int result;
+	int namelen;
+	char *op = "add_measure";
+	char *cause = " ";
+
+	memset(entry, 0, sizeof *entry);
+	if (!violation)
+		memcpy(entry->digest, hash, hash_len > IMA_DIGEST_SIZE ?
+		       IMA_DIGEST_SIZE : hash_len);
+	if (name) {
+		namelen = strlen(name);
+		memcpy(entry->file_name, name, namelen > IMA_EVENT_NAME_LEN_MAX
+		       ? IMA_EVENT_NAME_LEN_MAX : namelen);
+		entry->file_name[namelen] = '\0';
+	}
+	result = ima_store_template_measure("ima", sizeof *entry, (char *)entry,
+					    violation, &cause);
+	if (result < 0)
+		integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
+				    name, op, cause, result);
+	return result;
+}
+
+/**
+ * ima_add_violation - add violation to measurement list.
+ * @inode: inode associated with the violation
+ * @fname: name associated with the inode
+ * @op: string pointer to audit operation (i.e. "invalid_pcr", "add_measure")
+ * @cause: string pointer to reason for violation (i.e. "ToMToU")
+ *
+ * Violations are flagged in the measurement list with zero hash values.
+ * By extending the PCR with 0xFF's instead of with zeroes, the PCR
+ * value is invalidated.
+ */
+void ima_add_violation(struct inode *inode, const unsigned char *fname,
+		       char *op, char *cause)
+{
+	int result;
+
+	/* can overflow, only indicator */
+	atomic_inc(&ima_htable.violations);
+
+	result = ima_store_inode_measure(inode, fname, 0, NULL, 1);
+	integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, fname, op,
+			    cause, result);
+}
+
+/**
+ * skip_measurement - measure only regular files, skip everything else.
+ * @inode: inode being measured
+ * @mask: contains the permission mask
+ *
+ * Quick sanity check to make sure that only regular files opened
+ * for read-only or execute are measured.
+ *
+ * Return 1 to skip measure, 0 to measure
+ */
+static int skip_measurement(struct inode *inode, int mask)
+{
+	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+		return 1;	/* can't measure */
+
+	if (special_file(inode->i_mode) || S_ISLNK(inode->i_mode))
+		return 1;	/* don't measure */
+
+	if (S_ISREG(inode->i_mode))
+		return 0;	/* measure */
+	return 1;		/* don't measure */
+}
+
+/**
+ * ima_must_measure - measure decision based on policy.
+ * @template_data: pointer to struct ima_data containing ima_args_data
+ *
+ * The policy is defined in terms of keypairs:
+ * 		subj=, obj=, type=, func=, mask=, fsmagic=
+ *	subj,obj, and type: are LSM specific.
+ * 	func: INODE_PERMISSION | BPRM_CHECK | FILE_MMAP
+ * 	mask: contains the permission mask
+ *	fsmagic: hex value
+ *
+ * Return 0 to measure. For matching a DONT_MEASURE policy, no policy,
+ * or other error, return an error code.
+*/
+int ima_must_measure(void *template_data)
+{
+	struct ima_data *idata = (struct ima_data *)template_data;
+	struct ima_args_data *data = &idata->data.args;
+	int rc;
+
+	if ((data->mask & MAY_WRITE) || (data->mask & MAY_APPEND))
+		return -EPERM;
+
+	if (skip_measurement(data->inode, data->mask))
+		return -EPERM;
+
+	rc = ima_match_policy(data->inode, data->function, data->mask);
+	if (rc)
+		return 0;
+	return -EACCES;
+}
+
+/**
+ * ima_collect_measurement - collect file measurements and store in the inode
+ * @template_data: pointer to struct ima_data containing ima_args_data
+ *
+ * Return 0 on success, error code otherwise
+ */
+int ima_collect_measurement(void *template_data)
+{
+	struct ima_iint_cache *iint;
+	struct ima_data *idata = (struct ima_data *)template_data;
+	struct ima_args_data *data = &idata->data.args;
+	struct inode *inode = data->inode;
+	struct dentry *dentry = data->dentry;
+	struct nameidata *nd = data->nd;
+	struct file *file = data->file;
+	int result = 0;
+
+	if (idata->type != IMA_DATA)
+		return -EPERM;
+
+	if (!inode || !dentry)
+		return -EINVAL;
+
+	iint = inode->i_integrity;
+	mutex_lock(&iint->mutex);
+	if (!iint->measured) {
+		memset(iint->digest, 0, IMA_DIGEST_SIZE);
+		result = ima_calc_hash(dentry, file, nd, iint->digest);
+	} else
+		result = -EEXIST;
+	mutex_unlock(&iint->mutex);
+	return result;
+}
+
+/**
+ * ima_store_measurement - store file and template measurements
+ * @template_data: pointer to struct ima_data containing ima_args_data,
+ * used to create an IMA template, or a template.
+ *
+ * For file measurements, first create an IMA template and then store it.
+ * For all other types of template measurements, just store it.
+ */
+void ima_store_measurement(void *template_data)
+{
+	struct ima_data *idata = (struct ima_data *)template_data;
+	int result;
+	char *op = "add_template_measure";
+	char *cause = "";
+
+	if (idata->type == IMA_DATA) {
+		struct ima_args_data *data = &idata->data.args;
+		struct ima_iint_cache *iint;
+
+		iint = data->inode->i_integrity;
+		mutex_lock(&iint->mutex);
+		if (iint->measured) {
+			mutex_unlock(&iint->mutex);
+			return;
+		}
+		result = ima_store_inode_measure(data->inode, data->filename,
+						 IMA_DIGEST_SIZE, iint->digest,
+						 0);
+		if (!result || result == -EEXIST) {
+			iint->measured = 1;
+			iint->version = data->inode->i_version;
+		}
+		mutex_unlock(&iint->mutex);
+	} else if (idata->type == IMA_TEMPLATE) {
+		struct ima_store_data *template = (struct ima_store_data *)
+		    &idata->data.template;
+
+		result = ima_store_template_measure(template->name,
+						    template->len,
+						    template->data, 0, &cause);
+		if (result < 0)
+			integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL,
+					    template->name, op, cause, result);
+	}
+}
Index: linux-2.6.26-git3/security/integrity/ima/ima.h
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/ima.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima.h
+ *	internal ima definitions
+ */
+
+#ifndef __LINUX_IMA_H
+#define __LINUX_IMA_H
+
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/security.h>
+#include <linux/integrity.h>
+#include <linux/hash.h>
+#include <linux/tpm.h>
+
+#define ima_printk(level, format, arg...)		\
+	printk(level "ima (%s): " format, __func__, ## arg)
+
+#define ima_error(format, arg...)	\
+	ima_printk(KERN_ERR, format, ## arg)
+
+#define ima_info(format, arg...)	\
+	ima_printk(KERN_INFO, format, ## arg)
+
+/* digest size for IMA, fits SHA1 or MD5 */
+#define IMA_DIGEST_SIZE		20
+#define IMA_EVENT_NAME_LEN_MAX	255
+
+#define IMA_HASH_BITS 9
+#define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS)
+
+/* set during initialization */
+extern int ima_used_chip;
+extern char *ima_hash;
+
+struct ima_measure_entry {
+	u8 digest[IMA_DIGEST_SIZE];	/* sha1 or md5 measurement hash */
+	char template_name[IMA_EVENT_NAME_LEN_MAX + 1];	/* name + \0 */
+	int template_len;
+	char *template;
+};
+
+struct ima_queue_entry {
+	struct hlist_node hnext;	/* place in hash collision list */
+	struct list_head later;		/* place in ima_measurements list */
+	struct ima_measure_entry *entry;
+};
+extern struct list_head ima_measurements;	/* list of all measurements */
+
+/* declarations */
+extern int ima_template_mode;
+extern const struct template_operations ima_template_ops;
+
+/* Internal IMA function definitions */
+int ima_init(void);
+void ima_cleanup(void);
+int ima_fs_init(void);
+void ima_fs_cleanup(void);
+void ima_create_htable(void);
+int ima_add_measure_entry(struct ima_measure_entry *entry, int violation);
+struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest);
+int ima_calc_hash(struct dentry *dentry, struct file *file,
+			struct nameidata *, char *digest);
+int ima_calc_template_hash(int template_len, char *template, char *digest);
+void ima_add_violation(struct inode *inode, const unsigned char *fname,
+			char *op, char *cause);
+
+enum ima_action {DONT_MEASURE, MEASURE};
+int ima_match_policy(struct inode *inode, enum lim_hooks func, int mask);
+int ima_add_rule(int, char *, char *, char *, char *, char *, char *);
+void ima_init_policy(void);
+void ima_update_policy(void);
+
+
+/* LIM API function definitions */
+int ima_must_measure(void *d);
+int ima_collect_measurement(void *d);
+int ima_appraise_measurement(void *d);
+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
+ */
+extern spinlock_t ima_queue_lock;
+
+struct ima_h_table {
+	atomic_t len;		/* number of stored measurements in the list */
+	atomic_long_t violations;
+	unsigned int max_htable_size;
+	struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE];
+	atomic_t queue_len[IMA_MEASURE_HTABLE_SIZE];
+};
+extern struct ima_h_table ima_htable;
+
+static inline unsigned long IMA_HASH_KEY(u8 *digest)
+{
+	 return(hash_ptr(digest, IMA_HASH_BITS));
+}
+
+/* TPM "Glue" definitions */
+
+#define IMA_TPM ((((u32)TPM_ANY_TYPE)<<16) | (u32)TPM_ANY_NUM)
+static inline void ima_extend(const u8 *hash)
+{
+	if (!ima_used_chip)
+		return;
+
+	if (tpm_pcr_extend(IMA_TPM, CONFIG_IMA_MEASURE_PCR_IDX, hash) != 0)
+		ima_error("Error Communicating to TPM chip\n");
+}
+
+static inline void ima_pcrread(int idx, u8 *pcr, int pcr_size)
+{
+	if (!ima_used_chip)
+		return;
+
+	if (tpm_pcr_read(IMA_TPM, idx, pcr) != 0)
+		ima_error("Error Communicating to TPM chip\n");
+}
+
+struct ima_inode_measure_entry {
+	u8 digest[IMA_DIGEST_SIZE];	/* sha1/md5 measurement hash */
+	char file_name[IMA_EVENT_NAME_LEN_MAX + 1];	/* name + \0 */
+};
+
+/* inode integrity data */
+struct ima_iint_cache {
+	u64 		version;
+	int 		measured;
+	u8 		hmac[IMA_DIGEST_SIZE];
+	u8 		digest[IMA_DIGEST_SIZE];
+	struct mutex mutex;
+};
+#endif
Index: linux-2.6.26-git3/security/integrity/ima/ima_crypto.c
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/ima_crypto.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zohar@us.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * 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_crypto.c
+ * 	Calculate a file's or a template's hash.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/crypto.h>
+#include <linux/mm.h>
+#include <linux/mount.h>
+#include <linux/scatterlist.h>
+#include "ima.h"
+
+/*
+ * Calculate the file hash, using an open file descriptor if available.
+ */
+static int update_file_hash(struct dentry *dentry, struct file *f,
+			    struct nameidata *nd, struct hash_desc *desc)
+{
+	struct file *file = f;
+	struct scatterlist sg[1];
+	loff_t i_size;
+	int rc = 0;
+	char *rbuf;
+	int offset = 0;
+
+	if (!file) {
+		struct dentry *de = dget(dentry);
+		struct vfsmount *mnt = mntget(nd->path.mnt);
+		if (!de || !mnt) {
+			rc = -EINVAL;
+			goto err_out;
+		}
+		file = dentry_open(de, mnt, O_RDONLY);
+		if (IS_ERR(file)) {
+			ima_info("%s dentry_open failed\n", de->d_name.name);
+			rc = PTR_ERR(file);
+			file = NULL;
+		}
+err_out:
+		if (!file) {
+			dput(de);
+			mntput(mnt);
+			goto out;
+		}
+	}
+
+	if (!file->f_dentry || !file->f_dentry->d_inode) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!rbuf) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	i_size = i_size_read(file->f_dentry->d_inode);
+	while (offset < i_size) {
+		int rbuf_len;
+
+		rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE);
+		if (rbuf_len < 0) {
+			rc = rbuf_len;
+			break;
+		}
+		offset += rbuf_len;
+		sg_set_buf(sg, rbuf, rbuf_len);
+
+		rc = crypto_hash_update(desc, sg, rbuf_len);
+		if (rc)
+			break;
+	}
+	kfree(rbuf);
+out:
+	if (file && !f)
+		fput(file);	/* clean up dentry_open() */
+	return rc;
+}
+
+/*
+ * Calculate the MD5/SHA1 digest
+ */
+int ima_calc_hash(struct dentry *dentry, struct file *file,
+		  struct nameidata *nd, char *digest)
+{
+	struct hash_desc desc;
+	int rc;
+
+	if (!dentry && !file)
+		return -EINVAL;
+
+	desc.tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(desc.tfm)) {
+		ima_info("failed to load %s transform: %ld\n",
+			 ima_hash, PTR_ERR(desc.tfm));
+		rc = PTR_ERR(desc.tfm);
+		return rc;
+	}
+	desc.flags = 0;
+	rc = crypto_hash_init(&desc);
+	if (rc)
+		goto out;
+
+	rc = update_file_hash(dentry, file, nd, &desc);
+	if (!rc)
+		rc = crypto_hash_final(&desc, digest);
+out:
+	crypto_free_hash(desc.tfm);
+	return rc;
+}
+
+/*
+ * Calculate the hash of a given template
+ */
+int ima_calc_template_hash(int template_len, char *template, char *digest)
+{
+	struct hash_desc desc;
+	struct scatterlist sg[1];
+	int rc;
+
+	desc.tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(desc.tfm)) {
+		ima_info("failed to load %s transform: %ld\n",
+			 ima_hash, PTR_ERR(desc.tfm));
+		rc = PTR_ERR(desc.tfm);
+		return rc;
+	}
+	desc.flags = 0;
+	rc = crypto_hash_init(&desc);
+	if (rc)
+		goto out;
+
+	sg_set_buf(sg, template, template_len);
+	rc = crypto_hash_update(&desc, sg, template_len);
+	if (!rc)
+		rc = crypto_hash_final(&desc, digest);
+out:
+	crypto_free_hash(desc.tfm);
+	return rc;
+}
Index: linux-2.6.26-git3/security/integrity/ima/ima_fs.c
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/ima_fs.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Kylene Hall <kjhall@us.ibm.com>
+ * Reiner Sailer <sailer@us.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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_fs.c
+ *	implemenents security file system for reporting
+ *	current measurement list and IMA statistics
+ */
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/integrity.h>
+
+#include "ima.h"
+
+#define TMPBUFLEN 12
+static ssize_t ima_show_htable_value(char __user *buf, size_t count,
+				     loff_t *ppos, atomic_t *val)
+{
+	char tmpbuf[TMPBUFLEN];
+	ssize_t len;
+
+	len = scnprintf(tmpbuf, TMPBUFLEN, "%i\n", atomic_read(val));
+	return simple_read_from_buffer(buf, count, ppos, tmpbuf, len);
+}
+
+static ssize_t ima_show_htable_violations(struct file *filp,
+					  char __user *buf,
+					  size_t count, loff_t *ppos)
+{
+	return ima_show_htable_value(buf, count, ppos, &ima_htable.violations);
+}
+
+static struct file_operations ima_htable_violations_ops = {
+	.read = ima_show_htable_violations
+};
+
+static ssize_t ima_show_measurements_count(struct file *filp,
+					   char __user *buf,
+					   size_t count, loff_t *ppos)
+{
+	return ima_show_htable_value(buf, count, ppos, &ima_htable.len);
+
+}
+
+static struct file_operations ima_measurements_count_ops = {
+	.read = ima_show_measurements_count
+};
+
+/* returns pointer to hlist_node */
+static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
+{
+	struct list_head *lpos;
+	loff_t l = *pos;
+	/* we need a lock since pos could point beyond last element */
+	rcu_read_lock();
+	list_for_each_rcu(lpos, &ima_measurements) {
+		if (!l--) {
+			rcu_read_unlock();
+			return lpos;
+		}
+	}
+	rcu_read_unlock();
+	return NULL;
+}
+
+static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	/* lock protects when reading beyond last element
+	 * against concurrent list-extension */
+	struct list_head *lpos = (struct list_head *)v;
+
+	rcu_read_lock();
+	lpos = rcu_dereference(lpos->next);
+	rcu_read_unlock();
+	(*pos)++;
+
+	return (lpos == &ima_measurements) ? NULL : lpos;
+}
+
+static void ima_measurements_stop(struct seq_file *m, void *v)
+{
+}
+
+/* print format:
+ *       32bit-le=pcr#
+ *       char[20]=template digest
+ *       32bit-le=template size
+ *       32bit-le=template name size
+ *       eventdata[n] = template name
+ *
+ */
+static int ima_measurements_show(struct seq_file *m, void *v)
+{
+	/* the list never shrinks, so we don't need a lock here */
+	struct list_head *lpos = v;
+	struct ima_queue_entry *qe;
+	struct ima_measure_entry *e;
+	struct ima_inode_measure_entry *entry;
+	const struct template_operations *template_ops;
+	int templatename_len;
+	int i;
+	u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX;
+	char data[4];
+
+	/* get entry */
+	qe = list_entry(lpos, struct ima_queue_entry, later);
+	e = qe->entry;
+	if (e == NULL)
+		return -1;
+
+	/*
+	 * 1st: PCRIndex
+	 * PCR used is always the same (config option) in
+	 * little-endian format
+	 */
+	memcpy(data, &pcr, 4);
+	for (i = 0; i < 4; i++)
+		seq_putc(m, data[i]);
+
+	/* 2nd: template digest */
+	for (i = 0; i < 20; i++)
+		seq_putc(m, e->digest[i]);
+
+	/* 3rd: template name size */
+	templatename_len = strlen(e->template_name);
+	if (templatename_len > IMA_EVENT_NAME_LEN_MAX)
+		templatename_len = IMA_EVENT_NAME_LEN_MAX;
+
+	memcpy(data, &templatename_len, 4);
+	for (i = 0; i < 4; i++)
+		seq_putc(m, data[i]);
+
+	/* 4th:  template name  */
+	for (i = 0; i < templatename_len; i++)
+		seq_putc(m, e->template_name[i]);
+
+	/* 5th:  template dependent */
+	entry = (struct ima_inode_measure_entry *)e->template;
+	if (integrity_find_template(e->template_name, &template_ops) == 0)
+		template_ops->display_template(m, entry, INTEGRITY_SHOW_BINARY);
+	else
+		seq_printf(m, " \n");
+	return 0;
+}
+
+static struct seq_operations ima_measurments_seqops = {
+	.start = ima_measurements_start,
+	.next = ima_measurements_next,
+	.stop = ima_measurements_stop,
+	.show = ima_measurements_show
+};
+
+static int ima_measurements_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &ima_measurments_seqops);
+}
+
+static struct file_operations ima_measurements_ops = {
+	.open = ima_measurements_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+void ima_template_show(struct seq_file *m, void *e,
+		       enum integrity_show_type show)
+{
+	struct ima_inode_measure_entry *entry =
+	    (struct ima_inode_measure_entry *)e;
+	int filename_len;
+	char data[4];
+	int i;
+
+	/* Display file digest */
+	if (ima_template_mode)
+		for (i = 0; i < 20; i++) {
+			switch (show) {
+			case INTEGRITY_SHOW_ASCII:
+				seq_printf(m, "%02x", entry->digest[i]);
+				break;
+			case INTEGRITY_SHOW_BINARY:
+				seq_putc(m, entry->digest[i]);
+			default:
+				break;
+			}
+		}
+
+	switch (show) {
+	case INTEGRITY_SHOW_ASCII:
+		seq_printf(m, " %s\n", entry->file_name);
+		break;
+	case INTEGRITY_SHOW_BINARY:
+		filename_len = strlen(entry->file_name);
+		if (filename_len > IMA_EVENT_NAME_LEN_MAX)
+			filename_len = IMA_EVENT_NAME_LEN_MAX;
+
+		memcpy(data, &filename_len, 4);
+		for (i = 0; i < 4; i++)
+			seq_putc(m, data[i]);
+		for (i = 0; i < filename_len; i++)
+			seq_putc(m, entry->file_name[i]);
+	default:
+		break;
+	}
+}
+
+/* print in ascii */
+static int ima_ascii_measurements_show(struct seq_file *m, void *v)
+{
+	/* the list never shrinks, so we don't need a lock here */
+	struct list_head *lpos = v;
+	struct ima_queue_entry *qe;
+	struct ima_measure_entry *e;
+	struct ima_inode_measure_entry *entry;
+	const struct template_operations *template_ops;
+	int i;
+
+	/* get entry */
+	qe = list_entry(lpos, struct ima_queue_entry, later);
+	e = qe->entry;
+	if (e == NULL)
+		return -1;
+
+	/* 1st: PCR used (config option) */
+	seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX);
+
+	/* 2nd: SHA1 template hash */
+	for (i = 0; i < 20; i++)
+		seq_printf(m, "%02x", e->digest[i]);
+
+	/* 3th:  template name */
+	seq_printf(m, " %s ", e->template_name);
+
+	/* 4th:  filename <= max + \'0' delimiter */
+	entry = (struct ima_inode_measure_entry *)e->template;
+	if (integrity_find_template(e->template_name, &template_ops) == 0)
+		template_ops->display_template(m, entry, INTEGRITY_SHOW_ASCII);
+	else
+		seq_printf(m, " \n");
+
+	return 0;
+}
+
+static struct seq_operations ima_ascii_measurements_seqops = {
+	.start = ima_measurements_start,
+	.next = ima_measurements_next,
+	.stop = ima_measurements_stop,
+	.show = ima_ascii_measurements_show
+};
+
+static int ima_ascii_measurements_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &ima_ascii_measurements_seqops);
+}
+
+static struct file_operations ima_ascii_measurements_ops = {
+	.open = ima_ascii_measurements_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static char *get_tag(char *bufStart, char *bufEnd, char delimiter, int *taglen)
+{
+	char *bufp = bufStart;
+	char *tag;
+
+	/* Get start of tag */
+	while (bufp < bufEnd) {
+		if (*bufp == ' ')	/* skip blanks */
+			while ((*bufp == ' ') && (bufp++ < bufEnd)) ;
+		else if (*bufp == '#') {	/* skip comment */
+			while ((*bufp != '\n') && (bufp++ < bufEnd)) ;
+			bufp++;
+		} else if (*bufp == '\n')	/* skip newline */
+			bufp++;
+		else if (*bufp == '\t')	/* skip tabs */
+			bufp++;
+		else
+			break;
+	}
+	if (bufp < bufEnd)
+		tag = bufp;
+	else
+		return NULL;
+
+	/* Get tag */
+	*taglen = 0;
+	while ((bufp < bufEnd) && (*taglen == 0)) {
+		if ((*bufp == delimiter) || (*bufp == '\n')) {
+			*taglen = bufp - tag;
+			*bufp = '\0';
+		}
+		bufp++;
+	}
+	if (*taglen == 0)	/* Didn't find end delimiter */
+		tag = NULL;
+	return tag;
+}
+
+static ssize_t ima_write_policy(struct file *file, const char __user *buf,
+				size_t buflen, loff_t *ppos)
+{
+	size_t rc = 0, datalen;
+	int action = 0;
+	char *data, *datap, *dataend;
+	char *subj = NULL, *obj = NULL, *type = NULL;
+	char *func = NULL, *mask = NULL, *fsmagic = NULL;
+	int err = 0;
+	char *tag;
+	int taglen, i;
+
+	datalen = buflen > 4095 ? 4095 : buflen;
+	data = kmalloc(datalen + 1, GFP_KERNEL);
+	if (!data)
+		rc = -ENOMEM;
+
+	if (copy_from_user(data, buf, datalen)) {
+		kfree(data);
+		return -EFAULT;
+	}
+
+	rc = datalen;
+	*(data + datalen) = ' ';
+
+	datap = data;
+	dataend = data + datalen;
+
+	if (strncmp(datap, "measure", 7) == 0) {
+		datap += 8;
+		action = 1;
+	} else if (strncmp(datap, "dont_measure", 12) == 0)
+		datap += 13;
+	else			/* bad format */
+		goto out;
+
+	for (i = 0; i < 6; i++) {
+		tag = get_tag(datap, dataend, ' ', &taglen);
+		if (!tag)
+			break;
+		if (strncmp(tag, "obj=", 4) == 0)
+			obj = tag + 4;
+		else if (strncmp(tag, "subj=", 5) == 0)
+			subj = tag + 5;
+		else if (strncmp(tag, "type=", 5) == 0)
+			type = tag + 5;
+		else if (strncmp(tag, "func=", 5) == 0)
+			func = tag + 5;
+		else if (strncmp(tag, "mask=", 5) == 0)
+			mask = tag + 5;
+		else if (strncmp(tag, "fsmagic=", 8) == 0)
+			fsmagic = tag + 8;
+		else {		/* bad format */
+			err = 1;
+			break;
+		}
+		datap += taglen + 1;
+	}
+
+	if (!err) {
+		ima_info("%s %s %s %s %s %s %s\n",
+			 action ? "measure " : "dont_measure",
+			 subj, obj, type, func, mask, fsmagic);
+		ima_add_rule(action, subj, obj, type, func, mask, fsmagic);
+	}
+out:
+	if (!data)
+		kfree(data);
+	return rc;
+}
+
+static struct dentry *ima_dir;
+static struct dentry *binary_runtime_measurements;
+static struct dentry *ascii_runtime_measurements;
+static struct dentry *runtime_measurements_count;
+static struct dentry *violations;
+static struct dentry *ima_policy;
+
+static int ima_release_policy(struct inode *inode, struct file *file)
+{
+	ima_update_policy();
+	securityfs_remove(ima_policy);
+	ima_policy = NULL;
+	return 0;
+}
+
+static struct file_operations ima_measure_policy_ops = {
+	.write = ima_write_policy,
+	.release = ima_release_policy
+};
+
+int ima_fs_init(void)
+{
+	ima_dir = securityfs_create_dir("ima", NULL);
+	if (!ima_dir || IS_ERR(ima_dir))
+		return -1;
+
+	binary_runtime_measurements =
+	    securityfs_create_file("binary_runtime_measurements",
+				   S_IRUSR | S_IRGRP, ima_dir, NULL,
+				   &ima_measurements_ops);
+	if (!binary_runtime_measurements || IS_ERR(binary_runtime_measurements))
+		goto out;
+
+	ascii_runtime_measurements =
+	    securityfs_create_file("ascii_runtime_measurements",
+				   S_IRUSR | S_IRGRP, ima_dir, NULL,
+				   &ima_ascii_measurements_ops);
+	if (!ascii_runtime_measurements || IS_ERR(ascii_runtime_measurements))
+		goto out;
+
+	runtime_measurements_count =
+	    securityfs_create_file("runtime_measurements_count",
+				   S_IRUSR | S_IRGRP, ima_dir, NULL,
+				   &ima_measurements_count_ops);
+	if (!runtime_measurements_count || IS_ERR(runtime_measurements_count))
+		goto out;
+
+	violations =
+	    securityfs_create_file("violations", S_IRUSR | S_IRGRP,
+				   ima_dir, NULL, &ima_htable_violations_ops);
+	if (!violations || IS_ERR(violations))
+		goto out;
+
+	ima_policy = securityfs_create_file("policy",
+					    S_IRUSR | S_IRGRP | S_IWUSR,
+					    ima_dir, NULL,
+					    &ima_measure_policy_ops);
+	ima_init_policy();
+	return 0;
+
+out:
+	securityfs_remove(runtime_measurements_count);
+	securityfs_remove(ascii_runtime_measurements);
+	securityfs_remove(binary_runtime_measurements);
+	securityfs_remove(ima_dir);
+	securityfs_remove(ima_policy);
+	return -1;
+}
+
+void __exit ima_fs_cleanup(void)
+{
+	securityfs_remove(violations);
+	securityfs_remove(runtime_measurements_count);
+	securityfs_remove(ascii_runtime_measurements);
+	securityfs_remove(binary_runtime_measurements);
+	securityfs_remove(ima_dir);
+	securityfs_remove(ima_policy);
+}
Index: linux-2.6.26-git3/security/integrity/ima/ima_queue.c
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/ima_queue.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Serge Hallyn <serue@us.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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_queue.c
+ *       implements queues that store IMA measurements and
+ *       maintains aggregate over the stored measurements
+ *       in the pre-configured TPM PCR (if available)
+ *       The measurement list is append-only. No entry is
+ *       ever removed or changed during the boot-cycle.
+ */
+#include <linux/module.h>
+
+#include "ima.h"
+
+struct list_head ima_measurements;	/* list of all measurements */
+struct ima_h_table ima_htable;	/* key: inode (before secure-hashing a file) */
+
+/* mutex protects atomicity of extending measurement list
+ * and extending the TPM PCR aggregate. Since tpm_extend can take
+ * long (and the tpm driver uses a mutex), we can't use the spinlock.
+ */
+static DEFINE_MUTEX(ima_extend_list_mutex);
+
+void ima_create_htable(void)
+{
+	int i;
+
+	INIT_LIST_HEAD(&ima_measurements);
+	atomic_set(&ima_htable.len, 0);
+	atomic_set(&ima_htable.violations, 0);
+	ima_htable.max_htable_size = IMA_MEASURE_HTABLE_SIZE;
+
+	for (i = 0; i < ima_htable.max_htable_size; i++) {
+		INIT_HLIST_HEAD(&ima_htable.queue[i]);
+		atomic_set(&ima_htable.queue_len[i], 0);
+	}
+}
+
+struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value)
+{
+	struct ima_queue_entry *qe, *ret = NULL;
+	unsigned int key;
+	struct hlist_node *pos;
+
+	key = IMA_HASH_KEY(digest_value);
+	rcu_read_lock();
+	hlist_for_each_entry_rcu(qe, pos, &ima_htable.queue[key], hnext) {
+		if (memcmp(qe->entry->digest, digest_value, 20) == 0) {
+			ret = qe;
+			break;
+		}
+	}
+	rcu_read_unlock();
+	return ret;
+}
+
+/* Called with mutex held */
+static int ima_add_digest_entry(struct ima_measure_entry *entry)
+{
+	struct ima_queue_entry *qe;
+	unsigned int key;
+
+	key = IMA_HASH_KEY(entry->digest);
+	qe = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (qe == NULL) {
+		ima_error("OUT OF MEMORY ERROR creating queue entry.\n");
+		return -ENOMEM;
+	}
+	qe->entry = entry;
+
+	hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]);
+	atomic_inc(&ima_htable.queue_len[key]);
+	return 0;
+}
+
+int ima_add_measure_entry(struct ima_measure_entry *entry, int violation)
+{
+	struct ima_queue_entry *qe;
+	int error = 0;
+
+	mutex_lock(&ima_extend_list_mutex);
+	if (!violation) {
+		if (ima_lookup_digest_entry(entry->digest)) {
+			error = -EEXIST;
+			goto out;
+		}
+	}
+	qe = kmalloc(sizeof(struct ima_queue_entry), GFP_KERNEL);
+	if (qe == NULL) {
+		ima_error("OUT OF MEMORY in %s.\n", __func__);
+		error = -ENOMEM;
+		goto out;
+	}
+	qe->entry = entry;
+
+	INIT_LIST_HEAD(&qe->later);
+	list_add_tail_rcu(&qe->later, &ima_measurements);
+
+	atomic_inc(&ima_htable.len);
+	if (ima_add_digest_entry(entry)) {
+		error = -ENOMEM;
+		goto out;
+	}
+	if (violation) {	/* Replace 0x00 with 0xFF */
+		u8 digest[IMA_DIGEST_SIZE];
+
+		memset(digest, 0xff, sizeof digest);
+		ima_extend(digest);
+	} else
+		ima_extend(entry->digest);
+out:
+	mutex_unlock(&ima_extend_list_mutex);
+	return error;
+}
Index: linux-2.6.26-git3/security/integrity/ima/ima_policy.c
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/ima_policy.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * ima_policy.c
+ * 	- initialize default measure policy rules
+	- load a policy ruleset
+ *
+ */
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/audit.h>
+#include <linux/security.h>
+#include <linux/integrity.h>
+#include <linux/magic.h>
+
+#include "ima.h"
+
+#define security_filter_rule_init security_audit_rule_init
+#define security_filter_rule_match security_audit_rule_match
+
+struct ima_measure_rule_entry {
+	struct list_head list;
+	int action;
+	void *lsm_obj_rule;
+	void *lsm_subj_rule;
+	void *lsm_type_rule;
+	enum lim_hooks func;
+	int mask;
+	ulong fsmagic;
+};
+
+/* Without LSM specific knowledge, default policy can only
+ * be written in terms of .action, .func, .mask and .fsmagic.
+ */
+static struct ima_measure_rule_entry default_rules[] = {
+	{.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC},
+	{.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC},
+	{.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC},
+	{.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC},
+	{.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC},
+	{.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC},
+	{.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC},
+	{.action = MEASURE,.func = INODE_PERMISSION,.mask = MAY_READ},
+};
+
+static struct list_head measure_default_rules;
+static struct list_head measure_policy_rules;
+static struct list_head *ima_measure;
+
+static DEFINE_MUTEX(ima_measure_mutex);
+
+/**
+ * ima_match_rules - determine whether an inode matches the measure rule.
+ * @rule: a pointer to a rule
+ * @inode: a pointer to an inode
+ * @func: LIM hook identifier
+ * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ *
+ * Returns true on rule match, false on failure.
+ */
+static bool ima_match_rules(struct ima_measure_rule_entry *rule,
+			   struct inode *inode, enum lim_hooks func, int mask)
+{
+	if (rule->func && rule->func != func)
+		return false;
+	if (rule->mask && rule->mask != mask)
+		return false;
+	if (rule->fsmagic && rule->fsmagic != inode->i_sb->s_magic)
+		return false;
+	if (rule->lsm_subj_rule) {
+		struct task_struct *tsk = current;
+		u32 sid;
+		int rc;
+
+		security_task_getsecid(tsk, &sid);
+		rc = security_filter_rule_match(sid, AUDIT_SUBJ_USER,
+						AUDIT_EQUAL,
+						rule->lsm_subj_rule, NULL);
+		if (!rc)
+			return false;
+	}
+	if (rule->lsm_obj_rule) {
+		u32 osid;
+		int rc;
+
+		security_inode_getsecid(inode, &osid);
+		rc = security_filter_rule_match(osid, AUDIT_OBJ_USER,
+						AUDIT_EQUAL,
+						rule->lsm_obj_rule, NULL);
+		if (!rc)
+			return false;
+	}
+	if (rule->lsm_type_rule) {
+		u32 osid;
+		int rc;
+
+		security_inode_getsecid(inode, &osid);
+		rc = security_filter_rule_match(osid, AUDIT_OBJ_TYPE,
+						AUDIT_EQUAL,
+						rule->lsm_type_rule, NULL);
+		if (!rc)
+			return false;
+	}
+	return true;
+}
+
+/**
+ * ima_match_policy - decision based on LSM and other conditions
+ * @inode: pointer to an inode
+ * @func: IMA hook identifier
+ * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ *
+ * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
+ * conditions. Returns rule action on rule match, 0 on failure.
+ */
+int ima_match_policy(struct inode *inode, enum lim_hooks func, int mask)
+{
+	struct ima_measure_rule_entry *entry;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(entry, ima_measure, list) {
+		bool rc;
+
+		rc = ima_match_rules(entry, inode, func, mask);
+		if (rc) {
+			rcu_read_unlock();
+			return entry->action;
+		}
+	}
+	rcu_read_unlock();
+	return 0;
+}
+
+/**
+ * ima_init_policy - initialize the default and policy measure rules.
+ */
+void ima_init_policy(void)
+{
+	int i;
+
+	INIT_LIST_HEAD(&measure_default_rules);
+	for (i = 0; i < ARRAY_SIZE(default_rules); i++)
+		list_add_tail(&default_rules[i].list, &measure_default_rules);
+	ima_measure = &measure_default_rules;
+
+	INIT_LIST_HEAD(&measure_policy_rules);
+}
+
+/**
+ * ima_update_policy - update default_rules with new measure rules
+ *
+ * Wait to update the default rules with a complete new set of measure rules.
+ */
+void ima_update_policy(void)
+{
+	char *op = "policy_update";
+	char *cause = "already exists";
+	int result = 1;
+
+	if (ima_measure == &measure_default_rules) {
+		ima_measure = &measure_policy_rules;
+		cause = "complete";
+		result = 0;
+	}
+	integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
+			    NULL, op, cause, result);
+}
+
+/**
+ * ima_add_rule - add ima measure rules
+ * @action: integer 1 indicating MEASURE, 0 indicating DONT_MEASURE
+ * @subj: pointer to an LSM subject value
+ * @obj:  pointer to an LSM object value
+ * @type:  pointer to an LSM object type value
+ * @func: LIM hook identifier
+ * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ * @fsmagic: fs magic hex value string
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int ima_add_rule(int action, char *subj, char *obj, char *type,
+		 char *func, char *mask, char *fsmagic)
+{
+	struct ima_measure_rule_entry *entry;
+	int result = 0;
+
+	/* Prevent installed policy from changing */
+	if (ima_measure != &measure_default_rules) {
+		integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
+				    NULL, "policy_update", "already exists", 1);
+		return -EACCES;
+	}
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	INIT_LIST_HEAD(&entry->list);
+	if (action < 0 || action > 1)
+		result = -EINVAL;
+	else
+		entry->action = action;
+	if (!result && subj)
+		result = security_filter_rule_init(AUDIT_SUBJ_USER, AUDIT_EQUAL,
+						   subj, &entry->lsm_subj_rule);
+	if (!result && obj)
+		result = security_filter_rule_init(AUDIT_OBJ_USER, AUDIT_EQUAL,
+						   obj, &entry->lsm_obj_rule);
+	if (!result && type)
+		result = security_filter_rule_init(AUDIT_OBJ_TYPE, AUDIT_EQUAL,
+						   obj, &entry->lsm_obj_rule);
+	if (!result && func) {
+		if (strcmp(func, "INODE_PERMISSION") == 0)
+			entry->func = INODE_PERMISSION;
+		else if (strcmp(func, "FILE_MMAP") == 0)
+			entry->func = FILE_MMAP;
+		else if (strcmp(func, "BPRM_CHECK") == 0)
+			entry->func = BPRM_CHECK;
+		else
+			result = -EINVAL;
+	}
+	if (!result && mask) {
+		if (strcmp(mask, "MAY_EXEC") == 0)
+			entry->mask = MAY_EXEC;
+		else if (strcmp(mask, "MAY_WRITE") == 0)
+			entry->mask = MAY_WRITE;
+		else if (strcmp(mask, "MAY_READ") == 0)
+			entry->mask = MAY_READ;
+		else if (strcmp(mask, "MAY_APPEND") == 0)
+			entry->mask = MAY_APPEND;
+		else
+			result = -EINVAL;
+	}
+	if (!result && fsmagic) {
+		int rc;
+
+		rc = strict_strtoul(fsmagic, 16, &entry->fsmagic);
+		if (rc)
+			result = -EINVAL;
+	}
+	if (!result) {
+		mutex_lock(&ima_measure_mutex);
+		list_add_tail(&entry->list, &measure_policy_rules);
+		mutex_unlock(&ima_measure_mutex);
+	}
+	return result;
+}
Index: linux-2.6.26-git3/Documentation/kernel-parameters.txt
===================================================================
--- linux-2.6.26-git3.orig/Documentation/kernel-parameters.txt
+++ linux-2.6.26-git3/Documentation/kernel-parameters.txt
@@ -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.
@@ -838,6 +839,10 @@ and is between 256 and 4096 characters. 
 	ihash_entries=	[KNL]
 			Set number of hash buckets for inode cache.
 
+	ima_hash=	[IMA] runtime ability to define hash crypto alg.
+			Format: { "MD5" | "SHA1" }
+			Default is "SHA1".
+
 	in2000=		[HW,SCSI]
 			See header of drivers/scsi/in2000.c.
 
Index: linux-2.6.26-git3/include/linux/ima.h
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/include/linux/ima.h
@@ -0,0 +1,48 @@
+/*
+ * ima.h
+ *
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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.
+ */
+
+#ifndef _LINUX_IMA_H
+#define _LINUX_IMA_H
+
+/* IMA LIM Data */
+enum ima_type { IMA_DATA, IMA_METADATA, IMA_TEMPLATE };
+
+struct ima_args_data {
+	const char	*filename;
+	struct inode 	*inode;
+	struct dentry 	*dentry;
+	struct nameidata 	*nd;
+	struct file 	*file;
+	enum lim_hooks	function;
+	u32		osid;
+	int 		mask;
+};
+
+struct ima_store_data {
+	char 		*name;
+	int 		len;
+	char 		*data;
+	int  		violation;
+};
+
+struct ima_data {
+	enum ima_type 	type;
+	union {
+		struct ima_args_data 	args;
+		struct ima_store_data	template;
+	} data;
+};
+
+void ima_fixup_argsdata(struct ima_args_data *data,
+			struct inode *inode, struct dentry *dentry,
+			struct file *file, struct nameidata *nd, int mask,
+			int function);
+#endif
Index: linux-2.6.26-git3/security/integrity/Makefile
===================================================================
--- linux-2.6.26-git3.orig/security/integrity/Makefile
+++ linux-2.6.26-git3/security/integrity/Makefile
@@ -4,3 +4,5 @@
 
 # Object file lists
 obj-$(CONFIG_INTEGRITY)			+= integrity.o integrity_audit.o
+
+obj-$(CONFIG_IMA)			+= ima/
Index: linux-2.6.26-git3/security/integrity/Kconfig
===================================================================
--- linux-2.6.26-git3.orig/security/integrity/Kconfig
+++ linux-2.6.26-git3/security/integrity/Kconfig
@@ -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



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Patch 5/5]integrity: IMA as an integrity service provider
  2008-07-16 20:05     ` [Patch 5/5]integrity: IMA as an integrity service provider Mimi Zohar
@ 2008-07-16 23:56       ` James Morris
  2008-07-17 21:54         ` Mimi Zohar
  0 siblings, 1 reply; 20+ messages in thread
From: James Morris @ 2008-07-16 23:56 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: linux-kernel, akpm, safford, serue, sailer, zohar, debora, srajiv

On Wed, 16 Jul 2008, Mimi Zohar wrote:


> +static ssize_t ima_show_htable_value(char __user *buf, size_t count,
> +				     loff_t *ppos, atomic_t *val)
> +{
> +	char tmpbuf[TMPBUFLEN];
> +	ssize_t len;
> +
> +	len = scnprintf(tmpbuf, TMPBUFLEN, "%i\n", atomic_read(val));
> +	return simple_read_from_buffer(buf, count, ppos, tmpbuf, len);
> +}
> +
> +static ssize_t ima_show_htable_violations(struct file *filp,
> +					  char __user *buf,
> +					  size_t count, loff_t *ppos)
> +{
> +	return ima_show_htable_value(buf, count, ppos, &ima_htable.violations);
> +}


ima_htable.violations is an atomic_long_t and is not safe to pass 
to ima_show_htable_value.  Did you check for compilation warnings?

> +void ima_add_violation(struct inode *inode, const unsigned char *fname,
> +                      char *op, char *cause)
> +{
> +       int result;
> +
> +       /* can overflow, only indicator */
> +       atomic_inc(&ima_htable.violations);

This also generates a warning.  You probably want atomic_long_inc().


- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Patch 5/5]integrity: IMA as an integrity service provider
  2008-07-16 23:56       ` James Morris
@ 2008-07-17 21:54         ` Mimi Zohar
  2008-07-22 15:08           ` James Morris
  0 siblings, 1 reply; 20+ messages in thread
From: Mimi Zohar @ 2008-07-17 21:54 UTC (permalink / raw)
  To: James Morris
  Cc: linux-kernel, akpm, safford, serue, sailer, zohar, debora, srajiv

On Thu, 2008-07-17 at 09:56 +1000, James Morris wrote: 
> On Wed, 16 Jul 2008, Mimi Zohar wrote:
> > +static ssize_t ima_show_htable_value(char __user *buf, size_t count,
> > +				     loff_t *ppos, atomic_t *val)
> > +{
> > +	char tmpbuf[TMPBUFLEN];
> > +	ssize_t len;
> > +
> > +	len = scnprintf(tmpbuf, TMPBUFLEN, "%i\n", atomic_read(val));
> > +	return simple_read_from_buffer(buf, count, ppos, tmpbuf, len);
> > +}
> > +
> > +static ssize_t ima_show_htable_violations(struct file *filp,
> > +					  char __user *buf,
> > +					  size_t count, loff_t *ppos)
> > +{
> > +	return ima_show_htable_value(buf, count, ppos, &ima_htable.violations);
> > +}
> 
> 
> ima_htable.violations is an atomic_long_t and is not safe to pass 
> to ima_show_htable_value.  Did you check for compilation warnings?

On a 32-bit x86, I'm not getting any warnings. I've compiled the code 
with both Sparse and EXTRA_CFLAGS=-W.  

Below is an updated version of the patch with the corrections.

> > +void ima_add_violation(struct inode *inode, const unsigned char *fname,
> > +                      char *op, char *cause)
> > +{
> > +       int result;
> > +
> > +       /* can overflow, only indicator */
> > +       atomic_inc(&ima_htable.violations);
> 
> This also generates a warning.  You probably want atomic_long_inc().

[Patch 5/5]integrity: IMA as an integrity service provider

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

This version addresses a number of issues discussed on LKML, including:
- Corrects the atomic_long_t variable usage, to use the appropriate 
  atomic_long calls.
- Added Documentation/ABI/testing/ima_policy which describes loading
  the IMA measurement policy.
- Added policy support for magic numbers and removed them from
  skip_measurement().
- Added policy support for LSM obj_type.
- Replaced using .i_mtime to detect when a file has been modified
  with .i_version. This requires the filesystem to be mounted with
  iversion.  (Requires iversion mount support.)
- Added const for integrity_template_operations.
- Removed integrity_fixup_ops(), to make integrity_operations const too.
- Removed ima_fixup_inodes() by registering the integrity_ops early in
  security_initcall(), but waiting to start IMA in late_initcall(), until
  after the TPM is available.
- Removed CONFIG_IMA_BOOTPARAM and CONFIG_IMA_BOOTPARAM_VALUE.
- Replaced,as appropriate, all GFP_ATOMICs with GFP_KERNEL.

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. 

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
---
Index: linux-2.6.26-git3/Documentation/ABI/testing/ima_policy
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/Documentation/ABI/testing/ima_policy
@@ -0,0 +1,55 @@
+What:		security/ima/policy
+Date:		May 2008
+Contact:	Mimi Zohar <zohar@us.ibm.com>
+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=]]
+			lsm:	[[subj=] [obj=] [type=]]
+
+		base: 	func:= [BPRM_CHECK][FILE_MMAP][INODE_PERMISSION]
+			mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
+			fsmagic:= hex 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
+
+		The default policy measures all executables in bprm_check,
+		all files mmapped executable in file_mmap, and all files
+		open for read in inode_permission.
+
+		Examples of LSM specific definitions:
+
+		SELinux:
+			dont_measure type=var_log_t
+			dont_measure type=auditd_log_t
+			measure subj=system_u func=INODE_PERM mask=MAY_READ
+
+		Smack:
+			measure subj=_ func=INODE_PERM mask=MAY_READ
Index: linux-2.6.26-git3/security/integrity/ima/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/Kconfig
@@ -0,0 +1,41 @@
+#
+# IBM Integrity Measurement Architecture
+#
+
+config IMA
+	bool "Integrity Measurement Architecture(IMA)"
+	depends on INTEGRITY
+	depends on ACPI
+	select CRYPTO
+	select CRYPTO_HMAC
+	select CRYPTO_MD5
+	select CRYPTO_SHA1
+	select TCG_TPM
+	select TCG_TIS
+	help
+	  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.  If your system
+	  has a TPM chip, then IMA also maintains an aggregate
+	  integrity value over this list inside the TPM hardware.
+	  These measurements and the aggregate (signed inside the
+	  TPM) can be retrieved and presented to remote parties to
+	  establish system properties. If unsure, say N.
+
+config IMA_MEASURE_PCR_IDX
+	int "PCR for Aggregate (8<= Index <= 14)"
+	depends on IMA
+	range 8 14
+	default 10
+	help
+	  IMA_MEASURE_PCR_IDX determines the TPM PCR register index
+	  that IMA uses to maintain the integrity aggregate of the
+	  measurement list.  If unsure, use the default 10.
+
+config IMA_BASE_HOOKS
+	bool "IMA base hooks"
+	depends on IMA
+	default n
+	help
+	  Enable this option to allow the LSM module to enforce integrity.
Index: linux-2.6.26-git3/security/integrity/ima/Makefile
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/Makefile
@@ -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
Index: linux-2.6.26-git3/security/integrity/ima/ima_main.c
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/ima_main.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Serge Hallyn <serue@us.ibm.com>
+ * Kylene Hall <kylene@us.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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_main.c
+ *             implements the IMA LIM hooks
+ */
+#include <linux/module.h>
+#include <linux/integrity.h>
+#include <linux/magic.h>
+#include <linux/writeback.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/audit.h>
+#include <linux/ima.h>
+#include <linux/mman.h>
+
+#include "ima.h"
+
+static bool ima_initialized = false;
+char *ima_hash = "sha1";
+static int __init hash_setup(char *str)
+{
+	char *op = "setup";
+	char *hash = "sha1";
+
+	if (strncmp(str, "md5", 3) == 0) {
+		op = "setup";
+		hash = "md5";
+		ima_hash = str;
+	} else if (strncmp(str, "sha1", 4) != 0) {
+		op = "hash_setup";
+		hash = "invalid_hash_type";
+	}
+	integrity_audit_msg(AUDIT_INTEGRITY_HASH, NULL, NULL, op, hash, 0);
+	return 1;
+}
+
+__setup("ima_hash=", hash_setup);
+
+/* For use when the LSM module makes LIM API calls */
+#ifdef CONFIG_IMA_BASE_HOOKS
+static int ima_base_hooks = 1;
+#else
+static int ima_base_hooks;
+#endif
+
+/*
+ * Setup the data structure used for the IMA LIM API calls.
+ */
+void ima_fixup_argsdata(struct ima_args_data *data,
+			struct inode *inode, struct dentry *dentry,
+			struct file *file, struct nameidata *nd, int mask,
+			int function)
+{
+	data->inode = inode;
+	data->dentry = dentry;
+	data->file = file;
+	data->nd = nd;
+	data->mask = mask;
+	data->function = function;
+
+	if (file && file->f_dentry) {
+		if (!dentry)
+			data->dentry = dentry = file->f_dentry;
+	}
+	if (nd && nd->path.dentry) {
+		if (!dentry)
+			data->dentry = dentry = nd->path.dentry;
+	}
+	if (dentry && dentry->d_inode) {
+		if (!inode)
+			data->inode = inode = dentry->d_inode;
+	}
+
+	return;
+}
+
+/**
+ * ima_file_free - called on close
+ * @file: pointer to file being closed
+ *
+ * Flag files that changed, based on i_version.
+ */
+static void ima_file_free(struct file *file)
+{
+	struct inode *inode = NULL;
+	struct ima_iint_cache *iint;
+
+	if (!file->f_dentry)	/* can be NULL */
+		return;
+
+	inode = file->f_dentry->d_inode;
+	if (S_ISDIR(inode->i_mode))
+		return;
+	if ((file->f_mode & FMODE_WRITE) &&
+	    (atomic_read(&inode->i_writecount) == 1)) {
+		iint = inode->i_integrity;
+		mutex_lock(&iint->mutex);
+		if (iint->version != inode->i_version)
+			iint->measured = 0;
+		mutex_unlock(&iint->mutex);
+	}
+}
+
+/**
+ * ima_alloc_integrity - allocate and attach an integrity structure
+ * @inode: the inode structure
+ *
+ * Returns 0 on success, -ENOMEM on failure
+ */
+static int ima_inode_alloc_integrity(struct inode *inode)
+{
+	struct ima_iint_cache *iint;
+
+	iint = kzalloc(sizeof(*iint), GFP_KERNEL);
+	if (!iint)
+		return -ENOMEM;
+
+	mutex_init(&iint->mutex);
+	inode->i_integrity = iint;
+	iint->version = inode->i_version;
+	return 0;
+}
+
+/**
+ * ima_inode_free_integrity - free the integrity structure
+ * @inode: the inode structure
+ */
+static void ima_inode_free_integrity(struct inode *inode)
+{
+	struct ima_iint_cache *iint = inode->i_integrity;
+
+	if (iint) {
+		inode->i_integrity = NULL;
+		kfree(iint);
+	}
+}
+
+/**
+ * ima_inode_permission - based on policy, collect/store measurement.
+ * @inode: pointer to the inode to be measured
+ * @mask: contains MAY_READ, MAY_WRITE, MAY_APPEND or MAY_EXECUTE
+ * @nd: pointer to a nameidata
+ *
+ * Measure the file associated with the inode, if the
+ * file is open for read and the results of the call to
+ * ima_must_measure() require the file to be measured.
+ *
+ * Invalidate the PCR:
+ * 	- Opening a file for write when already open for read,
+ *	  results in a time of measure, time of use (ToMToU) error.
+ *	- Opening a file for read when already open for write,
+ * 	  could result in a file measurement error.
+ *
+ * Return 0 on success, an error code on failure.
+ * (Based on the results of appraise_measurement().)
+ */
+static int ima_inode_permission(struct inode *inode, int mask,
+				struct nameidata *nd)
+{
+	struct ima_data idata;
+	struct ima_args_data *data = &idata.data.args;
+
+	if (!ima_initialized)
+		return 0;
+
+	memset(&idata, 0, sizeof idata);
+	ima_fixup_argsdata(data, inode, NULL, NULL, nd, mask, INODE_PERMISSION);
+
+	/* The file name is not required, but only a hint. */
+	if (nd)
+		data->filename = (!nd->path.dentry->d_name.name) ?
+		    (char *)nd->path.dentry->d_iname :
+		    (char *)nd->path.dentry->d_name.name;
+
+	/* Invalidate PCR, if a measured file is already open for read */
+	if ((mask == MAY_WRITE) || (mask == MAY_APPEND)) {
+		int mask_sav = data->mask;
+		int rc;
+
+		data->mask = MAY_READ;
+		rc = ima_must_measure(&idata);
+		if (!rc) {
+			if (atomic_read(&(data->dentry->d_count)) - 1 >
+			    atomic_read(&(inode->i_writecount)))
+				ima_add_violation(inode, data->filename,
+						  "invalid_pcr", "ToMToU");
+		}
+		data->mask = mask_sav;
+		goto out;
+	}
+
+	/* measure executables later */
+	if (mask & MAY_READ) {
+		int rc;
+
+		rc = ima_must_measure(&idata);
+		if (!rc) {
+			/* Invalidate PCR, if a measured file is
+			 * already open for write.
+			 */
+			if (atomic_read(&(inode->i_writecount)) > 0)
+				ima_add_violation(inode, data->filename,
+						  "invalid_pcr",
+						  "open_writers");
+
+			idata.type = IMA_DATA;
+			rc = ima_collect_measurement(&idata);
+			if (!rc)
+				ima_store_measurement(&idata);
+		}
+	}
+out:
+	return 0;
+}
+
+/**
+ * ima_file_mmap - based on policy, collect/store measurement.
+ * @inode: pointer to the inode to be measured
+ * @mask: contains MAY_READ, MAY_WRITE, MAY_APPEND or MAY_EXECUTE
+ * @nd: pointer to a nameidata
+ *
+ * Measure files being mmapped executable based on the ima_must_measure()
+ * policy decision.
+ *
+ * Return 0 on success, an error code on failure.
+ * (Based on the results of appraise_measurement().)
+ */
+static int ima_file_mmap(struct file *file, unsigned long reqprot,
+			 unsigned long prot, unsigned long flags,
+			 unsigned long addr, unsigned long addr_only)
+{
+	struct ima_data idata;
+	struct ima_args_data *data = &idata.data.args;
+	int rc = 0;
+
+	if (!ima_initialized)
+		return 0;
+	if (!file || !file->f_dentry)
+		return rc;
+	if (!(prot & VM_EXEC))
+		return rc;
+
+	ima_fixup_argsdata(data, NULL, NULL, file, NULL, MAY_EXEC, FILE_MMAP);
+	data->filename = (file->f_dentry->d_name.name) ?
+	    (char *)file->f_dentry->d_iname :
+	    (char *)file->f_dentry->d_name.name;
+
+	rc = ima_must_measure(&idata);
+	if (!rc) {
+		idata.type = IMA_DATA;
+		rc = ima_collect_measurement(&idata);
+		if (!rc)
+			ima_store_measurement(&idata);
+	}
+	return 0;
+}
+
+/**
+ * ima_bprm_check_integrity - based on policy, collect/store measurement.
+ * @bprm: contains the linux_binprm structure
+ *
+ * The OS protects against an executable file, already open for write,
+ * from being executed in deny_write_access() and an executable file,
+ * already open for execute, from being modified in get_write_access().
+ * So we can be certain that what we verify and measure here is actually
+ * what is being executed.
+ *
+ * Return 0 on success, an error code on failure.
+ * (Based on the results of appraise_measurement().)
+ */
+static int ima_bprm_check_integrity(struct linux_binprm *bprm)
+{
+	struct ima_data idata;
+	struct ima_args_data *data = &idata.data.args;
+	int rc = 0;
+
+	if (!ima_initialized)
+		return 0;
+	ima_fixup_argsdata(data, NULL, NULL, bprm->file, NULL, MAY_EXEC,
+			   BPRM_CHECK);
+	data->filename = bprm->filename;
+
+	rc = ima_must_measure(&idata);
+	if (!rc) {
+		idata.type = IMA_DATA;
+		rc = ima_collect_measurement(&idata);
+		if (!rc)
+			ima_store_measurement(&idata);
+	}
+	return 0;
+}
+
+static const struct integrity_operations ima_integrity_ops = {
+	.bprm_check_integrity = ima_bprm_check_integrity,
+	.inode_permission = ima_inode_permission,
+	.inode_alloc_integrity = ima_inode_alloc_integrity,
+	.inode_free_integrity = ima_inode_free_integrity,
+	.file_free_integrity = ima_file_free,
+	.file_mmap = ima_file_mmap,
+};
+
+static const struct integrity_operations ima_base_ops = {
+	.inode_alloc_integrity = ima_inode_alloc_integrity,
+	.inode_free_integrity = ima_inode_free_integrity,
+	.file_free_integrity = ima_file_free,
+};
+
+/* Register the integrity ops early so that i_integrity is
+ * allocated at inode initialization.
+ */
+static int __init init_ops(void)
+{
+	int error;
+
+	if (ima_base_hooks)
+		error = register_integrity(&ima_base_ops);
+	else
+		error = register_integrity(&ima_integrity_ops);
+	return error;
+}
+
+/* After the TPM is available, start IMA
+ */
+static int __init init_ima(void)
+{
+	int error;
+
+	error = ima_init();
+	if (error)
+		goto out;
+	ima_initialized = true;
+	integrity_register_template("ima", &ima_template_ops);
+out:
+	return error;
+}
+
+static void __exit cleanup_ima(void)
+{
+	integrity_unregister_template("ima");
+	unregister_integrity(&ima_integrity_ops);
+	ima_cleanup();
+}
+
+security_initcall(init_ops);	/* Register the integrity ops early */
+late_initcall(init_ima);	/* Start IMA after the TPM is available */
+module_exit(cleanup_ima);
+
+MODULE_DESCRIPTION("Integrity Measurement Architecture");
+MODULE_LICENSE("GPL");
Index: linux-2.6.26-git3/security/integrity/ima/ima_init.c
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/ima_init.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer      <sailer@watson.ibm.com>
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Mimi Zohar         <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima_init.c
+ *             initialization and cleanup functions
+ */
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include "ima.h"
+
+/* name for boot aggregate entry */
+static char *boot_aggregate_name = "boot_aggregate";
+static const char version[] = "v7.6 02/27/2007";
+
+int ima_used_chip;
+
+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);
+	if (entry == NULL) {
+		ima_add_violation(NULL, boot_aggregate_name,
+				  "add_measure", "ENOMEM");
+		return;
+	}
+	count = strlen(boot_aggregate_name);
+	if (count > IMA_EVENT_NAME_LEN_MAX)
+		count = IMA_EVENT_NAME_LEN_MAX;
+	memcpy(entry->template_name, boot_aggregate_name, count);
+	entry->template_name[count] = '\0';
+	if (ima_used_chip) {
+		int i;
+		u8 pcr_i[20];
+		struct hash_desc desc;
+		struct crypto_hash *tfm;
+		struct scatterlist sg;
+
+		tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
+		if (!tfm || IS_ERR(tfm)) {
+			kfree(entry);
+			ima_error("error initializing digest.\n");
+			return;
+		}
+		desc.tfm = tfm;
+		desc.flags = 0;
+		crypto_hash_init(&desc);
+
+		for (i = 0; i < 8; i++) {
+			ima_pcrread(i, pcr_i, sizeof(pcr_i));
+			/* now accumulate with current aggregate */
+			sg_init_one(&sg, (u8 *) pcr_i, 20);
+			crypto_hash_update(&desc, &sg, 20);
+		}
+		crypto_hash_final(&desc, entry->digest);
+		crypto_free_hash(tfm);
+	} else
+		memset(entry->digest, 0xff, 20);
+
+	/* now add measurement; if TPM bypassed, we have a ff..ff entry */
+	err = ima_add_measure_entry(entry, 0);
+	if (err < 0) {
+		kfree(entry);
+		ima_add_violation(NULL, boot_aggregate_name,
+				  "add_measure", " ");
+	}
+}
+
+int ima_init(void)
+{
+	int rc;
+
+	ima_used_chip = 0;
+	rc = tpm_pcr_read(IMA_TPM, 0, NULL);
+	if (rc == 0)
+		ima_used_chip = 1;
+
+	if (!ima_used_chip)
+		ima_info("No TPM chip found(rc = %d), activating TPM-bypass!\n",
+			 rc);
+
+	ima_create_htable();	/* for measurements */
+	ima_add_boot_aggregate();	/* boot aggregate must be first entry */
+
+	return ima_fs_init();
+}
+
+void __exit ima_cleanup(void)
+{
+	ima_fs_cleanup();
+}
Index: linux-2.6.26-git3/security/integrity/ima/ima_api.c
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/ima_api.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ *
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima_api.c
+ *            - implements the LIM API
+ */
+#include <linux/module.h>
+#include <linux/integrity.h>
+#include <linux/magic.h>
+#include <linux/writeback.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/audit.h>
+#include <linux/ima.h>
+
+#include "ima.h"
+
+const struct template_operations ima_template_ops = {
+	.must_measure = ima_must_measure,
+	.collect_measurement = ima_collect_measurement,
+	.store_measurement = ima_store_measurement,
+	.display_template = ima_template_show
+};
+
+/**
+ * mode_setup - for compatability with non-template IMA versions
+ * @str: is pointer to a string
+ */
+int ima_template_mode = 1;
+static int __init mode_setup(char *str)
+{
+	if (strncmp(str, "ima", 3) == 0)
+		ima_template_mode = 0;
+	if (strncmp(str, "template", 7) == 0)
+		ima_template_mode = 1;
+	ima_info("template_mode %s \n",
+	       	  ima_template_mode ? "template" : "ima");
+	return 1;
+}
+
+__setup("ima_mode=", mode_setup);
+
+/**
+ * ima_digest_cpy - copy the hash in the IMA template structure to a digest
+ * @template_name: string containing the name of the template (i.e. "ima")
+ * @template: pointer to template structure
+ * @digest: pointer to the digest
+ *
+ * Returns 0 on success, error code otherwise
+ */
+static int ima_digest_cpy(char *template_name, void *template, u8 *digest)
+{
+	int rc, result = 0;
+	struct ima_inode_measure_entry *inode_template =
+	    (struct ima_inode_measure_entry *)template;
+
+	rc = strcmp(template_name, "ima");
+	if (rc == 0)
+		memcpy(digest, inode_template->digest,
+		       sizeof inode_template->digest);
+	else
+		result = -ENODATA;
+	return result;
+}
+
+/**
+ * ima_store_template_measure - collect and protect template measurements
+ * @template_name: string containing the name of the template (i.e. "ima")
+ * @template_len: length of the template data
+ * @template: actual template data
+ * @violation: invalidate pcr measurement indication
+ * @audit_cause: string containing the audit failure cause
+ *
+ * Calculate the hash of a template entry, add the template entry
+ * to an ordered list of measurement entries maintained inside the kernel,
+ * and also update the aggregate integrity value (maintained inside the
+ * configured TPM PCR) over the hashes of the current list of measurement
+ * entries.
+ *
+ * Applications retrieve the current kernel-held measurement list through
+ * the securityfs entries in /sys/kernel/security/ima. The signed aggregate
+ * TPM PCR (called quote) can be retrieved using a TPM user space library
+ * and is used to validate the measurement list.
+ *
+ * Returns 0 on success, error code otherwise
+ */
+static int ima_store_template_measure(char *template_name, int template_len,
+				      char *template, int violation,
+				      char **audit_cause)
+{
+	struct ima_measure_entry *entry;
+	u8 digest[IMA_DIGEST_SIZE];
+	struct ima_queue_entry *qe;
+	int count, result = 0;
+
+	memset(digest, 0, IMA_DIGEST_SIZE);
+	if (!violation) {
+		int rc = -ENODATA;
+
+		if (!ima_template_mode)
+			rc = ima_digest_cpy(template_name, template, digest);
+		if (rc < 0)
+			result = ima_calc_template_hash(template_len, template,
+							digest);
+
+		/* hash exists already? */
+		qe = ima_lookup_digest_entry(digest);
+		if (qe) {
+			*audit_cause = "hash_exists";
+			result = -EEXIST;
+			goto out;
+		}
+	}
+
+	/* create new entry and add to measurement list */
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry) {
+		*audit_cause = "ENOMEM";
+		result = -ENOMEM;
+		goto out;
+	}
+
+	entry->template = kzalloc(template_len, GFP_KERNEL);
+	if (!entry->template) {
+		*audit_cause = "ENOMEM";
+		result = -ENOMEM;
+		goto out;
+	}
+	if (!template_name) {
+		*audit_cause = "null_template_name";
+		count = 1;
+	} else {
+		count = strlen(template_name);
+		if (count > IMA_EVENT_NAME_LEN_MAX)
+			count = IMA_EVENT_NAME_LEN_MAX;
+		memcpy(entry->template_name, template_name, count);
+	}
+	entry->template_name[count] = '\0';
+	entry->template_len = template_len;
+	memcpy(entry->template, template, template_len);
+	memcpy(entry->digest, digest, IMA_DIGEST_SIZE);
+
+	result = ima_add_measure_entry(entry, violation);
+	if (result < 0)
+		kfree(entry);
+out:
+	return result;
+}
+
+/**
+ * ima_store_inode_measure - create and store an inode template measurement
+ * @name: ascii file name associated with the measurement hash
+ * @hash_len: length of hash value in bytes (16 for MD5, 20 for SHA1)
+ * @hash: actual hash value pre-calculated
+ *
+ * Returns 0 on success, error code otherwise
+ */
+static int ima_store_inode_measure(struct inode *inode,
+				   const unsigned char *name,
+				   int hash_len, char *hash, int violation)
+{
+	struct ima_inode_measure_entry measure_entry, *entry = &measure_entry;
+	int result;
+	int namelen;
+	char *op = "add_measure";
+	char *cause = " ";
+
+	memset(entry, 0, sizeof *entry);
+	if (!violation)
+		memcpy(entry->digest, hash, hash_len > IMA_DIGEST_SIZE ?
+		       IMA_DIGEST_SIZE : hash_len);
+	if (name) {
+		namelen = strlen(name);
+		memcpy(entry->file_name, name, namelen > IMA_EVENT_NAME_LEN_MAX
+		       ? IMA_EVENT_NAME_LEN_MAX : namelen);
+		entry->file_name[namelen] = '\0';
+	}
+	result = ima_store_template_measure("ima", sizeof *entry, (char *)entry,
+					    violation, &cause);
+	if (result < 0)
+		integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
+				    name, op, cause, result);
+	return result;
+}
+
+/**
+ * ima_add_violation - add violation to measurement list.
+ * @inode: inode associated with the violation
+ * @fname: name associated with the inode
+ * @op: string pointer to audit operation (i.e. "invalid_pcr", "add_measure")
+ * @cause: string pointer to reason for violation (i.e. "ToMToU")
+ *
+ * Violations are flagged in the measurement list with zero hash values.
+ * By extending the PCR with 0xFF's instead of with zeroes, the PCR
+ * value is invalidated.
+ */
+void ima_add_violation(struct inode *inode, const unsigned char *fname,
+		       char *op, char *cause)
+{
+	int result;
+
+	/* can overflow, only indicator */
+	atomic_long_inc(&ima_htable.violations);
+
+	result = ima_store_inode_measure(inode, fname, 0, NULL, 1);
+	integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, fname, op,
+			    cause, result);
+}
+
+/**
+ * skip_measurement - measure only regular files, skip everything else.
+ * @inode: inode being measured
+ * @mask: contains the permission mask
+ *
+ * Quick sanity check to make sure that only regular files opened
+ * for read-only or execute are measured.
+ *
+ * Return 1 to skip measure, 0 to measure
+ */
+static int skip_measurement(struct inode *inode, int mask)
+{
+	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+		return 1;	/* can't measure */
+
+	if (special_file(inode->i_mode) || S_ISLNK(inode->i_mode))
+		return 1;	/* don't measure */
+
+	if (S_ISREG(inode->i_mode))
+		return 0;	/* measure */
+	return 1;		/* don't measure */
+}
+
+/**
+ * ima_must_measure - measure decision based on policy.
+ * @template_data: pointer to struct ima_data containing ima_args_data
+ *
+ * The policy is defined in terms of keypairs:
+ * 		subj=, obj=, type=, func=, mask=, fsmagic=
+ *	subj,obj, and type: are LSM specific.
+ * 	func: INODE_PERMISSION | BPRM_CHECK | FILE_MMAP
+ * 	mask: contains the permission mask
+ *	fsmagic: hex value
+ *
+ * Return 0 to measure. For matching a DONT_MEASURE policy, no policy,
+ * or other error, return an error code.
+*/
+int ima_must_measure(void *template_data)
+{
+	struct ima_data *idata = (struct ima_data *)template_data;
+	struct ima_args_data *data = &idata->data.args;
+	int rc;
+
+	if ((data->mask & MAY_WRITE) || (data->mask & MAY_APPEND))
+		return -EPERM;
+
+	if (skip_measurement(data->inode, data->mask))
+		return -EPERM;
+
+	rc = ima_match_policy(data->inode, data->function, data->mask);
+	if (rc)
+		return 0;
+	return -EACCES;
+}
+
+/**
+ * ima_collect_measurement - collect file measurements and store in the inode
+ * @template_data: pointer to struct ima_data containing ima_args_data
+ *
+ * Return 0 on success, error code otherwise
+ */
+int ima_collect_measurement(void *template_data)
+{
+	struct ima_iint_cache *iint;
+	struct ima_data *idata = (struct ima_data *)template_data;
+	struct ima_args_data *data = &idata->data.args;
+	struct inode *inode = data->inode;
+	struct dentry *dentry = data->dentry;
+	struct nameidata *nd = data->nd;
+	struct file *file = data->file;
+	int result = 0;
+
+	if (idata->type != IMA_DATA)
+		return -EPERM;
+
+	if (!inode || !dentry)
+		return -EINVAL;
+
+	iint = inode->i_integrity;
+	mutex_lock(&iint->mutex);
+	if (!iint->measured) {
+		memset(iint->digest, 0, IMA_DIGEST_SIZE);
+		result = ima_calc_hash(dentry, file, nd, iint->digest);
+	} else
+		result = -EEXIST;
+	mutex_unlock(&iint->mutex);
+	return result;
+}
+
+/**
+ * ima_store_measurement - store file and template measurements
+ * @template_data: pointer to struct ima_data containing ima_args_data,
+ * used to create an IMA template, or a template.
+ *
+ * For file measurements, first create an IMA template and then store it.
+ * For all other types of template measurements, just store it.
+ */
+void ima_store_measurement(void *template_data)
+{
+	struct ima_data *idata = (struct ima_data *)template_data;
+	int result;
+	char *op = "add_template_measure";
+	char *cause = "";
+
+	if (idata->type == IMA_DATA) {
+		struct ima_args_data *data = &idata->data.args;
+		struct ima_iint_cache *iint;
+
+		iint = data->inode->i_integrity;
+		mutex_lock(&iint->mutex);
+		if (iint->measured) {
+			mutex_unlock(&iint->mutex);
+			return;
+		}
+		result = ima_store_inode_measure(data->inode, data->filename,
+						 IMA_DIGEST_SIZE, iint->digest,
+						 0);
+		if (!result || result == -EEXIST) {
+			iint->measured = 1;
+			iint->version = data->inode->i_version;
+		}
+		mutex_unlock(&iint->mutex);
+	} else if (idata->type == IMA_TEMPLATE) {
+		struct ima_store_data *template = (struct ima_store_data *)
+		    &idata->data.template;
+
+		result = ima_store_template_measure(template->name,
+						    template->len,
+						    template->data, 0, &cause);
+		if (result < 0)
+			integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL,
+					    template->name, op, cause, result);
+	}
+}
Index: linux-2.6.26-git3/security/integrity/ima/ima.h
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/ima.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima.h
+ *	internal ima definitions
+ */
+
+#ifndef __LINUX_IMA_H
+#define __LINUX_IMA_H
+
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/security.h>
+#include <linux/integrity.h>
+#include <linux/hash.h>
+#include <linux/tpm.h>
+
+#define ima_printk(level, format, arg...)		\
+	printk(level "ima (%s): " format, __func__, ## arg)
+
+#define ima_error(format, arg...)	\
+	ima_printk(KERN_ERR, format, ## arg)
+
+#define ima_info(format, arg...)	\
+	ima_printk(KERN_INFO, format, ## arg)
+
+/* digest size for IMA, fits SHA1 or MD5 */
+#define IMA_DIGEST_SIZE		20
+#define IMA_EVENT_NAME_LEN_MAX	255
+
+#define IMA_HASH_BITS 9
+#define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS)
+
+/* set during initialization */
+extern int ima_used_chip;
+extern char *ima_hash;
+
+struct ima_measure_entry {
+	u8 digest[IMA_DIGEST_SIZE];	/* sha1 or md5 measurement hash */
+	char template_name[IMA_EVENT_NAME_LEN_MAX + 1];	/* name + \0 */
+	int template_len;
+	char *template;
+};
+
+struct ima_queue_entry {
+	struct hlist_node hnext;	/* place in hash collision list */
+	struct list_head later;		/* place in ima_measurements list */
+	struct ima_measure_entry *entry;
+};
+extern struct list_head ima_measurements;	/* list of all measurements */
+
+/* declarations */
+extern int ima_template_mode;
+extern const struct template_operations ima_template_ops;
+
+/* Internal IMA function definitions */
+int ima_init(void);
+void ima_cleanup(void);
+int ima_fs_init(void);
+void ima_fs_cleanup(void);
+void ima_create_htable(void);
+int ima_add_measure_entry(struct ima_measure_entry *entry, int violation);
+struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest);
+int ima_calc_hash(struct dentry *dentry, struct file *file,
+			struct nameidata *, char *digest);
+int ima_calc_template_hash(int template_len, char *template, char *digest);
+void ima_add_violation(struct inode *inode, const unsigned char *fname,
+			char *op, char *cause);
+
+enum ima_action {DONT_MEASURE, MEASURE};
+int ima_match_policy(struct inode *inode, enum lim_hooks func, int mask);
+int ima_add_rule(int, char *, char *, char *, char *, char *, char *);
+void ima_init_policy(void);
+void ima_update_policy(void);
+
+
+/* LIM API function definitions */
+int ima_must_measure(void *d);
+int ima_collect_measurement(void *d);
+int ima_appraise_measurement(void *d);
+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
+ */
+extern spinlock_t ima_queue_lock;
+
+struct ima_h_table {
+	atomic_t len;		/* number of stored measurements in the list */
+	atomic_long_t violations;
+	unsigned int max_htable_size;
+	struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE];
+	atomic_t queue_len[IMA_MEASURE_HTABLE_SIZE];
+};
+extern struct ima_h_table ima_htable;
+
+static inline unsigned long IMA_HASH_KEY(u8 *digest)
+{
+	 return(hash_ptr(digest, IMA_HASH_BITS));
+}
+
+/* TPM "Glue" definitions */
+
+#define IMA_TPM ((((u32)TPM_ANY_TYPE)<<16) | (u32)TPM_ANY_NUM)
+static inline void ima_extend(const u8 *hash)
+{
+	if (!ima_used_chip)
+		return;
+
+	if (tpm_pcr_extend(IMA_TPM, CONFIG_IMA_MEASURE_PCR_IDX, hash) != 0)
+		ima_error("Error Communicating to TPM chip\n");
+}
+
+static inline void ima_pcrread(int idx, u8 *pcr, int pcr_size)
+{
+	if (!ima_used_chip)
+		return;
+
+	if (tpm_pcr_read(IMA_TPM, idx, pcr) != 0)
+		ima_error("Error Communicating to TPM chip\n");
+}
+
+struct ima_inode_measure_entry {
+	u8 digest[IMA_DIGEST_SIZE];	/* sha1/md5 measurement hash */
+	char file_name[IMA_EVENT_NAME_LEN_MAX + 1];	/* name + \0 */
+};
+
+/* inode integrity data */
+struct ima_iint_cache {
+	u64 		version;
+	int 		measured;
+	u8 		hmac[IMA_DIGEST_SIZE];
+	u8 		digest[IMA_DIGEST_SIZE];
+	struct mutex mutex;
+};
+#endif
Index: linux-2.6.26-git3/security/integrity/ima/ima_crypto.c
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/ima_crypto.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zohar@us.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * 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_crypto.c
+ * 	Calculate a file's or a template's hash.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/crypto.h>
+#include <linux/mm.h>
+#include <linux/mount.h>
+#include <linux/scatterlist.h>
+#include "ima.h"
+
+/*
+ * Calculate the file hash, using an open file descriptor if available.
+ */
+static int update_file_hash(struct dentry *dentry, struct file *f,
+			    struct nameidata *nd, struct hash_desc *desc)
+{
+	struct file *file = f;
+	struct scatterlist sg[1];
+	loff_t i_size;
+	int rc = 0;
+	char *rbuf;
+	int offset = 0;
+
+	if (!file) {
+		struct dentry *de = dget(dentry);
+		struct vfsmount *mnt = mntget(nd->path.mnt);
+		if (!de || !mnt) {
+			rc = -EINVAL;
+			goto err_out;
+		}
+		file = dentry_open(de, mnt, O_RDONLY);
+		if (IS_ERR(file)) {
+			ima_info("%s dentry_open failed\n", de->d_name.name);
+			rc = PTR_ERR(file);
+			file = NULL;
+		}
+err_out:
+		if (!file) {
+			dput(de);
+			mntput(mnt);
+			goto out;
+		}
+	}
+
+	if (!file->f_dentry || !file->f_dentry->d_inode) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!rbuf) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	i_size = i_size_read(file->f_dentry->d_inode);
+	while (offset < i_size) {
+		int rbuf_len;
+
+		rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE);
+		if (rbuf_len < 0) {
+			rc = rbuf_len;
+			break;
+		}
+		offset += rbuf_len;
+		sg_set_buf(sg, rbuf, rbuf_len);
+
+		rc = crypto_hash_update(desc, sg, rbuf_len);
+		if (rc)
+			break;
+	}
+	kfree(rbuf);
+out:
+	if (file && !f)
+		fput(file);	/* clean up dentry_open() */
+	return rc;
+}
+
+/*
+ * Calculate the MD5/SHA1 digest
+ */
+int ima_calc_hash(struct dentry *dentry, struct file *file,
+		  struct nameidata *nd, char *digest)
+{
+	struct hash_desc desc;
+	int rc;
+
+	if (!dentry && !file)
+		return -EINVAL;
+
+	desc.tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(desc.tfm)) {
+		ima_info("failed to load %s transform: %ld\n",
+			 ima_hash, PTR_ERR(desc.tfm));
+		rc = PTR_ERR(desc.tfm);
+		return rc;
+	}
+	desc.flags = 0;
+	rc = crypto_hash_init(&desc);
+	if (rc)
+		goto out;
+
+	rc = update_file_hash(dentry, file, nd, &desc);
+	if (!rc)
+		rc = crypto_hash_final(&desc, digest);
+out:
+	crypto_free_hash(desc.tfm);
+	return rc;
+}
+
+/*
+ * Calculate the hash of a given template
+ */
+int ima_calc_template_hash(int template_len, char *template, char *digest)
+{
+	struct hash_desc desc;
+	struct scatterlist sg[1];
+	int rc;
+
+	desc.tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(desc.tfm)) {
+		ima_info("failed to load %s transform: %ld\n",
+			 ima_hash, PTR_ERR(desc.tfm));
+		rc = PTR_ERR(desc.tfm);
+		return rc;
+	}
+	desc.flags = 0;
+	rc = crypto_hash_init(&desc);
+	if (rc)
+		goto out;
+
+	sg_set_buf(sg, template, template_len);
+	rc = crypto_hash_update(&desc, sg, template_len);
+	if (!rc)
+		rc = crypto_hash_final(&desc, digest);
+out:
+	crypto_free_hash(desc.tfm);
+	return rc;
+}
Index: linux-2.6.26-git3/security/integrity/ima/ima_fs.c
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/ima_fs.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Kylene Hall <kjhall@us.ibm.com>
+ * Reiner Sailer <sailer@us.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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_fs.c
+ *	implemenents security file system for reporting
+ *	current measurement list and IMA statistics
+ */
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/integrity.h>
+
+#include "ima.h"
+
+#define TMPBUFLEN 12
+static ssize_t ima_show_htable_value(char __user *buf, size_t count,
+				     loff_t *ppos, atomic_long_t *val)
+{
+	char tmpbuf[TMPBUFLEN];
+	ssize_t len;
+
+	len = scnprintf(tmpbuf, TMPBUFLEN, "%i\n", atomic_read(val));
+	return simple_read_from_buffer(buf, count, ppos, tmpbuf, len);
+}
+
+static ssize_t ima_show_htable_violations(struct file *filp,
+					  char __user *buf,
+					  size_t count, loff_t *ppos)
+{
+	return ima_show_htable_value(buf, count, ppos, &ima_htable.violations);
+}
+
+static struct file_operations ima_htable_violations_ops = {
+	.read = ima_show_htable_violations
+};
+
+static ssize_t ima_show_measurements_count(struct file *filp,
+					   char __user *buf,
+					   size_t count, loff_t *ppos)
+{
+	return ima_show_htable_value(buf, count, ppos, &ima_htable.len);
+
+}
+
+static struct file_operations ima_measurements_count_ops = {
+	.read = ima_show_measurements_count
+};
+
+/* returns pointer to hlist_node */
+static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
+{
+	struct list_head *lpos;
+	loff_t l = *pos;
+	/* we need a lock since pos could point beyond last element */
+	rcu_read_lock();
+	list_for_each_rcu(lpos, &ima_measurements) {
+		if (!l--) {
+			rcu_read_unlock();
+			return lpos;
+		}
+	}
+	rcu_read_unlock();
+	return NULL;
+}
+
+static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	/* lock protects when reading beyond last element
+	 * against concurrent list-extension */
+	struct list_head *lpos = (struct list_head *)v;
+
+	rcu_read_lock();
+	lpos = rcu_dereference(lpos->next);
+	rcu_read_unlock();
+	(*pos)++;
+
+	return (lpos == &ima_measurements) ? NULL : lpos;
+}
+
+static void ima_measurements_stop(struct seq_file *m, void *v)
+{
+}
+
+/* print format:
+ *       32bit-le=pcr#
+ *       char[20]=template digest
+ *       32bit-le=template size
+ *       32bit-le=template name size
+ *       eventdata[n] = template name
+ *
+ */
+static int ima_measurements_show(struct seq_file *m, void *v)
+{
+	/* the list never shrinks, so we don't need a lock here */
+	struct list_head *lpos = v;
+	struct ima_queue_entry *qe;
+	struct ima_measure_entry *e;
+	struct ima_inode_measure_entry *entry;
+	const struct template_operations *template_ops;
+	int templatename_len;
+	int i;
+	u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX;
+	char data[4];
+
+	/* get entry */
+	qe = list_entry(lpos, struct ima_queue_entry, later);
+	e = qe->entry;
+	if (e == NULL)
+		return -1;
+
+	/*
+	 * 1st: PCRIndex
+	 * PCR used is always the same (config option) in
+	 * little-endian format
+	 */
+	memcpy(data, &pcr, 4);
+	for (i = 0; i < 4; i++)
+		seq_putc(m, data[i]);
+
+	/* 2nd: template digest */
+	for (i = 0; i < 20; i++)
+		seq_putc(m, e->digest[i]);
+
+	/* 3rd: template name size */
+	templatename_len = strlen(e->template_name);
+	if (templatename_len > IMA_EVENT_NAME_LEN_MAX)
+		templatename_len = IMA_EVENT_NAME_LEN_MAX;
+
+	memcpy(data, &templatename_len, 4);
+	for (i = 0; i < 4; i++)
+		seq_putc(m, data[i]);
+
+	/* 4th:  template name  */
+	for (i = 0; i < templatename_len; i++)
+		seq_putc(m, e->template_name[i]);
+
+	/* 5th:  template dependent */
+	entry = (struct ima_inode_measure_entry *)e->template;
+	if (integrity_find_template(e->template_name, &template_ops) == 0)
+		template_ops->display_template(m, entry, INTEGRITY_SHOW_BINARY);
+	else
+		seq_printf(m, " \n");
+	return 0;
+}
+
+static struct seq_operations ima_measurments_seqops = {
+	.start = ima_measurements_start,
+	.next = ima_measurements_next,
+	.stop = ima_measurements_stop,
+	.show = ima_measurements_show
+};
+
+static int ima_measurements_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &ima_measurments_seqops);
+}
+
+static struct file_operations ima_measurements_ops = {
+	.open = ima_measurements_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+void ima_template_show(struct seq_file *m, void *e,
+		       enum integrity_show_type show)
+{
+	struct ima_inode_measure_entry *entry =
+	    (struct ima_inode_measure_entry *)e;
+	int filename_len;
+	char data[4];
+	int i;
+
+	/* Display file digest */
+	if (ima_template_mode)
+		for (i = 0; i < 20; i++) {
+			switch (show) {
+			case INTEGRITY_SHOW_ASCII:
+				seq_printf(m, "%02x", entry->digest[i]);
+				break;
+			case INTEGRITY_SHOW_BINARY:
+				seq_putc(m, entry->digest[i]);
+			default:
+				break;
+			}
+		}
+
+	switch (show) {
+	case INTEGRITY_SHOW_ASCII:
+		seq_printf(m, " %s\n", entry->file_name);
+		break;
+	case INTEGRITY_SHOW_BINARY:
+		filename_len = strlen(entry->file_name);
+		if (filename_len > IMA_EVENT_NAME_LEN_MAX)
+			filename_len = IMA_EVENT_NAME_LEN_MAX;
+
+		memcpy(data, &filename_len, 4);
+		for (i = 0; i < 4; i++)
+			seq_putc(m, data[i]);
+		for (i = 0; i < filename_len; i++)
+			seq_putc(m, entry->file_name[i]);
+	default:
+		break;
+	}
+}
+
+/* print in ascii */
+static int ima_ascii_measurements_show(struct seq_file *m, void *v)
+{
+	/* the list never shrinks, so we don't need a lock here */
+	struct list_head *lpos = v;
+	struct ima_queue_entry *qe;
+	struct ima_measure_entry *e;
+	struct ima_inode_measure_entry *entry;
+	const struct template_operations *template_ops;
+	int i;
+
+	/* get entry */
+	qe = list_entry(lpos, struct ima_queue_entry, later);
+	e = qe->entry;
+	if (e == NULL)
+		return -1;
+
+	/* 1st: PCR used (config option) */
+	seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX);
+
+	/* 2nd: SHA1 template hash */
+	for (i = 0; i < 20; i++)
+		seq_printf(m, "%02x", e->digest[i]);
+
+	/* 3th:  template name */
+	seq_printf(m, " %s ", e->template_name);
+
+	/* 4th:  filename <= max + \'0' delimiter */
+	entry = (struct ima_inode_measure_entry *)e->template;
+	if (integrity_find_template(e->template_name, &template_ops) == 0)
+		template_ops->display_template(m, entry, INTEGRITY_SHOW_ASCII);
+	else
+		seq_printf(m, " \n");
+
+	return 0;
+}
+
+static struct seq_operations ima_ascii_measurements_seqops = {
+	.start = ima_measurements_start,
+	.next = ima_measurements_next,
+	.stop = ima_measurements_stop,
+	.show = ima_ascii_measurements_show
+};
+
+static int ima_ascii_measurements_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &ima_ascii_measurements_seqops);
+}
+
+static struct file_operations ima_ascii_measurements_ops = {
+	.open = ima_ascii_measurements_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static char *get_tag(char *bufStart, char *bufEnd, char delimiter, int *taglen)
+{
+	char *bufp = bufStart;
+	char *tag;
+
+	/* Get start of tag */
+	while (bufp < bufEnd) {
+		if (*bufp == ' ')	/* skip blanks */
+			while ((*bufp == ' ') && (bufp++ < bufEnd)) ;
+		else if (*bufp == '#') {	/* skip comment */
+			while ((*bufp != '\n') && (bufp++ < bufEnd)) ;
+			bufp++;
+		} else if (*bufp == '\n')	/* skip newline */
+			bufp++;
+		else if (*bufp == '\t')	/* skip tabs */
+			bufp++;
+		else
+			break;
+	}
+	if (bufp < bufEnd)
+		tag = bufp;
+	else
+		return NULL;
+
+	/* Get tag */
+	*taglen = 0;
+	while ((bufp < bufEnd) && (*taglen == 0)) {
+		if ((*bufp == delimiter) || (*bufp == '\n')) {
+			*taglen = bufp - tag;
+			*bufp = '\0';
+		}
+		bufp++;
+	}
+	if (*taglen == 0)	/* Didn't find end delimiter */
+		tag = NULL;
+	return tag;
+}
+
+static ssize_t ima_write_policy(struct file *file, const char __user *buf,
+				size_t buflen, loff_t *ppos)
+{
+	size_t rc = 0, datalen;
+	int action = 0;
+	char *data, *datap, *dataend;
+	char *subj = NULL, *obj = NULL, *type = NULL;
+	char *func = NULL, *mask = NULL, *fsmagic = NULL;
+	int err = 0;
+	char *tag;
+	int taglen, i;
+
+	datalen = buflen > 4095 ? 4095 : buflen;
+	data = kmalloc(datalen + 1, GFP_KERNEL);
+	if (!data)
+		rc = -ENOMEM;
+
+	if (copy_from_user(data, buf, datalen)) {
+		kfree(data);
+		return -EFAULT;
+	}
+
+	rc = datalen;
+	*(data + datalen) = ' ';
+
+	datap = data;
+	dataend = data + datalen;
+
+	if (strncmp(datap, "measure", 7) == 0) {
+		datap += 8;
+		action = 1;
+	} else if (strncmp(datap, "dont_measure", 12) == 0)
+		datap += 13;
+	else			/* bad format */
+		goto out;
+
+	for (i = 0; i < 6; i++) {
+		tag = get_tag(datap, dataend, ' ', &taglen);
+		if (!tag)
+			break;
+		if (strncmp(tag, "obj=", 4) == 0)
+			obj = tag + 4;
+		else if (strncmp(tag, "subj=", 5) == 0)
+			subj = tag + 5;
+		else if (strncmp(tag, "type=", 5) == 0)
+			type = tag + 5;
+		else if (strncmp(tag, "func=", 5) == 0)
+			func = tag + 5;
+		else if (strncmp(tag, "mask=", 5) == 0)
+			mask = tag + 5;
+		else if (strncmp(tag, "fsmagic=", 8) == 0)
+			fsmagic = tag + 8;
+		else {		/* bad format */
+			err = 1;
+			break;
+		}
+		datap += taglen + 1;
+	}
+
+	if (!err) {
+		ima_info("%s %s %s %s %s %s %s\n",
+			 action ? "measure " : "dont_measure",
+			 subj, obj, type, func, mask, fsmagic);
+		ima_add_rule(action, subj, obj, type, func, mask, fsmagic);
+	}
+out:
+	if (!data)
+		kfree(data);
+	return rc;
+}
+
+static struct dentry *ima_dir;
+static struct dentry *binary_runtime_measurements;
+static struct dentry *ascii_runtime_measurements;
+static struct dentry *runtime_measurements_count;
+static struct dentry *violations;
+static struct dentry *ima_policy;
+
+static int ima_release_policy(struct inode *inode, struct file *file)
+{
+	ima_update_policy();
+	securityfs_remove(ima_policy);
+	ima_policy = NULL;
+	return 0;
+}
+
+static struct file_operations ima_measure_policy_ops = {
+	.write = ima_write_policy,
+	.release = ima_release_policy
+};
+
+int ima_fs_init(void)
+{
+	ima_dir = securityfs_create_dir("ima", NULL);
+	if (!ima_dir || IS_ERR(ima_dir))
+		return -1;
+
+	binary_runtime_measurements =
+	    securityfs_create_file("binary_runtime_measurements",
+				   S_IRUSR | S_IRGRP, ima_dir, NULL,
+				   &ima_measurements_ops);
+	if (!binary_runtime_measurements || IS_ERR(binary_runtime_measurements))
+		goto out;
+
+	ascii_runtime_measurements =
+	    securityfs_create_file("ascii_runtime_measurements",
+				   S_IRUSR | S_IRGRP, ima_dir, NULL,
+				   &ima_ascii_measurements_ops);
+	if (!ascii_runtime_measurements || IS_ERR(ascii_runtime_measurements))
+		goto out;
+
+	runtime_measurements_count =
+	    securityfs_create_file("runtime_measurements_count",
+				   S_IRUSR | S_IRGRP, ima_dir, NULL,
+				   &ima_measurements_count_ops);
+	if (!runtime_measurements_count || IS_ERR(runtime_measurements_count))
+		goto out;
+
+	violations =
+	    securityfs_create_file("violations", S_IRUSR | S_IRGRP,
+				   ima_dir, NULL, &ima_htable_violations_ops);
+	if (!violations || IS_ERR(violations))
+		goto out;
+
+	ima_policy = securityfs_create_file("policy",
+					    S_IRUSR | S_IRGRP | S_IWUSR,
+					    ima_dir, NULL,
+					    &ima_measure_policy_ops);
+	ima_init_policy();
+	return 0;
+
+out:
+	securityfs_remove(runtime_measurements_count);
+	securityfs_remove(ascii_runtime_measurements);
+	securityfs_remove(binary_runtime_measurements);
+	securityfs_remove(ima_dir);
+	securityfs_remove(ima_policy);
+	return -1;
+}
+
+void __exit ima_fs_cleanup(void)
+{
+	securityfs_remove(violations);
+	securityfs_remove(runtime_measurements_count);
+	securityfs_remove(ascii_runtime_measurements);
+	securityfs_remove(binary_runtime_measurements);
+	securityfs_remove(ima_dir);
+	securityfs_remove(ima_policy);
+}
Index: linux-2.6.26-git3/security/integrity/ima/ima_queue.c
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/ima_queue.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Serge Hallyn <serue@us.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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_queue.c
+ *       implements queues that store IMA measurements and
+ *       maintains aggregate over the stored measurements
+ *       in the pre-configured TPM PCR (if available)
+ *       The measurement list is append-only. No entry is
+ *       ever removed or changed during the boot-cycle.
+ */
+#include <linux/module.h>
+
+#include "ima.h"
+
+struct list_head ima_measurements;	/* list of all measurements */
+struct ima_h_table ima_htable;	/* key: inode (before secure-hashing a file) */
+
+/* mutex protects atomicity of extending measurement list
+ * and extending the TPM PCR aggregate. Since tpm_extend can take
+ * long (and the tpm driver uses a mutex), we can't use the spinlock.
+ */
+static DEFINE_MUTEX(ima_extend_list_mutex);
+
+void ima_create_htable(void)
+{
+	int i;
+
+	INIT_LIST_HEAD(&ima_measurements);
+	atomic_set(&ima_htable.len, 0);
+	atomic_long_set(&ima_htable.violations, 0);
+	ima_htable.max_htable_size = IMA_MEASURE_HTABLE_SIZE;
+
+	for (i = 0; i < ima_htable.max_htable_size; i++) {
+		INIT_HLIST_HEAD(&ima_htable.queue[i]);
+		atomic_set(&ima_htable.queue_len[i], 0);
+	}
+}
+
+struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value)
+{
+	struct ima_queue_entry *qe, *ret = NULL;
+	unsigned int key;
+	struct hlist_node *pos;
+
+	key = IMA_HASH_KEY(digest_value);
+	rcu_read_lock();
+	hlist_for_each_entry_rcu(qe, pos, &ima_htable.queue[key], hnext) {
+		if (memcmp(qe->entry->digest, digest_value, 20) == 0) {
+			ret = qe;
+			break;
+		}
+	}
+	rcu_read_unlock();
+	return ret;
+}
+
+/* Called with mutex held */
+static int ima_add_digest_entry(struct ima_measure_entry *entry)
+{
+	struct ima_queue_entry *qe;
+	unsigned int key;
+
+	key = IMA_HASH_KEY(entry->digest);
+	qe = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (qe == NULL) {
+		ima_error("OUT OF MEMORY ERROR creating queue entry.\n");
+		return -ENOMEM;
+	}
+	qe->entry = entry;
+
+	hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]);
+	atomic_inc(&ima_htable.queue_len[key]);
+	return 0;
+}
+
+int ima_add_measure_entry(struct ima_measure_entry *entry, int violation)
+{
+	struct ima_queue_entry *qe;
+	int error = 0;
+
+	mutex_lock(&ima_extend_list_mutex);
+	if (!violation) {
+		if (ima_lookup_digest_entry(entry->digest)) {
+			error = -EEXIST;
+			goto out;
+		}
+	}
+	qe = kmalloc(sizeof(struct ima_queue_entry), GFP_KERNEL);
+	if (qe == NULL) {
+		ima_error("OUT OF MEMORY in %s.\n", __func__);
+		error = -ENOMEM;
+		goto out;
+	}
+	qe->entry = entry;
+
+	INIT_LIST_HEAD(&qe->later);
+	list_add_tail_rcu(&qe->later, &ima_measurements);
+
+	atomic_inc(&ima_htable.len);
+	if (ima_add_digest_entry(entry)) {
+		error = -ENOMEM;
+		goto out;
+	}
+	if (violation) {	/* Replace 0x00 with 0xFF */
+		u8 digest[IMA_DIGEST_SIZE];
+
+		memset(digest, 0xff, sizeof digest);
+		ima_extend(digest);
+	} else
+		ima_extend(entry->digest);
+out:
+	mutex_unlock(&ima_extend_list_mutex);
+	return error;
+}
Index: linux-2.6.26-git3/security/integrity/ima/ima_policy.c
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/security/integrity/ima/ima_policy.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * ima_policy.c
+ * 	- initialize default measure policy rules
+	- load a policy ruleset
+ *
+ */
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/audit.h>
+#include <linux/security.h>
+#include <linux/integrity.h>
+#include <linux/magic.h>
+
+#include "ima.h"
+
+#define security_filter_rule_init security_audit_rule_init
+#define security_filter_rule_match security_audit_rule_match
+
+struct ima_measure_rule_entry {
+	struct list_head list;
+	int action;
+	void *lsm_obj_rule;
+	void *lsm_subj_rule;
+	void *lsm_type_rule;
+	enum lim_hooks func;
+	int mask;
+	ulong fsmagic;
+};
+
+/* Without LSM specific knowledge, default policy can only
+ * be written in terms of .action, .func, .mask and .fsmagic.
+ */
+static struct ima_measure_rule_entry default_rules[] = {
+	{.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC},
+	{.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC},
+	{.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC},
+	{.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC},
+	{.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC},
+	{.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC},
+	{.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC},
+	{.action = MEASURE,.func = INODE_PERMISSION,.mask = MAY_READ},
+};
+
+static struct list_head measure_default_rules;
+static struct list_head measure_policy_rules;
+static struct list_head *ima_measure;
+
+static DEFINE_MUTEX(ima_measure_mutex);
+
+/**
+ * ima_match_rules - determine whether an inode matches the measure rule.
+ * @rule: a pointer to a rule
+ * @inode: a pointer to an inode
+ * @func: LIM hook identifier
+ * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ *
+ * Returns true on rule match, false on failure.
+ */
+static bool ima_match_rules(struct ima_measure_rule_entry *rule,
+			   struct inode *inode, enum lim_hooks func, int mask)
+{
+	if (rule->func && rule->func != func)
+		return false;
+	if (rule->mask && rule->mask != mask)
+		return false;
+	if (rule->fsmagic && rule->fsmagic != inode->i_sb->s_magic)
+		return false;
+	if (rule->lsm_subj_rule) {
+		struct task_struct *tsk = current;
+		u32 sid;
+		int rc;
+
+		security_task_getsecid(tsk, &sid);
+		rc = security_filter_rule_match(sid, AUDIT_SUBJ_USER,
+						AUDIT_EQUAL,
+						rule->lsm_subj_rule, NULL);
+		if (!rc)
+			return false;
+	}
+	if (rule->lsm_obj_rule) {
+		u32 osid;
+		int rc;
+
+		security_inode_getsecid(inode, &osid);
+		rc = security_filter_rule_match(osid, AUDIT_OBJ_USER,
+						AUDIT_EQUAL,
+						rule->lsm_obj_rule, NULL);
+		if (!rc)
+			return false;
+	}
+	if (rule->lsm_type_rule) {
+		u32 osid;
+		int rc;
+
+		security_inode_getsecid(inode, &osid);
+		rc = security_filter_rule_match(osid, AUDIT_OBJ_TYPE,
+						AUDIT_EQUAL,
+						rule->lsm_type_rule, NULL);
+		if (!rc)
+			return false;
+	}
+	return true;
+}
+
+/**
+ * ima_match_policy - decision based on LSM and other conditions
+ * @inode: pointer to an inode
+ * @func: IMA hook identifier
+ * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ *
+ * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
+ * conditions. Returns rule action on rule match, 0 on failure.
+ */
+int ima_match_policy(struct inode *inode, enum lim_hooks func, int mask)
+{
+	struct ima_measure_rule_entry *entry;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(entry, ima_measure, list) {
+		bool rc;
+
+		rc = ima_match_rules(entry, inode, func, mask);
+		if (rc) {
+			rcu_read_unlock();
+			return entry->action;
+		}
+	}
+	rcu_read_unlock();
+	return 0;
+}
+
+/**
+ * ima_init_policy - initialize the default and policy measure rules.
+ */
+void ima_init_policy(void)
+{
+	int i;
+
+	INIT_LIST_HEAD(&measure_default_rules);
+	for (i = 0; i < ARRAY_SIZE(default_rules); i++)
+		list_add_tail(&default_rules[i].list, &measure_default_rules);
+	ima_measure = &measure_default_rules;
+
+	INIT_LIST_HEAD(&measure_policy_rules);
+}
+
+/**
+ * ima_update_policy - update default_rules with new measure rules
+ *
+ * Wait to update the default rules with a complete new set of measure rules.
+ */
+void ima_update_policy(void)
+{
+	char *op = "policy_update";
+	char *cause = "already exists";
+	int result = 1;
+
+	if (ima_measure == &measure_default_rules) {
+		ima_measure = &measure_policy_rules;
+		cause = "complete";
+		result = 0;
+	}
+	integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
+			    NULL, op, cause, result);
+}
+
+/**
+ * ima_add_rule - add ima measure rules
+ * @action: integer 1 indicating MEASURE, 0 indicating DONT_MEASURE
+ * @subj: pointer to an LSM subject value
+ * @obj:  pointer to an LSM object value
+ * @type:  pointer to an LSM object type value
+ * @func: LIM hook identifier
+ * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ * @fsmagic: fs magic hex value string
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int ima_add_rule(int action, char *subj, char *obj, char *type,
+		 char *func, char *mask, char *fsmagic)
+{
+	struct ima_measure_rule_entry *entry;
+	int result = 0;
+
+	/* Prevent installed policy from changing */
+	if (ima_measure != &measure_default_rules) {
+		integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
+				    NULL, "policy_update", "already exists", 1);
+		return -EACCES;
+	}
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	INIT_LIST_HEAD(&entry->list);
+	if (action < 0 || action > 1)
+		result = -EINVAL;
+	else
+		entry->action = action;
+	if (!result && subj)
+		result = security_filter_rule_init(AUDIT_SUBJ_USER, AUDIT_EQUAL,
+						   subj, &entry->lsm_subj_rule);
+	if (!result && obj)
+		result = security_filter_rule_init(AUDIT_OBJ_USER, AUDIT_EQUAL,
+						   obj, &entry->lsm_obj_rule);
+	if (!result && type)
+		result = security_filter_rule_init(AUDIT_OBJ_TYPE, AUDIT_EQUAL,
+						   obj, &entry->lsm_obj_rule);
+	if (!result && func) {
+		if (strcmp(func, "INODE_PERMISSION") == 0)
+			entry->func = INODE_PERMISSION;
+		else if (strcmp(func, "FILE_MMAP") == 0)
+			entry->func = FILE_MMAP;
+		else if (strcmp(func, "BPRM_CHECK") == 0)
+			entry->func = BPRM_CHECK;
+		else
+			result = -EINVAL;
+	}
+	if (!result && mask) {
+		if (strcmp(mask, "MAY_EXEC") == 0)
+			entry->mask = MAY_EXEC;
+		else if (strcmp(mask, "MAY_WRITE") == 0)
+			entry->mask = MAY_WRITE;
+		else if (strcmp(mask, "MAY_READ") == 0)
+			entry->mask = MAY_READ;
+		else if (strcmp(mask, "MAY_APPEND") == 0)
+			entry->mask = MAY_APPEND;
+		else
+			result = -EINVAL;
+	}
+	if (!result && fsmagic) {
+		int rc;
+
+		rc = strict_strtoul(fsmagic, 16, &entry->fsmagic);
+		if (rc)
+			result = -EINVAL;
+	}
+	if (!result) {
+		mutex_lock(&ima_measure_mutex);
+		list_add_tail(&entry->list, &measure_policy_rules);
+		mutex_unlock(&ima_measure_mutex);
+	}
+	return result;
+}
Index: linux-2.6.26-git3/Documentation/kernel-parameters.txt
===================================================================
--- linux-2.6.26-git3.orig/Documentation/kernel-parameters.txt
+++ linux-2.6.26-git3/Documentation/kernel-parameters.txt
@@ -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.
@@ -838,6 +839,10 @@ and is between 256 and 4096 characters. 
 	ihash_entries=	[KNL]
 			Set number of hash buckets for inode cache.
 
+	ima_hash=	[IMA] runtime ability to define hash crypto alg.
+			Format: { "MD5" | "SHA1" }
+			Default is "SHA1".
+
 	in2000=		[HW,SCSI]
 			See header of drivers/scsi/in2000.c.
 
Index: linux-2.6.26-git3/include/linux/ima.h
===================================================================
--- /dev/null
+++ linux-2.6.26-git3/include/linux/ima.h
@@ -0,0 +1,48 @@
+/*
+ * ima.h
+ *
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * 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.
+ */
+
+#ifndef _LINUX_IMA_H
+#define _LINUX_IMA_H
+
+/* IMA LIM Data */
+enum ima_type { IMA_DATA, IMA_METADATA, IMA_TEMPLATE };
+
+struct ima_args_data {
+	const char	*filename;
+	struct inode 	*inode;
+	struct dentry 	*dentry;
+	struct nameidata 	*nd;
+	struct file 	*file;
+	enum lim_hooks	function;
+	u32		osid;
+	int 		mask;
+};
+
+struct ima_store_data {
+	char 		*name;
+	int 		len;
+	char 		*data;
+	int  		violation;
+};
+
+struct ima_data {
+	enum ima_type 	type;
+	union {
+		struct ima_args_data 	args;
+		struct ima_store_data	template;
+	} data;
+};
+
+void ima_fixup_argsdata(struct ima_args_data *data,
+			struct inode *inode, struct dentry *dentry,
+			struct file *file, struct nameidata *nd, int mask,
+			int function);
+#endif
Index: linux-2.6.26-git3/security/integrity/Makefile
===================================================================
--- linux-2.6.26-git3.orig/security/integrity/Makefile
+++ linux-2.6.26-git3/security/integrity/Makefile
@@ -4,3 +4,5 @@
 
 # Object file lists
 obj-$(CONFIG_INTEGRITY)			+= integrity.o integrity_audit.o
+
+obj-$(CONFIG_IMA)			+= ima/
Index: linux-2.6.26-git3/security/integrity/Kconfig
===================================================================
--- linux-2.6.26-git3.orig/security/integrity/Kconfig
+++ linux-2.6.26-git3/security/integrity/Kconfig
@@ -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



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Patch 5/5]integrity: IMA as an integrity service provider
  2008-07-17 21:54         ` Mimi Zohar
@ 2008-07-22 15:08           ` James Morris
  0 siblings, 0 replies; 20+ messages in thread
From: James Morris @ 2008-07-22 15:08 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: linux-kernel, Andrew Morton, safford, serue, sailer, zohar,
	debora, srajiv

I've applied these patches to:
git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6#devel

which will go into linux-next in about a week.

I fixed up a couple of outstanding issues with atomic vs. atomic_long (see 
the patch below).

Please test.

----

commit fe2e6187810af248f910f1ca498fe03b54cade2e
Author: James Morris <jmorris@namei.org>
Date:   Tue Jul 22 10:43:04 2008 -0400

    integrity: fix up some atomic vs. atomic_long issues
    
    Ensure atomic_long_t is used correctly throughout the
    integrity code.
    
    Signed-off-by: James Morris <jmorris@namei.org>

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index de982c6..986bfb1 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -98,7 +98,7 @@ void ima_template_show(struct seq_file *m, void *e,
 extern spinlock_t ima_queue_lock;
 
 struct ima_h_table {
-	atomic_t len;		/* number of stored measurements in the list */
+	atomic_long_t len;	/* number of stored measurements in the list */
 	atomic_long_t violations;
 	unsigned int max_htable_size;
 	struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE];
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index fa3cdb0..781460f 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -28,7 +28,7 @@ static ssize_t ima_show_htable_value(char __user *buf, size_t count,
 	char tmpbuf[TMPBUFLEN];
 	ssize_t len;
 
-	len = scnprintf(tmpbuf, TMPBUFLEN, "%i\n", atomic_read(val));
+	len = scnprintf(tmpbuf, TMPBUFLEN, "%li\n", atomic_long_read(val));
 	return simple_read_from_buffer(buf, count, ppos, tmpbuf, len);
 }
 
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index e09ddb9..1cb4f03 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -106,7 +106,7 @@ int ima_add_measure_entry(struct ima_measure_entry *entry, int violation)
 	INIT_LIST_HEAD(&qe->later);
 	list_add_tail_rcu(&qe->later, &ima_measurements);
 
-	atomic_inc(&ima_htable.len);
+	atomic_long_inc(&ima_htable.len);
 	if (ima_add_digest_entry(entry)) {
 		error = -ENOMEM;
 		goto out;

^ permalink raw reply related	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2008-07-22 15:16 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20080707192529.489789904@linux.vnet.ibm.com>
2008-07-07 21:56 ` [PATCH 1/5] integrity: TPM cleanup Mimi Zohar
2008-07-08  1:33   ` James Morris
2008-07-08 12:01     ` Mimi Zohar
2008-07-15 23:13   ` James Morris
2008-07-16 20:04     ` Mimi Zohar
2008-07-16 20:04     ` [Patch 1/5]integrity: " Mimi Zohar
2008-07-16 20:05     ` [Patch 2/5]integrity: TPM internel kernel interface Mimi Zohar
2008-07-16 20:05     ` [Patch 3/5] integrity: special fs magic Mimi Zohar
2008-07-16 20:05     ` [PATCH 4/5]integrity: Linux Integrity Module(LIM) Mimi Zohar
2008-07-16 20:05     ` [Patch 5/5]integrity: IMA as an integrity service provider Mimi Zohar
2008-07-16 23:56       ` James Morris
2008-07-17 21:54         ` Mimi Zohar
2008-07-22 15:08           ` James Morris
2008-07-07 21:56 ` [PATCH 2/5] integrity: TPM internel kernel interface Mimi Zohar
2008-07-07 21:56 ` [PATCH 3/5] integrity: special fs magic Mimi Zohar
2008-07-07 21:57 ` [PATCH 4/5] integrity: Linux Integrity Module(LIM) Mimi Zohar
2008-07-08  1:31   ` James Morris
2008-07-08 12:04     ` Mimi Zohar
2008-07-07 21:57 ` [PATCH 5/5] integrity: IMA as an integrity service provider Mimi Zohar
2008-07-07 22:03 ` LTP IMA path Mimi Zohar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox