#include <linux/workqueue.h>
#include <linux/random.h>
#include <linux/err.h>
+#include <linux/user_namespace.h>
#include "internal.h"
static struct kmem_cache *key_jar;
* get the key quota record for a user, allocating a new record if one doesn't
* already exist
*/
-struct key_user *key_user_lookup(uid_t uid)
+struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns)
{
struct key_user *candidate = NULL, *user;
struct rb_node *parent = NULL;
p = &(*p)->rb_left;
else if (uid > user->uid)
p = &(*p)->rb_right;
+ else if (user_ns < user->user_ns)
+ p = &(*p)->rb_left;
+ else if (user_ns > user->user_ns)
+ p = &(*p)->rb_right;
else
goto found;
}
atomic_set(&candidate->nkeys, 0);
atomic_set(&candidate->nikeys, 0);
candidate->uid = uid;
+ candidate->user_ns = get_user_ns(user_ns);
candidate->qnkeys = 0;
candidate->qnbytes = 0;
spin_lock_init(&candidate->lock);
if (atomic_dec_and_lock(&user->usage, &key_user_lock)) {
rb_erase(&user->node, &key_user_tree);
spin_unlock(&key_user_lock);
+ put_user_ns(user->user_ns);
kfree(user);
}
* instantiate the key or discard it before returning
*/
struct key *key_alloc(struct key_type *type, const char *desc,
- uid_t uid, gid_t gid, struct task_struct *ctx,
+ uid_t uid, gid_t gid, const struct cred *cred,
key_perm_t perm, unsigned long flags)
{
struct key_user *user = NULL;
quotalen = desclen + type->def_datalen;
/* get hold of the key tracking for this user */
- user = key_user_lookup(uid);
+ user = key_user_lookup(uid, cred->user->user_ns);
if (!user)
goto no_memory_1;
#endif
/* let the security module know about the key */
- ret = security_key_alloc(key, ctx, flags);
+ ret = security_key_alloc(key, cred, flags);
if (ret < 0)
goto security_error;
const void *data,
size_t datalen,
struct key *keyring,
- struct key *instkey)
+ struct key *authkey)
{
int ret, awaken;
ret = __key_link(keyring, key);
/* disable the authorisation key */
- if (instkey)
- key_revoke(instkey);
+ if (authkey)
+ key_revoke(authkey);
}
}
const void *data,
size_t datalen,
struct key *keyring,
- struct key *instkey)
+ struct key *authkey)
{
int ret;
if (keyring)
down_write(&keyring->sem);
- ret = __key_instantiate_and_link(key, data, datalen, keyring, instkey);
+ ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey);
if (keyring)
up_write(&keyring->sem);
int key_negate_and_link(struct key *key,
unsigned timeout,
struct key *keyring,
- struct key *instkey)
+ struct key *authkey)
{
struct timespec now;
int ret, awaken;
set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
now = current_kernel_time();
key->expiry = now.tv_sec + timeout;
+ key_schedule_gc(key->expiry + key_gc_delay);
if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
awaken = 1;
ret = __key_link(keyring, key);
/* disable the authorisation key */
- if (instkey)
- key_revoke(instkey);
+ if (authkey)
+ key_revoke(authkey);
}
mutex_unlock(&key_construction_mutex);
goto error;
found:
- /* pretend it doesn't exist if it's dead */
- if (atomic_read(&key->usage) == 0 ||
- test_bit(KEY_FLAG_DEAD, &key->flags) ||
- key->type == &key_type_dead)
+ /* pretend it doesn't exist if it is awaiting deletion */
+ if (atomic_read(&key->usage) == 0)
goto not_found;
/* this races with key_put(), but that doesn't matter since key_put()
key_perm_t perm,
unsigned long flags)
{
+ const struct cred *cred = current_cred();
struct key_type *ktype;
struct key *keyring, *key = NULL;
key_ref_t key_ref;
}
/* allocate a new key */
- key = key_alloc(ktype, description, current_fsuid(), current_fsgid(),
- current, perm, flags);
+ key = key_alloc(ktype, description, cred->fsuid, cred->fsgid, cred,
+ perm, flags);
if (IS_ERR(key)) {
key_ref = ERR_CAST(key);
goto error_3;
*/
void key_revoke(struct key *key)
{
+ struct timespec now;
+ time_t time;
+
key_check(key);
/* make sure no one's trying to change or use the key when we mark it
key->type->revoke)
key->type->revoke(key);
+ /* set the death time to no more than the expiry time */
+ now = current_kernel_time();
+ time = now.tv_sec;
+ if (key->revoked_at == 0 || key->revoked_at > time) {
+ key->revoked_at = time;
+ key_schedule_gc(key->revoked_at + key_gc_delay);
+ }
+
up_write(&key->sem);
} /* end key_revoke() */
for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) {
key = rb_entry(_n, struct key, serial_node);
- if (key->type == ktype)
+ if (key->type == ktype) {
key->type = &key_type_dead;
+ set_bit(KEY_FLAG_DEAD, &key->flags);
+ }
}
spin_unlock(&key_serial_lock);
spin_unlock(&key_serial_lock);
up_write(&key_types_sem);
+ key_schedule_gc(0);
+
} /* end unregister_key_type() */
EXPORT_SYMBOL(unregister_key_type);