Merge branch 'fixes-v4.14-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull keys fixes from James Morris:
 "Notable here is a rewrite of big_key crypto by Jason Donenfeld to
  address some issues in the original code.

  From Jason's commit log:
   "This started out as just replacing the use of crypto/rng with
    get_random_bytes_wait, so that we wouldn't use bad randomness at
    boot time. But, upon looking further, it appears that there were
    even deeper underlying cryptographic problems, and that this seems
    to have been committed with very little crypto review. So, I rewrote
    the whole thing, trying to keep to the conventions introduced by the
    previous author, to fix these cryptographic flaws."

  There has been positive review of the new code by Eric Biggers and
  Herbert Xu, and it passes basic testing via the keyutils test suite.
  Eric also manually tested it.

  Generally speaking, we likely need to improve the amount of crypto
  review for kernel crypto users including keys (I'll post a note
  separately to ksummit-discuss)"

* 'fixes-v4.14-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  security/keys: rewrite all of big_key crypto
  security/keys: properly zero out sensitive key material in big_key
  KEYS: use kmemdup() in request_key_auth_new()
  KEYS: restrict /proc/keys by credentials at open time
  KEYS: reset parent each time before searching key_user_tree
  KEYS: prevent KEYCTL_READ on negative key
  KEYS: prevent creating a different user's keyrings
  KEYS: fix writing past end of user-supplied buffer in keyring_read()
  KEYS: fix key refcount leak in keyctl_read_key()
  KEYS: fix key refcount leak in keyctl_assume_authority()
  KEYS: don't revoke uninstantiated key in request_key_auth_new()
  KEYS: fix cred refcount leak in request_key_auth_new()
This commit is contained in:
Linus Torvalds 2017-09-29 10:26:35 -07:00
Родитель 770b782f55 2569e7e1d6
Коммит 95d3652eec
10 изменённых файлов: 138 добавлений и 151 удалений

Просмотреть файл

