Commit 8de6ac7f authored by James Morris's avatar James Morris

Merge branch 'next-evm' of git://github.com/mzohar/linux-evm into next

parents 843d183c fb788d8b
...@@ -33,6 +33,14 @@ extern void evm_inode_post_removexattr(struct dentry *dentry, ...@@ -33,6 +33,14 @@ extern void evm_inode_post_removexattr(struct dentry *dentry,
extern int evm_inode_init_security(struct inode *inode, extern int evm_inode_init_security(struct inode *inode,
const struct xattr *xattr_array, const struct xattr *xattr_array,
struct xattr *evm); 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 #else
#ifdef CONFIG_INTEGRITY #ifdef CONFIG_INTEGRITY
static inline enum integrity_status evm_verifyxattr(struct dentry *dentry, static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
......
...@@ -16,6 +16,7 @@ enum integrity_status { ...@@ -16,6 +16,7 @@ enum integrity_status {
INTEGRITY_PASS = 0, INTEGRITY_PASS = 0,
INTEGRITY_FAIL, INTEGRITY_FAIL,
INTEGRITY_NOLABEL, INTEGRITY_NOLABEL,
INTEGRITY_NOXATTRS,
INTEGRITY_UNKNOWN, INTEGRITY_UNKNOWN,
}; };
......
...@@ -52,6 +52,11 @@ ...@@ -52,6 +52,11 @@
#define XATTR_CAPS_SUFFIX "capability" #define XATTR_CAPS_SUFFIX "capability"
#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX #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__ #ifdef __KERNEL__
#include <linux/types.h> #include <linux/types.h>
......
...@@ -38,7 +38,9 @@ config TRUSTED_KEYS ...@@ -38,7 +38,9 @@ config TRUSTED_KEYS
config ENCRYPTED_KEYS config ENCRYPTED_KEYS
tristate "ENCRYPTED KEYS" tristate "ENCRYPTED KEYS"
depends on KEYS && TRUSTED_KEYS depends on KEYS
select CRYPTO
select CRYPTO_HMAC
select CRYPTO_AES select CRYPTO_AES
select CRYPTO_CBC select CRYPTO_CBC
select CRYPTO_SHA256 select CRYPTO_SHA256
......
config EVM config EVM
boolean "EVM support" boolean "EVM support"
depends on SECURITY && KEYS && TCG_TPM depends on SECURITY && KEYS && (TRUSTED_KEYS=y || TRUSTED_KEYS=n)
select CRYPTO_HMAC select CRYPTO_HMAC
select CRYPTO_MD5 select CRYPTO_MD5
select CRYPTO_SHA1 select CRYPTO_SHA1
select ENCRYPTED_KEYS select ENCRYPTED_KEYS
select TRUSTED_KEYS
default n default n
help help
EVM protects a file's security extended attributes against EVM protects a file's security extended attributes against
......
...@@ -4,3 +4,4 @@ ...@@ -4,3 +4,4 @@
obj-$(CONFIG_EVM) += evm.o obj-$(CONFIG_EVM) += evm.o
evm-y := evm_main.o evm_crypto.o evm_secfs.o evm-y := evm_main.o evm_crypto.o evm_secfs.o
evm-$(CONFIG_FS_POSIX_ACL) += evm_posix_acl.o
...@@ -66,7 +66,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, ...@@ -66,7 +66,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
struct integrity_iint_cache *iint) struct integrity_iint_cache *iint)
{ {
struct evm_ima_xattr_data xattr_data; struct evm_ima_xattr_data xattr_data;
enum integrity_status evm_status; enum integrity_status evm_status = INTEGRITY_PASS;
int rc; int rc;
if (iint && iint->evm_status == INTEGRITY_PASS) if (iint && iint->evm_status == INTEGRITY_PASS)
...@@ -76,25 +76,18 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, ...@@ -76,25 +76,18 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
rc = evm_calc_hmac(dentry, xattr_name, xattr_value, rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
xattr_value_len, xattr_data.digest); xattr_value_len, xattr_data.digest);
if (rc < 0) if (rc < 0) {
goto err_out; evm_status = (rc == -ENODATA)
? INTEGRITY_NOXATTRS : INTEGRITY_FAIL;
goto out;
}
xattr_data.type = EVM_XATTR_HMAC; xattr_data.type = EVM_XATTR_HMAC;
rc = vfs_xattr_cmp(dentry, XATTR_NAME_EVM, (u8 *)&xattr_data, rc = vfs_xattr_cmp(dentry, XATTR_NAME_EVM, (u8 *)&xattr_data,
sizeof xattr_data, GFP_NOFS); sizeof xattr_data, GFP_NOFS);
if (rc < 0) if (rc < 0)
goto err_out; evm_status = (rc == -ENODATA)
evm_status = INTEGRITY_PASS; ? INTEGRITY_NOLABEL : INTEGRITY_FAIL;
goto out;
err_out:
switch (rc) {
case -ENODATA: /* file not labelled */
evm_status = INTEGRITY_NOLABEL;
break;
default:
evm_status = INTEGRITY_FAIL;
}
out: out:
if (iint) if (iint)
iint->evm_status = evm_status; iint->evm_status = evm_status;
...@@ -158,21 +151,6 @@ enum integrity_status evm_verifyxattr(struct dentry *dentry, ...@@ -158,21 +151,6 @@ enum integrity_status evm_verifyxattr(struct dentry *dentry,
} }
EXPORT_SYMBOL_GPL(evm_verifyxattr); 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 * evm_verify_current_integrity - verify the dentry's metadata integrity
* @dentry: pointer to the affected dentry * @dentry: pointer to the affected dentry
...@@ -189,6 +167,39 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *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); 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 * evm_inode_setxattr - protect the EVM extended attribute
* @dentry: pointer to the affected dentry * @dentry: pointer to the affected dentry
...@@ -202,16 +213,8 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *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, int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,
const void *xattr_value, size_t xattr_value_len) const void *xattr_value, size_t xattr_value_len)
{ {
return evm_protect_xattr(dentry, xattr_name, xattr_value,
enum integrity_status evm_status; xattr_value_len);
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;
} }
/** /**
...@@ -224,14 +227,7 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, ...@@ -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) int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name)
{ {
enum integrity_status evm_status; return evm_protect_xattr(dentry, xattr_name, NULL, 0);
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;
} }
/** /**
...@@ -250,7 +246,8 @@ int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name) ...@@ -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, void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
const void *xattr_value, size_t xattr_value_len) 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; return;
evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len); 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) ...@@ -286,10 +283,13 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
unsigned int ia_valid = attr->ia_valid; unsigned int ia_valid = attr->ia_valid;
enum integrity_status evm_status; 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; return 0;
evm_status = evm_verify_current_integrity(dentry); 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;
} }
/** /**
......
/*
* Copyright (C) 2011 IBM Corporation
*
* Author:
* Mimi Zohar <zohar@us.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*/
#include <linux/module.h>
#include <linux/xattr.h>
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;
}
...@@ -74,6 +74,7 @@ static void iint_free(struct integrity_iint_cache *iint) ...@@ -74,6 +74,7 @@ static void iint_free(struct integrity_iint_cache *iint)
{ {
iint->version = 0; iint->version = 0;
iint->flags = 0UL; iint->flags = 0UL;
iint->evm_status = INTEGRITY_UNKNOWN;
kmem_cache_free(iint_cache, iint); kmem_cache_free(iint_cache, iint);
} }
......
...@@ -14,7 +14,7 @@ obj-y := \ ...@@ -14,7 +14,7 @@ obj-y := \
user_defined.o user_defined.o
obj-$(CONFIG_TRUSTED_KEYS) += trusted.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_KEYS_COMPAT) += compat.o
obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSCTL) += sysctl.o obj-$(CONFIG_SYSCTL) += sysctl.o
#
# Makefile for encrypted keys
#
obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted.o ecryptfs_format.o
obj-$(CONFIG_TRUSTED_KEYS) += masterkey_trusted.o
...@@ -298,31 +298,6 @@ static char *datablob_format(struct encrypted_key_payload *epayload, ...@@ -298,31 +298,6 @@ static char *datablob_format(struct encrypted_key_payload *epayload,
return ascii_buf; 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 * request_user_key - request the user key
* *
...@@ -469,8 +444,14 @@ static struct key *request_master_key(struct encrypted_key_payload *epayload, ...@@ -469,8 +444,14 @@ static struct key *request_master_key(struct encrypted_key_payload *epayload,
goto out; goto out;
if (IS_ERR(mkey)) { if (IS_ERR(mkey)) {
pr_info("encrypted_key: key %s not found", int ret = PTR_ERR(epayload);
epayload->master_desc);
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; goto out;
} }
......
...@@ -2,6 +2,17 @@ ...@@ -2,6 +2,17 @@
#define __ENCRYPTED_KEY_H #define __ENCRYPTED_KEY_H
#define ENCRYPTED_DEBUG 0 #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 #if ENCRYPTED_DEBUG
static inline void dump_master_key(const u8 *master_key, size_t master_keylen) static inline void dump_master_key(const u8 *master_key, size_t master_keylen)
......
/*
* Copyright (C) 2010 IBM Corporation
* Copyright (C) 2010 Politecnico di Torino, Italy
* TORSEC group -- http://security.polito.it
*
* Authors:
* Mimi Zohar <zohar@us.ibm.com>
* Roberto Sassu <roberto.sassu@polito.it>
*
* 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 <linux/uaccess.h>
#include <linux/module.h>
#include <keys/trusted-type.h>
/*
* 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;
}
...@@ -348,7 +348,7 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, ...@@ -348,7 +348,7 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
int ret; int ret;
if (unlikely(IS_PRIVATE(inode))) if (unlikely(IS_PRIVATE(inode)))
return -EOPNOTSUPP; return 0;
memset(new_xattrs, 0, sizeof new_xattrs); memset(new_xattrs, 0, sizeof new_xattrs);
if (!initxattrs) if (!initxattrs)
...@@ -381,7 +381,7 @@ int security_old_inode_init_security(struct inode *inode, struct inode *dir, ...@@ -381,7 +381,7 @@ int security_old_inode_init_security(struct inode *inode, struct inode *dir,
void **value, size_t *len) void **value, size_t *len)
{ {
if (unlikely(IS_PRIVATE(inode))) if (unlikely(IS_PRIVATE(inode)))
return -EOPNOTSUPP; return 0;
return security_ops->inode_init_security(inode, dir, qstr, name, value, return security_ops->inode_init_security(inode, dir, qstr, name, value,
len); len);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment