Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity into next

This commit is contained in:
James Morris 2015-12-26 16:06:53 +11:00
commit 3cb92fe481
23 changed files with 658 additions and 85 deletions

View file

@ -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;
}

View file

@ -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 */

View file

@ -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,
@ -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,

View file

@ -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

View file

@ -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

View file

@ -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)
{
@ -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) |

View file

@ -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"
@ -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))

View file

@ -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.

View file

@ -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;

View file

@ -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"
@ -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;
@ -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 {
@ -240,7 +283,7 @@ 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))
@ -248,12 +291,9 @@ int evm_init_key(void)
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);

View file

@ -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
@ -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);
}
@ -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);
}
@ -472,21 +485,34 @@ out:
}
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;
}
/*

View file

@ -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)
@ -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;
}

View file

@ -254,4 +254,5 @@ out:
void __init integrity_load_keys(void)
{
ima_load_x509();
evm_load_x509();
}

View file

@ -107,6 +107,27 @@ config IMA_DEFAULT_HASH
default "sha512" if IMA_DEFAULT_HASH_SHA512
default "wp512" if IMA_DEFAULT_HASH_WP512
config IMA_WRITE_POLICY
bool "Enable multiple writes to the IMA policy"
depends on IMA
default n
help
IMA policy can now be updated multiple times. The new rules get
appended to the original policy. Have in mind that the rules are
scanned in FIFO order so be careful when you design and add new ones.
If unsure, say N.
config IMA_READ_POLICY
bool "Enable reading back the current IMA policy"
depends on IMA
default y if IMA_WRITE_POLICY
default n if !IMA_WRITE_POLICY
help
It is often useful to be able to read back the IMA policy. It is
even more important after introducing CONFIG_IMA_WRITE_POLICY.
This option allows the root user to see the current policy rules.
config IMA_APPRAISE
bool "Appraise integrity measurements"
depends on IMA
@ -123,14 +144,35 @@ config IMA_APPRAISE
If unsure, say N.
config IMA_TRUSTED_KEYRING
bool "Require all keys on the .ima keyring be signed"
bool "Require all keys on the .ima keyring be signed (deprecated)"
depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
depends on INTEGRITY_ASYMMETRIC_KEYS
select INTEGRITY_TRUSTED_KEYRING
default y
help
This option requires that all keys added to the .ima
keyring be signed by a key on the system trusted keyring.
This option is deprecated in favor of INTEGRITY_TRUSTED_KEYRING
config IMA_MOK_KEYRING
bool "Create IMA machine owner keys (MOK) and blacklist keyrings"
depends on SYSTEM_TRUSTED_KEYRING
depends on IMA_TRUSTED_KEYRING
default n
help
This option creates IMA MOK and blacklist keyrings. IMA MOK is an
intermediate keyring that sits between .system and .ima keyrings,
effectively forming a simple CA hierarchy. To successfully import a
key into .ima_mok it must be signed by a key which CA is in .system
keyring. On turn any key that needs to go in .ima keyring must be
signed by CA in either .system or .ima_mok keyrings. IMA MOK is empty
at kernel boot.
IMA blacklist keyring contains all revoked IMA keys. It is consulted
before any other keyring. If the search is successful the requested
operation is rejected and error is returned to the caller.
config IMA_LOAD_X509
bool "Load X509 certificate onto the '.ima' trusted keyring"
depends on IMA_TRUSTED_KEYRING

View file

@ -8,3 +8,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_template.o ima_template_lib.o
ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
obj-$(CONFIG_IMA_MOK_KEYRING) += ima_mok.o

View file

@ -166,6 +166,11 @@ void ima_update_policy(void);
void ima_update_policy_flag(void);
ssize_t ima_parse_add_rule(char *);
void ima_delete_rules(void);
int ima_check_policy(void);
void *ima_policy_start(struct seq_file *m, loff_t *pos);
void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
void ima_policy_stop(struct seq_file *m, void *v);
int ima_policy_show(struct seq_file *m, void *v);
/* Appraise integrity measurements */
#define IMA_APPRAISE_ENFORCE 0x01
@ -250,17 +255,12 @@ static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
{
return -EINVAL;
}
#endif /* CONFIG_IMA_LSM_RULES */
#ifdef CONFIG_IMA_TRUSTED_KEYRING
static inline int ima_init_keyring(const unsigned int id)
{
return integrity_init_keyring(id);
}
#else
static inline int ima_init_keyring(const unsigned int id)
{
return 0;
}
#endif /* CONFIG_IMA_TRUSTED_KEYRING */
#endif
#ifdef CONFIG_IMA_READ_POLICY
#define POLICY_FILE_FLAGS (S_IWUSR | S_IRUSR)
#else
#define POLICY_FILE_FLAGS S_IWUSR
#endif /* CONFIG_IMA_WRITE_POLICY */
#endif /* __LINUX_IMA_H */

