[RFC PATCH 1/2] refactor IMA template code into separate files.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This RFC patch refactors the existing IMA template code, to enable the addition
of a separate TLV formatted measurement list. There are few changes to the
code, other than moving the template specific code into template specific files.

Signed-off-by: David Safford <david.safford@xxxxxx>
---
 security/integrity/ima/Kconfig                |  17 +-
 security/integrity/ima/Makefile               |   6 +-
 security/integrity/ima/ima.h                  |  85 ++-----
 security/integrity/ima/ima_api.c              | 113 +--------
 security/integrity/ima/ima_crypto.c           |  88 ++-----
 security/integrity/ima/ima_fs.c               | 207 +---------------
 security/integrity/ima/ima_fs_template.c      | 230 ++++++++++++++++++
 security/integrity/ima/ima_init.c             |  10 +-
 security/integrity/ima/ima_main.c             |  43 +---
 security/integrity/ima/ima_policy.c           |   6 +-
 .../ima/{ima_queue.c => ima_queue_template.c} |  21 +-
 security/integrity/ima/ima_template.c         | 219 ++++++++++++++++-
 security/integrity/ima/ima_template.h         |  88 +++++++
 13 files changed, 630 insertions(+), 503 deletions(-)
 create mode 100644 security/integrity/ima/ima_fs_template.c
 rename security/integrity/ima/{ima_queue.c => ima_queue_template.c} (90%)
 create mode 100644 security/integrity/ima/ima_template.h

diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index 6a8f67714c83..5d549356ffd3 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -57,10 +57,23 @@ config IMA_LSM_RULES
 	help
 	  Disabling this option will disregard LSM based policy rules.
 
+choice
+	prompt "IMA measurement list format"
+	default IMA_LIST_TEMPLATE
+	depends on IMA
+	help
+	  Choose the original template format or new TLV format.
+
+	config IMA_LIST_TEMPLATE
+		bool "template"
+	config IMA_LIST_TLV
+		bool "tlv"
+endchoice
+
 choice
 	prompt "Default template"
 	default IMA_NG_TEMPLATE
-	depends on IMA
+	depends on IMA && IMA_LIST_TEMPLATE
 	help
 	  Select the default IMA measurement template.
 
@@ -80,7 +93,7 @@ endchoice
 
 config IMA_DEFAULT_TEMPLATE
 	string
-	depends on IMA
+	depends on IMA && IMA_LIST_TEMPLATE
 	default "ima" if IMA_TEMPLATE
 	default "ima-ng" if IMA_NG_TEMPLATE
 	default "ima-sig" if IMA_SIG_TEMPLATE
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
index d921dc4f9eb0..7845a7c9d6c7 100644
--- a/security/integrity/ima/Makefile
+++ b/security/integrity/ima/Makefile
@@ -6,8 +6,10 @@
 
 obj-$(CONFIG_IMA) += ima.o
 
-ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
-	 ima_policy.o ima_template.o ima_template_lib.o
+ima-y := ima_fs.o ima_init.o ima_main.o ima_crypto.o ima_api.o ima_policy.o
 ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
 ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
+ima-$(CONFIG_IMA_LIST_TLV) += ima_queue_tlv.o ima_tlv.o ima_fs_tlv.o
+ima-$(CONFIG_IMA_LIST_TEMPLATE) += ima_queue_template.o ima_template.o \
+				ima_fs_template.o ima_template_lib.o
 obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 354bb5716ce3..b11b5769a446 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -32,6 +32,7 @@
 #include <asm/ima.h>
 #endif
 
+
 enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_BINARY_NO_FIELD_LEN,
 		     IMA_SHOW_BINARY_OLD_STRING_FMT, IMA_SHOW_ASCII };
 enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
@@ -43,12 +44,6 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
 #define IMA_HASH_BITS 9
 #define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS)
 
-#define IMA_TEMPLATE_FIELD_ID_MAX_LEN	16
-#define IMA_TEMPLATE_NUM_FIELDS_MAX	15
-
-#define IMA_TEMPLATE_IMA_NAME "ima"
-#define IMA_TEMPLATE_IMA_FMT "d|n"
-
 /* current content of the policy */
 extern int ima_policy_flag;
 
@@ -67,43 +62,7 @@ struct ima_event_data {
 	const char *violation;
 };
 
-/* IMA template field data definition */
-struct ima_field_data {
-	u8 *data;
-	u32 len;
-};
-
-/* IMA template field definition */
-struct ima_template_field {
-	const char field_id[IMA_TEMPLATE_FIELD_ID_MAX_LEN];
-	int (*field_init)(struct ima_event_data *event_data,
-			  struct ima_field_data *field_data);
-	void (*field_show)(struct seq_file *m, enum ima_show_type show,
-			   struct ima_field_data *field_data);
-};
-
-/* IMA template descriptor definition */
-struct ima_template_desc {
-	struct list_head list;
-	char *name;
-	char *fmt;
-	int num_fields;
-	struct ima_template_field **fields;
-};
-
-struct ima_template_entry {
-	int pcr;
-	u8 digest[TPM_DIGEST_SIZE];	/* sha1 or md5 measurement hash */
-	struct ima_template_desc *template_desc; /* template descriptor */
-	u32 template_data_len;
-	struct ima_field_data template_data[0];	/* template related data */
-};
 
-struct ima_queue_entry {
-	struct hlist_node hnext;	/* place in hash collision list */
-	struct list_head later;		/* place in ima_measurements list */
-	struct ima_template_entry *entry;
-};
 extern struct list_head ima_measurements;	/* list of all measurements */
 
 /* Some details preceding the binary serialized measurement list */
@@ -130,15 +89,23 @@ extern bool ima_canonical_fmt;
 /* Internal IMA function definitions */
 int ima_init(void);
 int ima_fs_init(void);
-int ima_add_template_entry(struct ima_template_entry *entry, int violation,
-			   const char *op, struct inode *inode,
-			   const unsigned char *filename);
+int ima_fs_record_init(void);
+int ima_hash_setup(char *str);
+extern int ima_hash_algo;
+extern int ima_hash_setup_done;
+extern struct dentry *ima_dir;
+extern struct dentry *binary_runtime_measurements;
+extern struct dentry *tlv_runtime_measurements;
+extern struct dentry *ascii_runtime_measurements;
+extern const struct file_operations ima_measurements_ops;
+extern const struct file_operations ima_ascii_measurements_ops;
+extern void ima_measurements_stop(struct seq_file *m, void *v);
+struct crypto_shash *ima_alloc_tfm(enum hash_algo algo);
+void ima_free_tfm(struct crypto_shash *tfm);
 int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash);
 int ima_calc_buffer_hash(const void *buf, loff_t len,
 			 struct ima_digest_data *hash);