@ -187,6 +187,7 @@ struct key {
#define KEY_FLAG_BUILTIN 8 /* set if key is built in to the kernel */ #define KEY_FLAG_BUILTIN 8 /* set if key is built in to the kernel */
#define KEY_FLAG_ROOT_CAN_INVAL 9 /* set if key can be invalidated by root without permission */ #define KEY_FLAG_ROOT_CAN_INVAL 9 /* set if key can be invalidated by root without permission */
#define KEY_FLAG_KEEP 10 /* set if key should not be removed */ #define KEY_FLAG_KEEP 10 /* set if key should not be removed */
#define KEY_FLAG_UID_KEYRING 11 /* set if key is a user or user session keyring */
/* 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
@ -243,6 +244,7 @@ extern struct key *key_alloc(struct key_type *type,
#define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */ #define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */
#define KEY_ALLOC_BUILT_IN 0x0004 /* Key is built into kernel */ #define KEY_ALLOC_BUILT_IN 0x0004 /* Key is built into kernel */
#define KEY_ALLOC_BYPASS_RESTRICTION 0x0008 /* Override the check on restricted keyrings */ #define KEY_ALLOC_BYPASS_RESTRICTION 0x0008 /* Override the check on restricted keyrings */
#define KEY_ALLOC_UID_KEYRING 0x0010 /* allocating a user or user session keyring */
extern void key_revoke(struct key *key); extern void key_revoke(struct key *key);
extern void key_invalidate(struct key *key); extern void key_invalidate(struct key *key);

Просмотреть файл

@ -45,10 +45,8 @@ config BIG_KEYS
bool "Large payload keys" bool "Large payload keys"
depends on KEYS depends on KEYS
depends on TMPFS depends on TMPFS
depends on (CRYPTO_ANSI_CPRNG = y || CRYPTO_DRBG = y)
select CRYPTO_AES select CRYPTO_AES
select CRYPTO_ECB select CRYPTO_GCM
select CRYPTO_RNG
help help
This option provides support for holding large keys within the kernel This option provides support for holding large keys within the kernel
(for example Kerberos ticket caches). The data may be stored out to (for example Kerberos ticket caches). The data may be stored out to

Просмотреть файл

@ -1,5 +1,6 @@
/* Large capacity key type /* Large capacity key type
* *
* Copyright (C) 2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com) * Written by David Howells (dhowells@redhat.com)
* *
@ -16,10 +17,10 @@
#include <linux/shmem_fs.h> #include <linux/shmem_fs.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/random.h>
#include <keys/user-type.h> #include <keys/user-type.h>
#include <keys/big_key-type.h> #include <keys/big_key-type.h>
#include <crypto/rng.h> #include <crypto/aead.h>
#include <crypto/skcipher.h>
/* /*
* Layout of key payload words. * Layout of key payload words.
@ -49,7 +50,12 @@ enum big_key_op {
/* /*
* Key size for big_key data encryption * Key size for big_key data encryption
*/ */
#define ENC_KEY_SIZE 16 #define ENC_KEY_SIZE 32
/*
* Authentication tag length
*/
#define ENC_AUTHTAG_SIZE 16
/* /*
* big_key defined keys take an arbitrary string as the description and an * big_key defined keys take an arbitrary string as the description and an
@ -64,57 +70,62 @@ struct key_type key_type_big_key = {
.destroy = big_key_destroy, .destroy = big_key_destroy,
.describe = big_key_describe, .describe = big_key_describe,
.read = big_key_read, .read = big_key_read,
/* no ->update(); don't add it without changing big_key_crypt() nonce */
}; };
/* /*
* Crypto names for big_key data encryption * Crypto names for big_key data authenticated encryption
*/ */
static const char big_key_rng_name[] = "stdrng"; static const char big_key_alg_name[] = "gcm(aes)";
static const char big_key_alg_name[] = "ecb(aes)";
/* /*
* Crypto algorithms for big_key data encryption * Crypto algorithms for big_key data authenticated encryption
*/ */
static struct crypto_rng *big_key_rng; static struct crypto_aead *big_key_aead;
static struct crypto_skcipher *big_key_skcipher;
/* /*
* Generate random key to encrypt big_key data * Since changing the key affects the entire object, we need a mutex.
*/ */
static inline int big_key_gen_enckey(u8 *key) static DEFINE_MUTEX(big_key_aead_lock);
{
return crypto_rng_get_bytes(big_key_rng, key, ENC_KEY_SIZE);
}
/* /*
* Encrypt/decrypt big_key data * Encrypt/decrypt big_key data
*/ */
static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key) static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key)
{ {
int ret = -EINVAL; int ret;
struct scatterlist sgio; struct scatterlist sgio;
SKCIPHER_REQUEST_ON_STACK(req, big_key_skcipher); struct aead_request *aead_req;
/* We always use a zero nonce. The reason we can get away with this is
* because we're using a different randomly generated key for every
* different encryption. Notably, too, key_type_big_key doesn't define
* an .update function, so there's no chance we'll wind up reusing the
* key to encrypt updated data. Simply put: one key, one encryption.
*/
u8 zero_nonce[crypto_aead_ivsize(big_key_aead)];
if (crypto_skcipher_setkey(big_key_skcipher, key, ENC_KEY_SIZE)) { aead_req = aead_request_alloc(big_key_aead, GFP_KERNEL);
if (!aead_req)
return -ENOMEM;
memset(zero_nonce, 0, sizeof(zero_nonce));
sg_init_one(&sgio, data, datalen + (op == BIG_KEY_ENC ? ENC_AUTHTAG_SIZE : 0));
aead_request_set_crypt(aead_req, &sgio, &sgio, datalen, zero_nonce);
aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
aead_request_set_ad(aead_req, 0);
mutex_lock(&big_key_aead_lock);
if (crypto_aead_setkey(big_key_aead, key, ENC_KEY_SIZE)) {
ret = -EAGAIN; ret = -EAGAIN;
goto error; goto error;
} }
skcipher_request_set_tfm(req, big_key_skcipher);
skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
NULL, NULL);
sg_init_one(&sgio, data, datalen);
skcipher_request_set_crypt(req, &sgio, &sgio, datalen, NULL);
if (op == BIG_KEY_ENC) if (op == BIG_KEY_ENC)
ret = crypto_skcipher_encrypt(req); ret = crypto_aead_encrypt(aead_req);
else else
ret = crypto_skcipher_decrypt(req); ret = crypto_aead_decrypt(aead_req);
skcipher_request_zero(req);
error: error:
mutex_unlock(&big_key_aead_lock);
aead_request_free(aead_req);
return ret; return ret;
} }
@ -146,16 +157,13 @@ int big_key_preparse(struct key_preparsed_payload *prep)
* *
* File content is stored encrypted with randomly generated key. * File content is stored encrypted with randomly generated key.
*/ */
size_t enclen = ALIGN(datalen, crypto_skcipher_blocksize(big_key_skcipher)); size_t enclen = datalen + ENC_AUTHTAG_SIZE;
loff_t pos = 0; loff_t pos = 0;
/* prepare aligned data to encrypt */
data = kmalloc(enclen, GFP_KERNEL); data = kmalloc(enclen, GFP_KERNEL);
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
memcpy(data, prep->data, datalen); memcpy(data, prep->data, datalen);
memset(data + datalen, 0x00, enclen - datalen);
/* generate random key */ /* generate random key */
enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL); enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL);
@ -163,13 +171,12 @@ int big_key_preparse(struct key_preparsed_payload *prep)
ret = -ENOMEM; ret = -ENOMEM;
goto error; goto error;
} }
ret = get_random_bytes_wait(enckey, ENC_KEY_SIZE);
ret = big_key_gen_enckey(enckey); if (unlikely(ret))
if (ret)
goto err_enckey; goto err_enckey;
/* encrypt aligned data */ /* encrypt aligned data */
ret = big_key_crypt(BIG_KEY_ENC, data, enclen, enckey); ret = big_key_crypt(BIG_KEY_ENC, data, datalen, enckey);
if (ret) if (ret)
goto err_enckey; goto err_enckey;
@ -195,7 +202,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
*path = file->f_path; *path = file->f_path;
path_get(path); path_get(path);
fput(file); fput(file);
kfree(data); kzfree(data);
} else { } else {
/* Just store the data in a buffer */ /* Just store the data in a buffer */
void *data = kmalloc(datalen, GFP_KERNEL); void *data = kmalloc(datalen, GFP_KERNEL);
@ -211,9 +218,9 @@ int big_key_preparse(struct key_preparsed_payload *prep)
err_fput: err_fput:
fput(file); fput(file);
err_enckey: err_enckey:
kfree(enckey); kzfree(enckey);
error: error:
kfree(data); kzfree(data);
return ret; return ret;
} }
@ -227,7 +234,7 @@ void big_key_free_preparse(struct key_preparsed_payload *prep)
path_put(path); path_put(path);
} }
kfree(prep->payload.data[big_key_data]); kzfree(prep->payload.data[big_key_data]);
} }
/* /*
@ -259,7 +266,7 @@ void big_key_destroy(struct key *key)
path->mnt = NULL; path->mnt = NULL;
path->dentry = NULL; path->dentry = NULL;
} }
kfree(key->payload.data[big_key_data]); kzfree(key->payload.data[big_key_data]);
key->payload.data[big_key_data] = NULL; key->payload.data[big_key_data] = NULL;
} }
@ -295,7 +302,7 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
struct file *file; struct file *file;
u8 *data; u8 *data;
u8 *enckey = (u8 *)key->payload.data[big_key_data]; u8 *enckey = (u8 *)key->payload.data[big_key_data];
size_t enclen = ALIGN(datalen, crypto_skcipher_blocksize(big_key_skcipher)); size_t enclen = datalen + ENC_AUTHTAG_SIZE;
loff_t pos = 0; loff_t pos = 0;
data = kmalloc(enclen, GFP_KERNEL); data = kmalloc(enclen, GFP_KERNEL);
@ -328,7 +335,7 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
err_fput: err_fput:
fput(file); fput(file);
error: error:
kfree(data); kzfree(data);
} else { } else {
ret = datalen; ret = datalen;
if (copy_to_user(buffer, key->payload.data[big_key_data], if (copy_to_user(buffer, key->payload.data[big_key_data],
@ -344,47 +351,31 @@ error:
*/ */
static int __init big_key_init(void) static int __init big_key_init(void)
{ {
struct crypto_skcipher *cipher;
struct crypto_rng *rng;
int ret; int ret;
rng = crypto_alloc_rng(big_key_rng_name, 0, 0);
if (IS_ERR(rng)) {
pr_err("Can't alloc rng: %ld\n", PTR_ERR(rng));
return PTR_ERR(rng);
}
big_key_rng = rng;
/* seed RNG */
ret = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng));
if (ret) {
pr_err("Can't reset rng: %d\n", ret);
goto error_rng;
}
/* init block cipher */ /* init block cipher */
cipher = crypto_alloc_skcipher(big_key_alg_name, 0, CRYPTO_ALG_ASYNC); big_key_aead = crypto_alloc_aead(big_key_alg_name, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(cipher)) { if (IS_ERR(big_key_aead)) {
ret = PTR_ERR(cipher); ret = PTR_ERR(big_key_aead);
pr_err("Can't alloc crypto: %d\n", ret); pr_err("Can't alloc crypto: %d\n", ret);
goto error_rng; return ret;
}
ret = crypto_aead_setauthsize(big_key_aead, ENC_AUTHTAG_SIZE);
if (ret < 0) {
pr_err("Can't set crypto auth tag len: %d\n", ret);
goto free_aead;
} }
big_key_skcipher = cipher;
ret = register_key_type(&key_type_big_key); ret = register_key_type(&key_type_big_key);
if (ret < 0) { if (ret < 0) {
pr_err("Can't register type: %d\n", ret); pr_err("Can't register type: %d\n", ret);
goto error_cipher; goto free_aead;
} }
return 0; return 0;
error_cipher: free_aead:
crypto_free_skcipher(big_key_skcipher); crypto_free_aead(big_key_aead);
error_rng:
crypto_free_rng(big_key_rng);
return ret; return ret;
} }

