From 8607c501478432b23654739c7321bc7456053cb6 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Wed, 5 Oct 2011 11:54:46 +0300 Subject: integrity: digital signature verification using multiple keyrings Define separate keyrings for each of the different use cases - evm, ima, and modules. Using different keyrings improves search performance, and also allows "locking" specific keyring to prevent adding new keys. This is useful for evm and module keyrings, when keys are usually only added from initramfs. Signed-off-by: Dmitry Kasatkin --- security/integrity/Kconfig | 14 ++++++++++++ security/integrity/Makefile | 1 + security/integrity/digsig.c | 48 ++++++++++++++++++++++++++++++++++++++++++ security/integrity/integrity.h | 21 ++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 security/integrity/digsig.c (limited to 'security') diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig index 4bf00acf7937..d87fa2a8fa3b 100644 --- a/security/integrity/Kconfig +++ b/security/integrity/Kconfig @@ -3,5 +3,19 @@ config INTEGRITY def_bool y depends on IMA || EVM +config INTEGRITY_DIGSIG + boolean "Digital signature verification using multiple keyrings" + depends on INTEGRITY + default n + select DIGSIG + help + This option enables digital signature verification support + using multiple keyrings. It defines separate keyrings for each + of the different use cases - evm, ima, and modules. + Different keyrings improves search performance, but also allow + to "lock" certain keyring to prevent adding new keys. + This is useful for evm and module keyrings, when keys are + usually only added from initramfs. + source security/integrity/ima/Kconfig source security/integrity/evm/Kconfig diff --git a/security/integrity/Makefile b/security/integrity/Makefile index 0ae44aea6516..bece0563ee5e 100644 --- a/security/integrity/Makefile +++ b/security/integrity/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_INTEGRITY) += integrity.o +obj-$(CONFIG_INTEGRITY_DIGSIG) += digsig.o integrity-y := iint.o diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c new file mode 100644 index 000000000000..2dc167d7cde9 --- /dev/null +++ b/security/integrity/digsig.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2011 Intel Corporation + * + * Author: + * Dmitry Kasatkin + * + * 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. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include + +#include "integrity.h" + +static struct key *keyring[INTEGRITY_KEYRING_MAX]; + +static const char *keyring_name[INTEGRITY_KEYRING_MAX] = { + "_evm", + "_module", + "_ima", +}; + +int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, + const char *digest, int digestlen) +{ + if (id >= INTEGRITY_KEYRING_MAX) + return -EINVAL; + + if (!keyring[id]) { + keyring[id] = + request_key(&key_type_keyring, keyring_name[id], NULL); + if (IS_ERR(keyring[id])) { + int err = PTR_ERR(keyring[id]); + pr_err("no %s keyring: %d\n", keyring_name[id], err); + keyring[id] = NULL; + return err; + } + } + + return digsig_verify(keyring[id], sig, siglen, digest, digestlen); +} diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 3143a3c39868..4da6ba81d153 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -46,5 +46,26 @@ struct integrity_iint_cache { struct integrity_iint_cache *integrity_iint_insert(struct inode *inode); struct integrity_iint_cache *integrity_iint_find(struct inode *inode); +#define INTEGRITY_KEYRING_EVM 0 +#define INTEGRITY_KEYRING_MODULE 1 +#define INTEGRITY_KEYRING_IMA 2 +#define INTEGRITY_KEYRING_MAX 3 + +#ifdef CONFIG_INTEGRITY_DIGSIG + +int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, + const char *digest, int digestlen); + +#else + +static inline int integrity_digsig_verify(const unsigned int id, + const char *sig, int siglen, + const char *digest, int digestlen) +{ + return -EOPNOTSUPP; +} + +#endif /* CONFIG_INTEGRITY_DIGSIG */ + /* set during initialization */ extern int iint_initialized; -- cgit v1.2.3 From 15647eb3985ef30dfd657038924dc85c03026733 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Thu, 1 Sep 2011 14:41:40 +0300 Subject: evm: digital signature verification support This patch adds support for digital signature verification to EVM. With this feature file metadata can be protected using digital signature instead of an HMAC. When building an image, which has to be flashed to different devices, an HMAC cannot be used to sign file metadata, because the HMAC key should be different on every device. Signed-off-by: Dmitry Kasatkin Acked-by: Mimi Zohar --- security/integrity/evm/evm.h | 12 +++++ security/integrity/evm/evm_crypto.c | 66 +++++++++++++++++++------- security/integrity/evm/evm_main.c | 94 ++++++++++++++++++++++++++++++++----- 3 files changed, 142 insertions(+), 30 deletions(-) (limited to 'security') diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index d320f5197437..c885247ebcf7 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h @@ -12,14 +12,21 @@ * File: evm.h * */ + +#ifndef __INTEGRITY_EVM_H +#define __INTEGRITY_EVM_H + #include #include + #include "../integrity.h" extern int evm_initialized; extern char *evm_hmac; +extern char *evm_hash; extern struct crypto_shash *hmac_tfm; +extern struct crypto_shash *hash_tfm; /* List of EVM protected security xattrs */ extern char *evm_config_xattrnames[]; @@ -32,7 +39,12 @@ 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_calc_hash(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); + +#endif diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 5dd5b140242c..847a2d7dff17 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -26,34 +26,48 @@ static unsigned char evmkey[MAX_KEY_SIZE]; static int evmkey_len = MAX_KEY_SIZE; struct crypto_shash *hmac_tfm; +struct crypto_shash *hash_tfm; -static struct shash_desc *init_desc(void) +static struct shash_desc *init_desc(const char type) { int rc; + char *algo; + struct crypto_shash **tfm; struct shash_desc *desc; - if (hmac_tfm == NULL) { - hmac_tfm = crypto_alloc_shash(evm_hmac, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(hmac_tfm)) { + if (type == EVM_XATTR_HMAC) { + tfm = &hmac_tfm; + algo = evm_hmac; + } else { + tfm = &hash_tfm; + algo = evm_hash; + } + + if (*tfm == NULL) { + *tfm = crypto_alloc_shash(algo, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(*tfm)) { pr_err("Can not allocate %s (reason: %ld)\n", - evm_hmac, PTR_ERR(hmac_tfm)); - rc = PTR_ERR(hmac_tfm); - hmac_tfm = NULL; + algo, PTR_ERR(*tfm)); + rc = PTR_ERR(*tfm); + *tfm = NULL; return ERR_PTR(rc); } } - desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(hmac_tfm), + desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(*tfm), GFP_KERNEL); if (!desc) return ERR_PTR(-ENOMEM); - desc->tfm = hmac_tfm; + desc->tfm = *tfm; desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; - rc = crypto_shash_setkey(hmac_tfm, evmkey, evmkey_len); - if (rc) - goto out; + if (type == EVM_XATTR_HMAC) { + rc = crypto_shash_setkey(*tfm, evmkey, evmkey_len); + if (rc) + goto out; + } + rc = crypto_shash_init(desc); out: if (rc) { @@ -97,9 +111,11 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, * 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) +static int evm_calc_hmac_or_hash(struct dentry *dentry, + const char *req_xattr_name, + const char *req_xattr_value, + size_t req_xattr_value_len, + char type, char *digest) { struct inode *inode = dentry->d_inode; struct shash_desc *desc; @@ -111,7 +127,7 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name, if (!inode->i_op || !inode->i_op->getxattr) return -EOPNOTSUPP; - desc = init_desc(); + desc = init_desc(type); if (IS_ERR(desc)) return PTR_ERR(desc); @@ -145,6 +161,22 @@ out: return error; } +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) +{ + return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value, + req_xattr_value_len, EVM_XATTR_HMAC, digest); +} + +int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name, + const char *req_xattr_value, size_t req_xattr_value_len, + char *digest) +{ + return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value, + req_xattr_value_len, IMA_XATTR_DIGEST, digest); +} + /* * Calculate the hmac and update security.evm xattr * @@ -175,7 +207,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr, { struct shash_desc *desc; - desc = init_desc(); + desc = init_desc(EVM_XATTR_HMAC); if (IS_ERR(desc)) { printk(KERN_INFO "init_desc failed\n"); return PTR_ERR(desc); diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 92d3d99a9f7b..8901501425f4 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -25,6 +25,7 @@ int evm_initialized; char *evm_hmac = "hmac(sha1)"; +char *evm_hash = "sha1"; char *evm_config_xattrnames[] = { #ifdef CONFIG_SECURITY_SELINUX @@ -46,6 +47,29 @@ static int __init evm_set_fixmode(char *str) } __setup("evm=", evm_set_fixmode); +static int evm_find_protected_xattrs(struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + char **xattr; + int error; + int count = 0; + + if (!inode->i_op || !inode->i_op->getxattr) + return -EOPNOTSUPP; + + for (xattr = evm_config_xattrnames; *xattr != NULL; xattr++) { + error = inode->i_op->getxattr(dentry, *xattr, NULL, 0); + if (error < 0) { + if (error == -ENODATA) + continue; + return error; + } + count++; + } + + return count; +} + /* * evm_verify_hmac - calculate and compare the HMAC with the EVM xattr * @@ -65,32 +89,72 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, size_t xattr_value_len, struct integrity_iint_cache *iint) { - struct evm_ima_xattr_data xattr_data; + struct evm_ima_xattr_data *xattr_data = NULL; + struct evm_ima_xattr_data calc; enum integrity_status evm_status = INTEGRITY_PASS; - int rc; + int rc, xattr_len; if (iint && iint->evm_status == INTEGRITY_PASS) return iint->evm_status; /* if status is not PASS, try to check again - against -ENOMEM */ - rc = evm_calc_hmac(dentry, xattr_name, xattr_value, - xattr_value_len, xattr_data.digest); - if (rc < 0) { - evm_status = (rc == -ENODATA) - ? INTEGRITY_NOXATTRS : INTEGRITY_FAIL; + /* first need to know the sig type */ + rc = vfs_getxattr_alloc(dentry, XATTR_NAME_EVM, (char **)&xattr_data, 0, + GFP_NOFS); + if (rc <= 0) { + if (rc == 0) + evm_status = INTEGRITY_FAIL; /* empty */ + else if (rc == -ENODATA) { + rc = evm_find_protected_xattrs(dentry); + if (rc > 0) + evm_status = INTEGRITY_NOLABEL; + else if (rc == 0) + evm_status = INTEGRITY_NOXATTRS; /* new file */ + } goto out; } - xattr_data.type = EVM_XATTR_HMAC; - rc = vfs_xattr_cmp(dentry, XATTR_NAME_EVM, (u8 *)&xattr_data, - sizeof xattr_data, GFP_NOFS); - if (rc < 0) - evm_status = (rc == -ENODATA) - ? INTEGRITY_NOLABEL : INTEGRITY_FAIL; + xattr_len = rc - 1; + + /* check value type */ + switch (xattr_data->type) { + case EVM_XATTR_HMAC: + rc = evm_calc_hmac(dentry, xattr_name, xattr_value, + xattr_value_len, calc.digest); + if (rc) + break; + rc = memcmp(xattr_data->digest, calc.digest, + sizeof(calc.digest)); + if (rc) + rc = -EINVAL; + break; + case EVM_IMA_XATTR_DIGSIG: + rc = evm_calc_hash(dentry, xattr_name, xattr_value, + xattr_value_len, calc.digest); + if (rc) + break; + rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM, + xattr_data->digest, xattr_len, + calc.digest, sizeof(calc.digest)); + if (!rc) { + /* we probably want to replace rsa with hmac here */ + evm_update_evmxattr(dentry, xattr_name, xattr_value, + xattr_value_len); + } + break; + default: + rc = -EINVAL; + break; + } + + if (rc) + evm_status = (rc == -ENODATA) ? + INTEGRITY_NOXATTRS : INTEGRITY_FAIL; out: if (iint) iint->evm_status = evm_status; + kfree(xattr_data); return evm_status; } @@ -354,6 +418,8 @@ static int __init init_evm(void) printk(KERN_INFO "EVM: Error registering secfs\n"); goto err; } + + return 0; err: return error; } @@ -363,6 +429,8 @@ static void __exit cleanup_evm(void) evm_cleanup_secfs(); if (hmac_tfm) crypto_free_shash(hmac_tfm); + if (hash_tfm) + crypto_free_shash(hash_tfm); } /* -- cgit v1.2.3 From af7ff2c2c45e6c6d533dd968709732da3d1d48f8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 15 Nov 2011 15:11:41 -0800 Subject: selinuxfs: remove custom hex_to_bin() Signed-off-by: Andy Shevchenko Cc: Eric Paris Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: James Morris --- security/selinux/selinuxfs.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'security') diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index f46658722c78..48a7d0014b4f 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -749,14 +749,6 @@ out: return length; } -static inline int hexcode_to_int(int code) { - if (code == '\0' || !isxdigit(code)) - return -1; - if (isdigit(code)) - return code - '0'; - return tolower(code) - 'a' + 10; -} - static ssize_t sel_write_create(struct file *file, char *buf, size_t size) { char *scon = NULL, *tcon = NULL; @@ -808,9 +800,11 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) if (c1 == '+') c1 = ' '; else if (c1 == '%') { - if ((c1 = hexcode_to_int(*r++)) < 0) + c1 = hex_to_bin(*r++); + if (c1 < 0) goto out; - if ((c2 = hexcode_to_int(*r++)) < 0) + c2 = hex_to_bin(*r++); + if (c2 < 0) goto out; c1 = (c1 << 4) | c2; } -- cgit v1.2.3 From 7845bc3964756240863ae453ffe4f7ee27ddc954 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 16 Nov 2011 11:15:54 +0000 Subject: KEYS: Give key types their own lockdep class for key->sem Give keys their own lockdep class to differentiate them from each other in case a key of one type has to refer to a key of another type. Signed-off-by: David Howells Acked-by: Mimi Zohar Signed-off-by: James Morris --- include/linux/key-type.h | 1 + security/keys/key.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'security') diff --git a/include/linux/key-type.h b/include/linux/key-type.h index 9efd081bb31e..39e3c082c49d 100644 --- a/include/linux/key-type.h +++ b/include/linux/key-type.h @@ -92,6 +92,7 @@ struct key_type { /* internal fields */ struct list_head link; /* link in types list */ + struct lock_class_key lock_class; /* key->sem lock class */ }; extern struct key_type key_type_keyring; diff --git a/security/keys/key.c b/security/keys/key.c index 4414abddcb5b..4f64c7267afb 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -291,6 +291,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, atomic_set(&key->usage, 1); init_rwsem(&key->sem); + lockdep_set_class(&key->sem, &type->lock_class); key->type = type; key->user = user; key->quotalen = quotalen; @@ -946,6 +947,8 @@ int register_key_type(struct key_type *ktype) struct key_type *p; int ret; + memset(&ktype->lock_class, 0, sizeof(ktype->lock_class)); + ret = -EEXIST; down_write(&key_types_sem); -- cgit v1.2.3 From de353533753e048b5c4658f0a42365937527ac45 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Mon, 21 Nov 2011 17:31:15 +0200 Subject: digsig: build dependency fix Fix build errors by adding Kconfig dependency on KEYS. CRYPTO dependency removed. CC security/integrity/digsig.o security/integrity/digsig.c: In function ?integrity_digsig_verify?: security/integrity/digsig.c:38:4: error: implicit declaration of function ?request_key? security/integrity/digsig.c:38:17: error: ?key_type_keyring? undeclared (first use in this function) security/integrity/digsig.c:38:17: note: each undeclared identifier is reported only once for each function it appears in make[2]: *** [security/integrity/digsig.o] Error 1 Reported-by: Randy Dunlap Signed-off-by: Dmitry Kasatkin Signed-off-by: James Morris --- lib/Kconfig | 2 +- security/integrity/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'security') diff --git a/lib/Kconfig b/lib/Kconfig index c1a89185fe6b..5634e473ff6d 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -295,7 +295,7 @@ config MPILIB_EXTRA config DIGSIG tristate "In-kernel signature checker" - depends on CRYPTO + depends on KEYS select MPILIB help Digital signature verification. Currently only RSA is supported. diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig index d87fa2a8fa3b..d384ea921482 100644 --- a/security/integrity/Kconfig +++ b/security/integrity/Kconfig @@ -5,7 +5,7 @@ config INTEGRITY config INTEGRITY_DIGSIG boolean "Digital signature verification using multiple keyrings" - depends on INTEGRITY + depends on INTEGRITY && KEYS default n select DIGSIG help -- cgit v1.2.3 From 88d7ed35085184f15a2af3d9e88d775059b2f307 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Mon, 5 Dec 2011 13:17:41 +0200 Subject: evm: key must be set once during initialization On multi-core systems, setting of the key before every caclculation, causes invalid HMAC calculation for other tfm users, because internal state (ipad, opad) can be invalid before set key call returns. It needs to be set only once during initialization. Signed-off-by: Dmitry Kasatkin Acked-by: Mimi Zohar Signed-off-by: James Morris --- security/integrity/evm/evm_crypto.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'security') diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 847a2d7dff17..3b9f5a080e4f 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -52,6 +52,14 @@ static struct shash_desc *init_desc(const char type) *tfm = NULL; return ERR_PTR(rc); } + if (type == EVM_XATTR_HMAC) { + rc = crypto_shash_setkey(*tfm, evmkey, evmkey_len); + if (rc) { + crypto_free_shash(*tfm); + *tfm = NULL; + return ERR_PTR(rc); + } + } } desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(*tfm), @@ -62,14 +70,7 @@ static struct shash_desc *init_desc(const char type) desc->tfm = *tfm; desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; - if (type == EVM_XATTR_HMAC) { - rc = crypto_shash_setkey(*tfm, evmkey, evmkey_len); - if (rc) - goto out; - } - rc = crypto_shash_init(desc); -out: if (rc) { kfree(desc); return ERR_PTR(rc); -- cgit v1.2.3 From 143b01d33221e4937d3930e6bb2b63d70b7c7a65 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Mon, 5 Dec 2011 13:17:42 +0200 Subject: evm: prevent racing during tfm allocation There is a small chance of racing during tfm allocation. This patch fixes it. Signed-off-by: Dmitry Kasatkin Acked-by: Mimi Zohar Signed-off-by: James Morris --- security/integrity/evm/evm_crypto.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'security') diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 3b9f5a080e4f..f1d4ad0cea2c 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -28,9 +28,11 @@ static int evmkey_len = MAX_KEY_SIZE; struct crypto_shash *hmac_tfm; struct crypto_shash *hash_tfm; +static DEFINE_MUTEX(mutex); + static struct shash_desc *init_desc(const char type) { - int rc; + long rc; char *algo; struct crypto_shash **tfm; struct shash_desc *desc; @@ -44,12 +46,15 @@ static struct shash_desc *init_desc(const char type) } if (*tfm == NULL) { + mutex_lock(&mutex); + if (*tfm) + goto out; *tfm = crypto_alloc_shash(algo, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(*tfm)) { - pr_err("Can not allocate %s (reason: %ld)\n", - algo, PTR_ERR(*tfm)); rc = PTR_ERR(*tfm); + pr_err("Can not allocate %s (reason: %ld)\n", algo, rc); *tfm = NULL; + mutex_unlock(&mutex); return ERR_PTR(rc); } if (type == EVM_XATTR_HMAC) { @@ -57,9 +62,12 @@ static struct shash_desc *init_desc(const char type) if (rc) { crypto_free_shash(*tfm); *tfm = NULL; + mutex_unlock(&mutex); return ERR_PTR(rc); } } +out: + mutex_unlock(&mutex); } desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(*tfm), -- cgit v1.2.3 From 2053c4727c5a891bf182397e425b6cb87b2ae613 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 8 Dec 2011 16:25:48 -0800 Subject: apparmor: add missing rcu_dereference() Adds a missed rcu_dereference() around real_parent. Signed-off-by: Kees Cook Acked-by: John Johansen Signed-off-by: James Morris --- security/apparmor/audit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security') diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index 96502b22b268..f3fafedd798a 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -133,7 +133,7 @@ static void audit_pre(struct audit_buffer *ab, void *ca) struct aa_profile *profile = sa->aad.profile; pid_t pid; rcu_read_lock(); - pid = tsk->real_parent->pid; + pid = rcu_dereference(tsk->real_parent)->pid; rcu_read_unlock(); audit_log_format(ab, " parent=%d", pid); if (profile->ns != root_ns) { -- cgit v1.2.3 From bb80d880ad2b11cd4ea5f28f815016b1548224a4 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 8 Dec 2011 16:30:42 -0800 Subject: tomoyo: add missing rcu_dereference() Adds a missed rcu_dereference() around real_parent. Signed-off-by: Kees Cook Acked-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security') diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index ed311d7a8ce0..cb9f5c2d6f3a 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -1122,7 +1122,7 @@ static inline pid_t tomoyo_sys_getppid(void) { pid_t pid; rcu_read_lock(); - pid = task_tgid_vnr(current->real_parent); + pid = task_tgid_vnr(rcu_dereference(current->real_parent)); rcu_read_unlock(); return pid; } -- cgit v1.2.3 From 735e93c70434614bffac4a914ca1da72e37d43c0 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 9 Dec 2011 11:23:46 -0800 Subject: Security: tomoyo: add .gitignore file This adds the .gitignore file for the autogenerated TOMOYO files to keep git from complaining after building things. Cc: Kentaro Takeda Cc: Tetsuo Handa Cc: James Morris Signed-off-by: Greg Kroah-Hartman Acked-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 security/tomoyo/.gitignore (limited to 'security') diff --git a/security/tomoyo/.gitignore b/security/tomoyo/.gitignore new file mode 100644 index 000000000000..5caf1a6f5907 --- /dev/null +++ b/security/tomoyo/.gitignore @@ -0,0 +1,2 @@ +builtin-policy.h +policy/ -- cgit v1.2.3 From b8aa09fd880eb4c2881b9f3c8a8d09c0404cd4eb Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 15 Dec 2011 13:41:32 +1030 Subject: apparmor: fix module parameter handling The 'aabool' wrappers actually pass off to the 'bool' parse functions, so you should use the same check function. Similarly for aauint and uint. (Note that 'bool' module parameters also allow 'int', which is why you got away with this, but that's changing very soon.) Cc: linux-security-module@vger.kernel.org Signed-off-by: Rusty Russell Acked-by: John Johansen Signed-off-by: James Morris --- security/apparmor/lsm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'security') diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 37832026e58a..41ae0c6cb903 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -671,7 +671,7 @@ static struct security_operations apparmor_ops = { static int param_set_aabool(const char *val, const struct kernel_param *kp); static int param_get_aabool(char *buffer, const struct kernel_param *kp); -#define param_check_aabool(name, p) __param_check(name, p, int) +#define param_check_aabool param_check_bool static struct kernel_param_ops param_ops_aabool = { .set = param_set_aabool, .get = param_get_aabool @@ -679,7 +679,7 @@ static struct kernel_param_ops param_ops_aabool = { static int param_set_aauint(const char *val, const struct kernel_param *kp); static int param_get_aauint(char *buffer, const struct kernel_param *kp); -#define param_check_aauint(name, p) __param_check(name, p, int) +#define param_check_aauint param_check_uint static struct kernel_param_ops param_ops_aauint = { .set = param_set_aauint, .get = param_get_aauint @@ -687,7 +687,7 @@ static struct kernel_param_ops param_ops_aauint = { static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp); static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp); -#define param_check_aalockpolicy(name, p) __param_check(name, p, int) +#define param_check_aalockpolicy param_check_bool static struct kernel_param_ops param_ops_aalockpolicy = { .set = param_set_aalockpolicy, .get = param_get_aalockpolicy -- cgit v1.2.3 From 2ff6fa8fafd6fa94029fa0558a6b85956930f1f5 Mon Sep 17 00:00:00 2001 From: Thomas Meyer Date: Thu, 17 Nov 2011 23:43:40 +0100 Subject: selinux: Casting (void *) value returned by kmalloc is useless The semantic patch that makes this change is available in scripts/coccinelle/api/alloc/drop_kmalloc_cast.cocci. Signed-off-by: Thomas Meyer Signed-off-by: James Morris --- security/selinux/ss/conditional.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security') diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 2ec904177fe0..377d148e7157 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -175,7 +175,7 @@ void cond_policydb_destroy(struct policydb *p) int cond_init_bool_indexes(struct policydb *p) { kfree(p->bool_val_to_struct); - p->bool_val_to_struct = (struct cond_bool_datum **) + p->bool_val_to_struct = kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL); if (!p->bool_val_to_struct) return -ENOMEM; -- cgit v1.2.3 From 45fae7493970d7c45626ccd96d4a74f5f1eea5a9 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Mon, 19 Dec 2011 15:57:27 +0100 Subject: ima: free duplicate measurement memory Info about new measurements are cached in the iint for performance. When the inode is flushed from cache, the associated iint is flushed as well. Subsequent access to the inode will cause the inode to be re-measured and will attempt to add a duplicate entry to the measurement list. This patch frees the duplicate measurement memory, fixing a memory leak. Signed-off-by: Roberto Sassu Signed-off-by: Mimi Zohar Cc: stable@vger.kernel.org --- security/integrity/ima/ima_api.c | 4 ++-- security/integrity/ima/ima_queue.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'security') diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 0d50df04ccc4..88a2788b981d 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -178,8 +178,8 @@ void ima_store_measurement(struct integrity_iint_cache *iint, strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX); result = ima_store_template(entry, violation, inode); - if (!result) + if (!result || result == -EEXIST) iint->flags |= IMA_MEASURED; - else + if (result < 0) kfree(entry); } diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 8e28f04a5e2e..e1a5062b1f6a 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -114,6 +114,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, memcpy(digest, entry->digest, sizeof digest); if (ima_lookup_digest_entry(digest)) { audit_cause = "hash_exists"; + result = -EEXIST; goto out; } } -- cgit v1.2.3 From 7b7e5916aa2f46e57f8bd8cb89c34620ebfda5da Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Mon, 19 Dec 2011 15:57:28 +0100 Subject: ima: fix invalid memory reference Don't free a valid measurement entry on TPM PCR extend failure. Signed-off-by: Roberto Sassu Signed-off-by: Mimi Zohar Cc: stable@vger.kernel.org --- security/integrity/ima/ima_queue.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'security') diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index e1a5062b1f6a..55a6271bce7a 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -23,6 +23,8 @@ #include #include "ima.h" +#define AUDIT_CAUSE_LEN_MAX 32 + LIST_HEAD(ima_measurements); /* list of all measurements */ /* key: inode (before secure-hashing a file) */ @@ -94,7 +96,8 @@ static int ima_pcr_extend(const u8 *hash) result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash); if (result != 0) - pr_err("IMA: Error Communicating to TPM chip\n"); + pr_err("IMA: Error Communicating to TPM chip, result: %d\n", + result); return result; } @@ -106,8 +109,9 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, { u8 digest[IMA_DIGEST_SIZE]; const char *audit_cause = "hash_added"; + char tpm_audit_cause[AUDIT_CAUSE_LEN_MAX]; int audit_info = 1; - int result = 0; + int result = 0, tpmresult = 0; mutex_lock(&ima_extend_list_mutex); if (!violation) { @@ -129,9 +133,11 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, if (violation) /* invalidate pcr */ memset(digest, 0xff, sizeof digest); - result = ima_pcr_extend(digest); - if (result != 0) { - audit_cause = "TPM error"; + tpmresult = ima_pcr_extend(digest); + if (tpmresult != 0) { + snprintf(tpm_audit_cause, AUDIT_CAUSE_LEN_MAX, "TPM_error(%d)", + tpmresult); + audit_cause = tpm_audit_cause; audit_info = 0; } out: -- cgit v1.2.3