diff --git a/include/linux/evm.h b/include/linux/evm.h index ea603c9e775d..9fc13a760928 100644 --- a/include/linux/evm.h +++ b/include/linux/evm.h @@ -33,6 +33,14 @@ extern void evm_inode_post_removexattr(struct dentry *dentry, extern int evm_inode_init_security(struct inode *inode, const struct xattr *xattr_array, struct xattr *evm); +#ifdef CONFIG_FS_POSIX_ACL +extern int posix_xattr_acl(const char *xattrname); +#else +static inline int posix_xattr_acl(const char *xattrname) +{ + return 0; +} +#endif #else #ifdef CONFIG_INTEGRITY static inline enum integrity_status evm_verifyxattr(struct dentry *dentry, diff --git a/include/linux/integrity.h b/include/linux/integrity.h index 968443385678..a0c41256cb92 100644 --- a/include/linux/integrity.h +++ b/include/linux/integrity.h @@ -16,6 +16,7 @@ enum integrity_status { INTEGRITY_PASS = 0, INTEGRITY_FAIL, INTEGRITY_NOLABEL, + INTEGRITY_NOXATTRS, INTEGRITY_UNKNOWN, }; diff --git a/include/linux/xattr.h b/include/linux/xattr.h index b20cb965c322..e5d122031542 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@ -52,6 +52,11 @@ #define XATTR_CAPS_SUFFIX "capability" #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX +#define XATTR_POSIX_ACL_ACCESS "posix_acl_access" +#define XATTR_NAME_POSIX_ACL_ACCESS XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_ACCESS +#define XATTR_POSIX_ACL_DEFAULT "posix_acl_default" +#define XATTR_NAME_POSIX_ACL_DEFAULT XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_DEFAULT + #ifdef __KERNEL__ #include diff --git a/security/Kconfig b/security/Kconfig index 22847a889081..51bd5a0b69ae 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -38,7 +38,9 @@ config TRUSTED_KEYS config ENCRYPTED_KEYS tristate "ENCRYPTED KEYS" - depends on KEYS && TRUSTED_KEYS + depends on KEYS + select CRYPTO + select CRYPTO_HMAC select CRYPTO_AES select CRYPTO_CBC select CRYPTO_SHA256 diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig index 884617d4aad0..afbb59dd262d 100644 --- a/security/integrity/evm/Kconfig +++ b/security/integrity/evm/Kconfig @@ -1,11 +1,10 @@ config EVM boolean "EVM support" - depends on SECURITY && KEYS && TCG_TPM + depends on SECURITY && KEYS && (TRUSTED_KEYS=y || TRUSTED_KEYS=n) select CRYPTO_HMAC select CRYPTO_MD5 select CRYPTO_SHA1 select ENCRYPTED_KEYS - select TRUSTED_KEYS default n help EVM protects a file's security extended attributes against diff --git a/security/integrity/evm/Makefile b/security/integrity/evm/Makefile index 0787d262b9e3..7393c415a066 100644 --- a/security/integrity/evm/Makefile +++ b/security/integrity/evm/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_EVM) += evm.o evm-y := evm_main.o evm_crypto.o evm_secfs.o +evm-$(CONFIG_FS_POSIX_ACL) += evm_posix_acl.o diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index f0127e536f84..92d3d99a9f7b 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -66,7 +66,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, struct integrity_iint_cache *iint) { struct evm_ima_xattr_data xattr_data; - enum integrity_status evm_status; + enum integrity_status evm_status = INTEGRITY_PASS; int rc; if (iint && iint->evm_status == INTEGRITY_PASS) @@ -76,25 +76,18 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, rc = evm_calc_hmac(dentry, xattr_name, xattr_value, xattr_value_len, xattr_data.digest); - if (rc < 0) - goto err_out; + if (rc < 0) { + evm_status = (rc == -ENODATA) + ? INTEGRITY_NOXATTRS : INTEGRITY_FAIL; + 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) - goto err_out; - evm_status = INTEGRITY_PASS; - goto out; - -err_out: - switch (rc) { - case -ENODATA: /* file not labelled */ - evm_status = INTEGRITY_NOLABEL; - break; - default: - evm_status = INTEGRITY_FAIL; - } + evm_status = (rc == -ENODATA) + ? INTEGRITY_NOLABEL : INTEGRITY_FAIL; out: if (iint) iint->evm_status = evm_status; @@ -158,21 +151,6 @@ enum integrity_status evm_verifyxattr(struct dentry *dentry, } 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_verify_current_integrity - verify the dentry's metadata integrity * @dentry: pointer to the affected dentry @@ -189,6 +167,39 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry) return evm_verify_hmac(dentry, NULL, NULL, 0, NULL); } +/* + * evm_protect_xattr - protect the EVM extended attribute + * + * Prevent security.evm from being modified or removed without the + * necessary permissions or when the existing value is invalid. + * + * The posix xattr acls are 'system' prefixed, which normally would not + * affect security.evm. An interesting side affect of writing posix xattr + * acls is their modifying of the i_mode, which is included in security.evm. + * For posix xattr acls only, permit security.evm, even if it currently + * doesn't exist, to be updated. + */ +static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name, + const void *xattr_value, size_t xattr_value_len) +{ + enum integrity_status evm_status; + + if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + } else if (!evm_protected_xattr(xattr_name)) { + if (!posix_xattr_acl(xattr_name)) + return 0; + evm_status = evm_verify_current_integrity(dentry); + if ((evm_status == INTEGRITY_PASS) || + (evm_status == INTEGRITY_NOXATTRS)) + return 0; + return -EPERM; + } + evm_status = evm_verify_current_integrity(dentry); + return evm_status == INTEGRITY_PASS ? 0 : -EPERM; +} + /** * evm_inode_setxattr - protect the EVM extended attribute * @dentry: pointer to the affected dentry @@ -202,16 +213,8 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry) int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, const void *xattr_value, size_t 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; + return evm_protect_xattr(dentry, xattr_name, xattr_value, + xattr_value_len); } /** @@ -224,14 +227,7 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, */ int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name) { - 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; + return evm_protect_xattr(dentry, xattr_name, NULL, 0); } /** @@ -250,7 +246,8 @@ int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name) 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)) + if (!evm_initialized || (!evm_protected_xattr(xattr_name) + && !posix_xattr_acl(xattr_name))) return; evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len); @@ -286,10 +283,13 @@ 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)) + 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; + if ((evm_status == INTEGRITY_PASS) || + (evm_status == INTEGRITY_NOXATTRS)) + return 0; + return -EPERM; } /** diff --git a/security/integrity/evm/evm_posix_acl.c b/security/integrity/evm/evm_posix_acl.c new file mode 100644 index 000000000000..b1753e98bf9a --- /dev/null +++ b/security/integrity/evm/evm_posix_acl.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2011 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. + */ + +#include +#include + +int posix_xattr_acl(char *xattr) +{ + int xattr_len = strlen(xattr); + + if ((strlen(XATTR_NAME_POSIX_ACL_ACCESS) == xattr_len) + && (strncmp(XATTR_NAME_POSIX_ACL_ACCESS, xattr, xattr_len) == 0)) + return 1; + if ((strlen(XATTR_NAME_POSIX_ACL_DEFAULT) == xattr_len) + && (strncmp(XATTR_NAME_POSIX_ACL_DEFAULT, xattr, xattr_len) == 0)) + return 1; + return 0; +} diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 0a23e075e1d2..399641c3e846 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -74,6 +74,7 @@ static void iint_free(struct integrity_iint_cache *iint) { iint->version = 0; iint->flags = 0UL; + iint->evm_status = INTEGRITY_UNKNOWN; kmem_cache_free(iint_cache, iint); } diff --git a/security/keys/Makefile b/security/keys/Makefile index b34cc6ee6900..a56f1ffdc64d 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile @@ -14,7 +14,7 @@ obj-y := \ user_defined.o obj-$(CONFIG_TRUSTED_KEYS) += trusted.o -obj-$(CONFIG_ENCRYPTED_KEYS) += ecryptfs_format.o encrypted.o +obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ obj-$(CONFIG_KEYS_COMPAT) += compat.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_SYSCTL) += sysctl.o diff --git a/security/keys/encrypted-keys/Makefile b/security/keys/encrypted-keys/Makefile new file mode 100644 index 000000000000..6bc7a86d1027 --- /dev/null +++ b/security/keys/encrypted-keys/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for encrypted keys +# + +obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted.o ecryptfs_format.o +obj-$(CONFIG_TRUSTED_KEYS) += masterkey_trusted.o diff --git a/security/keys/ecryptfs_format.c b/security/keys/encrypted-keys/ecryptfs_format.c similarity index 100% rename from security/keys/ecryptfs_format.c rename to security/keys/encrypted-keys/ecryptfs_format.c diff --git a/security/keys/ecryptfs_format.h b/security/keys/encrypted-keys/ecryptfs_format.h similarity index 100% rename from security/keys/ecryptfs_format.h rename to security/keys/encrypted-keys/ecryptfs_format.h diff --git a/security/keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c similarity index 97% rename from security/keys/encrypted.c rename to security/keys/encrypted-keys/encrypted.c index e7eca9ec4c65..3f577954b85a 100644 --- a/security/keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -298,31 +298,6 @@ out: return ascii_buf; } -/* - * request_trusted_key - request the trusted key - * - * Trusted keys are sealed to PCRs and other metadata. Although userspace - * manages both trusted/encrypted key-types, like the encrypted key type - * data, trusted key type data is not visible decrypted from userspace. - */ -static struct key *request_trusted_key(const char *trusted_desc, - u8 **master_key, size_t *master_keylen) -{ - struct trusted_key_payload *tpayload; - struct key *tkey; - - tkey = request_key(&key_type_trusted, trusted_desc, NULL); - if (IS_ERR(tkey)) - goto error; - - down_read(&tkey->sem); - tpayload = rcu_dereference(tkey->payload.data); - *master_key = tpayload->key; - *master_keylen = tpayload->key_len; -error: - return tkey; -} - /* * request_user_key - request the user key * @@ -469,8 +444,14 @@ static struct key *request_master_key(struct encrypted_key_payload *epayload, goto out; if (IS_ERR(mkey)) { - pr_info("encrypted_key: key %s not found", - epayload->master_desc); + int ret = PTR_ERR(epayload); + + if (ret == -ENOTSUPP) + pr_info("encrypted_key: key %s not supported", + epayload->master_desc); + else + pr_info("encrypted_key: key %s not found", + epayload->master_desc); goto out; } diff --git a/security/keys/encrypted.h b/security/keys/encrypted-keys/encrypted.h similarity index 81% rename from security/keys/encrypted.h rename to security/keys/encrypted-keys/encrypted.h index cef5e2f2b7d1..b6ade8945250 100644 --- a/security/keys/encrypted.h +++ b/security/keys/encrypted-keys/encrypted.h @@ -2,6 +2,17 @@ #define __ENCRYPTED_KEY_H #define ENCRYPTED_DEBUG 0 +#ifdef CONFIG_TRUSTED_KEYS +extern struct key *request_trusted_key(const char *trusted_desc, + u8 **master_key, size_t *master_keylen); +#else +static inline struct key *request_trusted_key(const char *trusted_desc, + u8 **master_key, + size_t *master_keylen) +{ + return ERR_PTR(-EOPNOTSUPP); +} +#endif #if ENCRYPTED_DEBUG static inline void dump_master_key(const u8 *master_key, size_t master_keylen) diff --git a/security/keys/encrypted-keys/masterkey_trusted.c b/security/keys/encrypted-keys/masterkey_trusted.c new file mode 100644 index 000000000000..a5da5128891b --- /dev/null +++ b/security/keys/encrypted-keys/masterkey_trusted.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010 IBM Corporation + * Copyright (C) 2010 Politecnico di Torino, Italy + * TORSEC group -- http://security.polito.it + * + * Authors: + * Mimi Zohar + * Roberto Sassu + * + * 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. + * + * See Documentation/security/keys-trusted-encrypted.txt + */ + +#include +#include +#include + +/* + * request_trusted_key - request the trusted key + * + * Trusted keys are sealed to PCRs and other metadata. Although userspace + * manages both trusted/encrypted key-types, like the encrypted key type + * data, trusted key type data is not visible decrypted from userspace. + */ +struct key *request_trusted_key(const char *trusted_desc, + u8 **master_key, size_t *master_keylen) +{ + struct trusted_key_payload *tpayload; + struct key *tkey; + + tkey = request_key(&key_type_trusted, trusted_desc, NULL); + if (IS_ERR(tkey)) + goto error; + + down_read(&tkey->sem); + tpayload = rcu_dereference(tkey->payload.data); + *master_key = tpayload->key; + *master_keylen = tpayload->key_len; +error: + return tkey; +} diff --git a/security/security.c b/security/security.c index 9ebda054a333..c1d69875db6c 100644 --- a/security/security.c +++ b/security/security.c @@ -348,7 +348,7 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, int ret; if (unlikely(IS_PRIVATE(inode))) - return -EOPNOTSUPP; + return 0; memset(new_xattrs, 0, sizeof new_xattrs); if (!initxattrs) @@ -381,7 +381,7 @@ int security_old_inode_init_security(struct inode *inode, struct inode *dir, void **value, size_t *len) { if (unlikely(IS_PRIVATE(inode))) - return -EOPNOTSUPP; + return 0; return security_ops->inode_init_security(inode, dir, qstr, name, value, len); }