2011-05-16 14:46:12

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 00/21] EVM

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.

Changes from v4:
- Added evm_inode_post_init calls for: btrfs, gfs2, jffs2, jfs, and xfs.
- Prevent an invalid security.evm xattr from being updated.
- evm_verifyxattr() performance improvement (Dmitry Kasatkin)
- Fixed evm_verify_hmac() to be fail safe (Dmitry Kasatkin)
- Additional naming change generalizations in preparation for other methods
of integrity authentication. (Dmitry Kasatkin)

Mimi Zohar
David Safford

Dmitry Kasatkin (5):
evm: add support for different security.evm data types
evm: crypto hash replaced by shash
evm: additional parameter to pass integrity cache entry 'iint'
evm: evm_verify_hmac must not return INTEGRITY_UNKNOWN
evm: replace hmac_status with evm_status

Mimi Zohar (16):
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: evm_inode_post_removexattr
evm: imbed evm_inode_post_setattr
evm: evm_inode_post_init
fs: add evm_inode_post_init calls
evm: add evm_inode_post_init call in btrfs
evm: add evm_inode_post_init call in gfs2
evm: add evm_inode_post_init call in jffs2
evm: add evm_inode_post_init call in jfs
evm: add evm_inode_post_init call in xfs
evm: permit only valid security.evm xattrs to be updated
evm: add evm_inode_setattr to prevent updating an invalid
security.evm

Documentation/ABI/testing/evm | 23 ++
Documentation/kernel-parameters.txt | 6 +
fs/attr.c | 5 +-
fs/btrfs/xattr.c | 39 +++-
fs/ext2/xattr_security.c | 31 +++-
fs/ext3/xattr_security.c | 30 ++-
fs/ext4/xattr_security.c | 30 ++-
fs/file_table.c | 2 +-
fs/gfs2/inode.c | 28 ++-
fs/jffs2/security.c | 26 ++-
fs/jfs/xattr.c | 45 +++--
fs/xattr.c | 63 ++++++-
fs/xfs/linux-2.6/xfs_iops.c | 27 ++-
include/linux/evm.h | 92 +++++++++
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 | 384 +++++++++++++++++++++++++++++++++++
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 | 26 ++-
36 files changed, 1465 insertions(+), 292 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


2011-05-16 14:45:43

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 01/21] integrity: move ima inode integrity data management

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 <[email protected]>
---
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 <[email protected]>
+ *
+ * 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 e0f08b5..22847a8 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -186,7 +186,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 <[email protected]>
+ *
+ * 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 <[email protected]>
- *
- * 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 <[email protected]>
+ *
+ * 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 1011423..d0c6576 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 */
@@ -334,7 +335,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

2011-05-16 14:46:13

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 02/21] xattr: define vfs_getxattr_alloc and vfs_xattr_cmp

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 <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
---
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 a19acdb..6da0c8c 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

2011-05-16 14:46:25

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 03/21] evm: re-release

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 <[email protected]>
---
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 <[email protected]>
+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 <[email protected]>
+ * Kylene Hall <[email protected]>
+ *
+ * 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 <[email protected]>
+ * Kylene Hall <[email protected]>
+ *
+ * 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 <[email protected]>
+ * Kylene Hall <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * 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

2011-05-16 14:46:31

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 04/21] evm: add support for different security.evm data types

From: Dmitry Kasatkin <[email protected]>

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 <[email protected]>
Signed-off-by: Mimi Zohar <[email protected]>
---
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

2011-05-16 14:47:34

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 05/21] ima: move ima_file_free before releasing the file

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 <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
---
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

2011-05-16 14:46:37

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 06/21] security: imbed evm calls in security hooks

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 <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
---
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 <[email protected]>
+ */
+
+#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 d0c6576..635bcc9 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] =
@@ -549,9 +550,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,
@@ -560,6 +566,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)
@@ -578,9 +585,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

2011-05-16 14:46:41

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 07/21] evm: evm_inode_post_removexattr

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

Signed-off-by: Mimi Zohar <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
---
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 6da0c8c..13814fe 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

2011-05-16 14:47:00

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 08/21] evm: imbed evm_inode_post_setattr

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

Signed-off-by: Mimi Zohar <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
---
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 91dbe2a..b717f86 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

2011-05-16 14:46:53

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 09/21] evm: evm_inode_post_init

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

Signed-off-by: Mimi Zohar <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
---
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

2011-05-16 14:47:22

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 10/21] fs: add evm_inode_post_init calls

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 are defined as separate patches.)

Signed-off-by: Mimi Zohar <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
---
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

2011-05-16 14:47:20

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 11/21] evm: crypto hash replaced by shash

From: Dmitry Kasatkin <[email protected]>

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 <[email protected]>
Signed-off-by: Mimi Zohar <[email protected]>
---
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

2011-05-16 14:47:39

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 12/21] evm: add evm_inode_post_init call in btrfs

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

Signed-off-by: Mimi Zohar <[email protected]>
---
fs/btrfs/xattr.c | 39 +++++++++++++++++++++++++++++----------
1 files changed, 29 insertions(+), 10 deletions(-)

diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c
index cfd6605..df07619 100644
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -22,6 +22,7 @@
#include <linux/rwsem.h>
#include <linux/xattr.h>
#include <linux/security.h>
+#include <linux/evm.h>
#include "ctree.h"
#include "btrfs_inode.h"
#include "transaction.h"
@@ -367,31 +368,49 @@ int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
const struct qstr *qstr)
{
int err;
- size_t len;
- void *value;
- char *suffix;
+ struct xattr lsm_xattr;
+ struct xattr evm_xattr;
char *name;

- err = security_inode_init_security(inode, dir, qstr, &suffix, &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;
}

- name = kmalloc(XATTR_SECURITY_PREFIX_LEN + strlen(suffix) + 1,
+ name = kmalloc(XATTR_SECURITY_PREFIX_LEN + strlen(lsm_xattr.name) + 1,
GFP_NOFS);
if (!name) {
err = -ENOMEM;
} else {
strcpy(name, XATTR_SECURITY_PREFIX);
- strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix);
- err = __btrfs_setxattr(trans, inode, name, value, len, 0);
+ strcpy(name + XATTR_SECURITY_PREFIX_LEN, lsm_xattr.name);
+ err = __btrfs_setxattr(trans, inode, name, lsm_xattr.value,
+ lsm_xattr.value_len, 0);
kfree(name);
}
+ if (err)
+ goto out;
+
+ err = evm_inode_post_init_security(inode, &lsm_xattr, &evm_xattr);
+ if (err)
+ goto out;

- kfree(suffix);
- kfree(value);
+ name = kasprintf(GFP_NOFS, "%s%s", XATTR_SECURITY_PREFIX,
+ evm_xattr.name);
+ if (!name)
+ err = -ENOMEM;
+ else {
+ err = __btrfs_setxattr(trans, inode, name, evm_xattr.value,
+ evm_xattr.value_len, 0);
+ kfree(name);
+ }
+ kfree(evm_xattr.value);
+out:
+ kfree(lsm_xattr.name);
+ kfree(lsm_xattr.value);
return err;
}
--
1.7.3.4

2011-05-16 14:48:57

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 13/21] evm: add evm_inode_post_init call in gfs2

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

Signed-off-by: Mimi Zohar <[email protected]>
---
fs/gfs2/inode.c | 28 +++++++++++++++++++---------
1 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 97d54a2..5ce875b 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -17,6 +17,7 @@
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <linux/security.h>
+#include <linux/evm.h>
#include <linux/time.h>

#include "gfs2.h"
@@ -767,12 +768,12 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
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(&ip->i_inode, &dip->i_inode, qstr,
- &name, &value, &len);
+ &lsm_xattr.name, &lsm_xattr.value,
+ &lsm_xattr.value_len);

if (err) {
if (err == -EOPNOTSUPP)
@@ -780,11 +781,20 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
return err;
}

- err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0,
- GFS2_EATYPE_SECURITY);
- kfree(value);
- kfree(name);
-
+ err = __gfs2_xattr_set(&ip->i_inode, lsm_xattr.name, lsm_xattr.value,
+ lsm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
+ if (err < 0)
+ goto out;
+ err = evm_inode_post_init_security(&ip->i_inode, &lsm_xattr,
+ &evm_xattr);
+ if (err)
+ goto out;
+ err = __gfs2_xattr_set(&ip->i_inode, evm_xattr.name, evm_xattr.value,
+ evm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
+ kfree(evm_xattr.value);
+out:
+ kfree(lsm_xattr.name);
+ kfree(lsm_xattr.value);
return err;
}

--
1.7.3.4

2011-05-16 14:47:48

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 14/21] evm: add evm_inode_post_init call in jffs2

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

Signed-off-by: Mimi Zohar <[email protected]>
---
fs/jffs2/security.c | 26 +++++++++++++++++++-------
1 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/fs/jffs2/security.c b/fs/jffs2/security.c
index cfeb716..6847769 100644
--- a/fs/jffs2/security.c
+++ b/fs/jffs2/security.c
@@ -20,6 +20,7 @@
#include <linux/xattr.h>
#include <linux/mtd/mtd.h>
#include <linux/security.h>
+#include <linux/evm.h>
#include "nodelist.h"

/* ---- Initial Security Label Attachment -------------- */
@@ -28,19 +29,30 @@ int jffs2_init_security(struct inode *inode, struct inode *dir,
{
int rc;
size_t len;
- void *value;
- char *name;
+ struct xattr lsm_xattr;
+ struct xattr evm_xattr;

- rc = security_inode_init_security(inode, dir, qstr, &name, &value, &len);
+ rc = security_inode_init_security(inode, dir, qstr, &lsm_xattr.name,
+ &lsm_xattr.value,
+ &lsm_xattr.value_len);
if (rc) {
if (rc == -EOPNOTSUPP)
return 0;
return rc;
}
- rc = do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY, name, value, len, 0);
-
- kfree(name);
- kfree(value);
+ rc = do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY, lsm_xattr.name,
+ lsm_xattr.value, lsm_xattr.value_len, 0);
+ if (rc)
+ goto out;
+ rc = evm_inode_post_init_security(inode, &lsm_xattr, &evm_xattr);
+ if (err)
+ goto out;
+ rc = do_jffs2_setxattr(inode, JFFS2_XPREFIX_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);
return rc;
}

--
1.7.3.4

2011-05-16 14:48:29

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 15/21] evm: add evm_inode_post_init call in jfs

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

Signed-off-by: Mimi Zohar <[email protected]>
---
fs/jfs/xattr.c | 45 +++++++++++++++++++++++++++++++--------------
1 files changed, 31 insertions(+), 14 deletions(-)

diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c
index 24838f1..68b4ec6 100644
--- a/fs/jfs/xattr.c
+++ b/fs/jfs/xattr.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/quotaops.h>
#include <linux/security.h>
+#include <linux/evm.h>
#include "jfs_incore.h"
#include "jfs_superblock.h"
#include "jfs_dmap.h"
@@ -1095,33 +1096,49 @@ int jfs_init_security(tid_t tid, struct inode *inode, struct inode *dir,
const struct qstr *qstr)
{
int rc;
- size_t len;
- void *value;
- char *suffix;
+ struct xattr lsm_xattr;
+ struct xattr evm_xattr;
char *name;

- rc = security_inode_init_security(inode, dir, qstr, &suffix, &value,
- &len);
+ rc = security_inode_init_security(inode, dir, qstr, &lsm_xattr.name,
+ &lsm_xattr.value,
+ &lsm_xattr.value_len);
if (rc) {
if (rc == -EOPNOTSUPP)
return 0;
return rc;
}
- name = kmalloc(XATTR_SECURITY_PREFIX_LEN + 1 + strlen(suffix),
+ name = kmalloc(XATTR_SECURITY_PREFIX_LEN + 1 + strlen(lsm_xattr.name),
GFP_NOFS);
if (!name) {
rc = -ENOMEM;
- goto kmalloc_failed;
- }
- strcpy(name, XATTR_SECURITY_PREFIX);
- strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix);
+ } else {
+ strcpy(name, XATTR_SECURITY_PREFIX);
+ strcpy(name + XATTR_SECURITY_PREFIX_LEN, lsm_xattr.name);

- rc = __jfs_setxattr(tid, inode, name, value, len, 0);
+ rc = __jfs_setxattr(tid, inode, name, lsm_xattr.value,
+ lsm_xattr.value_len, 0);
+ kfree(name);
+ }
+ if (rc)
+ goto kmalloc_failed;

- kfree(name);
+ rc = evm_inode_post_init_security(inode, &lsm_xattr, &evm_xattr);
+ if (rc)
+ goto kmalloc_failed;
+ name = kasprintf(GFP_NOFS, "%s%s", XATTR_SECURITY_PREFIX,
+ evm_xattr.name);
+ if (!name) {
+ rc = -ENOMEM;
+ } else {
+ rc = __jfs_setxattr(tid, inode, name, evm_xattr.value,
+ evm_xattr.value_len, 0);
+ kfree(name);
+ }
+ kfree(evm_xattr.value);
kmalloc_failed:
- kfree(suffix);
- kfree(value);
+ kfree(lsm_xattr.name);
+ kfree(lsm_xattr.value);

return rc;
}
--
1.7.3.4

2011-05-16 14:48:09

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 16/21] evm: add evm_inode_post_init call in xfs

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

Signed-off-by: Mimi Zohar <[email protected]>
---
fs/xfs/linux-2.6/xfs_iops.c | 27 +++++++++++++++++++--------
1 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index dd21784..01b354d 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -46,6 +46,7 @@
#include <linux/namei.h>
#include <linux/posix_acl.h>
#include <linux/security.h>
+#include <linux/evm.h>
#include <linux/fiemap.h>
#include <linux/slab.h>

@@ -106,23 +107,33 @@ xfs_init_security(
const struct qstr *qstr)
{
struct xfs_inode *ip = XFS_I(inode);
- size_t length;
- void *value;
- unsigned char *name;
+ struct xattr lsm_xattr;
+ struct xattr evm_xattr;
int error;

- error = security_inode_init_security(inode, dir, qstr, (char **)&name,
- &value, &length);
+ error = security_inode_init_security(inode, dir, qstr, &lsm_xattr.name,
+ &lsm_xattr.value,
+ &lsm_xattr.value_len);
if (error) {
if (error == -EOPNOTSUPP)
return 0;
return -error;
}

- error = xfs_attr_set(ip, name, value, length, ATTR_SECURE);
+ error = xfs_attr_set(ip, lsm_xattr.name, lsm_xattr.value,
+ lsm_xattr.value_len, ATTR_SECURE);
+ if (error)
+ goto out;

- kfree(name);
- kfree(value);
+ error = evm_inode_post_init_security(inode, &lsm_xattr, &evm_xattr);
+ if (error)
+ goto out;
+ error = xfs_attr_set(ip, evm_xattr.name, evm_xattr.value,
+ evm_xattr.value_len, ATTR_SECURE);
+ kfree(evm_xattr.value);
+out:
+ kfree(lsm_xattr.name);
+ kfree(lsm_xattr.value);
return error;
}

--
1.7.3.4

2011-05-16 14:49:46

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 17/21] evm: additional parameter to pass integrity cache entry 'iint'

From: Dmitry Kasatkin <[email protected]>

Additional iint parameter allows to skip lookup in the cache.

Signed-off-by: Dmitry Kasatkin <[email protected]>
Signed-off-by: Mimi Zohar <[email protected]>
---
include/linux/evm.h | 8 ++++++--
security/integrity/evm/evm_main.c | 18 ++++++++----------
2 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/include/linux/evm.h b/include/linux/evm.h
index c3bc089..8db7b74 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -11,11 +11,14 @@
#include <linux/integrity.h>
#include <linux/xattr.h>

+struct integrity_iint_cache;
+
#ifdef CONFIG_EVM
extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
const char *xattr_name,
void *xattr_value,
- size_t xattr_value_len);
+ size_t xattr_value_len,
+ struct integrity_iint_cache *iint);
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);
@@ -34,7 +37,8 @@ extern int evm_inode_post_init_security(struct inode *inode,
static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
const char *xattr_name,
void *xattr_value,
- size_t xattr_value_len)
+ size_t xattr_value_len,
+ struct integrity_iint_cache *iint)
{
return INTEGRITY_UNKNOWN;
}
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index af1bc6a..944783c 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -127,21 +127,19 @@ static int evm_protected_xattr(const char *req_xattr_name)
*/
enum integrity_status evm_verifyxattr(struct dentry *dentry,
const char *xattr_name,
- void *xattr_value, size_t xattr_value_len)
+ void *xattr_value, size_t xattr_value_len,
+ struct integrity_iint_cache *iint)
{
- 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,
+ if (!iint) {
+ iint = integrity_iint_find(dentry->d_inode);
+ if (!iint)
+ return INTEGRITY_UNKNOWN;
+ }
+ return evm_verify_hmac(dentry, xattr_name, xattr_value,
xattr_value_len, iint);
- return status;
}
EXPORT_SYMBOL_GPL(evm_verifyxattr);

--
1.7.3.4

2011-05-16 14:48:22

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 18/21] evm: evm_verify_hmac must not return INTEGRITY_UNKNOWN

From: Dmitry Kasatkin <[email protected]>

If EVM is not supported or enabled, evm_verify_hmac() returns
INTEGRITY_UNKNOWN, which ima_appraise_measurement() ignores and sets
the appraisal status based solely on the security.ima verification.

evm_verify_hmac() also returns INTEGRITY_UNKNOWN for other failures, such
as temporary failures like -ENOMEM, resulting in possible attack vectors.
This patch changes the default return code for temporary/unexpected
failures, like -ENOMEM, from INTEGRITY_UNKNOWN to INTEGRITY_FAIL, making
evm_verify_hmac() fail safe.

As a result, failures need to be re-evaluated in order to catch both
temporary errors, such as the -ENOMEM, as well as errors that have been
resolved in fix mode.

Signed-off-by: Dmitry Kasatkin <[email protected]>
Signed-off-by: Mimi Zohar <[email protected]>
---
security/integrity/evm/evm_main.c | 11 +++++------
1 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 944783c..245ef23 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -57,14 +57,16 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
char hmac_val[MAX_DIGEST_SIZE + 1];
int rc;

- if (iint->hmac_status != INTEGRITY_UNKNOWN)
+ if (iint->hmac_status == INTEGRITY_PASS)
return iint->hmac_status;

+ /* if status is not PASS, try to check again - against -ENOMEM */
+
memset(hmac_val, 0, sizeof hmac_val);
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
xattr_value_len, hmac_val + 1);
if (rc < 0)
- return INTEGRITY_UNKNOWN;
+ goto err_out;

hmac_val[0] = EVM_XATTR_HMAC;
rc = vfs_xattr_cmp(dentry, XATTR_NAME_EVM, hmac_val, sizeof hmac_val,
@@ -79,11 +81,8 @@ err_out:
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;
+ iint->hmac_status = INTEGRITY_FAIL;
}
return iint->hmac_status;
}
--
1.7.3.4

2011-05-16 14:48:37

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 19/21] evm: replace hmac_status with evm_status

From: Dmitry Kasatkin <[email protected]>

We will use digital signatures in addtion to hmac.

Signed-off-by: Dmitry Kasatkin <[email protected]>
Signed-off-by: Mimi Zohar <[email protected]>
---
security/integrity/evm/evm_main.c | 14 +++++++-------
security/integrity/iint.c | 2 +-
security/integrity/integrity.h | 2 +-
3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 245ef23..3afefff 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -57,8 +57,8 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
char hmac_val[MAX_DIGEST_SIZE + 1];
int rc;

- if (iint->hmac_status == INTEGRITY_PASS)
- return iint->hmac_status;
+ if (iint->evm_status == INTEGRITY_PASS)
+ return iint->evm_status;

/* if status is not PASS, try to check again - against -ENOMEM */

@@ -73,18 +73,18 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
GFP_NOFS);
if (rc < 0)
goto err_out;
- iint->hmac_status = INTEGRITY_PASS;
- return iint->hmac_status;
+ iint->evm_status = INTEGRITY_PASS;
+ return iint->evm_status;

err_out:
switch (rc) {
case -ENODATA: /* file not labelled */
- iint->hmac_status = INTEGRITY_NOLABEL;
+ iint->evm_status = INTEGRITY_NOLABEL;
break;
default:
- iint->hmac_status = INTEGRITY_FAIL;
+ iint->evm_status = INTEGRITY_FAIL;
}
- return iint->hmac_status;
+ return iint->evm_status;
}

static int evm_protected_xattr(const char *req_xattr_name)
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 991df20..0a23e07 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -157,7 +157,7 @@ static void init_once(void *foo)
iint->version = 0;
iint->flags = 0UL;
mutex_init(&iint->mutex);
- iint->hmac_status = INTEGRITY_UNKNOWN;
+ iint->evm_status = INTEGRITY_UNKNOWN;
}

static int __init integrity_iintcache_init(void)
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 2232cd1..eb2c639 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -28,7 +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;
+ enum integrity_status evm_status;
};

/* rbtree tree calls to lookup, insert, delete
--
1.7.3.4

2011-05-16 14:48:48

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 20/21] evm: permit only valid security.evm xattrs to be updated

In addition to requiring CAP_SYS_ADMIN permission to modify/delete
security.evm, prohibit invalid security.evm xattrs from changing,
unless in fixmode. This patch prevents inadvertent 'fixing' of
security.evm to reflect offline modifications.

Reported-by: Roberto Sassu <[email protected]>
Signed-off-by: Mimi Zohar <[email protected]>
---
Documentation/kernel-parameters.txt | 6 +++
security/integrity/evm/evm_main.c | 77 ++++++++++++++++++++++++++++------
2 files changed, 69 insertions(+), 14 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index cc85a92..d9901cd 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -48,6 +48,7 @@ parameter is applicable:
EDD BIOS Enhanced Disk Drive Services (EDD) is enabled
EFI EFI Partitioning (GPT) is enabled
EIDE EIDE/ATAPI support is enabled.
+ EVM Extended Verification Module
FB The frame buffer device is enabled.
GCOV GCOV profiling is enabled.
HW Appropriate hardware is enabled.
@@ -750,6 +751,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
This option is obsoleted by the "netdev=" option, which
has equivalent usage. See its documentation for details.

+ evm_mode= [EVM]
+ Format: { "fix" }
+ Permit 'security.evm' to be updated regardless of
+ current integrity status.
+
failslab=
fail_page_alloc=
fail_make_request=[KNL]
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 3afefff..af9d229 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -38,13 +38,25 @@ char *evm_config_xattrnames[] = {
NULL
};

+static int evm_fixmode;
+static int __init evm_set_fixmode(char *str)
+{
+ if (strncmp(str, "fix", 3) == 0)
+ evm_fixmode = 1;
+ return 0;
+}
+__setup("evm_mode=", evm_set_fixmode);
+
/*
* 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.)
+ * and compare it against the stored security.evm xattr.
+ *
+ * For performance:
+ * - use the previoulsy retrieved xattr value and length to calculate the
+ * HMAC.)
+ * - cache the verification result in the iint, when available.
*
* Returns integrity status
*/
@@ -55,9 +67,10 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
struct integrity_iint_cache *iint)
{
char hmac_val[MAX_DIGEST_SIZE + 1];
+ enum integrity_status evm_status;
int rc;

- if (iint->evm_status == INTEGRITY_PASS)
+ if (iint && iint->evm_status == INTEGRITY_PASS)
return iint->evm_status;

/* if status is not PASS, try to check again - against -ENOMEM */
@@ -73,18 +86,21 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
GFP_NOFS);
if (rc < 0)
goto err_out;
- iint->evm_status = INTEGRITY_PASS;
- return iint->evm_status;
+ evm_status = INTEGRITY_PASS;
+ goto out;

err_out:
switch (rc) {
case -ENODATA: /* file not labelled */
- iint->evm_status = INTEGRITY_NOLABEL;
+ evm_status = INTEGRITY_NOLABEL;
break;
default:
- iint->evm_status = INTEGRITY_FAIL;
+ evm_status = INTEGRITY_FAIL;
}
- return iint->evm_status;
+out:
+ if (iint)
+ iint->evm_status = evm_status;
+ return evm_status;
}

static int evm_protected_xattr(const char *req_xattr_name)
@@ -157,6 +173,22 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
return 0;
}

+/*
+ * evm_verify_current_integrity - verify the dentry's metadata integrity
+ * @dentry: pointer to the affected dentry
+ *
+ * Verify and return the dentry's metadata integrity. The exceptions are
+ * before EVM is initialized or in 'fix' mode.
+ */
+static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+
+ if (!evm_initialized || !S_ISREG(inode->i_mode) || evm_fixmode)
+ return 0;
+ return evm_verify_hmac(dentry, NULL, NULL, 0, NULL);
+}
+
/**
* evm_inode_setxattr - protect the EVM extended attribute
* @dentry: pointer to the affected dentry
@@ -164,13 +196,22 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_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
+ * Updating 'security.evm' requires CAP_SYS_ADMIN privileges and that
+ * the current value is valid.
*/
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);
+
+ enum integrity_status evm_status;
+ int ret;
+
+ ret = evm_protect_xattr(dentry, xattr_name, xattr_value,
+ xattr_value_len);
+ if (ret)
+ return ret;
+ evm_status = evm_verify_current_integrity(dentry);
+ return evm_status == INTEGRITY_PASS ? 0 : -EPERM;
}

/**
@@ -178,11 +219,19 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,
* @dentry: pointer to the affected dentry
* @xattr_name: pointer to the affected extended attribute name
*
- * Prevent 'security.evm' from being removed.
+ * Removing 'security.evm' requires CAP_SYS_ADMIN privileges and that
+ * the current value is valid.
*/
int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name)
{
- return evm_protect_xattr(dentry, xattr_name, NULL, 0);
+ enum integrity_status evm_status;
+ int ret;
+
+ ret = evm_protect_xattr(dentry, xattr_name, NULL, 0);
+ if (ret)
+ return ret;
+ evm_status = evm_verify_current_integrity(dentry);
+ return evm_status == INTEGRITY_PASS ? 0 : -EPERM;
}

/**
--
1.7.3.4

2011-05-16 14:49:06

by Mimi Zohar

[permalink] [raw]
Subject: [PATCH v5 21/21] evm: add evm_inode_setattr to prevent updating an invalid security.evm

Permit changing of security.evm only when valid, unless in fixmode.

Reported-by: Roberto Sassu <[email protected]>
Signed-off-by: Mimi Zohar <[email protected]>
---
include/linux/evm.h | 6 ++++++
security/integrity/evm/evm_main.c | 15 +++++++++++++++
security/security.c | 7 ++++++-
3 files changed, 27 insertions(+), 1 deletions(-)

diff --git a/include/linux/evm.h b/include/linux/evm.h
index 8db7b74..afc0669 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -19,6 +19,7 @@ extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
void *xattr_value,
size_t xattr_value_len,
struct integrity_iint_cache *iint);
+extern int evm_inode_setattr(struct dentry *dentry, struct iattr *attr);
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);
@@ -44,6 +45,11 @@ static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
}
#endif

+static int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ return 0;
+}
+
static inline void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
{
return;
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index af9d229..61fe355 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -278,6 +278,21 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
}

/**
+ * evm_inode_setattr - prevent updating an invalid EVM extended attribute
+ * @dentry: pointer to the affected dentry
+ */
+int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ unsigned int ia_valid = attr->ia_valid;
+ enum integrity_status evm_status;
+
+ if (ia_valid & ~(ATTR_MODE | ATTR_UID | ATTR_GID))
+ return 0;
+ evm_status = evm_verify_current_integrity(dentry);
+ return evm_status == INTEGRITY_PASS ? 0 : -EPERM;
+}
+
+/**
* evm_inode_post_setattr - update 'security.evm' after modifying metadata
* @dentry: pointer to the affected dentry
* @ia_valid: for the UID and GID status
diff --git a/security/security.c b/security/security.c
index 635bcc9..d21f899 100644
--- a/security/security.c
+++ b/security/security.c
@@ -534,9 +534,14 @@ int security_inode_exec_permission(struct inode *inode, unsigned int flags)

int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
{
+ int ret;
+
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_setattr(dentry, attr);
+ ret = security_ops->inode_setattr(dentry, attr);
+ if (ret)
+ return ret;
+ return evm_inode_setattr(dentry, attr);
}
EXPORT_SYMBOL_GPL(security_inode_setattr);

--
1.7.3.4

2011-05-16 15:29:19

by Steven Whitehouse

[permalink] [raw]
Subject: Re: [PATCH v5 13/21] evm: add evm_inode_post_init call in gfs2

Hi,

On Mon, 2011-05-16 at 10:45 -0400, Mimi Zohar wrote:
> After creating the initial LSM security extended attribute, call
> evm_inode_post_init_security() to create the 'security.evm'
> extended attribute.
>
> Signed-off-by: Mimi Zohar <[email protected]>
> ---
> fs/gfs2/inode.c | 28 +++++++++++++++++++---------
> 1 files changed, 19 insertions(+), 9 deletions(-)
>
[snip]
> + struct xattr lsm_xattr;
> + struct xattr evm_xattr;
>
> err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr,
> - &name, &value, &len);
> + &lsm_xattr.name, &lsm_xattr.value,
> + &lsm_xattr.value_len);
>
> if (err) {
> if (err == -EOPNOTSUPP)
> @@ -780,11 +781,20 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
> return err;
> }
>
> - err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0,
> - GFS2_EATYPE_SECURITY);
> - kfree(value);
> - kfree(name);
> -
> + err = __gfs2_xattr_set(&ip->i_inode, lsm_xattr.name, lsm_xattr.value,
> + lsm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
> + if (err < 0)
> + goto out;
> + err = evm_inode_post_init_security(&ip->i_inode, &lsm_xattr,
> + &evm_xattr);
> + if (err)
> + goto out;
> + err = __gfs2_xattr_set(&ip->i_inode, evm_xattr.name, evm_xattr.value,
> + evm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
> + kfree(evm_xattr.value);
> +out:
> + kfree(lsm_xattr.name);
> + kfree(lsm_xattr.value);
> return err;
> }
>

Just wondering whether we could have a single call to the security
subsystem which returns a vector of xattrs rather than having to call
two different functions?

Steve.

2011-05-16 15:51:12

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 13/21] evm: add evm_inode_post_init call in gfs2

On Mon, 2011-05-16 at 16:30 +0100, Steven Whitehouse wrote:
> Hi,
>
> On Mon, 2011-05-16 at 10:45 -0400, Mimi Zohar wrote:
> > After creating the initial LSM security extended attribute, call
> > evm_inode_post_init_security() to create the 'security.evm'
> > extended attribute.
> >
> > Signed-off-by: Mimi Zohar <[email protected]>
> > ---
> > fs/gfs2/inode.c | 28 +++++++++++++++++++---------
> > 1 files changed, 19 insertions(+), 9 deletions(-)
> >
> [snip]
> > + struct xattr lsm_xattr;
> > + struct xattr evm_xattr;
> >
> > err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr,
> > - &name, &value, &len);
> > + &lsm_xattr.name, &lsm_xattr.value,
> > + &lsm_xattr.value_len);
> >
> > if (err) {
> > if (err == -EOPNOTSUPP)
> > @@ -780,11 +781,20 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
> > return err;
> > }
> >
> > - err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0,
> > - GFS2_EATYPE_SECURITY);
> > - kfree(value);
> > - kfree(name);
> > -
> > + err = __gfs2_xattr_set(&ip->i_inode, lsm_xattr.name, lsm_xattr.value,
> > + lsm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
> > + if (err < 0)
> > + goto out;
> > + err = evm_inode_post_init_security(&ip->i_inode, &lsm_xattr,
> > + &evm_xattr);
> > + if (err)
> > + goto out;
> > + err = __gfs2_xattr_set(&ip->i_inode, evm_xattr.name, evm_xattr.value,
> > + evm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
> > + kfree(evm_xattr.value);
> > +out:
> > + kfree(lsm_xattr.name);
> > + kfree(lsm_xattr.value);
> > return err;
> > }
> >
>
> Just wondering whether we could have a single call to the security
> subsystem which returns a vector of xattrs rather than having to call
> two different functions?
>
> Steve.

There are a number of places that the LSM function is called immediately
followed by either EVM/IMA. In each of those places it is hidden from
the caller by calling the security_inode_XXX_security(). In this case
each fs has it's own method of creating an extended attribute. If that
method could be passed to security_inode_init_security, then
security_inode_init_security() could call both the LSM and EVM functions
directly.

Mimi

2011-05-16 16:13:53

by Steven Whitehouse

[permalink] [raw]
Subject: Re: [PATCH v5 13/21] evm: add evm_inode_post_init call in gfs2

Hi,

On Mon, 2011-05-16 at 11:50 -0400, Mimi Zohar wrote:
> On Mon, 2011-05-16 at 16:30 +0100, Steven Whitehouse wrote:
> > Hi,
> >
> > On Mon, 2011-05-16 at 10:45 -0400, Mimi Zohar wrote:
> > > After creating the initial LSM security extended attribute, call
> > > evm_inode_post_init_security() to create the 'security.evm'
> > > extended attribute.
> > >
> > > Signed-off-by: Mimi Zohar <[email protected]>
> > > ---
> > > fs/gfs2/inode.c | 28 +++++++++++++++++++---------
> > > 1 files changed, 19 insertions(+), 9 deletions(-)
> > >
> > [snip]
> > > + struct xattr lsm_xattr;
> > > + struct xattr evm_xattr;
> > >
> > > err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr,
> > > - &name, &value, &len);
> > > + &lsm_xattr.name, &lsm_xattr.value,
> > > + &lsm_xattr.value_len);
> > >
> > > if (err) {
> > > if (err == -EOPNOTSUPP)
> > > @@ -780,11 +781,20 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
> > > return err;
> > > }
> > >
> > > - err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0,
> > > - GFS2_EATYPE_SECURITY);
> > > - kfree(value);
> > > - kfree(name);
> > > -
> > > + err = __gfs2_xattr_set(&ip->i_inode, lsm_xattr.name, lsm_xattr.value,
> > > + lsm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
> > > + if (err < 0)
> > > + goto out;
> > > + err = evm_inode_post_init_security(&ip->i_inode, &lsm_xattr,
> > > + &evm_xattr);
> > > + if (err)
> > > + goto out;
> > > + err = __gfs2_xattr_set(&ip->i_inode, evm_xattr.name, evm_xattr.value,
> > > + evm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
> > > + kfree(evm_xattr.value);
> > > +out:
> > > + kfree(lsm_xattr.name);
> > > + kfree(lsm_xattr.value);
> > > return err;
> > > }
> > >
> >
> > Just wondering whether we could have a single call to the security
> > subsystem which returns a vector of xattrs rather than having to call
> > two different functions?
> >
> > Steve.
>
> There are a number of places that the LSM function is called immediately
> followed by either EVM/IMA. In each of those places it is hidden from
> the caller by calling the security_inode_XXX_security(). In this case
> each fs has it's own method of creating an extended attribute. If that
> method could be passed to security_inode_init_security, then
> security_inode_init_security() could call both the LSM and EVM functions
> directly.
>
> Mimi
>

I'm still not quite sure I understand... from a (very brief) look at the
paper, it seems that what you are trying to do is add a new xattr to
inodes which has some hash of some of the inode metadata (presumably
including the selinux xattr and some other fields).

I'm not sure why it matters whether the selinux data has been written to
the buffers before the xattr containing the hash? The data will not
change (I hope!) and if it does presumably the hash will pick that up
when it is checked at a later date?

The reason I'm asking is that currently the creation of GFS2 inodes is
broken down into a number of transactions, carefully designed to ensure
that the correct clean up occurs if there is an error. I would like to
try and reduce the number of transactions during the create process
where possible. That means I would like to move to a model which looks
like this:

1. Calculate number of blocks required, based on inode + xattrs (if any)
2. Allocate blocks
3. Populate with data (i.e. set xattrs)

I'm trying to work out whether there is some reason why we have to use
your proposed:

1. Get selinux xattr
2. Set selinux xattr
3. Get EVM xattr
4. Set EVM xattr

as opposed to getting all the xattrs in a single call and then being
able to set them all in a single operation, if that makes sense?

Steve.

2011-05-16 16:36:25

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 13/21] evm: add evm_inode_post_init call in gfs2

On Mon, 2011-05-16 at 17:14 +0100, Steven Whitehouse wrote:
> Hi,
>
> On Mon, 2011-05-16 at 11:50 -0400, Mimi Zohar wrote:
> > On Mon, 2011-05-16 at 16:30 +0100, Steven Whitehouse wrote:
> > > Hi,
> > >
> > > On Mon, 2011-05-16 at 10:45 -0400, Mimi Zohar wrote:
> > > > After creating the initial LSM security extended attribute, call
> > > > evm_inode_post_init_security() to create the 'security.evm'
> > > > extended attribute.
> > > >
> > > > Signed-off-by: Mimi Zohar <[email protected]>
> > > > ---
> > > > fs/gfs2/inode.c | 28 +++++++++++++++++++---------
> > > > 1 files changed, 19 insertions(+), 9 deletions(-)
> > > >
> > > [snip]
> > > > + struct xattr lsm_xattr;
> > > > + struct xattr evm_xattr;
> > > >
> > > > err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr,
> > > > - &name, &value, &len);
> > > > + &lsm_xattr.name, &lsm_xattr.value,
> > > > + &lsm_xattr.value_len);
> > > >
> > > > if (err) {
> > > > if (err == -EOPNOTSUPP)
> > > > @@ -780,11 +781,20 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
> > > > return err;
> > > > }
> > > >
> > > > - err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0,
> > > > - GFS2_EATYPE_SECURITY);
> > > > - kfree(value);
> > > > - kfree(name);
> > > > -
> > > > + err = __gfs2_xattr_set(&ip->i_inode, lsm_xattr.name, lsm_xattr.value,
> > > > + lsm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
> > > > + if (err < 0)
> > > > + goto out;
> > > > + err = evm_inode_post_init_security(&ip->i_inode, &lsm_xattr,
> > > > + &evm_xattr);
> > > > + if (err)
> > > > + goto out;
> > > > + err = __gfs2_xattr_set(&ip->i_inode, evm_xattr.name, evm_xattr.value,
> > > > + evm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
> > > > + kfree(evm_xattr.value);
> > > > +out:
> > > > + kfree(lsm_xattr.name);
> > > > + kfree(lsm_xattr.value);
> > > > return err;
> > > > }
> > > >
> > >
> > > Just wondering whether we could have a single call to the security
> > > subsystem which returns a vector of xattrs rather than having to call
> > > two different functions?
> > >
> > > Steve.
> >
> > There are a number of places that the LSM function is called immediately
> > followed by either EVM/IMA. In each of those places it is hidden from
> > the caller by calling the security_inode_XXX_security(). In this case
> > each fs has it's own method of creating an extended attribute. If that
> > method could be passed to security_inode_init_security, then
> > security_inode_init_security() could call both the LSM and EVM functions
> > directly.
> >
> > Mimi
> >
>
> I'm still not quite sure I understand... from a (very brief) look at the
> paper, it seems that what you are trying to do is add a new xattr to
> inodes which has some hash of some of the inode metadata (presumably
> including the selinux xattr and some other fields).

Yes, for the time being the other metadata is i_ino, i_generation,
i_uid, i_gid, and i_mode. The IMA-appriasal extension would store the
file hash as an extended attribute. The digital-signature extension
would store a digitial signature instead of the hash.

> I'm not sure why it matters whether the selinux data has been written to
> the buffers before the xattr containing the hash? The data will not
> change (I hope!) and if it does presumably the hash will pick that up
> when it is checked at a later date?

In this case it doesn't matter, as there aren't any other xattrs at this
point. When the file closes, the file hash would be written out as
security.ima, causing security.evm to be updated to reflect the change.

> The reason I'm asking is that currently the creation of GFS2 inodes is
> broken down into a number of transactions, carefully designed to ensure
> that the correct clean up occurs if there is an error. I would like to
> try and reduce the number of transactions during the create process
> where possible. That means I would like to move to a model which looks
> like this:
>
> 1. Calculate number of blocks required, based on inode + xattrs (if any)
> 2. Allocate blocks
> 3. Populate with data (i.e. set xattrs)
>
> I'm trying to work out whether there is some reason why we have to use
> your proposed:
>
> 1. Get selinux xattr
> 2. Set selinux xattr
> 3. Get EVM xattr
> 4. Set EVM xattr
>
> as opposed to getting all the xattrs in a single call and then being
> able to set them all in a single operation, if that makes sense?
>
> Steve.

Yes, it makes sense.

thanks,

Mimi

2011-05-16 17:51:19

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 13/21] evm: add evm_inode_post_init call in gfs2

On Mon, 2011-05-16 at 12:35 -0400, Mimi Zohar wrote:
> On Mon, 2011-05-16 at 17:14 +0100, Steven Whitehouse wrote:
> > Hi,
> >
> > On Mon, 2011-05-16 at 11:50 -0400, Mimi Zohar wrote:
> > > On Mon, 2011-05-16 at 16:30 +0100, Steven Whitehouse wrote:
> > > > Hi,
> > > >
> > > > On Mon, 2011-05-16 at 10:45 -0400, Mimi Zohar wrote:
> > > > > After creating the initial LSM security extended attribute, call
> > > > > evm_inode_post_init_security() to create the 'security.evm'
> > > > > extended attribute.
> > > > >
> > > > > Signed-off-by: Mimi Zohar <[email protected]>
> > > > > ---
> > > > > fs/gfs2/inode.c | 28 +++++++++++++++++++---------
> > > > > 1 files changed, 19 insertions(+), 9 deletions(-)
> > > > >
> > > > [snip]
> > > > > + struct xattr lsm_xattr;
> > > > > + struct xattr evm_xattr;
> > > > >
> > > > > err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr,
> > > > > - &name, &value, &len);
> > > > > + &lsm_xattr.name, &lsm_xattr.value,
> > > > > + &lsm_xattr.value_len);
> > > > >
> > > > > if (err) {
> > > > > if (err == -EOPNOTSUPP)
> > > > > @@ -780,11 +781,20 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
> > > > > return err;
> > > > > }
> > > > >
> > > > > - err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0,
> > > > > - GFS2_EATYPE_SECURITY);
> > > > > - kfree(value);
> > > > > - kfree(name);
> > > > > -
> > > > > + err = __gfs2_xattr_set(&ip->i_inode, lsm_xattr.name, lsm_xattr.value,
> > > > > + lsm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
> > > > > + if (err < 0)
> > > > > + goto out;
> > > > > + err = evm_inode_post_init_security(&ip->i_inode, &lsm_xattr,
> > > > > + &evm_xattr);
> > > > > + if (err)
> > > > > + goto out;
> > > > > + err = __gfs2_xattr_set(&ip->i_inode, evm_xattr.name, evm_xattr.value,
> > > > > + evm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
> > > > > + kfree(evm_xattr.value);
> > > > > +out:
> > > > > + kfree(lsm_xattr.name);
> > > > > + kfree(lsm_xattr.value);
> > > > > return err;
> > > > > }
> > > > >
> > > >
> > > > Just wondering whether we could have a single call to the security
> > > > subsystem which returns a vector of xattrs rather than having to call
> > > > two different functions?
> > > >
> > > > Steve.
> > >
> > > There are a number of places that the LSM function is called immediately
> > > followed by either EVM/IMA. In each of those places it is hidden from
> > > the caller by calling the security_inode_XXX_security(). In this case
> > > each fs has it's own method of creating an extended attribute. If that
> > > method could be passed to security_inode_init_security, then
> > > security_inode_init_security() could call both the LSM and EVM functions
> > > directly.
> > >
> > > Mimi
> > >
> >
> > I'm still not quite sure I understand... from a (very brief) look at the
> > paper, it seems that what you are trying to do is add a new xattr to
> > inodes which has some hash of some of the inode metadata (presumably
> > including the selinux xattr and some other fields).
>
> Yes, for the time being the other metadata is i_ino, i_generation,
> i_uid, i_gid, and i_mode. The IMA-appriasal extension would store the
> file hash as an extended attribute. The digital-signature extension
> would store a digitial signature instead of the hash.
>
> > I'm not sure why it matters whether the selinux data has been written to
> > the buffers before the xattr containing the hash? The data will not
> > change (I hope!) and if it does presumably the hash will pick that up
> > when it is checked at a later date?
>
> In this case it doesn't matter, as there aren't any other xattrs at this
> point. When the file closes, the file hash would be written out as
> security.ima, causing security.evm to be updated to reflect the change.
>
> > The reason I'm asking is that currently the creation of GFS2 inodes is
> > broken down into a number of transactions, carefully designed to ensure
> > that the correct clean up occurs if there is an error. I would like to
> > try and reduce the number of transactions during the create process
> > where possible. That means I would like to move to a model which looks
> > like this:
> >
> > 1. Calculate number of blocks required, based on inode + xattrs (if any)
> > 2. Allocate blocks
> > 3. Populate with data (i.e. set xattrs)
> >
> > I'm trying to work out whether there is some reason why we have to use
> > your proposed:
> >
> > 1. Get selinux xattr
> > 2. Set selinux xattr
> > 3. Get EVM xattr
> > 4. Set EVM xattr
> >
> > as opposed to getting all the xattrs in a single call and then being
> > able to set them all in a single operation, if that makes sense?
> >
> > Steve.
>
> Yes, it makes sense.

Just to clarify (and am cc'ing Stephen, Eric, and Casey).

Instead of:

int security_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, char **name,
void **value, size_t *len);

You're suggesting changing the interface to something like:

int security_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, struct xattr **xattrs);

where 'struct xattr' is defined as (9th patch):

--- 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);

xattrs would be null terminated. The fs would be responsible for freeing the xattrs?

thanks,

Mimi

2011-05-16 17:56:47

by Steven Whitehouse

[permalink] [raw]
Subject: Re: [PATCH v5 13/21] evm: add evm_inode_post_init call in gfs2

Hi,

On Mon, 2011-05-16 at 13:50 -0400, Mimi Zohar wrote:
> On Mon, 2011-05-16 at 12:35 -0400, Mimi Zohar wrote:
> > On Mon, 2011-05-16 at 17:14 +0100, Steven Whitehouse wrote:
> > > Hi,
> > >
> > > On Mon, 2011-05-16 at 11:50 -0400, Mimi Zohar wrote:
> > > > On Mon, 2011-05-16 at 16:30 +0100, Steven Whitehouse wrote:
> > > > > Hi,
> > > > >
> > > > > On Mon, 2011-05-16 at 10:45 -0400, Mimi Zohar wrote:
> > > > > > After creating the initial LSM security extended attribute, call
> > > > > > evm_inode_post_init_security() to create the 'security.evm'
> > > > > > extended attribute.
> > > > > >
> > > > > > Signed-off-by: Mimi Zohar <[email protected]>
> > > > > > ---
> > > > > > fs/gfs2/inode.c | 28 +++++++++++++++++++---------
> > > > > > 1 files changed, 19 insertions(+), 9 deletions(-)
> > > > > >
> > > > > [snip]
> > > > > > + struct xattr lsm_xattr;
> > > > > > + struct xattr evm_xattr;
> > > > > >
> > > > > > err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr,
> > > > > > - &name, &value, &len);
> > > > > > + &lsm_xattr.name, &lsm_xattr.value,
> > > > > > + &lsm_xattr.value_len);
> > > > > >
> > > > > > if (err) {
> > > > > > if (err == -EOPNOTSUPP)
> > > > > > @@ -780,11 +781,20 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
> > > > > > return err;
> > > > > > }
> > > > > >
> > > > > > - err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0,
> > > > > > - GFS2_EATYPE_SECURITY);
> > > > > > - kfree(value);
> > > > > > - kfree(name);
> > > > > > -
> > > > > > + err = __gfs2_xattr_set(&ip->i_inode, lsm_xattr.name, lsm_xattr.value,
> > > > > > + lsm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
> > > > > > + if (err < 0)
> > > > > > + goto out;
> > > > > > + err = evm_inode_post_init_security(&ip->i_inode, &lsm_xattr,
> > > > > > + &evm_xattr);
> > > > > > + if (err)
> > > > > > + goto out;
> > > > > > + err = __gfs2_xattr_set(&ip->i_inode, evm_xattr.name, evm_xattr.value,
> > > > > > + evm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
> > > > > > + kfree(evm_xattr.value);
> > > > > > +out:
> > > > > > + kfree(lsm_xattr.name);
> > > > > > + kfree(lsm_xattr.value);
> > > > > > return err;
> > > > > > }
> > > > > >
> > > > >
> > > > > Just wondering whether we could have a single call to the security
> > > > > subsystem which returns a vector of xattrs rather than having to call
> > > > > two different functions?
> > > > >
> > > > > Steve.
> > > >
> > > > There are a number of places that the LSM function is called immediately
> > > > followed by either EVM/IMA. In each of those places it is hidden from
> > > > the caller by calling the security_inode_XXX_security(). In this case
> > > > each fs has it's own method of creating an extended attribute. If that
> > > > method could be passed to security_inode_init_security, then
> > > > security_inode_init_security() could call both the LSM and EVM functions
> > > > directly.
> > > >
> > > > Mimi
> > > >
> > >
> > > I'm still not quite sure I understand... from a (very brief) look at the
> > > paper, it seems that what you are trying to do is add a new xattr to
> > > inodes which has some hash of some of the inode metadata (presumably
> > > including the selinux xattr and some other fields).
> >
> > Yes, for the time being the other metadata is i_ino, i_generation,
> > i_uid, i_gid, and i_mode. The IMA-appriasal extension would store the
> > file hash as an extended attribute. The digital-signature extension
> > would store a digitial signature instead of the hash.
> >
> > > I'm not sure why it matters whether the selinux data has been written to
> > > the buffers before the xattr containing the hash? The data will not
> > > change (I hope!) and if it does presumably the hash will pick that up
> > > when it is checked at a later date?
> >
> > In this case it doesn't matter, as there aren't any other xattrs at this
> > point. When the file closes, the file hash would be written out as
> > security.ima, causing security.evm to be updated to reflect the change.
> >
> > > The reason I'm asking is that currently the creation of GFS2 inodes is
> > > broken down into a number of transactions, carefully designed to ensure
> > > that the correct clean up occurs if there is an error. I would like to
> > > try and reduce the number of transactions during the create process
> > > where possible. That means I would like to move to a model which looks
> > > like this:
> > >
> > > 1. Calculate number of blocks required, based on inode + xattrs (if any)
> > > 2. Allocate blocks
> > > 3. Populate with data (i.e. set xattrs)
> > >
> > > I'm trying to work out whether there is some reason why we have to use
> > > your proposed:
> > >
> > > 1. Get selinux xattr
> > > 2. Set selinux xattr
> > > 3. Get EVM xattr
> > > 4. Set EVM xattr
> > >
> > > as opposed to getting all the xattrs in a single call and then being
> > > able to set them all in a single operation, if that makes sense?
> > >
> > > Steve.
> >
> > Yes, it makes sense.
>
> Just to clarify (and am cc'ing Stephen, Eric, and Casey).
>
> Instead of:
>
> int security_inode_init_security(struct inode *inode, struct inode *dir,
> const struct qstr *qstr, char **name,
> void **value, size_t *len);
>
> You're suggesting changing the interface to something like:
>
> int security_inode_init_security(struct inode *inode, struct inode *dir,
> const struct qstr *qstr, struct xattr **xattrs);
>
> where 'struct xattr' is defined as (9th patch):
>
> --- 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);
>
> xattrs would be null terminated. The fs would be responsible for freeing the xattrs?
>
> thanks,
>
> Mimi
>

Yes, if that makes sense... I got the impression from the paper that
there is the possibility of more xattrs being added in future and this
way the fs end of things wouldn't have to change again when that
happens. I'm still trying to get my head around it all, but it seems a
cleaner solution to me - though I may well be missing something still,

Steve.

2011-05-16 18:21:26

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 13/21] evm: add evm_inode_post_init call in gfs2

On Mon, 2011-05-16 at 18:57 +0100, Steven Whitehouse wrote:
> Hi,
>
> On Mon, 2011-05-16 at 13:50 -0400, Mimi Zohar wrote:
> > On Mon, 2011-05-16 at 12:35 -0400, Mimi Zohar wrote:
> > > On Mon, 2011-05-16 at 17:14 +0100, Steven Whitehouse wrote:
> > > > Hi,
> > > >
> > > > On Mon, 2011-05-16 at 11:50 -0400, Mimi Zohar wrote:
> > > > > On Mon, 2011-05-16 at 16:30 +0100, Steven Whitehouse wrote:
> > > > > > Hi,
> > > > > >
> > > > > > On Mon, 2011-05-16 at 10:45 -0400, Mimi Zohar wrote:
> > > > > > > After creating the initial LSM security extended attribute, call
> > > > > > > evm_inode_post_init_security() to create the 'security.evm'
> > > > > > > extended attribute.
> > > > > > >
> > > > > > > Signed-off-by: Mimi Zohar <[email protected]>
> > > > > > > ---
> > > > > > > fs/gfs2/inode.c | 28 +++++++++++++++++++---------
> > > > > > > 1 files changed, 19 insertions(+), 9 deletions(-)
> > > > > > >
> > > > > > [snip]
> > > > > > > + struct xattr lsm_xattr;
> > > > > > > + struct xattr evm_xattr;
> > > > > > >
> > > > > > > err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr,
> > > > > > > - &name, &value, &len);
> > > > > > > + &lsm_xattr.name, &lsm_xattr.value,
> > > > > > > + &lsm_xattr.value_len);
> > > > > > >
> > > > > > > if (err) {
> > > > > > > if (err == -EOPNOTSUPP)
> > > > > > > @@ -780,11 +781,20 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
> > > > > > > return err;
> > > > > > > }
> > > > > > >
> > > > > > > - err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0,
> > > > > > > - GFS2_EATYPE_SECURITY);
> > > > > > > - kfree(value);
> > > > > > > - kfree(name);
> > > > > > > -
> > > > > > > + err = __gfs2_xattr_set(&ip->i_inode, lsm_xattr.name, lsm_xattr.value,
> > > > > > > + lsm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
> > > > > > > + if (err < 0)
> > > > > > > + goto out;
> > > > > > > + err = evm_inode_post_init_security(&ip->i_inode, &lsm_xattr,
> > > > > > > + &evm_xattr);
> > > > > > > + if (err)
> > > > > > > + goto out;
> > > > > > > + err = __gfs2_xattr_set(&ip->i_inode, evm_xattr.name, evm_xattr.value,
> > > > > > > + evm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
> > > > > > > + kfree(evm_xattr.value);
> > > > > > > +out:
> > > > > > > + kfree(lsm_xattr.name);
> > > > > > > + kfree(lsm_xattr.value);
> > > > > > > return err;
> > > > > > > }
> > > > > > >
> > > > > >
> > > > > > Just wondering whether we could have a single call to the security
> > > > > > subsystem which returns a vector of xattrs rather than having to call
> > > > > > two different functions?
> > > > > >
> > > > > > Steve.
> > > > >
> > > > > There are a number of places that the LSM function is called immediately
> > > > > followed by either EVM/IMA. In each of those places it is hidden from
> > > > > the caller by calling the security_inode_XXX_security(). In this case
> > > > > each fs has it's own method of creating an extended attribute. If that
> > > > > method could be passed to security_inode_init_security, then
> > > > > security_inode_init_security() could call both the LSM and EVM functions
> > > > > directly.
> > > > >
> > > > > Mimi
> > > > >
> > > >
> > > > I'm still not quite sure I understand... from a (very brief) look at the
> > > > paper, it seems that what you are trying to do is add a new xattr to
> > > > inodes which has some hash of some of the inode metadata (presumably
> > > > including the selinux xattr and some other fields).
> > >
> > > Yes, for the time being the other metadata is i_ino, i_generation,
> > > i_uid, i_gid, and i_mode. The IMA-appriasal extension would store the
> > > file hash as an extended attribute. The digital-signature extension
> > > would store a digitial signature instead of the hash.
> > >
> > > > I'm not sure why it matters whether the selinux data has been written to
> > > > the buffers before the xattr containing the hash? The data will not
> > > > change (I hope!) and if it does presumably the hash will pick that up
> > > > when it is checked at a later date?
> > >
> > > In this case it doesn't matter, as there aren't any other xattrs at this
> > > point. When the file closes, the file hash would be written out as
> > > security.ima, causing security.evm to be updated to reflect the change.
> > >
> > > > The reason I'm asking is that currently the creation of GFS2 inodes is
> > > > broken down into a number of transactions, carefully designed to ensure
> > > > that the correct clean up occurs if there is an error. I would like to
> > > > try and reduce the number of transactions during the create process
> > > > where possible. That means I would like to move to a model which looks
> > > > like this:
> > > >
> > > > 1. Calculate number of blocks required, based on inode + xattrs (if any)
> > > > 2. Allocate blocks
> > > > 3. Populate with data (i.e. set xattrs)
> > > >
> > > > I'm trying to work out whether there is some reason why we have to use
> > > > your proposed:
> > > >
> > > > 1. Get selinux xattr
> > > > 2. Set selinux xattr
> > > > 3. Get EVM xattr
> > > > 4. Set EVM xattr
> > > >
> > > > as opposed to getting all the xattrs in a single call and then being
> > > > able to set them all in a single operation, if that makes sense?
> > > >
> > > > Steve.
> > >
> > > Yes, it makes sense.
> >
> > Just to clarify (and am cc'ing Stephen, Eric, and Casey).
> >
> > Instead of:
> >
> > int security_inode_init_security(struct inode *inode, struct inode *dir,
> > const struct qstr *qstr, char **name,
> > void **value, size_t *len);
> >
> > You're suggesting changing the interface to something like:
> >
> > int security_inode_init_security(struct inode *inode, struct inode *dir,
> > const struct qstr *qstr, struct xattr **xattrs);
> >
> > where 'struct xattr' is defined as (9th patch):
> >
> > --- 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);
> >
> > xattrs would be null terminated. The fs would be responsible for freeing the xattrs?
> >
> > thanks,
> >
> > Mimi
> >
>
> Yes, if that makes sense... I got the impression from the paper that
> there is the possibility of more xattrs being added in future and this
> way the fs end of things wouldn't have to change again when that
> happens. I'm still trying to get my head around it all, but it seems a
> cleaner solution to me - though I may well be missing something still,
>
> Steve.

At this point at least, the only other xattr would be security.ima,
which isn't created/updated until __fput() is called.

Your suggestion of security_inode_init_security() returning multiple
xattrs is a cleaner solution for EVM, but such a change requires the LSM
folks approval.

thanks,

Mimi

2011-05-16 18:23:39

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v5 13/21] evm: add evm_inode_post_init call in gfs2

On 5/16/2011 10:57 AM, Steven Whitehouse wrote:
> Hi,
>
> On Mon, 2011-05-16 at 13:50 -0400, Mimi Zohar wrote:
>> On Mon, 2011-05-16 at 12:35 -0400, Mimi Zohar wrote:
>>> On Mon, 2011-05-16 at 17:14 +0100, Steven Whitehouse wrote:
>>>> Hi,
>>>>
>>>> On Mon, 2011-05-16 at 11:50 -0400, Mimi Zohar wrote:
>>>>> On Mon, 2011-05-16 at 16:30 +0100, Steven Whitehouse wrote:
>>>>>> Hi,
>>>>>>
>>>>>> On Mon, 2011-05-16 at 10:45 -0400, Mimi Zohar wrote:
>>>>>>> After creating the initial LSM security extended attribute, call
>>>>>>> evm_inode_post_init_security() to create the 'security.evm'
>>>>>>> extended attribute.
>>>>>>>
>>>>>>> Signed-off-by: Mimi Zohar <[email protected]>
>>>>>>> ---
>>>>>>> fs/gfs2/inode.c | 28 +++++++++++++++++++---------
>>>>>>> 1 files changed, 19 insertions(+), 9 deletions(-)
>>>>>>>
>>>>>> [snip]
>>>>>>> + struct xattr lsm_xattr;
>>>>>>> + struct xattr evm_xattr;
>>>>>>>
>>>>>>> err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr,
>>>>>>> - &name, &value, &len);
>>>>>>> + &lsm_xattr.name, &lsm_xattr.value,
>>>>>>> + &lsm_xattr.value_len);
>>>>>>>
>>>>>>> if (err) {
>>>>>>> if (err == -EOPNOTSUPP)
>>>>>>> @@ -780,11 +781,20 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
>>>>>>> return err;
>>>>>>> }
>>>>>>>
>>>>>>> - err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0,
>>>>>>> - GFS2_EATYPE_SECURITY);
>>>>>>> - kfree(value);
>>>>>>> - kfree(name);
>>>>>>> -
>>>>>>> + err = __gfs2_xattr_set(&ip->i_inode, lsm_xattr.name, lsm_xattr.value,
>>>>>>> + lsm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
>>>>>>> + if (err < 0)
>>>>>>> + goto out;
>>>>>>> + err = evm_inode_post_init_security(&ip->i_inode, &lsm_xattr,
>>>>>>> + &evm_xattr);
>>>>>>> + if (err)
>>>>>>> + goto out;
>>>>>>> + err = __gfs2_xattr_set(&ip->i_inode, evm_xattr.name, evm_xattr.value,
>>>>>>> + evm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
>>>>>>> + kfree(evm_xattr.value);
>>>>>>> +out:
>>>>>>> + kfree(lsm_xattr.name);
>>>>>>> + kfree(lsm_xattr.value);
>>>>>>> return err;
>>>>>>> }
>>>>>>>
>>>>>> Just wondering whether we could have a single call to the security
>>>>>> subsystem which returns a vector of xattrs rather than having to call
>>>>>> two different functions?
>>>>>>
>>>>>> Steve.
>>>>> There are a number of places that the LSM function is called immediately
>>>>> followed by either EVM/IMA. In each of those places it is hidden from
>>>>> the caller by calling the security_inode_XXX_security(). In this case
>>>>> each fs has it's own method of creating an extended attribute. If that
>>>>> method could be passed to security_inode_init_security, then
>>>>> security_inode_init_security() could call both the LSM and EVM functions
>>>>> directly.
>>>>>
>>>>> Mimi
>>>>>
>>>> I'm still not quite sure I understand... from a (very brief) look at the
>>>> paper, it seems that what you are trying to do is add a new xattr to
>>>> inodes which has some hash of some of the inode metadata (presumably
>>>> including the selinux xattr and some other fields).
>>> Yes, for the time being the other metadata is i_ino, i_generation,
>>> i_uid, i_gid, and i_mode. The IMA-appriasal extension would store the
>>> file hash as an extended attribute. The digital-signature extension
>>> would store a digitial signature instead of the hash.
>>>
>>>> I'm not sure why it matters whether the selinux data has been written to
>>>> the buffers before the xattr containing the hash? The data will not
>>>> change (I hope!) and if it does presumably the hash will pick that up
>>>> when it is checked at a later date?
>>> In this case it doesn't matter, as there aren't any other xattrs at this
>>> point. When the file closes, the file hash would be written out as
>>> security.ima, causing security.evm to be updated to reflect the change.
>>>
>>>> The reason I'm asking is that currently the creation of GFS2 inodes is
>>>> broken down into a number of transactions, carefully designed to ensure
>>>> that the correct clean up occurs if there is an error. I would like to
>>>> try and reduce the number of transactions during the create process
>>>> where possible. That means I would like to move to a model which looks
>>>> like this:
>>>>
>>>> 1. Calculate number of blocks required, based on inode + xattrs (if any)
>>>> 2. Allocate blocks
>>>> 3. Populate with data (i.e. set xattrs)
>>>>
>>>> I'm trying to work out whether there is some reason why we have to use
>>>> your proposed:
>>>>
>>>> 1. Get selinux xattr
>>>> 2. Set selinux xattr
>>>> 3. Get EVM xattr
>>>> 4. Set EVM xattr
>>>>
>>>> as opposed to getting all the xattrs in a single call and then being
>>>> able to set them all in a single operation, if that makes sense?
>>>>
>>>> Steve.
>>> Yes, it makes sense.
>> Just to clarify (and am cc'ing Stephen, Eric, and Casey).
>>
>> Instead of:
>>
>> int security_inode_init_security(struct inode *inode, struct inode *dir,
>> const struct qstr *qstr, char **name,
>> void **value, size_t *len);
>>
>> You're suggesting changing the interface to something like:
>>
>> int security_inode_init_security(struct inode *inode, struct inode *dir,
>> const struct qstr *qstr, struct xattr **xattrs);
>>
>> where 'struct xattr' is defined as (9th patch):
>>
>> --- 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);
>>
>> xattrs would be null terminated. The fs would be responsible for freeing the xattrs?
>>
>> thanks,
>>
>> Mimi
>>
> Yes, if that makes sense... I got the impression from the paper that
> there is the possibility of more xattrs being added in future and this
> way the fs end of things wouldn't have to change again when that
> happens. I'm still trying to get my head around it all, but it seems a
> cleaner solution to me - though I may well be missing something still,

There is a very real possibility that multiple concurrent LSMs will
be supported before too long. Smack already uses multiple attributes
(SMACK64, SMACK64EXEC) on a file. Getting all the attributes in a
single call could result in an interface that requires parsing a
string argument, and we all know how popular those are. Introducing
an interface that we know isn't going to accommodate this upcoming
direction does not seem prudent.

> Steve.
>
>
>

2011-05-16 18:48:26

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 13/21] evm: add evm_inode_post_init call in gfs2

On Mon, 2011-05-16 at 11:23 -0700, Casey Schaufler wrote:
> On 5/16/2011 10:57 AM, Steven Whitehouse wrote:
> > Hi,
> >
> > On Mon, 2011-05-16 at 13:50 -0400, Mimi Zohar wrote:
> >> On Mon, 2011-05-16 at 12:35 -0400, Mimi Zohar wrote:
> >>> On Mon, 2011-05-16 at 17:14 +0100, Steven Whitehouse wrote:
> >>>> Hi,
> >>>>
> >>>> On Mon, 2011-05-16 at 11:50 -0400, Mimi Zohar wrote:
> >>>>> On Mon, 2011-05-16 at 16:30 +0100, Steven Whitehouse wrote:
> >>>>>> Hi,
> >>>>>>
> >>>>>> On Mon, 2011-05-16 at 10:45 -0400, Mimi Zohar wrote:
> >>>>>>> After creating the initial LSM security extended attribute, call
> >>>>>>> evm_inode_post_init_security() to create the 'security.evm'
> >>>>>>> extended attribute.
> >>>>>>>
> >>>>>>> Signed-off-by: Mimi Zohar <[email protected]>
> >>>>>>> ---
> >>>>>>> fs/gfs2/inode.c | 28 +++++++++++++++++++---------
> >>>>>>> 1 files changed, 19 insertions(+), 9 deletions(-)
> >>>>>>>
> >>>>>> [snip]
> >>>>>>> + struct xattr lsm_xattr;
> >>>>>>> + struct xattr evm_xattr;
> >>>>>>>
> >>>>>>> err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr,
> >>>>>>> - &name, &value, &len);
> >>>>>>> + &lsm_xattr.name, &lsm_xattr.value,
> >>>>>>> + &lsm_xattr.value_len);
> >>>>>>>
> >>>>>>> if (err) {
> >>>>>>> if (err == -EOPNOTSUPP)
> >>>>>>> @@ -780,11 +781,20 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
> >>>>>>> return err;
> >>>>>>> }
> >>>>>>>
> >>>>>>> - err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0,
> >>>>>>> - GFS2_EATYPE_SECURITY);
> >>>>>>> - kfree(value);
> >>>>>>> - kfree(name);
> >>>>>>> -
> >>>>>>> + err = __gfs2_xattr_set(&ip->i_inode, lsm_xattr.name, lsm_xattr.value,
> >>>>>>> + lsm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
> >>>>>>> + if (err < 0)
> >>>>>>> + goto out;
> >>>>>>> + err = evm_inode_post_init_security(&ip->i_inode, &lsm_xattr,
> >>>>>>> + &evm_xattr);
> >>>>>>> + if (err)
> >>>>>>> + goto out;
> >>>>>>> + err = __gfs2_xattr_set(&ip->i_inode, evm_xattr.name, evm_xattr.value,
> >>>>>>> + evm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
> >>>>>>> + kfree(evm_xattr.value);
> >>>>>>> +out:
> >>>>>>> + kfree(lsm_xattr.name);
> >>>>>>> + kfree(lsm_xattr.value);
> >>>>>>> return err;
> >>>>>>> }
> >>>>>>>
> >>>>>> Just wondering whether we could have a single call to the security
> >>>>>> subsystem which returns a vector of xattrs rather than having to call
> >>>>>> two different functions?
> >>>>>>
> >>>>>> Steve.
> >>>>> There are a number of places that the LSM function is called immediately
> >>>>> followed by either EVM/IMA. In each of those places it is hidden from
> >>>>> the caller by calling the security_inode_XXX_security(). In this case
> >>>>> each fs has it's own method of creating an extended attribute. If that
> >>>>> method could be passed to security_inode_init_security, then
> >>>>> security_inode_init_security() could call both the LSM and EVM functions
> >>>>> directly.
> >>>>>
> >>>>> Mimi
> >>>>>
> >>>> I'm still not quite sure I understand... from a (very brief) look at the
> >>>> paper, it seems that what you are trying to do is add a new xattr to
> >>>> inodes which has some hash of some of the inode metadata (presumably
> >>>> including the selinux xattr and some other fields).
> >>> Yes, for the time being the other metadata is i_ino, i_generation,
> >>> i_uid, i_gid, and i_mode. The IMA-appriasal extension would store the
> >>> file hash as an extended attribute. The digital-signature extension
> >>> would store a digitial signature instead of the hash.
> >>>
> >>>> I'm not sure why it matters whether the selinux data has been written to
> >>>> the buffers before the xattr containing the hash? The data will not
> >>>> change (I hope!) and if it does presumably the hash will pick that up
> >>>> when it is checked at a later date?
> >>> In this case it doesn't matter, as there aren't any other xattrs at this
> >>> point. When the file closes, the file hash would be written out as
> >>> security.ima, causing security.evm to be updated to reflect the change.
> >>>
> >>>> The reason I'm asking is that currently the creation of GFS2 inodes is
> >>>> broken down into a number of transactions, carefully designed to ensure
> >>>> that the correct clean up occurs if there is an error. I would like to
> >>>> try and reduce the number of transactions during the create process
> >>>> where possible. That means I would like to move to a model which looks
> >>>> like this:
> >>>>
> >>>> 1. Calculate number of blocks required, based on inode + xattrs (if any)
> >>>> 2. Allocate blocks
> >>>> 3. Populate with data (i.e. set xattrs)
> >>>>
> >>>> I'm trying to work out whether there is some reason why we have to use
> >>>> your proposed:
> >>>>
> >>>> 1. Get selinux xattr
> >>>> 2. Set selinux xattr
> >>>> 3. Get EVM xattr
> >>>> 4. Set EVM xattr
> >>>>
> >>>> as opposed to getting all the xattrs in a single call and then being
> >>>> able to set them all in a single operation, if that makes sense?
> >>>>
> >>>> Steve.
> >>> Yes, it makes sense.
> >> Just to clarify (and am cc'ing Stephen, Eric, and Casey).
> >>
> >> Instead of:
> >>
> >> int security_inode_init_security(struct inode *inode, struct inode *dir,
> >> const struct qstr *qstr, char **name,
> >> void **value, size_t *len);
> >>
> >> You're suggesting changing the interface to something like:
> >>
> >> int security_inode_init_security(struct inode *inode, struct inode *dir,
> >> const struct qstr *qstr, struct xattr **xattrs);
> >>
> >> where 'struct xattr' is defined as (9th patch):
> >>
> >> --- 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);
> >>
> >> xattrs would be null terminated. The fs would be responsible for freeing the xattrs?
> >>
> >> thanks,
> >>
> >> Mimi
> >>
> > Yes, if that makes sense... I got the impression from the paper that
> > there is the possibility of more xattrs being added in future and this
> > way the fs end of things wouldn't have to change again when that
> > happens. I'm still trying to get my head around it all, but it seems a
> > cleaner solution to me - though I may well be missing something still,
>
> There is a very real possibility that multiple concurrent LSMs will
> be supported before too long. Smack already uses multiple attributes
> (SMACK64, SMACK64EXEC) on a file. Getting all the attributes in a
> single call could result in an interface that requires parsing a
> string argument, and we all know how popular those are. Introducing
> an interface that we know isn't going to accommodate this upcoming
> direction does not seem prudent.

I would think that Smack would benefit from Steven's suggestion of
returning an array of xattrs. Without his suggestion, I'm not sure how
you are, or planning on, initializing multiple xattrs from a single LSM,
unless of course you're not using security_inode_init_security().

Multiple LSMs calling security_inode_init_security() will be an issue
for EVM, as EVM assumes there is a single LSM xattr on which to base the
initial hmac.

thanks,

Mimi

2011-05-16 19:25:13

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v5 13/21] evm: add evm_inode_post_init call in gfs2

On 5/16/2011 11:48 AM, Mimi Zohar wrote:
> On Mon, 2011-05-16 at 11:23 -0700, Casey Schaufler wrote:
>> On 5/16/2011 10:57 AM, Steven Whitehouse wrote:
>>> Hi,
>>>
>>> On Mon, 2011-05-16 at 13:50 -0400, Mimi Zohar wrote:
>>>> On Mon, 2011-05-16 at 12:35 -0400, Mimi Zohar wrote:
>>>>> On Mon, 2011-05-16 at 17:14 +0100, Steven Whitehouse wrote:
>>>>>> Hi,
>>>>>>
>>>>>> On Mon, 2011-05-16 at 11:50 -0400, Mimi Zohar wrote:
>>>>>>> On Mon, 2011-05-16 at 16:30 +0100, Steven Whitehouse wrote:
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> On Mon, 2011-05-16 at 10:45 -0400, Mimi Zohar wrote:
>>>>>>>>> After creating the initial LSM security extended attribute, call
>>>>>>>>> evm_inode_post_init_security() to create the 'security.evm'
>>>>>>>>> extended attribute.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Mimi Zohar <[email protected]>
>>>>>>>>> ---
>>>>>>>>> fs/gfs2/inode.c | 28 +++++++++++++++++++---------
>>>>>>>>> 1 files changed, 19 insertions(+), 9 deletions(-)
>>>>>>>>>
>>>>>>>> [snip]
>>>>>>>>> + struct xattr lsm_xattr;
>>>>>>>>> + struct xattr evm_xattr;
>>>>>>>>>
>>>>>>>>> err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr,
>>>>>>>>> - &name, &value, &len);
>>>>>>>>> + &lsm_xattr.name, &lsm_xattr.value,
>>>>>>>>> + &lsm_xattr.value_len);
>>>>>>>>>
>>>>>>>>> if (err) {
>>>>>>>>> if (err == -EOPNOTSUPP)
>>>>>>>>> @@ -780,11 +781,20 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
>>>>>>>>> return err;
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> - err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0,
>>>>>>>>> - GFS2_EATYPE_SECURITY);
>>>>>>>>> - kfree(value);
>>>>>>>>> - kfree(name);
>>>>>>>>> -
>>>>>>>>> + err = __gfs2_xattr_set(&ip->i_inode, lsm_xattr.name, lsm_xattr.value,
>>>>>>>>> + lsm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
>>>>>>>>> + if (err < 0)
>>>>>>>>> + goto out;
>>>>>>>>> + err = evm_inode_post_init_security(&ip->i_inode, &lsm_xattr,
>>>>>>>>> + &evm_xattr);
>>>>>>>>> + if (err)
>>>>>>>>> + goto out;
>>>>>>>>> + err = __gfs2_xattr_set(&ip->i_inode, evm_xattr.name, evm_xattr.value,
>>>>>>>>> + evm_xattr.value_len, 0, GFS2_EATYPE_SECURITY);
>>>>>>>>> + kfree(evm_xattr.value);
>>>>>>>>> +out:
>>>>>>>>> + kfree(lsm_xattr.name);
>>>>>>>>> + kfree(lsm_xattr.value);
>>>>>>>>> return err;
>>>>>>>>> }
>>>>>>>>>
>>>>>>>> Just wondering whether we could have a single call to the security
>>>>>>>> subsystem which returns a vector of xattrs rather than having to call
>>>>>>>> two different functions?
>>>>>>>>
>>>>>>>> Steve.
>>>>>>> There are a number of places that the LSM function is called immediately
>>>>>>> followed by either EVM/IMA. In each of those places it is hidden from
>>>>>>> the caller by calling the security_inode_XXX_security(). In this case
>>>>>>> each fs has it's own method of creating an extended attribute. If that
>>>>>>> method could be passed to security_inode_init_security, then
>>>>>>> security_inode_init_security() could call both the LSM and EVM functions
>>>>>>> directly.
>>>>>>>
>>>>>>> Mimi
>>>>>>>
>>>>>> I'm still not quite sure I understand... from a (very brief) look at the
>>>>>> paper, it seems that what you are trying to do is add a new xattr to
>>>>>> inodes which has some hash of some of the inode metadata (presumably
>>>>>> including the selinux xattr and some other fields).
>>>>> Yes, for the time being the other metadata is i_ino, i_generation,
>>>>> i_uid, i_gid, and i_mode. The IMA-appriasal extension would store the
>>>>> file hash as an extended attribute. The digital-signature extension
>>>>> would store a digitial signature instead of the hash.
>>>>>
>>>>>> I'm not sure why it matters whether the selinux data has been written to
>>>>>> the buffers before the xattr containing the hash? The data will not
>>>>>> change (I hope!) and if it does presumably the hash will pick that up
>>>>>> when it is checked at a later date?
>>>>> In this case it doesn't matter, as there aren't any other xattrs at this
>>>>> point. When the file closes, the file hash would be written out as
>>>>> security.ima, causing security.evm to be updated to reflect the change.
>>>>>
>>>>>> The reason I'm asking is that currently the creation of GFS2 inodes is
>>>>>> broken down into a number of transactions, carefully designed to ensure
>>>>>> that the correct clean up occurs if there is an error. I would like to
>>>>>> try and reduce the number of transactions during the create process
>>>>>> where possible. That means I would like to move to a model which looks
>>>>>> like this:
>>>>>>
>>>>>> 1. Calculate number of blocks required, based on inode + xattrs (if any)
>>>>>> 2. Allocate blocks
>>>>>> 3. Populate with data (i.e. set xattrs)
>>>>>>
>>>>>> I'm trying to work out whether there is some reason why we have to use
>>>>>> your proposed:
>>>>>>
>>>>>> 1. Get selinux xattr
>>>>>> 2. Set selinux xattr
>>>>>> 3. Get EVM xattr
>>>>>> 4. Set EVM xattr
>>>>>>
>>>>>> as opposed to getting all the xattrs in a single call and then being
>>>>>> able to set them all in a single operation, if that makes sense?
>>>>>>
>>>>>> Steve.
>>>>> Yes, it makes sense.
>>>> Just to clarify (and am cc'ing Stephen, Eric, and Casey).
>>>>
>>>> Instead of:
>>>>
>>>> int security_inode_init_security(struct inode *inode, struct inode *dir,
>>>> const struct qstr *qstr, char **name,
>>>> void **value, size_t *len);
>>>>
>>>> You're suggesting changing the interface to something like:
>>>>
>>>> int security_inode_init_security(struct inode *inode, struct inode *dir,
>>>> const struct qstr *qstr, struct xattr **xattrs);
>>>>
>>>> where 'struct xattr' is defined as (9th patch):
>>>>
>>>> --- 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);
>>>>
>>>> xattrs would be null terminated. The fs would be responsible for freeing the xattrs?
>>>>
>>>> thanks,
>>>>
>>>> Mimi
>>>>
>>> Yes, if that makes sense... I got the impression from the paper that
>>> there is the possibility of more xattrs being added in future and this
>>> way the fs end of things wouldn't have to change again when that
>>> happens. I'm still trying to get my head around it all, but it seems a
>>> cleaner solution to me - though I may well be missing something still,
>> There is a very real possibility that multiple concurrent LSMs will
>> be supported before too long. Smack already uses multiple attributes
>> (SMACK64, SMACK64EXEC) on a file. Getting all the attributes in a
>> single call could result in an interface that requires parsing a
>> string argument, and we all know how popular those are. Introducing
>> an interface that we know isn't going to accommodate this upcoming
>> direction does not seem prudent.
> I would think that Smack would benefit from Steven's suggestion of
> returning an array of xattrs. Without his suggestion, I'm not sure how
> you are, or planning on, initializing multiple xattrs from a single LSM,
> unless of course you're not using security_inode_init_security().

The good news is that Smack has one required attribute. The others
are for special purposes and will usually be absent. It is easy to
imagine an LSM that always uses multiple attributes on a given file.

Yes, the array of xattr structures makes sense for any one LSM,
but there still needs to be the potential for multiple calls for
the multiple LSM case. I can't see that going away without a radical
LSM restructuring.

> Multiple LSMs calling security_inode_init_security() will be an issue
> for EVM, as EVM assumes there is a single LSM xattr on which to base the
> initial hmac.

That is far from the biggest issue with multiple LSMs, but is definitely
something to worry about.

> thanks,
>
> Mimi
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>
>

2011-05-19 00:26:06

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On Mon, 16 May 2011 10:44:54 -0400
Mimi Zohar <[email protected]> wrote:

> 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.

The changelog forgot to define "offline tampering". I can guess what
it means, but my guess will surely be incomplete. I can do a web
search for the term but that really only leads me to this patchset.

It would be much better if I didn't have to guess. A good description
would list all the known offline tampering scenarios and would explain
how the patchset addresses them and whether there are any scenarios
which are not addressed.

Secondly, the changelog didn't attempt to give anyone a reason to merge
the patchset. Why is offline tampering bad? Why should we bother
addressing it? What value does this patchset provide to our users?
Again, I could guess. But it would be much much better to have these
things explained to us by the people who understand them.

Thirdly, I'm not seeing a description of the user interface anywhere.
Please fully describe it in a manner which can be efficiently reviewed.
For example, if there are any user-provided inputs, describe them. If
tampering has been detected then this is presumably communicated to the
operator in some fashion. Please fully describe that reporting scheme.
What steps do we expect the operator to take after tampering has been
detected? How does the patchset aid them in that? etc.


Once we have a better understanding of what the feature does and why it
does it and how it interfaces with the user, we can start looking at
the implementation.

2011-05-19 00:55:47

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 13/21] evm: add evm_inode_post_init call in gfs2

On Mon, 2011-05-16 at 12:25 -0700, Casey Schaufler wrote:
> On 5/16/2011 11:48 AM, Mimi Zohar wrote:
> > On Mon, 2011-05-16 at 11:23 -0700, Casey Schaufler wrote:

> >> There is a very real possibility that multiple concurrent LSMs will
> >> be supported before too long. Smack already uses multiple attributes
> >> (SMACK64, SMACK64EXEC) on a file. Getting all the attributes in a
> >> single call could result in an interface that requires parsing a
> >> string argument, and we all know how popular those are. Introducing
> >> an interface that we know isn't going to accommodate this upcoming
> >> direction does not seem prudent.
> > I would think that Smack would benefit from Steven's suggestion of
> > returning an array of xattrs. Without his suggestion, I'm not sure how
> > you are, or planning on, initializing multiple xattrs from a single LSM,
> > unless of course you're not using security_inode_init_security().
>
> The good news is that Smack has one required attribute. The others
> are for special purposes and will usually be absent. It is easy to
> imagine an LSM that always uses multiple attributes on a given file.
>
> Yes, the array of xattr structures makes sense for any one LSM,
> but there still needs to be the potential for multiple calls for
> the multiple LSM case. I can't see that going away without a radical
> LSM restructuring.
>
> > Multiple LSMs calling security_inode_init_security() will be an issue
> > for EVM, as EVM assumes there is a single LSM xattr on which to base the
> > initial hmac.
>
> That is far from the biggest issue with multiple LSMs, but is definitely
> something to worry about.

Ok. After thinking about this a bit more, moving
evm_inode_init_security() into security_inode_init_security() only works
for the single LSM and EVM case, but not for the multiple LSMs and EVM
case, as the 'stacker' would call each LSM's
security_inode_iint_security(). Having the 'stacker' return an array of
xattrs would make sense and, at the same time, resolve the EVM issue. In
evm_inode_post_init_security(), EVM could then walk the list of xattrs.

Mimi


2011-05-19 01:51:47

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On Wed, 2011-05-18 at 17:25 -0700, Andrew Morton wrote:
> On Mon, 16 May 2011 10:44:54 -0400
> Mimi Zohar <[email protected]> wrote:
>
> > 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.
>
> The changelog forgot to define "offline tampering". I can guess what
> it means, but my guess will surely be incomplete. I can do a web
> search for the term but that really only leads me to this patchset.
>
> It would be much better if I didn't have to guess. A good description
> would list all the known offline tampering scenarios and would explain
> how the patchset addresses them and whether there are any scenarios
> which are not addressed.

ok.

> Secondly, the changelog didn't attempt to give anyone a reason to merge
> the patchset. Why is offline tampering bad? Why should we bother
> addressing it? What value does this patchset provide to our users?
> Again, I could guess. But it would be much much better to have these
> things explained to us by the people who understand them.

Perhaps posting the EVM patches separately from the IMA-appraisal patches
wasn't the best idea after all, at least in terms of the patch description.
Previously, the combined EVM/IMA-appraisal patchset continued with:

IMA currently maintains an integrity measurement list, containing the hashes
of all executables, mmapped execute files, and files open for read by root
(assuming the default measurement policy). The measurement list, with other
information, can be used to assert the integrity of the running system to a
third party. This patchset extends IMA with local measurement appraisal. The
extension stores and maintains the file integrity measurement as an extended
attribute 'security.ima', which EVM can be configured to protect. Other
methods of validating a file's integrity will be posted as a separate
patchset (eg. IMA-digital-signatures).

DAC/MAC protect the integrity of a running system. An offline attack can
bypass these protection mechanisms by mounting the disk under a different
operating system and modifying the file data/metadata. If the disk is
subsequently remounted under the EVM + DAC/MAC + IMA protected OS, then the
hash of the file data won't match the hash stored in the IMA xattr, or the
TPM-calculated HMAC of the file's metadata won't be valid. Therefore, IMA +
MAC + EVM can protect system integrity online and detect offline tampering.

> Thirdly, I'm not seeing a description of the user interface anywhere.
> Please fully describe it in a manner which can be efficiently reviewed.
> For example, if there are any user-provided inputs, describe them. If
> tampering has been detected then this is presumably communicated to the
> operator in some fashion. Please fully describe that reporting scheme.
> What steps do we expect the operator to take after tampering has been
> detected? How does the patchset aid them in that? etc.

There aren't any userspace utilities to speak of, except for labeling
the filesystem. EVM/IMA-appraisal is in addition to the existing
mandatory/discretionary access controls. The EVM/IMA-appraisal decision
is based on file data and metadata integrity.

> Once we have a better understanding of what the feature does and why it
> does it and how it interfaces with the user, we can start looking at
> the implementation.

Much appreciated!

thanks,

Mimi

2011-05-19 02:06:25

by Serge E. Hallyn

[permalink] [raw]
Subject: Re: [PATCH v5 01/21] integrity: move ima inode integrity data management

Quoting Mimi Zohar ([email protected]):
> Move the inode integrity data(iint) management up to the integrity directory
> in order to share the iint among the different integrity models.

You also

rename several globally visible ima_* functions, structs, locks etc to
integrity_\0
replace '20' by SHA1_DIGEST_SIZE
remove unnecessary initialization of iint_initialized to 0

Which all are fine, but probably should be mentioned in changelog,
along with the magic phrase "no other functional changes" to aid
reviewers.

> Changelog:
> - Rebased on current ima_iint.c
> - Define integrity_iint_store/lock as static
>
> Signed-off-by: Mimi Zohar <[email protected]>

Acked-by: Serge Hallyn <[email protected]>

thanks,
-serge

> ---
> 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 <[email protected]>
> + *
> + * 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 e0f08b5..22847a8 100644
> --- a/security/Kconfig
> +++ b/security/Kconfig
> @@ -186,7 +186,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 <[email protected]>
> + *
> + * 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 <[email protected]>
> - *
> - * 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 <[email protected]>
> + *
> + * 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 1011423..d0c6576 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 */
> @@ -334,7 +335,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
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

2011-05-19 02:11:14

by Serge E. Hallyn

[permalink] [raw]
Subject: Re: [PATCH v5 02/21] xattr: define vfs_getxattr_alloc and vfs_xattr_cmp

Quoting Mimi Zohar ([email protected]):
> 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 <[email protected]>
> Acked-by: Serge Hallyn <[email protected]>

Still looks good.

thanks,
-serge

> ---
> 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 a19acdb..6da0c8c 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
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

2011-05-19 06:05:48

by Serge E. Hallyn

[permalink] [raw]
Subject: Re: [PATCH v5 03/21] evm: re-release

Quoting Mimi Zohar ([email protected]):
> 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.

That should read http://linux-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 <[email protected]>
> ---
> 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 <[email protected]>
> +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 <[email protected]>
> + * Kylene Hall <[email protected]>
> + *
> + * 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 <[email protected]>
> + * Kylene Hall <[email protected]>
> + *
> + * 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>

The rule historically has been linux/ includes come first. I could
be wrong but suspect that's still the case here.

> +#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);

crypto_hash_setkey() can fail, right?

> + 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)) {

Is this special case only here to avoid one vfs_getxattr_alloc(),
or is there another reason for it?

> + 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 :

If decrypted_datalen > MAX_KEY_SIZE, shouldn't you assume something went
wrong and return an error?

> + ekp->decrypted_datalen;
> + memcpy(evmkey, ekp->decrypted_data, evmkey_len);
> +
> + /* burn the original key contents */
> + memset(ekp->decrypted_data, 0, evmkey_len);

You're potentially leaving akp->decrypted_datalen - evmkey_len bits
unburned.

> + 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 <[email protected]>
> + * Kylene Hall <[email protected]>
> + *
> + * 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) {

Can you put a comment here as to why currently checking the lengths is
unnecessary due to the xattrs which exist? (Or add a length comparison)

> + 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 <[email protected]>
> + *
> + * 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
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

2011-05-19 09:24:24

by Steven Whitehouse

[permalink] [raw]
Subject: Re: [PATCH v5 13/21] evm: add evm_inode_post_init call in gfs2

Hi,

On Wed, 2011-05-18 at 20:55 -0400, Mimi Zohar wrote:
> On Mon, 2011-05-16 at 12:25 -0700, Casey Schaufler wrote:
> > On 5/16/2011 11:48 AM, Mimi Zohar wrote:
> > > On Mon, 2011-05-16 at 11:23 -0700, Casey Schaufler wrote:
>
> > >> There is a very real possibility that multiple concurrent LSMs will
> > >> be supported before too long. Smack already uses multiple attributes
> > >> (SMACK64, SMACK64EXEC) on a file. Getting all the attributes in a
> > >> single call could result in an interface that requires parsing a
> > >> string argument, and we all know how popular those are. Introducing
> > >> an interface that we know isn't going to accommodate this upcoming
> > >> direction does not seem prudent.
> > > I would think that Smack would benefit from Steven's suggestion of
> > > returning an array of xattrs. Without his suggestion, I'm not sure how
> > > you are, or planning on, initializing multiple xattrs from a single LSM,
> > > unless of course you're not using security_inode_init_security().
> >
> > The good news is that Smack has one required attribute. The others
> > are for special purposes and will usually be absent. It is easy to
> > imagine an LSM that always uses multiple attributes on a given file.
> >
> > Yes, the array of xattr structures makes sense for any one LSM,
> > but there still needs to be the potential for multiple calls for
> > the multiple LSM case. I can't see that going away without a radical
> > LSM restructuring.
> >
> > > Multiple LSMs calling security_inode_init_security() will be an issue
> > > for EVM, as EVM assumes there is a single LSM xattr on which to base the
> > > initial hmac.
> >
> > That is far from the biggest issue with multiple LSMs, but is definitely
> > something to worry about.
>
> Ok. After thinking about this a bit more, moving
> evm_inode_init_security() into security_inode_init_security() only works
> for the single LSM and EVM case, but not for the multiple LSMs and EVM
> case, as the 'stacker' would call each LSM's
> security_inode_iint_security(). Having the 'stacker' return an array of
> xattrs would make sense and, at the same time, resolve the EVM issue. In
> evm_inode_post_init_security(), EVM could then walk the list of xattrs.
>
> Mimi
>
>
>
That sounds like a reasonable solution to me,

Steve.

2011-05-19 21:37:59

by Serge E. Hallyn

[permalink] [raw]
Subject: Re: [PATCH v5 03/21] evm: re-release

Quoting Mimi Zohar ([email protected]):
...
> +extern int evm_hmac_size;
...
> +int evm_hmac_size = SHA1_DIGEST_SIZE;

I think I object to having both MAX_DIGEST_SIZE and evm_hmac_size, both
of which are set to SHA1_DIGEST_SIZE throughout this patchset. Especially
because of the comment I was about to make on patch 4/21, where you
then prepend the hmac with a 'type' byte, and start passing around
MAX_DIGEST_SIZE+1 and evm_hmac_size+1.

Even if you're going to be using those differently in a later patchset,
let's focus on this set for now and keep things simpler. One constant
for the hmac size, and then please define a new one (in patch 4) for
the annotated digest size. I can't think think of a good name. Which
suggests that perhaps you should define a nicely typed struct to contain
the header+hmac...

I see no other problems, so presuming that these are nicely addressed
I expect to happily ack.

thanks,
-serge

2011-05-19 22:06:56

by Serge E. Hallyn

[permalink] [raw]
Subject: Re: [PATCH v5 05/21] ima: move ima_file_free before releasing the file

Quoting Mimi Zohar ([email protected]):
> Integrity appraisal measures files on file_free and stores the file
> measurement as an xattr. Measure the file before releasing it.

Can you put a bit more in the commit msg about why? What's magic
about the fs-specific release function?

> Signed-off-by: Mimi Zohar <[email protected]>
> Acked-by: Serge Hallyn <[email protected]>
> ---
> 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
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

2011-05-19 22:13:05

by Serge E. Hallyn

[permalink] [raw]
Subject: Re: [PATCH v5 06/21] security: imbed evm calls in security hooks

Quoting Mimi Zohar ([email protected]):
> 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 <[email protected]>
> Acked-by: Serge Hallyn <[email protected]>

Still looks good, thanks.

> ---
> 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 <[email protected]>
> + */
> +
> +#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 d0c6576..635bcc9 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] =
> @@ -549,9 +550,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,
> @@ -560,6 +566,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)
> @@ -578,9 +585,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
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

2011-05-19 22:45:33

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 01/21] integrity: move ima inode integrity data management

On Wed, 2011-05-18 at 21:06 -0500, Serge E. Hallyn wrote:
> Quoting Mimi Zohar ([email protected]):
> > Move the inode integrity data(iint) management up to the integrity directory
> > in order to share the iint among the different integrity models.
>
> You also
>
> rename several globally visible ima_* functions, structs, locks etc to
> integrity_\0
> replace '20' by SHA1_DIGEST_SIZE
> remove unnecessary initialization of iint_initialized to 0

Yes, will update the changelog to reflect these changes as well.

> Which all are fine, but probably should be mentioned in changelog,
> along with the magic phrase "no other functional changes" to aid
> reviewers.

Wasn't aware of this.

> > Changelog:
> > - Rebased on current ima_iint.c
> > - Define integrity_iint_store/lock as static
> >
> > Signed-off-by: Mimi Zohar <[email protected]>
>
> Acked-by: Serge Hallyn <[email protected]>
>
> thanks,
> -serge

Thanks!

Mimi

2011-05-19 22:49:15

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 03/21] evm: re-release

On Thu, 2011-05-19 at 01:05 -0500, Serge E. Hallyn wrote:
> Quoting Mimi Zohar ([email protected]):
> > 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.
>
> That should read http://linux-ima.sourceforge.net/#EVM.

Thanks for catching that.

> > 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 <[email protected]>
> > ---
> > 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 <[email protected]>
> > +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 <[email protected]>
> > + * Kylene Hall <[email protected]>
> > + *
> > + * 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 <[email protected]>
> > + * Kylene Hall <[email protected]>
> > + *
> > + * 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>
>
> The rule historically has been linux/ includes come first. I could
> be wrong but suspect that's still the case here.

No, you're correct.

> > +#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);
>
> crypto_hash_setkey() can fail, right?

Yes, will add the check.

> > + 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)) {
>
> Is this special case only here to avoid one vfs_getxattr_alloc(),
> or is there another reason for it?

Right, it's to avoid making an unecessary vfs_getxattr_alloc() call.

> > + 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 :
>
> If decrypted_datalen > MAX_KEY_SIZE, shouldn't you assume something went
> wrong and return an error?

Yes, it's probably a good idea to return something meaningful, rather
than letting it fail latter on use. :-)

> > + ekp->decrypted_datalen;
> > + memcpy(evmkey, ekp->decrypted_data, evmkey_len);
> > +
> > + /* burn the original key contents */
> > + memset(ekp->decrypted_data, 0, evmkey_len);
>
> You're potentially leaving akp->decrypted_datalen - evmkey_len bits
> unburned.

Right, it should be: memset(ekp->decrypted_data, 0, ekp->decrypted_datalen);

> > + 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 <[email protected]>
> > + * Kylene Hall <[email protected]>
> > + *
> > + * 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) {
>
> Can you put a comment here as to why currently checking the lengths is
> unnecessary due to the xattrs which exist? (Or add a length comparison)

yes, length checking is necessary.

> > + 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 <[email protected]>
> > + *
> > + * 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


2011-05-20 00:51:56

by James Morris

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On Wed, 18 May 2011, Mimi Zohar wrote:

> > Once we have a better understanding of what the feature does and why it
> > does it and how it interfaces with the user, we can start looking at
> > the implementation.
>
> Much appreciated!

What is the status of potential users of the feature?

I recall that MeeGo were planning to use EVM, but they've since changed
their security plans. Do they still plan to use it? Are any other users
committing to use EVM?

Also -- this was raised some time back, but I can't find the discussion --
what does IMA/EVM provide over disk encryption as a protection against
offline attacks?

- James
--
James Morris
<[email protected]>

2011-05-20 00:55:09

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 05/21] ima: move ima_file_free before releasing the file

On Thu, 2011-05-19 at 17:06 -0500, Serge E. Hallyn wrote:
> Quoting Mimi Zohar ([email protected]):
> > Integrity appraisal measures files on file_free and stores the file
> > measurement as an xattr. Measure the file before releasing it.
>
> Can you put a bit more in the commit msg about why? What's magic
> about the fs-specific release function?

ima_file_free(), called on __fput(), currently flags files that have
changed, so that the file is re-measured. However, for appraising a
files's integrity, flagging the file is not enough. The file's
security.ima xattr must be updated to reflect any changes. This patch
moves releasing the file to after calculating the new file hash.

> > Signed-off-by: Mimi Zohar <[email protected]>
> > Acked-by: Serge Hallyn <[email protected]>
> > ---
> > 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);
> > --

2011-05-20 01:07:12

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On Fri, 2011-05-20 at 10:51 +1000, James Morris wrote:
> On Wed, 18 May 2011, Mimi Zohar wrote:
>
> > > Once we have a better understanding of what the feature does and why it
> > > does it and how it interfaces with the user, we can start looking at
> > > the implementation.
> >
> > Much appreciated!
>
> What is the status of potential users of the feature?
>
> I recall that MeeGo were planning to use EVM, but they've since changed
> their security plans. Do they still plan to use it? Are any other users
> committing to use EVM?
>
> Also -- this was raised some time back, but I can't find the discussion --
> what does IMA/EVM provide over disk encryption as a protection against
> offline attacks?
>
> - James

Dave Safford's whitepaper discusses this.
http://downloads.sf.net/project/linux-ima/linux-ima/Integrity_overview.pdf

Mimi


Mimi

2011-05-20 11:12:07

by Harald Hoyer

[permalink] [raw]
Subject: Re: [PATCH v5 03/21] evm: re-release

Am 20.05.2011 00:49, schrieb Mimi Zohar:
> On Thu, 2011-05-19 at 01:05 -0500, Serge E. Hallyn wrote:
>> Quoting Mimi Zohar ([email protected]):
>>> 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.
>>
>> That should read http://linux-ima.sourceforge.net/#EVM.
>
> Thanks for catching that.

The dracut patch, could easily turned into a separate dracut module with its own
files, without patching. Somebody did not understand the modular nature of
dracut. While you are at it, I happily integrate that module in upstream, if you
submit it to the initramfs mailing list.

2011-05-20 11:21:58

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 03/21] evm: re-release

On Fri, 2011-05-20 at 13:12 +0200, Harald Hoyer wrote:
> Am 20.05.2011 00:49, schrieb Mimi Zohar:
> > On Thu, 2011-05-19 at 01:05 -0500, Serge E. Hallyn wrote:
> >> Quoting Mimi Zohar ([email protected]):
> >>> 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.
> >>
> >> That should read http://linux-ima.sourceforge.net/#EVM.
> >
> > Thanks for catching that.
>
> The dracut patch, could easily turned into a separate dracut module with its own
> files, without patching. Somebody did not understand the modular nature of
> dracut. While you are at it, I happily integrate that module in upstream, if you
> submit it to the initramfs mailing list.