View file

@ -25,6 +25,8 @@
#include "ima.h"
static DEFINE_MUTEX(ima_write_mutex);
static int valid_policy = 1;
#define TMPBUFLEN 12
static ssize_t ima_show_htable_value(char __user *buf, size_t count,
@ -261,6 +263,11 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
{
char *data = NULL;
ssize_t result;
int res;
res = mutex_lock_interruptible(&ima_write_mutex);
if (res)
return res;
if (datalen >= PAGE_SIZE)
datalen = PAGE_SIZE - 1;
@ -286,6 +293,8 @@ out:
if (result < 0)
valid_policy = 0;
kfree(data);
mutex_unlock(&ima_write_mutex);
return result;
}
@ -302,14 +311,31 @@ enum ima_fs_flags {
static unsigned long ima_fs_flags;
#ifdef CONFIG_IMA_READ_POLICY
static const struct seq_operations ima_policy_seqops = {
.start = ima_policy_start,
.next = ima_policy_next,
.stop = ima_policy_stop,
.show = ima_policy_show,
};
#endif
/*
* ima_open_policy: sequentialize access to the policy file
*/
static int ima_open_policy(struct inode *inode, struct file *filp)
{
/* No point in being allowed to open it if you aren't going to write */
if (!(filp->f_flags & O_WRONLY))
if (!(filp->f_flags & O_WRONLY)) {
#ifndef CONFIG_IMA_READ_POLICY
return -EACCES;
#else
if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
return -EACCES;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
return seq_open(filp, &ima_policy_seqops);
#endif
}
if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags))
return -EBUSY;
return 0;
@ -326,6 +352,14 @@ static int ima_release_policy(struct inode *inode, struct file *file)
{
const char *cause = valid_policy ? "completed" : "failed";
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
return 0;
if (valid_policy && ima_check_policy() < 0) {
cause = "failed";
valid_policy = 0;
}
pr_info("IMA: policy update %s\n", cause);
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
"policy_update", cause, !valid_policy, 0);
@ -336,15 +370,21 @@ static int ima_release_policy(struct inode *inode, struct file *file)
clear_bit(IMA_FS_BUSY, &ima_fs_flags);
return 0;
}
ima_update_policy();
#ifndef CONFIG_IMA_WRITE_POLICY
securityfs_remove(ima_policy);
ima_policy = NULL;
#else
clear_bit(IMA_FS_BUSY, &ima_fs_flags);
#endif
return 0;
}
static const struct file_operations ima_measure_policy_ops = {
.open = ima_open_policy,
.write = ima_write_policy,
.read = seq_read,
.release = ima_release_policy,
.llseek = generic_file_llseek,
};
@ -382,8 +422,7 @@ int __init ima_fs_init(void)
if (IS_ERR(violations))
goto out;
ima_policy = securityfs_create_file("policy",
S_IWUSR,
ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS,
ima_dir, NULL,
&ima_measure_policy_ops);
if (IS_ERR(ima_policy))

View file

@ -116,7 +116,7 @@ int __init ima_init(void)
if (!ima_used_chip)
pr_info("No TPM chip found, activating TPM-bypass!\n");
rc = ima_init_keyring(INTEGRITY_KEYRING_IMA);
rc = integrity_init_keyring(INTEGRITY_KEYRING_IMA);
if (rc)
return rc;

View file

