Skip to content

Commit

Permalink
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/…
Browse files Browse the repository at this point in the history
…zohar/linux-integrity into next
  • Loading branch information
James Morris committed Dec 26, 2015
2 parents 5beb0c4 + 0112721 commit 3cb92fe
Show file tree
Hide file tree
Showing 23 changed files with 657 additions and 84 deletions.
2 changes: 2 additions & 0 deletions crypto/asymmetric_keys/x509_public_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
goto error_free_cert;
} else if (!prep->trusted) {
ret = x509_validate_trust(cert, get_system_trusted_keyring());
if (ret)
ret = x509_validate_trust(cert, get_ima_mok_keyring());
if (!ret)
prep->trusted = 1;
}
Expand Down
24 changes: 24 additions & 0 deletions include/keys/system_keyring.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,28 @@ extern int system_verify_data(const void *data, unsigned long len,
enum key_being_used_for usage);
#endif

#ifdef CONFIG_IMA_MOK_KEYRING
extern struct key *ima_mok_keyring;
extern struct key *ima_blacklist_keyring;

static inline struct key *get_ima_mok_keyring(void)
{
return ima_mok_keyring;
}
static inline struct key *get_ima_blacklist_keyring(void)
{
return ima_blacklist_keyring;
}
#else
static inline struct key *get_ima_mok_keyring(void)
{
return NULL;
}
static inline struct key *get_ima_blacklist_keyring(void)
{
return NULL;
}
#endif /* CONFIG_IMA_MOK_KEYRING */


#endif /* _KEYS_SYSTEM_KEYRING_H */
7 changes: 7 additions & 0 deletions include/linux/evm.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
struct integrity_iint_cache;

#ifdef CONFIG_EVM
extern int evm_set_key(void *key, size_t keylen);
extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
const char *xattr_name,
void *xattr_value,
Expand Down Expand Up @@ -42,6 +43,12 @@ static inline int posix_xattr_acl(const char *xattrname)
}
#endif
#else

static inline int evm_set_key(void *key, size_t keylen)
{
return -EOPNOTSUPP;
}

#ifdef CONFIG_INTEGRITY
static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
const char *xattr_name,
Expand Down
1 change: 1 addition & 0 deletions include/linux/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ struct key {
#define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */
#define KEY_FLAG_BUILTIN 10 /* set if key is builtin */
#define KEY_FLAG_ROOT_CAN_INVAL 11 /* set if key can be invalidated by root without permission */
#define KEY_FLAG_KEEP 12 /* set if key should not be removed */

/* the key type and key description string
* - the desc is used to match a key against search criteria
Expand Down
11 changes: 11 additions & 0 deletions security/integrity/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ config INTEGRITY_ASYMMETRIC_KEYS
This option enables digital signature verification using
asymmetric keys.

config INTEGRITY_TRUSTED_KEYRING
bool "Require all keys on the integrity keyrings be signed"
depends on SYSTEM_TRUSTED_KEYRING
depends on INTEGRITY_ASYMMETRIC_KEYS
select KEYS_DEBUG_PROC_KEYS
default y
help
This option requires that all keys added to the .ima and
.evm keyrings be signed by a key on the system trusted
keyring.

config INTEGRITY_AUDIT
bool "Enables integrity auditing support "
depends on AUDIT
Expand Down
14 changes: 12 additions & 2 deletions security/integrity/digsig.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,22 @@
static struct key *keyring[INTEGRITY_KEYRING_MAX];

static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
#ifndef CONFIG_INTEGRITY_TRUSTED_KEYRING
"_evm",
"_module",
#ifndef CONFIG_IMA_TRUSTED_KEYRING
"_ima",
#else
".evm",
".ima",
#endif
"_module",
};

#ifdef CONFIG_INTEGRITY_TRUSTED_KEYRING
static bool init_keyring __initdata = true;
#else
static bool init_keyring __initdata;
#endif

int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
const char *digest, int digestlen)
{
Expand Down Expand Up @@ -68,6 +75,9 @@ int __init integrity_init_keyring(const unsigned int id)
const struct cred *cred = current_cred();
int err = 0;

if (!init_keyring)
return 0;

keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
KGIDT_INIT(0), cred,
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
Expand Down
14 changes: 14 additions & 0 deletions security/integrity/digsig_asymmetric.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <linux/key-type.h>
#include <crypto/public_key.h>
#include <keys/asymmetric-type.h>
#include <keys/system_keyring.h>

#include "integrity.h"

Expand All @@ -32,9 +33,22 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)

pr_debug("key search: \"%s\"\n", name);

key = get_ima_blacklist_keyring();
if (key) {
key_ref_t kref;

kref = keyring_search(make_key_ref(key, 1),
&key_type_asymmetric, name);
if (!IS_ERR(kref)) {
pr_err("Key '%s' is in ima_blacklist_keyring\n", name);
return ERR_PTR(-EKEYREJECTED);
}
}

if (keyring) {
/* search in specific keyring */
key_ref_t kref;

kref = keyring_search(make_key_ref(keyring, 1),
&key_type_asymmetric, name);
if (IS_ERR(kref))
Expand Down
17 changes: 17 additions & 0 deletions security/integrity/evm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,20 @@ config EVM_EXTRA_SMACK_XATTRS
additional info to the calculation, requires existing EVM
labeled file systems to be relabeled.

config EVM_LOAD_X509
bool "Load an X509 certificate onto the '.evm' trusted keyring"
depends on EVM && INTEGRITY_TRUSTED_KEYRING
default n
help
Load an X509 certificate onto the '.evm' trusted keyring.

This option enables X509 certificate loading from the kernel
onto the '.evm' trusted keyring. A public key can be used to
verify EVM integrity starting from the 'init' process.

config EVM_X509_PATH
string "EVM X509 certificate path"
depends on EVM_LOAD_X509
default "/etc/keys/x509_evm.der"
help
This option defines X509 certificate path.
3 changes: 3 additions & 0 deletions security/integrity/evm/evm.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@

#include "../integrity.h"

#define EVM_INIT_HMAC 0x0001
#define EVM_INIT_X509 0x0002

extern int evm_initialized;
extern char *evm_hmac;
extern char *evm_hash;
Expand Down
54 changes: 47 additions & 7 deletions security/integrity/evm/evm_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/crypto.h>
#include <linux/xattr.h>
#include <linux/evm.h>
#include <keys/encrypted-type.h>
#include <crypto/hash.h>
#include "evm.h"
Expand All @@ -32,6 +33,44 @@ struct crypto_shash *hash_tfm;

static DEFINE_MUTEX(mutex);

#define EVM_SET_KEY_BUSY 0

static unsigned long evm_set_key_flags;

/**
* evm_set_key() - set EVM HMAC key from the kernel
* @key: pointer to a buffer with the key data
* @size: length of the key data
*
* This function allows setting the EVM HMAC key from the kernel
* without using the "encrypted" key subsystem keys. It can be used
* by the crypto HW kernel module which has its own way of managing
* keys.
*
* key length should be between 32 and 128 bytes long
*/
int evm_set_key(void *key, size_t keylen)
{
int rc;

rc = -EBUSY;
if (test_and_set_bit(EVM_SET_KEY_BUSY, &evm_set_key_flags))
goto busy;
rc = -EINVAL;
if (keylen > MAX_KEY_SIZE)
goto inval;
memcpy(evmkey, key, keylen);
evm_initialized |= EVM_INIT_HMAC;
pr_info("key initialized\n");
return 0;
inval:
clear_bit(EVM_SET_KEY_BUSY, &evm_set_key_flags);
busy:
pr_err("key initialization failed\n");
return rc;
}
EXPORT_SYMBOL_GPL(evm_set_key);

static struct shash_desc *init_desc(char type)
{
long rc;
Expand All @@ -40,6 +79,10 @@ static struct shash_desc *init_desc(char type)
struct shash_desc *desc;

if (type == EVM_XATTR_HMAC) {
if (!(evm_initialized & EVM_INIT_HMAC)) {
pr_err("HMAC key is not set\n");
return ERR_PTR(-ENOKEY);
}
tfm = &hmac_tfm;
algo = evm_hmac;
} else {
Expand Down Expand Up @@ -240,20 +283,17 @@ int evm_init_key(void)
{
struct key *evm_key;
struct encrypted_key_payload *ekp;
int rc = 0;
int rc;

evm_key = request_key(&key_type_encrypted, EVMKEY, NULL);
if (IS_ERR(evm_key))
return -ENOENT;

down_read(&evm_key->sem);
ekp = evm_key->payload.data[0];
if (ekp->decrypted_datalen > MAX_KEY_SIZE) {
rc = -EINVAL;
goto out;
}
memcpy(evmkey, ekp->decrypted_data, ekp->decrypted_datalen);
out:

rc = evm_set_key(ekp->decrypted_data, ekp->decrypted_datalen);

/* burn the original key contents */
memset(ekp->decrypted_data, 0, ekp->decrypted_datalen);
up_read(&evm_key->sem);
Expand Down
32 changes: 29 additions & 3 deletions security/integrity/evm/evm_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,15 @@ int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name)
return evm_protect_xattr(dentry, xattr_name, NULL, 0);
}

static void evm_reset_status(struct inode *inode)
{
struct integrity_iint_cache *iint;

iint = integrity_iint_find(inode);
if (iint)
iint->evm_status = INTEGRITY_UNKNOWN;
}

/**
* evm_inode_post_setxattr - update 'security.evm' to reflect the changes
* @dentry: pointer to the affected dentry
Expand All @@ -378,6 +387,8 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
&& !posix_xattr_acl(xattr_name)))
return;

evm_reset_status(dentry->d_inode);

evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
}

Expand All @@ -396,6 +407,8 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
if (!evm_initialized || !evm_protected_xattr(xattr_name))
return;

evm_reset_status(dentry->d_inode);

evm_update_evmxattr(dentry, xattr_name, NULL, 0);
}

Expand Down Expand Up @@ -472,21 +485,34 @@ int evm_inode_init_security(struct inode *inode,
}
EXPORT_SYMBOL_GPL(evm_inode_init_security);

#ifdef CONFIG_EVM_LOAD_X509
void __init evm_load_x509(void)
{
int rc;

rc = integrity_load_x509(INTEGRITY_KEYRING_EVM, CONFIG_EVM_X509_PATH);
if (!rc)
evm_initialized |= EVM_INIT_X509;
}
#endif

static int __init init_evm(void)
{
int error;

evm_init_config();

error = integrity_init_keyring(INTEGRITY_KEYRING_EVM);
if (error)
return error;

error = evm_init_secfs();
if (error < 0) {
pr_info("Error registering secfs\n");
goto err;
return error;
}

return 0;
err:
return error;
}

/*
Expand Down
12 changes: 4 additions & 8 deletions security/integrity/evm/evm_secfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
char temp[80];
int i, error;
int i;

if (!capable(CAP_SYS_ADMIN) || evm_initialized)
if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_INIT_HMAC))
return -EPERM;

if (count >= sizeof(temp) || count == 0)
Expand All @@ -78,12 +78,8 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf,
if ((sscanf(temp, "%d", &i) != 1) || (i != 1))
return -EINVAL;

error = evm_init_key();
if (!error) {
evm_initialized = 1;
pr_info("initialized\n");
} else
pr_err("initialization failed\n");
evm_init_key();

return count;
}

Expand Down
1 change: 1 addition & 0 deletions security/integrity/iint.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,4 +254,5 @@ int __init integrity_read_file(const char *path, char **data)
void __init integrity_load_keys(void)
{
ima_load_x509();
evm_load_x509();
}
Loading

0 comments on commit 3cb92fe

Please sign in to comment.