thanks!

Mimi

2011-05-20 12:29:16

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 03/21] evm: re-release

On Thu, 2011-05-19 at 16:37 -0500, Serge E. Hallyn wrote:
> Quoting Mimi Zohar ([email protected]):
> ...
> > +extern int evm_hmac_size;
> ...
> > +int evm_hmac_size = SHA1_DIGEST_SIZE;
>
> I think I object to having both MAX_DIGEST_SIZE and evm_hmac_size, both
> of which are set to SHA1_DIGEST_SIZE throughout this patchset. Especially
> because of the comment I was about to make on patch 4/21, where you
> then prepend the hmac with a 'type' byte, and start passing around
> MAX_DIGEST_SIZE+1 and evm_hmac_size+1.
>
> Even if you're going to be using those differently in a later patchset,
> let's focus on this set for now and keep things simpler. One constant
> for the hmac size, and then please define a new one (in patch 4) for
> the annotated digest size. I can't think think of a good name. Which
> suggests that perhaps you should define a nicely typed struct to contain
> the header+hmac...
>
> I see no other problems, so presuming that these are nicely addressed
> I expect to happily ack.
>
> thanks,
> -serge

Ok, MAX_DIGEST_SIZE was defined in the first patch of this patchset,
which moves the iint from IMA to integrity, but it seems to be
unnecessary for any of the additional EVM or IMA extensions, including
support for additional IMA hash sizes. I'll remove MAX_DIGEST_SIZE.

The reason for introducing the extra byte at this point in the patch
set, as opposed to waiting to do so in the digital signature patches, is
to permit existing labeled systems to continue to run properly (and be
bisect safe). Defining a structure is a good idea.

thanks,

Mimi

2011-05-20 13:07:00

by David Safford

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On Thu, 2011-05-19 at 21:07 -0400, Mimi Zohar wrote:
> On Fri, 2011-05-20 at 10:51 +1000, James Morris wrote:
> > On Wed, 18 May 2011, Mimi Zohar wrote:
> >
> > > > Once we have a better understanding of what the feature does and why it
> > > > does it and how it interfaces with the user, we can start looking at
> > > > the implementation.
> > >
> > > Much appreciated!
> >
> > What is the status of potential users of the feature?
> >
> > I recall that MeeGo were planning to use EVM, but they've since changed
> > their security plans. Do they still plan to use it? Are any other users
> > committing to use EVM?
> >
> > Also -- this was raised some time back, but I can't find the discussion --
> > what does IMA/EVM provide over disk encryption as a protection against
> > offline attacks?
> >
> > - James
>
> Dave Safford's whitepaper discusses this.
> http://downloads.sf.net/project/linux-ima/linux-ima/Integrity_overview.pdf
>
> Mimi

The short answer is that encryption provides confidentiality, but does
not provide integrity, authenticity, or immutability.

The easiest way to think about it is to consider a one time pad, which
provides perfect confidentiality, but is trivially bit-twiddled. Yes,
AES is better in this respect, and encrypted file systems can combine
integrity (as long as you encrypt-then-authenticate), but usually they
don't.

If you want policy driven integrity, authenticity, and immutability,
(and we have two IBM customers wanting them this year), then you want
the combination IMA, IMA-Appraisal, EVM, and Dmitry's digital signature
extensions.

dave

2011-05-20 13:40:23

by Serge E. Hallyn

[permalink] [raw]
Subject: Re: [PATCH v5 05/21] ima: move ima_file_free before releasing the file

Quoting Mimi Zohar ([email protected]):
> On Thu, 2011-05-19 at 17:06 -0500, Serge E. Hallyn wrote:
> > Quoting Mimi Zohar ([email protected]):
> > > Integrity appraisal measures files on file_free and stores the file
> > > measurement as an xattr. Measure the file before releasing it.
> >
> > Can you put a bit more in the commit msg about why? What's magic
> > about the fs-specific release function?
>
> ima_file_free(), called on __fput(), currently flags files that have
> changed, so that the file is re-measured. However, for appraising a
> files's integrity, flagging the file is not enough. The file's
> security.ima xattr must be updated to reflect any changes. This patch
> moves releasing the file to after calculating the new file hash.

Sorry if I'm being dense, but I still don't understand (even though
apparently I used to :) why the fs release is magic here. The
dropping of the writelock comes later, so no file will be able to
open the file for execute or write until that point, meaning that
won't be happening without a re-measure with or without this patch.

So you must be thinking something about general opens(), but I
don't believe that file_operations->release makes a difference to
another tasks's ability to open the file, nor to the writing out
of changed contents.

security_file_free() doesn't appear to be hooked by ima or evm,
and if a security module changes its security.X xattr you'll
end up re-measuring the xattrs anyway.

So I'm still missing something, sorry :)

-serge

> > > Signed-off-by: Mimi Zohar <[email protected]>
> > > Acked-by: Serge Hallyn <[email protected]>
> > > ---
> > > 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);
> > > --
>

2011-05-20 13:43:30

by Serge E. Hallyn

[permalink] [raw]
Subject: Re: [PATCH v5 03/21] evm: re-release

Quoting Mimi Zohar ([email protected]):
> On Thu, 2011-05-19 at 16:37 -0500, Serge E. Hallyn wrote:
> > Quoting Mimi Zohar ([email protected]):
> > ...
> > > +extern int evm_hmac_size;
> > ...
> > > +int evm_hmac_size = SHA1_DIGEST_SIZE;
> >
> > I think I object to having both MAX_DIGEST_SIZE and evm_hmac_size, both
> > of which are set to SHA1_DIGEST_SIZE throughout this patchset. Especially
> > because of the comment I was about to make on patch 4/21, where you
> > then prepend the hmac with a 'type' byte, and start passing around
> > MAX_DIGEST_SIZE+1 and evm_hmac_size+1.
> >
> > Even if you're going to be using those differently in a later patchset,
> > let's focus on this set for now and keep things simpler. One constant
> > for the hmac size, and then please define a new one (in patch 4) for
> > the annotated digest size. I can't think think of a good name. Which
> > suggests that perhaps you should define a nicely typed struct to contain
> > the header+hmac...
> >
> > I see no other problems, so presuming that these are nicely addressed
> > I expect to happily ack.
> >
> > thanks,
> > -serge
>
> Ok, MAX_DIGEST_SIZE was defined in the first patch of this patchset,
> which moves the iint from IMA to integrity, but it seems to be
> unnecessary for any of the additional EVM or IMA extensions, including
> support for additional IMA hash sizes. I'll remove MAX_DIGEST_SIZE.
>
> The reason for introducing the extra byte at this point in the patch

Right, just to be clear, I had no complaints about introducing the extra
byte now.

> set, as opposed to waiting to do so in the digital signature patches, is
> to permit existing labeled systems to continue to run properly (and be
> bisect safe). Defining a structure is a good idea.
>
> thanks,
>
> Mimi

Sorry to be adding work. I just fear misinterpretations of the +1 will
cause hard to debug maintenance snafus.

thanks,
-serge

2011-05-20 14:13:45

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On 5/19/2011 5:51 PM, James Morris wrote:
> On Wed, 18 May 2011, Mimi Zohar wrote:
>
>>> Once we have a better understanding of what the feature does and why it
>>> does it and how it interfaces with the user, we can start looking at
>>> the implementation.
>> Much appreciated!
> What is the status of potential users of the feature?
>
> I recall that MeeGo were planning to use EVM, but they've since changed
> their security plans. Do they still plan to use it?

It's something we'll be discussing at the MeeGo conference in San Francisco
next week.


> Are any other users
> committing to use EVM?
>
> Also -- this was raised some time back, but I can't find the discussion --
> what does IMA/EVM provide over disk encryption as a protection against
> offline attacks?
>
> - James

2011-05-20 14:35:56

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 05/21] ima: move ima_file_free before releasing the file

On Fri, 2011-05-20 at 08:40 -0500, Serge E. Hallyn wrote:
> Quoting Mimi Zohar ([email protected]):
> > On Thu, 2011-05-19 at 17:06 -0500, Serge E. Hallyn wrote:
> > > Quoting Mimi Zohar ([email protected]):
> > > > Integrity appraisal measures files on file_free and stores the file
> > > > measurement as an xattr. Measure the file before releasing it.
> > >
> > > Can you put a bit more in the commit msg about why? What's magic
> > > about the fs-specific release function?
> >
> > ima_file_free(), called on __fput(), currently flags files that have
> > changed, so that the file is re-measured. However, for appraising a
> > files's integrity, flagging the file is not enough. The file's
> > security.ima xattr must be updated to reflect any changes. This patch
> > moves releasing the file to after calculating the new file hash.
>
> Sorry if I'm being dense, but I still don't understand (even though
> apparently I used to :) why the fs release is magic here. The
> dropping of the writelock comes later, so no file will be able to
> open the file for execute or write until that point, meaning that
> won't be happening without a re-measure with or without this patch.
>
> So you must be thinking something about general opens(), but I
> don't believe that file_operations->release makes a difference to
> another tasks's ability to open the file, nor to the writing out
> of changed contents.
>
> security_file_free() doesn't appear to be hooked by ima or evm,
> and if a security module changes its security.X xattr you'll
> end up re-measuring the xattrs anyway.
>
> So I'm still missing something, sorry :)
>
> -serge

No, my mistake. IMA-appraisal, not EVM, needs to be able to read the
file in order to re-calculate the hash and update the 'security.ima'
extended attribute. Will move this patch to the IMA patchset.

thanks,

Mimi

> > > > Signed-off-by: Mimi Zohar <[email protected]>
> > > > Acked-by: Serge Hallyn <[email protected]>
> > > > ---
> > > > 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);
> > > > --
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2011-05-20 15:25:57

by Serge E. Hallyn

[permalink] [raw]
Subject: Re: [PATCH v5 05/21] ima: move ima_file_free before releasing the file

Quoting Mimi Zohar ([email protected]):
> On Fri, 2011-05-20 at 08:40 -0500, Serge E. Hallyn wrote:
> > Quoting Mimi Zohar ([email protected]):
> > > On Thu, 2011-05-19 at 17:06 -0500, Serge E. Hallyn wrote:
> > > > Quoting Mimi Zohar ([email protected]):
> > > > > Integrity appraisal measures files on file_free and stores the file
> > > > > measurement as an xattr. Measure the file before releasing it.
> > > >
> > > > Can you put a bit more in the commit msg about why? What's magic
> > > > about the fs-specific release function?
> > >
> > > ima_file_free(), called on __fput(), currently flags files that have
> > > changed, so that the file is re-measured. However, for appraising a
> > > files's integrity, flagging the file is not enough. The file's
> > > security.ima xattr must be updated to reflect any changes. This patch
> > > moves releasing the file to after calculating the new file hash.
> >
> > Sorry if I'm being dense, but I still don't understand (even though
> > apparently I used to :) why the fs release is magic here. The
> > dropping of the writelock comes later, so no file will be able to
> > open the file for execute or write until that point, meaning that
> > won't be happening without a re-measure with or without this patch.
> >
> > So you must be thinking something about general opens(), but I
> > don't believe that file_operations->release makes a difference to
> > another tasks's ability to open the file, nor to the writing out
> > of changed contents.
> >
> > security_file_free() doesn't appear to be hooked by ima or evm,
> > and if a security module changes its security.X xattr you'll
> > end up re-measuring the xattrs anyway.
> >
> > So I'm still missing something, sorry :)
> >
> > -serge
>
> No, my mistake. IMA-appraisal, not EVM, needs to be able to read the
> file in order to re-calculate the hash and update the 'security.ima'
> extended attribute. Will move this patch to the IMA patchset.

Gotcha, thanks. Please do keep my ack on it :)

-serge

2011-05-20 18:50:37

by Serge E. Hallyn

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

Hi Mimi,

just fyi I think I'm done with the patches where my reviews might be
useful. I'll give them another look-over when you repost. You said
something about ltp testcases - please let me know if you'd like any
help, otherwise if they're not yet upstream when you repost, please
point me to them, and i'll build a test kernel and exercise it
somewhere.

thanks,
-serge

2011-05-23 22:09:25

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On Fri, 2011-05-20 at 13:50 -0500, Serge E. Hallyn wrote:
> Hi Mimi,
>
> just fyi I think I'm done with the patches where my reviews might be
> useful. I'll give them another look-over when you repost. You said
> something about ltp testcases - please let me know if you'd like any
> help, otherwise if they're not yet upstream when you repost, please
> point me to them, and i'll build a test kernel and exercise it
> somewhere.
>
> thanks,
> -serge

Thanks so much Serge for all the reviews! In terms of the EVM ltp
testcases, I have some tests, but they make a number of assumptions,
like having an EVM key and a fully labeled system. After re-posting,
I'll take a look into creating a set of EVM testcases, which don't
require a fully labeled system.

thanks,

Mimi

2011-05-26 06:08:56

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

xcOn Wed 2011-05-18 17:25:52, Andrew Morton wrote:
> On Mon, 16 May 2011 10:44:54 -0400
> Mimi Zohar <[email protected]> wrote:
>
> > 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
...
> Thirdly, I'm not seeing a description of the user interface anywhere.
> Please fully describe it in a manner which can be efficiently reviewed.
> For example, if there are any user-provided inputs, describe them. If

Fourthly, is it likely to find its way to the next cellphone I buy,
and will it prevent me from rooting it?
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2011-05-26 16:34:14

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On 5/25/2011 11:08 PM, Pavel Machek wrote:
> ...
> Fourthly, is it likely to find its way to the next cellphone I buy,
> and will it prevent me from rooting it?
> Pavel

That will of course depend on the phone vendor. You are certainly
going to be able to vote with your checkbook (digital wallet?) but
odds are pretty good that should EVM prove effective it will be
ubiquitous within the next five years on embedded devices.

2011-05-26 18:12:12

by David Safford

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On Thu, 2011-05-26 at 09:34 -0700, Casey Schaufler wrote:
> On 5/25/2011 11:08 PM, Pavel Machek wrote:
> > ...
> > Fourthly, is it likely to find its way to the next cellphone I buy,
> > and will it prevent me from rooting it?
> > Pavel
>
> That will of course depend on the phone vendor. You are certainly
> going to be able to vote with your checkbook (digital wallet?) but
> odds are pretty good that should EVM prove effective it will be
> ubiquitous within the next five years on embedded devices.

um, not quite the right threat model...

Rooting is normally done through an exploit of the loader
or the kernel, neither of which EVM can prevent. The phones
which have blocked rooting in hardware have done so by adding
and enforcing digital signatures on the boot images, which is
entirely orthogonal to EVM.

Whether or not the phone is rooted, IMA-Appraisal, EVM, and
the Digital Signature Extensions help protect against remote
software attacks, and offline hardware attacks on individual
files, but not against rooting itself.

dave
(happy owner of a rooted Droid)

2011-05-26 18:39:08

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On Thu 2011-05-26 14:11:54, David Safford wrote:
> On Thu, 2011-05-26 at 09:34 -0700, Casey Schaufler wrote:
> > On 5/25/2011 11:08 PM, Pavel Machek wrote:
> > > ...
> > > Fourthly, is it likely to find its way to the next cellphone I buy,
> > > and will it prevent me from rooting it?
> >
> > That will of course depend on the phone vendor. You are certainly
> > going to be able to vote with your checkbook (digital wallet?) but
> > odds are pretty good that should EVM prove effective it will be
> > ubiquitous within the next five years on embedded devices.

Hmm. But maybe it is more effective to vote with NAKs, now? It does
not seem to have any non-evil uses.

Phone vendors will play nasty tricks on us, but... why make it easy
for them?

> um, not quite the right threat model...
>
> Rooting is normally done through an exploit of the loader
> or the kernel, neither of which EVM can prevent. The phones

Androids are often rooted by exploiting kernel or userspace
security holes. G1 was rooted by shell that was left running on
console...

> Whether or not the phone is rooted, IMA-Appraisal, EVM, and
> the Digital Signature Extensions help protect against remote
> software attacks, and offline hardware attacks on individual
> files, but not against rooting itself.

As far as I can tell, file signatures only prevent "offline hardware
attacks"; that is user trying to "attack" (== root) his own computer.

Pavel

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2011-05-26 19:30:14

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On 5/26/2011 11:38 AM, Pavel Machek wrote:
> On Thu 2011-05-26 14:11:54, David Safford wrote:
>> On Thu, 2011-05-26 at 09:34 -0700, Casey Schaufler wrote:
>>> On 5/25/2011 11:08 PM, Pavel Machek wrote:
>>>> ...
>>>> Fourthly, is it likely to find its way to the next cellphone I buy,
>>>> and will it prevent me from rooting it?
>>> That will of course depend on the phone vendor. You are certainly
>>> going to be able to vote with your checkbook (digital wallet?) but
>>> odds are pretty good that should EVM prove effective it will be
>>> ubiquitous within the next five years on embedded devices.
> Hmm. But maybe it is more effective to vote with NAKs, now? It does
> not seem to have any non-evil uses.
>
> Phone vendors will play nasty tricks on us, but... why make it easy
> for them?

