@@ -13,6 +13,10 @@
#include <linux/fs.h>
struct linux_binprm;
+enum ima_buffer_id {
+ MEASURING_MAX_BUFFER_ID
+};
+
#ifdef CONFIG_IMA
extern int ima_bprm_check(struct linux_binprm *bprm);
extern int ima_file_check(struct file *file, int mask, int opened);
@@ -22,6 +26,8 @@ extern int ima_read_file(struct file *file, enum kernel_read_file_id id);
extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
enum kernel_read_file_id id);
extern void ima_post_path_mknod(struct dentry *dentry);
+extern void ima_buffer_check(void *buf, loff_t size,
+ enum ima_buffer_id buffer_id);
#else
static inline int ima_bprm_check(struct linux_binprm *bprm)
@@ -60,6 +66,11 @@ static inline void ima_post_path_mknod(struct dentry *dentry)
return;
}
+static inline void ima_buffer_check(void *buf, loff_t size,
+ enum ima_buffer_id buffer_id)
+{
+ return;
+}
#endif /* CONFIG_IMA */
#ifdef CONFIG_IMA_APPRAISE
@@ -6,6 +6,6 @@
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_policy.o ima_template.o ima_template_lib.o ima_buffer.o
ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o
@@ -154,6 +154,8 @@ enum ima_hooks {
MAX_CHECK
};
+int ima_match_buffer_id(enum ima_hooks func, int *pcr);
+
/* LIM API function definitions */
int ima_get_action(struct inode *inode, int mask,
enum ima_hooks func, int *pcr);
new file mode 100644
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 IBM Corporation
+ *
+ * Author:
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/ima.h>
+
+#include "ima.h"
+
+struct buffer_idmap {
+ enum ima_hooks func;
+ char *buf;
+};
+
+static struct buffer_idmap _idmap[MEASURING_MAX_BUFFER_ID] = {
+};
+
+static void process_buffer_measurement(void *buf, loff_t size,
+ enum ima_buffer_id buffer_id, int pcr)
+{
+ struct {
+ struct ima_digest_data hdr;
+ char digest[IMA_MAX_DIGEST_SIZE];
+ } hash;
+ struct ima_template_entry *entry;
+ struct integrity_iint_cache tmp_iint, *iint = &tmp_iint;
+ struct ima_event_data event_data = {iint, NULL, NULL, NULL, 0, NULL};
+ int violation = 0;
+ int result;
+
+ memset(&hash, 0, sizeof(hash));
+ hash.hdr.algo = ima_hash_algo;
+ result = ima_calc_buffer_hash(buf, size, &hash.hdr);
+ if (result < 0) {
+ pr_debug("failed calculating buffer hash\n");
+ return;
+ }
+
+ iint->ima_hash = &hash.hdr;
+ event_data.filename = _idmap[buffer_id].buf;
+ result = ima_alloc_init_template(&event_data, &entry);
+ if (result < 0) {
+ pr_debug("failed allocating template\n");
+ return;
+ }
+
+ result = ima_store_template(entry, violation, NULL,
+ event_data.filename, pcr);
+ if (result < 0) {
+ pr_debug("failed storing buffer measurement\n");
+ ima_free_template_entry(entry);
+ }
+}
+
+/**
+ * ima_buffer_check - based on policy, collect & store buffer measurement
+ * @buf: pointer to buffer
+ * @size: size of buffer
+ * @buffer_id: caller identifier
+ *
+ * Buffers can only be measured, not appraised.
+ */
+void ima_buffer_check(void *buf, loff_t size, enum ima_buffer_id buffer_id)
+{
+ int pcr = CONFIG_IMA_MEASURE_PCR_IDX;
+
+ if (buffer_id > MEASURING_MAX_BUFFER_ID)
+ return;
+
+ if (!ima_match_buffer_id(_idmap[buffer_id].func, &pcr))
+ return;
+
+ process_buffer_measurement(buf, size, buffer_id, pcr);
+}
+EXPORT_SYMBOL_GPL(ima_buffer_check);
@@ -370,6 +370,32 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
return action;
}
+/**
+ * ima_match_buffer_id - decision based on policy
+ * @buffer_id: IMA buffer identifier
+ *
+ * Measure decision based the buffer identifier's existence in policy.
+ * Without an inode, buffers can only be measured, not appraised.
+ */
+int ima_match_buffer_id(enum ima_hooks func, int *pcr)
+{
+ struct ima_rule_entry *entry;
+ int result = 0;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(entry, ima_rules, list) {
+ if ((entry->action == MEASURE) && (entry->flags & IMA_FUNC) &&
+ (entry->func == func)) {
+ if (entry->flags & IMA_PCR)
+ *pcr = entry->pcr;
+ result = 1;
+ }
+ }
+ rcu_read_unlock();
+
+ return result;
+}
+
/*
* Initialize the ima_policy_flag variable based on the currently
* loaded policy. Based on this flag, the decision to short circuit
In addition to files, other data (eg. boot command line) should be included in the measurement list to attest to the integrity of a running system. A new IMA hook named ima_buffer_check() calculates and includes the buffer hash in the measurement list. Callers of this hook provide the buffer, buffer length and a buffer identifier. Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com> --- include/linux/ima.h | 11 +++++ security/integrity/ima/Makefile | 2 +- security/integrity/ima/ima.h | 2 + security/integrity/ima/ima_buffer.c | 82 +++++++++++++++++++++++++++++++++++++ security/integrity/ima/ima_policy.c | 26 ++++++++++++ 5 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 security/integrity/ima/ima_buffer.c