mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 10:40:53 +07:00
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity into next
This commit is contained in:
commit
3cb92fe481
@ -321,6 +321,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
|
|||||||
goto error_free_cert;
|
goto error_free_cert;
|
||||||
} else if (!prep->trusted) {
|
} else if (!prep->trusted) {
|
||||||
ret = x509_validate_trust(cert, get_system_trusted_keyring());
|
ret = x509_validate_trust(cert, get_system_trusted_keyring());
|
||||||
|
if (ret)
|
||||||
|
ret = x509_validate_trust(cert, get_ima_mok_keyring());
|
||||||
if (!ret)
|
if (!ret)
|
||||||
prep->trusted = 1;
|
prep->trusted = 1;
|
||||||
}
|
}
|
||||||
|
@ -35,4 +35,28 @@ extern int system_verify_data(const void *data, unsigned long len,
|
|||||||
enum key_being_used_for usage);
|
enum key_being_used_for usage);
|
||||||
#endif
|
#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 */
|
#endif /* _KEYS_SYSTEM_KEYRING_H */
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
struct integrity_iint_cache;
|
struct integrity_iint_cache;
|
||||||
|
|
||||||
#ifdef CONFIG_EVM
|
#ifdef CONFIG_EVM
|
||||||
|
extern int evm_set_key(void *key, size_t keylen);
|
||||||
extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
|
extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
|
||||||
const char *xattr_name,
|
const char *xattr_name,
|
||||||
void *xattr_value,
|
void *xattr_value,
|
||||||
@ -42,6 +43,12 @@ static inline int posix_xattr_acl(const char *xattrname)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
static inline int evm_set_key(void *key, size_t keylen)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
#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,
|
||||||
const char *xattr_name,
|
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_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_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_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 key type and key description string
|
||||||
* - the desc is used to match a key against search criteria
|
* - 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
|
This option enables digital signature verification using
|
||||||
asymmetric keys.
|
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
|
config INTEGRITY_AUDIT
|
||||||
bool "Enables integrity auditing support "
|
bool "Enables integrity auditing support "
|
||||||
depends on AUDIT
|
depends on AUDIT
|
||||||
|
@ -24,15 +24,22 @@
|
|||||||
static struct key *keyring[INTEGRITY_KEYRING_MAX];
|
static struct key *keyring[INTEGRITY_KEYRING_MAX];
|
||||||
|
|
||||||
static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
|
static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
|
||||||
|
#ifndef CONFIG_INTEGRITY_TRUSTED_KEYRING
|
||||||
"_evm",
|
"_evm",
|
||||||
"_module",
|
|
||||||
#ifndef CONFIG_IMA_TRUSTED_KEYRING
|
|
||||||
"_ima",
|
"_ima",
|
||||||
#else
|
#else
|
||||||
|
".evm",
|
||||||
".ima",
|
".ima",
|
||||||
#endif
|
#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,
|
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
|
||||||
const char *digest, int digestlen)
|
const char *digest, int digestlen)
|
||||||
{
|
{
|
||||||
@ -68,6 +75,9 @@ int __init integrity_init_keyring(const unsigned int id)
|
|||||||
const struct cred *cred = current_cred();
|
const struct cred *cred = current_cred();
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
if (!init_keyring)
|
||||||
|
return 0;
|
||||||
|
|
||||||
keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
|
keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
|
||||||
KGIDT_INIT(0), cred,
|
KGIDT_INIT(0), cred,
|
||||||
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <linux/key-type.h>
|
#include <linux/key-type.h>
|
||||||
#include <crypto/public_key.h>
|
#include <crypto/public_key.h>
|
||||||
#include <keys/asymmetric-type.h>
|
#include <keys/asymmetric-type.h>
|
||||||
|
#include <keys/system_keyring.h>
|
||||||
|
|
||||||
#include "integrity.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);
|
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) {
|
if (keyring) {
|
||||||
/* search in specific keyring */
|
/* search in specific keyring */
|
||||||
key_ref_t kref;
|
key_ref_t kref;
|
||||||
|
|
||||||
kref = keyring_search(make_key_ref(keyring, 1),
|
kref = keyring_search(make_key_ref(keyring, 1),
|
||||||
&key_type_asymmetric, name);
|
&key_type_asymmetric, name);
|
||||||
if (IS_ERR(kref))
|
if (IS_ERR(kref))
|
||||||
|
@ -42,3 +42,20 @@ config EVM_EXTRA_SMACK_XATTRS
|
|||||||
additional info to the calculation, requires existing EVM
|
additional info to the calculation, requires existing EVM
|
||||||
labeled file systems to be relabeled.
|
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"
|
#include "../integrity.h"
|
||||||
|
|
||||||
|
#define EVM_INIT_HMAC 0x0001
|
||||||
|
#define EVM_INIT_X509 0x0002
|
||||||
|
|
||||||
extern int evm_initialized;
|
extern int evm_initialized;
|
||||||
extern char *evm_hmac;
|
extern char *evm_hmac;
|
||||||
extern char *evm_hash;
|
extern char *evm_hash;
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/crypto.h>
|
#include <linux/crypto.h>
|
||||||
#include <linux/xattr.h>
|
#include <linux/xattr.h>
|
||||||
|
#include <linux/evm.h>
|
||||||
#include <keys/encrypted-type.h>
|
#include <keys/encrypted-type.h>
|
||||||
#include <crypto/hash.h>
|
#include <crypto/hash.h>
|
||||||
#include "evm.h"
|
#include "evm.h"
|
||||||
@ -32,6 +33,44 @@ struct crypto_shash *hash_tfm;
|
|||||||
|
|
||||||
static DEFINE_MUTEX(mutex);
|
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)
|
static struct shash_desc *init_desc(char type)
|
||||||
{
|
{
|
||||||
long rc;
|
long rc;
|
||||||
@ -40,6 +79,10 @@ static struct shash_desc *init_desc(char type)
|
|||||||
struct shash_desc *desc;
|
struct shash_desc *desc;
|
||||||
|
|
||||||
if (type == EVM_XATTR_HMAC) {
|
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;
|
tfm = &hmac_tfm;
|
||||||
algo = evm_hmac;
|
algo = evm_hmac;
|
||||||
} else {
|
} else {
|
||||||
@ -240,7 +283,7 @@ int evm_init_key(void)
|
|||||||
{
|
{
|
||||||
struct key *evm_key;
|
struct key *evm_key;
|
||||||
struct encrypted_key_payload *ekp;
|
struct encrypted_key_payload *ekp;
|
||||||
int rc = 0;
|
int rc;
|
||||||
|
|
||||||
evm_key = request_key(&key_type_encrypted, EVMKEY, NULL);
|
evm_key = request_key(&key_type_encrypted, EVMKEY, NULL);
|
||||||
if (IS_ERR(evm_key))
|
if (IS_ERR(evm_key))
|
||||||
@ -248,12 +291,9 @@ int evm_init_key(void)
|
|||||||
|
|
||||||
down_read(&evm_key->sem);
|
down_read(&evm_key->sem);
|
||||||
ekp = evm_key->payload.data[0];
|
ekp = evm_key->payload.data[0];
|
||||||
if (ekp->decrypted_datalen > MAX_KEY_SIZE) {
|
|
||||||
rc = -EINVAL;
|
rc = evm_set_key(ekp->decrypted_data, ekp->decrypted_datalen);
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
memcpy(evmkey, ekp->decrypted_data, ekp->decrypted_datalen);
|
|
||||||
out:
|
|
||||||
/* burn the original key contents */
|
/* burn the original key contents */
|
||||||
memset(ekp->decrypted_data, 0, ekp->decrypted_datalen);
|
memset(ekp->decrypted_data, 0, ekp->decrypted_datalen);
|
||||||
up_read(&evm_key->sem);
|
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);
|
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
|
* evm_inode_post_setxattr - update 'security.evm' to reflect the changes
|
||||||
* @dentry: pointer to the affected dentry
|
* @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)))
|
&& !posix_xattr_acl(xattr_name)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
evm_reset_status(dentry->d_inode);
|
||||||
|
|
||||||
evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
|
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))
|
if (!evm_initialized || !evm_protected_xattr(xattr_name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
evm_reset_status(dentry->d_inode);
|
||||||
|
|
||||||
evm_update_evmxattr(dentry, xattr_name, NULL, 0);
|
evm_update_evmxattr(dentry, xattr_name, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,21 +485,34 @@ int evm_inode_init_security(struct inode *inode,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(evm_inode_init_security);
|
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)
|
static int __init init_evm(void)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
evm_init_config();
|
evm_init_config();
|
||||||
|
|
||||||
|
error = integrity_init_keyring(INTEGRITY_KEYRING_EVM);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
error = evm_init_secfs();
|
error = evm_init_secfs();
|
||||||
if (error < 0) {
|
if (error < 0) {
|
||||||
pr_info("Error registering secfs\n");
|
pr_info("Error registering secfs\n");
|
||||||
goto err;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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)
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
char temp[80];
|
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;
|
return -EPERM;
|
||||||
|
|
||||||
if (count >= sizeof(temp) || count == 0)
|
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))
|
if ((sscanf(temp, "%d", &i) != 1) || (i != 1))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
error = evm_init_key();
|
evm_init_key();
|
||||||
if (!error) {
|
|
||||||
evm_initialized = 1;
|
|
||||||
pr_info("initialized\n");
|
|
||||||
} else
|
|
||||||
pr_err("initialization failed\n");
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,4 +254,5 @@ int __init integrity_read_file(const char *path, char **data)
|
|||||||
void __init integrity_load_keys(void)
|
void __init integrity_load_keys(void)
|
||||||
{
|
{
|
||||||
ima_load_x509();
|
ima_load_x509();
|
||||||
|
evm_load_x509();
|
||||||
}
|
}
|
||||||
|
@ -107,6 +107,27 @@ config IMA_DEFAULT_HASH
|
|||||||
default "sha512" if IMA_DEFAULT_HASH_SHA512
|
default "sha512" if IMA_DEFAULT_HASH_SHA512
|
||||||
default "wp512" if IMA_DEFAULT_HASH_WP512
|
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
|
config IMA_APPRAISE
|
||||||
bool "Appraise integrity measurements"
|
bool "Appraise integrity measurements"
|
||||||
depends on IMA
|
depends on IMA
|
||||||
@ -123,14 +144,35 @@ config IMA_APPRAISE
|
|||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
config IMA_TRUSTED_KEYRING
|
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 IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
|
||||||
depends on INTEGRITY_ASYMMETRIC_KEYS
|
depends on INTEGRITY_ASYMMETRIC_KEYS
|
||||||
|
select INTEGRITY_TRUSTED_KEYRING
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
This option requires that all keys added to the .ima
|
This option requires that all keys added to the .ima
|
||||||
keyring be signed by a key on the system trusted keyring.
|
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
|
config IMA_LOAD_X509
|
||||||
bool "Load X509 certificate onto the '.ima' trusted keyring"
|
bool "Load X509 certificate onto the '.ima' trusted keyring"
|
||||||
depends on 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-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_policy.o ima_template.o ima_template_lib.o
|
||||||
ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.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);
|
void ima_update_policy_flag(void);
|
||||||
ssize_t ima_parse_add_rule(char *);
|
ssize_t ima_parse_add_rule(char *);
|
||||||
void ima_delete_rules(void);
|
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 */
|
/* Appraise integrity measurements */
|
||||||
#define IMA_APPRAISE_ENFORCE 0x01
|
#define IMA_APPRAISE_ENFORCE 0x01
|
||||||
@ -250,17 +255,12 @@ static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
|
|||||||
{
|
{
|
||||||
return -EINVAL;
|
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 /* 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"
|
#include "ima.h"
|
||||||
|
|
||||||
|
static DEFINE_MUTEX(ima_write_mutex);
|
||||||
|
|
||||||
static int valid_policy = 1;
|
static int valid_policy = 1;
|
||||||
#define TMPBUFLEN 12
|
#define TMPBUFLEN 12
|
||||||
static ssize_t ima_show_htable_value(char __user *buf, size_t count,
|
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;
|
char *data = NULL;
|
||||||
ssize_t result;
|
ssize_t result;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = mutex_lock_interruptible(&ima_write_mutex);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
|
||||||
if (datalen >= PAGE_SIZE)
|
if (datalen >= PAGE_SIZE)
|
||||||
datalen = PAGE_SIZE - 1;
|
datalen = PAGE_SIZE - 1;
|
||||||
@ -286,6 +293,8 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
|
|||||||
if (result < 0)
|
if (result < 0)
|
||||||
valid_policy = 0;
|
valid_policy = 0;
|
||||||
kfree(data);
|
kfree(data);
|
||||||
|
mutex_unlock(&ima_write_mutex);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,14 +311,31 @@ enum ima_fs_flags {
|
|||||||
|
|
||||||
static unsigned long 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
|
* ima_open_policy: sequentialize access to the policy file
|
||||||
*/
|
*/
|
||||||
static int ima_open_policy(struct inode *inode, struct file *filp)
|
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;
|
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))
|
if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
return 0;
|
return 0;
|
||||||
@ -326,6 +352,14 @@ static int ima_release_policy(struct inode *inode, struct file *file)
|
|||||||
{
|
{
|
||||||
const char *cause = valid_policy ? "completed" : "failed";
|
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);
|
pr_info("IMA: policy update %s\n", cause);
|
||||||
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
|
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
|
||||||
"policy_update", cause, !valid_policy, 0);
|
"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);
|
clear_bit(IMA_FS_BUSY, &ima_fs_flags);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ima_update_policy();
|
ima_update_policy();
|
||||||
|
#ifndef CONFIG_IMA_WRITE_POLICY
|
||||||
securityfs_remove(ima_policy);
|
securityfs_remove(ima_policy);
|
||||||
ima_policy = NULL;
|
ima_policy = NULL;
|
||||||
|
#else
|
||||||
|
clear_bit(IMA_FS_BUSY, &ima_fs_flags);
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations ima_measure_policy_ops = {
|
static const struct file_operations ima_measure_policy_ops = {
|
||||||
.open = ima_open_policy,
|
.open = ima_open_policy,
|
||||||
.write = ima_write_policy,
|
.write = ima_write_policy,
|
||||||
|
.read = seq_read,
|
||||||
.release = ima_release_policy,
|
.release = ima_release_policy,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
};
|
};
|
||||||
@ -382,8 +422,7 @@ int __init ima_fs_init(void)
|
|||||||
if (IS_ERR(violations))
|
if (IS_ERR(violations))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ima_policy = securityfs_create_file("policy",
|
ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS,
|
||||||
S_IWUSR,
|
|
||||||
ima_dir, NULL,
|
ima_dir, NULL,
|
||||||
&ima_measure_policy_ops);
|
&ima_measure_policy_ops);
|
||||||
if (IS_ERR(ima_policy))
|
if (IS_ERR(ima_policy))
|
||||||
|
@ -116,7 +116,7 @@ int __init ima_init(void)
|
|||||||
if (!ima_used_chip)
|
if (!ima_used_chip)
|
||||||
pr_info("No TPM chip found, activating TPM-bypass!\n");
|
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)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
55
security/integrity/ima/ima_mok.c
Normal file
55
security/integrity/ima/ima_mok.c
Normal 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);
|
@ -16,7 +16,9 @@
|
|||||||
#include <linux/magic.h>
|
#include <linux/magic.h>
|
||||||
#include <linux/parser.h>
|
#include <linux/parser.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/rculist.h>
|
||||||
#include <linux/genhd.h>
|
#include <linux/genhd.h>
|
||||||
|
#include <linux/seq_file.h>
|
||||||
|
|
||||||
#include "ima.h"
|
#include "ima.h"
|
||||||
|
|
||||||
@ -38,6 +40,7 @@
|
|||||||
#define AUDIT 0x0040
|
#define AUDIT 0x0040
|
||||||
|
|
||||||
int ima_policy_flag;
|
int ima_policy_flag;
|
||||||
|
static int temp_ima_appraise;
|
||||||
|
|
||||||
#define MAX_LSM_RULES 6
|
#define MAX_LSM_RULES 6
|
||||||
enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
|
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_default_rules);
|
||||||
static LIST_HEAD(ima_policy_rules);
|
static LIST_HEAD(ima_policy_rules);
|
||||||
|
static LIST_HEAD(ima_temp_rules);
|
||||||
static struct list_head *ima_rules;
|
static struct list_head *ima_rules;
|
||||||
|
|
||||||
static DEFINE_MUTEX(ima_rules_mutex);
|
|
||||||
|
|
||||||
static int ima_policy __initdata;
|
static int ima_policy __initdata;
|
||||||
|
|
||||||
static int __init default_measure_policy_setup(char *str)
|
static int __init default_measure_policy_setup(char *str)
|
||||||
{
|
{
|
||||||
if (ima_policy)
|
if (ima_policy)
|
||||||
@ -171,21 +174,18 @@ static int __init default_appraise_policy_setup(char *str)
|
|||||||
__setup("ima_appraise_tcb", default_appraise_policy_setup);
|
__setup("ima_appraise_tcb", default_appraise_policy_setup);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Although the IMA policy does not change, the LSM policy can be
|
* The LSM policy can be reloaded, leaving the IMA LSM based rules referring
|
||||||
* reloaded, leaving the IMA LSM based rules referring to the old,
|
* to the old, stale LSM policy. Update the IMA LSM based rules to reflect
|
||||||
* stale LSM policy.
|
* the reloaded LSM policy. We assume the rules still exist; and BUG_ON() if
|
||||||
*
|
* they don't.
|
||||||
* 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)
|
static void ima_lsm_update_rules(void)
|
||||||
{
|
{
|
||||||
struct ima_rule_entry *entry, *tmp;
|
struct ima_rule_entry *entry;
|
||||||
int result;
|
int result;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
mutex_lock(&ima_rules_mutex);
|
list_for_each_entry(entry, &ima_policy_rules, list) {
|
||||||
list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
|
|
||||||
for (i = 0; i < MAX_LSM_RULES; i++) {
|
for (i = 0; i < MAX_LSM_RULES; i++) {
|
||||||
if (!entry->lsm[i].rule)
|
if (!entry->lsm[i].rule)
|
||||||
continue;
|
continue;
|
||||||
@ -196,7 +196,6 @@ static void ima_lsm_update_rules(void)
|
|||||||
BUG_ON(!entry->lsm[i].rule);
|
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)
|
* Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
|
||||||
* conditions.
|
* conditions.
|
||||||
*
|
*
|
||||||
* (There is no need for locking when walking the policy list,
|
* Since the IMA policy may be updated multiple times we need to lock the
|
||||||
* as elements in the list are never deleted, nor does the list
|
* list when walking it. Reads are many orders of magnitude more numerous
|
||||||
* change.)
|
* than writes so ima_match_policy() is classical RCU candidate.
|
||||||
*/
|
*/
|
||||||
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
|
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
|
||||||
int flags)
|
int flags)
|
||||||
@ -329,7 +328,8 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
|
|||||||
struct ima_rule_entry *entry;
|
struct ima_rule_entry *entry;
|
||||||
int action = 0, actmask = flags | (flags << 1);
|
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))
|
if (!(entry->action & actmask))
|
||||||
continue;
|
continue;
|
||||||
@ -351,6 +351,7 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
|
|||||||
if (!actmask)
|
if (!actmask)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
@ -365,12 +366,12 @@ void ima_update_policy_flag(void)
|
|||||||
{
|
{
|
||||||
struct ima_rule_entry *entry;
|
struct ima_rule_entry *entry;
|
||||||
|
|
||||||
ima_policy_flag = 0;
|
|
||||||
list_for_each_entry(entry, ima_rules, list) {
|
list_for_each_entry(entry, ima_rules, list) {
|
||||||
if (entry->action & IMA_DO_MASK)
|
if (entry->action & IMA_DO_MASK)
|
||||||
ima_policy_flag |= entry->action;
|
ima_policy_flag |= entry->action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ima_appraise |= temp_ima_appraise;
|
||||||
if (!ima_appraise)
|
if (!ima_appraise)
|
||||||
ima_policy_flag &= ~IMA_APPRAISE;
|
ima_policy_flag &= ~IMA_APPRAISE;
|
||||||
}
|
}
|
||||||
@ -415,16 +416,48 @@ void __init ima_init_policy(void)
|
|||||||
ima_rules = &ima_default_rules;
|
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
|
* ima_update_policy - update default_rules with new measure rules
|
||||||
*
|
*
|
||||||
* Called on file .release to update the default rules with a complete new
|
* 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
|
* policy. What we do here is to splice ima_policy_rules and ima_temp_rules so
|
||||||
* added to the policy.
|
* 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)
|
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();
|
ima_update_policy_flag();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,8 +469,8 @@ enum {
|
|||||||
Opt_obj_user, Opt_obj_role, Opt_obj_type,
|
Opt_obj_user, Opt_obj_role, Opt_obj_type,
|
||||||
Opt_subj_user, Opt_subj_role, Opt_subj_type,
|
Opt_subj_user, Opt_subj_role, Opt_subj_type,
|
||||||
Opt_func, Opt_mask, Opt_fsmagic,
|
Opt_func, Opt_mask, Opt_fsmagic,
|
||||||
Opt_uid, Opt_euid, Opt_fowner,
|
Opt_fsuuid, Opt_uid, Opt_euid, Opt_fowner,
|
||||||
Opt_appraise_type, Opt_fsuuid, Opt_permit_directio
|
Opt_appraise_type, Opt_permit_directio
|
||||||
};
|
};
|
||||||
|
|
||||||
static match_table_t policy_tokens = {
|
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))
|
if (!result && (entry->action == UNKNOWN))
|
||||||
result = -EINVAL;
|
result = -EINVAL;
|
||||||
else if (entry->func == MODULE_CHECK)
|
else if (entry->func == MODULE_CHECK)
|
||||||
ima_appraise |= IMA_APPRAISE_MODULES;
|
temp_ima_appraise |= IMA_APPRAISE_MODULES;
|
||||||
else if (entry->func == FIRMWARE_CHECK)
|
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_format(ab, "res=%d", !result);
|
||||||
audit_log_end(ab);
|
audit_log_end(ab);
|
||||||
return result;
|
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
|
* ima_parse_add_rule - add a rule to ima_policy_rules
|
||||||
* @rule - ima measurement policy rule
|
* @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
|
* Returns the length of the rule parsed, an error code on failure
|
||||||
*/
|
*/
|
||||||
ssize_t ima_parse_add_rule(char *rule)
|
ssize_t ima_parse_add_rule(char *rule)
|
||||||
@ -782,26 +815,230 @@ ssize_t ima_parse_add_rule(char *rule)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&ima_rules_mutex);
|
list_add_tail(&entry->list, &ima_temp_rules);
|
||||||
list_add_tail(&entry->list, &ima_policy_rules);
|
|
||||||
mutex_unlock(&ima_rules_mutex);
|
|
||||||
|
|
||||||
return len;
|
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)
|
void ima_delete_rules(void)
|
||||||
{
|
{
|
||||||
struct ima_rule_entry *entry, *tmp;
|
struct ima_rule_entry *entry, *tmp;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
mutex_lock(&ima_rules_mutex);
|
temp_ima_appraise = 0;
|
||||||
list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
|
list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) {
|
||||||
for (i = 0; i < MAX_LSM_RULES; i++)
|
for (i = 0; i < MAX_LSM_RULES; i++)
|
||||||
kfree(entry->lsm[i].args_p);
|
kfree(entry->lsm[i].args_p);
|
||||||
|
|
||||||
list_del(&entry->list);
|
list_del(&entry->list);
|
||||||
kfree(entry);
|
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);
|
int __init integrity_read_file(const char *path, char **data);
|
||||||
|
|
||||||
#define INTEGRITY_KEYRING_EVM 0
|
#define INTEGRITY_KEYRING_EVM 0
|
||||||
#define INTEGRITY_KEYRING_MODULE 1
|
#define INTEGRITY_KEYRING_IMA 1
|
||||||
#define INTEGRITY_KEYRING_IMA 2
|
#define INTEGRITY_KEYRING_MODULE 2
|
||||||
#define INTEGRITY_KEYRING_MAX 3
|
#define INTEGRITY_KEYRING_MAX 3
|
||||||
|
|
||||||
#ifdef CONFIG_INTEGRITY_SIGNATURE
|
#ifdef CONFIG_INTEGRITY_SIGNATURE
|
||||||
@ -149,7 +149,6 @@ static inline int integrity_init_keyring(const unsigned int id)
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_INTEGRITY_SIGNATURE */
|
#endif /* CONFIG_INTEGRITY_SIGNATURE */
|
||||||
|
|
||||||
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
|
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
|
||||||
@ -171,6 +170,14 @@ static inline void ima_load_x509(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
#ifdef CONFIG_INTEGRITY_AUDIT
|
||||||
/* declarations */
|
/* declarations */
|
||||||
void integrity_audit_msg(int audit_msgno, struct inode *inode,
|
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;
|
awaken = 1;
|
||||||
|
|
||||||
/* and link it into the destination keyring */
|
/* 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);
|
__key_link(key, _edit);
|
||||||
|
}
|
||||||
|
|
||||||
/* disable the authorisation key */
|
/* disable the authorisation key */
|
||||||
if (authkey)
|
if (authkey)
|
||||||
|
@ -358,11 +358,14 @@ long keyctl_update_key(key_serial_t id,
|
|||||||
* and any links to the key will be automatically garbage collected after a
|
* and any links to the key will be automatically garbage collected after a
|
||||||
* certain amount of time (/proc/sys/kernel/keys/gc_delay).
|
* 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.
|
* If successful, 0 is returned.
|
||||||
*/
|
*/
|
||||||
long keyctl_revoke_key(key_serial_t id)
|
long keyctl_revoke_key(key_serial_t id)
|
||||||
{
|
{
|
||||||
key_ref_t key_ref;
|
key_ref_t key_ref;
|
||||||
|
struct key *key;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
key_ref = lookup_user_key(id, 0, KEY_NEED_WRITE);
|
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);
|
||||||
ret = 0;
|
if (test_bit(KEY_FLAG_KEEP, &key->flags))
|
||||||
|
return -EPERM;
|
||||||
|
else {
|
||||||
|
key_revoke(key);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
key_ref_put(key_ref);
|
key_ref_put(key_ref);
|
||||||
error:
|
error:
|
||||||
@ -392,11 +400,14 @@ long keyctl_revoke_key(key_serial_t id)
|
|||||||
* The key and any links to the key will be automatically garbage collected
|
* The key and any links to the key will be automatically garbage collected
|
||||||
* immediately.
|
* immediately.
|
||||||
*
|
*
|
||||||
|
* Keys with KEY_FLAG_KEEP set should not be invalidated.
|
||||||
|
*
|
||||||
* If successful, 0 is returned.
|
* If successful, 0 is returned.
|
||||||
*/
|
*/
|
||||||
long keyctl_invalidate_key(key_serial_t id)
|
long keyctl_invalidate_key(key_serial_t id)
|
||||||
{
|
{
|
||||||
key_ref_t key_ref;
|
key_ref_t key_ref;
|
||||||
|
struct key *key;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
kenter("%d", id);
|
kenter("%d", id);
|
||||||
@ -420,8 +431,13 @@ long keyctl_invalidate_key(key_serial_t id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
invalidate:
|
invalidate:
|
||||||
key_invalidate(key_ref_to_ptr(key_ref));
|
key = key_ref_to_ptr(key_ref);
|
||||||
ret = 0;
|
if (test_bit(KEY_FLAG_KEEP, &key->flags))
|
||||||
|
ret = -EPERM;
|
||||||
|
else {
|
||||||
|
key_invalidate(key);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
error_put:
|
error_put:
|
||||||
key_ref_put(key_ref);
|
key_ref_put(key_ref);
|
||||||
error:
|
error:
|
||||||
@ -433,12 +449,13 @@ long keyctl_invalidate_key(key_serial_t id)
|
|||||||
* Clear the specified keyring, creating an empty process keyring if one of the
|
* Clear the specified keyring, creating an empty process keyring if one of the
|
||||||
* special keyring IDs is used.
|
* special keyring IDs is used.
|
||||||
*
|
*
|
||||||
* The keyring must grant the caller Write permission for this to work. If
|
* The keyring must grant the caller Write permission and not have
|
||||||
* successful, 0 will be returned.
|
* KEY_FLAG_KEEP set for this to work. If successful, 0 will be returned.
|
||||||
*/
|
*/
|
||||||
long keyctl_keyring_clear(key_serial_t ringid)
|
long keyctl_keyring_clear(key_serial_t ringid)
|
||||||
{
|
{
|
||||||
key_ref_t keyring_ref;
|
key_ref_t keyring_ref;
|
||||||
|
struct key *keyring;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
|
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:
|
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:
|
error_put:
|
||||||
key_ref_put(keyring_ref);
|
key_ref_put(keyring_ref);
|
||||||
error:
|
error:
|
||||||
@ -511,11 +532,14 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
|
|||||||
* itself need not grant the caller anything. If the last link to a key is
|
* itself need not grant the caller anything. If the last link to a key is
|
||||||
* removed then that key will be scheduled for destruction.
|
* 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.
|
* If successful, 0 will be returned.
|
||||||
*/
|
*/
|
||||||
long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
|
long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
|
||||||
{
|
{
|
||||||
key_ref_t keyring_ref, key_ref;
|
key_ref_t keyring_ref, key_ref;
|
||||||
|
struct key *keyring, *key;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
keyring_ref = lookup_user_key(ringid, 0, KEY_NEED_WRITE);
|
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;
|
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);
|
key_ref_put(key_ref);
|
||||||
error2:
|
error2:
|
||||||
@ -1289,6 +1319,8 @@ long keyctl_set_reqkey_keyring(int reqkey_defl)
|
|||||||
* the current time. The key and any links to the key will be automatically
|
* the current time. The key and any links to the key will be automatically
|
||||||
* garbage collected after the timeout expires.
|
* garbage collected after the timeout expires.
|
||||||
*
|
*
|
||||||
|
* Keys with KEY_FLAG_KEEP set should not be timed out.
|
||||||
|
*
|
||||||
* If successful, 0 is returned.
|
* If successful, 0 is returned.
|
||||||
*/
|
*/
|
||||||
long keyctl_set_timeout(key_serial_t id, unsigned timeout)
|
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:
|
okay:
|
||||||
key = key_ref_to_ptr(key_ref);
|
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);
|
key_put(key);
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
error:
|
error:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user