linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 00/11] EVM
@ 2011-03-28 16:39 Mimi Zohar
  2011-03-28 16:39 ` [PATCH v4 01/11] integrity: move ima inode integrity data management Mimi Zohar
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: Mimi Zohar @ 2011-03-28 16:39 UTC (permalink / raw)
  To: linux-security-module
  Cc: Mimi Zohar, linux-kernel, linux-fsdevel, James Morris,
	David Safford

Extended Verification Module(EVM) detects offline tampering of the security
extended attributes (e.g. security.selinux, security.SMACK64, security.ima),
which is the basis for LSM permission decisions and, with the IMA-appraisal
patchset, integrity appraisal decisions. This patchset provides the framework
and an initial method to detect offline tampering of the security extended
attributes.  The initial method maintains an HMAC-sha1 across a set of
security extended attributes, storing the HMAC as the extended attribute
'security.evm'. To verify the integrity of an extended attribute, EVM exports
evm_verifyxattr(), which re-calculates the HMAC and compares it with the
version stored in 'security.evm'.  Other methods of validating the integrity
of a file's metadata will be posted separately (eg. EVM-digital-signatures).

While this patchset does authenticate the security xattrs, and
cryptographically binds them to the inode, coming extensions will bind other
directory and inode metadata for more complete protection.  To help simplify
the review and upstreaming process, each extension will be posted separately
(eg. IMA-appraisal, IMA-appraisal-directory).  For a general overview of the
proposed Linux integrity subsystem, refer to Dave Safford's whitepaper:
http://downloads.sf.net/project/linux-ima/linux-ima/Integrity_overview.pdf.

Much appreciation to Dave Hansen, Serge Hallyn, and Matt Helsley for
reviewing the original patches.

Mimi Zohar
David Safford

Dmitry Kasatkin (2):
  evm: add support for different security.evm data types
  evm: crypto hash replaced by shash

Mimi Zohar (9):
  integrity: move ima inode integrity data management
  xattr: define vfs_getxattr_alloc and vfs_xattr_cmp
  evm: re-release
  ima: move ima_file_free before releasing the file
  security: imbed evm calls in security hooks
  evm: inode post removexattr
  evm: imbed evm_inode_post_setattr
  evm: inode_post_init
  fs: add evm_inode_post_init calls

 Documentation/ABI/testing/evm       |   23 +++
 fs/attr.c                           |    5 +-
 fs/ext2/xattr_security.c            |   31 +++-
 fs/ext3/xattr_security.c            |   30 +++-
 fs/ext4/xattr_security.c            |   30 +++-
 fs/file_table.c                     |    2 +-
 fs/xattr.c                          |   63 +++++++-
 include/linux/evm.h                 |   82 +++++++++
 include/linux/ima.h                 |   13 --
 include/linux/integrity.h           |   43 +++++
 include/linux/xattr.h               |   14 ++-
 security/Kconfig                    |    2 +-
 security/Makefile                   |    4 +-
 security/integrity/Kconfig          |    7 +
 security/integrity/Makefile         |   12 ++
 security/integrity/evm/Kconfig      |   12 ++
 security/integrity/evm/Makefile     |    6 +
 security/integrity/evm/evm.h        |   39 +++++
 security/integrity/evm/evm_crypto.c |  211 +++++++++++++++++++++++
 security/integrity/evm/evm_main.c   |  323 +++++++++++++++++++++++++++++++++++
 security/integrity/evm/evm_secfs.c  |  108 ++++++++++++
 security/integrity/iint.c           |  171 ++++++++++++++++++
 security/integrity/ima/Kconfig      |    1 +
 security/integrity/ima/Makefile     |    2 +-
 security/integrity/ima/ima.h        |   29 +---
 security/integrity/ima/ima_api.c    |    7 +-
 security/integrity/ima/ima_iint.c   |  169 ------------------
 security/integrity/ima/ima_main.c   |   12 +-
 security/integrity/integrity.h      |   38 ++++
 security/security.c                 |   19 ++-
 30 files changed, 1265 insertions(+), 243 deletions(-)
 create mode 100644 Documentation/ABI/testing/evm
 create mode 100644 include/linux/evm.h
 create mode 100644 include/linux/integrity.h
 create mode 100644 security/integrity/Kconfig
 create mode 100644 security/integrity/Makefile
 create mode 100644 security/integrity/evm/Kconfig
 create mode 100644 security/integrity/evm/Makefile
 create mode 100644 security/integrity/evm/evm.h
 create mode 100644 security/integrity/evm/evm_crypto.c
 create mode 100644 security/integrity/evm/evm_main.c
 create mode 100644 security/integrity/evm/evm_secfs.c
 create mode 100644 security/integrity/iint.c
 delete mode 100644 security/integrity/ima/ima_iint.c
 create mode 100644 security/integrity/integrity.h

-- 
1.7.3.4


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

* [PATCH v4 01/11] integrity: move ima inode integrity data management
  2011-03-28 16:39 [PATCH v4 00/11] EVM Mimi Zohar
@ 2011-03-28 16:39 ` Mimi Zohar
  2011-03-28 16:39 ` [PATCH v4 02/11] xattr: define vfs_getxattr_alloc and vfs_xattr_cmp Mimi Zohar
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2011-03-28 16:39 UTC (permalink / raw)
  To: linux-security-module
  Cc: Mimi Zohar, linux-kernel, linux-fsdevel, James Morris,
	David Safford, Mimi Zohar

Move the inode integrity data(iint) management up to the integrity directory
in order to share the iint among the different integrity models.

Changelog:
   - Rebased on current ima_iint.c
   - Define integrity_iint_store/lock as static

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
---
 include/linux/ima.h               |   13 ---
 include/linux/integrity.h         |   30 +++++++
 security/Kconfig                  |    2 +-
 security/Makefile                 |    4 +-
 security/integrity/Kconfig        |    6 ++
 security/integrity/Makefile       |   10 ++
 security/integrity/iint.c         |  170 +++++++++++++++++++++++++++++++++++++
 security/integrity/ima/Kconfig    |    1 +
 security/integrity/ima/Makefile   |    2 +-
 security/integrity/ima/ima.h      |   29 ++-----
 security/integrity/ima/ima_api.c  |    7 +-
 security/integrity/ima/ima_iint.c |  169 ------------------------------------
 security/integrity/ima/ima_main.c |   12 ++--
 security/integrity/integrity.h    |   37 ++++++++
 security/security.c               |    3 +-
 15 files changed, 279 insertions(+), 216 deletions(-)
 create mode 100644 include/linux/integrity.h
 create mode 100644 security/integrity/Kconfig
 create mode 100644 security/integrity/Makefile
 create mode 100644 security/integrity/iint.c
 delete mode 100644 security/integrity/ima/ima_iint.c
 create mode 100644 security/integrity/integrity.h

diff --git a/include/linux/ima.h b/include/linux/ima.h
index 09e6e62..6ac8e50 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -15,8 +15,6 @@ struct linux_binprm;
 
 #ifdef CONFIG_IMA
 extern int ima_bprm_check(struct linux_binprm *bprm);
-extern int ima_inode_alloc(struct inode *inode);
-extern void ima_inode_free(struct inode *inode);
 extern int ima_file_check(struct file *file, int mask);
 extern void ima_file_free(struct file *file);
 extern int ima_file_mmap(struct file *file, unsigned long prot);
@@ -27,16 +25,6 @@ static inline int ima_bprm_check(struct linux_binprm *bprm)
 	return 0;
 }
 
-static inline int ima_inode_alloc(struct inode *inode)
-{
-	return 0;
-}
-
-static inline void ima_inode_free(struct inode *inode)
-{
-	return;
-}
-
 static inline int ima_file_check(struct file *file, int mask)
 {
 	return 0;
@@ -51,6 +39,5 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot)
 {
 	return 0;
 }
-
 #endif /* CONFIG_IMA_H */
 #endif /* _LINUX_IMA_H */
diff --git a/include/linux/integrity.h b/include/linux/integrity.h
new file mode 100644
index 0000000..9059812
--- /dev/null
+++ b/include/linux/integrity.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2009 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+
+#ifndef _LINUX_INTEGRITY_H
+#define _LINUX_INTEGRITY_H
+
+#include <linux/fs.h>
+
+#ifdef CONFIG_INTEGRITY
+extern int integrity_inode_alloc(struct inode *inode);
+extern void integrity_inode_free(struct inode *inode);
+
+#else
+static inline int integrity_inode_alloc(struct inode *inode)
+{
+	return 0;
+}
+
+static inline void integrity_inode_free(struct inode *inode)
+{
+	return;
+}
+#endif /* CONFIG_INTEGRITY_H */
+#endif /* _LINUX_INTEGRITY_H */
diff --git a/security/Kconfig b/security/Kconfig
index 95accd4..58489f4 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -185,7 +185,7 @@ source security/smack/Kconfig
 source security/tomoyo/Kconfig
 source security/apparmor/Kconfig
 
-source security/integrity/ima/Kconfig
+source security/integrity/Kconfig
 
 choice
 	prompt "Default security module"
diff --git a/security/Makefile b/security/Makefile
index 8bb0fe9..a5e502f 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -24,5 +24,5 @@ obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/built-in.o
 obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
 
 # Object integrity file lists
-subdir-$(CONFIG_IMA)			+= integrity/ima
-obj-$(CONFIG_IMA)			+= integrity/ima/built-in.o
+subdir-$(CONFIG_INTEGRITY)		+= integrity
+obj-$(CONFIG_INTEGRITY)			+= integrity/built-in.o
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig
new file mode 100644
index 0000000..2704691
--- /dev/null
+++ b/security/integrity/Kconfig
@@ -0,0 +1,6 @@
+#
+config INTEGRITY
+	def_bool y
+	depends on IMA
+
+source security/integrity/ima/Kconfig
diff --git a/security/integrity/Makefile b/security/integrity/Makefile
new file mode 100644
index 0000000..6eddd61
--- /dev/null
+++ b/security/integrity/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for caching inode integrity data (iint)
+#
+
+obj-$(CONFIG_INTEGRITY) += integrity.o
+
+integrity-y := iint.o
+
+subdir-$(CONFIG_IMA)			+= ima
+obj-$(CONFIG_IMA)			+= ima/built-in.o
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
new file mode 100644
index 0000000..d17de48
--- /dev/null
+++ b/security/integrity/iint.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: integrity_iint.c
+ *	- implements the integrity hooks: integrity_inode_alloc,
+ *	  integrity_inode_free
+ *	- cache integrity information associated with an inode
+ *	  using a rbtree tree.
+ */
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/rbtree.h>
+#include "integrity.h"
+
+static struct rb_root integrity_iint_tree = RB_ROOT;
+static DEFINE_SPINLOCK(integrity_iint_lock);
+static struct kmem_cache *iint_cache __read_mostly;
+
+int iint_initialized;
+
+/*
+ * __integrity_iint_find - return the iint associated with an inode
+ */
+static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode)
+{
+	struct integrity_iint_cache *iint;
+	struct rb_node *n = integrity_iint_tree.rb_node;
+
+	assert_spin_locked(&integrity_iint_lock);
+
+	while (n) {
+		iint = rb_entry(n, struct integrity_iint_cache, rb_node);
+
+		if (inode < iint->inode)
+			n = n->rb_left;
+		else if (inode > iint->inode)
+			n = n->rb_right;
+		else
+			break;
+	}
+	if (!n)
+		return NULL;
+
+	return iint;
+}
+
+/*
+ * integrity_iint_find - return the iint associated with an inode
+ */
+struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
+{
+	struct integrity_iint_cache *iint;
+
+	if (!IS_IMA(inode))
+		return NULL;
+
+	spin_lock(&integrity_iint_lock);
+	iint = __integrity_iint_find(inode);
+	spin_unlock(&integrity_iint_lock);
+
+	return iint;
+}
+
+static void iint_free(struct integrity_iint_cache *iint)
+{
+	iint->version = 0;
+	iint->flags = 0UL;
+	kmem_cache_free(iint_cache, iint);
+}
+
+/**
+ * integrity_inode_alloc - allocate an iint associated with an inode
+ * @inode: pointer to the inode
+ */
+int integrity_inode_alloc(struct inode *inode)
+{
+	struct rb_node **p;
+	struct rb_node *new_node, *parent = NULL;
+	struct integrity_iint_cache *new_iint, *test_iint;
+	int rc;
+
+	new_iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
+	if (!new_iint)
+		return -ENOMEM;
+
+	new_iint->inode = inode;
+	new_node = &new_iint->rb_node;
+
+	mutex_lock(&inode->i_mutex);	/* i_flags */
+	spin_lock(&integrity_iint_lock);
+
+	p = &integrity_iint_tree.rb_node;
+	while (*p) {
+		parent = *p;
+		test_iint = rb_entry(parent, struct integrity_iint_cache,
+				     rb_node);
+		rc = -EEXIST;
+		if (inode < test_iint->inode)
+			p = &(*p)->rb_left;
+		else if (inode > test_iint->inode)
+			p = &(*p)->rb_right;
+		else
+			goto out_err;
+	}
+
+	inode->i_flags |= S_IMA;
+	rb_link_node(new_node, parent, p);
+	rb_insert_color(new_node, &integrity_iint_tree);
+
+	spin_unlock(&integrity_iint_lock);
+	mutex_unlock(&inode->i_mutex);	/* i_flags */
+
+	return 0;
+out_err:
+	spin_unlock(&integrity_iint_lock);
+	mutex_unlock(&inode->i_mutex);	/* i_flags */
+	iint_free(new_iint);
+
+	return rc;
+}
+
+/**
+ * integrity_inode_free - called on security_inode_free
+ * @inode: pointer to the inode
+ *
+ * Free the integrity information(iint) associated with an inode.
+ */
+void integrity_inode_free(struct inode *inode)
+{
+	struct integrity_iint_cache *iint;
+
+	if (!IS_IMA(inode))
+		return;
+
+	spin_lock(&integrity_iint_lock);
+	iint = __integrity_iint_find(inode);
+	rb_erase(&iint->rb_node, &integrity_iint_tree);
+	spin_unlock(&integrity_iint_lock);
+
+	iint_free(iint);
+}
+
+static void init_once(void *foo)
+{
+	struct integrity_iint_cache *iint = foo;
+
+	memset(iint, 0, sizeof *iint);
+	iint->version = 0;
+	iint->flags = 0UL;
+	mutex_init(&iint->mutex);
+}
+
+static int __init integrity_iintcache_init(void)
+{
+	iint_cache =
+	    kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
+			      0, SLAB_PANIC, init_once);
+	iint_initialized = 1;
+	return 0;
+}
+security_initcall(integrity_iintcache_init);
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index b6ecfd4..19c053b 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -3,6 +3,7 @@
 config IMA
 	bool "Integrity Measurement Architecture(IMA)"
 	depends on SECURITY
+	select INTEGRITY
 	select SECURITYFS
 	select CRYPTO
 	select CRYPTO_HMAC
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
index 787c4cb..5690c02 100644
--- a/security/integrity/ima/Makefile
+++ b/security/integrity/ima/Makefile
@@ -6,4 +6,4 @@
 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_iint.o ima_audit.o
+	 ima_policy.o ima_audit.o
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 08408bd..29d97af 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -24,11 +24,13 @@
 #include <linux/tpm.h>
 #include <linux/audit.h>
 
+#include "../integrity.h"
+
 enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_ASCII };
 enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
 
 /* digest size for IMA, fits SHA1 or MD5 */
-#define IMA_DIGEST_SIZE		20
+#define IMA_DIGEST_SIZE		SHA1_DIGEST_SIZE
 #define IMA_EVENT_NAME_LEN_MAX	255
 
 #define IMA_HASH_BITS 9
@@ -96,34 +98,21 @@ static inline unsigned long ima_hash_key(u8 *digest)
 	return hash_long(*digest, IMA_HASH_BITS);
 }
 
-/* iint cache flags */
-#define IMA_MEASURED		0x01
-
-/* integrity data associated with an inode */
-struct ima_iint_cache {
-	struct rb_node rb_node; /* rooted in ima_iint_tree */
-	struct inode *inode;	/* back pointer to inode in question */
-	u64 version;		/* track inode changes */
-	unsigned char flags;
-	u8 digest[IMA_DIGEST_SIZE];
-	struct mutex mutex;	/* protects: version, flags, digest */
-};
-
 /* LIM API function definitions */
 int ima_must_measure(struct inode *inode, int mask, int function);
-int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file);
-void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
+int ima_collect_measurement(struct integrity_iint_cache *iint,
+			    struct file *file);
+void ima_store_measurement(struct integrity_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,
-		       enum ima_show_type show);
+void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show);
 
 /* rbtree tree calls to lookup, insert, delete
  * integrity data associated with an inode.
  */
-struct ima_iint_cache *ima_iint_insert(struct inode *inode);
-struct ima_iint_cache *ima_iint_find(struct inode *inode);
+struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
+struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
 
 /* IMA policy related functions */
 enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK };
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index da36d2c..0d50df0 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -126,7 +126,8 @@ int ima_must_measure(struct inode *inode, int mask, int function)
  *
  * Return 0 on success, error code otherwise
  */
-int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file)
+int ima_collect_measurement(struct integrity_iint_cache *iint,
+			    struct file *file)
 {
 	int result = -EEXIST;
 
@@ -156,8 +157,8 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file)
  *
  * Must be called with iint->mutex held.
  */
-void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
-			   const unsigned char *filename)
+void ima_store_measurement(struct integrity_iint_cache *iint,
+			   struct file *file, const unsigned char *filename)
 {
 	const char *op = "add_template_measure";
 	const char *audit_cause = "ENOMEM";
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
deleted file mode 100644
index 4ae7304..0000000
--- a/security/integrity/ima/ima_iint.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2008 IBM Corporation
- *
- * Authors:
- * Mimi Zohar <zohar@us.ibm.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- *
- * File: ima_iint.c
- * 	- implements the IMA hooks: ima_inode_alloc, ima_inode_free
- *	- cache integrity information associated with an inode
- *	  using a rbtree tree.
- */
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/rbtree.h>
-#include "ima.h"
-
-static struct rb_root ima_iint_tree = RB_ROOT;
-static DEFINE_SPINLOCK(ima_iint_lock);
-static struct kmem_cache *iint_cache __read_mostly;
-
-int iint_initialized = 0;
-
-/*
- * __ima_iint_find - return the iint associated with an inode
- */
-static struct ima_iint_cache *__ima_iint_find(struct inode *inode)
-{
-	struct ima_iint_cache *iint;
-	struct rb_node *n = ima_iint_tree.rb_node;
-
-	assert_spin_locked(&ima_iint_lock);
-
-	while (n) {
-		iint = rb_entry(n, struct ima_iint_cache, rb_node);
-
-		if (inode < iint->inode)
-			n = n->rb_left;
-		else if (inode > iint->inode)
-			n = n->rb_right;
-		else
-			break;
-	}
-	if (!n)
-		return NULL;
-
-	return iint;
-}
-
-/*
- * ima_iint_find - return the iint associated with an inode
- */
-struct ima_iint_cache *ima_iint_find(struct inode *inode)
-{
-	struct ima_iint_cache *iint;
-
-	if (!IS_IMA(inode))
-		return NULL;
-
-	spin_lock(&ima_iint_lock);
-	iint = __ima_iint_find(inode);
-	spin_unlock(&ima_iint_lock);
-
-	return iint;
-}
-
-static void iint_free(struct ima_iint_cache *iint)
-{
-	iint->version = 0;
-	iint->flags = 0UL;
-	kmem_cache_free(iint_cache, iint);
-}
-
-/**
- * ima_inode_alloc - allocate an iint associated with an inode
- * @inode: pointer to the inode
- */
-int ima_inode_alloc(struct inode *inode)
-{
-	struct rb_node **p;
-	struct rb_node *new_node, *parent = NULL;
-	struct ima_iint_cache *new_iint, *test_iint;
-	int rc;
-
-	new_iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
-	if (!new_iint)
-		return -ENOMEM;
-
-	new_iint->inode = inode;
-	new_node = &new_iint->rb_node;
-
-	mutex_lock(&inode->i_mutex); /* i_flags */
-	spin_lock(&ima_iint_lock);
-
-	p = &ima_iint_tree.rb_node;
-	while (*p) {
-		parent = *p;
-		test_iint = rb_entry(parent, struct ima_iint_cache, rb_node);
-
-		rc = -EEXIST;
-		if (inode < test_iint->inode)
-			p = &(*p)->rb_left;
-		else if (inode > test_iint->inode)
-			p = &(*p)->rb_right;
-		else
-			goto out_err;
-	}
-
-	inode->i_flags |= S_IMA;
-	rb_link_node(new_node, parent, p);
-	rb_insert_color(new_node, &ima_iint_tree);
-
-	spin_unlock(&ima_iint_lock);
-	mutex_unlock(&inode->i_mutex); /* i_flags */
-
-	return 0;
-out_err:
-	spin_unlock(&ima_iint_lock);
-	mutex_unlock(&inode->i_mutex); /* i_flags */
-	iint_free(new_iint);
-
-	return rc;
-}
-
-/**
- * ima_inode_free - called on security_inode_free
- * @inode: pointer to the inode
- *
- * Free the integrity information(iint) associated with an inode.
- */
-void ima_inode_free(struct inode *inode)
-{
-	struct ima_iint_cache *iint;
-
-	if (!IS_IMA(inode))
-		return;
-
-	spin_lock(&ima_iint_lock);
-	iint = __ima_iint_find(inode);
-	rb_erase(&iint->rb_node, &ima_iint_tree);
-	spin_unlock(&ima_iint_lock);
-
-	iint_free(iint);
-}
-
-static void init_once(void *foo)
-{
-	struct ima_iint_cache *iint = foo;
-
-	memset(iint, 0, sizeof *iint);
-	iint->version = 0;
-	iint->flags = 0UL;
-	mutex_init(&iint->mutex);
-}
-
-static int __init ima_iintcache_init(void)
-{
-	iint_cache =
-	    kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0,
-			      SLAB_PANIC, init_once);
-	iint_initialized = 1;
-	return 0;
-}
-security_initcall(ima_iintcache_init);
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 39d66dc..25f9fe7 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -82,7 +82,7 @@ out:
 				  "open_writers");
 }
 
-static void ima_check_last_writer(struct ima_iint_cache *iint,
+static void ima_check_last_writer(struct integrity_iint_cache *iint,
 				  struct inode *inode,
 				  struct file *file)
 {
@@ -105,12 +105,12 @@ static void ima_check_last_writer(struct ima_iint_cache *iint,
 void ima_file_free(struct file *file)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	struct ima_iint_cache *iint;
+	struct integrity_iint_cache *iint;
 
 	if (!iint_initialized || !S_ISREG(inode->i_mode))
 		return;
 
-	iint = ima_iint_find(inode);
+	iint = integrity_iint_find(inode);
 	if (!iint)
 		return;
 
@@ -121,7 +121,7 @@ static int process_measurement(struct file *file, const unsigned char *filename,
 			       int mask, int function)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	struct ima_iint_cache *iint;
+	struct integrity_iint_cache *iint;
 	int rc = 0;
 
 	if (!ima_initialized || !S_ISREG(inode->i_mode))
@@ -131,9 +131,9 @@ static int process_measurement(struct file *file, const unsigned char *filename,
 	if (rc != 0)
 		return rc;
 retry:
-	iint = ima_iint_find(inode);
+	iint = integrity_iint_find(inode);
 	if (!iint) {
-		rc = ima_inode_alloc(inode);
+		rc = integrity_inode_alloc(inode);
 		if (!rc || rc == -EEXIST)
 			goto retry;
 		return rc;
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
new file mode 100644
index 0000000..2217a28
--- /dev/null
+++ b/security/integrity/integrity.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2009-2010 IBM Corporation
+ *
+ * Authors:
+ * 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/types.h>
+#include <linux/integrity.h>
+#include <crypto/sha.h>
+
+#define MAX_DIGEST_SIZE		SHA1_DIGEST_SIZE
+
+/* iint cache flags */
+#define IMA_MEASURED		0x01
+
+/* integrity data associated with an inode */
+struct integrity_iint_cache {
+	struct rb_node rb_node; /* rooted in integrity_iint_tree */
+	struct inode *inode;	/* back pointer to inode in question */
+	u64 version;		/* track inode changes */
+	unsigned char flags;
+	u8 digest[MAX_DIGEST_SIZE];
+	struct mutex mutex;	/* protects: version, flags, digest */
+};
+
+/* rbtree tree calls to lookup, insert, delete
+ * integrity data associated with an inode.
+ */
+struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
+struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
diff --git a/security/security.c b/security/security.c
index 9187665..9c34793 100644
--- a/security/security.c
+++ b/security/security.c
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/security.h>
+#include <linux/integrity.h>
 #include <linux/ima.h>
 
 /* Boot-time LSM user choice */
@@ -330,7 +331,7 @@ int security_inode_alloc(struct inode *inode)
 
 void security_inode_free(struct inode *inode)
 {
-	ima_inode_free(inode);
+	integrity_inode_free(inode);
 	security_ops->inode_free_security(inode);
 }
 
-- 
1.7.3.4

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

* [PATCH v4 02/11] xattr: define vfs_getxattr_alloc and vfs_xattr_cmp
  2011-03-28 16:39 [PATCH v4 00/11] EVM Mimi Zohar
  2011-03-28 16:39 ` [PATCH v4 01/11] integrity: move ima inode integrity data management Mimi Zohar
@ 2011-03-28 16:39 ` Mimi Zohar
  2011-03-28 16:39 ` [PATCH v4 03/11] evm: re-release Mimi Zohar
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2011-03-28 16:39 UTC (permalink / raw)
  To: linux-security-module
  Cc: Mimi Zohar, linux-kernel, linux-fsdevel, James Morris,
	David Safford, Mimi Zohar

vfs_getxattr_alloc() and vfs_xattr_cmp() are two new kernel xattr helper
functions.  vfs_getxattr_alloc() first allocates memory for the requested
xattr and then retrieves it. vfs_xattr_cmp() compares a given value with
the contents of an extended attribute.

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
Acked-by: Serge Hallyn <serge.hallyn@ubuntu.com>
---
 fs/xattr.c            |   58 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/xattr.h |    5 +++-
 2 files changed, 62 insertions(+), 1 deletions(-)

diff --git a/fs/xattr.c b/fs/xattr.c
index 01bb813..e1f6b8b 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -159,6 +159,64 @@ out_noalloc:
 }
 EXPORT_SYMBOL_GPL(xattr_getsecurity);
 
+/*
+ * vfs_getxattr_alloc - allocate memory, if necessary, before calling getxattr
+ *
+ * Allocate memory, if not already allocated, or re-allocate correct size,
+ * before retrieving the extended attribute.
+ *
+ * Returns the result of alloc, if failed, or the getxattr operation.
+ */
+ssize_t
+vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
+		   size_t xattr_size, gfp_t flags)
+{
+	struct inode *inode = dentry->d_inode;
+	char *value = *xattr_value;
+	int error;
+
+	error = xattr_permission(inode, name, MAY_READ);
+	if (error)
+		return error;
+
+	if (!inode->i_op->getxattr)
+		return -EOPNOTSUPP;
+
+	error = inode->i_op->getxattr(dentry, name, NULL, 0);
+	if (error < 0)
+		return error;
+
+	if (!value || (error > xattr_size)) {
+		value = krealloc(*xattr_value, error + 1, flags);
+		if (!value)
+			return -ENOMEM;
+		memset(value, 0, error + 1);
+	}
+
+	error = inode->i_op->getxattr(dentry, name, value, error);
+	*xattr_value = value;
+	return error;
+}
+
+/* Compare an extended attribute value with the given value */
+int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name,
+		  const char *value, size_t size, gfp_t flags)
+{
+	char *xattr_value = NULL;
+	int rc;
+
+	rc = vfs_getxattr_alloc(dentry, xattr_name, &xattr_value, 0, flags);
+	if (rc < 0)
+		return rc;
+
+	if ((rc != size) || (memcmp(xattr_value, value, rc) != 0))
+		rc = -EINVAL;
+	else
+		rc = 0;
+	kfree(xattr_value);
+	return rc;
+}
+
 ssize_t
 vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
 {
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index 6050783..953a0d5 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -78,7 +78,10 @@ ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer,
 ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);
 int generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags);
 int generic_removexattr(struct dentry *dentry, const char *name);
-
+ssize_t vfs_getxattr_alloc(struct dentry *dentry, const char *name,
+			   char **xattr_value, size_t size, gfp_t flags);
+int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name,
+		  const char *value, size_t size, gfp_t flags);
 #endif  /*  __KERNEL__  */
 
 #endif	/* _LINUX_XATTR_H */
-- 
1.7.3.4

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

* [PATCH v4 03/11] evm: re-release
  2011-03-28 16:39 [PATCH v4 00/11] EVM Mimi Zohar
  2011-03-28 16:39 ` [PATCH v4 01/11] integrity: move ima inode integrity data management Mimi Zohar
  2011-03-28 16:39 ` [PATCH v4 02/11] xattr: define vfs_getxattr_alloc and vfs_xattr_cmp Mimi Zohar
@ 2011-03-28 16:39 ` Mimi Zohar
  2011-03-28 16:39 ` [PATCH v4 04/11] evm: add support for different security.evm data types Mimi Zohar
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2011-03-28 16:39 UTC (permalink / raw)
  To: linux-security-module
  Cc: Mimi Zohar, linux-kernel, linux-fsdevel, James Morris,
	David Safford, Mimi Zohar

EVM protects a file's security extended attributes(xattrs) against integrity
attacks.  This patchset provides the framework and an initial method.  The
initial method maintains an HMAC-sha1 value across the security extended
attributes, storing the HMAC value as the extended attribute 'security.evm'.
Other methods of validating the integrity of a file's metadata will be posted
separately (eg. EVM-digital-signatures).

While this patchset does authenticate the security xattrs, and
cryptographically binds them to the inode, coming extensions will bind other
directory and inode metadata for more complete protection.  To help simplify
the review and upstreaming process, each extension will be posted separately
(eg. IMA-appraisal, IMA-appraisal-directory).  For a general overview of the
proposed Linux integrity subsystem, refer to Dave Safford's whitepaper:
http://downloads.sf.net/project/linux-ima/linux-ima/Integrity_overview.pdf.

EVM depends on the Kernel Key Retention System to provide it with a
trusted/encrypted key for the HMAC-sha1 operation. The key is loaded onto the
root's keyring using keyctl.  Until EVM receives notification that the key has
been successfully loaded onto the keyring (echo 1 > <securityfs>/evm), EVM can
not create or validate the 'security.evm' xattr, but returns INTEGRITY_UNKNOWN.
Loading the key and signaling EVM should be done as early as possible. Normally
this is done in the initramfs, which has already been measured as part of the
trusted boot.  For more information on creating and loading existing
trusted/encrypted keys, refer to Documentation/keys-trusted-encrypted.txt.  A
sample dracut patch, which loads the trusted/encrypted key and enables EVM, is
available from http://linu-ima.sourceforge.net/#EVM.

Based on the LSMs enabled, the set of EVM protected security xattrs is defined
at compile.  EVM adds the following three calls to the existing security hooks:
evm_inode_setxattr(), evm_inode_post_setxattr(), and evm_inode_removexattr.  To
initialize and update the 'security.evm' extended attribute, EVM defines three
calls: evm_inode_post_init(), evm_inode_post_setattr() and
evm_inode_post_removexattr() hooks.  To verify the integrity of a security
xattr, EVM exports evm_verifyxattr().

Changelog:
- locking based on i_mutex, remove evm_mutex
- using trusted/encrypted keys for storing the EVM key used in the HMAC-sha1
  operation.
- replaced crypto hash with shash (Dmitry Kasatkin)
- support for additional methods of verifying the security xattrs
  (Dmitry Kasatkin)
- iint not allocated for all regular files, but only for those appraised
- Use cap_sys_admin in lieu of cap_mac_admin
- Use __vfs_setxattr_noperm(), without permission checks, from EVM

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
---
 Documentation/ABI/testing/evm       |   23 +++
 include/linux/integrity.h           |    7 +
 include/linux/xattr.h               |    3 +
 security/integrity/Kconfig          |    3 +-
 security/integrity/Makefile         |    2 +
 security/integrity/evm/Kconfig      |   12 ++
 security/integrity/evm/Makefile     |    6 +
 security/integrity/evm/evm.h        |   34 ++++
 security/integrity/evm/evm_crypto.c |  177 ++++++++++++++++++++++
 security/integrity/evm/evm_main.c   |  283 +++++++++++++++++++++++++++++++++++
 security/integrity/evm/evm_secfs.c  |  108 +++++++++++++
 security/integrity/iint.c           |    1 +
 security/integrity/integrity.h      |    1 +
 13 files changed, 659 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/ABI/testing/evm
 create mode 100644 security/integrity/evm/Kconfig
 create mode 100644 security/integrity/evm/Makefile
 create mode 100644 security/integrity/evm/evm.h
 create mode 100644 security/integrity/evm/evm_crypto.c
 create mode 100644 security/integrity/evm/evm_main.c
 create mode 100644 security/integrity/evm/evm_secfs.c

diff --git a/Documentation/ABI/testing/evm b/Documentation/ABI/testing/evm
new file mode 100644
index 0000000..37c4e02
--- /dev/null
+++ b/Documentation/ABI/testing/evm
@@ -0,0 +1,23 @@
+What:		security/evm
+Date:		March 2011
+Contact:	Mimi Zohar <zohar@us.ibm.com>
+Description:
+		EVM protects a file's security extended attributes(xattrs)
+		against integrity attacks. The initial method maintains an
+		HMAC-sha1 value across the extended attributes, storing the
+		value as the extended attribute 'security.evm'.
+
+		EVM depends on the Kernel Key Retention System to provide it
+		with a trusted/encrypted key for the HMAC-sha1 operation.
+		The key is loaded onto the root's keyring using keyctl.  Until
+		EVM receives notification that the key has been successfully
+		loaded onto the keyring (echo 1 > <securityfs>/evm), EVM
+		can not create or validate the 'security.evm' xattr, but
+		returns INTEGRITY_UNKNOWN.  Loading the key and signaling EVM
+		should be done as early as possible.  Normally this is done
+		in the initramfs, which has already been measured as part
+		of the trusted boot.  For more information on creating and
+		loading existing trusted/encrypted keys, refer to:
+		Documentation/keys-trusted-encrypted.txt.  (A sample dracut
+		patch, which loads the trusted/encrypted key and enables
+		EVM, is available from http://linu-ima.sourceforge.net/#EVM.)
diff --git a/include/linux/integrity.h b/include/linux/integrity.h
index 9059812..e715a2a 100644
--- a/include/linux/integrity.h
+++ b/include/linux/integrity.h
@@ -12,6 +12,13 @@
 
 #include <linux/fs.h>
 
+enum integrity_status {
+	INTEGRITY_PASS = 0,
+	INTEGRITY_FAIL,
+	INTEGRITY_NOLABEL,
+	INTEGRITY_UNKNOWN,
+};
+
 #ifdef CONFIG_INTEGRITY
 extern int integrity_inode_alloc(struct inode *inode);
 extern void integrity_inode_free(struct inode *inode);
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index 953a0d5..61a9a349 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -34,6 +34,9 @@
 #define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
 
 /* Security namespace */
+#define XATTR_EVM_SUFFIX "evm"
+#define XATTR_NAME_EVM XATTR_SECURITY_PREFIX XATTR_EVM_SUFFIX
+
 #define XATTR_SELINUX_SUFFIX "selinux"
 #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
 
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig
index 2704691..4bf00ac 100644
--- a/security/integrity/Kconfig
+++ b/security/integrity/Kconfig
@@ -1,6 +1,7 @@
 #
 config INTEGRITY
 	def_bool y
-	depends on IMA
+	depends on IMA || EVM
 
 source security/integrity/ima/Kconfig
+source security/integrity/evm/Kconfig
diff --git a/security/integrity/Makefile b/security/integrity/Makefile
index 6eddd61..0ae44ae 100644
--- a/security/integrity/Makefile
+++ b/security/integrity/Makefile
@@ -8,3 +8,5 @@ integrity-y := iint.o
 
 subdir-$(CONFIG_IMA)			+= ima
 obj-$(CONFIG_IMA)			+= ima/built-in.o
+subdir-$(CONFIG_EVM)			+= evm
+obj-$(CONFIG_EVM)			+= evm/built-in.o
diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig
new file mode 100644
index 0000000..73f6540
--- /dev/null
+++ b/security/integrity/evm/Kconfig
@@ -0,0 +1,12 @@
+config EVM
+	boolean "EVM support"
+	depends on SECURITY && KEYS && ENCRYPTED_KEYS
+	select CRYPTO_HMAC
+	select CRYPTO_MD5
+	select CRYPTO_SHA1
+	default n
+	help
+	  EVM protects a file's security extended attributes against
+	  integrity attacks.
+
+	  If you are unsure how to answer this question, answer N.
diff --git a/security/integrity/evm/Makefile b/security/integrity/evm/Makefile
new file mode 100644
index 0000000..0787d26
--- /dev/null
+++ b/security/integrity/evm/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for building the Extended Verification Module(EVM)
+#
+obj-$(CONFIG_EVM) += evm.o
+
+evm-y := evm_main.o evm_crypto.o evm_secfs.o
diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h
new file mode 100644
index 0000000..f2bbe43
--- /dev/null
+++ b/security/integrity/evm/evm.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2005-2010 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zohar@us.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: evm.h
+ *
+ */
+#include <linux/security.h>
+#include "../integrity.h"
+
+extern int evm_initialized;
+extern char *evm_hmac;
+extern int evm_hmac_size;
+
+/* List of EVM protected security xattrs */
+extern char *evm_config_xattrnames[];
+
+extern int evm_init_key(void);
+extern int evm_update_evmxattr(struct dentry *dentry,
+			       const char *req_xattr_name,
+			       const char *req_xattr_value,
+			       size_t req_xattr_value_len);
+extern int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
+			 const char *req_xattr_value,
+			 size_t req_xattr_value_len, char *digest);
+extern int evm_init_secfs(void);
+extern void evm_cleanup_secfs(void);
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
new file mode 100644
index 0000000..c43be5a
--- /dev/null
+++ b/security/integrity/evm/evm_crypto.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2005-2010 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zohar@us.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: evm_crypto.c
+ *	 Using root's kernel master key (kmk), calculate the HMAC
+ */
+
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <linux/xattr.h>
+#include <keys/encrypted-type.h>
+#include <linux/scatterlist.h>
+#include "evm.h"
+
+#define EVMKEY "evm-key"
+#define MAX_KEY_SIZE 128
+static unsigned char evmkey[MAX_KEY_SIZE];
+static int evmkey_len = MAX_KEY_SIZE;
+
+static int init_desc(struct hash_desc *desc)
+{
+	int rc;
+
+	desc->tfm = crypto_alloc_hash(evm_hmac, 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(desc->tfm)) {
+		pr_info("Can not allocate %s (reason: %ld)\n",
+			evm_hmac, PTR_ERR(desc->tfm));
+		rc = PTR_ERR(desc->tfm);
+		return rc;
+	}
+	desc->flags = 0;
+	crypto_hash_setkey(desc->tfm, evmkey, evmkey_len);
+	rc = crypto_hash_init(desc);
+	if (rc)
+		crypto_free_hash(desc->tfm);
+	return rc;
+}
+
+/* Protect against 'cutting & pasting' security.evm xattr, include inode
+ * specific info.
+ *
+ * (Additional directory/file metadata needs to be added for more complete
+ * protection.)
+ */
+static void hmac_add_misc(struct hash_desc *desc, struct inode *inode,
+			  char *digest)
+{
+	struct h_misc {
+		unsigned long ino;
+		__u32 generation;
+		uid_t uid;
+		gid_t gid;
+		umode_t mode;
+	} hmac_misc;
+	struct scatterlist sg[1];
+
+	memset(&hmac_misc, 0, sizeof hmac_misc);
+	hmac_misc.ino = inode->i_ino;
+	hmac_misc.generation = inode->i_generation;
+	hmac_misc.uid = inode->i_uid;
+	hmac_misc.gid = inode->i_gid;
+	hmac_misc.mode = inode->i_mode;
+	sg_init_one(sg, &hmac_misc, sizeof hmac_misc);
+	crypto_hash_update(desc, sg, sizeof hmac_misc);
+	crypto_hash_final(desc, digest);
+}
+
+/*
+ * Calculate the HMAC value across the set of protected security xattrs.
+ *
+ * Instead of retrieving the requested xattr, for performance, calculate
+ * the hmac using the requested xattr value. Don't alloc/free memory for
+ * each xattr, but attempt to re-use the previously allocated memory.
+ */
+int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
+		  const char *req_xattr_value, size_t req_xattr_value_len,
+		  char *digest)
+{
+	struct inode *inode = dentry->d_inode;
+	struct hash_desc desc;
+	struct scatterlist sg[1];
+	char **xattrname;
+	size_t xattr_size = 0;
+	char *xattr_value = NULL;
+	int error;
+	int size;
+
+	if (!inode->i_op || !inode->i_op->getxattr)
+		return -EOPNOTSUPP;
+	error = init_desc(&desc);
+	if (error)
+		return error;
+
+	error = -ENODATA;
+	for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
+		if ((req_xattr_name && req_xattr_value)
+		    && !strcmp(*xattrname, req_xattr_name)) {
+			error = 0;
+			sg_init_one(sg, req_xattr_value, req_xattr_value_len);
+			crypto_hash_update(&desc, sg, req_xattr_value_len);
+			continue;
+		}
+		size = vfs_getxattr_alloc(dentry, *xattrname,
+					  &xattr_value, xattr_size, GFP_NOFS);
+		if (size == -ENOMEM) {
+			error = -ENOMEM;
+			goto out;
+		}
+		if (size < 0)
+			continue;
+
+		error = 0;
+		xattr_size = size;
+		sg_init_one(sg, xattr_value, xattr_size);
+		crypto_hash_update(&desc, sg, xattr_size);
+	}
+	hmac_add_misc(&desc, inode, digest);
+	kfree(xattr_value);
+out:
+	crypto_free_hash(desc.tfm);
+	return error;
+}
+
+/*
+ * Calculate the hmac and update security.evm xattr
+ *
+ * Expects to be called with i_mutex locked.
+ */
+int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
+			const char *xattr_value, size_t xattr_value_len)
+{
+	struct inode *inode = dentry->d_inode;
+	u8 hmac[MAX_DIGEST_SIZE];
+	int rc = 0;
+
+	rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
+			   xattr_value_len, hmac);
+	if (rc == 0)
+		rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM,
+					   hmac, evm_hmac_size, 0);
+	else if (rc == -ENODATA)
+		rc = inode->i_op->removexattr(dentry, XATTR_NAME_EVM);
+	return rc;
+}
+
+/*
+ * Get the key from the TPM for the SHA1-HMAC
+ */
+int evm_init_key(void)
+{
+	struct key *evm_key;
+	struct encrypted_key_payload *ekp;
+
+	evm_key = request_key(&key_type_encrypted, EVMKEY, NULL);
+	if (IS_ERR(evm_key))
+		return -ENOENT;
+
+	down_read(&evm_key->sem);
+	ekp = evm_key->payload.data;
+	evmkey_len = ekp->decrypted_datalen > MAX_KEY_SIZE ? MAX_KEY_SIZE :
+			ekp->decrypted_datalen;
+	memcpy(evmkey, ekp->decrypted_data, evmkey_len);
+
+	/* burn the original key contents */
+	memset(ekp->decrypted_data, 0, evmkey_len);
+	up_read(&evm_key->sem);
+	key_put(evm_key);
+	return 0;
+}
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
new file mode 100644
index 0000000..66d7544
--- /dev/null
+++ b/security/integrity/evm/evm_main.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2005-2010 IBM Corporation
+ *
+ * Author:
+ * Mimi Zohar <zohar@us.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: evm_main.c
+ *	implements evm_inode_setxattr, evm_inode_post_setxattr,
+ *	evm_inode_removexattr, and evm_verifyxattr
+ */
+
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <linux/xattr.h>
+#include <linux/integrity.h>
+#include "evm.h"
+
+int evm_initialized;
+
+char *evm_hmac = "hmac(sha1)";
+int evm_hmac_size = SHA1_DIGEST_SIZE;
+
+char *evm_config_xattrnames[] = {
+#ifdef CONFIG_SECURITY_SELINUX
+	XATTR_NAME_SELINUX,
+#endif
+#ifdef CONFIG_SECURITY_SMACK
+	XATTR_NAME_SMACK,
+#endif
+	XATTR_NAME_CAPS,
+	NULL
+};
+
+/*
+ * evm_verify_hmac - calculate and compare the HMAC with the EVM xattr
+ *
+ * Compute the HMAC on the dentry's protected set of extended attributes
+ * and compare it against the stored security.evm xattr. (For performance,
+ * use the previoulsy retrieved xattr value and length to calculate the
+ * HMAC.)
+ *
+ * Returns integrity status
+ */
+static enum integrity_status evm_verify_hmac(struct dentry *dentry,
+					     const char *xattr_name,
+					     char *xattr_value,
+					     size_t xattr_value_len,
+					     struct integrity_iint_cache *iint)
+{
+	char hmac_val[MAX_DIGEST_SIZE];
+	int rc;
+
+	if (iint->hmac_status != INTEGRITY_UNKNOWN)
+		return iint->hmac_status;
+
+	memset(hmac_val, 0, sizeof hmac_val);
+	rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
+			   xattr_value_len, hmac_val);
+	if (rc < 0)
+		return INTEGRITY_UNKNOWN;
+
+	rc = vfs_xattr_cmp(dentry, XATTR_NAME_EVM, hmac_val, sizeof hmac_val,
+			   GFP_NOFS);
+	if (rc < 0)
+		goto err_out;
+	iint->hmac_status = INTEGRITY_PASS;
+	return iint->hmac_status;
+
+err_out:
+	switch (rc) {
+	case -ENODATA:		/* file not labelled */
+		iint->hmac_status = INTEGRITY_NOLABEL;
+		break;
+	case -EINVAL:
+		iint->hmac_status = INTEGRITY_FAIL;
+		break;
+	default:
+		iint->hmac_status = INTEGRITY_UNKNOWN;
+	}
+	return iint->hmac_status;
+}
+
+static int evm_protected_xattr(const char *req_xattr_name)
+{
+	char **xattrname;
+	int found = 0;
+
+	for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
+		if (strncmp(req_xattr_name, *xattrname,
+			    strlen(req_xattr_name)) == 0) {
+			found = 1;
+			break;
+		}
+	}
+	return found;
+}
+
+/**
+ * evm_verifyxattr - verify the integrity of the requested xattr
+ * @dentry: object of the verify xattr
+ * @xattr_name: requested xattr
+ * @xattr_value: requested xattr value
+ * @xattr_value_len: requested xattr value length
+ *
+ * Calculate the HMAC for the given dentry and verify it against the stored
+ * security.evm xattr. For performance, use the xattr value and length
+ * previously retrieved to calculate the HMAC.
+ *
+ * Returns the xattr integrity status.
+ *
+ * This function requires the caller to lock the inode's i_mutex before it
+ * is executed.
+ */
+enum integrity_status evm_verifyxattr(struct dentry *dentry,
+				      const char *xattr_name,
+				      void *xattr_value, size_t xattr_value_len)
+{
+	struct inode *inode = dentry->d_inode;
+	struct integrity_iint_cache *iint;
+	enum integrity_status status;
+
+	if (!evm_initialized || !evm_protected_xattr(xattr_name))
+		return INTEGRITY_UNKNOWN;
+
+	iint = integrity_iint_find(inode);
+	if (!iint)
+		return INTEGRITY_UNKNOWN;
+	status = evm_verify_hmac(dentry, xattr_name, xattr_value,
+				 xattr_value_len, iint);
+	return status;
+}
+EXPORT_SYMBOL_GPL(evm_verifyxattr);
+
+/*
+ * evm_protect_xattr - protect the EVM extended attribute
+ *
+ * Prevent security.evm from being modified or removed.
+ */
+static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
+			     const void *xattr_value, size_t xattr_value_len)
+{
+	if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) {
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+	}
+	return 0;
+}
+
+/**
+ * evm_inode_setxattr - protect the EVM extended attribute
+ * @dentry: pointer to the affected dentry
+ * @xattr_name: pointer to the affected extended attribute name
+ * @xattr_value: pointer to the new extended attribute value
+ * @xattr_value_len: pointer to the new extended attribute value length
+ *
+ * Prevent 'security.evm' from being modified
+ */
+int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,
+		       const void *xattr_value, size_t xattr_value_len)
+{
+	return evm_protect_xattr(dentry, xattr_name, xattr_value,
+				 xattr_value_len);
+}
+
+/**
+ * evm_inode_removexattr - protect the EVM extended attribute
+ * @dentry: pointer to the affected dentry
+ * @xattr_name: pointer to the affected extended attribute name
+ *
+ * Prevent 'security.evm' from being removed.
+ */
+int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name)
+{
+	return evm_protect_xattr(dentry, xattr_name, NULL, 0);
+}
+
+/**
+ * evm_inode_post_setxattr - update 'security.evm' to reflect the changes
+ * @dentry: pointer to the affected dentry
+ * @xattr_name: pointer to the affected extended attribute name
+ * @xattr_value: pointer to the new extended attribute value
+ * @xattr_value_len: pointer to the new extended attribute value length
+ *
+ * Update the HMAC stored in 'security.evm' to reflect the change.
+ *
+ * No need to take the i_mutex lock here, as this function is called from
+ * __vfs_setxattr_noperm().  The caller of which has taken the inode's
+ * i_mutex lock.
+ */
+void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
+			     const void *xattr_value, size_t xattr_value_len)
+{
+	if (!evm_initialized || !evm_protected_xattr(xattr_name))
+		return;
+
+	evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
+	return;
+}
+
+/**
+ * evm_inode_post_removexattr - update 'security.evm' after removing the xattr
+ * @dentry: pointer to the affected dentry
+ * @xattr_name: pointer to the affected extended attribute name
+ *
+ * Update the HMAC stored in 'security.evm' to reflect removal of the xattr.
+ */
+void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
+{
+	struct inode *inode = dentry->d_inode;
+
+	if (!evm_initialized || !evm_protected_xattr(xattr_name))
+		return;
+
+	mutex_lock(&inode->i_mutex);
+	evm_update_evmxattr(dentry, xattr_name, NULL, 0);
+	mutex_unlock(&inode->i_mutex);
+	return;
+}
+
+/**
+ * evm_inode_post_setattr - update 'security.evm' after modifying metadata
+ * @dentry: pointer to the affected dentry
+ * @ia_valid: for the UID and GID status
+ *
+ * For now, update the HMAC stored in 'security.evm' to reflect UID/GID
+ * changes.
+ *
+ * This function is called from notify_change(), which expects the caller
+ * to lock the inode's i_mutex.
+ */
+void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
+{
+	if (!evm_initialized)
+		return;
+
+	if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
+		evm_update_evmxattr(dentry, NULL, NULL, 0);
+	return;
+}
+
+static struct crypto_hash *tfm_hmac;	/* preload crypto alg */
+static int __init init_evm(void)
+{
+	int error;
+
+	tfm_hmac = crypto_alloc_hash(evm_hmac, 0, CRYPTO_ALG_ASYNC);
+	error = evm_init_secfs();
+	if (error < 0) {
+		printk(KERN_INFO "EVM: Error registering secfs\n");
+		goto err;
+	}
+err:
+	return error;
+}
+
+static void __exit cleanup_evm(void)
+{
+	evm_cleanup_secfs();
+	crypto_free_hash(tfm_hmac);
+}
+
+/*
+ * evm_display_config - list the EVM protected security extended attributes
+ */
+static int __init evm_display_config(void)
+{
+	char **xattrname;
+
+	for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++)
+		printk(KERN_INFO "EVM: %s\n", *xattrname);
+	return 0;
+}
+
+pure_initcall(evm_display_config);
+late_initcall(init_evm);
+
+MODULE_DESCRIPTION("Extended Verification Module");
+MODULE_LICENSE("GPL");
diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c
new file mode 100644
index 0000000..ac76299
--- /dev/null
+++ b/security/integrity/evm/evm_secfs.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: evm_secfs.c
+ *	- Used to signal when key is on keyring
+ *	- Get the key and enable EVM
+ */
+
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include "evm.h"
+
+static struct dentry *evm_init_tpm;
+
+/**
+ * evm_read_key - read() for <securityfs>/evm
+ *
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t evm_read_key(struct file *filp, char __user *buf,
+			    size_t count, loff_t *ppos)
+{
+	char temp[80];
+	ssize_t rc;
+
+	if (*ppos != 0)
+		return 0;
+
+	sprintf(temp, "%d", evm_initialized);
+	rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
+
+	return rc;
+}
+
+/**
+ * evm_write_key - write() for <securityfs>/evm
+ * @file: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Used to signal that key is on the kernel key ring.
+ * - get the integrity hmac key from the kernel key ring
+ * - create list of hmac protected extended attributes
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t evm_write_key(struct file *file, const char __user *buf,
+			     size_t count, loff_t *ppos)
+{
+	char temp[80];
+	int i, error;
+
+	if (!capable(CAP_SYS_ADMIN) || evm_initialized)
+		return -EPERM;
+
+	if (count >= sizeof(temp) || count == 0)
+		return -EINVAL;
+
+	if (copy_from_user(temp, buf, count) != 0)
+		return -EFAULT;
+
+	temp[count] = '\0';
+
+	if ((sscanf(temp, "%d", &i) != 1) || (i != 1))
+		return -EINVAL;
+
+	error = evm_init_key();
+	if (!error) {
+		evm_initialized = 1;
+		pr_info("EVM: initialized\n");
+	} else
+		pr_err("EVM: initialization failed\n");
+	return count;
+}
+
+static const struct file_operations evm_key_ops = {
+	.read		= evm_read_key,
+	.write		= evm_write_key,
+};
+
+int __init evm_init_secfs(void)
+{
+	int error = 0;
+
+	evm_init_tpm = securityfs_create_file("evm", S_IRUSR | S_IRGRP,
+					      NULL, NULL, &evm_key_ops);
+	if (!evm_init_tpm || IS_ERR(evm_init_tpm))
+		error = -EFAULT;
+	return error;
+}
+
+void __exit evm_cleanup_secfs(void)
+{
+	if (evm_init_tpm)
+		securityfs_remove(evm_init_tpm);
+}
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index d17de48..991df20 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -157,6 +157,7 @@ static void init_once(void *foo)
 	iint->version = 0;
 	iint->flags = 0UL;
 	mutex_init(&iint->mutex);
+	iint->hmac_status = INTEGRITY_UNKNOWN;
 }
 
 static int __init integrity_iintcache_init(void)
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 2217a28..2232cd1 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -28,6 +28,7 @@ struct integrity_iint_cache {
 	unsigned char flags;
 	u8 digest[MAX_DIGEST_SIZE];
 	struct mutex mutex;	/* protects: version, flags, digest */
+	enum integrity_status hmac_status;
 };
 
 /* rbtree tree calls to lookup, insert, delete
-- 
1.7.3.4

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

* [PATCH v4 04/11] evm: add support for different security.evm data types
  2011-03-28 16:39 [PATCH v4 00/11] EVM Mimi Zohar
                   ` (2 preceding siblings ...)
  2011-03-28 16:39 ` [PATCH v4 03/11] evm: re-release Mimi Zohar
@ 2011-03-28 16:39 ` Mimi Zohar
  2011-03-28 16:39 ` [PATCH v4 05/11] ima: move ima_file_free before releasing the file Mimi Zohar
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2011-03-28 16:39 UTC (permalink / raw)
  To: linux-security-module
  Cc: Dmitry Kasatkin, linux-kernel, linux-fsdevel, James Morris,
	David Safford, Mimi Zohar

From: Dmitry Kasatkin <dmitry.kasatkin@nokia.com>

EVM protects a file's security extended attributes(xattrs) against integrity
attacks. The current patchset maintains an HMAC-sha1 value across the security
xattrs, storing the value as the extended attribute 'security.evm'. We
anticipate other methods for protecting the security extended attributes.
This patch reserves the first byte of 'security.evm' as a place holder for
the type of method.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
---
 include/linux/integrity.h           |    6 ++++++
 security/integrity/evm/evm_crypto.c |   10 ++++++----
 security/integrity/evm/evm_main.c   |    5 +++--
 3 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/include/linux/integrity.h b/include/linux/integrity.h
index e715a2a..6659757 100644
--- a/include/linux/integrity.h
+++ b/include/linux/integrity.h
@@ -19,6 +19,12 @@ enum integrity_status {
 	INTEGRITY_UNKNOWN,
 };
 
+enum evm_ima_xattr_type {
+	IMA_XATTR_DIGEST = 0x01,
+	EVM_XATTR_HMAC,
+	EVM_IMA_XATTR_DIGSIG,
+};
+
 #ifdef CONFIG_INTEGRITY
 extern int integrity_inode_alloc(struct inode *inode);
 extern void integrity_inode_free(struct inode *inode);
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index c43be5a..644df7e 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -138,14 +138,16 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
 			const char *xattr_value, size_t xattr_value_len)
 {
 	struct inode *inode = dentry->d_inode;
-	u8 hmac[MAX_DIGEST_SIZE];
+	u8 hmac[MAX_DIGEST_SIZE + 1];
 	int rc = 0;
 
 	rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
-			   xattr_value_len, hmac);
-	if (rc == 0)
+			   xattr_value_len, hmac + 1);
+	if (rc == 0) {
+		hmac[0] = EVM_XATTR_HMAC;
 		rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM,
-					   hmac, evm_hmac_size, 0);
+					   hmac, evm_hmac_size + 1, 0);
+	}
 	else if (rc == -ENODATA)
 		rc = inode->i_op->removexattr(dentry, XATTR_NAME_EVM);
 	return rc;
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 66d7544..42c792f 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -52,7 +52,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
 					     size_t xattr_value_len,
 					     struct integrity_iint_cache *iint)
 {
-	char hmac_val[MAX_DIGEST_SIZE];
+	char hmac_val[MAX_DIGEST_SIZE + 1];
 	int rc;
 
 	if (iint->hmac_status != INTEGRITY_UNKNOWN)
@@ -60,10 +60,11 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
 
 	memset(hmac_val, 0, sizeof hmac_val);
 	rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
-			   xattr_value_len, hmac_val);
+			   xattr_value_len, hmac_val + 1);
 	if (rc < 0)
 		return INTEGRITY_UNKNOWN;
 
+	hmac_val[0] = EVM_XATTR_HMAC;
 	rc = vfs_xattr_cmp(dentry, XATTR_NAME_EVM, hmac_val, sizeof hmac_val,
 			   GFP_NOFS);
 	if (rc < 0)
-- 
1.7.3.4

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

* [PATCH v4 05/11] ima: move ima_file_free before releasing the file
  2011-03-28 16:39 [PATCH v4 00/11] EVM Mimi Zohar
                   ` (3 preceding siblings ...)
  2011-03-28 16:39 ` [PATCH v4 04/11] evm: add support for different security.evm data types Mimi Zohar
@ 2011-03-28 16:39 ` Mimi Zohar
  2011-03-28 16:39 ` [PATCH v4 06/11] security: imbed evm calls in security hooks Mimi Zohar
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2011-03-28 16:39 UTC (permalink / raw)
  To: linux-security-module
  Cc: Mimi Zohar, linux-kernel, linux-fsdevel, James Morris,
	David Safford, Mimi Zohar

Integrity appraisal measures files on file_free and stores the file
measurement as an xattr.  Measure the file before releasing it.

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
Acked-by: Serge Hallyn <serge.hallyn@ubuntu.com>
---
 fs/file_table.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/fs/file_table.c b/fs/file_table.c
index 01e4c1e..33f54a1 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -243,10 +243,10 @@ static void __fput(struct file *file)
 		if (file->f_op && file->f_op->fasync)
 			file->f_op->fasync(-1, file, 0);
 	}
+	ima_file_free(file);
 	if (file->f_op && file->f_op->release)
 		file->f_op->release(inode, file);
 	security_file_free(file);
-	ima_file_free(file);
 	if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL &&
 		     !(file->f_mode & FMODE_PATH))) {
 		cdev_put(inode->i_cdev);
-- 
1.7.3.4


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

* [PATCH v4 06/11] security: imbed evm calls in security hooks
  2011-03-28 16:39 [PATCH v4 00/11] EVM Mimi Zohar
                   ` (4 preceding siblings ...)
  2011-03-28 16:39 ` [PATCH v4 05/11] ima: move ima_file_free before releasing the file Mimi Zohar
@ 2011-03-28 16:39 ` Mimi Zohar
  2011-03-28 16:39 ` [PATCH v4 07/11] evm: inode post removexattr Mimi Zohar
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2011-03-28 16:39 UTC (permalink / raw)
  To: linux-security-module
  Cc: Mimi Zohar, linux-kernel, linux-fsdevel, James Morris,
	David Safford, Mimi Zohar

Imbed the evm calls evm_inode_setxattr(), evm_inode_post_setxattr(),
evm_inode_removexattr() in the security hooks.  evm_inode_setxattr()
protects security.evm xattr.  evm_inode_post_setxattr() and
evm_inode_removexattr() updates the hmac associated with an inode.

(Assumes an LSM module protects the setting/removing of xattr.)

Changelog:
  - Don't define evm_verifyxattr(), unless CONFIG_INTEGRITY is enabled.
  - xattr_name is a 'const', value is 'void *'

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
Acked-by: Serge Hallyn <serge.hallyn@ubuntu.com>
---
 include/linux/evm.h               |   56 +++++++++++++++++++++++++++++++++++++
 security/integrity/evm/evm_main.c |    1 +
 security/security.c               |   16 +++++++++-
 3 files changed, 71 insertions(+), 2 deletions(-)
 create mode 100644 include/linux/evm.h

diff --git a/include/linux/evm.h b/include/linux/evm.h
new file mode 100644
index 0000000..8b4e9e3
--- /dev/null
+++ b/include/linux/evm.h
@@ -0,0 +1,56 @@
+/*
+ * evm.h
+ *
+ * Copyright (c) 2009 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ */
+
+#ifndef _LINUX_EVM_H
+#define _LINUX_EVM_H
+
+#include <linux/integrity.h>
+
+#ifdef CONFIG_EVM
+extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
+					     const char *xattr_name,
+					     void *xattr_value,
+					     size_t xattr_value_len);
+extern int evm_inode_setxattr(struct dentry *dentry, const char *name,
+			      const void *value, size_t size);
+extern void evm_inode_post_setxattr(struct dentry *dentry,
+				    const char *xattr_name,
+				    const void *xattr_value,
+				    size_t xattr_value_len);
+extern int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name);
+#else
+#ifdef CONFIG_INTEGRITY
+static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
+						    const char *xattr_name,
+						    void *xattr_value,
+						    size_t xattr_value_len)
+{
+	return INTEGRITY_UNKNOWN;
+}
+#endif
+
+static inline int evm_inode_setxattr(struct dentry *dentry, const char *name,
+				     const void *value, size_t size)
+{
+	return 0;
+}
+
+static inline void evm_inode_post_setxattr(struct dentry *dentry,
+					   const char *xattr_name,
+					   const void *xattr_value,
+					   size_t xattr_value_len)
+{
+	return;
+}
+
+static inline int evm_inode_removexattr(struct dentry *dentry,
+					const char *xattr_name)
+{
+	return 0;
+}
+#endif /* CONFIG_EVM_H */
+#endif /* LINUX_EVM_H */
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 42c792f..e89ceb1 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -18,6 +18,7 @@
 #include <linux/crypto.h>
 #include <linux/xattr.h>
 #include <linux/integrity.h>
+#include <linux/evm.h>
 #include "evm.h"
 
 int evm_initialized;
diff --git a/security/security.c b/security/security.c
index 9c34793..7271ed3 100644
--- a/security/security.c
+++ b/security/security.c
@@ -18,6 +18,7 @@
 #include <linux/security.h>
 #include <linux/integrity.h>
 #include <linux/ima.h>
+#include <linux/evm.h>
 
 /* Boot-time LSM user choice */
 static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
@@ -545,9 +546,14 @@ int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
 int security_inode_setxattr(struct dentry *dentry, const char *name,
 			    const void *value, size_t size, int flags)
 {
+	int ret;
+
 	if (unlikely(IS_PRIVATE(dentry->d_inode)))
 		return 0;
-	return security_ops->inode_setxattr(dentry, name, value, size, flags);
+	ret = security_ops->inode_setxattr(dentry, name, value, size, flags);
+	if (ret)
+		return ret;
+	return evm_inode_setxattr(dentry, name, value, size);
 }
 
 void security_inode_post_setxattr(struct dentry *dentry, const char *name,
@@ -556,6 +562,7 @@ void security_inode_post_setxattr(struct dentry *dentry, const char *name,
 	if (unlikely(IS_PRIVATE(dentry->d_inode)))
 		return;
 	security_ops->inode_post_setxattr(dentry, name, value, size, flags);
+	evm_inode_post_setxattr(dentry, name, value, size);
 }
 
 int security_inode_getxattr(struct dentry *dentry, const char *name)
@@ -574,9 +581,14 @@ int security_inode_listxattr(struct dentry *dentry)
 
 int security_inode_removexattr(struct dentry *dentry, const char *name)
 {
+	int ret;
+
 	if (unlikely(IS_PRIVATE(dentry->d_inode)))
 		return 0;
-	return security_ops->inode_removexattr(dentry, name);
+	ret = security_ops->inode_removexattr(dentry, name);
+	if (ret)
+		return ret;
+	return evm_inode_removexattr(dentry, name);
 }
 
 int security_inode_need_killpriv(struct dentry *dentry)
-- 
1.7.3.4

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

* [PATCH v4 07/11] evm: inode post removexattr
  2011-03-28 16:39 [PATCH v4 00/11] EVM Mimi Zohar
                   ` (5 preceding siblings ...)
  2011-03-28 16:39 ` [PATCH v4 06/11] security: imbed evm calls in security hooks Mimi Zohar
@ 2011-03-28 16:39 ` Mimi Zohar
  2011-03-28 16:39 ` [PATCH v4 08/11] evm: imbed evm_inode_post_setattr Mimi Zohar
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2011-03-28 16:39 UTC (permalink / raw)
  To: linux-security-module
  Cc: Mimi Zohar, linux-kernel, linux-fsdevel, James Morris,
	David Safford, Mimi Zohar

When an EVM protected extended attribute is removed, update 'security.evm'.

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
Acked-by: Serge Hallyn <serge.hallyn@ubuntu.com>
---
 fs/xattr.c          |    5 ++++-
 include/linux/evm.h |    9 +++++++++
 2 files changed, 13 insertions(+), 1 deletions(-)

diff --git a/fs/xattr.c b/fs/xattr.c
index e1f6b8b..ad7cdc6 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -14,6 +14,7 @@
 #include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/security.h>
+#include <linux/evm.h>
 #include <linux/syscalls.h>
 #include <linux/module.h>
 #include <linux/fsnotify.h>
@@ -294,8 +295,10 @@ vfs_removexattr(struct dentry *dentry, const char *name)
 	error = inode->i_op->removexattr(dentry, name);
 	mutex_unlock(&inode->i_mutex);
 
-	if (!error)
+	if (!error) {
 		fsnotify_xattr(dentry);
+		evm_inode_post_removexattr(dentry, name);
+	}
 	return error;
 }
 EXPORT_SYMBOL_GPL(vfs_removexattr);
diff --git a/include/linux/evm.h b/include/linux/evm.h
index 8b4e9e3..a730782 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -22,6 +22,8 @@ extern void evm_inode_post_setxattr(struct dentry *dentry,
 				    const void *xattr_value,
 				    size_t xattr_value_len);
 extern int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name);
+extern void evm_inode_post_removexattr(struct dentry *dentry,
+				       const char *xattr_name);
 #else
 #ifdef CONFIG_INTEGRITY
 static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
@@ -52,5 +54,12 @@ static inline int evm_inode_removexattr(struct dentry *dentry,
 {
 	return 0;
 }
+
+static inline void evm_inode_post_removexattr(struct dentry *dentry,
+					      const char *xattr_name)
+{
+	return;
+}
+
 #endif /* CONFIG_EVM_H */
 #endif /* LINUX_EVM_H */
-- 
1.7.3.4

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

* [PATCH v4 08/11] evm: imbed evm_inode_post_setattr
  2011-03-28 16:39 [PATCH v4 00/11] EVM Mimi Zohar
                   ` (6 preceding siblings ...)
  2011-03-28 16:39 ` [PATCH v4 07/11] evm: inode post removexattr Mimi Zohar
@ 2011-03-28 16:39 ` Mimi Zohar
  2011-03-28 16:39 ` [PATCH v4 09/11] evm: inode_post_init Mimi Zohar
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2011-03-28 16:39 UTC (permalink / raw)
  To: linux-security-module
  Cc: Mimi Zohar, linux-kernel, linux-fsdevel, James Morris,
	David Safford, Mimi Zohar

Changing the inode's metadata may require the 'security.evm' extended
attribute to be re-calculated and updated.

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
Acked-by: Serge Hallyn <serge.hallyn@ubuntu.com>
---
 fs/attr.c           |    5 ++++-
 include/linux/evm.h |    6 ++++++
 2 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/fs/attr.c b/fs/attr.c
index 7ca4181..fbc5a09 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -13,6 +13,7 @@
 #include <linux/fsnotify.h>
 #include <linux/fcntl.h>
 #include <linux/security.h>
+#include <linux/evm.h>
 
 /**
  * inode_change_ok - check if attribute changes to an inode are allowed
@@ -236,8 +237,10 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
 	if (ia_valid & ATTR_SIZE)
 		up_write(&dentry->d_inode->i_alloc_sem);
 
-	if (!error)
+	if (!error) {
 		fsnotify_change(dentry, ia_valid);
+		evm_inode_post_setattr(dentry, ia_valid);
+	}
 
 	return error;
 }
diff --git a/include/linux/evm.h b/include/linux/evm.h
index a730782..33a9247 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -15,6 +15,7 @@ extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
 					     const char *xattr_name,
 					     void *xattr_value,
 					     size_t xattr_value_len);
+extern void evm_inode_post_setattr(struct dentry *dentry, int ia_valid);
 extern int evm_inode_setxattr(struct dentry *dentry, const char *name,
 			      const void *value, size_t size);
 extern void evm_inode_post_setxattr(struct dentry *dentry,
@@ -35,6 +36,11 @@ static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
 }
 #endif
 
+static inline void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
+{
+	return;
+}
+
 static inline int evm_inode_setxattr(struct dentry *dentry, const char *name,
 				     const void *value, size_t size)
 {
-- 
1.7.3.4

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

* [PATCH v4 09/11] evm: inode_post_init
  2011-03-28 16:39 [PATCH v4 00/11] EVM Mimi Zohar
                   ` (7 preceding siblings ...)
  2011-03-28 16:39 ` [PATCH v4 08/11] evm: imbed evm_inode_post_setattr Mimi Zohar
@ 2011-03-28 16:39 ` Mimi Zohar
  2011-03-28 16:39 ` [PATCH v4 10/11] fs: add evm_inode_post_init calls Mimi Zohar
  2011-03-28 16:39 ` [PATCH v4 11/11] evm: crypto hash replaced by shash Mimi Zohar
  10 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2011-03-28 16:39 UTC (permalink / raw)
  To: linux-security-module
  Cc: Mimi Zohar, linux-kernel, linux-fsdevel, James Morris,
	David Safford, Mimi Zohar

Initialize 'security.evm' for new files. Reduce number of arguments
by defining 'struct xattr'.

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
Acked-by: Serge Hallyn <serge.hallyn@ubuntu.com>
---
 include/linux/evm.h                 |   11 ++++++++++
 include/linux/xattr.h               |    6 +++++
 security/integrity/evm/evm.h        |    3 ++
 security/integrity/evm/evm_crypto.c |   20 ++++++++++++++++++
 security/integrity/evm/evm_main.c   |   38 +++++++++++++++++++++++++++++++++++
 5 files changed, 78 insertions(+), 0 deletions(-)

diff --git a/include/linux/evm.h b/include/linux/evm.h
index 33a9247..c3bc089 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -9,6 +9,7 @@
 #define _LINUX_EVM_H
 
 #include <linux/integrity.h>
+#include <linux/xattr.h>
 
 #ifdef CONFIG_EVM
 extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
@@ -25,6 +26,9 @@ extern void evm_inode_post_setxattr(struct dentry *dentry,
 extern int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name);
 extern void evm_inode_post_removexattr(struct dentry *dentry,
 				       const char *xattr_name);
+extern int evm_inode_post_init_security(struct inode *inode,
+					const struct xattr *new,
+					struct xattr *evm);
 #else
 #ifdef CONFIG_INTEGRITY
 static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
@@ -67,5 +71,12 @@ static inline void evm_inode_post_removexattr(struct dentry *dentry,
 	return;
 }
 
+static inline int evm_inode_post_init_security(struct inode *inode,
+					       const struct xattr *new,
+					       struct xattr *evm)
+{
+	return -EOPNOTSUPP;
+}
+
 #endif /* CONFIG_EVM_H */
 #endif /* LINUX_EVM_H */
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index 61a9a349..32d934e 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -70,6 +70,12 @@ struct xattr_handler {
 		   size_t size, int flags, int handler_flags);
 };
 
+struct xattr {
+	char *name;
+	void *value;
+	size_t value_len;
+};
+
 ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
 ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t);
 ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h
index f2bbe43..65ab9db 100644
--- a/security/integrity/evm/evm.h
+++ b/security/integrity/evm/evm.h
@@ -12,6 +12,7 @@
  * File: evm.h
  *
  */
+#include <linux/xattr.h>
 #include <linux/security.h>
 #include "../integrity.h"
 
@@ -30,5 +31,7 @@ extern int evm_update_evmxattr(struct dentry *dentry,
 extern int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
 			 const char *req_xattr_value,
 			 size_t req_xattr_value_len, char *digest);
+extern int evm_init_hmac(struct inode *inode, const struct xattr *xattr,
+			 char *hmac_val);
 extern int evm_init_secfs(void);
 extern void evm_cleanup_secfs(void);
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index 644df7e..e029a37 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -153,6 +153,26 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
 	return rc;
 }
 
+int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,
+		  char *hmac_val)
+{
+	struct hash_desc desc;
+	struct scatterlist sg[1];
+	int error;
+
+	error = init_desc(&desc);
+	if (error != 0) {
+		printk(KERN_INFO "init_desc failed\n");
+		return error;
+	}
+
+	sg_init_one(sg, lsm_xattr->value, lsm_xattr->value_len);
+	crypto_hash_update(&desc, sg, lsm_xattr->value_len);
+	hmac_add_misc(&desc, inode, hmac_val);
+	crypto_free_hash(desc.tfm);
+	return 0;
+}
+
 /*
  * Get the key from the TPM for the SHA1-HMAC
  */
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index e89ceb1..98941ab 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -98,6 +98,12 @@ static int evm_protected_xattr(const char *req_xattr_name)
 			found = 1;
 			break;
 		}
+		if (strncmp(req_xattr_name,
+			    *xattrname + XATTR_SECURITY_PREFIX_LEN,
+			    strlen(req_xattr_name)) == 0) {
+			found = 1;
+			break;
+		}
 	}
 	return found;
 }
@@ -245,6 +251,38 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
 	return;
 }
 
+/*
+ * evm_inode_post_init_security - initializes security.evm
+ */
+int evm_inode_post_init_security(struct inode *inode,
+				 const struct xattr *lsm_xattr,
+				 struct xattr *evm_xattr)
+{
+	u8 *hmac_val;
+	int rc;
+
+	if (!evm_initialized || !evm_protected_xattr(lsm_xattr->name))
+		return -EOPNOTSUPP;
+
+	hmac_val = kzalloc(evm_hmac_size + 1, GFP_NOFS);
+	if (!hmac_val)
+		return -ENOMEM;
+
+	hmac_val[0] = EVM_XATTR_HMAC;
+	rc = evm_init_hmac(inode, lsm_xattr, hmac_val + 1);
+	if (rc < 0)
+		goto out;
+
+	evm_xattr->value = hmac_val;
+	evm_xattr->value_len = evm_hmac_size + 1;
+	evm_xattr->name = XATTR_EVM_SUFFIX;
+	return 0;
+out:
+	kfree(hmac_val);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(evm_inode_post_init_security);
+
 static struct crypto_hash *tfm_hmac;	/* preload crypto alg */
 static int __init init_evm(void)
 {
-- 
1.7.3.4

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

* [PATCH v4 10/11] fs: add evm_inode_post_init calls
  2011-03-28 16:39 [PATCH v4 00/11] EVM Mimi Zohar
                   ` (8 preceding siblings ...)
  2011-03-28 16:39 ` [PATCH v4 09/11] evm: inode_post_init Mimi Zohar
@ 2011-03-28 16:39 ` Mimi Zohar
  2011-03-28 16:39 ` [PATCH v4 11/11] evm: crypto hash replaced by shash Mimi Zohar
  10 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2011-03-28 16:39 UTC (permalink / raw)
  To: linux-security-module
  Cc: Mimi Zohar, linux-kernel, linux-fsdevel, James Morris,
	David Safford, Mimi Zohar

After creating the initial LSM security extended attribute, call
evm_inode_post_init_security() to create the 'security.evm'
extended attribute.

(Support for other fs still needed.)

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
Acked-by: Serge Hallyn <serge.hallyn@ubuntu.com>
---
 fs/ext2/xattr_security.c |   31 ++++++++++++++++++++++++-------
 fs/ext3/xattr_security.c |   30 +++++++++++++++++++++++-------
 fs/ext4/xattr_security.c |   30 +++++++++++++++++++++++-------
 3 files changed, 70 insertions(+), 21 deletions(-)

diff --git a/fs/ext2/xattr_security.c b/fs/ext2/xattr_security.c
index 5d979b4..e17820c 100644
--- a/fs/ext2/xattr_security.c
+++ b/fs/ext2/xattr_security.c
@@ -9,6 +9,7 @@
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
 #include <linux/security.h>
+#include <linux/evm.h>
 #include "xattr.h"
 
 static size_t
@@ -51,21 +52,37 @@ ext2_init_security(struct inode *inode, struct inode *dir,
 		   const struct qstr *qstr)
 {
 	int err;
-	size_t len;
-	void *value;
-	char *name;
+	struct xattr lsm_xattr;
+	struct xattr evm_xattr;
 
-	err = security_inode_init_security(inode, dir, qstr, &name, &value, &len);
+	err = security_inode_init_security(inode, dir, qstr, &lsm_xattr.name,
+					   &lsm_xattr.value,
+					   &lsm_xattr.value_len);
 	if (err) {
 		if (err == -EOPNOTSUPP)
 			return 0;
 		return err;
 	}
 	err = ext2_xattr_set(inode, EXT2_XATTR_INDEX_SECURITY,
-			     name, value, len, 0);
-	kfree(name);
-	kfree(value);
+			     lsm_xattr.name, lsm_xattr.value,
+			     lsm_xattr.value_len, 0);
+	if (err < 0)
+		goto out;
+
+	err = evm_inode_post_init_security(inode, &lsm_xattr, &evm_xattr);
+	if (err)
+		goto out;
+	err = ext2_xattr_set(inode, EXT2_XATTR_INDEX_SECURITY,
+			     evm_xattr.name, evm_xattr.value,
+			     evm_xattr.value_len, 0);
+	kfree(evm_xattr.value);
+out:
+	kfree(lsm_xattr.name);
+	kfree(lsm_xattr.value);
+	if (err == -EOPNOTSUPP)
+		return 0;
 	return err;
+
 }
 
 const struct xattr_handler ext2_xattr_security_handler = {
diff --git a/fs/ext3/xattr_security.c b/fs/ext3/xattr_security.c
index b8d9f83..844786b 100644
--- a/fs/ext3/xattr_security.c
+++ b/fs/ext3/xattr_security.c
@@ -10,6 +10,7 @@
 #include <linux/ext3_jbd.h>
 #include <linux/ext3_fs.h>
 #include <linux/security.h>
+#include <linux/evm.h>
 #include "xattr.h"
 
 static size_t
@@ -53,20 +54,35 @@ ext3_init_security(handle_t *handle, struct inode *inode, struct inode *dir,
 		   const struct qstr *qstr)
 {
 	int err;
-	size_t len;
-	void *value;
-	char *name;
+	struct xattr lsm_xattr;
+	struct xattr evm_xattr;
 
-	err = security_inode_init_security(inode, dir, qstr, &name, &value, &len);
+	err = security_inode_init_security(inode, dir, qstr, &lsm_xattr.name,
+					   &lsm_xattr.value,
+					   &lsm_xattr.value_len);
 	if (err) {
 		if (err == -EOPNOTSUPP)
 			return 0;
 		return err;
 	}
 	err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY,
-				    name, value, len, 0);
-	kfree(name);
-	kfree(value);
+				    lsm_xattr.name, lsm_xattr.value,
+				    lsm_xattr.value_len, 0);
+	if (err < 0)
+		goto out;
+
+	err = evm_inode_post_init_security(inode, &lsm_xattr, &evm_xattr);
+	if (err)
+		goto out;
+	err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY,
+				    evm_xattr.name, evm_xattr.value,
+				    evm_xattr.value_len, 0);
+	kfree(evm_xattr.value);
+out:
+	kfree(lsm_xattr.name);
+	kfree(lsm_xattr.value);
+	if (err == -EOPNOTSUPP)
+		return 0;
 	return err;
 }
 
diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c
index 007c3bf..c5fdb96 100644
--- a/fs/ext4/xattr_security.c
+++ b/fs/ext4/xattr_security.c
@@ -8,6 +8,7 @@
 #include <linux/fs.h>
 #include <linux/security.h>
 #include <linux/slab.h>
+#include <linux/evm.h>
 #include "ext4_jbd2.h"
 #include "ext4.h"
 #include "xattr.h"
@@ -53,20 +54,35 @@ ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir,
 		   const struct qstr *qstr)
 {
 	int err;
-	size_t len;
-	void *value;
-	char *name;
+	struct xattr lsm_xattr;
+	struct xattr evm_xattr;
 
-	err = security_inode_init_security(inode, dir, qstr, &name, &value, &len);
+	err = security_inode_init_security(inode, dir, qstr, &lsm_xattr.name,
+					   &lsm_xattr.value,
+					   &lsm_xattr.value_len);
 	if (err) {
 		if (err == -EOPNOTSUPP)
 			return 0;
 		return err;
 	}
 	err = ext4_xattr_set_handle(handle, inode, EXT4_XATTR_INDEX_SECURITY,
-				    name, value, len, 0);
-	kfree(name);
-	kfree(value);
+				    lsm_xattr.name, lsm_xattr.value,
+				    lsm_xattr.value_len, 0);
+	if (err < 0)
+		goto out;
+
+	err = evm_inode_post_init_security(inode, &lsm_xattr, &evm_xattr);
+	if (err)
+		goto out;
+	err = ext4_xattr_set_handle(handle, inode, EXT4_XATTR_INDEX_SECURITY,
+				    evm_xattr.name, evm_xattr.value,
+				    evm_xattr.value_len, 0);
+	kfree(evm_xattr.value);
+out:
+	kfree(lsm_xattr.name);
+	kfree(lsm_xattr.value);
+	if (err == -EOPNOTSUPP)
+		return 0;
 	return err;
 }
 
-- 
1.7.3.4

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

* [PATCH v4 11/11] evm: crypto hash replaced by shash
  2011-03-28 16:39 [PATCH v4 00/11] EVM Mimi Zohar
                   ` (9 preceding siblings ...)
  2011-03-28 16:39 ` [PATCH v4 10/11] fs: add evm_inode_post_init calls Mimi Zohar
@ 2011-03-28 16:39 ` Mimi Zohar
  10 siblings, 0 replies; 12+ messages in thread
From: Mimi Zohar @ 2011-03-28 16:39 UTC (permalink / raw)
  To: linux-security-module
  Cc: Dmitry Kasatkin, linux-kernel, linux-fsdevel, James Morris,
	David Safford, Mimi Zohar

From: Dmitry Kasatkin <dmitry.kasatkin@nokia.com>

Using shash is more efficient, because the algorithm is allocated only
once. Only the descriptor to store the hash state needs to be allocated
for every operation.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
---
 security/integrity/evm/evm.h        |    2 +
 security/integrity/evm/evm_crypto.c |   94 ++++++++++++++++++++---------------
 security/integrity/evm/evm_main.c   |    6 +-
 3 files changed, 58 insertions(+), 44 deletions(-)

diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h
index 65ab9db..08b0a84 100644
--- a/security/integrity/evm/evm.h
+++ b/security/integrity/evm/evm.h
@@ -20,6 +20,8 @@ extern int evm_initialized;
 extern char *evm_hmac;
 extern int evm_hmac_size;
 
+extern struct crypto_shash *hmac_tfm;
+
 /* List of EVM protected security xattrs */
 extern char *evm_config_xattrnames[];
 
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index e029a37..4b2d040 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -17,7 +17,7 @@
 #include <linux/crypto.h>
 #include <linux/xattr.h>
 #include <keys/encrypted-type.h>
-#include <linux/scatterlist.h>
+#include <crypto/hash.h>
 #include "evm.h"
 
 #define EVMKEY "evm-key"
@@ -25,23 +25,41 @@
 static unsigned char evmkey[MAX_KEY_SIZE];
 static int evmkey_len = MAX_KEY_SIZE;
 
-static int init_desc(struct hash_desc *desc)
+struct crypto_shash *hmac_tfm;
+
+static struct shash_desc *init_desc(void)
 {
 	int rc;
+	struct shash_desc *desc;
+
+	if (hmac_tfm == NULL) {
+		hmac_tfm = crypto_alloc_shash(evm_hmac, 0, CRYPTO_ALG_ASYNC);
+		if (IS_ERR(hmac_tfm)) {
+			pr_err("Can not allocate %s (reason: %ld)\n",
+			       evm_hmac, PTR_ERR(hmac_tfm));
+			rc = PTR_ERR(hmac_tfm);
+			hmac_tfm = NULL;
+			return ERR_PTR(rc);
+		}
+	}
+
+	desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(hmac_tfm),
+			GFP_KERNEL);
+	if (!desc)
+		return ERR_PTR(-ENOMEM);
+
+	desc->tfm = hmac_tfm;
+	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	crypto_shash_setkey(hmac_tfm, evmkey, evmkey_len);
 
-	desc->tfm = crypto_alloc_hash(evm_hmac, 0, CRYPTO_ALG_ASYNC);
-	if (IS_ERR(desc->tfm)) {
-		pr_info("Can not allocate %s (reason: %ld)\n",
-			evm_hmac, PTR_ERR(desc->tfm));
-		rc = PTR_ERR(desc->tfm);
-		return rc;
+	rc = crypto_shash_init(desc);
+	if (rc) {
+		kfree(desc);
+		return ERR_PTR(rc);
 	}
-	desc->flags = 0;
-	crypto_hash_setkey(desc->tfm, evmkey, evmkey_len);
-	rc = crypto_hash_init(desc);
-	if (rc)
-		crypto_free_hash(desc->tfm);
-	return rc;
+
+	return desc;
 }
 
 /* Protect against 'cutting & pasting' security.evm xattr, include inode
@@ -50,7 +68,7 @@ static int init_desc(struct hash_desc *desc)
  * (Additional directory/file metadata needs to be added for more complete
  * protection.)
  */
-static void hmac_add_misc(struct hash_desc *desc, struct inode *inode,
+static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
 			  char *digest)
 {
 	struct h_misc {
@@ -60,7 +78,6 @@ static void hmac_add_misc(struct hash_desc *desc, struct inode *inode,
 		gid_t gid;
 		umode_t mode;
 	} hmac_misc;
-	struct scatterlist sg[1];
 
 	memset(&hmac_misc, 0, sizeof hmac_misc);
 	hmac_misc.ino = inode->i_ino;
@@ -68,9 +85,8 @@ static void hmac_add_misc(struct hash_desc *desc, struct inode *inode,
 	hmac_misc.uid = inode->i_uid;
 	hmac_misc.gid = inode->i_gid;
 	hmac_misc.mode = inode->i_mode;
-	sg_init_one(sg, &hmac_misc, sizeof hmac_misc);
-	crypto_hash_update(desc, sg, sizeof hmac_misc);
-	crypto_hash_final(desc, digest);
+	crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof hmac_misc);
+	crypto_shash_final(desc, digest);
 }
 
 /*
@@ -85,8 +101,7 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
 		  char *digest)
 {
 	struct inode *inode = dentry->d_inode;
-	struct hash_desc desc;
-	struct scatterlist sg[1];
+	struct shash_desc *desc;
 	char **xattrname;
 	size_t xattr_size = 0;
 	char *xattr_value = NULL;
@@ -95,17 +110,17 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
 
 	if (!inode->i_op || !inode->i_op->getxattr)
 		return -EOPNOTSUPP;
-	error = init_desc(&desc);
-	if (error)
-		return error;
+	desc = init_desc();
+	if (IS_ERR(desc))
+		return PTR_ERR(desc);
 
 	error = -ENODATA;
 	for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
 		if ((req_xattr_name && req_xattr_value)
 		    && !strcmp(*xattrname, req_xattr_name)) {
 			error = 0;
-			sg_init_one(sg, req_xattr_value, req_xattr_value_len);
-			crypto_hash_update(&desc, sg, req_xattr_value_len);
+			crypto_shash_update(desc, (const u8 *)req_xattr_value,
+					     req_xattr_value_len);
 			continue;
 		}
 		size = vfs_getxattr_alloc(dentry, *xattrname,
@@ -119,13 +134,13 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
 
 		error = 0;
 		xattr_size = size;
-		sg_init_one(sg, xattr_value, xattr_size);
-		crypto_hash_update(&desc, sg, xattr_size);
+		crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size);
 	}
-	hmac_add_misc(&desc, inode, digest);
-	kfree(xattr_value);
+	hmac_add_misc(desc, inode, digest);
+
 out:
-	crypto_free_hash(desc.tfm);
+	kfree(xattr_value);
+	kfree(desc);
 	return error;
 }
 
@@ -156,20 +171,17 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
 int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,
 		  char *hmac_val)
 {
-	struct hash_desc desc;
-	struct scatterlist sg[1];
-	int error;
+	struct shash_desc *desc;
 
-	error = init_desc(&desc);
-	if (error != 0) {
+	desc = init_desc();
+	if (IS_ERR(desc)) {
 		printk(KERN_INFO "init_desc failed\n");
-		return error;
+		return PTR_ERR(desc);
 	}
 
-	sg_init_one(sg, lsm_xattr->value, lsm_xattr->value_len);
-	crypto_hash_update(&desc, sg, lsm_xattr->value_len);
-	hmac_add_misc(&desc, inode, hmac_val);
-	crypto_free_hash(desc.tfm);
+	crypto_shash_update(desc, lsm_xattr->value, lsm_xattr->value_len);
+	hmac_add_misc(desc, inode, hmac_val);
+	kfree(desc);
 	return 0;
 }
 
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 98941ab..af1bc6a 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -19,6 +19,7 @@
 #include <linux/xattr.h>
 #include <linux/integrity.h>
 #include <linux/evm.h>
+#include <crypto/hash.h>
 #include "evm.h"
 
 int evm_initialized;
@@ -283,12 +284,10 @@ out:
 }
 EXPORT_SYMBOL_GPL(evm_inode_post_init_security);
 
-static struct crypto_hash *tfm_hmac;	/* preload crypto alg */
 static int __init init_evm(void)
 {
 	int error;
 
-	tfm_hmac = crypto_alloc_hash(evm_hmac, 0, CRYPTO_ALG_ASYNC);
 	error = evm_init_secfs();
 	if (error < 0) {
 		printk(KERN_INFO "EVM: Error registering secfs\n");
@@ -301,7 +300,8 @@ err:
 static void __exit cleanup_evm(void)
 {
 	evm_cleanup_secfs();
-	crypto_free_hash(tfm_hmac);
+	if (hmac_tfm)
+		crypto_free_shash(hmac_tfm);
 }
 
 /*
-- 
1.7.3.4

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

end of thread, other threads:[~2011-03-28 16:41 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-03-28 16:39 [PATCH v4 00/11] EVM Mimi Zohar
2011-03-28 16:39 ` [PATCH v4 01/11] integrity: move ima inode integrity data management Mimi Zohar
2011-03-28 16:39 ` [PATCH v4 02/11] xattr: define vfs_getxattr_alloc and vfs_xattr_cmp Mimi Zohar
2011-03-28 16:39 ` [PATCH v4 03/11] evm: re-release Mimi Zohar
2011-03-28 16:39 ` [PATCH v4 04/11] evm: add support for different security.evm data types Mimi Zohar
2011-03-28 16:39 ` [PATCH v4 05/11] ima: move ima_file_free before releasing the file Mimi Zohar
2011-03-28 16:39 ` [PATCH v4 06/11] security: imbed evm calls in security hooks Mimi Zohar
2011-03-28 16:39 ` [PATCH v4 07/11] evm: inode post removexattr Mimi Zohar
2011-03-28 16:39 ` [PATCH v4 08/11] evm: imbed evm_inode_post_setattr Mimi Zohar
2011-03-28 16:39 ` [PATCH v4 09/11] evm: inode_post_init Mimi Zohar
2011-03-28 16:39 ` [PATCH v4 10/11] fs: add evm_inode_post_init calls Mimi Zohar
2011-03-28 16:39 ` [PATCH v4 11/11] evm: crypto hash replaced by shash Mimi Zohar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).