---
 Documentation/ima/INSTALL                    |  327 ++++++++++++++++++
 Documentation/ima/integrity_measurements.txt |   87 +++++
 Makefile                                     |    2 
 drivers/char/tpm/tpm.c                       |   95 +++++
 drivers/char/tpm/tpm.h                       |    5 
 drivers/char/tpm/tpm_atmel.c                 |    2 
 drivers/char/tpm/tpm_infineon.c              |    2 
 drivers/char/tpm/tpm_nsc.c                   |    2 
 drivers/char/tpm/tpm_tis.c                   |    2 
 include/linux/ima_module.h                   |   33 +
 include/linux/tpm.h                          |   46 ++
 init/Kconfig                                 |    1 
 kernel/module.c                              |    3 
 security/Kconfig                             |    1 
 security/Makefile                            |    2 
 security/ima/Kconfig                         |   94 +++++
 security/ima/Makefile                        |    4 
 security/ima/ima.h                           |  292 ++++++++++++++++
 security/ima/ima_fs.c                        |  464 ++++++++++++++++++++++++++
 security/ima/ima_init.c                      |  182 ++++++++++
 security/ima/ima_lsmhooks.c                  |  165 +++++++++
 security/ima/ima_main.c                      |  465 +++++++++++++++++++++++++++
 security/ima/ima_queue.c                     |  180 ++++++++++
 23 files changed, 2450 insertions(+), 6 deletions(-)

Index: linux-2.6.29.1/Documentation/ima/INSTALL
===================================================================
--- /dev/null
+++ linux-2.6.29.1/Documentation/ima/INSTALL
@@ -0,0 +1,327 @@
+File: INSTALL
+
+Installation File for
+IBM Integrity Measurement Architecture
+
+Copyright IBM (c) April 30 2005, Nov 22 2006
+Author: Reiner Sailer, sailer@watson.ibm.com
+
+For background information, examples, and publications
+   on this topic, please visit:
+   http://www.research.ibm.com/secure_systems_department/projects/tcglinux/
+
+The following instructions work for Fedora Core3 but should be
+generic (you just need a configuration file that works for the kernel)
+
+
+1. Required kernel configuration options
+========================================
+ a)  crypto->SHA1 is (y)
+          [IMA needs sha before modules are loaded]
+
+ b)  security->Default Linux Capabilities (n)
+              [IMA cannot share LSM with the capabilities]
+
+ c)  choose (y) for "TCG run-time Integrity Measurement Architecture"
+              [switchtes IMA measurements on]
+
+ d)  choose (y) for "IMA test mode"
+          This option tells IMA to try to use a real hw TPM or bypass it
+          if in test mode.
+          Choose (y) if you don't have a TPM on your machine or if you
+	  have a TPM on your machine but you want to test IMA and the
+          dependencies first. In any case, make sure you have a TPM
+          driver with the internal kernel interface patch posted to
+          LKML 05/2005. If you choose (n) and IMA can't start up for any
+          reason, it panics the kernel to protect attestation (see below, 8.).
+	  Say (n) only after testing your kernel configuration.
+	  If unsure, say (y).
+
+ e)  If you'd like to compile SELinux and IMA and choose between
+     them at boot-time then configure:
+     NSA SELinux boot paramter
+         NSA SELinux boot parameter default value to (0)
+          (see 3 for kernel command line options)
+
+
+2. Compile and install the new kernel and initrd
+================================================
+make all; make modules_install; make install
+
+
+3. Change kernel command line options
+=====================================
+to activate the Integrity Measurement Architecture at boot-time,
+add: 'ima=1', to deactivate use 'ima=0' (default)
+
+If you have both SELinux and IBM IMA support compiled into
+the kernel, then switch at least one of:
+ 'ima=1 selinux=0' activates the Integrity Measurement Architecture
+ 'ima=0 selinux=1' activates SELinux
+
+You can't activate both because the kernel does not yet
+support LSM stacking.
+
+
+4. Trouble-shooting (restart your system to activate new kernel)
+================================================================
+Use `dmesg |grep IMA` to print IMA status startup information:
+You may find the following output:
+
+   a) you are fine if you see
+   the following lines (if you have TPM hardware):
+   ----
+   IBM Integrity Measurement Architecture (IBM IMA vx.x mm/dd/yyyy).
+       IMA (test mode)
+   ----
+   or the following lines (if you don't have TPM hardware):
+   ----
+   IBM Integrity Measurement Architecture (IBM IMA vx.x mm/dd/yyyy).
+       IMA (test mode)
+       IMA (TPM/BYPASS - no TPM chip found)
+   ----
+
+   b) you need to add the "ima=1" kernel boot paramter if you see:
+   ---
+   IBM Integrity Measurement Architecture (IBM IMA vx.x mm/dd/yyyy).
+       IMA (not enabled in kernel command line) aborting!
+   ---
+
+   c) you need to disable security->Default Linux Capabilities or
+      SELinux  (see configuration requirements) if you see:
+   ---
+   IBM Integrity Measurement Architecture (IBM IMA vx.x mm/dd/yyyy).
+       IMA (test mode)
+       IMA (LSM/not free) aborting!
+   ---
+
+
+5. Measurement example
+======================
+To read the measurements, read from /ima/binary_measurements. They
+have the following format:
+
+1. PCR         ( 32bit) ... number of the PCR into which this measurement was extended
+2. Flags       ( 32bit) ... b31-b16 application flags (label of measurement request)
+                            b15-b04 kernel flags (private field, not currently used by IMA)
+                            b03-b00 measure hook identification (file_mmap, load_module, user write to /ima/measurereq)
+3. Digest      (160bit) ... SHA1 value of the file that was measured
+4. EventSize   ( 32bit) ... length of event data
+5. EventData[n](Eventsize Bytes) ... name of the measured file (with path, except for modules)
+
+/ima/binary_measurements returns always full measurement entries (as many as fit
+the buffer).
+
+We have written a small script formatting and printing the measurements:
+# print_ima_measurements
+
+### PCR HASH                                     [UUUUKKKH] NAME
+  0 010 3A7DC481417E40A9C1CFE8D55E40BE0B740A3748 [00000000] boot_aggregate
+  1 010 BCF30EC20A2DFB900A5C852B73F94CDA5A8F7D36 [00000001] nash
+  2 010 2A954FC4EBAC54BA26909A5AD52AEE5848425C3F [00000001] udev
+  3 010 BD145AE0CFC2021C065AEAE52355FEFEA741A0E2 [00000001] insmod
+  4 010 E6C3BFACC06E1A93B1D7214870EB7757085E44AE [00000002] jbd
+  5 010 26AEC8A3E2E9EE1FF6B67564DEEBFE16D5E77A9D [00000002] ext3
+  6 010 F3B8622110E3979FC4DE41598157C80F5F688AC6 [00000001] init
+  7 010 5ACBD4089B3BBAD951AD13775B41BB951EAE306C [00000001] ld-2.3.5.so
+  8 010 8F4D9E003B9D0851043B95F03514E965E498DD3D [00000001] bash
+  9 010 25DB40D24D8EC0B971BC4FB0E995211FBA16908C [00000001] libtermcap.so.2.0.8
+ 10 010 1E93D1BF0880268EAFFE4818AD81DA39E0C8EA48 [00000001] libdl-2.3.5.so
+ 11 010 99554AD938DB53DDEAF1EFFBE472F05BF5F95878 [00000001] libsepol.so.1
+ 12 010 DCDDF67F5239F6E029CA7FA4C1332A7A109A22E2 [00000001] libc-2.3.5.so
+ 13 010 E9114FC95121F4F04EBEEE500107C80732279F87 [00000001] libselinux.so.1
+ 14 010 7581908B0A16A31D900FC19F4791875FFB60B6C4 [00000001] libnss_files-2.3.5.so
+
+The Flags have following meaning:
+U - Flags(16bit) ... submitted by the appliation in user space whith measurement request (see 7.)
+K - Flags(12bit) ... kernel flags (for future use)
+H - Flags(4bit)  ... Identifies the measurement hook (MMAP=1,MODULE=2,USER=4)
+
+
+
+6. Statistics / IMA FS
+======================
+
+setup:
+
+mount -t imafs none /ima
+
+/ima
+
+READ-Entries:
+/ima/binary_measurements         ... see above
+
+/ima/binary_measurements_count   ... length of the measurement list (entries)
+/ima/changed_files               ... number of files that are measured and changed between measurements
+/ima/clean_inode_hits            ... number of measurement requests that where skipped because of a clean
+                                     flag in the inode (best performance)
+/ima/clean_hashtable_hits        ... number of measurement requests that where skipped because of a clean
+                                     flag in the hashtable entry (second best performance)
+/ima/dirty_hashtable_hits        ... number of measurement requests that required building a SHA1 over the
+                                     file just to realize it did not really change (files are marked dirty
+                                     if a user requests write permission when opening it)
+/ima/kernel_count                ... number of measurements initiated in the kernel (mmap+module)
+/ima/user_count                  ... number of measurements initiated by user applications (imafs/measurereq)
+/ima/violations                  ... number of violations (if /ima/violations != 0, then attestation will fail)
+
+WRITE-Entries:
+/ima/measurereq                  ... write a request from within a user space application into the kernel:
+                                     struct measure_request {
+                                          int fd;          /* file descriptor of open file to be measured */
+                                          u_int16_t label; /* passed through into measurement (see U-flags in 5) */
+                                     }
+
+
+7. Equipping user space applications to measure input files
+===========================================================
+There are files other than executables that might be important to log,
+e.g., batch files (startup scripts), configuration files, certificates etc.
+IMA can only measure regular files (no symlinks, character files etc.) an
+cannot measure files of the imafs.
+
+For this reason, IMA offers the /ima/measurereq interface. User applications
+can use this entry in the following way to measure the file "/etc/any/config":
+
+struct measure_request {
+	int fd;
+	u_int16_t label;
+};
+int fd_mreq, fd_config;
+struct measure_request mr;
+....
+fd_mreq = open("/ima/measurereq", O_WRONLY);
+if (fd_mreq <= 0) <error>
+...
+/* open config file */
+fd_config = open("/etc/any/config", O_RDONLY); /* do not open measured files RW! (see Note) */
+if (fd_config <= 0) <error>
+
+/* measure the file before using it */
+
+mr.fd = fd_config;       /* file descriptor of the file that shall be measured */
+mr.label=3134;           /* any label/tag; it only appears in the measurement entry  */
+
+if (write(fd_mreq, &mr, sizeof(struct measure_request))         -- (A)
+	<error measuring>;                                      |
+/* now use the file -- see NOTE below */                        |- protected
+...                                                             |  section (see Note)
+/* then close the file */                                       |
+close(fd_config)                                               -- (B)
+...
+/* reuse fd_mreq to measure other files if necessary */
+...
+close(fd_mreq);
+
+Note:
+=====
+since the principle of IMA (inherited from TCG) is "measure before load",
+we ensure that the application really reads from the file the data that we measured.
+
+For this reason, we apply detection mechanisms that ensure that the measured file is not
+unnnoticedly written to by anybody before it is closed by the application that initiated
+the measurement. Such writing can happen either by the file (inode) already having writers
+at the time the measurement is initiated ((A) above) or by writers that open the file
+with write/append permission between the measurment request and the last read
+of the file by the application ((A)->(B) above).
+
+If a file is opened read/write while being used in the above <protected section>
+or if a file already has writers when the measurement is being initiated (this also applies
+to measured files opened with write/append permission), then this is a
+Time-of-Measurement-Time-of-Use (ToMToU) race condition violation and leads to invalidating
+the measurement aggregate in the TPM. Once this happens, /ima/violations is incremented
+and remote attestations will notice that the TPM aggregate does not match the measurement list.
+
+
+8. Real-mode versus test-mode IMA
+=================================
+
+If the test option is switched off, then IMA runs in real-mode. A kernel
+configured in IMA real-mode guarantees that the kernel panics as soon
+as it looses its ability to talk to the TPM hardware. This guarantees
+that the kernel (if running) has always the opportunity to invalidate
+the TPM measurement aggregate. For example, if for any reason the TPM
+hardware is not accessible when IMA starts in real-mode, IMA will
+panic the kernel. Finally, IMA does not respect the IMA enable/disable
+command line option when in real-mode.
+
+In test-mode, IMA will merely print an error message and go on without the
+real TPM. Such a system could later on have access to the TPM (e.g., after
+it was corrupted) and recreate arbitrary contents of TPM measurements. Remote
+parties would have difficulty to tell the difference because the chain of trust
+was broken when the originally booted kernel (measured by the boot loader)
+could not extend into the TPM. Finally, IMA can be switched on and off via the
+command line option as long as IMA runs in test mode; such a system, once corrupted,
+could re-create a favourite measurement list and extend the TPM aggregate accordingly.
+Also here, a remote party might have difficulty to predict the actual command line
+parameters the system used during boot.
+
+We recommend running in test-mode first to ensure all drivers etc. work together
+with the local TPM hardware and later on switch over to real-mode (stacking LSM
+is required to retain access to other LSM users).
+
+
+9. Validating the PCR Aggregate
+===============================
+Given a list of measurements (ordered SHA1 values), the PCR aggregate of these
+measurements can be re-calculated as illustrated by the following 'pseudo'-code
+(e.g., using openssl library calls):
+
+/* simulates the PCR aggregate */
+unsigned char PCR[SHA_DIGEST_LENGTH];
+
+/* init with initial PCR content 0..0 */
+memset(PCR,0,SHA_DIGEST_LENGTH);
+
+SHA_CTX c;
+
+/* get the measurements one-by-one from /ima/binary_measurements  (or from a list
+   provided from a remote system) */
+while( (len = read( fd_bin_measurements, event, 69 )) ) {
+	buf = event+4; 		  /* position of SHA1 in the measurement entry */
+	SHA1_Init(&c);
+	SHA1_Update(&c, PCR, SHA_DIGEST_LENGTH); /* PCR = SHA(PCR || MEASUREMENT) */
+	SHA1_Update(&c, buf, SHA_DIGEST_LENGTH);
+	SHA1_Final(PCR, &c);
+}
+
+After reading the latest measurement, the current PCR aggregate is in PCR and can
+be compared with the current TPM PCR aggregate (e.g., cat /sys/class/misc/tpm0/device/pcrs
+and looking at the PCR number #10 in case of the default kernel configuration).
+
+
+
+10. Attestation / Putting the pieces together
+=============================================
+While the PCR aggregate can be validated on the local system, this usually takes
+place on remote systems. The generic protocol for remote attestation using IMA
+would look most probably as follows:
+
+Given:
+(i)   measured System A running IMA (real-mode) and equipped with HW TPM
+(ii)  challenging System B (no IMA or TPM required)
+(iii) a way to retrieve TPM_SIGNATURE_OVER(PCR registers, Nonce), called QUOTE,
+      on System A (see TrouSerS project on sourceforge.net or any other TSS implementation)
+
+1. step: B-->A: NonceB (160bit, non-predictable for A)
+
+2. step: A-->B: TPM_SIGNATURE_OVER{PCR registers, NonceB, Versionetc.}, MeasurementList
+
+3. step: B:
+	a) validate (1) TPM signature; (2) nonce in the signature matches the nonce in the request
+
+      	b) validate Measurement list (see above):
+           b.1 recalculate Aggregate over the Measurement list (see above)
+           b.2 compare aggregate with TPM-signed PCR register holding the aggregate
+           b.3 equal -> success
+               non-equal -> either A was cheating with the list, or the TPM aggregate was
+                            invalidated on system A (cat /ima/violations on system A yields != 0)
+
+       c) validate boot aggregate:
+           Ideally, the boot aggregate -- as a SHA1 over the first 8 PCR registers -- should include
+           measurements of later stages of the boot loader, the kernel, the initrd, and the
+           grub-configuration file. To get there, you need to install a grub boot loader that takes
+           such measurements and extends them into the TPM PCRs.
+
+       d) validate individual measurements; there are many opportunities here to check program
+           versions against service level agreements, make root-kits visible, check configuration
+           files etc.
Index: linux-2.6.29.1/Documentation/ima/integrity_measurements.txt
===================================================================
--- /dev/null
+++ linux-2.6.29.1/Documentation/ima/integrity_measurements.txt
@@ -0,0 +1,87 @@
+The IBM Integrity Measurement Architecture (IMA) offers means to
+securely identify the software that was loaded into a system run-time
+since the last reboot. The IMA builds the information necessary to
+identify the loaded software and provides the basis for services to
+build on top of such information. However, it does not include any
+means that would enable remote parties to extract the information
+itself.
+
+Guarantees: IMA offers "software load-guarantees" in that
+identification of all loaded software is guaranteed to be reflected in
+measurement data and protected in a hardware TPM security chip (if
+available). IMA is non-intrusive and neither disturbs the system, nor
+prevents the system from any actions. However, if running in real
+mode, when the TPM chip is not accessible IMA might require the system
+not to start (for security guarantee reasons).
+
+Limitations: IMA does not detect corruption of software once it is
+loaded into main memory. Instead, it indicates known vulnerabilities
+in such software (e.g., buffer overflow) by securely identifying the
+software at load-time. Only executable files (binaries, libraries,
+kernel modules) are measured by default. However, IMA offers a
+ima file system that enables applications to instruct the kernel to
+measure files that they have opened (/ima/measurereq).
+
+Assumed usage: Verify system installed software configurations and
+system run-time integrity from a secure management location.
+
+Operation: IMA is mainly an LSM module that measures all files mapped
+executable in the kernel as well as kernel modules. It operates after
+the principle >measure before load< as it is known from the Trusted
+Computing Group to identify static system boot configurations and
+extends this principle into the dynamic run-time. To this end, the
+file_mmap security hook builds a SHA1 hash value (our measurement)
+over the whole file, which is probably only partly mapped. These
+measurements are kept in an ordered list inside the kernel. We measure
+executable files only the first time they are loaded and after they
+changed. We use for efficiency dirty-flagging both in the inode of the
+mapped file (re-use) and in the kernel-held measurement list.
+
+Each time a new measurement entry is created and added to the
+measurement list, the hash value of this measurement entry is also
+"extended" into the hardware TPM chip (if available, see INSTALL). All
+these extensions result in a unique aggregate value (160 bit) inside
+the TPM chip, which securely identifies the current measurement list
+inside the kernel.
+
+Since the TPM chip cannot be manipulated from software and since the
+aggregation of the extended values is done in a way that cannot be
+undone (uses HW SHA1), the aggregate in the TPM serves as an integrity
+check value for the current measurement list in the kernel - since the
+kernel can be corrupted if the system software becomes
+compromised. Any software that might corrupt the system has already
+been measured and its measure value has already been aggregated into
+the hardware TPM chip before such software can corrupt the integrity
+measurement architecture itself.
+
+Benefit: Authorized parties can (i) ask the Linux system that runs IMA
+for the kernel-held measurement list and the current signed
+TPM-aggregate, (ii) recalculate the aggregate using the measurement
+list, and (iii) compare the calculated aggregate with the signed TPM
+aggregate. If both aggregates are the same, then the system has
+delivered the correct and latest measurement list. Since each
+measurement of the measurement list uniquely defines a certain
+executable file, the authorized (remote) party can therefore validate
+the software that was loaded into the Linux system since reboot. Many
+applications are possible. The control of the system is fully in the
+hands of the person that controls the Linux client; this person must
+actively offer services to remote parties so they can retrieve the
+measurement list and/or the signed TPM aggregate.
+
+Some of our work shows that IMA is very useful to detect Rootkit
+exploits that totally take over the software of a Linux system but
+cannot hide themselves from contributing to the TPM aggregate and this
+will be detectable from a non-corrupted platform. While the corrupted
+system might not show the Rootkit, a remote party can securely
+identify known bad or unknown software having been loaded into the
+system.
+
+Practice: IMA runs up about 650 measurements when running a Fedora
+Core 3 environment including Gnome desktop. Our system (cron switched
+off) does not accumulate more than this after 18 days uptime. If lots
+of different files (executables, libraries, and kernel modules) are
+executed, then the list may become very long and evaluating the
+measurements might incur increasing overhead. Generally, IMA is useful
+where the executed content is foreseeable and the validating party
+knows which measurements to expect.
+
Index: linux-2.6.29.1/Makefile
===================================================================
--- linux-2.6.29.1.orig/Makefile
+++ linux-2.6.29.1/Makefile
@@ -636,7 +636,7 @@ export mod_strip_cmd
 
 
 ifeq ($(KBUILD_EXTMOD),)
-core-y		+= kernel/ mm/ fs/ ipc/ security/ crypto/ block/
+core-y		+= kernel/ mm/ fs/ ipc/ crypto/ security/ block/
 
 vmlinux-dirs	:= $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
 		     $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
Index: linux-2.6.29.1/drivers/char/tpm/tpm.c
===================================================================
--- linux-2.6.29.1.orig/drivers/char/tpm/tpm.c
+++ linux-2.6.29.1/drivers/char/tpm/tpm.c
@@ -30,6 +30,10 @@
 
 #include "tpm.h"
 