-int ima_calc_field_array_hash(struct ima_field_data *field_data,
-			      struct ima_template_desc *desc, int num_fields,
-			      struct ima_digest_data *hash);
+int ima_pcr_extend(const u8 *hash, int pcr);
 int __init ima_calc_boot_aggregate(struct ima_digest_data *hash);
 void ima_add_violation(struct file *file, const unsigned char *filename,
 		       struct integrity_iint_cache *iint,
@@ -146,13 +113,13 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
 int ima_init_crypto(void);
 void ima_putc(struct seq_file *m, void *data, int datalen);
 void ima_print_digest(struct seq_file *m, u8 *digest, u32 size);
-struct ima_template_desc *ima_template_desc_current(void);
-int ima_restore_measurement_entry(struct ima_template_entry *entry);
+
 int ima_restore_measurement_list(loff_t bufsize, void *buf);
 int ima_measurements_show(struct seq_file *m, void *v);
+int ima_ascii_measurements_show(struct seq_file *m, void *v);
+void *ima_measurements_start(struct seq_file *m, loff_t *pos);
+void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos);
 unsigned long ima_get_binary_runtime_size(void);
-int ima_init_template(void);
-void ima_init_template_list(void);
 
 /*
  * used to protect h_table and sha_table
@@ -190,6 +157,12 @@ enum ima_hooks {
 	__ima_hooks(__ima_hook_enumify)
 };
 
+#ifdef CONFIG_IMA_LIST_TLV
+#include "ima_tlv.h"
+#else
+#include "ima_template.h"
+#endif
+
 /* LIM API function definitions */
 int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
 		   int mask, enum ima_hooks func, int *pcr);
@@ -203,12 +176,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
 			   int xattr_len, int pcr);
 void ima_audit_measurement(struct integrity_iint_cache *iint,
 			   const unsigned char *filename);
-int ima_alloc_init_template(struct ima_event_data *event_data,
-			    struct ima_template_entry **entry);
-int ima_store_template(struct ima_template_entry *entry, int violation,
-		       struct inode *inode,
-		       const unsigned char *filename, int pcr);
-void ima_free_template_entry(struct ima_template_entry *entry);
+
 const char *ima_d_path(const struct path *path, char **pathbuf, char *filename);
 
 /* IMA policy related functions */
@@ -318,5 +286,4 @@ static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
 #else
 #define	POLICY_FILE_FLAGS	S_IWUSR
 #endif /* CONFIG_IMA_READ_POLICY */
-
 #endif /* __LINUX_IMA_H */
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index a02c5acfd403..6443777d0fa1 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -22,103 +22,6 @@
 
 #include "ima.h"
 
-/*
- * ima_free_template_entry - free an existing template entry
- */
-void ima_free_template_entry(struct ima_template_entry *entry)
-{
-	int i;
-
-	for (i = 0; i < entry->template_desc->num_fields; i++)
-		kfree(entry->template_data[i].data);
-
-	kfree(entry);
-}
-
-/*
- * ima_alloc_init_template - create and initialize a new template entry
- */
-int ima_alloc_init_template(struct ima_event_data *event_data,
-			    struct ima_template_entry **entry)
-{
-	struct ima_template_desc *template_desc = ima_template_desc_current();
-	int i, result = 0;
-
-	*entry = kzalloc(sizeof(**entry) + template_desc->num_fields *
-			 sizeof(struct ima_field_data), GFP_NOFS);
-	if (!*entry)
-		return -ENOMEM;
-
-	(*entry)->template_desc = template_desc;
-	for (i = 0; i < template_desc->num_fields; i++) {
-		struct ima_template_field *field = template_desc->fields[i];
-		u32 len;
-
-		result = field->field_init(event_data,
-					   &((*entry)->template_data[i]));
-		if (result != 0)
-			goto out;
-
-		len = (*entry)->template_data[i].len;
-		(*entry)->template_data_len += sizeof(len);
-		(*entry)->template_data_len += len;
-	}
-	return 0;
-out:
-	ima_free_template_entry(*entry);
-	*entry = NULL;
-	return result;
-}
-
-/*
- * ima_store_template - store ima template measurements
- *
- * 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
- */
-int ima_store_template(struct ima_template_entry *entry,
-		       int violation, struct inode *inode,
-		       const unsigned char *filename, int pcr)
-{
-	static const char op[] = "add_template_measure";
-	static const char audit_cause[] = "hashing_error";
-	char *template_name = entry->template_desc->name;
-	int result;
-	struct {
-		struct ima_digest_data hdr;
-		char digest[TPM_DIGEST_SIZE];
-	} hash;
-
-	if (!violation) {
-		int num_fields = entry->template_desc->num_fields;
-
-		/* this function uses default algo */
-		hash.hdr.algo = HASH_ALGO_SHA1;
-		result = ima_calc_field_array_hash(&entry->template_data[0],
-						   entry->template_desc,
-						   num_fields, &hash.hdr);
-		if (result < 0) {
-			integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
-					    template_name, op,
-					    audit_cause, result, 0);
-			return result;
-		}
-		memcpy(entry->digest, hash.hdr.digest, hash.hdr.length);
-	}
-	entry->pcr = pcr;
-	result = ima_add_template_entry(entry, violation, op, inode, filename);
-	return result;
-}
 
 /*
  * ima_add_violation - add violation to measurement list.
@@ -131,7 +34,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
 		       struct integrity_iint_cache *iint,
 		       const char *op, const char *cause)
 {
-	struct ima_template_entry *entry;
+	struct ima_record_entry *entry;
 	struct inode *inode = file_inode(file);
 	struct ima_event_data event_data = {iint, file, filename, NULL, 0,
 					    cause};
@@ -141,15 +44,15 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
 	/* can overflow, only indicator */
 	atomic_long_inc(&ima_htable.violations);
 
-	result = ima_alloc_init_template(&event_data, &entry);
+	result = ima_alloc_init_record(&event_data, &entry);
 	if (result < 0) {
 		result = -ENOMEM;
 		goto err_out;
 	}
-	result = ima_store_template(entry, violation, inode,
+	result = ima_store_record(entry, violation, inode,
 				    filename, CONFIG_IMA_MEASURE_PCR_IDX);
 	if (result < 0)
-		ima_free_template_entry(entry);
+		ima_free_record_entry(entry);
 err_out:
 	integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
 			    op, cause, result, 0);