Просмотреть файл

@ -141,7 +141,7 @@ extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
extern key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx); extern key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx);
extern key_ref_t search_process_keyrings(struct keyring_search_context *ctx); extern key_ref_t search_process_keyrings(struct keyring_search_context *ctx);
extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check); extern struct key *find_keyring_by_name(const char *name, bool uid_keyring);
extern int install_user_keyrings(void); extern int install_user_keyrings(void);
extern int install_thread_keyring_to_cred(struct cred *); extern int install_thread_keyring_to_cred(struct cred *);

Просмотреть файл

@ -54,10 +54,10 @@ void __key_check(const struct key *key)
struct key_user *key_user_lookup(kuid_t uid) struct key_user *key_user_lookup(kuid_t uid)
{ {
struct key_user *candidate = NULL, *user; struct key_user *candidate = NULL, *user;
struct rb_node *parent = NULL; struct rb_node *parent, **p;
struct rb_node **p;
try_again: try_again:
parent = NULL;
p = &key_user_tree.rb_node; p = &key_user_tree.rb_node;
spin_lock(&key_user_lock); spin_lock(&key_user_lock);
@ -302,6 +302,8 @@ struct key *key_alloc(struct key_type *type, const char *desc,
key->flags |= 1 << KEY_FLAG_IN_QUOTA; key->flags |= 1 << KEY_FLAG_IN_QUOTA;
if (flags & KEY_ALLOC_BUILT_IN) if (flags & KEY_ALLOC_BUILT_IN)
key->flags |= 1 << KEY_FLAG_BUILTIN; key->flags |= 1 << KEY_FLAG_BUILTIN;
if (flags & KEY_ALLOC_UID_KEYRING)
key->flags |= 1 << KEY_FLAG_UID_KEYRING;
#ifdef KEY_DEBUGGING #ifdef KEY_DEBUGGING
key->magic = KEY_DEBUG_MAGIC; key->magic = KEY_DEBUG_MAGIC;

Просмотреть файл

@ -766,12 +766,17 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
key = key_ref_to_ptr(key_ref); key = key_ref_to_ptr(key_ref);
if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
ret = -ENOKEY;
goto error2;
}
/* see if we can read it directly */ /* see if we can read it directly */
ret = key_permission(key_ref, KEY_NEED_READ); ret = key_permission(key_ref, KEY_NEED_READ);
if (ret == 0) if (ret == 0)
goto can_read_key; goto can_read_key;
if (ret != -EACCES) if (ret != -EACCES)
goto error; goto error2;
/* we can't; see if it's searchable from this process's keyrings /* we can't; see if it's searchable from this process's keyrings
* - we automatically take account of the fact that it may be * - we automatically take account of the fact that it may be
@ -1406,11 +1411,9 @@ long keyctl_assume_authority(key_serial_t id)
} }
ret = keyctl_change_reqkey_auth(authkey); ret = keyctl_change_reqkey_auth(authkey);
if (ret < 0) if (ret == 0)
goto error;
key_put(authkey);
ret = authkey->serial; ret = authkey->serial;
key_put(authkey);
error: error:
return ret; return ret;
} }

Просмотреть файл

@ -423,7 +423,7 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m)
} }
struct keyring_read_iterator_context { struct keyring_read_iterator_context {
size_t qty; size_t buflen;
size_t count; size_t count;
key_serial_t __user *buffer; key_serial_t __user *buffer;
}; };
@ -435,9 +435,9 @@ static int keyring_read_iterator(const void *object, void *data)
int ret; int ret;
kenter("{%s,%d},,{%zu/%zu}", kenter("{%s,%d},,{%zu/%zu}",
key->type->name, key->serial, ctx->count, ctx->qty); key->type->name, key->serial, ctx->count, ctx->buflen);
if (ctx->count >= ctx->qty) if (ctx->count >= ctx->buflen)
return 1; return 1;
ret = put_user(key->serial, ctx->buffer); ret = put_user(key->serial, ctx->buffer);
@ -472,16 +472,12 @@ static long keyring_read(const struct key *keyring,
return 0; return 0;
/* Calculate how much data we could return */ /* Calculate how much data we could return */
ctx.qty = nr_keys * sizeof(key_serial_t);
if (!buffer || !buflen) if (!buffer || !buflen)
return ctx.qty; return nr_keys * sizeof(key_serial_t);
if (buflen > ctx.qty)
ctx.qty = buflen;
/* Copy the IDs of the subscribed keys into the buffer */ /* Copy the IDs of the subscribed keys into the buffer */
ctx.buffer = (key_serial_t __user *)buffer; ctx.buffer = (key_serial_t __user *)buffer;
ctx.buflen = buflen;
ctx.count = 0; ctx.count = 0;
ret = assoc_array_iterate(&keyring->keys, keyring_read_iterator, &ctx); ret = assoc_array_iterate(&keyring->keys, keyring_read_iterator, &ctx);
if (ret < 0) { if (ret < 0) {
@ -1101,15 +1097,15 @@ found:
/* /*
* Find a keyring with the specified name. * Find a keyring with the specified name.
* *
* All named keyrings in the current user namespace are searched, provided they * Only keyrings that have nonzero refcount, are not revoked, and are owned by a
* grant Search permission directly to the caller (unless this check is * user in the current user namespace are considered. If @uid_keyring is %true,
* skipped). Keyrings whose usage points have reached zero or who have been * the keyring additionally must have been allocated as a user or user session
* revoked are skipped. * keyring; otherwise, it must grant Search permission directly to the caller.
* *
* Returns a pointer to the keyring with the keyring's refcount having being * Returns a pointer to the keyring with the keyring's refcount having being
* incremented on success. -ENOKEY is returned if a key could not be found. * incremented on success. -ENOKEY is returned if a key could not be found.
*/ */
struct key *find_keyring_by_name(const char *name, bool skip_perm_check) struct key *find_keyring_by_name(const char *name, bool uid_keyring)
{ {
struct key *keyring; struct key *keyring;
int bucket; int bucket;
@ -1137,10 +1133,15 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
if (strcmp(keyring->description, name) != 0) if (strcmp(keyring->description, name) != 0)
continue; continue;
if (!skip_perm_check && if (uid_keyring) {
key_permission(make_key_ref(keyring, 0), if (!test_bit(KEY_FLAG_UID_KEYRING,
&keyring->flags))
continue;
} else {
if (key_permission(make_key_ref(keyring, 0),
KEY_NEED_SEARCH) < 0) KEY_NEED_SEARCH) < 0)
continue; continue;
}
/* we've got a match but we might end up racing with /* we've got a match but we might end up racing with
* key_cleanup() if the keyring is currently 'dead' * key_cleanup() if the keyring is currently 'dead'

Просмотреть файл

@ -187,7 +187,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
struct keyring_search_context ctx = { struct keyring_search_context ctx = {
.index_key.type = key->type, .index_key.type = key->type,
.index_key.description = key->description, .index_key.description = key->description,
.cred = current_cred(), .cred = m->file->f_cred,
.match_data.cmp = lookup_user_key_possessed, .match_data.cmp = lookup_user_key_possessed,
.match_data.raw_data = key, .match_data.raw_data = key,
.match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
@ -207,11 +207,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
} }
} }
/* check whether the current task is allowed to view the key (assuming /* check whether the current task is allowed to view the key */
* non-possession)
* - the caller holds a spinlock, and thus the RCU read lock, making our
* access to __current_cred() safe
*/
rc = key_task_permission(key_ref, ctx.cred, KEY_NEED_VIEW); rc = key_task_permission(key_ref, ctx.cred, KEY_NEED_VIEW);
if (rc < 0) if (rc < 0)
return 0; return 0;

Просмотреть файл

@ -77,6 +77,7 @@ int install_user_keyrings(void)
if (IS_ERR(uid_keyring)) { if (IS_ERR(uid_keyring)) {
uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID, uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID,
cred, user_keyring_perm, cred, user_keyring_perm,
KEY_ALLOC_UID_KEYRING |
KEY_ALLOC_IN_QUOTA, KEY_ALLOC_IN_QUOTA,
NULL, NULL); NULL, NULL);
if (IS_ERR(uid_keyring)) { if (IS_ERR(uid_keyring)) {
@ -94,6 +95,7 @@ int install_user_keyrings(void)
session_keyring = session_keyring =
keyring_alloc(buf, user->uid, INVALID_GID, keyring_alloc(buf, user->uid, INVALID_GID,
cred, user_keyring_perm, cred, user_keyring_perm,
KEY_ALLOC_UID_KEYRING |
KEY_ALLOC_IN_QUOTA, KEY_ALLOC_IN_QUOTA,
NULL, NULL); NULL, NULL);
if (IS_ERR(session_keyring)) { if (IS_ERR(session_keyring)) {

Просмотреть файл

@ -120,6 +120,18 @@ static void request_key_auth_revoke(struct key *key)
} }
} }
static void free_request_key_auth(struct request_key_auth *rka)
{
if (!rka)
return;
key_put(rka->target_key);
key_put(rka->dest_keyring);
if (rka->cred)
put_cred(rka->cred);
kfree(rka->callout_info);
kfree(rka);
}
/* /*
* Destroy an instantiation authorisation token key. * Destroy an instantiation authorisation token key.
*/ */
@ -129,15 +141,7 @@ static void request_key_auth_destroy(struct key *key)
kenter("{%d}", key->serial); kenter("{%d}", key->serial);
if (rka->cred) { free_request_key_auth(rka);
put_cred(rka->cred);
rka->cred = NULL;
}
key_put(rka->target_key);
key_put(rka->dest_keyring);
kfree(rka->callout_info);
kfree(rka);
} }
/* /*
@ -151,22 +155,18 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
const struct cred *cred = current->cred; const struct cred *cred = current->cred;
struct key *authkey = NULL; struct key *authkey = NULL;
char desc[20]; char desc[20];
int ret; int ret = -ENOMEM;
kenter("%d,", target->serial); kenter("%d,", target->serial);
/* allocate a auth record */ /* allocate a auth record */
rka = kmalloc(sizeof(*rka), GFP_KERNEL); rka = kzalloc(sizeof(*rka), GFP_KERNEL);
if (!rka) { if (!rka)
kleave(" = -ENOMEM"); goto error;
return ERR_PTR(-ENOMEM); rka->callout_info = kmemdup(callout_info, callout_len, GFP_KERNEL);
} if (!rka->callout_info)
rka->callout_info = kmalloc(callout_len, GFP_KERNEL); goto error_free_rka;
if (!rka->callout_info) { rka->callout_len = callout_len;
kleave(" = -ENOMEM");
kfree(rka);
return ERR_PTR(-ENOMEM);
}
/* see if the calling process is already servicing the key request of /* see if the calling process is already servicing the key request of
* another process */ * another process */
@ -176,8 +176,12 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
/* if the auth key has been revoked, then the key we're /* if the auth key has been revoked, then the key we're
* servicing is already instantiated */ * servicing is already instantiated */
if (test_bit(KEY_FLAG_REVOKED, &cred->request_key_auth->flags)) if (test_bit(KEY_FLAG_REVOKED,
goto auth_key_revoked; &cred->request_key_auth->flags)) {
up_read(&cred->request_key_auth->sem);
ret = -EKEYREVOKED;
goto error_free_rka;
}
irka = cred->request_key_auth->payload.data[0]; irka = cred->request_key_auth->payload.data[0];
rka->cred = get_cred(irka->cred); rka->cred = get_cred(irka->cred);
@ -193,8 +197,6 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
rka->target_key = key_get(target); rka->target_key = key_get(target);
rka->dest_keyring = key_get(dest_keyring); rka->dest_keyring = key_get(dest_keyring);
memcpy(rka->callout_info, callout_info, callout_len);
rka->callout_len = callout_len;
/* allocate the auth key */ /* allocate the auth key */
sprintf(desc, "%x", target->serial); sprintf(desc, "%x", target->serial);
@ -205,32 +207,22 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA, NULL); KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA, NULL);
if (IS_ERR(authkey)) { if (IS_ERR(authkey)) {
ret = PTR_ERR(authkey); ret = PTR_ERR(authkey);
goto error_alloc; goto error_free_rka;
} }
/* construct the auth key */ /* construct the auth key */
ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL); ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL);
if (ret < 0) if (ret < 0)
goto error_inst; goto error_put_authkey;
kleave(" = {%d,%d}", authkey->serial, refcount_read(&authkey->usage)); kleave(" = {%d,%d}", authkey->serial, refcount_read(&authkey->usage));
return authkey; return authkey;
auth_key_revoked: error_put_authkey:
up_read(&cred->request_key_auth->sem);
kfree(rka->callout_info);
kfree(rka);
kleave("= -EKEYREVOKED");
return ERR_PTR(-EKEYREVOKED);
error_inst:
key_revoke(authkey);
key_put(authkey); key_put(authkey);
error_alloc: error_free_rka:
key_put(rka->target_key); free_request_key_auth(rka);
key_put(rka->dest_keyring); error:
kfree(rka->callout_info);
kfree(rka);
kleave("= %d", ret); kleave("= %d", ret);
return ERR_PTR(ret); return ERR_PTR(ret);
} }