|
From: Mimi Z. <zo...@li...> - 2010-06-07 12:43:45
|
The current maximum template-data digest size is limited to 20 bytes.
This patch adds support for larger template-data digests and introduces
the command line option 'ima_template_hash=' used to specify the
template hash algorithm.
Signed-off-by: Mimi Zohar <zo...@us...>
---
Documentation/kernel-parameters.txt | 4 ++
include/linux/tpm.h | 1 +
security/integrity/ima/Kconfig | 2 +
security/integrity/ima/ima.h | 16 +++++-
security/integrity/ima/ima_api.c | 87 ++++++++++++++++++++++++++++++-----
security/integrity/ima/ima_crypto.c | 22 ++++----
security/integrity/ima/ima_fs.c | 50 ++++++++++++++------
security/integrity/ima/ima_iint.c | 5 +-
security/integrity/ima/ima_init.c | 19 +++++---
security/integrity/ima/ima_main.c | 31 ++++++++++++-
security/integrity/ima/ima_queue.c | 4 +-
11 files changed, 188 insertions(+), 53 deletions(-)
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 009b6ab..987fa8e 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -993,6 +993,10 @@ and is between 256 and 4096 characters. It is defined in the file
Format: { "ima" | "ima-ng" }
default: "ima"
+ ima_template_hash= [IMA] Choose an IMA template data hash algorithm
+ Format: { "sha1" | "sha256" | "sha512" }
+ default: "sha1"
+
in2000= [HW,SCSI]
See header of drivers/scsi/in2000.c.
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index ac5d1c1..00bd423 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -26,6 +26,7 @@
* Chip num is this value or a valid tpm idx
*/
#define TPM_ANY_NUM 0xFFFF
+#define TPM_DIGEST_SIZE 20
#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index b6ecfd4..da249ea 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -8,6 +8,8 @@ config IMA
select CRYPTO_HMAC
select CRYPTO_MD5
select CRYPTO_SHA1
+ select CRYPTO_SHA256
+ select CRYPTO_SHA512
select TCG_TPM if !S390
select TCG_TIS if TCG_TPM
help
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 6a6c80c..4c7d1a4 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -41,6 +41,9 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
extern int ima_initialized;
extern int ima_used_chip;
extern char *ima_hash;
+extern int ima_hash_size;
+extern char *ima_template_hash;
+extern int ima_template_hash_size;
/* IMA inode template definition */
struct ima_template_data {
@@ -52,7 +55,7 @@ struct ima_template_entry {
u8 digest[IMA_DIGEST_SIZE]; /* sha1 or md5 measurement hash */
const char *template_name;
int template_len;
- struct ima_template_data template;
+ u8 template[0]; /* ima, ima_ng template data */
};
struct ima_queue_entry {
@@ -79,6 +82,13 @@ int ima_calc_template_hash(int template_len, void *template, char *digest);
int ima_calc_boot_aggregate(char *digest);
void ima_add_violation(struct inode *inode, const unsigned char *filename,
const char *op, const char *cause);
+extern void ima_ng_get_offsets(unsigned short *o_digest,
+ unsigned short *o_filename);
+extern struct ima_template_entry *ima_ng_alloc_init_entry(const unsigned char
+ *filename,
+ u8 *digest);
+extern struct ima_template_entry *ima_alloc_init_entry(const unsigned char
+ *filename, u8 *digest);
/*
* used to protect h_table and sha_table
@@ -104,13 +114,13 @@ static inline unsigned long ima_hash_key(u8 *digest)
struct ima_iint_cache {
u64 version; /* track inode changes */
unsigned long flags;
- u8 digest[IMA_DIGEST_SIZE];
struct mutex mutex; /* protects: version, flags, digest */
long readcount; /* measured files readcount */
long writecount; /* measured files writecount */
long opencount; /* opens reference count */
struct kref refcount; /* ima_iint_cache reference count */
struct rcu_head rcu;
+ u8 digest[0];
};
/* LIM API function definitions */
@@ -121,7 +131,7 @@ void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
const unsigned char *filename);
int ima_store_template(struct ima_template_entry *entry, int violation,
struct inode *inode);
-void ima_template_show(struct seq_file *m, void *e,
+void ima_template_show(struct seq_file *m, int e_len, void *e,
enum ima_show_type show);
/* radix tree calls to lookup, insert, delete
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 3eb2f22..a3d0029 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -43,11 +43,6 @@ int ima_store_template(struct ima_template_entry *entry,
int result;
memset(entry->digest, 0, sizeof(entry->digest));
- if (ima_template == IMA_NG_TEMPLATE)
- entry->template_name = IMA_NG_TEMPLATE_NAME;
- else
- entry->template_name = IMA_TEMPLATE_NAME;
- entry->template_len = sizeof(entry->template);
if (!violation) {
result = ima_calc_template_hash(entry->template_len,
@@ -81,13 +76,13 @@ void ima_add_violation(struct inode *inode, const unsigned char *filename,
/* can overflow, only indicator */
atomic_long_inc(&ima_htable.violations);
- entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ entry = ima_template == IMA_TEMPLATE ?
+ ima_alloc_init_entry(filename, NULL) :
+ ima_ng_alloc_init_entry(filename, NULL);
if (!entry) {
result = -ENOMEM;
goto err_out;
}
- memset(&entry->template, 0, sizeof(entry->template));
- strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
result = ima_store_template(entry, violation, inode);
if (result < 0)
kfree(entry);
@@ -152,6 +147,74 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file)
return result;
}
+/* ima_alloc_init_entry - allocate and initialize a template entry
+ *
+ * Allocate contigous memory for ima_template_entry + ima_template_data.
+ */
+struct ima_template_entry *ima_alloc_init_entry(const unsigned char *filename,
+ u8 *digest)
+{
+ struct ima_template_entry *entry;
+ struct ima_template_data *data;
+
+ entry = kmalloc(sizeof(*entry) + sizeof(*data), GFP_KERNEL);
+ if (!entry)
+ goto out;
+ entry->template_name = IMA_TEMPLATE_NAME;
+ entry->template_len = sizeof(*data);
+
+ data = (struct ima_template_data *)entry->template;
+ memset(data, 0, sizeof(*data));
+ strncpy(data->file_name, filename, IMA_EVENT_NAME_LEN_MAX);
+ memset(data->digest, 0, sizeof data->digest);
+ if (digest)
+ memcpy(data->digest, digest, IMA_DIGEST_SIZE);
+out:
+ return entry;
+}
+
+void ima_ng_get_offsets(unsigned short *o_digest, unsigned short *o_filename)
+{
+ *o_digest = strlen(ima_template_hash) + 1;
+ *o_filename = *o_digest + ima_template_hash_size;
+}
+
+/* ima_ng_alloc_init_entry - allocate and initialize the new entry
+ *
+ * The ima-ng template is variable length. Calculate the ima_ng
+ * template size, allocate contigous memory for ima_template_entry
+ * + ima_ng template data, and initialize it.
+ *
+ * Format:
+ * char algname[] - null terminated hash algorithm name
+ * u8 digest[] - digest size based on algorithm
+ * char file_name[] - null terminated file name
+ */
+struct ima_template_entry *ima_ng_alloc_init_entry(const unsigned char
+ *filename, u8 *digest)
+{
+ struct ima_template_entry *entry;
+ unsigned short o_digest, o_filename;
+ unsigned short template_data_size;
+
+ ima_ng_get_offsets(&o_digest, &o_filename);
+ template_data_size = o_filename + strlen(filename) + 1;
+
+ entry = kzalloc(sizeof(*entry) + template_data_size, GFP_KERNEL);
+ if (!entry)
+ goto out;
+ entry->template_name = IMA_NG_TEMPLATE_NAME;
+ entry->template_len = template_data_size;
+
+ strcpy(entry->template, ima_template_hash);
+ if (digest)
+ memcpy(entry->template + o_digest, digest,
+ ima_template_hash_size);
+ strcpy(entry->template + o_filename, filename);
+out:
+ return entry;
+}
+
/*
* ima_store_measurement - store file measurement
*
@@ -177,15 +240,15 @@ void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
struct ima_template_entry *entry;
int violation = 0;
- entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ entry = ima_template == IMA_TEMPLATE ?
+ ima_alloc_init_entry(filename, iint->digest) :
+ ima_ng_alloc_init_entry(filename, iint->digest);
+
if (!entry) {
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
op, audit_cause, result, 0);
return;
}
- memset(&entry->template, 0, sizeof(entry->template));
- memcpy(entry->template.digest, iint->digest, IMA_DIGEST_SIZE);
- strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
result = ima_store_template(entry, violation, inode);
if (!result)
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index 9b3ade7..ef289e3 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -21,14 +21,14 @@
#include <linux/slab.h>
#include "ima.h"
-static int init_desc(struct hash_desc *desc)
+static int init_desc(struct hash_desc *desc, char *alg)
{
int rc;
- desc->tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC);
+ desc->tfm = crypto_alloc_hash(alg, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(desc->tfm)) {
pr_info("IMA: failed to load %s transform: %ld\n",
- ima_hash, PTR_ERR(desc->tfm));
+ alg, PTR_ERR(desc->tfm));
rc = PTR_ERR(desc->tfm);
return rc;
}
@@ -40,7 +40,7 @@ static int init_desc(struct hash_desc *desc)
}
/*
- * Calculate the MD5/SHA1 file digest
+ * Calculate the file digest
*/
int ima_calc_hash(struct file *file, char *digest)
{
@@ -50,7 +50,7 @@ int ima_calc_hash(struct file *file, char *digest)
char *rbuf;
int rc;
- rc = init_desc(&desc);
+ rc = init_desc(&desc, ima_template_hash);
if (rc != 0)
return rc;
@@ -94,7 +94,7 @@ int ima_calc_template_hash(int template_len, void *template, char *digest)
struct scatterlist sg[1];
int rc;
- rc = init_desc(&desc);
+ rc = init_desc(&desc, ima_hash);
if (rc != 0)
return rc;
@@ -122,19 +122,19 @@ int __init ima_calc_boot_aggregate(char *digest)
{
struct hash_desc desc;
struct scatterlist sg;
- u8 pcr_i[IMA_DIGEST_SIZE];
+ u8 pcr_i[TPM_DIGEST_SIZE];
int rc, i;
- rc = init_desc(&desc);
+ rc = init_desc(&desc, ima_template_hash);
if (rc != 0)
return rc;
- /* cumulative sha1 over tpm registers 0-7 */
+ /* cumulative hash over TPM registers 0-7 */
for (i = TPM_PCR0; i < TPM_PCR8; i++) {
ima_pcrread(i, pcr_i);
/* now accumulate with current aggregate */
- sg_init_one(&sg, pcr_i, IMA_DIGEST_SIZE);
- rc = crypto_hash_update(&desc, &sg, IMA_DIGEST_SIZE);
+ sg_init_one(&sg, pcr_i, TPM_DIGEST_SIZE);
+ rc = crypto_hash_update(&desc, &sg, TPM_DIGEST_SIZE);
}
if (!rc)
crypto_hash_final(&desc, digest);
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 5221c83..85491d4 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -22,14 +22,20 @@
#include <linux/rculist.h>
#include <linux/rcupdate.h>
#include <linux/parser.h>
+#include <crypto/sha.h>
#include "ima.h"
int ima_template = IMA_NG_TEMPLATE;
static int __init ima_template_setup(char *str)
{
- if (strncmp(str, "ima", 3) == 0)
+ if (strncmp(str, "ima", 3) == 0) {
ima_template = IMA_TEMPLATE;
+ if (strncmp(ima_template_hash, "sha256", 6) == 0) {
+ ima_template_hash = "sha1";
+ ima_template_hash_size = SHA1_DIGEST_SIZE;
+ }
+ }
return 1;
}
__setup("ima_template=", ima_template_setup);
@@ -154,8 +160,7 @@ static int ima_measurements_show(struct seq_file *m, void *v)
ima_putc(m, &e->template_len, sizeof e->template_len);
/* 5th: template specific data */
- ima_template_show(m, (struct ima_template_data *)&e->template,
- IMA_SHOW_BINARY);
+ ima_template_show(m, e->template_len, &e->template, IMA_SHOW_BINARY);
return 0;
}
@@ -178,30 +183,44 @@ static const struct file_operations ima_measurements_ops = {
.release = seq_release,
};
-static void ima_print_digest(struct seq_file *m, u8 *digest)
+static void ima_print_digest(struct seq_file *m, u8 *digest, int digest_size)
{
int i;
- for (i = 0; i < IMA_DIGEST_SIZE; i++)
+ for (i = 0; i < digest_size; i++)
seq_printf(m, "%02x", *(digest + i));
}
-void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show)
+void ima_template_show(struct seq_file *m, int e_len, void *e,
+ enum ima_show_type show)
{
struct ima_template_data *entry = e;
+ unsigned short o_digest, o_filename;
int namelen;
switch (show) {
case IMA_SHOW_ASCII:
- ima_print_digest(m, entry->digest);
- seq_printf(m, " %s\n", entry->file_name);
+ if (ima_template == IMA_TEMPLATE) {
+ ima_print_digest(m, entry->digest,
+ ima_template_hash_size);
+ seq_printf(m, " %s\n", entry->file_name);
+ } else {
+ ima_ng_get_offsets(&o_digest, &o_filename);
+ seq_printf(m, "%s ", (char *)e);
+ ima_print_digest(m, e + o_digest,
+ ima_template_hash_size);
+ seq_printf(m, " %s\n", (char *)e + o_filename);
+ }
break;
case IMA_SHOW_BINARY:
- ima_putc(m, entry->digest, IMA_DIGEST_SIZE);
-
- namelen = strlen(entry->file_name);
- ima_putc(m, &namelen, sizeof namelen);
- ima_putc(m, entry->file_name, namelen);
+ if (ima_template == IMA_TEMPLATE) {
+ ima_putc(m, entry->digest, IMA_DIGEST_SIZE);
+
+ namelen = strlen(entry->file_name);
+ ima_putc(m, &namelen, sizeof namelen);
+ ima_putc(m, entry->file_name, namelen);
+ } else
+ ima_putc(m, e, e_len);
default:
break;
}
@@ -223,14 +242,13 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX);
/* 2nd: SHA1 template hash */
- ima_print_digest(m, e->digest);
+ ima_print_digest(m, e->digest, ima_hash_size);
/* 3th: template name */
seq_printf(m, " %s ", e->template_name);
/* 4th: template specific data */
- ima_template_show(m, (struct ima_template_data *)&e->template,
- IMA_SHOW_ASCII);
+ ima_template_show(m, e->template_len, &e->template, IMA_SHOW_ASCII);
return 0;
}
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
index 7625b85..0b5619b 100644
--- a/security/integrity/ima/ima_iint.c
+++ b/security/integrity/ima/ima_iint.c
@@ -139,8 +139,9 @@ static void init_once(void *foo)
static int __init ima_iintcache_init(void)
{
iint_cache =
- kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0,
- SLAB_PANIC, init_once);
+ kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache)
+ + ima_template_hash_size,
+ 0, SLAB_PANIC, init_once);
return 0;
}
security_initcall(ima_iintcache_init);
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index 17f1f06..9701db2 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -46,23 +46,28 @@ static void __init ima_add_boot_aggregate(void)
const char *audit_cause = "ENOMEM";
int result = -ENOMEM;
int violation = 1;
+ u8 *digest;
- entry = kmalloc(sizeof(*entry), GFP_KERNEL);
- if (!entry)
+ digest = kzalloc(ima_template_hash_size, GFP_KERNEL);
+ if (!digest)
goto err_out;
- memset(&entry->template, 0, sizeof(entry->template));
- strncpy(entry->template.file_name, boot_aggregate_name,
- IMA_EVENT_NAME_LEN_MAX);
if (ima_used_chip) {
violation = 0;
- result = ima_calc_boot_aggregate(entry->template.digest);
+ result = ima_calc_boot_aggregate(digest);
if (result < 0) {
audit_cause = "hashing_error";
- kfree(entry);
+ kfree(digest);
goto err_out;
}
}
+ entry = ima_template == IMA_TEMPLATE ?
+ ima_alloc_init_entry(boot_aggregate_name, digest) :
+ ima_ng_alloc_init_entry(boot_aggregate_name, digest);
+ kfree(digest);
+ if (!entry)
+ goto err_out;
+
result = ima_store_template(entry, violation, NULL);
if (result < 0)
kfree(entry);
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index f936413..414f642 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -22,20 +22,49 @@
#include <linux/mount.h>
#include <linux/mman.h>
#include <linux/slab.h>
+#include <crypto/sha.h>
+#include <crypto/md5.h>
#include "ima.h"
int ima_initialized;
char *ima_hash = "sha1";
+int ima_hash_size = SHA1_DIGEST_SIZE;
static int __init hash_setup(char *str)
{
- if (strncmp(str, "md5", 3) == 0)
+ if (strncmp(str, "md5", 3) == 0) {
ima_hash = "md5";
+ ima_hash_size = MD5_DIGEST_SIZE;
+ }
return 1;
}
__setup("ima_hash=", hash_setup);
+char *ima_template_hash = "sha256";
+int ima_template_hash_size = SHA256_DIGEST_SIZE;
+static int __init template_hash_setup(char *str)
+{
+ if (strncmp(str, "md5", 3) == 0) {
+ ima_template_hash = "md5";
+ ima_template_hash_size = MD5_DIGEST_SIZE;
+ }
+ if (strncmp(str, "sha1", 4) == 0) {
+ ima_template_hash = "sha1";
+ ima_template_hash_size = SHA1_DIGEST_SIZE;
+ }
+ if (ima_template == IMA_TEMPLATE)
+ goto out;
+
+ if (strncmp(str, "sha512", 6) == 0) {
+ ima_template_hash = "sha512";
+ ima_template_hash_size = SHA512_DIGEST_SIZE;
+ }
+out:
+ return 1;
+}
+__setup("ima_template_hash=", template_hash_setup);
+
struct ima_imbalance {
struct hlist_node node;
unsigned long fsmagic;
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index 8e28f04..a8c0b12 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -107,6 +107,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
u8 digest[IMA_DIGEST_SIZE];
const char *audit_cause = "hash_added";
int audit_info = 1;
+ unsigned short o_digest, o_filename;
int result = 0;
mutex_lock(&ima_extend_list_mutex);
@@ -135,8 +136,9 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
}
out:
mutex_unlock(&ima_extend_list_mutex);
+ ima_ng_get_offsets(&o_digest, &o_filename);
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
- entry->template.file_name,
+ entry->template + o_filename,
op, audit_cause, result, audit_info);
return result;
}
--
1.6.6.1
|