For one thing, it is probable that in the not-too-distant future
the phone will not be yours. Many service providers are moving in
the direction of zero-cost phones. The subscriber will pay the
monthly charge and the phone (smart or dumb) will be included in
the package. The difference between that and what is available
today will be a teeny tiny paragraph in the contract that says
that the free phone remains the property of the service provider.
Most people will not notice the difference. Consider this a
nasty trick if you want to. I expect that the average consumer
will love it because they will be spending 5 dollars/euros/pounds
a month less. Service providers will love it because the upgrade
and control choice will be theirs.

There is nothing evil about maintaining the owner's control over
the device. The fact that the device is in a user's hand does
not transfer ownership to the user.

Welcome to computers in the 21st century.

2011-05-26 19:49:21

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On Thu, 2011-05-26 at 20:38 +0200, Pavel Machek wrote:
> On Thu 2011-05-26 14:11:54, David Safford wrote:
> > On Thu, 2011-05-26 at 09:34 -0700, Casey Schaufler wrote:
> > > On 5/25/2011 11:08 PM, Pavel Machek wrote:
> > > > ...
> > > > Fourthly, is it likely to find its way to the next cellphone I buy,
> > > > and will it prevent me from rooting it?
> > >
> > > That will of course depend on the phone vendor. You are certainly
> > > going to be able to vote with your checkbook (digital wallet?) but
> > > odds are pretty good that should EVM prove effective it will be
> > > ubiquitous within the next five years on embedded devices.
>
> Hmm. But maybe it is more effective to vote with NAKs, now? It does
> not seem to have any non-evil uses.
>
> Phone vendors will play nasty tricks on us, but... why make it easy
> for them?
>
> > um, not quite the right threat model...
> >
> > Rooting is normally done through an exploit of the loader
> > or the kernel, neither of which EVM can prevent. The phones
>
> Androids are often rooted by exploiting kernel or userspace
> security holes. G1 was rooted by shell that was left running on
> console...
>
> > Whether or not the phone is rooted, IMA-Appraisal, EVM, and
> > the Digital Signature Extensions help protect against remote
> > software attacks, and offline hardware attacks on individual
> > files, but not against rooting itself.
>
> As far as I can tell, file signatures only prevent "offline hardware
> attacks"; that is user trying to "attack" (== root) his own computer.
>
> Pavel

Since when is my being able to detect and prevent unauthorized/malicious
files on my own system (eg. device - VM) from being read/executed deemed
evil?! Are you suggesting that we're better off not knowing the
integrity or authenticity of a file? I suggest you read Dave's
Integrity Overview whitepaper?

Becoming involved in designing when/how new EVM encrypted key(s) are
made available, determining if we need separate keyrings for EVM keys
and the keys for appraising files(IMA-appraisal signatures), or defining
the authorization mechanism required to add such keys (eg. LSM, extend
capabilities), would be welcomed. Such discussions can take place on
either the LSM or linux-ima mailing lists.

thanks,

Mimi

2011-05-26 20:02:20

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On Thu 2011-05-26 12:30:07, Casey Schaufler wrote:
> On 5/26/2011 11:38 AM, Pavel Machek wrote:
> > On Thu 2011-05-26 14:11:54, David Safford wrote:
> >> On Thu, 2011-05-26 at 09:34 -0700, Casey Schaufler wrote:
> >>> On 5/25/2011 11:08 PM, Pavel Machek wrote:
> >>>> ...
> >>>> Fourthly, is it likely to find its way to the next cellphone I buy,
> >>>> and will it prevent me from rooting it?
> >>> That will of course depend on the phone vendor. You are certainly
> >>> going to be able to vote with your checkbook (digital wallet?) but
> >>> odds are pretty good that should EVM prove effective it will be
> >>> ubiquitous within the next five years on embedded devices.
> > Hmm. But maybe it is more effective to vote with NAKs, now? It does
> > not seem to have any non-evil uses.
> >
> > Phone vendors will play nasty tricks on us, but... why make it easy
> > for them?
>
> For one thing, it is probable that in the not-too-distant future
> the phone will not be yours. Many service providers are moving in
> the direction of zero-cost phones. The subscriber will pay the

Really? References?

No, I don't think this is going to happen, for variety of reasons. 1)
prepaid cards, 2) phones are easily damaged, 3) phones are often stolen.

> Most people will not notice the difference. Consider this a
> nasty trick if you want to. I expect that the average consumer

I _do_ consider it nasty trick...

> Welcome to computers in the 21st century.

...and I do not want to help people playing nasty tricks. Protection
against offline attacks should not be merged.

Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2011-05-26 20:17:36

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On Thu 2011-05-26 15:49:07, Mimi Zohar wrote:

> > > Whether or not the phone is rooted, IMA-Appraisal, EVM, and
> > > the Digital Signature Extensions help protect against remote
> > > software attacks, and offline hardware attacks on individual
> > > files, but not against rooting itself.
> >
> > As far as I can tell, file signatures only prevent "offline hardware
> > attacks"; that is user trying to "attack" (== root) his own computer.
>
> Since when is my being able to detect and prevent unauthorized/malicious
> files on my own system (eg. device - VM) from being read/executed deemed
> evil?! Are you suggesting that we're better off not knowing the

Well, unauthorized files should not get onto your system in the first
place -- and the kernel can do that already, see for example the
immutable bit. Only added bit of prevention seems to be "if someone
takes the disk out and modifies the filesystem offline".

Normally, you protect against that by not giving your disk to
strangers. (And file signatures are useless because the stranger can
replace your kernel, too).

> integrity or authenticity of a file? I suggest you read Dave's
> Integrity Overview whitepaper?

I suggest you explain the patchset in the emails, then? Everyone here
seems to be confused... Attack it protects against, and what kind of
hardware is needed for the protection to be effective?

Because AFAICT, file signatures, as proposed, are only useful for
locking down my cellphone against myself. (That's -- evil).

Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2011-05-26 20:32:36

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On 5/26/2011 1:02 PM, Pavel Machek wrote:
> On Thu 2011-05-26 12:30:07, Casey Schaufler wrote:
>> On 5/26/2011 11:38 AM, Pavel Machek wrote:
>>> On Thu 2011-05-26 14:11:54, David Safford wrote:
>>>> On Thu, 2011-05-26 at 09:34 -0700, Casey Schaufler wrote:
>>>>> On 5/25/2011 11:08 PM, Pavel Machek wrote:
>>>>>> ...
>>>>>> Fourthly, is it likely to find its way to the next cellphone I buy,
>>>>>> and will it prevent me from rooting it?
>>>>> That will of course depend on the phone vendor. You are certainly
>>>>> going to be able to vote with your checkbook (digital wallet?) but
>>>>> odds are pretty good that should EVM prove effective it will be
>>>>> ubiquitous within the next five years on embedded devices.
>>> Hmm. But maybe it is more effective to vote with NAKs, now? It does
>>> not seem to have any non-evil uses.
>>>
>>> Phone vendors will play nasty tricks on us, but... why make it easy
>>> for them?
>> For one thing, it is probable that in the not-too-distant future
>> the phone will not be yours. Many service providers are moving in
>> the direction of zero-cost phones. The subscriber will pay the
> Really? References?

Yes, and no.

> No, I don't think this is going to happen, for variety of reasons. 1)
> prepaid cards, 2) phones are easily damaged, 3) phones are often stolen.

I have no idea how prepaid cards make a difference, but I'm willing
to be educated.

Phones are commodity electronics. If they get damaged they get replaced.
That's another selling point for the scheme. Clumsy customers will love
it.

"Someone stole my SSRBQ phone!"
"Thank you sir, we'll track down our phone using the GPS software we
put on it. Now we'll use the battery overload software we just downloaded
to it to heat it up and set the magnesium case on fire. What's that sir?
your dog just exploded?"

Seriously, the service provider will download meltdown software to
the stolen phone and treat it as broken. The customer gets a new phone
to use. No worries.

>> Most people will not notice the difference. Consider this a
>> nasty trick if you want to. I expect that the average consumer
> I _do_ consider it nasty trick...

It's only "nasty" if the customer doesn't like it.
It's only a trick if the fact that the customer does not own the phone
is hidden. I fully expect the providers to tout it as a feature.

>> Welcome to computers in the 21st century.
> ...and I do not want to help people playing nasty tricks. Protection
> against offline attacks should not be merged.
>
> Pavel

OK, but what about the owners of loaned phones, set top boxes or aircraft
entertainment systems, who routinely put their hardware in the hands of
people they have no reason to trust? I suppose they can run WinCE. Or
Symbian.

2011-05-27 17:46:19

by David Safford

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On Thu, 2011-05-26 at 22:17 +0200, Pavel Machek wrote:

> I suggest you explain the patchset in the emails, then? Everyone here
> seems to be confused... Attack it protects against, and what kind of
> hardware is needed for the protection to be effective?

The white paper is over 15 pages, and it barely scratches the surface.
Every customer has different security threat models and requirements.
Discussing this in general on the mailing list is really hard.

So let's try to simplify this just down to digital signatures in
the cellphone environment, as you state:

> Because AFAICT, file signatures, as proposed, are only useful for
> locking down my cellphone against myself. (That's -- evil).

The proposed digital signatures can enforce authenticity of a file's
data (IMA-Appraisal with Digital Signature), and of a file's metadata
(EVM with Digital Signature). For most users, enforcing authenticity
of files is a good thing - a user knows that they are running authentic
software signed by their phone manufacturer, and not malicious files
that they, or someone else installed. In this threat model, EVM is
mainly authenticating the meta-data of a file (owner, mode, LSM label...).
IMA-Appraisal and EVM are policy driven, so that the owner is free to
tailor them or turn them off. There are clearly many other use cases for
digitally signed data and metadata - authenticity is an important
kernel feature, one which should be done once, done correctly, and
upstreamed.

You argue that EVM can be abused to lock down your phone against
rooting, but

1. EVM has no control over rooting through the loader, or rooting
through vulnerabilities in the kernel, or rooting through
vulnerabilities in signed applications, or rooting through
the adb shell, or rooting in any way I have seen.

2. The real issue with phones is manufacturers who try to prevent you
from running the kernel and software of your choice. Locked
bootloaders are not a technical problem - they are a market
problem that can only be addressed with market or regulatory
forces. In some countries, manufacturers are simply not allowed
to do such locking.

Blocking signature verification would serve only to punish Linux
users who care about the authenticity of their files, while doing
_nothing_ to stop manufacturers from locking their bootloaders.

dave
>
> Pavel

2011-05-29 06:58:36

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On Fri 2011-05-27 13:45:51, David Safford wrote:
> On Thu, 2011-05-26 at 22:17 +0200, Pavel Machek wrote:
>
> > I suggest you explain the patchset in the emails, then? Everyone here
> > seems to be confused... Attack it protects against, and what kind of
> > hardware is needed for the protection to be effective?
>
> The white paper is over 15 pages, and it barely scratches the surface.
> Every customer has different security threat models and requirements.
> Discussing this in general on the mailing list is really hard.
>
> So let's try to simplify this just down to digital signatures in
> the cellphone environment, as you state:

Good.

> > Because AFAICT, file signatures, as proposed, are only useful for
> > locking down my cellphone against myself. (That's -- evil).
>
> The proposed digital signatures can enforce authenticity of a file's
> data (IMA-Appraisal with Digital Signature), and of a file's metadata
> (EVM with Digital Signature). For most users, enforcing authenticity
> of files is a good thing - a user knows that they are running authentic
> software signed by their phone manufacturer, and not malicious files
> that they, or someone else installed. In this threat model, EVM is

Ok, so lets talk about smartphone, similar to my HTC Dream (developer
version, unlocked bootloader, flashable from kernel (*)).

Yes, I could install the crazy EVM/IMA infastructure to prevent
applications modifying selected files.

But... I could just do chattr +i on selected files, I do not need
fancy EVM/IMA for that.

> Blocking signature verification would serve only to punish Linux
> users who care about the authenticity of their files, while doing
> _nothing_ to stop manufacturers from locking their bootloaders.

chattr already protects authenticity of my files, as do standard unix
permissions.

So... where's the difference?

Pavel
(*) but it does not change anything.

True; determined attacker could steal my cellphone, open it up,
desolder the flash, and change attributes of the filesystem.

But... the same determined attacker can also replace
bootloader&kernel&filesystem -- that is in the same flash! -- with
unlocked versions. So the argumentation is the same for locked down
phone.

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2011-05-31 12:05:18

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On Sun, 2011-05-29 at 08:58 +0200, Pavel Machek wrote:
> On Fri 2011-05-27 13:45:51, David Safford wrote:
> > On Thu, 2011-05-26 at 22:17 +0200, Pavel Machek wrote:
> >
> > > I suggest you explain the patchset in the emails, then? Everyone here
> > > seems to be confused... Attack it protects against, and what kind of
> > > hardware is needed for the protection to be effective?
> >
> > The white paper is over 15 pages, and it barely scratches the surface.
> > Every customer has different security threat models and requirements.
> > Discussing this in general on the mailing list is really hard.
> >
> > So let's try to simplify this just down to digital signatures in
> > the cellphone environment, as you state:
>
> Good.
>
> > > Because AFAICT, file signatures, as proposed, are only useful for
> > > locking down my cellphone against myself. (That's -- evil).
> >
> > The proposed digital signatures can enforce authenticity of a file's
> > data (IMA-Appraisal with Digital Signature), and of a file's metadata
> > (EVM with Digital Signature). For most users, enforcing authenticity
> > of files is a good thing - a user knows that they are running authentic
> > software signed by their phone manufacturer, and not malicious files
> > that they, or someone else installed. In this threat model, EVM is
>
> Ok, so lets talk about smartphone, similar to my HTC Dream (developer
> version, unlocked bootloader, flashable from kernel (*)).
>
> Yes, I could install the crazy EVM/IMA infastructure to prevent
> applications modifying selected files.
>
> But... I could just do chattr +i on selected files, I do not need
> fancy EVM/IMA for that.

For files that you don't expect to change, such as ELF executables, you
probably could use the immutable flag, but using a digital signature
provides authenticity as well, which the immutable flag does not
provide.

> > Blocking signature verification would serve only to punish Linux
> > users who care about the authenticity of their files, while doing
> > _nothing_ to stop manufacturers from locking their bootloaders.
>
> chattr already protects authenticity of my files, as do standard unix
> permissions.
>
> So... where's the difference?
> Pavel

Neither digital signatures nor the immutable flag work for files that
change, such as config files. For these files, ima-appraisal would
store a file hash.

> (*) but it does not change anything.
>
> True; determined attacker could steal my cellphone, open it up,
> desolder the flash, and change attributes of the filesystem.

With EVM, assuming that i_flag is included in the EVM HMAC, which it
currently isn't, you would be able to detect the change and prevent the
file from being accessed.

>
> But... the same determined attacker can also replace
> bootloader&kernel&filesystem -- that is in the same flash! -- with
> unlocked versions. So the argumentation is the same for locked down
> phone.
>

As EVM is not involved in the boot process, it can not and does not
address this, but other technologies could.

thanks,

Mimi

2011-05-31 13:41:15

by Valdis Klētnieks

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

On Tue, 31 May 2011 08:05:08 EDT, Mimi Zohar said:

> For files that you don't expect to change, such as ELF executables, you
> probably could use the immutable flag, but using a digital signature
> provides authenticity as well, which the immutable flag does not
> provide.

The problem with 'chattr +i' is that if an attacker gets root, they can 'chattr
-i' and start scribbling. I've never personally trusted it for anything more
than protecting against overexuberant root processes that forget to obey file
permissions (like the DHCP script that keeps insisting on removing all the IPv6
nameservers out of my /etc/resolv.conf even when it's mode 444). As you noted,
digitally signing the executables with a key not found on the system raises the
bar substantially..


Attachments:
(No filename) (227.00 B)

2011-06-01 22:11:15

by Dmitry Kasatkin

[permalink] [raw]
Subject: Re: [PATCH v5 00/21] EVM

reposted in plain text..

On Sun, May 29, 2011 at 9:58 AM, Pavel Machek <[email protected]> wrote:
>
> chattr already protects authenticity of my files, as do standard unix
> permissions.
>
> So... where's the difference?
>

chattr only protects against runtime attacks.
That is Access Control feature - not integrity.

> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Pavel
> (*) but it does not change anything.
>
> True; determined attacker could steal my cellphone, open it up,
> desolder the flash, and change attributes of the filesystem.
>
> But... the same determined attacker can also replace
> bootloader&kernel&filesystem -- that is in the same flash! -- with
> unlocked versions. So the argumentation is the same for locked down
> phone.
>

That is completely incorrect in respect to locked/protected devices.
Chain of trust starts from ROM.
Bootloader is authenticated by the ROM and that will not allow to boot
the device.
Next bootloader will authenticate the kernel and display the message
on the screen
if it has been tampered.
And the next, authentic kernel will enforce filesystem integrity
protection using EVM.

The important use case is not to lock down phone against yourself,
but to protect normal users against possibility to sell/give them devices with
not authentic software which could do different nasty things, like
stealing the data or spying.