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:
James Morris
2014-07-24 21:36:19 +10:00
48 changed files with 3033 additions and 225 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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