@@ -283,7 +186,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
 	static const char audit_cause[] = "ENOMEM";
 	int result = -ENOMEM;
 	struct inode *inode = file_inode(file);
-	struct ima_template_entry *entry;
+	struct ima_record_entry *entry;
 	struct ima_event_data event_data = {iint, file, filename, xattr_value,
 					    xattr_len, NULL};
 	int violation = 0;
@@ -291,20 +194,20 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
 	if (iint->measured_pcrs & (0x1 << pcr))
 		return;
 
-	result = ima_alloc_init_template(&event_data, &entry);
+	result = ima_alloc_init_record(&event_data, &entry);
 	if (result < 0) {
 		integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
 				    op, audit_cause, result, 0);
 		return;
 	}
 
-	result = ima_store_template(entry, violation, inode, filename, pcr);
+	result = ima_store_record(entry, violation, inode, filename, pcr);
 	if ((!result || result == -EEXIST) && !(file->f_flags & O_DIRECT)) {
 		iint->flags |= IMA_MEASURED;
 		iint->measured_pcrs |= (0x1 << pcr);
 	}
 	if (result < 0)
-		ima_free_template_entry(entry);
+		ima_free_record_entry(entry);
 }
 
 void ima_audit_measurement(struct integrity_iint_cache *iint,
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index 4e085a17124f..3f34af6c48ce 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -78,7 +78,7 @@ int __init ima_init_crypto(void)
 	return 0;
 }
 
-static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo)
+struct crypto_shash *ima_alloc_tfm(enum hash_algo algo)
 {
 	struct crypto_shash *tfm = ima_shash_tfm;
 	int rc;
@@ -97,7 +97,7 @@ static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo)
 	return tfm;
 }
 
-static void ima_free_tfm(struct crypto_shash *tfm)
+void ima_free_tfm(struct crypto_shash *tfm)
 {
 	if (tfm != ima_shash_tfm)
 		crypto_free_shash(tfm);
@@ -442,74 +442,7 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
 	return ima_calc_file_shash(file, hash);
 }
 
-/*
- * Calculate the hash of template data
- */
-static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data,
-					 struct ima_template_desc *td,
-					 int num_fields,
-					 struct ima_digest_data *hash,
-					 struct crypto_shash *tfm)
-{
-	SHASH_DESC_ON_STACK(shash, tfm);
-	int rc, i;
-
-	shash->tfm = tfm;
-	shash->flags = 0;
-
-	hash->length = crypto_shash_digestsize(tfm);
-
-	rc = crypto_shash_init(shash);
-	if (rc != 0)
-		return rc;
-
-	for (i = 0; i < num_fields; i++) {
-		u8 buffer[IMA_EVENT_NAME_LEN_MAX + 1] = { 0 };
-		u8 *data_to_hash = field_data[i].data;
-		u32 datalen = field_data[i].len;
-		u32 datalen_to_hash =
-		    !ima_canonical_fmt ? datalen : cpu_to_le32(datalen);
-
-		if (strcmp(td->name, IMA_TEMPLATE_IMA_NAME) != 0) {
-			rc = crypto_shash_update(shash,
-						(const u8 *) &datalen_to_hash,
-						sizeof(datalen_to_hash));
-			if (rc)
-				break;
-		} else if (strcmp(td->fields[i]->field_id, "n") == 0) {
-			memcpy(buffer, data_to_hash, datalen);
-			data_to_hash = buffer;
-			datalen = IMA_EVENT_NAME_LEN_MAX + 1;
-		}
-		rc = crypto_shash_update(shash, data_to_hash, datalen);
-		if (rc)
-			break;
-	}
-
-	if (!rc)
-		rc = crypto_shash_final(shash, hash->digest);
-
-	return rc;
-}
-
-int ima_calc_field_array_hash(struct ima_field_data *field_data,
-			      struct ima_template_desc *desc, int num_fields,
-			      struct ima_digest_data *hash)
-{
-	struct crypto_shash *tfm;
-	int rc;
-
-	tfm = ima_alloc_tfm(hash->algo);
-	if (IS_ERR(tfm))
-		return PTR_ERR(tfm);
-
-	rc = ima_calc_field_array_hash_tfm(field_data, desc, num_fields,
-					   hash, tfm);
-
-	ima_free_tfm(tfm);
 
-	return rc;
-}
 
 static int calc_buffer_ahash_atfm(const void *buf, loff_t len,
 				  struct ima_digest_data *hash,
@@ -638,6 +571,23 @@ static void __init ima_pcrread(int idx, u8 *pcr)
 		pr_err("Error Communicating to TPM chip\n");
 }
 
+/*
+ * FIXME - This still assumes SHA1
+ */
+int ima_pcr_extend(const u8 *hash, int pcr)
+{
+	int result = 0;
+
+	if (!ima_used_chip)
+		return result;
+
+	result = tpm_pcr_extend(NULL, pcr, hash);
+	if (result != 0)
+		pr_err("Error Communicating to TPM chip, result: %d\n", result);
+	return result;
+}
+
+
 /*
  * Calculate the boot aggregate hash
  */
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index ae9d5c766a3c..f3375ca5b268 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -31,16 +31,6 @@
 
 static DEFINE_MUTEX(ima_write_mutex);
 
-bool ima_canonical_fmt;
-static int __init default_canonical_fmt_setup(char *str)
-{
-#ifdef __BIG_ENDIAN
-	ima_canonical_fmt = true;
-#endif
-	return 1;
-}
-__setup("ima_canonical_fmt", default_canonical_fmt_setup);
-
 static int valid_policy = 1;
 #define TMPBUFLEN 12
 static ssize_t ima_show_htable_value(char __user *buf, size_t count,
@@ -78,40 +68,8 @@ static const struct file_operations ima_measurements_count_ops = {
 	.llseek = generic_file_llseek,
 };
 
-/* returns pointer to hlist_node */
-static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
-{
-	loff_t l = *pos;
-	struct ima_queue_entry *qe;
-
-	/* we need a lock since pos could point beyond last element */
-	rcu_read_lock();
-	list_for_each_entry_rcu(qe, &ima_measurements, later) {
-		if (!l--) {
-			rcu_read_unlock();
-			return qe;
-		}
-	}
-	rcu_read_unlock();
-	return NULL;
-}
 
-static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
-{
-	struct ima_queue_entry *qe = v;
-
-	/* lock protects when reading beyond last element
-	 * against concurrent list-extension
-	 */
-	rcu_read_lock();
-	qe = list_entry_rcu(qe->later.next, struct ima_queue_entry, later);
-	rcu_read_unlock();
-	(*pos)++;
-
-	return (&qe->later == &ima_measurements) ? NULL : qe;
-}
-
-static void ima_measurements_stop(struct seq_file *m, void *v)
+void ima_measurements_stop(struct seq_file *m, void *v)
 {
 }
 
@@ -121,75 +79,6 @@ void ima_putc(struct seq_file *m, void *data, int datalen)
 		seq_putc(m, *(char *)data++);
 }
 
-/* print format:
- *       32bit-le=pcr#
- *       char[20]=template digest
- *       32bit-le=template name size
- *       char[n]=template name
- *       [eventdata length]
- *       eventdata[n]=template specific data
- */
-int ima_measurements_show(struct seq_file *m, void *v)
-{
-	/* the list never shrinks, so we don't need a lock here */
-	struct ima_queue_entry *qe = v;
-	struct ima_template_entry *e;
-	char *template_name;
-	u32 pcr, namelen, template_data_len; /* temporary fields */
-	bool is_ima_template = false;
-	int i;
-
-	/* get entry */
-	e = qe->entry;
-	if (e == NULL)
-		return -1;
-
-	template_name = (e->template_desc->name[0] != '\0') ?
-	    e->template_desc->name : e->template_desc->fmt;
-
-	/*
-	 * 1st: PCRIndex
-	 * PCR used defaults to the same (config option) in
-	 * little-endian format, unless set in policy
-	 */
-	pcr = !ima_canonical_fmt ? e->pcr : cpu_to_le32(e->pcr);
-	ima_putc(m, &pcr, sizeof(e->pcr));
-
-	/* 2nd: template digest */
-	ima_putc(m, e->digest, TPM_DIGEST_SIZE);
-
-	/* 3rd: template name size */
-	namelen = !ima_canonical_fmt ? strlen(template_name) :
-		cpu_to_le32(strlen(template_name));
-	ima_putc(m, &namelen, sizeof(namelen));
-
-	/* 4th:  template name */
-	ima_putc(m, template_name, strlen(template_name));
-
-	/* 5th:  template length (except for 'ima' template) */
-	if (strcmp(template_name, IMA_TEMPLATE_IMA_NAME) == 0)
-		is_ima_template = true;
-
-	if (!is_ima_template) {
-		template_data_len = !ima_canonical_fmt ? e->template_data_len :
-			cpu_to_le32(e->template_data_len);
-		ima_putc(m, &template_data_len, sizeof(e->template_data_len));
-	}
-
-	/* 6th:  template specific data */
-	for (i = 0; i < e->template_desc->num_fields; i++) {
-		enum ima_show_type show = IMA_SHOW_BINARY;
-		struct ima_template_field *field = e->template_desc->fields[i];
-
-		if (is_ima_template && strcmp(field->field_id, "d") == 0)
-			show = IMA_SHOW_BINARY_NO_FIELD_LEN;
-		if (is_ima_template && strcmp(field->field_id, "n") == 0)
-			show = IMA_SHOW_BINARY_OLD_STRING_FMT;
-		field->field_show(m, show, &e->template_data[i]);
-	}
-	return 0;
-}
-
 static const struct seq_operations ima_measurments_seqops = {
 	.start = ima_measurements_start,
 	.next = ima_measurements_next,
@@ -202,79 +91,13 @@ static int ima_measurements_open(struct inode *inode, struct file *file)
 	return seq_open(file, &ima_measurments_seqops);
 }
 
-static const struct file_operations ima_measurements_ops = {
+const struct file_operations ima_measurements_ops = {
 	.open = ima_measurements_open,
 	.read = seq_read,
 	.llseek = seq_lseek,
 	.release = seq_release,
 };
 
-void ima_print_digest(struct seq_file *m, u8 *digest, u32 size)
-{
-	u32 i;
-
-	for (i = 0; i < size; i++)
-		seq_printf(m, "%02x", *(digest + i));
-}
-
-/* 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 ima_queue_entry *qe = v;
-	struct ima_template_entry *e;
-	char *template_name;
-	int i;
-
-	/* get entry */
-	e = qe->entry;
-	if (e == NULL)
-		return -1;
-
-	template_name = (e->template_desc->name[0] != '\0') ?
-	    e->template_desc->name : e->template_desc->fmt;
-
-	/* 1st: PCR used (config option) */
-	seq_printf(m, "%2d ", e->pcr);
-
-	/* 2nd: SHA1 template hash */
-	ima_print_digest(m, e->digest, TPM_DIGEST_SIZE);
-
-	/* 3th:  template name */
-	seq_printf(m, " %s", template_name);
-
-	/* 4th:  template specific data */
-	for (i = 0; i < e->template_desc->num_fields; i++) {
-		seq_puts(m, " ");
-		if (e->template_data[i].len == 0)
-			continue;
-
-		e->template_desc->fields[i]->field_show(m, IMA_SHOW_ASCII,
-							&e->template_data[i]);
-	}
-	seq_puts(m, "\n");
-	return 0;
-}
-
-static const 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 const 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_read_policy(char *path)
 {
 	void *data;
@@ -358,13 +181,14 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
 	return result;
 }
 
-static struct dentry *ima_dir;
-static struct dentry *ima_symlink;
-static struct dentry *binary_runtime_measurements;
-static struct dentry *ascii_runtime_measurements;
+struct dentry *ima_dir;
+struct dentry *binary_runtime_measurements;
+struct dentry *tlv_runtime_measurements;
+struct dentry *ascii_runtime_measurements;
 static struct dentry *runtime_measurements_count;
 static struct dentry *violations;
 static struct dentry *ima_policy;
