From 9d8f13ba3f4833219e50767b022b82cd0da930eb Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Mon, 6 Jun 2011 15:29:25 -0400 Subject: security: new security_inode_init_security API adds function callback This patch changes the security_inode_init_security API by adding a filesystem specific callback to write security extended attributes. This change is in preparation for supporting the initialization of multiple LSM xattrs and the EVM xattr. Initially the callback function walks an array of xattrs, writing each xattr separately, but could be optimized to write multiple xattrs at once. For existing security_inode_init_security() calls, which have not yet been converted to use the new callback function, such as those in reiserfs and ocfs2, this patch defines security_old_inode_init_security(). Signed-off-by: Mimi Zohar --- security/security.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index 4ba6d4cc061f..3464d58a5766 100644 --- a/security/security.c +++ b/security/security.c @@ -18,6 +18,8 @@ #include #include +#define MAX_LSM_XATTR 1 + /* Boot-time LSM user choice */ static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = CONFIG_DEFAULT_SECURITY; @@ -339,15 +341,46 @@ void security_inode_free(struct inode *inode) } int security_inode_init_security(struct inode *inode, struct inode *dir, - const struct qstr *qstr, char **name, - void **value, size_t *len) + const struct qstr *qstr, + const initxattrs initxattrs, void *fs_data) +{ + struct xattr new_xattrs[MAX_LSM_XATTR + 1]; + struct xattr *lsm_xattr; + int ret; + + if (unlikely(IS_PRIVATE(inode))) + return -EOPNOTSUPP; + + memset(new_xattrs, 0, sizeof new_xattrs); + if (!initxattrs) + return security_ops->inode_init_security(inode, dir, qstr, + NULL, NULL, NULL); + lsm_xattr = new_xattrs; + ret = security_ops->inode_init_security(inode, dir, qstr, + &lsm_xattr->name, + &lsm_xattr->value, + &lsm_xattr->value_len); + if (ret) + goto out; + ret = initxattrs(inode, new_xattrs, fs_data); +out: + kfree(lsm_xattr->name); + kfree(lsm_xattr->value); + + return (ret == -EOPNOTSUPP) ? 0 : ret; +} +EXPORT_SYMBOL(security_inode_init_security); + +int security_old_inode_init_security(struct inode *inode, struct inode *dir, + const struct qstr *qstr, char **name, + void **value, size_t *len) { if (unlikely(IS_PRIVATE(inode))) return -EOPNOTSUPP; return security_ops->inode_init_security(inode, dir, qstr, name, value, len); } -EXPORT_SYMBOL(security_inode_init_security); +EXPORT_SYMBOL(security_old_inode_init_security); #ifdef CONFIG_SECURITY_PATH int security_path_mknod(struct path *dir, struct dentry *dentry, int mode, -- cgit v1.2.3-59-g8ed1b From f381c272224f5f158f5cff64f8f3481fa0eee8b3 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Wed, 9 Mar 2011 14:13:22 -0500 Subject: 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: - don't define MAX_DIGEST_SIZE - rename several globally visible 'ima_' prefixed functions, structs, locks, etc to 'integrity_' - replace '20' with SHA1_DIGEST_SIZE - reflect location change in appropriate Kconfig and Makefiles - remove unnecessary initialization of iint_initialized to 0 - rebased on current ima_iint.c - define integrity_iint_store/lock as static There should be no other functional changes. Signed-off-by: Mimi Zohar Acked-by: Serge Hallyn --- 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 | 35 ++++++++ security/security.c | 3 +- 15 files changed, 277 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 (limited to 'security/security.c') diff --git a/include/linux/ima.h b/include/linux/ima.h index 09e6e62f9953..6ac8e50c6cf5 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 000000000000..905981247327 --- /dev/null +++ b/include/linux/integrity.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2009 IBM Corporation + * Author: Mimi Zohar + * + * 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 + +#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 e0f08b52e4ab..22847a889081 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 8bb0fe9e1ca9..a5e502f8a05b 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 000000000000..270469155681 --- /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 000000000000..6eddd61b84e8 --- /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 000000000000..d17de48bd6cc --- /dev/null +++ b/security/integrity/iint.c @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2008 IBM Corporation + * + * Authors: + * Mimi Zohar + * + * 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 +#include +#include +#include +#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 b6ecfd4d8d78..19c053b82303 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 787c4cb916cd..5690c021de8f 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 08408bd71462..29d97af5e9a4 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -24,11 +24,13 @@ #include #include +#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 da36d2c085a4..0d50df04ccc4 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 4ae73040ab7b..000000000000 --- a/security/integrity/ima/ima_iint.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2008 IBM Corporation - * - * Authors: - * Mimi Zohar - * - * 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 -#include -#include -#include -#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 39d66dc2b8e9..25f9fe762896 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 000000000000..7351836325a8 --- /dev/null +++ b/security/integrity/integrity.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009-2010 IBM Corporation + * + * Authors: + * Mimi Zohar + * + * 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 +#include +#include + +/* 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[SHA1_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 3464d58a5766..947fdcfbc83e 100644 --- a/security/security.c +++ b/security/security.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #define MAX_LSM_XATTR 1 @@ -336,7 +337,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); } -- cgit v1.2.3-59-g8ed1b From 3e1be52d6c6b21d9080dd886c0e609e009831562 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Wed, 9 Mar 2011 14:38:26 -0500 Subject: 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 Acked-by: Serge Hallyn --- 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 (limited to 'security/security.c') diff --git a/include/linux/evm.h b/include/linux/evm.h new file mode 100644 index 000000000000..8b4e9e3b395e --- /dev/null +++ b/include/linux/evm.h @@ -0,0 +1,56 @@ +/* + * evm.h + * + * Copyright (c) 2009 IBM Corporation + * Author: Mimi Zohar + */ + +#ifndef _LINUX_EVM_H +#define _LINUX_EVM_H + +#include + +#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 c0580dd15ec0..1746c3669c6f 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "evm.h" int evm_initialized; diff --git a/security/security.c b/security/security.c index 947fdcfbc83e..21a79b3d1e8e 100644 --- a/security/security.c +++ b/security/security.c @@ -18,6 +18,7 @@ #include #include #include +#include #define MAX_LSM_XATTR 1 @@ -580,9 +581,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, @@ -591,6 +597,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) @@ -609,9 +616,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) -- cgit v1.2.3-59-g8ed1b From 823eb1ccd0b310449e99c822412ea8208334d14c Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Wed, 15 Jun 2011 21:19:10 -0400 Subject: evm: call evm_inode_init_security from security_inode_init_security Changelog v7: - moved the initialization call to security_inode_init_security, renaming evm_inode_post_init_security to evm_inode_init_security - increase size of xattr array for EVM xattr Signed-off-by: Mimi Zohar --- security/security.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index 21a79b3d1e8e..181990ae90c1 100644 --- a/security/security.c +++ b/security/security.c @@ -20,7 +20,7 @@ #include #include -#define MAX_LSM_XATTR 1 +#define MAX_LSM_EVM_XATTR 2 /* Boot-time LSM user choice */ static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = @@ -346,8 +346,8 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, const initxattrs initxattrs, void *fs_data) { - struct xattr new_xattrs[MAX_LSM_XATTR + 1]; - struct xattr *lsm_xattr; + struct xattr new_xattrs[MAX_LSM_EVM_XATTR + 1]; + struct xattr *lsm_xattr, *evm_xattr, *xattr; int ret; if (unlikely(IS_PRIVATE(inode))) @@ -364,11 +364,17 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, &lsm_xattr->value_len); if (ret) goto out; + + evm_xattr = lsm_xattr + 1; + ret = evm_inode_init_security(inode, lsm_xattr, evm_xattr); + if (ret) + goto out; ret = initxattrs(inode, new_xattrs, fs_data); out: - kfree(lsm_xattr->name); - kfree(lsm_xattr->value); - + for (xattr = new_xattrs; xattr->name != NULL; xattr++) { + kfree(xattr->name); + kfree(xattr->value); + } return (ret == -EOPNOTSUPP) ? 0 : ret; } EXPORT_SYMBOL(security_inode_init_security); -- cgit v1.2.3-59-g8ed1b From 817b54aa45db03437c6d09a7693fc6926eb8e822 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Fri, 13 May 2011 12:53:38 -0400 Subject: 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 Signed-off-by: Mimi Zohar --- include/linux/evm.h | 6 ++++++ security/integrity/evm/evm_main.c | 15 +++++++++++++++ security/security.c | 7 ++++++- 3 files changed, 27 insertions(+), 1 deletion(-) (limited to 'security/security.c') diff --git a/include/linux/evm.h b/include/linux/evm.h index 6d4e89b020c5..db5556dcdd27 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 94d66af07aa4..8fc5b5d7ceaa 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -277,6 +277,21 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name) return; } +/** + * 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 diff --git a/security/security.c b/security/security.c index 181990ae90c1..19251ccb2de0 100644 --- a/security/security.c +++ b/security/security.c @@ -571,9 +571,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); -- cgit v1.2.3-59-g8ed1b