Merge tag 'keys-next-20140722' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs into next
This commit is contained in:
@@ -13,7 +13,9 @@
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/key-type.h>
|
||||
#include <linux/digsig.h>
|
||||
|
||||
@@ -24,7 +26,11 @@ static struct key *keyring[INTEGRITY_KEYRING_MAX];
|
||||
static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
|
||||
"_evm",
|
||||
"_module",
|
||||
#ifndef CONFIG_IMA_TRUSTED_KEYRING
|
||||
"_ima",
|
||||
#else
|
||||
".ima",
|
||||
#endif
|
||||
};
|
||||
|
||||
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
|
||||
@@ -56,3 +62,25 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int integrity_init_keyring(const unsigned int id)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
int err = 0;
|
||||
|
||||
keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
|
||||
KGIDT_INIT(0), 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(keyring[id]))
|
||||
set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags);
|
||||
else {
|
||||
err = PTR_ERR(keyring[id]);
|
||||
pr_info("Can't allocate %s keyring (%d)\n",
|
||||
keyring_name[id], err);
|
||||
keyring[id] = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
@@ -123,3 +123,13 @@ config IMA_APPRAISE
|
||||
For more information on integrity appraisal refer to:
|
||||
<http://linux-ima.sourceforge.net>
|
||||
If unsure, say N.
|
||||
|
||||
config IMA_TRUSTED_KEYRING
|
||||
bool "Require all keys on the .ima keyring be signed"
|
||||
depends on IMA_APPRAISE && 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
|
||||
keyring be signed by a key on the system trusted keyring.
|
||||
|
@@ -249,4 +249,16 @@ 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
|
||||
|
@@ -325,8 +325,14 @@ static int __init init_ima(void)
|
||||
|
||||
hash_setup(CONFIG_IMA_DEFAULT_HASH);
|
||||
error = ima_init();
|
||||
if (!error)
|
||||
ima_initialized = 1;
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = ima_init_keyring(INTEGRITY_KEYRING_IMA);
|
||||
if (error)
|
||||
goto out;
|
||||
ima_initialized = 1;
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@@ -124,6 +124,7 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
|
||||
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
|
||||
const char *digest, int digestlen);
|
||||
|
||||
int integrity_init_keyring(const unsigned int id);
|
||||
#else
|
||||
|
||||
static inline int integrity_digsig_verify(const unsigned int id,
|
||||
@@ -133,6 +134,10 @@ static inline int integrity_digsig_verify(const unsigned int id,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int integrity_init_keyring(const unsigned int id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_INTEGRITY_SIGNATURE */
|
||||
|
||||
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
|
||||
|
@@ -34,7 +34,9 @@ MODULE_LICENSE("GPL");
|
||||
struct key_type key_type_big_key = {
|
||||
.name = "big_key",
|
||||
.def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
|
||||
.instantiate = big_key_instantiate,
|
||||
.preparse = big_key_preparse,
|
||||
.free_preparse = big_key_free_preparse,
|
||||
.instantiate = generic_key_instantiate,
|
||||
.match = user_match,
|
||||
.revoke = big_key_revoke,
|
||||
.destroy = big_key_destroy,
|
||||
@@ -43,11 +45,11 @@ struct key_type key_type_big_key = {
|
||||
};
|
||||
|
||||
/*
|
||||
* Instantiate a big key
|
||||
* Preparse a big key
|
||||
*/
|
||||
int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||
int big_key_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
struct path *path = (struct path *)&key->payload.data2;
|
||||
struct path *path = (struct path *)&prep->payload;
|
||||
struct file *file;
|
||||
ssize_t written;
|
||||
size_t datalen = prep->datalen;
|
||||
@@ -58,11 +60,9 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||
goto error;
|
||||
|
||||
/* Set an arbitrary quota */
|
||||
ret = key_payload_reserve(key, 16);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
prep->quotalen = 16;
|
||||
|
||||
key->type_data.x[1] = datalen;
|
||||
prep->type_data[1] = (void *)(unsigned long)datalen;
|
||||
|
||||
if (datalen > BIG_KEY_FILE_THRESHOLD) {
|
||||
/* Create a shmem file to store the data in. This will permit the data
|
||||
@@ -73,7 +73,7 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||
file = shmem_kernel_file_setup("", datalen, 0);
|
||||
if (IS_ERR(file)) {
|
||||
ret = PTR_ERR(file);
|
||||
goto err_quota;
|
||||
goto error;
|
||||
}
|
||||
|
||||
written = kernel_write(file, prep->data, prep->datalen, 0);
|
||||
@@ -93,23 +93,32 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||
} else {
|
||||
/* Just store the data in a buffer */
|
||||
void *data = kmalloc(datalen, GFP_KERNEL);
|
||||
if (!data) {
|
||||
ret = -ENOMEM;
|
||||
goto err_quota;
|
||||
}
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
key->payload.data = memcpy(data, prep->data, prep->datalen);
|
||||
prep->payload[0] = memcpy(data, prep->data, prep->datalen);
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_fput:
|
||||
fput(file);
|
||||
err_quota:
|
||||
key_payload_reserve(key, 0);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear preparsement.
|
||||
*/
|
||||
void big_key_free_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
if (prep->datalen > BIG_KEY_FILE_THRESHOLD) {
|
||||
struct path *path = (struct path *)&prep->payload;
|
||||
path_put(path);
|
||||
} else {
|
||||
kfree(prep->payload[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dispose of the links from a revoked keyring
|
||||
* - called with the key sem write-locked
|
||||
|
@@ -811,7 +811,7 @@ static int encrypted_instantiate(struct key *key,
|
||||
goto out;
|
||||
}
|
||||
|
||||
rcu_assign_keypointer(key, epayload);
|
||||
prep->payload[0] = epayload;
|
||||
out:
|
||||
kfree(datablob);
|
||||
return ret;
|
||||
|
@@ -437,6 +437,11 @@ static int __key_instantiate_and_link(struct key *key,
|
||||
/* disable the authorisation key */
|
||||
if (authkey)
|
||||
key_revoke(authkey);
|
||||
|
||||
if (prep->expiry != TIME_T_MAX) {
|
||||
key->expiry = prep->expiry;
|
||||
key_schedule_gc(prep->expiry + key_gc_delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,6 +484,7 @@ int key_instantiate_and_link(struct key *key,
|
||||
prep.data = data;
|
||||
prep.datalen = datalen;
|
||||
prep.quotalen = key->type->def_datalen;
|
||||
prep.expiry = TIME_T_MAX;
|
||||
if (key->type->preparse) {
|
||||
ret = key->type->preparse(&prep);
|
||||
if (ret < 0)
|
||||
@@ -488,7 +494,7 @@ int key_instantiate_and_link(struct key *key,
|
||||
if (keyring) {
|
||||
ret = __key_link_begin(keyring, &key->index_key, &edit);
|
||||
if (ret < 0)
|
||||
goto error_free_preparse;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit);
|
||||
@@ -496,10 +502,9 @@ int key_instantiate_and_link(struct key *key,
|
||||
if (keyring)
|
||||
__key_link_end(keyring, &key->index_key, edit);
|
||||
|
||||
error_free_preparse:
|
||||
error:
|
||||
if (key->type->preparse)
|
||||
key->type->free_preparse(&prep);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -811,11 +816,12 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
|
||||
prep.datalen = plen;
|
||||
prep.quotalen = index_key.type->def_datalen;
|
||||
prep.trusted = flags & KEY_ALLOC_TRUSTED;
|
||||
prep.expiry = TIME_T_MAX;
|
||||
if (index_key.type->preparse) {
|
||||
ret = index_key.type->preparse(&prep);
|
||||
if (ret < 0) {
|
||||
key_ref = ERR_PTR(ret);
|
||||
goto error_put_type;
|
||||
goto error_free_prep;
|
||||
}
|
||||
if (!index_key.description)
|
||||
index_key.description = prep.description;
|
||||
@@ -941,6 +947,7 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
|
||||
prep.data = payload;
|
||||
prep.datalen = plen;
|
||||
prep.quotalen = key->type->def_datalen;
|
||||
prep.expiry = TIME_T_MAX;
|
||||
if (key->type->preparse) {
|
||||
ret = key->type->preparse(&prep);
|
||||
if (ret < 0)
|
||||
@@ -956,9 +963,9 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
|
||||
|
||||
up_write(&key->sem);
|
||||
|
||||
error:
|
||||
if (key->type->preparse)
|
||||
key->type->free_preparse(&prep);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(key_update);
|
||||
@@ -1023,6 +1030,38 @@ void key_invalidate(struct key *key)
|
||||
}
|
||||
EXPORT_SYMBOL(key_invalidate);
|
||||
|
||||
/**
|
||||
* generic_key_instantiate - Simple instantiation of a key from preparsed data
|
||||
* @key: The key to be instantiated
|
||||
* @prep: The preparsed data to load.
|
||||
*
|
||||
* Instantiate a key from preparsed data. We assume we can just copy the data
|
||||
* in directly and clear the old pointers.
|
||||
*
|
||||
* This can be pointed to directly by the key type instantiate op pointer.
|
||||
*/
|
||||
int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_devel("==>%s()\n", __func__);
|
||||
|
||||
ret = key_payload_reserve(key, prep->quotalen);
|
||||
if (ret == 0) {
|
||||
key->type_data.p[0] = prep->type_data[0];
|
||||
key->type_data.p[1] = prep->type_data[1];
|
||||
rcu_assign_keypointer(key, prep->payload[0]);
|
||||
key->payload.data2[1] = prep->payload[1];
|
||||
prep->type_data[0] = NULL;
|
||||
prep->type_data[1] = NULL;
|
||||
prep->payload[0] = NULL;
|
||||
prep->payload[1] = NULL;
|
||||
}
|
||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(generic_key_instantiate);
|
||||
|
||||
/**
|
||||
* register_key_type - Register a type of key.
|
||||
* @ktype: The new key type.
|
||||
|
@@ -37,8 +37,6 @@ static int key_get_type_from_user(char *type,
|
||||
return ret;
|
||||
if (ret == 0 || ret >= len)
|
||||
return -EINVAL;
|
||||
if (type[0] == '.')
|
||||
return -EPERM;
|
||||
type[len - 1] = '\0';
|
||||
return 0;
|
||||
}
|
||||
@@ -86,6 +84,10 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
|
||||
if (!*description) {
|
||||
kfree(description);
|
||||
description = NULL;
|
||||
} else if ((description[0] == '.') &&
|
||||
(strncmp(type, "keyring", 7) == 0)) {
|
||||
ret = -EPERM;
|
||||
goto error2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,12 +406,25 @@ long keyctl_invalidate_key(key_serial_t id)
|
||||
key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH);
|
||||
if (IS_ERR(key_ref)) {
|
||||
ret = PTR_ERR(key_ref);
|
||||
|
||||
/* Root is permitted to invalidate certain special keys */
|
||||
if (capable(CAP_SYS_ADMIN)) {
|
||||
key_ref = lookup_user_key(id, 0, 0);
|
||||
if (IS_ERR(key_ref))
|
||||
goto error;
|
||||
if (test_bit(KEY_FLAG_ROOT_CAN_INVAL,
|
||||
&key_ref_to_ptr(key_ref)->flags))
|
||||
goto invalidate;
|
||||
goto error_put;
|
||||
}
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
invalidate:
|
||||
key_invalidate(key_ref_to_ptr(key_ref));
|
||||
ret = 0;
|
||||
|
||||
error_put:
|
||||
key_ref_put(key_ref);
|
||||
error:
|
||||
kleave(" = %ld", ret);
|
||||
|
@@ -73,6 +73,8 @@ static inline unsigned keyring_hash(const char *desc)
|
||||
* can be treated as ordinary keys in addition to having their own special
|
||||
* operations.
|
||||
*/
|
||||
static int keyring_preparse(struct key_preparsed_payload *prep);
|
||||
static void keyring_free_preparse(struct key_preparsed_payload *prep);
|
||||
static int keyring_instantiate(struct key *keyring,
|
||||
struct key_preparsed_payload *prep);
|
||||
static void keyring_revoke(struct key *keyring);
|
||||
@@ -84,6 +86,8 @@ static long keyring_read(const struct key *keyring,
|
||||
struct key_type key_type_keyring = {
|
||||
.name = "keyring",
|
||||
.def_datalen = 0,
|
||||
.preparse = keyring_preparse,
|
||||
.free_preparse = keyring_free_preparse,
|
||||
.instantiate = keyring_instantiate,
|
||||
.match = user_match,
|
||||
.revoke = keyring_revoke,
|
||||
@@ -122,6 +126,21 @@ static void keyring_publish_name(struct key *keyring)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Preparse a keyring payload
|
||||
*/
|
||||
static int keyring_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
return prep->datalen != 0 ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a preparse of a user defined key payload
|
||||
*/
|
||||
static void keyring_free_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise a keyring.
|
||||
*
|
||||
@@ -130,17 +149,10 @@ static void keyring_publish_name(struct key *keyring)
|
||||
static int keyring_instantiate(struct key *keyring,
|
||||
struct key_preparsed_payload *prep)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (prep->datalen == 0) {
|
||||
assoc_array_init(&keyring->keys);
|
||||
/* make the keyring available by name if it has one */
|
||||
keyring_publish_name(keyring);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
assoc_array_init(&keyring->keys);
|
||||
/* make the keyring available by name if it has one */
|
||||
keyring_publish_name(keyring);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -20,6 +20,8 @@
|
||||
#include "internal.h"
|
||||
#include <keys/user-type.h>
|
||||
|
||||
static int request_key_auth_preparse(struct key_preparsed_payload *);
|
||||
static void request_key_auth_free_preparse(struct key_preparsed_payload *);
|
||||
static int request_key_auth_instantiate(struct key *,
|
||||
struct key_preparsed_payload *);
|
||||
static void request_key_auth_describe(const struct key *, struct seq_file *);
|
||||
@@ -33,6 +35,8 @@ static long request_key_auth_read(const struct key *, char __user *, size_t);
|
||||
struct key_type key_type_request_key_auth = {
|
||||
.name = ".request_key_auth",
|
||||
.def_datalen = sizeof(struct request_key_auth),
|
||||
.preparse = request_key_auth_preparse,
|
||||
.free_preparse = request_key_auth_free_preparse,
|
||||
.instantiate = request_key_auth_instantiate,
|
||||
.describe = request_key_auth_describe,
|
||||
.revoke = request_key_auth_revoke,
|
||||
@@ -40,6 +44,15 @@ struct key_type key_type_request_key_auth = {
|
||||
.read = request_key_auth_read,
|
||||
};
|
||||
|
||||
int request_key_auth_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Instantiate a request-key authorisation key.
|
||||
*/
|
||||
|
@@ -27,7 +27,9 @@ static int logon_vet_description(const char *desc);
|
||||
struct key_type key_type_user = {
|
||||
.name = "user",
|
||||
.def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
|
||||
.instantiate = user_instantiate,
|
||||
.preparse = user_preparse,
|
||||
.free_preparse = user_free_preparse,
|
||||
.instantiate = generic_key_instantiate,
|
||||
.update = user_update,
|
||||
.match = user_match,
|
||||
.revoke = user_revoke,
|
||||
@@ -47,7 +49,9 @@ EXPORT_SYMBOL_GPL(key_type_user);
|
||||
struct key_type key_type_logon = {
|
||||
.name = "logon",
|
||||
.def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
|
||||
.instantiate = user_instantiate,
|
||||
.preparse = user_preparse,
|
||||
.free_preparse = user_free_preparse,
|
||||
.instantiate = generic_key_instantiate,
|
||||
.update = user_update,
|
||||
.match = user_match,
|
||||
.revoke = user_revoke,
|
||||
@@ -58,38 +62,37 @@ struct key_type key_type_logon = {
|
||||
EXPORT_SYMBOL_GPL(key_type_logon);
|
||||
|
||||
/*
|
||||
* instantiate a user defined key
|
||||
* Preparse a user defined key payload
|
||||
*/
|
||||
int user_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||
int user_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
struct user_key_payload *upayload;
|
||||
size_t datalen = prep->datalen;
|
||||
int ret;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (datalen <= 0 || datalen > 32767 || !prep->data)
|
||||
goto error;
|
||||
return -EINVAL;
|
||||
|
||||
ret = key_payload_reserve(key, datalen);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = -ENOMEM;
|
||||
upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
|
||||
if (!upayload)
|
||||
goto error;
|
||||
return -ENOMEM;
|
||||
|
||||
/* attach the data */
|
||||
prep->quotalen = datalen;
|
||||
prep->payload[0] = upayload;
|
||||
upayload->datalen = datalen;
|
||||
memcpy(upayload->data, prep->data, datalen);
|
||||
rcu_assign_keypointer(key, upayload);
|
||||
ret = 0;
|
||||
|
||||
error:
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(user_preparse);
|
||||
|
||||
EXPORT_SYMBOL_GPL(user_instantiate);
|
||||
/*
|
||||
* Free a preparse of a user defined key payload
|
||||
*/
|
||||
void user_free_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
kfree(prep->payload[0]);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(user_free_preparse);
|
||||
|
||||
/*
|
||||
* update a user defined key
|
||||
|
Reference in New Issue
Block a user