@ -0,0 +1,55 @@
/*
* Copyright (C) 2015 Juniper Networks, Inc.
*
* Author:
* Petko Manolov <petko.manolov@konsulko.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/export.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/cred.h>
#include <linux/err.h>
#include <linux/init.h>
#include <keys/asymmetric-type.h>
struct key *ima_mok_keyring;
struct key *ima_blacklist_keyring;
/*
* Allocate the IMA MOK and blacklist keyrings
*/
__init int ima_mok_init(void)
{
pr_notice("Allocating IMA MOK and blacklist keyrings.\n");
ima_mok_keyring = keyring_alloc(".ima_mok",
KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_WRITE | KEY_USR_SEARCH,
KEY_ALLOC_NOT_IN_QUOTA, NULL);
ima_blacklist_keyring = keyring_alloc(".ima_blacklist",
KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_WRITE | KEY_USR_SEARCH,
KEY_ALLOC_NOT_IN_QUOTA, NULL);
if (IS_ERR(ima_mok_keyring) || IS_ERR(ima_blacklist_keyring))
panic("Can't allocate IMA MOK or blacklist keyrings.");
set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_mok_keyring->flags);
set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_blacklist_keyring->flags);
set_bit(KEY_FLAG_KEEP, &ima_blacklist_keyring->flags);
return 0;
}
device_initcall(ima_mok_init);

View file

@ -16,7 +16,9 @@
#include <linux/magic.h>
#include <linux/parser.h>
#include <linux/slab.h>
#include <linux/rculist.h>
#include <linux/genhd.h>
#include <linux/seq_file.h>
#include "ima.h"
@ -38,6 +40,7 @@
#define AUDIT 0x0040
int ima_policy_flag;
static int temp_ima_appraise;
#define MAX_LSM_RULES 6
enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
@ -135,11 +138,11 @@ static struct ima_rule_entry default_appraise_rules[] = {
static LIST_HEAD(ima_default_rules);
static LIST_HEAD(ima_policy_rules);
static LIST_HEAD(ima_temp_rules);
static struct list_head *ima_rules;
static DEFINE_MUTEX(ima_rules_mutex);
static int ima_policy __initdata;
static int __init default_measure_policy_setup(char *str)
{
if (ima_policy)
@ -171,21 +174,18 @@ static int __init default_appraise_policy_setup(char *str)
__setup("ima_appraise_tcb", default_appraise_policy_setup);
/*
* Although the IMA policy does not change, the LSM policy can be
* reloaded, leaving the IMA LSM based rules referring to the old,
* stale LSM policy.
*
* Update the IMA LSM based rules to reflect the reloaded LSM policy.
* We assume the rules still exist; and BUG_ON() if they don't.
* The LSM policy can be reloaded, leaving the IMA LSM based rules referring
* to the old, stale LSM policy. Update the IMA LSM based rules to reflect
* the reloaded LSM policy. We assume the rules still exist; and BUG_ON() if
* they don't.
*/
static void ima_lsm_update_rules(void)
{
struct ima_rule_entry *entry, *tmp;
struct ima_rule_entry *entry;
int result;
int i;
mutex_lock(&ima_rules_mutex);
list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
list_for_each_entry(entry, &ima_policy_rules, list) {
for (i = 0; i < MAX_LSM_RULES; i++) {
if (!entry->lsm[i].rule)
continue;
@ -196,7 +196,6 @@ static void ima_lsm_update_rules(void)
BUG_ON(!entry->lsm[i].rule);
}
}
mutex_unlock(&ima_rules_mutex);
}
/**
@ -319,9 +318,9 @@ static int get_subaction(struct ima_rule_entry *rule, int func)
* Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
* conditions.
*
* (There is no need for locking when walking the policy list,
* as elements in the list are never deleted, nor does the list
* change.)
* Since the IMA policy may be updated multiple times we need to lock the
* list when walking it. Reads are many orders of magnitude more numerous
* than writes so ima_match_policy() is classical RCU candidate.
*/
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
int flags)
@ -329,7 +328,8 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
struct ima_rule_entry *entry;
int action = 0, actmask = flags | (flags << 1);
list_for_each_entry(entry, ima_rules, list) {
rcu_read_lock();
list_for_each_entry_rcu(entry, ima_rules, list) {
if (!(entry->action & actmask))
continue;
@ -351,6 +351,7 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
if (!actmask)
break;
}
rcu_read_unlock();
return action;
}
@ -365,12 +366,12 @@ void ima_update_policy_flag(void)
{
struct ima_rule_entry *entry;
ima_policy_flag = 0;
list_for_each_entry(entry, ima_rules, list) {
if (entry->action & IMA_DO_MASK)
ima_policy_flag |= entry->action;
}
ima_appraise |= temp_ima_appraise;
if (!ima_appraise)
ima_policy_flag &= ~IMA_APPRAISE;
}
@ -415,16 +416,48 @@ void __init ima_init_policy(void)
ima_rules = &ima_default_rules;
}
/* Make sure we have a valid policy, at least containing some rules. */
int ima_check_policy()
{
if (list_empty(&ima_temp_rules))
return -EINVAL;
return 0;
}
/**
* ima_update_policy - update default_rules with new measure rules
*
* Called on file .release to update the default rules with a complete new
* policy. Once updated, the policy is locked, no additional rules can be
* added to the policy.
* policy. What we do here is to splice ima_policy_rules and ima_temp_rules so
* they make a queue. The policy may be updated multiple times and this is the
* RCU updater.
*
* Policy rules are never deleted so ima_policy_flag gets zeroed only once when
* we switch from the default policy to user defined.
*/
void ima_update_policy(void)
{
ima_rules = &ima_policy_rules;
struct list_head *first, *last, *policy;
/* append current policy with the new rules */
first = (&ima_temp_rules)->next;
last = (&ima_temp_rules)->prev;
policy = &ima_policy_rules;
synchronize_rcu();
last->next = policy;
rcu_assign_pointer(list_next_rcu(policy->prev), first);
first->prev = policy->prev;
policy->prev = last;
/* prepare for the next policy rules addition */
INIT_LIST_HEAD(&ima_temp_rules);
if (ima_rules != policy) {
ima_policy_flag = 0;
ima_rules = policy;
}
ima_update_policy_flag();
}
@ -436,8 +469,8 @@ enum {
Opt_obj_user, Opt_obj_role, Opt_obj_type,
Opt_subj_user, Opt_subj_role, Opt_subj_type,
Opt_func, Opt_mask, Opt_fsmagic,
Opt_uid, Opt_euid, Opt_fowner,
Opt_appraise_type, Opt_fsuuid, Opt_permit_directio
Opt_fsuuid, Opt_uid, Opt_euid, Opt_fowner,
Opt_appraise_type, Opt_permit_directio
};
static match_table_t policy_tokens = {
@ -734,9 +767,9 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
if (!result && (entry->action == UNKNOWN))
result = -EINVAL;
else if (entry->func == MODULE_CHECK)
ima_appraise |= IMA_APPRAISE_MODULES;
temp_ima_appraise |= IMA_APPRAISE_MODULES;
else if (entry->func == FIRMWARE_CHECK)
ima_appraise |= IMA_APPRAISE_FIRMWARE;
temp_ima_appraise |= IMA_APPRAISE_FIRMWARE;
audit_log_format(ab, "res=%d", !result);
audit_log_end(ab);
return result;
@ -746,7 +779,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
* ima_parse_add_rule - add a rule to ima_policy_rules
* @rule - ima measurement policy rule
*
* Uses a mutex to protect the policy list from multiple concurrent writers.
* Avoid locking by allowing just one writer at a time in ima_write_policy()
* Returns the length of the rule parsed, an error code on failure
*/
ssize_t ima_parse_add_rule(char *rule)
@ -782,26 +815,230 @@ ssize_t ima_parse_add_rule(char *rule)
return result;
}
mutex_lock(&ima_rules_mutex);
list_add_tail(&entry->list, &ima_policy_rules);
mutex_unlock(&ima_rules_mutex);
list_add_tail(&entry->list, &ima_temp_rules);
return len;
}
/* ima_delete_rules called to cleanup invalid policy */
/**
* ima_delete_rules() called to cleanup invalid in-flight policy.
* We don't need locking as we operate on the temp list, which is
* different from the active one. There is also only one user of
* ima_delete_rules() at a time.
*/
void ima_delete_rules(void)
{
struct ima_rule_entry *entry, *tmp;
int i;
mutex_lock(&ima_rules_mutex);
list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
temp_ima_appraise = 0;
list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) {
for (i = 0; i < MAX_LSM_RULES; i++)
kfree(entry->lsm[i].args_p);
list_del(&entry->list);
kfree(entry);
}
mutex_unlock(&ima_rules_mutex);
}
#ifdef CONFIG_IMA_READ_POLICY
enum {
mask_exec = 0, mask_write, mask_read, mask_append
};
static char *mask_tokens[] = {
"MAY_EXEC",
"MAY_WRITE",
"MAY_READ",
"MAY_APPEND"
};
enum {
func_file = 0, func_mmap, func_bprm,
func_module, func_firmware, func_post
};
static char *func_tokens[] = {
"FILE_CHECK",
"MMAP_CHECK",
"BPRM_CHECK",
"MODULE_CHECK",
"FIRMWARE_CHECK",
"POST_SETATTR"
};
void *ima_policy_start(struct seq_file *m, loff_t *pos)
{
loff_t l = *pos;
struct ima_rule_entry *entry;
rcu_read_lock();
list_for_each_entry_rcu(entry, ima_rules, list) {
if (!l--) {
rcu_read_unlock();
return entry;
}
}
rcu_read_unlock();
return NULL;
}
void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos)
{
struct ima_rule_entry *entry = v;
rcu_read_lock();
entry = list_entry_rcu(entry->list.next, struct ima_rule_entry, list);
rcu_read_unlock();
(*pos)++;
return (&entry->list == ima_rules) ? NULL : entry;
}
void ima_policy_stop(struct seq_file *m, void *v)
{
}
#define pt(token) policy_tokens[token + Opt_err].pattern
#define mt(token) mask_tokens[token]
#define ft(token) func_tokens[token]
int ima_policy_show(struct seq_file *m, void *v)
{
struct ima_rule_entry *entry = v;
int i = 0;
char tbuf[64] = {0,};
rcu_read_lock();
if (entry->action & MEASURE)
seq_puts(m, pt(Opt_measure));
if (entry->action & DONT_MEASURE)
seq_puts(m, pt(Opt_dont_measure));
if (entry->action & APPRAISE)
seq_puts(m, pt(Opt_appraise));
if (entry->action & DONT_APPRAISE)
seq_puts(m, pt(Opt_dont_appraise));
if (entry->action & AUDIT)
seq_puts(m, pt(Opt_audit));
seq_puts(m, " ");
if (entry->flags & IMA_FUNC) {
switch (entry->func) {
case FILE_CHECK:
seq_printf(m, pt(Opt_func), ft(func_file));
break;
case MMAP_CHECK:
seq_printf(m, pt(Opt_func), ft(func_mmap));
break;
case BPRM_CHECK:
seq_printf(m, pt(Opt_func), ft(func_bprm));
break;
case MODULE_CHECK:
seq_printf(m, pt(Opt_func), ft(func_module));
break;
case FIRMWARE_CHECK:
seq_printf(m, pt(Opt_func), ft(func_firmware));
break;
case POST_SETATTR:
seq_printf(m, pt(Opt_func), ft(func_post));
break;
default:
snprintf(tbuf, sizeof(tbuf), "%d", entry->func);
seq_printf(m, pt(Opt_func), tbuf);
break;
}
seq_puts(m, " ");
}
if (entry->flags & IMA_MASK) {
if (entry->mask & MAY_EXEC)
seq_printf(m, pt(Opt_mask), mt(mask_exec));
if (entry->mask & MAY_WRITE)
seq_printf(m, pt(Opt_mask), mt(mask_write));
if (entry->mask & MAY_READ)
seq_printf(m, pt(Opt_mask), mt(mask_read));
if (entry->mask & MAY_APPEND)
seq_printf(m, pt(Opt_mask), mt(mask_append));
seq_puts(m, " ");
}
if (entry->flags & IMA_FSMAGIC) {
snprintf(tbuf, sizeof(tbuf), "0x%lx", entry->fsmagic);
seq_printf(m, pt(Opt_fsmagic), tbuf);
seq_puts(m, " ");
}
if (entry->flags & IMA_FSUUID) {
seq_puts(m, "fsuuid=");
for (i = 0; i < ARRAY_SIZE(entry->fsuuid); ++i) {
switch (i) {
case 4:
case 6:
case 8:
case 10:
seq_puts(m, "-");
}
seq_printf(m, "%x", entry->fsuuid[i]);
}
seq_puts(m, " ");
}
if (entry->flags & IMA_UID) {
snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid));
seq_printf(m, pt(Opt_uid), tbuf);
seq_puts(m, " ");
}
if (entry->flags & IMA_EUID) {
snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid));
seq_printf(m, pt(Opt_euid), tbuf);
seq_puts(m, " ");
}
if (entry->flags & IMA_FOWNER) {
snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner));
seq_printf(m, pt(Opt_fowner), tbuf);
seq_puts(m, " ");
}
for (i = 0; i < MAX_LSM_RULES; i++) {
if (entry->lsm[i].rule) {
switch (i) {
case LSM_OBJ_USER:
seq_printf(m, pt(Opt_obj_user),
(char *)entry->lsm[i].args_p);
break;
case LSM_OBJ_ROLE:
seq_printf(m, pt(Opt_obj_role),
(char *)entry->lsm[i].args_p);
break;
case LSM_OBJ_TYPE:
seq_printf(m, pt(Opt_obj_type),
(char *)entry->lsm[i].args_p);
break;
case LSM_SUBJ_USER:
seq_printf(m, pt(Opt_subj_user),
(char *)entry->lsm[i].args_p);
break;
case LSM_SUBJ_ROLE:
seq_printf(m, pt(Opt_subj_role),
(char *)entry->lsm[i].args_p);
break;
case LSM_SUBJ_TYPE:
seq_printf(m, pt(Opt_subj_type),
(char *)entry->lsm[i].args_p);
break;
}
}
}
if (entry->flags & IMA_DIGSIG_REQUIRED)
seq_puts(m, "appraise_type=imasig ");
if (entry->flags & IMA_PERMIT_DIRECTIO)
seq_puts(m, "permit_directio ");
rcu_read_unlock();
seq_puts(m, "\n");
return 0;
}
#endif /* CONFIG_IMA_READ_POLICY */

View file

@ -125,8 +125,8 @@ int integrity_kernel_read(struct file *file, loff_t offset,
int __init integrity_read_file(const char *path, char **data);
#define INTEGRITY_KEYRING_EVM 0
#define INTEGRITY_KEYRING_MODULE 1
#define INTEGRITY_KEYRING_IMA 2
#define INTEGRITY_KEYRING_IMA 1
#define INTEGRITY_KEYRING_MODULE 2
#define INTEGRITY_KEYRING_MAX 3
#ifdef CONFIG_INTEGRITY_SIGNATURE
@ -149,7 +149,6 @@ static inline int integrity_init_keyring(const unsigned int id)
{
return 0;
}
#endif /* CONFIG_INTEGRITY_SIGNATURE */
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
@ -171,6 +170,14 @@ static inline void ima_load_x509(void)
}
#endif
#ifdef CONFIG_EVM_LOAD_X509
void __init evm_load_x509(void);
#else
static inline void evm_load_x509(void)
{
}
#endif
#ifdef CONFIG_INTEGRITY_AUDIT
/* declarations */
void integrity_audit_msg(int audit_msgno, struct inode *inode,

View file

@ -429,8 +429,12 @@ static int __key_instantiate_and_link(struct key *key,
awaken = 1;
/* and link it into the destination keyring */
if (keyring)
if (keyring) {
if (test_bit(KEY_FLAG_KEEP, &keyring->flags))
set_bit(KEY_FLAG_KEEP, &key->flags);
__key_link(key, _edit);
}
/* disable the authorisation key */
if (authkey)

View file

@ -358,11 +358,14 @@ error:
* and any links to the key will be automatically garbage collected after a
* certain amount of time (/proc/sys/kernel/keys/gc_delay).
*
* Keys with KEY_FLAG_KEEP set should not be revoked.
*
* If successful, 0 is returned.
*/
long keyctl_revoke_key(key_serial_t id)
{
key_ref_t key_ref;
struct key *key;
long ret;
key_ref = lookup_user_key(id, 0, KEY_NEED_WRITE);
@ -377,8 +380,13 @@ long keyctl_revoke_key(key_serial_t id)
}
}
key_revoke(key_ref_to_ptr(key_ref));
ret = 0;
key = key_ref_to_ptr(key_ref);
if (test_bit(KEY_FLAG_KEEP, &key->flags))
return -EPERM;
else {
key_revoke(key);
ret = 0;
}
key_ref_put(key_ref);
error:
@ -392,11 +400,14 @@ error:
* The key and any links to the key will be automatically garbage collected
* immediately.
*
* Keys with KEY_FLAG_KEEP set should not be invalidated.
*
* If successful, 0 is returned.
*/
long keyctl_invalidate_key(key_serial_t id)
{
key_ref_t key_ref;
struct key *key;
long ret;
kenter("%d", id);
@ -420,8 +431,13 @@ long keyctl_invalidate_key(key_serial_t id)
}
invalidate:
key_invalidate(key_ref_to_ptr(key_ref));
ret = 0;
key = key_ref_to_ptr(key_ref);
if (test_bit(KEY_FLAG_KEEP, &key->flags))
ret = -EPERM;
else {
key_invalidate(key);
ret = 0;
}
error_put:
key_ref_put(key_ref);
error:
@ -433,12 +449,13 @@ error:
* Clear the specified keyring, creating an empty process keyring if one of the
* special keyring IDs is used.
*
* The keyring must grant the caller Write permission for this to work. If
* successful, 0 will be returned.
* The keyring must grant the caller Write permission and not have
* KEY_FLAG_KEEP set for this to work. If successful, 0 will be returned.
*/
long keyctl_keyring_clear(key_serial_t ringid)
{
key_ref_t keyring_ref;
struct key *keyring;
long ret;
keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
@ -460,7 +477,11 @@ long keyctl_keyring_clear(key_serial_t ringid)
}
clear:
ret = keyring_clear(key_ref_to_ptr(keyring_ref));
keyring = key_ref_to_ptr(keyring_ref);
if (test_bit(KEY_FLAG_KEEP, &keyring->flags))
ret = -EPERM;
else
ret = keyring_clear(keyring);
error_put:
key_ref_put(keyring_ref);
error:
@ -511,11 +532,14 @@ error:
* itself need not grant the caller anything. If the last link to a key is
* removed then that key will be scheduled for destruction.
*
* Keys or keyrings with KEY_FLAG_KEEP set should not be unlinked.
*
* If successful, 0 will be returned.
*/
long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
{
key_ref_t keyring_ref, key_ref;
struct key *keyring, *key;
long ret;
keyring_ref = lookup_user_key(ringid, 0, KEY_NEED_WRITE);
@ -530,7 +554,13 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
goto error2;
}
ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));
keyring = key_ref_to_ptr(keyring_ref);
key = key_ref_to_ptr(key_ref);
if (test_bit(KEY_FLAG_KEEP, &keyring->flags) &&
test_bit(KEY_FLAG_KEEP, &key->flags))
ret = -EPERM;
else
ret = key_unlink(keyring, key);
key_ref_put(key_ref);
error2:
@ -1289,6 +1319,8 @@ error:
* the current time. The key and any links to the key will be automatically
* garbage collected after the timeout expires.
*
* Keys with KEY_FLAG_KEEP set should not be timed out.
*
* If successful, 0 is returned.
*/
long keyctl_set_timeout(key_serial_t id, unsigned timeout)
@ -1320,10 +1352,14 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
okay:
key = key_ref_to_ptr(key_ref);
key_set_timeout(key, timeout);
if (test_bit(KEY_FLAG_KEEP, &key->flags))
ret = -EPERM;
else {
key_set_timeout(key, timeout);
ret = 0;
}
key_put(key);
ret = 0;
error:
return ret;
}