diff options
Diffstat (limited to 'security/keys')
-rw-r--r-- | security/keys/internal.h | 35 | ||||
-rw-r--r-- | security/keys/key.c | 34 | ||||
-rw-r--r-- | security/keys/process_keys.c | 16 | ||||
-rw-r--r-- | security/keys/request_key.c | 556 | ||||
-rw-r--r-- | security/keys/request_key_auth.c | 11 |
5 files changed, 335 insertions, 317 deletions
diff --git a/security/keys/internal.h b/security/keys/internal.h index 1bb416f4bbc..d36d6939335 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -1,6 +1,6 @@ /* 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; }; diff --git a/security/keys/key.c b/security/keys/key.c index 01bbc6d9d19..fdd5ca6d89f 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -1,6 +1,6 @@ -/* 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); diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index b6f86808475..2a0eb946fc7 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -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; diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 557500110a1..6381e616c47 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -1,6 +1,6 @@ -/* request_key.c: request a key from userspace +/* Request a key from userspace * - * 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 @@ -18,27 +18,54 @@ #include <linux/keyctl.h> #include "internal.h" -struct key_construction { - struct list_head link; /* link in construction queue */ - struct key *key; /* key being constructed */ -}; +/* + * wait_on_bit() sleep function for uninterruptible waiting + */ +static int key_wait_bit(void *flags) +{ + schedule(); + return 0; +} + +/* + * wait_on_bit() sleep function for interruptible waiting + */ +static int key_wait_bit_intr(void *flags) +{ + schedule(); + return signal_pending(current) ? -ERESTARTSYS : 0; +} + +/* + * call to complete the construction of a key + */ +void complete_request_key(struct key_construction *cons, int error) +{ + kenter("{%d,%d},%d", cons->key->serial, cons->authkey->serial, error); -/* when waiting for someone else's keys, you get added to this */ -DECLARE_WAIT_QUEUE_HEAD(request_key_conswq); + if (error < 0) + key_negate_and_link(cons->key, key_negative_timeout, NULL, + cons->authkey); + else + key_revoke(cons->authkey); + + key_put(cons->key); + key_put(cons->authkey); + kfree(cons); +} +EXPORT_SYMBOL(complete_request_key); -/*****************************************************************************/ /* * request userspace finish the construction of a key * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>" */ -static int call_sbin_request_key(struct key *key, - struct key *authkey, +static int call_sbin_request_key(struct key_construction *cons, const char *op, void *aux) { struct task_struct *tsk = current; key_serial_t prkey, sskey; - struct key *keyring; + struct key *key = cons->key, *authkey = cons->authkey, *keyring; char *argv[9], *envp[3], uid_str[12], gid_str[12]; char key_str[12], keyring_str[3][12]; char desc[20]; @@ -82,8 +109,7 @@ static int call_sbin_request_key(struct key *key, rcu_read_lock(); sskey = rcu_dereference(tsk->signal->session_keyring)->serial; rcu_read_unlock(); - } - else { + } else { sskey = tsk->user->session_keyring->serial; } @@ -110,228 +136,77 @@ static int call_sbin_request_key(struct key *key, /* do it */ ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, UMH_WAIT_PROC); + kdebug("usermode -> 0x%x", ret); + if (ret >= 0) { + /* ret is the exit/wait code */ + if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags) || + key_validate(key) < 0) + ret = -ENOKEY; + else + /* ignore any errors from userspace if the key was + * instantiated */ + ret = 0; + } error_link: key_put(keyring); error_alloc: kleave(" = %d", ret); + complete_request_key(cons, ret); return ret; +} -} /* end call_sbin_request_key() */ - -/*****************************************************************************/ /* - * call out to userspace for the key - * - called with the construction sem held, but the sem is dropped here + * call out to userspace for key construction * - we ignore program failure and go on key status instead */ -static struct key *__request_key_construction(struct key_type *type, - const char *description, - const char *callout_info, - void *aux, - unsigned long flags) +static int construct_key(struct key *key, const char *callout_info, void *aux) { + struct key_construction *cons; request_key_actor_t actor; - struct key_construction cons; - struct timespec now; - struct key *key, *authkey; - int ret, negated; + struct key *authkey; + int ret; - kenter("%s,%s,%s,%lx", type->name, description, callout_info, flags); + kenter("%d,%s,%p", key->serial, callout_info, aux); - /* create a key and add it to the queue */ - key = key_alloc(type, description, - current->fsuid, current->fsgid, current, KEY_POS_ALL, - flags); - if (IS_ERR(key)) - goto alloc_failed; - - set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); - - cons.key = key; - list_add_tail(&cons.link, &key->user->consq); - - /* we drop the construction sem here on behalf of the caller */ - up_write(&key_construction_sem); + cons = kmalloc(sizeof(*cons), GFP_KERNEL); + if (!cons) + return -ENOMEM; /* allocate an authorisation key */ authkey = request_key_auth_new(key, callout_info); if (IS_ERR(authkey)) { + kfree(cons); ret = PTR_ERR(authkey); authkey = NULL; - goto alloc_authkey_failed; - } - - /* make the call */ - actor = call_sbin_request_key; - if (type->request_key) - actor = type->request_key; - ret = actor(key, authkey, "create", aux); - if (ret < 0) - goto request_failed; - - /* if the key wasn't instantiated, then we want to give an error */ - ret = -ENOKEY; - if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) - goto request_failed; - - key_revoke(authkey); - key_put(authkey); - - down_write(&key_construction_sem); - list_del(&cons.link); - up_write(&key_construction_sem); - - /* also give an error if the key was negatively instantiated */ -check_not_negative: - if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { - key_put(key); - key = ERR_PTR(-ENOKEY); - } - -out: - kleave(" = %p", key); - return key; - -request_failed: - key_revoke(authkey); - key_put(authkey); - -alloc_authkey_failed: - /* it wasn't instantiated - * - remove from construction queue - * - mark the key as dead - */ - negated = 0; - down_write(&key_construction_sem); - - list_del(&cons.link); - - /* check it didn't get instantiated between the check and the down */ - if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { - set_bit(KEY_FLAG_NEGATIVE, &key->flags); - set_bit(KEY_FLAG_INSTANTIATED, &key->flags); - negated = 1; - } - - clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); - - up_write(&key_construction_sem); - - if (!negated) - goto check_not_negative; /* surprisingly, the key got - * instantiated */ - - /* set the timeout and store in the session keyring if we can */ - now = current_kernel_time(); - key->expiry = now.tv_sec + key_negative_timeout; - - if (current->signal->session_keyring) { - struct key *keyring; - - rcu_read_lock(); - keyring = rcu_dereference(current->signal->session_keyring); - atomic_inc(&keyring->usage); - rcu_read_unlock(); - - key_link(keyring, key); - key_put(keyring); - } - - key_put(key); - - /* notify anyone who was waiting */ - wake_up_all(&request_key_conswq); - - key = ERR_PTR(ret); - goto out; - -alloc_failed: - up_write(&key_construction_sem); - goto out; - -} /* end __request_key_construction() */ - -/*****************************************************************************/ -/* - * call out to userspace to request the key - * - we check the construction queue first to see if an appropriate key is - * already being constructed by userspace - */ -static struct key *request_key_construction(struct key_type *type, - const char *description, - const char *callout_info, - void *aux, - struct key_user *user, - unsigned long flags) -{ - struct key_construction *pcons; - struct key *key, *ckey; - - DECLARE_WAITQUEUE(myself, current); - - kenter("%s,%s,{%d},%s,%lx", - type->name, description, user->uid, callout_info, flags); - - /* see if there's such a key under construction already */ - down_write(&key_construction_sem); - - list_for_each_entry(pcons, &user->consq, link) { - ckey = pcons->key; - - if (ckey->type != type) - continue; - - if (type->match(ckey, description)) - goto found_key_under_construction; + } else { + cons->authkey = key_get(authkey); + cons->key = key_get(key); + + /* make the call */ + actor = call_sbin_request_key; + if (key->type->request_key) + actor = key->type->request_key; + + ret = actor(cons, "create", aux); + + /* check that the actor called complete_request_key() prior to + * returning an error */ + WARN_ON(ret < 0 && + !test_bit(KEY_FLAG_REVOKED, &authkey->flags)); + key_put(authkey); } - /* see about getting userspace to construct the key */ - key = __request_key_construction(type, description, callout_info, aux, - flags); - error: - kleave(" = %p", key); - return key; - - /* someone else has the same key under construction - * - we want to keep an eye on their key - */ - found_key_under_construction: - atomic_inc(&ckey->usage); - up_write(&key_construction_sem); - - /* wait for the key to be completed one way or another */ - add_wait_queue(&request_key_conswq, &myself); - - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (!test_bit(KEY_FLAG_USER_CONSTRUCT, &ckey->flags)) - break; - if (signal_pending(current)) - break; - schedule(); - } - - set_current_state(TASK_RUNNING); - remove_wait_queue(&request_key_conswq, &myself); - - /* we'll need to search this process's keyrings to see if the key is - * now there since we can't automatically assume it's also available - * there */ - key_put(ckey); - ckey = NULL; - - key = NULL; /* request a retry */ - goto error; - -} /* end request_key_construction() */ + kleave(" = %d", ret); + return ret; +} -/*****************************************************************************/ /* - * link a freshly minted key to an appropriate destination keyring + * link a key to the appropriate destination keyring + * - the caller must hold a write lock on the destination keyring */ -static void request_key_link(struct key *key, struct key *dest_keyring) +static void construct_key_make_link(struct key *key, struct key *dest_keyring) { struct task_struct *tsk = current; struct key *drop = NULL; @@ -363,11 +238,11 @@ static void request_key_link(struct key *key, struct key *dest_keyring) break; case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: - dest_keyring = current->user->session_keyring; + dest_keyring = tsk->user->session_keyring; break; case KEY_REQKEY_DEFL_USER_KEYRING: - dest_keyring = current->user->uid_keyring; + dest_keyring = tsk->user->uid_keyring; break; case KEY_REQKEY_DEFL_GROUP_KEYRING: @@ -377,15 +252,115 @@ static void request_key_link(struct key *key, struct key *dest_keyring) } /* and attach the key to it */ - key_link(dest_keyring, key); - + __key_link(dest_keyring, key); key_put(drop); - kleave(""); +} -} /* end request_key_link() */ +/* + * allocate a new key in under-construction state and attempt to link it in to + * the requested place + * - may return a key that's already under construction instead + */ +static int construct_alloc_key(struct key_type *type, + const char *description, + struct key *dest_keyring, + unsigned long flags, + struct key_user *user, + struct key **_key) +{ + struct key *key; + key_ref_t key_ref; + + kenter("%s,%s,,,", type->name, description); + + mutex_lock(&user->cons_lock); + + key = key_alloc(type, description, + current->fsuid, current->fsgid, current, KEY_POS_ALL, + flags); + if (IS_ERR(key)) + goto alloc_failed; + + set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); + + if (dest_keyring) + down_write(&dest_keyring->sem); + + /* attach the key to the destination keyring under lock, but we do need + * to do another check just in case someone beat us to it whilst we + * waited for locks */ + mutex_lock(&key_construction_mutex); + + key_ref = search_process_keyrings(type, description, type->match, + current); + if (!IS_ERR(key_ref)) + goto key_already_present; + + if (dest_keyring) + construct_key_make_link(key, dest_keyring); + + mutex_unlock(&key_construction_mutex); + if (dest_keyring) + up_write(&dest_keyring->sem); + mutex_unlock(&user->cons_lock); + *_key = key; + kleave(" = 0 [%d]", key_serial(key)); + return 0; + +key_already_present: + mutex_unlock(&key_construction_mutex); + if (dest_keyring) + up_write(&dest_keyring->sem); + mutex_unlock(&user->cons_lock); + key_put(key); + *_key = key = key_ref_to_ptr(key_ref); + kleave(" = -EINPROGRESS [%d]", key_serial(key)); + return -EINPROGRESS; + +alloc_failed: + mutex_unlock(&user->cons_lock); + *_key = NULL; + kleave(" = %ld", PTR_ERR(key)); + return PTR_ERR(key); +} + +/* + * commence key construction + */ +static struct key *construct_key_and_link(struct key_type *type, + const char *description, + const char *callout_info, + void *aux, + struct key *dest_keyring, + unsigned long flags) +{ + struct key_user *user; + struct key *key; + int ret; + + user = key_user_lookup(current->fsuid); + if (!user) + return ERR_PTR(-ENOMEM); + + ret = construct_alloc_key(type, description, dest_keyring, flags, user, + &key); + key_user_put(user); + + if (ret == 0) { + ret = construct_key(key, callout_info, aux); + if (ret < 0) + goto construction_failed; + } + + return key; + +construction_failed: + key_negate_and_link(key, key_negative_timeout, NULL, NULL); + key_put(key); + return ERR_PTR(ret); +} -/*****************************************************************************/ /* * request a key * - search the process's keyrings @@ -400,7 +375,6 @@ struct key *request_key_and_link(struct key_type *type, struct key *dest_keyring, unsigned long flags) { - struct key_user *user; struct key *key; key_ref_t key_ref; @@ -412,112 +386,124 @@ struct key *request_key_and_link(struct key_type *type, key_ref = search_process_keyrings(type, description, type->match, current); - kdebug("search 1: %p", key_ref); - if (!IS_ERR(key_ref)) { key = key_ref_to_ptr(key_ref); - } - else if (PTR_ERR(key_ref) != -EAGAIN) { + } else if (PTR_ERR(key_ref) != -EAGAIN) { key = ERR_PTR(PTR_ERR(key_ref)); - } - else { + } else { /* the search failed, but the keyrings were searchable, so we * should consult userspace if we can */ key = ERR_PTR(-ENOKEY); if (!callout_info) goto error; - /* - get hold of the user's construction queue */ - user = key_user_lookup(current->fsuid); - if (!user) - goto nomem; - - for (;;) { - if (signal_pending(current)) - goto interrupted; - - /* ask userspace (returns NULL if it waited on a key - * being constructed) */ - key = request_key_construction(type, description, - callout_info, aux, - user, flags); - if (key) - break; - - /* someone else made the key we want, so we need to - * search again as it might now be available to us */ - key_ref = search_process_keyrings(type, description, - type->match, - current); - - kdebug("search 2: %p", key_ref); - - if (!IS_ERR(key_ref)) { - key = key_ref_to_ptr(key_ref); - break; - } - - if (PTR_ERR(key_ref) != -EAGAIN) { - key = ERR_PTR(PTR_ERR(key_ref)); - break; - } - } - - key_user_put(user); - - /* link the new key into the appropriate keyring */ - if (!IS_ERR(key)) - request_key_link(key, dest_keyring); + key = construct_key_and_link(type, description, callout_info, + aux, dest_keyring, flags); } error: kleave(" = %p", key); return key; +} -nomem: - key = ERR_PTR(-ENOMEM); - goto error; - -interrupted: - key_user_put(user); - key = ERR_PTR(-EINTR); - goto error; +/* + * wait for construction of a key to complete + */ +int wait_for_key_construction(struct key *key, bool intr) +{ + int ret; -} /* end request_key_and_link() */ + ret = wait_on_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT, + intr ? key_wait_bit_intr : key_wait_bit, + intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); + if (ret < 0) + return ret; + return key_validate(key); +} +EXPORT_SYMBOL(wait_for_key_construction); -/*****************************************************************************/ /* * request a key * - search the process's keyrings * - check the list of keys being created or updated * - call out to userspace for a key if supplementary info was provided + * - waits uninterruptible for creation to complete */ struct key *request_key(struct key_type *type, const char *description, const char *callout_info) { - return request_key_and_link(type, description, callout_info, NULL, - NULL, KEY_ALLOC_IN_QUOTA); - -} /* end request_key() */ - + struct key *key; + int ret; + + key = request_key_and_link(type, description, callout_info, NULL, + NULL, KEY_ALLOC_IN_QUOTA); + if (!IS_ERR(key)) { + ret = wait_for_key_construction(key, false); + if (ret < 0) { + key_put(key); + return ERR_PTR(ret); + } + } + return key; +} EXPORT_SYMBOL(request_key); -/*****************************************************************************/ /* * request a key with auxiliary data for the upcaller * - search the process's keyrings * - check the list of keys being created or updated * - call out to userspace for a key if supplementary info was provided + * - waits uninterruptible for creation to complete */ struct key *request_key_with_auxdata(struct key_type *type, const char *description, const char *callout_info, void *aux) { - return request_key_and_link(type, description, callout_info, aux, - NULL, KEY_ALLOC_IN_QUOTA); + struct key *key; + int ret; + + key = request_key_and_link(type, description, callout_info, aux, + NULL, KEY_ALLOC_IN_QUOTA); + if (!IS_ERR(key)) { + ret = wait_for_key_construction(key, false); + if (ret < 0) { + key_put(key); + return ERR_PTR(ret); + } + } + return key; +} +EXPORT_SYMBOL(request_key_with_auxdata); -} /* end request_key_with_auxdata() */ +/* + * request a key (allow async construction) + * - search the process's keyrings + * - check the list of keys being created or updated + * - call out to userspace for a key if supplementary info was provided + */ +struct key *request_key_async(struct key_type *type, + const char *description, + const char *callout_info) +{ + return request_key_and_link(type, description, callout_info, NULL, + NULL, KEY_ALLOC_IN_QUOTA); +} +EXPORT_SYMBOL(request_key_async); -EXPORT_SYMBOL(request_key_with_auxdata); +/* + * request a key with auxiliary data for the upcaller (allow async construction) + * - search the process's keyrings + * - check the list of keys being created or updated + * - call out to userspace for a key if supplementary info was provided + */ +struct key *request_key_async_with_auxdata(struct key_type *type, + const char *description, + const char *callout_info, + void *aux) +{ + return request_key_and_link(type, description, callout_info, aux, + NULL, KEY_ALLOC_IN_QUOTA); +} +EXPORT_SYMBOL(request_key_async_with_auxdata); diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index cbf58a91b00..510f7be73a2 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c @@ -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(¤t->request_key_auth->sem); + kfree(rka->callout_info); kfree(rka); kleave("= -EKEYREVOKED"); return ERR_PTR(-EKEYREVOKED); @@ -212,6 +220,7 @@ error_inst: key_put(authkey); error_alloc: key_put(rka->target_key); + kfree(rka->callout_info); kfree(rka); kleave("= %d", ret); return ERR_PTR(ret); |