+#define TPM_CHIP_NUM_MASK		0x0000ffff
+#define TPM_CHIP_TYPE_SHIFT		16
+#define READ_PCR_RESULT_SIZE 		30
+
 enum tpm_const {
 	TPM_MINOR = 224,	/* officially assigned */
 	TPM_BUFSIZE = 2048,
@@ -327,6 +331,25 @@ static void user_reader_timeout(unsigned
 	schedule_work(&chip->work);
 }
 
+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 ||
+		       pos->vendor.drv_type == chip_typ) ){
+			spin_unlock(&driver_lock);
+			return pos;
+		}
+	spin_unlock(&driver_lock);
+	return NULL;
+}
+
+
 static void timeout_work(struct work_struct *work)
 {
 	struct tpm_chip *chip = container_of(work, struct tpm_chip, work);
@@ -366,13 +389,16 @@ EXPORT_SYMBOL_GPL(tpm_calc_ordinal_durat
 /*
  * Internal kernel interface to transmit TPM commands
  */
-static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
+ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 			    size_t bufsiz)
 {
 	ssize_t rc;
 	u32 count, ordinal;
 	unsigned long stop;
 
+	if ( !chip )
+		return -ENODEV;
+
 	count = be32_to_cpu(*((__be32 *) (buf + 2)));
 	ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
 	if (count == 0)
@@ -425,6 +451,7 @@ out:
 	mutex_unlock(&chip->tpm_mutex);
 	return rc;
 }
+EXPORT_SYMBOL_GPL(tpm_transmit);
 
 #define TPM_DIGEST_SIZE 20
 #define TPM_ERROR_SIZE 10
@@ -772,6 +799,72 @@ out:
 }
 EXPORT_SYMBOL_GPL(tpm_show_pcrs);
 
