Commit 76181c13 authored by David Howells's avatar David Howells Committed by Linus Torvalds

KEYS: Make request_key() and co fundamentally asynchronous

Make request_key() and co fundamentally asynchronous to make it easier for
NFS to make use of them.  There are now accessor functions that do
asynchronous constructions, a wait function to wait for construction to
complete, and a completion function for the key type to indicate completion
of construction.

Note that the construction queue is now gone.  Instead, keys under
construction are linked in to the appropriate keyring in advance, and that
anyone encountering one must wait for it to be complete before they can use
it.  This is done automatically for userspace.

The following auxiliary changes are also made:

 (1) Key type implementation stuff is split from linux/key.h into
     linux/key-type.h.

 (2) AF_RXRPC provides a way to allocate null rxrpc-type keys so that AFS does
     not need to call key_instantiate_and_link() directly.

 (3) Adjust the debugging macros so that they're -Wformat checked even if
     they are disabled, and make it so they can be enabled simply by defining
     __KDEBUG to be consistent with other code of mine.

 (3) Documentation.

[alan@lxorguk.ukuu.org.uk: keys: missing word in documentation]
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarAlan Cox <alan@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 398c95bd
......@@ -20,6 +20,19 @@ or:
const char *callout_string,
void *aux);
or:
struct key *request_key_async(const struct key_type *type,
const char *description,
const char *callout_string);
or:
struct key *request_key_async_with_auxdata(const struct key_type *type,
const char *description,
const char *callout_string,
void *aux);
Or by userspace invoking the request_key system call:
key_serial_t request_key(const char *type,
......@@ -32,10 +45,14 @@ does not need to link the key to a keyring to prevent it from being immediately
destroyed. The kernel interface returns a pointer directly to the key, and
it's up to the caller to destroy the key.
The request_key_with_auxdata() call is like the in-kernel request_key() call,
except that it permits auxiliary data to be passed to the upcaller (the default
is NULL). This is only useful for those key types that define their own upcall
mechanism rather than using /sbin/request-key.
The request_key*_with_auxdata() calls are like the in-kernel request_key*()
calls, except that they permit auxiliary data to be passed to the upcaller (the
default is NULL). This is only useful for those key types that define their
own upcall mechanism rather than using /sbin/request-key.
The two async in-kernel calls may return keys that are still in the process of
being constructed. The two non-async ones will wait for construction to
complete first.
The userspace interface links the key to a keyring associated with the process
to prevent the key from going away, and returns the serial number of the key to
......
......@@ -4,7 +4,7 @@
This service allows cryptographic keys, authentication tokens, cross-domain
user mappings, and similar to be cached in the kernel for the use of
filesystems other kernel services.
filesystems and other kernel services.
Keyrings are permitted; these are a special type of key that can hold links to
other keys. Processes each have three standard keyring subscriptions that a
......@@ -726,6 +726,15 @@ call, and the key released upon close. How to deal with conflicting keys due to
two different users opening the same file is left to the filesystem author to
solve.
To access the key manager, the following header must be #included:
<linux/key.h>
Specific key types should have a header file under include/keys/ that should be
used to access that type. For keys of type "user", for example, that would be:
<keys/user-type.h>
Note that there are two different types of pointers to keys that may be
encountered:
......@@ -791,6 +800,36 @@ payload contents" for more information.
passed to the key_type->request_key() op if it exists.
(*) A key can be requested asynchronously by calling one of:
struct key *request_key_async(const struct key_type *type,
const char *description,
const char *callout_string);
or:
struct key *request_key_async_with_auxdata(const struct key_type *type,
const char *description,
const char *callout_string,
void *aux);
which are asynchronous equivalents of request_key() and
request_key_with_auxdata() respectively.
These two functions return with the key potentially still under
construction. To wait for contruction completion, the following should be
called:
int wait_for_key_construction(struct key *key, bool intr);
The function will wait for the key to finish being constructed and then
invokes key_validate() to return an appropriate value to indicate the state
of the key (0 indicates the key is usable).
If intr is true, then the wait can be interrupted by a signal, in which
case error ERESTARTSYS will be returned.
(*) When it is no longer required, the key should be released using:
void key_put(struct key *key);
......@@ -924,7 +963,11 @@ DEFINING A KEY TYPE
A kernel service may want to define its own key type. For instance, an AFS
filesystem might want to define a Kerberos 5 ticket key type. To do this, it
author fills in a struct key_type and registers it with the system.
author fills in a key_type struct and registers it with the system.
Source files that implement key types should include the following header file:
<linux/key-type.h>
The structure has a number of fields, some of which are mandatory:
......@@ -1053,22 +1096,44 @@ The structure has a number of fields, some of which are mandatory:
as might happen when the userspace buffer is accessed.
(*) int (*request_key)(struct key *key, struct key *authkey, const char *op,
(*) int (*request_key)(struct key_construction *cons, const char *op,
void *aux);
This method is optional. If provided, request_key() and
request_key_with_auxdata() will invoke this function rather than
upcalling to /sbin/request-key to operate upon a key of this type.
This method is optional. If provided, request_key() and friends will
invoke this function rather than upcalling to /sbin/request-key to operate
upon a key of this type.
The aux parameter is as passed to request_key_async_with_auxdata() and
similar or is NULL otherwise. Also passed are the construction record for
the key to be operated upon and the operation type (currently only
"create").
This method is permitted to return before the upcall is complete, but the
following function must be called under all circumstances to complete the
instantiation process, whether or not it succeeds, whether or not there's
an error:
void complete_request_key(struct key_construction *cons, int error);
The error parameter should be 0 on success, -ve on error. The
construction record is destroyed by this action and the authorisation key
will be revoked. If an error is indicated, the key under construction
will be negatively instantiated if it wasn't already instantiated.
If this method returns an error, that error will be returned to the
caller of request_key*(). complete_request_key() must be called prior to
returning.
The key under construction and the authorisation key can be found in the
key_construction struct pointed to by cons:
(*) struct key *key;
The key under construction.
The aux parameter is as passed to request_key_with_auxdata() or is NULL
otherwise. Also passed are the key to be operated upon, the
authorisation key for this operation and the operation type (currently
only "create").
(*) struct key *authkey;
This function should return only when the upcall is complete. Upon return
the authorisation key will be revoked, and the target key will be
negatively instantiated if it is still uninstantiated. The error will be
returned to the caller of request_key*().
The authorisation key.
============================
......
......@@ -857,3 +857,10 @@ The kernel interface functions are as follows:
This is used to extract the error number from a message indicating either
a local error occurred or a network error occurred.
(*) Allocate a null key for doing anonymous security.
struct key *rxrpc_get_null_key(const char *keyname);
This is used to allocate a null RxRPC key that can be used to indicate
anonymous security for a particular domain.
......@@ -33,6 +33,7 @@ static struct afs_cell *afs_cell_root;
static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
{
struct afs_cell *cell;
struct key *key;
size_t namelen;
char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
int ret;
......@@ -89,20 +90,14 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
do {
*dp++ = toupper(*cp);
} while (*cp++);
cell->anonymous_key = key_alloc(&key_type_rxrpc, keyname, 0, 0, current,
KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(cell->anonymous_key)) {
_debug("no key");
ret = PTR_ERR(cell->anonymous_key);
goto error;
}
ret = key_instantiate_and_link(cell->anonymous_key, NULL, 0,
NULL, NULL);
if (ret < 0) {
_debug("instantiate failed");
key = rxrpc_get_null_key(keyname);
if (IS_ERR(key)) {
_debug("no key");
ret = PTR_ERR(key);
goto error;
}
cell->anonymous_key = key;
_debug("anon key %p{%x}",
cell->anonymous_key, key_serial(cell->anonymous_key));
......
......@@ -19,4 +19,6 @@
*/
extern struct key_type key_type_rxrpc;
extern struct key *rxrpc_get_null_key(const char *);
#endif /* _KEYS_USER_TYPE_H */
/* Definitions for key type implementations
*
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef _LINUX_KEY_TYPE_H
#define _LINUX_KEY_TYPE_H
#include <linux/key.h>
#ifdef CONFIG_KEYS
/*
* key under-construction record
* - passed to the request_key actor if supplied
*/
struct key_construction {
struct key *key; /* key being constructed */
struct key *authkey;/* authorisation for key being constructed */
};
typedef int (*request_key_actor_t)(struct key_construction *key,
const char *op, void *aux);
/*
* kernel managed key type definition
*/
struct key_type {
/* name of the type */
const char *name;
/* default payload length for quota precalculation (optional)
* - this can be used instead of calling key_payload_reserve(), that
* function only needs to be called if the real datalen is different
*/
size_t def_datalen;
/* instantiate a key of this type
* - this method should call key_payload_reserve() to determine if the
* user's quota will hold the payload
*/
int (*instantiate)(struct key *key, const void *data, size_t datalen);
/* update a key of this type (optional)
* - this method should call key_payload_reserve() to recalculate the
* quota consumption
* - the key must be locked against read when modifying
*/
int (*update)(struct key *key, const void *data, size_t datalen);
/* match a key against a description */
int (*match)(const struct key *key, const void *desc);
/* clear some of the data from a key on revokation (optional)
* - the key's semaphore will be write-locked by the caller
*/
void (*revoke)(struct key *key);
/* clear the data from a key (optional) */
void (*destroy)(struct key *key);
/* describe a key */
void (*describe)(const struct key *key, struct seq_file *p);
/* read a key's data (optional)
* - permission checks will be done by the caller
* - the key's semaphore will be readlocked by the caller
* - should return the amount of data that could be read, no matter how
* much is copied into the buffer
* - shouldn't do the copy if the buffer is NULL
*/
long (*read)(const struct key *key, char __user *buffer, size_t buflen);
/* handle request_key() for this type instead of invoking
* /sbin/request-key (optional)
* - key is the key to instantiate
* - authkey is the authority to assume when instantiating this key
* - op is the operation to be done, usually "create"
* - the call must not return until the instantiation process has run
* its course
*/
request_key_actor_t request_key;
/* internal fields */
struct list_head link; /* link in types list */
};
extern struct key_type key_type_keyring;
extern int register_key_type(struct key_type *ktype);
extern void unregister_key_type(struct key_type *ktype);
extern int key_payload_reserve(struct key *key, size_t datalen);
extern int key_instantiate_and_link(struct key *key,
const void *data,
size_t datalen,
struct key *keyring,
struct key *instkey);
extern int key_negate_and_link(struct key *key,
unsigned timeout,
struct key *keyring,
struct key *instkey);
extern void complete_request_key(struct key_construction *cons, int error);
#endif /* CONFIG_KEYS */
#endif /* _LINUX_KEY_TYPE_H */
/* key.h: authentication token and access key management
/* Authentication token and access key management
*
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
* Copyright (C) 2004, 2007 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
......@@ -175,78 +175,6 @@ struct key {
} payload;
};
/*****************************************************************************/
/*
* kernel managed key type definition
*/
typedef int (*request_key_actor_t)(struct key *key, struct key *authkey,
const char *op, void *aux);
struct key_type {
/* name of the type */
const char *name;
/* default payload length for quota precalculation (optional)
* - this can be used instead of calling key_payload_reserve(), that
* function only needs to be called if the real datalen is different
*/
size_t def_datalen;
/* instantiate a key of this type
* - this method should call key_payload_reserve() to determine if the
* user's quota will hold the payload
*/
int (*instantiate)(struct key *key, const void *data, size_t datalen);
/* update a key of this type (optional)
* - this method should call key_payload_reserve() to recalculate the
* quota consumption
* - the key must be locked against read when modifying
*/
int (*update)(struct key *key, const void *data, size_t datalen);
/* match a key against a description */
int (*match)(const struct key *key, const void *desc);
/* clear some of the data from a key on revokation (optional)
* - the key's semaphore will be write-locked by the caller
*/
void (*revoke)(struct key *key);
/* clear the data from a key (optional) */
void (*destroy)(struct key *key);
/* describe a key */
void (*describe)(const struct key *key, struct seq_file *p);
/* read a key's data (optional)
* - permission checks will be done by the caller
* - the key's semaphore will be readlocked by the caller
* - should return the amount of data that could be read, no matter how
* much is copied into the buffer
* - shouldn't do the copy if the buffer is NULL
*/
long (*read)(const struct key *key, char __user *buffer, size_t buflen);
/* handle request_key() for this type instead of invoking
* /sbin/request-key (optional)
* - key is the key to instantiate
* - authkey is the authority to assume when instantiating this key
* - op is the operation to be done, usually "create"
* - the call must not return until the instantiation process has run
* its course
*/
request_key_actor_t request_key;
/* internal fields */
struct list_head link; /* link in types list */
};
extern struct key_type key_type_keyring;
extern int register_key_type(struct key_type *ktype);
extern void unregister_key_type(struct key_type *ktype);
extern struct key *key_alloc(struct key_type *type,
const char *desc,
uid_t uid, gid_t gid,
......@@ -259,16 +187,6 @@ extern struct key *key_alloc(struct key_type *type,
#define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */
#define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */
extern int key_payload_reserve(struct key *key, size_t datalen);
extern int key_instantiate_and_link(struct key *key,
const void *data,
size_t datalen,
struct key *keyring,
struct key *instkey);
extern int key_negate_and_link(struct key *key,
unsigned timeout,
struct key *keyring,
struct key *instkey);
extern void key_revoke(struct key *key);
extern void key_put(struct key *key);
......@@ -293,6 +211,17 @@ extern struct key *request_key_with_auxdata(struct key_type *type,
const char *callout_info,
void *aux);
extern struct key *request_key_async(struct key_type *type,
const char *description,
const char *callout_info);
extern struct key *request_key_async_with_auxdata(struct key_type *type,
const char *description,
const char *callout_info,
void *aux);
extern int wait_for_key_construction(struct key *key, bool intr);
extern int key_validate(struct key *key);
extern key_ref_t key_create_or_update(key_ref_t keyring,
......@@ -328,8 +257,6 @@ extern int keyring_add_key(struct key *keyring,
extern struct key *key_lookup(key_serial_t id);
extern void keyring_replace_payload(struct key *key, void *replacement);
#define key_serial(key) ((key) ? (key)->serial : 0)
/*
......
......@@ -14,6 +14,7 @@
#include <linux/skbuff.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/key-type.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/af_rxrpc.h>
......
......@@ -15,7 +15,7 @@
#include <linux/module.h>
#include <linux/net.h>
#include <linux/skbuff.h>
#include <linux/key.h>
#include <linux/key-type.h>
#include <linux/crypto.h>
#include <net/sock.h>
#include <net/af_rxrpc.h>
......@@ -40,7 +40,6 @@ struct key_type key_type_rxrpc = {
.destroy = rxrpc_destroy,
.describe = rxrpc_describe,
};
EXPORT_SYMBOL(key_type_rxrpc);
/*
......@@ -330,5 +329,32 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *conn,
_leave(" = -ENOMEM [ins %d]", ret);
return -ENOMEM;
}
EXPORT_SYMBOL(rxrpc_get_server_data_key);
/**
* rxrpc_get_null_key - Generate a null RxRPC key
* @keyname: The name to give the key.
*
* Generate a null RxRPC key that can be used to indicate anonymous security is
* required for a particular domain.
*/
struct key *rxrpc_get_null_key(const char *keyname)
{
struct key *key;
int ret;
key = key_alloc(&key_type_rxrpc, keyname, 0, 0, current,
KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(key))
return key;
ret = key_instantiate_and_link(key, NULL, 0, NULL, NULL);
if (ret < 0) {
key_revoke(key);
key_put(key);
return ERR_PTR(ret);
}
return key;
}
EXPORT_SYMBOL(rxrpc_get_null_key);
/* internal.h: authentication token and access key management internal defs
*
* Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved.
* Copyright (C) 2003-5, 2007 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
......@@ -12,17 +12,28 @@
#ifndef _INTERNAL_H
#define _INTERNAL_H
#include <linux/key.h>
#include <linux/key-type.h>
#include <linux/key-ui.h>
#if 0
#define kenter(FMT, a...) printk("==> %s("FMT")\n",__FUNCTION__ , ## a)
#define kleave(FMT, a...) printk("<== %s()"FMT"\n",__FUNCTION__ , ## a)
#define kdebug(FMT, a...) printk(FMT"\n" , ## a)
static inline __attribute__((format(printf, 1, 2)))
void no_printk(const char *fmt, ...)
{
}
#ifdef __KDEBUG
#define kenter(FMT, ...) \
printk(KERN_DEBUG "==> %s("FMT")\n", __FUNCTION__, ##__VA_ARGS__)
#define kleave(FMT, ...) \
printk(KERN_DEBUG "<== %s()"FMT"\n", __FUNCTION__, ##__VA_ARGS__)
#define kdebug(FMT, ...) \
printk(KERN_DEBUG "xxx" FMT"yyy\n", ##__VA_ARGS__)
#else
#define kenter(FMT, a...) do {} while(0)
#define kleave(FMT, a...) do {} while(0)
#define kdebug(FMT, a...) do {} while(0)
#define kenter(FMT, ...) \
no_printk(KERN_DEBUG "==> %s("FMT")\n", __FUNCTION__, ##__VA_ARGS__)
#define kleave(FMT, ...) \
no_printk(KERN_DEBUG "<== %s()"FMT"\n", __FUNCTION__, ##__VA_ARGS__)
#define kdebug(FMT, ...) \
no_printk(KERN_DEBUG FMT"\n", ##__VA_ARGS__)
#endif
extern struct key_type key_type_user;
......@@ -36,7 +47,7 @@ extern struct key_type key_type_user;
*/
struct key_user {
struct rb_node node;
struct list_head consq; /* construction queue */
struct mutex cons_lock; /* construction initiation lock */
spinlock_t lock;
atomic_t usage; /* for accessing qnkeys & qnbytes */
atomic_t nkeys; /* number of keys */
......@@ -62,7 +73,7 @@ extern void key_user_put(struct key_user *user);
extern struct rb_root key_serial_tree;
extern spinlock_t key_serial_lock;
extern struct semaphore key_alloc_sem;
extern struct rw_semaphore key_construction_sem;
extern struct mutex key_construction_mutex;
extern wait_queue_head_t request_key_conswq;
......@@ -109,7 +120,7 @@ extern struct key *request_key_and_link(struct key_type *type,
struct request_key_auth {
struct key *target_key;
struct task_struct *context;
const char *callout_info;
char *callout_info;
pid_t pid;
};
......
/* key.c: basic authentication token and access key management
/* Basic authentication token and access key management
*
* Copyright (C) 2004-6 Red Hat, Inc. All Rights Reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
......@@ -34,7 +34,7 @@ static void key_cleanup(struct work_struct *work);
static DECLARE_WORK(key_cleanup_task, key_cleanup);
/* we serialise key instantiation and link */
DECLARE_RWSEM(key_construction_sem);
DEFINE_MUTEX(key_construction_mutex);
/* any key who's type gets unegistered will be re-typed to this */
static struct key_type key_type_dead = {
......@@ -104,7 +104,7 @@ struct key_user *key_user_lookup(uid_t uid)
candidate->qnkeys = 0;
candidate->qnbytes = 0;
spin_lock_init(&candidate->lock);
INIT_LIST_HEAD(&candidate->consq);
mutex_init(&candidate->cons_lock);
rb_link_node(&candidate->node, parent, p);
rb_insert_color(&candidate->node, &key_user_tree);
......@@ -418,7 +418,7 @@ static int __key_instantiate_and_link(struct key *key,
awaken = 0;
ret = -EBUSY;
down_write(&key_construction_sem);
mutex_lock(&key_construction_mutex);
/* can't instantiate twice */
if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
......@@ -443,11 +443,11 @@ static int __key_instantiate_and_link(struct key *key,
}
}
up_write(&key_construction_sem);
mutex_unlock(&key_construction_mutex);
/* wake up anyone waiting for a key to be constructed */
if (awaken)
wake_up_all(&request_key_conswq);
wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
return ret;
......@@ -500,7 +500,7 @@ int key_negate_and_link(struct key *key,
if (keyring)
down_write(&keyring->sem);
down_write(&key_construction_sem);
mutex_lock(&key_construction_mutex);
/* can't instantiate twice */
if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
......@@ -525,14 +525,14 @@ int key_negate_and_link(struct key *key,
key_revoke(instkey);
}
up_write(&key_construction_sem);
mutex_unlock(&key_construction_mutex);
if (keyring)
up_write(&keyring->sem);
/* wake up anyone waiting for a key to be constructed */
if (awaken)
wake_up_all(&request_key_conswq);
wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
return ret;
......@@ -899,12 +899,14 @@ void key_revoke(struct key *key)
{
key_check(key);
/* make sure no one's trying to change or use the key when we mark
* it */
down_write(&key->sem);
set_bit(KEY_FLAG_REVOKED, &key->flags);
if (key->type->revoke)
/* make sure no one's trying to change or use the key when we mark it
* - we tell lockdep that we might nest because we might be revoking an
* authorisation key whilst holding the sem on a key we've just
* instantiated
*/
down_write_nested(&key->sem, 1);
if (!test_and_set_bit(KEY_FLAG_REVOKED, &key->flags) &&
key->type->revoke)
key->type->revoke(key);
up_write(&key->sem);
......
......@@ -26,7 +26,7 @@ static DEFINE_MUTEX(key_session_mutex);
/* the root user's tracking struct */
struct key_user root_key_user = {
.usage = ATOMIC_INIT(3),
.consq = LIST_HEAD_INIT(root_key_user.consq),
.cons_lock = __MUTEX_INITIALIZER(root_key_user.cons_lock),
.lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock),
.nkeys = ATOMIC_INIT(2),
.nikeys = ATOMIC_INIT(2),
......@@ -679,8 +679,18 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
break;
}
/* check the status */
if (perm) {
if (!partial) {
ret = wait_for_key_construction(key, true);
switch (ret) {
case -ERESTARTSYS:
goto invalid_key;
default:
if (perm)
goto invalid_key;
case 0:
break;
}
} else if (perm) {
ret = key_validate(key);
if (ret < 0)
goto invalid_key;
......
This diff is collapsed.
......@@ -127,6 +127,7 @@ static void request_key_auth_destroy(struct key *key)
}
key_put(rka->target_key);
kfree(rka->callout_info);
kfree(rka);
} /* end request_key_auth_destroy() */
......@@ -151,6 +152,12 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
kleave(" = -ENOMEM");
return ERR_PTR(-ENOMEM);
}
rka->callout_info = kmalloc(strlen(callout_info) + 1, GFP_KERNEL);
if (!rka->callout_info) {
kleave(" = -ENOMEM");
kfree(rka);
return ERR_PTR(-ENOMEM);
}
/* see if the calling process is already servicing the key request of
* another process */
......@@ -179,7 +186,7 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
}
rka->target_key = key_get(target);
rka->callout_info = callout_info;
strcpy(rka->callout_info, callout_info);
/* allocate the auth key */
sprintf(desc, "%x", target->serial);
......@@ -203,6 +210,7 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
auth_key_revoked:
up_read(&current->request_key_auth->sem);
kfree(rka->callout_info);
kfree(rka);
kleave("= -EKEYREVOKED");
return ERR_PTR(-EKEYREVOKED);
......@@ -212,6 +220,7 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
key_put(authkey);
error_alloc:
key_put(rka->target_key);
kfree(rka->callout_info);
kfree(rka);
kleave("= %d", ret);
return ERR_PTR(ret);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment