Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity into next
This commit is contained in:
Коммит
3cb92fe481
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) |
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -254,4 +254,5 @@ out:
|
|||
void __init integrity_load_keys(void)
|
||||
{
|
||||
ima_load_x509();
|
||||
evm_load_x509();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
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));
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче