diff options
Diffstat (limited to 'security/keys')
-rw-r--r-- | security/keys/key.c | 18 | ||||
-rw-r--r-- | security/keys/keyctl.c | 155 | ||||
-rw-r--r-- | security/keys/process_keys.c | 7 |
3 files changed, 65 insertions, 115 deletions
diff --git a/security/keys/key.c b/security/keys/key.c index 99781b79831..a057e3311aa 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -1,6 +1,6 @@ /* key.c: basic authentication token and access key management * - * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. + * Copyright (C) 2004-6 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or @@ -271,7 +271,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, * its description */ if (!not_in_quota) { spin_lock(&user->lock); - if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS && + if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS || user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES ) goto no_quota; @@ -795,12 +795,16 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, goto error_3; } - /* search for an existing key of the same type and description in the - * destination keyring + /* if it's possible to update this type of key, search for an existing + * key of the same type and description in the destination keyring and + * update that instead if possible */ - key_ref = __keyring_search_one(keyring_ref, ktype, description, 0); - if (!IS_ERR(key_ref)) - goto found_matching_key; + if (ktype->update) { + key_ref = __keyring_search_one(keyring_ref, ktype, description, + 0); + if (!IS_ERR(key_ref)) + goto found_matching_key; + } /* decide on the permissions we want */ perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 0c62798ac7d..ed71d86d2ce 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -17,10 +17,33 @@ #include <linux/keyctl.h> #include <linux/fs.h> #include <linux/capability.h> +#include <linux/string.h> #include <linux/err.h> #include <asm/uaccess.h> #include "internal.h" +static int key_get_type_from_user(char *type, + const char __user *_type, + unsigned len) +{ + int ret; + + ret = strncpy_from_user(type, _type, len); + + if (ret < 0) + return -EFAULT; + + if (ret == 0 || ret >= len) + return -EINVAL; + + if (type[0] == '.') + return -EPERM; + + type[len - 1] = '\0'; + + return 0; +} + /*****************************************************************************/ /* * extract the description of a new key from userspace and either add it as a @@ -38,40 +61,22 @@ asmlinkage long sys_add_key(const char __user *_type, key_ref_t keyring_ref, key_ref; char type[32], *description; void *payload; - long dlen, ret; + long ret; ret = -EINVAL; if (plen > 32767) goto error; /* draw all the data into kernel space */ - ret = strncpy_from_user(type, _type, sizeof(type) - 1); + ret = key_get_type_from_user(type, _type, sizeof(type)); if (ret < 0) goto error; - type[31] = '\0'; - - ret = -EPERM; - if (type[0] == '.') - goto error; - - ret = -EFAULT; - dlen = strnlen_user(_description, PAGE_SIZE - 1); - if (dlen <= 0) - goto error; - ret = -EINVAL; - if (dlen > PAGE_SIZE - 1) - goto error; - - ret = -ENOMEM; - description = kmalloc(dlen + 1, GFP_KERNEL); - if (!description) + description = strndup_user(_description, PAGE_SIZE); + if (IS_ERR(description)) { + ret = PTR_ERR(description); goto error; - description[dlen] = '\0'; - - ret = -EFAULT; - if (copy_from_user(description, _description, dlen) != 0) - goto error2; + } /* pull the payload in if one was supplied */ payload = NULL; @@ -136,59 +141,28 @@ asmlinkage long sys_request_key(const char __user *_type, struct key *key; key_ref_t dest_ref; char type[32], *description, *callout_info; - long dlen, ret; + long ret; /* pull the type into kernel space */ - ret = strncpy_from_user(type, _type, sizeof(type) - 1); + ret = key_get_type_from_user(type, _type, sizeof(type)); if (ret < 0) goto error; - type[31] = '\0'; - - ret = -EPERM; - if (type[0] == '.') - goto error; /* pull the description into kernel space */ - ret = -EFAULT; - dlen = strnlen_user(_description, PAGE_SIZE - 1); - if (dlen <= 0) - goto error; - - ret = -EINVAL; - if (dlen > PAGE_SIZE - 1) - goto error; - - ret = -ENOMEM; - description = kmalloc(dlen + 1, GFP_KERNEL); - if (!description) + description = strndup_user(_description, PAGE_SIZE); + if (IS_ERR(description)) { + ret = PTR_ERR(description); goto error; - description[dlen] = '\0'; - - ret = -EFAULT; - if (copy_from_user(description, _description, dlen) != 0) - goto error2; + } /* pull the callout info into kernel space */ callout_info = NULL; if (_callout_info) { - ret = -EFAULT; - dlen = strnlen_user(_callout_info, PAGE_SIZE - 1); - if (dlen <= 0) - goto error2; - - ret = -EINVAL; - if (dlen > PAGE_SIZE - 1) - goto error2; - - ret = -ENOMEM; - callout_info = kmalloc(dlen + 1, GFP_KERNEL); - if (!callout_info) + callout_info = strndup_user(_callout_info, PAGE_SIZE); + if (IS_ERR(callout_info)) { + ret = PTR_ERR(callout_info); goto error2; - callout_info[dlen] = '\0'; - - ret = -EFAULT; - if (copy_from_user(callout_info, _callout_info, dlen) != 0) - goto error3; + } } /* get the destination keyring if specified */ @@ -264,36 +238,21 @@ long keyctl_get_keyring_ID(key_serial_t id, int create) long keyctl_join_session_keyring(const char __user *_name) { char *name; - long nlen, ret; + long ret; /* fetch the name from userspace */ name = NULL; if (_name) { - ret = -EFAULT; - nlen = strnlen_user(_name, PAGE_SIZE - 1); - if (nlen <= 0) - goto error; - - ret = -EINVAL; - if (nlen > PAGE_SIZE - 1) + name = strndup_user(_name, PAGE_SIZE); + if (IS_ERR(name)) { + ret = PTR_ERR(name); goto error; - - ret = -ENOMEM; - name = kmalloc(nlen + 1, GFP_KERNEL); - if (!name) - goto error; - name[nlen] = '\0'; - - ret = -EFAULT; - if (copy_from_user(name, _name, nlen) != 0) - goto error2; + } } /* join the session */ ret = join_session_keyring(name); - error2: - kfree(name); error: return ret; @@ -566,32 +525,18 @@ long keyctl_keyring_search(key_serial_t ringid, struct key_type *ktype; key_ref_t keyring_ref, key_ref, dest_ref; char type[32], *description; - long dlen, ret; + long ret; /* pull the type and description into kernel space */ - ret = strncpy_from_user(type, _type, sizeof(type) - 1); + ret = key_get_type_from_user(type, _type, sizeof(type)); if (ret < 0) goto error; - type[31] = '\0'; - ret = -EFAULT; - dlen = strnlen_user(_description, PAGE_SIZE - 1); - if (dlen <= 0) + description = strndup_user(_description, PAGE_SIZE); + if (IS_ERR(description)) { + ret = PTR_ERR(description); goto error; - - ret = -EINVAL; - if (dlen > PAGE_SIZE - 1) - goto error; - - ret = -ENOMEM; - description = kmalloc(dlen + 1, GFP_KERNEL); - if (!description) - goto error; - description[dlen] = '\0'; - - ret = -EFAULT; - if (copy_from_user(description, _description, dlen) != 0) - goto error2; + } /* get the keyring at which to begin the search */ keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH); diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 74cb79eb917..f6940618e34 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -16,11 +16,12 @@ #include <linux/keyctl.h> #include <linux/fs.h> #include <linux/err.h> +#include <linux/mutex.h> #include <asm/uaccess.h> #include "internal.h" /* session keyring create vs join semaphore */ -static DECLARE_MUTEX(key_session_sem); +static DEFINE_MUTEX(key_session_mutex); /* the root user's tracking struct */ struct key_user root_key_user = { @@ -711,7 +712,7 @@ long join_session_keyring(const char *name) } /* allow the user to join or create a named keyring */ - down(&key_session_sem); + mutex_lock(&key_session_mutex); /* look for an existing keyring of this name */ keyring = find_keyring_by_name(name, 0); @@ -737,7 +738,7 @@ long join_session_keyring(const char *name) key_put(keyring); error2: - up(&key_session_sem); + mutex_unlock(&key_session_mutex); error: return ret; |