+static struct dentry *ima_symlink;
 
 enum ima_fs_flags {
 	IMA_FS_BUSY,
@@ -463,20 +287,6 @@ int __init ima_fs_init(void)
 	if (IS_ERR(ima_symlink))
 		goto out;
 
-	binary_runtime_measurements =
-	    securityfs_create_file("binary_runtime_measurements",
-				   S_IRUSR | S_IRGRP, ima_dir, NULL,
-				   &ima_measurements_ops);
-	if (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 (IS_ERR(ascii_runtime_measurements))
-		goto out;
-
 	runtime_measurements_count =
 	    securityfs_create_file("runtime_measurements_count",
 				   S_IRUSR | S_IRGRP, ima_dir, NULL,
@@ -496,6 +306,9 @@ int __init ima_fs_init(void)
 	if (IS_ERR(ima_policy))
 		goto out;
 
+	if (ima_fs_record_init())
+		goto out;
+
 	return 0;
 out:
 	securityfs_remove(violations);
diff --git a/security/integrity/ima/ima_fs_template.c b/security/integrity/ima/ima_fs_template.c
new file mode 100644
index 000000000000..55e961461392
--- /dev/null
+++ b/security/integrity/ima/ima_fs_template.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Kylene Hall <kjhall@xxxxxxxxxx>
+ * Reiner Sailer <sailer@xxxxxxxxxx>
+ * Mimi Zohar <zohar@xxxxxxxxxx>
+ *
+ * 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
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/fcntl.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/rculist.h>
+#include <linux/rcupdate.h>
+#include <linux/parser.h>
+#include <linux/vmalloc.h>
+
+#include "ima.h"
+
+bool ima_canonical_fmt;
+static int __init default_canonical_fmt_setup(char *str)
+{
+#ifdef __BIG_ENDIAN
+	ima_canonical_fmt = true;
+#endif
+	return 1;
+}
+__setup("ima_canonical_fmt", default_canonical_fmt_setup);
+
+/* returns pointer to hlist_node */
+void *ima_measurements_start(struct seq_file *m, loff_t *pos)
+{
+	loff_t l = *pos;
+	struct ima_queue_entry *qe;
+
+	/* we need a lock since pos could point beyond last element */
+	rcu_read_lock();
+	list_for_each_entry_rcu(qe, &ima_measurements, later) {
+		if (!l--) {
+			rcu_read_unlock();
+			return qe;
+		}
+	}
+	rcu_read_unlock();
+	return NULL;
+}
+
+void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	struct ima_queue_entry *qe = v;
+
+	/* lock protects when reading beyond last element
+	 * against concurrent list-extension
+	 */
+	rcu_read_lock();
+	qe = list_entry_rcu(qe->later.next, struct ima_queue_entry, later);
+	rcu_read_unlock();
+	(*pos)++;
+
+	return (&qe->later == &ima_measurements) ? NULL : qe;
+}
+
+
+/* print format:
+ *       32bit-le=pcr#
+ *       char[20]=template digest
+ *       32bit-le=template name size
+ *       char[n]=template name
+ *       [eventdata length]
+ *       eventdata[n]=template specific data
+ */
+int ima_measurements_show(struct seq_file *m, void *v)
+{
+	/* the list never shrinks, so we don't need a lock here */
+	struct ima_queue_entry *qe = v;
+	struct ima_record_entry *e;
+	char *template_name;
+	u32 pcr, namelen, template_data_len; /* temporary fields */
+	bool is_ima_template = false;
+	int i;
+
+	/* get entry */
+	e = qe->entry;
+	if (e == NULL)
+		return -1;
+
+	template_name = (e->template_desc->name[0] != '\0') ?
+	    e->template_desc->name : e->template_desc->fmt;
+
+	/*
+	 * 1st: PCRIndex
+	 * PCR used defaults to the same (config option) in
+	 * little-endian format, unless set in policy
+	 */
+	pcr = !ima_canonical_fmt ? e->pcr : cpu_to_le32(e->pcr);
+	ima_putc(m, &pcr, sizeof(e->pcr));
+
+	/* 2nd: template digest */
+	ima_putc(m, e->digest, TPM_DIGEST_SIZE);
+
+	/* 3rd: template name size */
+	namelen = !ima_canonical_fmt ? strlen(template_name) :
+		cpu_to_le32(strlen(template_name));
+	ima_putc(m, &namelen, sizeof(namelen));
+
+	/* 4th:  template name */
+	ima_putc(m, template_name, strlen(template_name));
+
+	/* 5th:  template length (except for 'ima' template) */
+	if (strcmp(template_name, IMA_TEMPLATE_IMA_NAME) == 0)
+		is_ima_template = true;
+
+	if (!is_ima_template) {
+		template_data_len = !ima_canonical_fmt ? e->template_data_len :
+			cpu_to_le32(e->template_data_len);
+		ima_putc(m, &template_data_len, sizeof(e->template_data_len));
+	}
+
+	/* 6th:  template specific data */
+	for (i = 0; i < e->template_desc->num_fields; i++) {
+		enum ima_show_type show = IMA_SHOW_BINARY;
+		struct ima_template_field *field = e->template_desc->fields[i];
+
+		if (is_ima_template && strcmp(field->field_id, "d") == 0)
+			show = IMA_SHOW_BINARY_NO_FIELD_LEN;
+		if (is_ima_template && strcmp(field->field_id, "n") == 0)
+			show = IMA_SHOW_BINARY_OLD_STRING_FMT;
+		field->field_show(m, show, &e->template_data[i]);
+	}
+	return 0;
+}
+
+
+void ima_print_digest(struct seq_file *m, u8 *digest, u32 size)
+{
+	u32 i;
+
+	for (i = 0; i < size; i++)
+		seq_printf(m, "%02x", *(digest + i));
+}
+
+/* print in ascii */
+int ima_ascii_measurements_show(struct seq_file *m, void *v)
+{
+	/* the list never shrinks, so we don't need a lock here */
+	struct ima_queue_entry *qe = v;
+	struct ima_record_entry *e;
+	char *template_name;
+	int i;
+
+	/* get entry */
+	e = qe->entry;
+	if (e == NULL)
+		return -1;
+
+	template_name = (e->template_desc->name[0] != '\0') ?
+	    e->template_desc->name : e->template_desc->fmt;
+
+	/* 1st: PCR used (config option) */
+	seq_printf(m, "%2d ", e->pcr);
+
+	/* 2nd: SHA1 template hash */
+	ima_print_digest(m, e->digest, TPM_DIGEST_SIZE);
+
+	/* 3th:  template name */
+	seq_printf(m, " %s", template_name);
+
+	/* 4th:  template specific data */
+	for (i = 0; i < e->template_desc->num_fields; i++) {
+		seq_puts(m, " ");
+		if (e->template_data[i].len == 0)
+			continue;
+
+		e->template_desc->fields[i]->field_show(m, IMA_SHOW_ASCII,
+							&e->template_data[i]);
+	}
+	seq_puts(m, "\n");
+	return 0;
+}
+
+const 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);
+}
+
+const struct file_operations ima_ascii_measurements_ops = {
+	.open = ima_ascii_measurements_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+int __init ima_fs_record_init(void)
+{
+	binary_runtime_measurements =
+	    securityfs_create_file("binary_runtime_measurements",
+				   S_IRUSR | S_IRGRP, ima_dir, NULL,
+				   &ima_measurements_ops);
+	if (IS_ERR(binary_runtime_measurements))
+		return -1;
+
+	ascii_runtime_measurements =
+	    securityfs_create_file("ascii_runtime_measurements",
+				   S_IRUSR | S_IRGRP, ima_dir, NULL,
+				   &ima_ascii_measurements_ops);
+	if (IS_ERR(ascii_runtime_measurements))
+		return -1;
+
+	return 0;
+}
+
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index 29b72cd2502e..22f606e8380e 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -47,7 +47,7 @@ static int __init ima_add_boot_aggregate(void)
 {
 	static const char op[] = "add_boot_aggregate";
 	const char *audit_cause = "ENOMEM";
-	struct ima_template_entry *entry;
+	struct ima_record_entry *entry;
 	struct integrity_iint_cache tmp_iint, *iint = &tmp_iint;
 	struct ima_event_data event_data = {iint, NULL, boot_aggregate_name,
 					    NULL, 0, NULL};
@@ -72,17 +72,17 @@ static int __init ima_add_boot_aggregate(void)
 		}
 	}
 