+/*
+ * Return 0 on success.  On error pass along error code.
+ * chip_id Upper 2 bytes equal ANY, HW_ONLY or SW_ONLY
+ * Lower 2 bytes equal tpm idx # or AN&
+ * res_buf must fit a TPM_PCR (20 bytes) or NULL if you don't care
+ */
+int tpm_pcr_read( u32 chip_id, int pcr_idx, u8* res_buf, int res_buf_size )
+{
+	 u8 data[READ_PCR_RESULT_SIZE];
+	 int rc;
+	 __be32 index;
+	 int chip_num = chip_id & TPM_CHIP_NUM_MASK;
+	 struct tpm_chip* chip;
+
+	 if ( res_buf && res_buf_size < TPM_DIGEST_SIZE )
+		 return -ENOSPC;
+	 if ( (chip = tpm_chip_lookup( chip_num,
+				       chip_id >> TPM_CHIP_TYPE_SHIFT ) ) == NULL )
+ 		 return -ENODEV;
+	 memcpy(data, pcrread, sizeof(pcrread));
+	 index = cpu_to_be32(pcr_idx);
+	 memcpy(data + 10, &index, 4);
+	 if ((rc = tpm_transmit(chip, data, sizeof(data))) > 0 )
+		 rc = be32_to_cpu(*((u32*)(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 */
+};
+
+/*
+ * Return 0 on success.  On error pass along error code.
+ * chip_id Upper 2 bytes equal ANY, HW_ONLY or SW_ONLY
+ * Lower 2 bytes equal tpm idx # or ANY
+ */
+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;
+
+	if ( (chip = tpm_chip_lookup( chip_num,
+				      chip_id >> TPM_CHIP_TYPE_SHIFT )) == NULL )
+		return -ENODEV;
+
+	memcpy(data, pcrextend, sizeof(pcrextend));
+	index = cpu_to_be32(pcr_idx);
+	memcpy(data + 10, &index, 4);
+	memcpy( data + 14, hash, TPM_DIGEST_SIZE );
+	if ((rc = tpm_transmit(chip, data, sizeof(data))) > 0 )
+		rc = be32_to_cpu(*((u32*)(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.29.1/drivers/char/tpm/tpm.h
===================================================================
--- linux-2.6.29.1.orig/drivers/char/tpm/tpm.h
+++ linux-2.6.29.1/drivers/char/tpm/tpm.h
@@ -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 */
@@ -65,6 +66,7 @@ struct tpm_vendor_specific {
 	void __iomem *iobase;		/* ioremapped address */
 	unsigned long base;		/* TPM base address */
 
+	int drv_type;
 	int irq;
 
 	int region_size;
@@ -139,6 +141,9 @@ extern ssize_t tpm_read(struct file *, c
 extern void tpm_remove_hardware(struct device *);
 extern int tpm_pm_suspend(struct device *, pm_message_t);
 extern int tpm_pm_resume(struct device *);
+/* internal kernel interface */
+extern ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
+			    size_t bufsiz);
 
 #ifdef CONFIG_ACPI
 extern struct dentry ** tpm_bios_log_setup(char *);
Index: linux-2.6.29.1/drivers/char/tpm/tpm_atmel.c
===================================================================
--- linux-2.6.29.1.orig/drivers/char/tpm/tpm_atmel.c
+++ linux-2.6.29.1/drivers/char/tpm/tpm_atmel.c
@@ -233,7 +233,7 @@ static void __exit cleanup_atmel(void)
 	atml_plat_remove();
 }
 
-module_init(init_atmel);
+fs_initcall(init_atmel);
 module_exit(cleanup_atmel);
 
 MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
Index: linux-2.6.29.1/drivers/char/tpm/tpm_infineon.c
===================================================================
--- linux-2.6.29.1.orig/drivers/char/tpm/tpm_infineon.c
+++ linux-2.6.29.1/drivers/char/tpm/tpm_infineon.c
@@ -633,7 +633,7 @@ static void __exit cleanup_inf(void)
 	pnp_unregister_driver(&tpm_inf_pnp_driver);
 }
 
-module_init(init_inf);
+fs_initcall(init_inf);
 module_exit(cleanup_inf);
 
 MODULE_AUTHOR("Marcel Selhorst <m.selhorst@sirrix.com>");
Index: linux-2.6.29.1/drivers/char/tpm/tpm_nsc.c
===================================================================
--- linux-2.6.29.1.orig/drivers/char/tpm/tpm_nsc.c
+++ linux-2.6.29.1/drivers/char/tpm/tpm_nsc.c
@@ -402,7 +402,7 @@ static void __exit cleanup_nsc(void)
 	platform_driver_unregister(&nsc_drv);
 }
 
-module_init(init_nsc);
+fs_initcall(init_nsc);
 module_exit(cleanup_nsc);
 
 MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
Index: linux-2.6.29.1/drivers/char/tpm/tpm_tis.c
===================================================================
--- linux-2.6.29.1.orig/drivers/char/tpm/tpm_tis.c
+++ linux-2.6.29.1/drivers/char/tpm/tpm_tis.c
@@ -716,7 +716,7 @@ static void __exit cleanup_tis(void)
 		pnp_unregister_driver(&tis_pnp_driver);
 }
 
-module_init(init_tis);
+fs_initcall(init_tis);
 module_exit(cleanup_tis);
 MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
 MODULE_DESCRIPTION("TPM Driver");
Index: linux-2.6.29.1/include/linux/ima_module.h
===================================================================
--- /dev/null
+++ linux-2.6.29.1/include/linux/ima_module.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Maintained by: Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * LSM IBM Integrity Measurement Architecture.
+ *
+ * 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_module.h
+ *             define modules measurement hook (no LSM hook) to measure
+ *             modules before they are relocated
+ */
+#ifdef CONFIG_IMA_MEASURE
+extern unsigned char ima_terminating;
+extern void ima_measure_kernel_module(void *start, unsigned long len);
+
+static inline void ima_measure_module(void *start, unsigned long len)
+{
+	if (!ima_terminating)
+		ima_measure_kernel_module(start, len);
+}
+#else
+static inline void ima_measure_module(void *start, unsigned long len)
+{
+}
+#endif
Index: linux-2.6.29.1/include/linux/tpm.h
===================================================================
--- /dev/null
+++ linux-2.6.29.1/include/linux/tpm.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2004 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>
+ *
+ * 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__
+
+/*
+ * 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,
+			int res_buf_size);
+extern int tpm_pcr_extend(u32 chip_id, int pcr_idx, const u8 * hash);
+#endif
+
+#endif
Index: linux-2.6.29.1/init/Kconfig
===================================================================
--- linux-2.6.29.1.orig/init/Kconfig
+++ linux-2.6.29.1/init/Kconfig
@@ -73,6 +73,7 @@ config INIT_ENV_ARG_LIMIT
 
 config LOCALVERSION
 	string "Local version - append to kernel release"
+	default "-ima"
 	help
 	  Append an extra string to the end of your kernel version.
 	  This will show up when you type uname, for example.
Index: linux-2.6.29.1/security/Kconfig
===================================================================
--- linux-2.6.29.1.orig/security/Kconfig
+++ linux-2.6.29.1/security/Kconfig
@@ -134,6 +134,7 @@ config SECURITY_DEFAULT_MMAP_MIN_ADDR
 
 source security/selinux/Kconfig
 source security/smack/Kconfig
+source security/ima/Kconfig
 
 endmenu
 
Index: linux-2.6.29.1/security/Makefile
===================================================================
--- linux-2.6.29.1.orig/security/Makefile
+++ linux-2.6.29.1/security/Makefile
@@ -5,6 +5,7 @@
 obj-$(CONFIG_KEYS)			+= keys/
 subdir-$(CONFIG_SECURITY_SELINUX)	+= selinux
 subdir-$(CONFIG_SECURITY_SMACK)		+= smack
+subdir-$(CONFIG_IMA_MEASURE)		+= ima
 
 # always enable default capabilities
 obj-y		+= commoncap.o
@@ -15,5 +16,6 @@ obj-$(CONFIG_SECURITYFS)		+= inode.o
 # Must precede capability.o in order to stack properly.
 obj-$(CONFIG_SECURITY_SELINUX)		+= selinux/built-in.o
 obj-$(CONFIG_SECURITY_SMACK)		+= smack/built-in.o
+obj-$(CONFIG_IMA_MEASURE)		+= ima/built-in.o
 obj-$(CONFIG_SECURITY_ROOTPLUG)		+= root_plug.o
 obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
Index: linux-2.6.29.1/security/ima/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6.29.1/security/ima/Kconfig
@@ -0,0 +1,94 @@
+#
+# IBM Integrity Measurement Architecture
+#
+
+#menu "TPM-based Integrity Measurement Architecture"
+
+config IMA_MEASURE
+	bool "TCG run-time Integrity Measurement Architecture"
+	depends on SECURITY && (CRYPTO_SHA1=y)
+	help
+		To measure executable code running on this
+		system, say Y. If you say Y, you must disable
+		any other security modules because LSM are
+		currently not stackable.To actually start IMA,
+		you need to set a kernel boot parameter "ima=1".
+		If unsure, say N.
+
+config IMA_TEST_MODE
+	bool "IMA test mode"
+	depends on IMA_MEASURE
+	default y
+	help
+		If you would like to test the measurement
+		architecture but you do not have a TPM hardware
+		on your system, say Y. Otherwise say N. If you say
+		Y and IMA does not find a TPM chip it will just bypass
+		the TPM. If you say N and IMA cannot access the TPM,
+		then IMA will panic.
+		If unsure, say Y.
+
+config IMA_MEASURE_PCR_IDX
+	int "PCR for Aggregate (8<= Index <= 15)"
+	depends on IMA_MEASURE
+	range 8 15
+	default 10
+	help
+		This determines the PCR index used for aggregating the
+		measurement list into the TPM hardware.
+		If unsure, use the default 10.
+
+config IMA_SKIP_BOOT_AGGREGATE
+	bool "Skip Boot Aggregate Creation"
+	depends on IMA_MEASURE
+	help
+		If y, the usual aggregate over the boot PCRs
+		of the TPM is not calculated and not added to
+		the measurement list.
+		If unsure, say N.
+
+config IMA_KMEM_BYPASS_PROTECTION
+	bool "Invalidate PCR on /dev/kmem write"
+	depends on IMA_MEASURE
+	help
+		This setting enforces TPM PCR invalidation if /dev/kmem
+		is written (bypass of measurements possible). Usually,
+		this does not restrict normal systems.
+		If unsure, say Y.
+
+config IMA_RAM_BYPASS_PROTECTION
+	bool "Invalidate PCR on /dev/ram write"
+	depends on IMA_MEASURE
+	help
+		This setting enforces TPM PCR invalidation if /dev/ram
+		is written (bypass of measurements possible). If you use
+		ramdisk, you might have a problem.
+		If unsure, say N.
+
+config IMA_HD_SD_BYPASS_PROTECTION
+	bool "Invalidate PCR on /dev/hdx /dev/sdx write"
+	depends on IMA_MEASURE
+	help
+		This setting enforces TPM PCR invalidation if /dev/hda,
+		/dev/hdb ... or /dev/sda, /dev/sdb ... are written
+		directly (bypass of measurement dirty flagging possible).
+		This requires some changes in /etc/rc.sysinit:
+		   * check filesystems readonly (in rc.sysinit add "-n" fsck
+		     option, remove -a where it appears
+		   * switch off swapping (kernel controlled open on rw)
+		otherwise the PCRs will usually be invalidated.
+		If unsure, say N.
+
+config IMA_MEM_BYPASS_PROTECTION
+	bool "Invalidate PCR on /dev/mem write"
+	depends on IMA_MEASURE
+	help
+		This setting enforces TPM PCR invalidation if /dev/mem
+		is written (bypass of measurements possible). X needs
+		currently to write directly to /dev/mem. For client systems,
+		you might want to chose N here. For server systems not running X,
+		it is safe to say yes.
+		If unsure, say N.
+
+#endmenu
+
Index: linux-2.6.29.1/security/ima/Makefile
===================================================================
--- /dev/null
+++ linux-2.6.29.1/security/ima/Makefile
@@ -0,0 +1,4 @@
+
+obj-$(CONFIG_IMA_MEASURE) += ima_init.o ima_main.o \
+	ima_queue.o ima_lsmhooks.o ima_fs.o
+
Index: linux-2.6.29.1/security/ima/ima.h
===================================================================
--- /dev/null
+++ linux-2.6.29.1/security/ima/ima.h
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Maintained by: Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * LSM IBM Integrity Measurement Architecture.
+ *
+ * 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
+ *             defs
+ */
+#ifndef __LINUX_IMA_H
+#define __LINUX_IMA_H
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <linux/crypto.h>
+#include <linux/security.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)
+
+/* if you cannot tolerate panic for the sake of attestation guarantees,
+ * then redefine IMA_PANIC to, e g., ima_error (see INSTALL documentation) */
+#define IMA_PANIC   \
+	panic
+
+/* set during registering as lsm */
+extern unsigned char ima_terminating;
+extern int ima_enabled;
+extern int ima_used_chip;
+
+void ima_invalidate_pcr(char *);
+
+#define IMA_MEASURE_MODULE_NAME	"IMA"
+#define IMA_EVENT_NAME_LEN_MAX	512
+#define IMA_MAX_EVENT_SIZE 1000
+
+/* file systems we expect to change without
+ * our inode_permission hook being called (nfs, remote fs) */
+#define NFS_SUPER_MAGIC		0x6969
+
+/* file systems we won't measure */
+#define IMA_MAGIC 		0x9999
+
+/* Flags for measurement entries (identifying hook) */
+#define IMA_FLAG_HOOK_MASK		0x0f
+#define IMA_MMAP_MEASURE_FLAG 	0x01
+#define IMA_MODULE_MEASURE_FLAG	0x02
+#define IMA_USER_MEASURE_FLAG 	0x04
+
+#define IMA_HASH_BITS 9
+#define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS)
+#define IMA_HASH_KEY(inode_number) (hash_long((unsigned long)(inode_number), IMA_HASH_BITS))
+#define IMA_SHA_KEY(sha_value) (hash_long( \
+	(unsigned long)(*sha_value), IMA_HASH_BITS));
+
+typedef enum { CLEAN, DIRTY, CHANGED } ima_entry_flags;
+
+/* security structure appended to inodes */
+struct ima_inode {
+	atomic_t measure_count;
+	/* # processes currently using this file in measure-mode */
+	ima_entry_flags dirty;
+};
+
+/* security structure appended to measured files*/
+struct ima_file {
+	char is_measuring;	/* identify fds that are "measuring" */
+};
+
+/* get/store security state information;
+ * if stacking were to be implemented, this would be the place */
+#define ima_get_inode_security(inode) \
+	((struct ima_inode *) ((inode)->i_security))
+
+#define ima_store_inode_security(inode,sec_struct) \
+	((inode)->i_security = (sec_struct))
+
+#define ima_get_file_security(file) \
+	((struct ima_file *) ((file)->f_security))
+
+#define ima_store_file_security(file, sec_struct) \
+	((file)->f_security = (sec_struct))
+
+struct ima_measure_entry {
+	u32 measure_flags;
+	unsigned long inode_nr;
+	dev_t dev_id;
+	ima_entry_flags dirty;
+	u8 digest[20];		/* sha1 measurement hash */
+	struct super_block *super_block;
+	/* super block link (for umount-dirty flagging) */
+	u16 file_len;		/* length */
+	char file_name[1];	/* name(path) + \0 */
+};
+
+struct ima_sha_entry {
+	struct hlist_node hnext;
+	u8 *digest;
+	struct ima_measure_entry *m_entry;
+};
+
+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 */
+int ima_fs_init(void);
+int ima_lsm_init(void);
+void ima_lsm_abort(void);
+int ima_init_eventlog(void);
+void ima_create_htable(void);
+void ima_create_sha_htable(void);
+void ima_invalidate_pcr(char *);
+void ima_measure_mmap_file(struct file *, u32 flags);
+void ima_measure_kernel_module(void *start, unsigned long len);
+int ima_measure_user_file(struct file *file, u32 measure_flags);
+int ima_add_measure_entry(struct ima_measure_entry *entry);
+int ima_measure_dirty_flag_super(struct super_block *);
+int ima_measure_dirty_flag_inode(struct inode *);
+struct ima_queue_entry *ima_lookup_digest_entry(u8 * digest);
+struct ima_measure_entry *ima_lookup_measure_entry(unsigned long, dev_t);
+struct ima_sha_entry *ima_lookup_sha_entry(u8 * sha_value);
+
+/*
+ * used to protect h_table and sha_table
+ */
+extern struct semaphore ima_write_list_mutex;
+
+/* used to protect inode->i_security and file->f_security */
+extern spinlock_t ima_ifsecurity_lock;
+
+struct ima_h_table {
+	atomic_t len;
+	atomic_t user_measure;	/* # measurements requested from userspace */
+	atomic_t kernel_measure;	/* # measurements performed from kernel */
+	atomic_t clean_inode_hits;	/* times we find an inode clean when measuring */
+	atomic_t clean_table_hits;	/* times we find a clean htable hit */
+	atomic_t dirty_table_hits;	/* times we find a dirty htable hit */
+	atomic_t changed_files;	/* times we realize a dirty marked entry really changed */
+	atomic_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;
+
+/*
+ * used to protect writes to sha_table
+ */
+struct ima_sha_table {
+	atomic_t len;
+	unsigned int max_htable_size;
+	struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE];
+	atomic_t queue_len[IMA_MEASURE_HTABLE_SIZE];
+};
+extern struct ima_sha_table ima_sha_htable;
+
+#define MEM_MINOR	1
+#define KMEM_MINOR	2
+#ifdef CONFIG_IMA_KMEM_BYPASS_PROTECTION
+static inline void ima_check_kmem_bypass(struct inode *inode)
+{
+	if ((imajor(inode) == MEM_MAJOR)
+	    && S_ISCHR(inode->i_mode) && (iminor(inode) == KMEM_MINOR))
+		ima_invalidate_pcr("/dev/kmem write violation");
+}
+#else
+static inline void ima_check_kmem_bypass(struct inode *inode)
+{
+	return;
+}
+#endif
+
+#ifdef CONFIG_IMA_MEM_BYPASS_PROTECTION
+static inline void ima_check_mem_bypass(struct inode *inode)
+{
+	if ((imajor(inode) == MEM_MAJOR)
+	    && S_ISCHR(inode->i_mode) && (iminor(inode) == MEM_MINOR))
+		ima_invalidate_pcr("/dev/mmem write violation");
+}
+#else
+static inline void ima_check_mem_bypass(struct inode *inode)
+{
+	return;
+}
+#endif
+
+#ifdef CONFIG_IMA_RAM_BYPASS_PROTECTION
+static inline void ima_check_ram_bypass(struct inode *inode)
+{
+	if ((imajor(inode) == RAMDISK_MAJOR) && S_ISBLK(inode->i_mode))
+		ima_invalidate_pcr("/dev/ram write violation");
+}
+#else
+static inline void ima_check_ram_bypass(struct inode *inode)
+{
+	return;
+}
+#endif
+
+#ifdef CONFIG_IMA_HD_SD_BYPASS_PROTECTION
+static inline void ima_check_hd_sd_bypass(struct inode *inode)
+{
+	if ((imajor(inode) == HD_MAJOR) && S_ISBLK(inode->i_mode))
+		ima_invalidate_pcr("/dev/hdx write violation");
+	else if ((imajor(inode) == SCSI_DISK0_MAJOR) && S_ISBLK(inode->i_mode))
+		ima_invalidate_pcr("/dev/sdx write violation");
+}
+#else
+static inline void ima_check_hd_sd_bypass(struct inode *inode)
+{
+	return;
+}
+#endif
+
+/* configuration options*/
+extern int ima_test_mode;
+extern int ima_skip_boot_aggregate;
+
+static inline void ima_read_configs(void)
+{
+#ifdef CONFIG_IMA_TEST_MODE
+	ima_test_mode = 1;
+#else
+	ima_test_mode = 0;
+#endif
+
+#ifdef CONFIG_IMA_SKIP_BOOT_AGGREGATE
+	ima_skip_boot_aggregate = 1;
+#else
+	ima_skip_boot_aggregate = 0;
+#endif
+}
+
+#define IMA_TPM (((u32)TPM_HW_TYPE) << 16) |(u32)TPM_ANY_NUM
+static inline void ima_extend(const u8 * hash)
+{
+	if (!ima_used_chip)
+		return;
+#ifdef CONFIG_TCG_TPM
+	if (tpm_pcr_extend(IMA_TPM, CONFIG_IMA_MEASURE_PCR_IDX, hash) != 0) {
+		if (!ima_test_mode)
+			IMA_PANIC
+			    ("IMA: Error Communicating to TPM chip and IMA not in test mode!\n");
+		else
+			ima_error("Error Communicating to TPM chip\n");
+	}
+#endif
+}
+
+static inline void ima_pcrread(int pcr_idx, u8 *res_buf, int res_buf_len)
+{
+	if (!ima_used_chip)
+		return;
+#ifdef CONFIG_TCG_TPM
+	if (tpm_pcr_read(IMA_TPM, pcr_idx, res_buf, res_buf_len) != 0) {
+		ima_error("Error Communicating to TPM chip\n");
+	}
+#endif
+}
+
+static inline int have_tpm(void )
+{
+#ifdef CONFIG_TCG_TPM
+	if (tpm_pcr_read(IMA_TPM, 0, NULL, 0) == 0)
+		return 1;
+#endif
+    return 0;
+}
+#endif
Index: linux-2.6.29.1/security/ima/ima_fs.c
===================================================================
--- /dev/null
+++ linux-2.6.29.1/security/ima/ima_fs.c
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Authors:
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * Contributors:
+ * Reiner Sailer <sailer@us.ibm.com>
+ *  Adaptation to RCU lists 07/15/05
+ *  Including ascii runtime and boot measurements  08/15/05
+ *
+ * Maintained by: Reiner Sailer <sailer@watson.ibm.com>
+ *
+ *
+ * LSM IBM Integrity Measurement Architecture.
+ *
+ * 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 imafs
+ *		for reporting measurement log and userspace measure requests
+ */
+
+#include <linux/module.h>
+#include <linux/file.h>
+#include <linux/seq_file.h>
+#include <linux/rculist.h>
+
+#include "ima.h"
+
+struct ima_measure_request {
+	int fd;
+	u16 label;
+};
+
+/* based on selinux pseudo filesystem */
+int ima_measure_user_file(struct file *file, u32 measure_flags);
+
+#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_clean_inode_hits(struct file *filp,
+						char __user * buf,
+						size_t count, loff_t * ppos)
+{
+	return ima_show_htable_value(buf, count, ppos,
+				     &ima_htable.clean_inode_hits);
+}
+
+static struct file_operations ima_htable_clean_inode_hits_ops = {
+	.read = ima_show_htable_clean_inode_hits
+};
+
+static ssize_t ima_show_htable_clean_table_hits(struct file *filp,
+						char __user * buf,
+						size_t count, loff_t * ppos)
+{
+	return ima_show_htable_value(buf, count, ppos,
+				     &ima_htable.clean_table_hits);
+}
+static struct file_operations ima_htable_clean_table_hits_ops = {
+	.read = ima_show_htable_clean_table_hits
+};
+
+static ssize_t ima_show_htable_dirty_table_hits(struct file *filp,
+						char __user * buf,
+						size_t count, loff_t * ppos)
+{
+	return ima_show_htable_value(buf, count, ppos,
+				     &ima_htable.dirty_table_hits);
+}
+static struct file_operations ima_htable_dirty_table_hits_ops = {
+	.read = ima_show_htable_dirty_table_hits
+};
+
+static ssize_t ima_show_htable_changed_files(struct file *filp,
+					     char __user * buf,
+					     size_t count, loff_t * ppos)
+{
+	return ima_show_htable_value(buf, count, ppos, &ima_htable.changed_files);
+}
+static struct file_operations ima_htable_changed_files_ops = {
+	.read = ima_show_htable_changed_files
+};
+
+static ssize_t ima_show_htable_user_measure(struct file *filp,
+					    char __user * buf,
+					    size_t count, loff_t * ppos)
+{
+	return ima_show_htable_value(buf, count, ppos, &ima_htable.user_measure);
+}
+static struct file_operations ima_htable_user_measure_ops = {
+	.read = ima_show_htable_user_measure
+};
+
+static ssize_t ima_show_htable_kernel_measure(struct file *filp,
+					      char __user * buf,
+					      size_t count, loff_t * ppos)
+{
+	return ima_show_htable_value(buf, count, ppos, &ima_htable.kernel_measure);
+}
+static struct file_operations ima_htable_kernel_measure_ops = {
+	.read = ima_show_htable_kernel_measure
+};
+
+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#
+ *       32bit-le=type# << flag
+ *       char[20]=digest
+ *       32bit-le=eventDataSize n
+ *       eventdata[n] = filename
+ *
+ *       flags bits:
+ *         31-16 application flags,
+ *         15-3  kernel flags,
+ *          2-0  hook
+ */
+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;
+	int filename_len;
+	int i;
+	u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX;
+	char data[4];
+
+	/* get entry */
+	qe = list_entry(lpos, struct ima_queue_entry, later);
+	if (qe == NULL)
+		return -1;
+
+	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: eventtype (=flags) */
+	memcpy(data, &e->measure_flags, 4);
+	for (i = 0; i < 4; i++)
+		seq_putc(m, data[i]);
+
+	/* 3rd: digest */
+	for (i = 0; i < 20; i++)
+		seq_putc(m, e->digest[i]);
+
+	/* 4th: eventDataSize */
+	filename_len = strlen(e->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]);
+
+	/* 5th:  filename  */
+
+	for (i = 0; i < filename_len; i++)
+		seq_putc(m, e->file_name[i]);
+
+	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,
+};
+
+/* 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;
+	int i;
+
+	/* get entry */
+	qe = list_entry(lpos, struct ima_queue_entry, later);
+	if (qe == NULL)
+		return -1;
+
+	e = qe->entry;
+	if (e == NULL)
+		return -1;
+
+	/* 1st: PCR used (config option) */
+	seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX);
+
+	/* 2nd: SHA1 */
+	for (i = 0; i < 20; i++)
+		seq_printf(m, "%02x", e->digest[i]);
+
+	/* 3th:  filename <= max + \'0' delimiter */
+	seq_printf(m, " %s\n", e->file_name);
+
+	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 ssize_t ima_measure_write(struct file *file,
+				 const char __user * buf, size_t count,
+				 loff_t * ppos)
+{
+	struct ima_measure_request *mr;
+	struct file *meas_file;
+	int error = -EINVAL;
+	char tmpbuf[sizeof(struct ima_measure_request)];
+
+	atomic_inc(&ima_htable.user_measure);
+	if (count != sizeof(struct ima_measure_request)) {
+		ima_error("illegal request size (%d, expected %d).\n",
+			  (int)count, (int)sizeof(struct ima_measure_request));
+		return -EIO;
+	}
+
+	if (copy_from_user(tmpbuf, buf, count)) {
+		ima_error("trouble copying request\n");
+		return -EIO;
+	}
+
+	mr = (struct ima_measure_request *)tmpbuf;
+	if (mr->fd < 0) {
+		ima_error("bad descriptor request\n");
+		return -EBADF;
+	}
+
+	meas_file = fget(mr->fd);
+	if (!meas_file) {
+		ima_error("could not open request\n");
+		return -EACCES;
+	}
+
+	error = ima_measure_user_file(meas_file,
+				  (u32) (((mr->
+					   label) << 16) | IMA_USER_MEASURE_FLAG));
+	fput(meas_file);
+	if (error) {
+		ima_error("problem measuring request\n");
+		return error;
+	} else
+		return count;
+}
+
+static struct file_operations ima_measure_ops = {
+	.write = ima_measure_write,
+};
+
+static struct dentry *ima_dir;
+static struct dentry *measure_req;
+static struct dentry *binary_runtime_measurements;
+static struct dentry *ascii_runtime_measurements;
+static struct dentry *runtime_measurements_count;
+static struct dentry *clean_inode_hits;
+static struct dentry *clean_hashtable_hits;
+static struct dentry *dirty_hashtable_hits;
+static struct dentry *changed_files;
+static struct dentry *user_count;
+static struct dentry *kernel_count;
+static struct dentry *violations;
+
+int ima_fs_init(void)
+{
+	if (!ima_enabled)
+		return -1;
+
+	ima_dir = securityfs_create_dir("ima", NULL);
+	if (!ima_dir || IS_ERR(ima_dir))
+		return -1;
+
+	measure_req = securityfs_create_file("measurereq", S_IWUSR | S_IWGRP,
+					     ima_dir, NULL, &ima_measure_ops);
+	if (!measure_req || IS_ERR(measure_req))
+		goto out;
+
+	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;
+
+	clean_inode_hits = securityfs_create_file("clean_inode_hits",
+						  S_IRUSR | S_IRGRP, ima_dir,
+						  NULL,
+					&ima_htable_clean_inode_hits_ops);
+	if (!clean_inode_hits || IS_ERR(clean_inode_hits))
+		goto out;
+
+	clean_hashtable_hits = securityfs_create_file("clean_hashtable_hits",
+						      S_IRUSR | S_IRGRP,
+						      ima_dir, NULL,
+					&ima_htable_clean_table_hits_ops);
+	if (!clean_hashtable_hits || IS_ERR(clean_hashtable_hits))
+		goto out;
+
+	dirty_hashtable_hits = securityfs_create_file("dirty_hashtable_hits",
+						      S_IRUSR | S_IRGRP,
+						      ima_dir, NULL,
+					&ima_htable_dirty_table_hits_ops);
+	if (!dirty_hashtable_hits || IS_ERR(dirty_hashtable_hits))
+		goto out;
+
+	changed_files = securityfs_create_file("changed_files",
+					       S_IRUSR | S_IRGRP, ima_dir, NULL,
+					       &ima_htable_changed_files_ops);
+	if (!changed_files || IS_ERR(changed_files))
+		goto out;
+
+	user_count = securityfs_create_file("user_count", S_IRUSR | S_IRGRP,
+					    ima_dir, NULL,
+					    &ima_htable_user_measure_ops);
+	if (!user_count || IS_ERR(user_count))
+		goto out;
+
+	kernel_count = securityfs_create_file("kernel_count",
+					      S_IRUSR | S_IRGRP, ima_dir, NULL,
+					      &ima_htable_kernel_measure_ops);
+
+	if (!kernel_count || IS_ERR(kernel_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;
+	return 0;
+
+out:
+	securityfs_remove(kernel_count);
+	securityfs_remove(user_count);
+	securityfs_remove(changed_files);
+	securityfs_remove(dirty_hashtable_hits);
+	securityfs_remove(clean_hashtable_hits);
+	securityfs_remove(clean_inode_hits);
+	securityfs_remove(runtime_measurements_count);
+	securityfs_remove(ascii_runtime_measurements);
+	securityfs_remove(binary_runtime_measurements);
+	securityfs_remove(measure_req);
+	securityfs_remove(ima_dir);
+    return -1;
+}
Index: linux-2.6.29.1/security/ima/ima_init.c
===================================================================
--- /dev/null
+++ linux-2.6.29.1/security/ima/ima_init.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer      <sailer@watson.ibm.com>
+ *
+ * Contributions:
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ *
+ * Maintained by: Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * LSM IBM Integrity Measurement Architecture.
+ *
+ * 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
+ *             init functions to start up IBM IMA as LSM
+ */
+#include <linux/module.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+
+#include "ima.h"
+
+/* name for boot aggregate entry */
+static char *boot_aggregate_name = "boot_aggregate";
+static const char version[] = "v2.6.29.1 04/13/2009";
+static const char illegal_pcr[20];
+
+/* configuration parameters */
+int ima_test_mode;
+int ima_skip_boot_aggregate;
+
+int ima_enabled = 0;
+int ima_used_chip = 0;
+
+static int __init ima_enabled_setup(char *str)
+{
+	ima_enabled = simple_strtol(str, NULL, 0);
+	return 1;
+}
+
+__setup("ima=", ima_enabled_setup);
+
+static void ima_add_boot_aggregate(void)
+{
+	/* cumulative sha1 the first 8 tpm registers */
+	struct ima_measure_entry *entry;
+	size_t count;
+	int err;
+
+	/* create new entry for boot aggregate */
+	entry = kmalloc(sizeof(struct ima_measure_entry), GFP_ATOMIC);
+	if (entry == NULL) {
+		ima_invalidate_pcr("error allocating new measurement entry");
+		return;
+	}
+	entry->inode_nr = 0;	/* 0,0 are special (no files) */
+	entry->dev_id = 0;
+	entry->measure_flags = 0;
+	entry->dirty = DIRTY;
+	entry->super_block = NULL;
+	memset(entry->digest, 0, 20);
+	count = strlen(boot_aggregate_name);
+	if (count > IMA_EVENT_NAME_LEN_MAX)
+		count = IMA_EVENT_NAME_LEN_MAX;
+	memcpy(entry->file_name, boot_aggregate_name, count);
+	entry->file_name[count] = '\0';	/* ez-print */
+	if (ima_used_chip) {
+		int i;
+		u8 pcr_i[20];
+		struct crypto_hash *tfm;
+		struct hash_desc desc;
+		struct scatterlist sg;
+
+		tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
+		if (!tfm || IS_ERR(tfm)) {
+			kfree(entry);
+			ima_error("Digest init failed ERROR.\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);
+	if (err < 0) {
+		kfree(entry);
+		if (err != -EEXIST)
+			ima_invalidate_pcr("error adding boot aggregate");
+	}
+}
+
+/* general invalidation function called by the measurement code */
+void ima_invalidate_pcr(char *cause)
+{
+	/* extend pcr with illegal digest (no digest yields 0) */
+	/* extending twice is obviously flagging the exception condition... */
+	ima_error("INVALIDATING PCR AGGREGATE. Cause=%s.\n", cause);
+	ima_extend(illegal_pcr);
+	ima_extend(illegal_pcr);
+	atomic_inc(&ima_htable.violations);	/* can overflow into 0; this is an indicator only */
+}
+
+static int ima_measure_init(void)
+{
+	printk(KERN_INFO "IBM Integrity Measurement Architecture"
+	       " (IBM IMA %s).\n", version);
+	ima_read_configs();
+
+	/* check pre-conditions and dependencies */
+	if (!ima_test_mode)
+		ima_enabled = 1;	/* unconditionally */
+	else {
+		if (!ima_enabled) {
+			printk(KERN_INFO "    IMA (not enabled in kernel"
+			       " command line) aborting!\n");
+			return 0;
+		}
+		printk(KERN_INFO "    IMA (test mode)\n");
+	}
+
+	/*
+	 * if (init_eventlog())
+	 *   return -EFAULT;
+	 * done at each read to catch post boot events written into
+	 */
+
+	if (have_tpm())
+		ima_used_chip = 1;
+	if (!ima_used_chip) {
+		if (ima_test_mode)
+			printk(KERN_INFO "    IMA (TPM/BYPASS - no TPM chip"
+			       " found)\n");
+		else
+			/* no way to invalidate pcr and inform remote party */
+			IMA_PANIC("IMA: TPM/no support and IMA not in test"
+				  " mode!\n");
+	}
+	if (ima_lsm_init()) {
+		ima_enabled = 0;
+		printk(KERN_INFO "    IMA (LSM/not free) aborting!\n");
+		return -EFAULT;
+	}
+	ima_create_htable();	/* for measurements */
+	ima_create_sha_htable();
+
+	if (ima_fs_init()) {
+		printk(KERN_INFO "    IMA (SecurityFS/Registering failed) aborting!\n");
+ 		/* leave hash tables hanging (no code to remove measurements) */
+		return -1;
+	}
+
+	/* boot aggregate must be very first entry */
+	if (!ima_skip_boot_aggregate)
+		ima_add_boot_aggregate();
+
+	/* module measurement hook becomes hot */
+	ima_terminating = 0;
+
+	return 0;
+}
+
+__initcall(ima_measure_init);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Reiner Sailer <sailer@watson.ibm.com>");
+MODULE_DESCRIPTION("Run-time LSM-based IBM Integrity Measurement Architecture");
Index: linux-2.6.29.1/security/ima/ima_lsmhooks.c
===================================================================
--- /dev/null
+++ linux-2.6.29.1/security/ima/ima_lsmhooks.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Maintained by: Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * LSM IBM Integrity Measurement Architecture.
+ *
+ * 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_lsmhooks.c
+ *             implements Linux Security Modules hooks that call into
+ *             into the measurement functions
+ */
+#include <linux/module.h>
+#include <asm/mman.h>
+#include <linux/mount.h>
+
+#include "ima.h"
+
+DEFINE_SPINLOCK(ima_ifsecurity_lock);
+
+/*
+ * if set, then hooks do nothing
+ *(controls non-lsm module hook as well)
+ */
+unsigned char ima_terminating = 1;
+
+/* measure files mmapped with exec permission */
+static int ima_file_mmap(struct file *file, unsigned long reqprot, unsigned long prot,
+		  unsigned long flags, unsigned long addr, unsigned long addr_only)
+{
+	/* filter interesting calls that actually map files executable */
+	if (!(reqprot & PROT_EXEC))
+		return 0;
+
+	/* now check protection  */
+	if (reqprot & MAP_SHARED & PROT_EXEC & PROT_WRITE) {
+		ima_error("MMAP protection flag error!!!\n");
+		ima_invalidate_pcr("MMAP protection flag violation!");
+	}
+	atomic_inc(&ima_htable.kernel_measure);
+	ima_measure_mmap_file(file, (u32) IMA_MMAP_MEASURE_FLAG);
+	/* IMA is non-intrusive, so we always map */
+	return 0;
+}
+
+/* dirty flags on open with MAY_WRITE|MAY_APPEND */
+static int ima_inode_permission(struct inode *inode, int mask)
+{
+	struct ima_inode *i_security;
+	struct ima_measure_entry *entry;
+
+	/* dirty-flagging applies to changing files */
+	if (!(mask & (MAY_WRITE | MAY_APPEND)) || !inode)
+		return 0;
+
+	/* general checks against bypassing dirty-flagging */
+	ima_check_kmem_bypass(inode);
+	ima_check_mem_bypass(inode);
+	ima_check_ram_bypass(inode);
+	ima_check_hd_sd_bypass(inode);
+
+	/* files that are written to are usually not executed (measured),
+	   optimize this path */
+	entry = ima_lookup_measure_entry(inode->i_ino, inode->i_rdev);
+	if (!entry)
+		return 0;
+	if (entry->dirty == CLEAN)
+		entry->dirty = DIRTY;
+	/* dirty flag inode if it stayed around longer than the file was open */
+	spin_lock(&ima_ifsecurity_lock);
+	i_security = ima_get_inode_security(inode);
+	if (!i_security) {
+		spin_unlock(&ima_ifsecurity_lock);
+		return 0;
+	}
+	if (atomic_read(&(i_security->measure_count))) {
+		/* write permission on measured file was granted! */
+		ima_invalidate_pcr("ToMToU violation");
+		ima_error("VIOLATION: Writing to measured file (%s) while it"
+			  "is being used!\n", entry->file_name);
+	}
+	if (i_security->dirty == CLEAN)
+		i_security->dirty = DIRTY;
+
+	spin_unlock(&ima_ifsecurity_lock);
+	return 0;
+}
+
+/* dirty flag files on an umounted file system */
+static int ima_sb_umount(struct vfsmount *mnt, int flags)
+{
+	/* mark all clean entries with this superblock dirty */
+	struct ima_queue_entry *qe;
+	struct super_block *super = mnt->mnt_sb;
+	struct ima_measure_entry *entry;
+
+	down(&ima_write_list_mutex);
+	list_for_each_entry_rcu(qe, &ima_measurements, later) {
+		entry = qe->entry;
+		if (entry->super_block == super && entry->dirty == CLEAN)
+			entry->dirty = DIRTY;
+	}
+	up(&ima_write_list_mutex);
+
+	return 0;
+}
+
+/* free security structure if applies */
+static void ima_inode_free_security(struct inode *inode)
+{
+	struct ima_inode *i_security;
+	spin_lock(&ima_ifsecurity_lock);
+	i_security = ima_get_inode_security(inode);
+	if (i_security) {
+		ima_store_inode_security(inode, NULL);
+		kfree(i_security);
+	}
+	spin_unlock(&ima_ifsecurity_lock);
+}
+
+static void ima_file_free_security(struct file *file)
+{
+	struct ima_file *f_security;
+	struct ima_inode *i_security = NULL;
+	spin_lock(&ima_ifsecurity_lock);
+	f_security = ima_get_file_security(file);
+	if (!f_security) {
+		spin_unlock(&ima_ifsecurity_lock);
+		return;
+	}
+	/* decrease measure count if file is measured */
+	i_security = ima_get_inode_security(file->f_dentry->d_inode);
+	if (i_security && f_security->is_measuring)
+		atomic_dec(&i_security->measure_count);
+	kfree(f_security);
+	ima_store_file_security(file, NULL);
+	spin_unlock(&ima_ifsecurity_lock);
+}
+
+static struct security_operations ima_ops = {
+	.file_mmap = ima_file_mmap,
+	.file_free_security = ima_file_free_security,
+	.inode_permission = ima_inode_permission,
+	.inode_free_security = ima_inode_free_security,
+	.sb_umount = ima_sb_umount
+};
+
+/* IMA requires early initialization in order measure
+   all executables etc from the very beginning. */
+int ima_lsm_init(void)
+{
+	if (register_security(&ima_ops)) {
+		ima_invalidate_pcr("IMA: Unable to register with kernel.\n");
+		return -1;
+	}
+    return 0;
+}
+
Index: linux-2.6.29.1/security/ima/ima_main.c
===================================================================
--- /dev/null
+++ linux-2.6.29.1/security/ima/ima_main.c
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2005 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>
+ * Maintained by: Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * LSM IBM Integrity Measurement Architecture.
+ *
+ * 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 run-time measurements
+ */
+#include <linux/module.h>
+#include <linux/file.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+
+#include "ima.h"
+
+extern spinlock_t ima_ifsecurity_lock;
+
+/*
+ * Returns the dirty flag setting for an inode
+ * (nfs, since we don't control changes)
+ */
+static inline ima_entry_flags get_default_dirty_setting(struct inode *inode)
+{
+	switch (inode->i_sb->s_magic) {
+	case NFS_SUPER_MAGIC:
+		return DIRTY;	/* dirty */
+		break;
+	default:		/* local fs etc. */
+		return CLEAN;	/* clean */
+	}
+}
+
+/*
+ * indicate whether this is an IMA file and must therefore be skipped,
+ *   or whether it is a regular file and may be measured.
+ * returns >0 if measurement must be skipped
+ * returns =0 if measurement allowed
+ */
+static inline int skip_measurement(struct inode *inode)
+{
+	if (S_ISREG(inode->i_mode) && (inode->i_sb->s_magic != IMA_MAGIC))
+		return 0;
+	else
+		return 1;
+}
+
+/*  measures new file and adds it to measurement list */
+static struct ima_measure_entry *ima_do_measure_file(struct file *file,
+					     struct inode *inode,
+					     struct ima_inode *i_security)
+{
+	struct path p;
+	mm_segment_t oldfs;
+	int error = -ENOMEM;
+	loff_t offset = 0;
+	size_t count;
+	struct crypto_hash *tfm;
+	struct hash_desc desc;
+	struct scatterlist sg;
+	struct ima_measure_entry *entry;
+	char *bufp;
+	char filepathbuf[IMA_EVENT_NAME_LEN_MAX];
+	const unsigned char *filepathp;
+
+	/* create read buffer */
+	bufp = kmalloc(PAGE_SIZE, GFP_ATOMIC);
+	if (!bufp) {
+		ima_error("no memory for read buffer\n");
+		goto out;	/* invalidate pcr */
+	}
+	/* create new entry and measure */
+	p.mnt = file->f_vfsmnt;
+	p.dentry = file->f_dentry;
+	filepathp = (const unsigned char *)
+	    d_path(&p, filepathbuf,
+		   IMA_EVENT_NAME_LEN_MAX);
+	if (filepathp < 0) {
+		filepathp = file->f_dentry->d_name.name;
+		count = file->f_dentry->d_name.len + 1;
+		if (count > IMA_EVENT_NAME_LEN_MAX)
+			count = IMA_EVENT_NAME_LEN_MAX;
+	} else {
+		count = strlen(filepathp);
+	}
+	entry = kmalloc(sizeof(struct ima_measure_entry) + count, GFP_ATOMIC);
+	if (!entry) {
+		ima_error("error allocating new measurement entry");
+		kfree(bufp);
+		goto out;	/* invalidate pcr */
+	}
+	entry->inode_nr = inode->i_ino;
+	entry->dev_id = inode->i_rdev;
+	entry->dirty = get_default_dirty_setting(inode);
+	entry->super_block = inode->i_sb;
+	memcpy(entry->file_name, filepathp, count);
+	entry->file_name[count] = '\0';	/* ez-print for long path case */
+	entry->file_len = count;
+	error = 0;
+
+	/* second add sha1 over file contents */
+	/* init context */
+	tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
+	if (!tfm || IS_ERR(tfm)) {
+		ima_error("Digest init failed ERROR.\n");
+		goto outm;
+	}
+	desc.tfm = tfm;
+	desc.flags = 0;
+	crypto_hash_init(&desc);
+	/* set fs so that kernel writes into kernel segment */
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	do {
+		count = (file->f_op->read) (file, (char __user *)bufp,
+					    PAGE_SIZE, &offset);
+		if (count < 0) {
+			error = count;
+			ima_error("Error reading from file (%d)\n", error);
+			goto outf;
+		}
+		/* update hash with this part */
+		sg_init_one(&sg, (u8 *) bufp, count);
+		crypto_hash_update(&desc, &sg, count);
+	} while (count);
+	set_fs(oldfs);
+
+	/* complete hash */
+	crypto_hash_final(&desc, entry->digest);
+	crypto_free_hash(tfm);
+
+	i_security->dirty = entry->dirty;
+	kfree(bufp);
+	return (entry);
+
+	/* error exits */
+      outf:
+	set_fs(oldfs);
+      outm:
+	kfree(entry);
+	kfree(bufp);
+      out:
+	return (NULL);
+}
+
+/* measure memory (kernel module; still the exact copy of the object file) */
+static int ima_do_measure_memory(void *start, unsigned long len, u32 measure_flags,
+		      char *name)
+{
+	struct crypto_hash *tfm;
+	struct hash_desc desc;
+	struct scatterlist sg;
+	u8 mem_digest[64];
+	char *bufp;
+	int error = 0;
+	struct ima_measure_entry *entry;
+	int count;
+
+	/* create read buffer */
+	bufp = kmalloc(PAGE_SIZE, GFP_ATOMIC);
+	if (!bufp) {
+		ima_error("no memory for read buffer\n");
+		return -ENOMEM; /* invalidate pcr */
+	}
+	/* init context */
+	tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
+	if (!tfm || IS_ERR(tfm)) {
+		ima_invalidate_pcr("No SHA1 available");
+		return -EFAULT;
+	}
+	desc.tfm = tfm;
+	desc.flags = 0;
+	crypto_hash_init(&desc);
+	do {
+		if (len < PAGE_SIZE)
+			count = len;
+		else
+			count = PAGE_SIZE;
+
+		memcpy(bufp, start, count);
+		sg_init_one(&sg, bufp, count);
+		crypto_hash_update(&desc, &sg, count);
+		start += count;
+		len -= count;
+	} while (len);
+	/* final round */
+	crypto_hash_final(&desc, mem_digest);
+	crypto_free_hash(tfm);
+	kfree(bufp);
+
+	if (!ima_lookup_sha_entry(mem_digest)) {
+		/* create new entry and measure */
+		entry = kmalloc(sizeof(struct ima_measure_entry), GFP_ATOMIC);
+		if (!entry) {
+			ima_invalidate_pcr("OUT OF MEMORY");
+			return (-EFAULT);	/* why not -ENOMEM? */
+		}
+		entry->inode_nr = 0;	/* special entries, no file entries */
+		entry->dev_id = 0;
+		entry->dirty = DIRTY;
+		entry->super_block = NULL;
+		memcpy(entry->digest, mem_digest, 20);
+		count = strlen(name);
+		if (count > IMA_EVENT_NAME_LEN_MAX)
+			count = IMA_EVENT_NAME_LEN_MAX;
+		strncpy(entry->file_name, name, count);
+		entry->file_name[count] = '\0';
+		entry->measure_flags = measure_flags;
+		error = ima_add_measure_entry(entry);
+		if (error < 0) {
+			kfree(entry);
+			if (error != -EEXIST)
+				ima_invalidate_pcr
+				    ("error adding measurement entry");
+		}
+	}
+	/* else we already have this hash value from an exec/file that was running earlier */
+	return 0;
+}
+
+/*
+ * XXX: how can we get rid of this function and use the "static" one in
+ * kernel/modules.c ?
+ */
+static unsigned int find_mod_sec(Elf_Ehdr * hdr, Elf_Shdr * sechdrs,
+				 const char *secstrings, const char *name)
+{
+	unsigned int i;
+	for (i = 1; i < hdr->e_shnum; i++)
+		/* Alloc bit cleared means "here is nothing to look for (ignore)" */
+		if ((sechdrs[i].sh_flags & SHF_ALLOC)
+		    && strcmp(secstrings + sechdrs[i].sh_name, name) == 0)
+			return i;
+	return 0;
+}
+
+/* Measure kernel modules in-memory before relocation */
+void ima_measure_kernel_module(void *start, unsigned long len)
+{
+	Elf_Ehdr *hdr;
+	Elf_Shdr *sechdrs;
+	struct module *mod;
+	unsigned int modindex;
+	char *secstrings;
+
+	/* get the module name for entry */
+	hdr = (Elf_Ehdr *) start;
+	sechdrs = (void *)hdr + hdr->e_shoff;
+	secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+	modindex = find_mod_sec(hdr, sechdrs, secstrings,
+				".gnu.linkonce.this_module");
+	if (!modindex) {
+		ima_error("No module found in object\n");
+		ima_invalidate_pcr("Module without name?!");
+		return;
+	}
+	mod = (void *)((size_t) hdr + sechdrs[modindex].sh_offset);
+	atomic_inc(&ima_htable.kernel_measure);	/* CHECK */
+	ima_do_measure_memory(start, len, (u32) IMA_MODULE_MEASURE_FLAG, mod->name);
+	return;
+}
+
+
+static void ima_measure_file(struct file *file, u32 measure_flags,
+			 struct inode *inode, struct ima_inode *i_security)
+{
+	struct ima_measure_entry *entry, *new_entry;
+
+	entry = ima_lookup_measure_entry(inode->i_ino, inode->i_rdev);
+	if ((entry != NULL) && (entry->dirty == CLEAN)) {
+		i_security->dirty = CLEAN;
+		atomic_inc(&ima_htable.clean_table_hits);
+		return;
+	}
+	new_entry = ima_do_measure_file(file, inode, i_security);
+	/* now we adjust the entry table:
+	 * -- if there was no entry, we just add the new one
+	 * -- if there was one but different hash, we add the new one
+	 * -- if there was one and same hash, we clear dirty bit on existing one
+	 */
+	if (!new_entry) {
+		/* internal error, make sure attestation fails from now on */
+		ima_invalidate_pcr("error measuring file");
+		return;
+	}
+	new_entry->measure_flags = measure_flags;
+	if (entry == NULL) {	/* no old entry for this inode found */
+		/* add if this hash is new (i.e., no copy measured yet) */
+		if (!ima_lookup_sha_entry(new_entry->digest)) {
+			int err = ima_add_measure_entry(new_entry);
+			if (err < 0) {
+				kfree(new_entry);
+				if (err != -EEXIST)
+					ima_invalidate_pcr
+					    ("error adding measurement entry");
+				else
+					atomic_inc(&ima_htable.dirty_table_hits);
+			}
+		} else
+			atomic_inc(&ima_htable.dirty_table_hits);
+		return;
+	}
+	/* old entry exists (!= clean) */
+	if (!memcmp(entry->digest, new_entry->digest, 20)) {
+		/* set with default (no clean-flag for nfs) */
+		entry->dirty = get_default_dirty_setting(inode);
+		i_security->dirty = entry->dirty;
+		atomic_inc(&ima_htable.dirty_table_hits);
+		kfree(new_entry);
+	} else {
+		/* dirty and look whether to add new entry */
+		entry->dirty = CHANGED;
+		atomic_inc(&ima_htable.changed_files);
+		if (!ima_lookup_sha_entry(new_entry->digest)) {
+			int err = ima_add_measure_entry(new_entry);
+			if (err < 0) {
+				kfree(new_entry);
+				if (err != -EEXIST)
+					ima_invalidate_pcr
+					    ("error adding measurement entry");
+			}
+		}
+	}
+}
+
+/* Measure user space file descriptor, protect file from being
+ * written until all measureing processes have closed the file
+ */
+int ima_measure_user_file(struct file *file, u32 measure_flags)
+{
+	struct inode *inode;
+	struct ima_file *f_security = NULL;
+	struct ima_inode *i_security = NULL;
+
+	if (!file || !file->f_op || !file->f_dentry || !file->f_dentry->d_inode)
+		return -EACCES;
+
+	inode = file->f_dentry->d_inode;
+
+	/* here we skip unnecessary measurements */
+	if (skip_measurement(inode))
+		return -EACCES;
+
+	/* a) if there is already a writer on this file --> error! */
+	if (atomic_read(&(inode->i_writecount)) > 0) {
+		struct ima_measure_entry *entry;
+		ima_invalidate_pcr("ToMToU violation");
+		entry = ima_lookup_measure_entry(inode->i_ino, inode->i_rdev);
+		ima_error("VIOLATION: Measured file (%s) has writers!\n",
+			  (entry != NULL) ? entry->file_name :
+			  "most likely measuring file opened rw");
+		return -EACCES;
+	}
+	inode = file->f_dentry->d_inode;
+	spin_lock(&ima_ifsecurity_lock);
+	/*
+	 * mark this file as measuring (increases measurement-refcount
+	 *      on inode)
+	 */
+	f_security = ima_get_file_security(file);
+	if (f_security) {
+		i_security = ima_get_inode_security(file->f_dentry->d_inode);
+		if (i_security == NULL) {
+			/* check the codepaths - is this possible? */
+			ima_invalidate_pcr
+			    ("Internal error (f_security not free but no i_security).\n");
+			spin_unlock(&ima_ifsecurity_lock);
+			return -EFAULT;
+		}
+	} else {
+		/* create f_security and if necessary i_security */
+		f_security = kmalloc(sizeof(struct ima_file), GFP_ATOMIC);
+		if (f_security == NULL) {
+			ima_invalidate_pcr("out of memory error");
+			spin_unlock(&ima_ifsecurity_lock);
+			return -ENOMEM;
+		} else {
+			f_security->is_measuring = 1;
+			ima_store_file_security(file, f_security);
+		}
+		/* we maintain an inode copy of clean etc. to speed up clean hits */
+		i_security = ima_get_inode_security(inode);
+		if (i_security != NULL)
+			atomic_inc(&(i_security->measure_count));
+		else {
+			i_security =
+			    kmalloc(sizeof(struct ima_inode), GFP_ATOMIC);
+			if (i_security == NULL) {
+				spin_unlock(&ima_ifsecurity_lock);
+				ima_invalidate_pcr("out of memory error");
+				return -EFAULT;
+			} else {
+				i_security->dirty = DIRTY;
+				/* is reset later after measuring file */
+				atomic_set(&(i_security->measure_count), 1);
+				ima_store_inode_security(inode, i_security);
+			}
+		}
+	}
+	spin_unlock(&ima_ifsecurity_lock);
+
+	/* catch most cases */
+	if (i_security->dirty == CLEAN)
+		atomic_inc(&ima_htable.clean_inode_hits);
+	else
+		ima_measure_file(file, measure_flags, inode, i_security);
+	return 0;
+}
+
+/* Measure files mapped as executable */
+void ima_measure_mmap_file(struct file *file, u32 measure_flags)
+{
+	struct inode *inode;
+	struct ima_inode *i_security = NULL;
+
+	if (!file || !file->f_op || !file->f_dentry || !file->f_dentry->d_inode)
+		return;
+
+	inode = file->f_dentry->d_inode;
+
+	/* here we skip non-allowed measurements */
+	if (skip_measurement(inode)) {
+		return;
+	}
+	/* if there is already a writer on this file --> error! */
+	if (atomic_read(&(inode->i_writecount)) > 0) {
+		ima_invalidate_pcr("Measured file has writers.");
+		return;
+	}
+	/* we maintain an inode copy of clean etc. to speed up clean hits */
+	spin_lock(&ima_ifsecurity_lock);
+	i_security = ima_get_inode_security(inode);
+	if (!i_security) {
+		i_security = kmalloc(sizeof(struct ima_inode), GFP_ATOMIC);
+		if (i_security == NULL) {
+			spin_unlock(&ima_ifsecurity_lock);
+			ima_invalidate_pcr("out of memory error");
+			return;
+		} else {
+			i_security->dirty = DIRTY;
+			/* is reset later after measuring file */
+			atomic_set(&(i_security->measure_count), 0);
+			ima_store_inode_security(inode, i_security);
+		}
+	}
+
+	spin_unlock(&ima_ifsecurity_lock);
+	/* catch most cases */
+	if (i_security->dirty == CLEAN)
+		atomic_inc(&ima_htable.clean_inode_hits);
+	else
+		ima_measure_file(file, measure_flags, inode, i_security);
+}
Index: linux-2.6.29.1/security/ima/ima_queue.c
===================================================================
--- /dev/null
+++ linux-2.6.29.1/security/ima/ima_queue.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Serge Hallyn <serue@us.ibm.com>
+ *
+ * Maintained by: Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * LSM IBM Integrity Measurement Architecture.
+ *
+ * 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 for run-time measurement
+ *             functions based on SHA1
+ */
+#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) */
+struct ima_sha_table ima_sha_htable;	/* key: hash (after 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.
+ */
+DECLARE_MUTEX(ima_write_list_mutex);
+
+void ima_create_sha_htable(void)
+{
+	int i;
+
+	atomic_set(&ima_sha_htable.len, 0);
+	ima_sha_htable.max_htable_size = IMA_MEASURE_HTABLE_SIZE;
+	for (i = 0; i < ima_sha_htable.max_htable_size; i++) {
+		INIT_HLIST_HEAD(&ima_sha_htable.queue[i]);
+		atomic_set(&ima_sha_htable.queue_len[i], 0);
+	}
+}
+
+void ima_create_htable(void)
+{
+	int i;
+
+	INIT_LIST_HEAD(&ima_measurements);
+	atomic_set(&ima_htable.len, 0);
+	atomic_set(&ima_htable.user_measure, 0);
+	atomic_set(&ima_htable.kernel_measure, 0);
+	atomic_set(&ima_htable.clean_inode_hits, 0);
+	atomic_set(&ima_htable.clean_table_hits, 0);
+	atomic_set(&ima_htable.dirty_table_hits, 0);
+	atomic_set(&ima_htable.changed_files, 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);
+	}
+
+	init_MUTEX(&ima_write_list_mutex);
+}
+
+/*
+ * also sets clean and dirty table hit marks
+ */
+struct ima_measure_entry *ima_lookup_measure_entry(unsigned long inode_number,
+					      dev_t dev_number)
+{
+	struct ima_queue_entry *tmp, *qe = NULL;
+	struct ima_measure_entry *me = NULL;
+	struct hlist_node *pos;
+
+	/* fill in later */
+	rcu_read_lock();
+	hlist_for_each_entry_rcu(tmp, pos,
+				 &ima_htable.queue[IMA_HASH_KEY(inode_number)], hnext) {
+		if (tmp->entry->inode_nr == inode_number &&
+		    tmp->entry->dev_id == dev_number) {
+			qe = tmp;
+			break;
+		}
+	}
+	if (!qe)
+		goto out;
+
+	if (qe->entry->dirty != CLEAN)
+		atomic_inc(&ima_htable.dirty_table_hits);
+	else
+		atomic_inc(&ima_htable.clean_table_hits);
+
+	me = qe->entry;
+
+      out:
+	rcu_read_unlock();
+	return me;
+}
+
+struct ima_sha_entry *ima_lookup_sha_entry(u8 * sha_value)
+{
+	struct ima_sha_entry *se, *ret = NULL;
+	unsigned int key;
+	struct hlist_node *pos;
+
+	key = IMA_SHA_KEY(sha_value);
+	rcu_read_lock();
+	hlist_for_each_entry_rcu(se, pos, &ima_sha_htable.queue[key], hnext) {
+		if (memcmp(se->digest, sha_value, 20) == 0) {
+			ret = se;
+			break;
+		}
+	}
+	rcu_read_unlock();
+	return ret;
+}
+
+/* Called with ima_queue_lock held */
+static int ima_add_sha_entry(struct ima_measure_entry *entry)
+{
+	struct ima_sha_entry *se;
+	unsigned int key;
+
+	key = IMA_SHA_KEY(entry->digest);
+	se = kmalloc(sizeof(struct ima_sha_entry), GFP_ATOMIC);
+	if (se == NULL) {
+		ima_error("OUT OF MEMORY ERROR creating queue entry.\n");
+		return -ENOMEM;
+	}
+	se->m_entry = entry;
+	se->digest = entry->digest;
+
+	hlist_add_head_rcu(&se->hnext, &ima_sha_htable.queue[key]);
+	atomic_inc(&ima_sha_htable.queue_len[key]);
+	atomic_inc(&ima_sha_htable.len);
+	return 0;
+}
+
+int ima_add_measure_entry(struct ima_measure_entry *entry)
+{
+	unsigned int key = IMA_HASH_KEY(entry->inode_nr);
+	struct ima_queue_entry *qe;
+	int error = 0;
+
+	down(&ima_write_list_mutex);
+	if (ima_lookup_sha_entry(entry->digest)) {
+		error = -EEXIST;
+		goto out;
+	}
+	qe = kmalloc(sizeof(struct ima_queue_entry), GFP_ATOMIC);
+	if (qe == NULL) {
+		ima_error("OUT OF MEMORY in %s.\n", __func__);
+		error = -ENOMEM;
+		goto out;
+	}
+	qe->entry = entry;
+
+	/* we need rcu since readers won't use spin-lock */
+	hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]);
+	atomic_inc(&ima_htable.queue_len[key]);
+
+	INIT_LIST_HEAD(&qe->later);
+	list_add_tail_rcu(&qe->later, &ima_measurements);
+
+	atomic_inc(&ima_htable.len);
+	if (ima_add_sha_entry(entry)) {
+		error = -ENOMEM;
+		goto out;
+	}
+	ima_extend(entry->digest);
+out:
+	up(&ima_write_list_mutex);
+	return error;
+}
Index: linux-2.6.29.1/kernel/module.c
===================================================================
--- linux-2.6.29.1.orig/kernel/module.c
+++ linux-2.6.29.1/kernel/module.c
@@ -51,6 +51,7 @@
 #include <linux/tracepoint.h>
 #include <linux/ftrace.h>
 #include <linux/async.h>
+#include <linux/ima_module.h>
 /***** TOMOYO Linux start. *****/
 #include <linux/tomoyo.h>
 /***** TOMOYO Linux end. *****/
@@ -1912,6 +1913,8 @@ static noinline struct module *load_modu
 	if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr))
 		goto truncated;
 
+	ima_measure_module((void *)hdr, len);
+
 	/* Convenience variables */
 	sechdrs = (void *)hdr + hdr->e_shoff;
 	secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