-	result = ima_alloc_init_template(&event_data, &entry);
+	result = ima_alloc_init_record(&event_data, &entry);
 	if (result < 0) {
 		audit_cause = "alloc_entry";
 		goto err_out;
 	}
 
-	result = ima_store_template(entry, violation, NULL,
+	result = ima_store_record(entry, violation, NULL,
 				    boot_aggregate_name,
 				    CONFIG_IMA_MEASURE_PCR_IDX);
 	if (result < 0) {
-		ima_free_template_entry(entry);
+		ima_free_record_entry(entry);
 		audit_cause = "store_entry";
 		goto err_out;
 	}
@@ -125,7 +125,7 @@ int __init ima_init(void)
 	rc = ima_init_crypto();
 	if (rc)
 		return rc;
-	rc = ima_init_template();
+	rc = ima_init_records();
 	if (rc != 0)
 		return rc;
 
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index dca44cf7838e..3f58fbf55426 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -39,36 +39,8 @@ int ima_appraise;
 #endif
 
 int ima_hash_algo = HASH_ALGO_SHA1;
-static int hash_setup_done;
+int ima_hash_setup_done;
 
-static int __init hash_setup(char *str)
-{
-	struct ima_template_desc *template_desc = ima_template_desc_current();
-	int i;
-
-	if (hash_setup_done)
-		return 1;
-
-	if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) {
-		if (strncmp(str, "sha1", 4) == 0)
-			ima_hash_algo = HASH_ALGO_SHA1;
-		else if (strncmp(str, "md5", 3) == 0)
-			ima_hash_algo = HASH_ALGO_MD5;
-		else
-			return 1;
-		goto out;
-	}
-
-	i = match_string(hash_algo_name, HASH_ALGO__LAST, str);
-	if (i < 0)
-		return 1;
-
-	ima_hash_algo = i;
-out:
-	hash_setup_done = 1;
-	return 1;
-}
-__setup("ima_hash=", hash_setup);
 
 /*
  * ima_rdwr_violation_check
@@ -172,7 +144,6 @@ static int process_measurement(struct file *file, const struct cred *cred,
 {
 	struct inode *inode = file_inode(file);
 	struct integrity_iint_cache *iint = NULL;
-	struct ima_template_desc *template_desc;
 	char *pathbuf = NULL;
 	char filename[NAME_MAX];
 	const char *pathname = NULL;
@@ -273,9 +244,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
 		goto out_locked;
 	}
 
-	template_desc = ima_template_desc_current();
-	if ((action & IMA_APPRAISE_SUBMASK) ||
-		    strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0)
+	if ((action & IMA_APPRAISE_SUBMASK) || ima_need_xattr())
 		/* read 'security.ima' */
 		xattr_len = ima_read_xattr(file_dentry(file), &xattr_value);
 
@@ -500,16 +469,16 @@ static int __init init_ima(void)
 {
 	int error;
 
-	ima_init_template_list();
-	hash_setup(CONFIG_IMA_DEFAULT_HASH);
+	ima_init_record_list();
+	ima_hash_setup(CONFIG_IMA_DEFAULT_HASH);
 	error = ima_init();
 
 	if (error && strcmp(hash_algo_name[ima_hash_algo],
 			    CONFIG_IMA_DEFAULT_HASH) != 0) {
 		pr_info("Allocating %s failed, going to use default hash algorithm %s\n",
 			hash_algo_name[ima_hash_algo], CONFIG_IMA_DEFAULT_HASH);
-		hash_setup_done = 0;
-		hash_setup(CONFIG_IMA_DEFAULT_HASH);
+		ima_hash_setup_done = 0;
+		ima_hash_setup(CONFIG_IMA_DEFAULT_HASH);
 		error = ima_init();
 	}
 
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index cdcc9a7b4e24..9922be2098c9 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -111,9 +111,9 @@ static struct ima_rule_entry original_measurement_rules[] __ro_after_init = {
 	 .flags = IMA_FUNC | IMA_MASK},
 	{.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC,
 	 .flags = IMA_FUNC | IMA_MASK},
-	{.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ,
-	 .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq,
-	 .flags = IMA_FUNC | IMA_MASK | IMA_UID},
+	//{.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ,
+	//.uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq,
+	// .flags = IMA_FUNC | IMA_MASK | IMA_UID},
 	{.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC},
 	{.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC},
 };
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue_template.c
similarity index 90%
rename from security/integrity/ima/ima_queue.c
rename to security/integrity/ima/ima_queue_template.c
index 418f35e38015..05d9f021a151 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue_template.c
@@ -74,7 +74,7 @@ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value,
  * binary_runtime_measurement list entry, which contains a
  * couple of variable length fields (e.g template name and data).
  */
-static int get_binary_runtime_size(struct ima_template_entry *entry)
+static int get_binary_runtime_size(struct ima_record_entry *entry)
 {
 	int size = 0;
 
@@ -93,7 +93,7 @@ static int get_binary_runtime_size(struct ima_template_entry *entry)
  *
  * (Called with ima_extend_list_mutex held.)
  */
-static int ima_add_digest_entry(struct ima_template_entry *entry,
+static int ima_add_digest_entry(struct ima_record_entry *entry,
 				bool update_htable)
 {
 	struct ima_queue_entry *qe;
@@ -138,19 +138,6 @@ unsigned long ima_get_binary_runtime_size(void)
 		return binary_runtime_size + sizeof(struct ima_kexec_hdr);
 };
 
-static int ima_pcr_extend(const u8 *hash, int pcr)
-{
-	int result = 0;
-
-	if (!ima_used_chip)
-		return result;
-
-	result = tpm_pcr_extend(NULL, pcr, hash);
-	if (result != 0)
-		pr_err("Error Communicating to TPM chip, result: %d\n", result);
-	return result;
-}
-
 /*
  * Add template entry to the measurement list and hash table, and
  * extend the pcr.
@@ -159,7 +146,7 @@ static int ima_pcr_extend(const u8 *hash, int pcr)
  * kexec, maintain the total memory size required for serializing the
  * binary_runtime_measurements.
  */
-int ima_add_template_entry(struct ima_template_entry *entry, int violation,
+int ima_add_template_entry(struct ima_record_entry *entry, int violation,
 			   const char *op, struct inode *inode,
 			   const unsigned char *filename)
 {
@@ -203,7 +190,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
 	return result;
 }
 
-int ima_restore_measurement_entry(struct ima_template_entry *entry)
+int ima_restore_measurement_entry(struct ima_record_entry *entry)
 {
 	int result = 0;
 
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index 30db39b23804..4eff9bc32adf 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -16,6 +16,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/rculist.h>
+#include <crypto/hash.h>
 #include "ima.h"
 #include "ima_template_lib.h"
 
@@ -52,6 +53,13 @@ static int template_desc_init_fields(const char *template_fmt,
 				     struct ima_template_field ***fields,
 				     int *num_fields);
 
+int ima_need_xattr(void)
+{
+	struct ima_template_desc *template_desc;
+	template_desc = ima_template_desc_current();
+	return (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0);
+}
+
 static int __init ima_template_setup(char *str)
 {
 	struct ima_template_desc *template_desc;
@@ -60,7 +68,7 @@ static int __init ima_template_setup(char *str)
 	if (ima_template)
 		return 1;
 
-	ima_init_template_list();
+	ima_init_record_list();
 
 	/*
 	 * Verify that a template with the supplied name exists.
@@ -203,7 +211,7 @@ static int template_desc_init_fields(const char *template_fmt,
 	return 0;
 }
 
-void ima_init_template_list(void)
+void ima_init_record_list(void)
 {
 	int i;
 
@@ -221,14 +229,14 @@ void ima_init_template_list(void)
 struct ima_template_desc *ima_template_desc_current(void)
 {
 	if (!ima_template) {
-		ima_init_template_list();
+		ima_init_record_list();
 		ima_template =
 		    lookup_template_desc(CONFIG_IMA_DEFAULT_TEMPLATE);
 	}
 	return ima_template;
 }
 
-int __init ima_init_template(void)
+int __init ima_init_records(void)
 {
 	struct ima_template_desc *template = ima_template_desc_current();
 	int result;
@@ -275,7 +283,7 @@ static struct ima_template_desc *restore_template_fmt(char *template_name)
 static int ima_restore_template_data(struct ima_template_desc *template_desc,
 				     void *template_data,
 				     int template_data_size,
-				     struct ima_template_entry **entry)
+				     struct ima_record_entry **entry)
 {
 	int ret = 0;
 	int i;
@@ -312,7 +320,7 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc,
 	}
 
 	if (ret < 0) {
-		ima_free_template_entry(*entry);
+		ima_free_record_entry(*entry);
 		*entry = NULL;
 	}
 
@@ -332,7 +340,7 @@ int ima_restore_measurement_list(loff_t size, void *buf)
 
 	void *bufp = buf + sizeof(*khdr);
 	void *bufendp;
-	struct ima_template_entry *entry;
+	struct ima_record_entry *entry;
 	struct ima_template_desc *template_desc;
 	DECLARE_BITMAP(hdr_mask, HDR__LAST);
 	unsigned long count = 0;
@@ -433,3 +441,200 @@ int ima_restore_measurement_list(loff_t size, void *buf)
 	}
 	return ret;
 }
+
+/*
+ * ima_free_record_entry - free an existing template entry
+ */
+void ima_free_record_entry(struct ima_record_entry *entry)
+{
+	int i;
+
+	for (i = 0; i < entry->template_desc->num_fields; i++)
+		kfree(entry->template_data[i].data);
+
+	kfree(entry);
+}
+
+/*
+ * ima_alloc_init_record - create and initialize a new template entry
+ */
+int ima_alloc_init_record(struct ima_event_data *event_data,
+			    struct ima_record_entry **entry)
+{
+	struct ima_template_desc *template_desc = ima_template_desc_current();
+	int i, result = 0;
+
+	*entry = kzalloc(sizeof(**entry) + template_desc->num_fields *
+			 sizeof(struct ima_field_data), GFP_NOFS);
+	if (!*entry)
+		return -ENOMEM;
+
+	(*entry)->template_desc = template_desc;
+	for (i = 0; i < template_desc->num_fields; i++) {
+		struct ima_template_field *field = template_desc->fields[i];
+		u32 len;
+
+		result = field->field_init(event_data,
+					   &((*entry)->template_data[i]));
+		if (result != 0)
+			goto out;
+
+		len = (*entry)->template_data[i].len;
+		(*entry)->template_data_len += sizeof(len);
+		(*entry)->template_data_len += len;
+	}
+	return 0;
+out:
+	ima_free_record_entry(*entry);
+	*entry = NULL;
+	return result;
+}
+
+/*
+ * ima_store_template - store ima template measurements
+ *
+ * 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
+ */
+int ima_store_record(struct ima_record_entry *entry,
+		       int violation, struct inode *inode,
+		       const unsigned char *filename, int pcr)
+{
+	static const char op[] = "add_template_measure";
+	static const char audit_cause[] = "hashing_error";
+	char *template_name = entry->template_desc->name;
+	int result;
+	struct {
+		struct ima_digest_data hdr;
+		char digest[TPM_DIGEST_SIZE];
+	} hash;
+
+	if (!violation) {
+		int num_fields = entry->template_desc->num_fields;
+
+		/* this function uses default algo */
+		hash.hdr.algo = HASH_ALGO_SHA1;
+		result = ima_calc_field_array_hash(&entry->template_data[0],
+						   entry->template_desc,
+						   num_fields, &hash.hdr);
+		if (result < 0) {
+			integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
+					    template_name, op,
+					    audit_cause, result, 0);
+			return result;
+		}
+		memcpy(entry->digest, hash.hdr.digest, hash.hdr.length);
+	}
+	entry->pcr = pcr;
+	result = ima_add_template_entry(entry, violation, op, inode, filename);
+	return result;
+}
+
+/*
+ * Calculate the hash of template data
+ */
+static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data,
+					 struct ima_template_desc *td,
+					 int num_fields,
+					 struct ima_digest_data *hash,
+					 struct crypto_shash *tfm)
+{
+	SHASH_DESC_ON_STACK(shash, tfm);
+	int rc, i;
+
+	shash->tfm = tfm;
+	shash->flags = 0;
+
+	hash->length = crypto_shash_digestsize(tfm);
+
+	rc = crypto_shash_init(shash);
+	if (rc != 0)
+		return rc;
+
+	for (i = 0; i < num_fields; i++) {
+		u8 buffer[IMA_EVENT_NAME_LEN_MAX + 1] = { 0 };
+		u8 *data_to_hash = field_data[i].data;
+		u32 datalen = field_data[i].len;
+		u32 datalen_to_hash =
+		    !ima_canonical_fmt ? datalen : cpu_to_le32(datalen);
+
+		if (strcmp(td->name, IMA_TEMPLATE_IMA_NAME) != 0) {
+			rc = crypto_shash_update(shash,
+						(const u8 *) &datalen_to_hash,
+						sizeof(datalen_to_hash));
+			if (rc)
+				break;
+		} else if (strcmp(td->fields[i]->field_id, "n") == 0) {
+			memcpy(buffer, data_to_hash, datalen);
+			data_to_hash = buffer;
+			datalen = IMA_EVENT_NAME_LEN_MAX + 1;
+		}
+		rc = crypto_shash_update(shash, data_to_hash, datalen);
+		if (rc)
+			break;
+	}
+
+	if (!rc)
+		rc = crypto_shash_final(shash, hash->digest);
+
+	return rc;
+}
+
+int ima_calc_field_array_hash(struct ima_field_data *field_data,
+			      struct ima_template_desc *desc, int num_fields,
+			      struct ima_digest_data *hash)
+{
+	struct crypto_shash *tfm;
+	int rc;
+
+	tfm = ima_alloc_tfm(hash->algo);
+	if (IS_ERR(tfm))
+		return PTR_ERR(tfm);
+
+	rc = ima_calc_field_array_hash_tfm(field_data, desc, num_fields,
+					   hash, tfm);
+
+	ima_free_tfm(tfm);
+
+	return rc;
+}
+
+int __init ima_hash_setup(char *str)
+{
+	struct ima_template_desc *template_desc = ima_template_desc_current();
+	int i;
+
+	if (ima_hash_setup_done)
+		return 1;
+
+	if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) {
+		if (strncmp(str, "sha1", 4) == 0)
+			ima_hash_algo = HASH_ALGO_SHA1;
+		else if (strncmp(str, "md5", 3) == 0)
+			ima_hash_algo = HASH_ALGO_MD5;
+		else
+			return 1;
+		goto out;
+	}
+
+	i = match_string(hash_algo_name, HASH_ALGO__LAST, str);
+	if (i < 0)
+		return 1;
+
+	ima_hash_algo = i;
+out:
+	ima_hash_setup_done = 1;
+	return 1;
+}
+__setup("ima_hash=", ima_hash_setup);
+
diff --git a/security/integrity/ima/ima_template.h b/security/integrity/ima/ima_template.h
new file mode 100644
index 000000000000..2234d89216e7
--- /dev/null
+++ b/security/integrity/ima/ima_template.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <sailer@xxxxxxxxxxxxxx>
+ * Mimi Zohar <zohar@xxxxxxxxxx>
+ *
+ * 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_template.h
+ *	internal Integrity Measurement Architecture (IMA) definitions
+ */
+
+#ifndef __LINUX_IMA_TEMPLATE_H
+#define __LINUX_IMA_TEMPLATE_H
+
+#define IMA_TEMPLATE_FIELD_ID_MAX_LEN	16
+#define IMA_TEMPLATE_NUM_FIELDS_MAX	15
+
+#define IMA_TEMPLATE_IMA_NAME "ima"
+#define IMA_TEMPLATE_IMA_FMT "d|n"
+
+/* IMA template field data definition */
+struct ima_field_data {
+	u8 *data;
+	u32 len;
+};
+
+/* IMA template field definition */
+struct ima_template_field {
+	const char field_id[IMA_TEMPLATE_FIELD_ID_MAX_LEN];
+	int (*field_init)(struct ima_event_data *event_data,
+			  struct ima_field_data *field_data);
+	void (*field_show)(struct seq_file *m, enum ima_show_type show,
+			   struct ima_field_data *field_data);
+};
+
+/* IMA template descriptor definition */
+struct ima_template_desc {
+	struct list_head list;
+	char *name;
+	char *fmt;
+	int num_fields;
+	struct ima_template_field **fields;
+};
+
+struct ima_record_entry {
+	int pcr;
+	u8 digest[TPM_DIGEST_SIZE];	/* sha1 or md5 measurement hash */
+	struct ima_template_desc *template_desc; /* template descriptor */
+	u32 template_data_len;
+	struct ima_field_data template_data[0];	/* template related data */
+};
+
+struct ima_queue_entry {
+	struct hlist_node hnext;	/* place in hash collision list */
+	struct list_head later;		/* place in ima_measurements list */
+	struct ima_record_entry *entry;
+};
+extern struct list_head ima_measurements;	/* list of all measurements */
+
+int ima_add_template_entry(struct ima_record_entry *entry, int violation,
+			   const char *op, struct inode *inode,
+			   const unsigned char *filename);
+
+int ima_calc_field_array_hash(struct ima_field_data *field_data,
+			      struct ima_template_desc *desc, int num_fields,
+			      struct ima_digest_data *hash);
+
+struct ima_template_desc *ima_template_desc_current(void);
+int ima_restore_measurement_entry(struct ima_record_entry *entry);
+int ima_need_xattr(void);
+int ima_init_records(void);
+void ima_init_record_list(void);
+int ima_alloc_init_record(struct ima_event_data *event_data,
+struct ima_record_entry **entry);
+
+
+int ima_store_record(struct ima_record_entry *entry, int violation,
+		       struct inode *inode,
+		       const unsigned char *filename, int pcr);
+void ima_free_record_entry(struct ima_record_entry *entry);
+
+
+#endif /* __LINUX_IMA_TEMPLATE_H */
-- 
2.17.1




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux Kernel]     [Linux Kernel Hardening]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux