summaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorMiloslav Trmač <mitr@redhat.com>2010-07-31 00:51:46 +0200
committerMiloslav Trmač <mitr@redhat.com>2010-07-31 00:51:46 +0200
commit49d7012c4c62f6681378a56d9af4d721178b8ad3 (patch)
treef628266a0c07d747dea77fca8cc08a6ff30b912b /crypto
parentdbff0a8826b2dd9abc0c7699ae883a95d468b12c (diff)
parent3f11cfa0d94fcdc42db8812118e7386050660d6e (diff)
downloadkernel-crypto-49d7012c4c62f6681378a56d9af4d721178b8ad3.tar.gz
kernel-crypto-49d7012c4c62f6681378a56d9af4d721178b8ad3.tar.xz
kernel-crypto-49d7012c4c62f6681378a56d9af4d721178b8ad3.zip
Merge branch 'standalone-master' into standalone-rename
Diffstat (limited to 'crypto')
-rw-r--r--crypto/userspace/ncr-int.h61
-rw-r--r--crypto/userspace/ncr-key-wrap.c22
-rw-r--r--crypto/userspace/ncr-key.c200
-rw-r--r--crypto/userspace/ncr-limits.c175
-rw-r--r--crypto/userspace/ncr-pk.c8
-rw-r--r--crypto/userspace/ncr-sessions.c129
-rw-r--r--crypto/userspace/ncr.c36
7 files changed, 328 insertions, 303 deletions
diff --git a/crypto/userspace/ncr-int.h b/crypto/userspace/ncr-int.h
index e79747c12ca..008a89b181f 100644
--- a/crypto/userspace/ncr-int.h
+++ b/crypto/userspace/ncr-int.h
@@ -1,6 +1,8 @@
#ifndef NCR_INT_H
# define NCR_INT_H
+#include <linux/idr.h>
+#include <linux/mutex.h>
#include "ncr.h"
#include <asm/atomic.h>
#include "cryptodev_int.h"
@@ -31,8 +33,6 @@ struct algo_properties_st {
};
struct session_item_st {
- struct list_head list;
-
const struct algo_properties_st *algorithm;
ncr_crypto_op_t op;
@@ -59,7 +59,6 @@ struct session_item_st {
};
struct key_item_st {
- struct list_head list;
/* This object is also not protected from concurrent access.
*/
ncr_key_type_t type;
@@ -90,19 +89,16 @@ struct key_item_st {
ncr_key_t desc;
};
-struct list_sem_st {
- struct list_head list;
- struct semaphore sem;
-};
-
/* all the data associated with the open descriptor
* are here.
*/
struct ncr_lists {
- struct list_sem_st key;
+ struct mutex key_idr_mutex;
+ struct idr key_idr;
/* sessions */
- struct list_sem_st sessions;
+ struct mutex session_idr_mutex;
+ struct idr session_idr;
};
void* ncr_init_lists(void);
@@ -112,29 +108,30 @@ int ncr_ioctl(struct ncr_lists*, struct file *filp,
unsigned int cmd, unsigned long arg);
/* key derivation */
-int ncr_key_derive(struct list_sem_st* key_lst, void __user* arg);
+int ncr_key_derive(struct ncr_lists *lst, void __user* arg);
/* key handling */
-int ncr_key_init(struct list_sem_st*, void __user* arg);
-int ncr_key_deinit(struct list_sem_st*, void __user* arg);
-int ncr_key_export(struct list_sem_st* key_lst,void __user* arg);
-int ncr_key_import(struct list_sem_st* key_lst,void __user* arg);
-void ncr_key_list_deinit(struct list_sem_st* lst);
-int ncr_key_generate(struct list_sem_st* data_lst, void __user* arg);
-int ncr_key_info(struct list_sem_st*, void __user* arg);
-
-int ncr_key_generate_pair(struct list_sem_st* lst, void __user* arg);
-int ncr_key_get_public(struct list_sem_st* lst, void __user* arg);
-
-int ncr_key_item_get_read(struct key_item_st**st, struct list_sem_st* lst,
+int ncr_key_init(struct ncr_lists *lst, void __user* arg);
+int ncr_key_deinit(struct ncr_lists *lst, void __user* arg);
+int ncr_key_export(struct ncr_lists *lst, void __user* arg);
+int ncr_key_import(struct ncr_lists *lst, void __user* arg);
+void ncr_key_list_deinit(struct ncr_lists *lst);
+int ncr_key_generate(struct ncr_lists *lst, void __user* arg);
+int ncr_key_info(struct ncr_lists *lst, void __user* arg);
+
+int ncr_key_generate_pair(struct ncr_lists *lst, void __user* arg);
+int ncr_key_get_public(struct ncr_lists *lst, void __user* arg);
+
+int ncr_key_item_get_read(struct key_item_st**st, struct ncr_lists *lst,
ncr_key_t desc);
/* get key item for writing */
-int ncr_key_item_get_write( struct key_item_st** st,
- struct list_sem_st* lst, ncr_key_t desc);
+int ncr_key_item_get_write( struct key_item_st** st,
+ struct ncr_lists *lst, ncr_key_t desc);
void _ncr_key_item_put( struct key_item_st* item);
typedef enum {
LIMIT_TYPE_KEY,
+ NUM_LIMIT_TYPES
} limits_type_t;
void ncr_limits_remove(uid_t uid, pid_t pid, limits_type_t type);
@@ -142,16 +139,16 @@ int ncr_limits_add_and_check(uid_t uid, pid_t pid, limits_type_t type);
void ncr_limits_init(void);
void ncr_limits_deinit(void);
-int ncr_key_wrap(struct list_sem_st* keys, void __user* arg);
-int ncr_key_unwrap(struct list_sem_st*, void __user* arg);
-int ncr_key_storage_wrap(struct list_sem_st* key_lst, void __user* arg);
-int ncr_key_storage_unwrap(struct list_sem_st*, void __user* arg);
+int ncr_key_wrap(struct ncr_lists *lst, void __user* arg);
+int ncr_key_unwrap(struct ncr_lists *lst, void __user* arg);
+int ncr_key_storage_wrap(struct ncr_lists *lst, void __user* arg);
+int ncr_key_storage_unwrap(struct ncr_lists *lst, void __user* arg);
/* sessions */
-struct session_item_st* ncr_session_new(struct list_sem_st* lst);
+struct session_item_st* ncr_session_new(struct ncr_lists *lst);
void _ncr_sessions_item_put( struct session_item_st* item);
-struct session_item_st* ncr_sessions_item_get( struct list_sem_st* lst, ncr_session_t desc);
-void ncr_sessions_list_deinit(struct list_sem_st* lst);
+struct session_item_st* ncr_sessions_item_get(struct ncr_lists *lst, ncr_session_t desc);
+void ncr_sessions_list_deinit(struct ncr_lists *lst);
int ncr_session_init(struct ncr_lists* lists, void __user* arg);
int ncr_session_update(struct ncr_lists* lists, void __user* arg);
diff --git a/crypto/userspace/ncr-key-wrap.c b/crypto/userspace/ncr-key-wrap.c
index cb431c9b5aa..34d8c527b83 100644
--- a/crypto/userspace/ncr-key-wrap.c
+++ b/crypto/userspace/ncr-key-wrap.c
@@ -403,7 +403,7 @@ val64_t * R = NULL;
ret = rfc3394_unwrap(wrapped_key, R, n, A, &ctx);
if (ret < 0) {
err();
- return ret;
+ goto cleanup;
}
if (memcmp(A, iv, 8)!= 0) {
@@ -429,7 +429,7 @@ cleanup:
return ret;
}
-int ncr_key_wrap(struct list_sem_st* key_lst, void __user* arg)
+int ncr_key_wrap(struct ncr_lists *lst, void __user* arg)
{
struct ncr_key_wrap_st wrap;
struct key_item_st* wkey = NULL;
@@ -443,7 +443,7 @@ int ret;
return -EFAULT;
}
- ret = ncr_key_item_get_read( &wkey, key_lst, wrap.keytowrap);
+ ret = ncr_key_item_get_read( &wkey, lst, wrap.keytowrap);
if (ret < 0) {
err();
return ret;
@@ -455,7 +455,7 @@ int ret;
goto fail;
}
- ret = ncr_key_item_get_read( &key, key_lst, wrap.key);
+ ret = ncr_key_item_get_read( &key, lst, wrap.key);
if (ret < 0) {
err();
goto fail;
@@ -512,7 +512,7 @@ fail:
/* Unwraps keys. All keys unwrapped are not accessible by
* userspace.
*/
-int ncr_key_unwrap(struct list_sem_st* key_lst, void __user* arg)
+int ncr_key_unwrap(struct ncr_lists *lst, void __user* arg)
{
struct ncr_key_wrap_st wrap;
struct key_item_st* wkey = NULL;
@@ -526,13 +526,13 @@ int ret;
return -EFAULT;
}
- ret = ncr_key_item_get_write( &wkey, key_lst, wrap.keytowrap);
+ ret = ncr_key_item_get_write( &wkey, lst, wrap.keytowrap);
if (ret < 0) {
err();
return ret;
}
- ret = ncr_key_item_get_read( &key, key_lst, wrap.key);
+ ret = ncr_key_item_get_read( &key, lst, wrap.key);
if (ret < 0) {
err();
goto fail;
@@ -574,7 +574,7 @@ fail:
return ret;
}
-int ncr_key_storage_wrap(struct list_sem_st* key_lst, void __user* arg)
+int ncr_key_storage_wrap(struct ncr_lists *lst, void __user* arg)
{
struct ncr_key_storage_wrap_st wrap;
struct key_item_st* wkey = NULL;
@@ -594,7 +594,7 @@ int ret;
return -EFAULT;
}
- ret = ncr_key_item_get_read( &wkey, key_lst, wrap.keytowrap);
+ ret = ncr_key_item_get_read( &wkey, lst, wrap.keytowrap);
if (ret < 0) {
err();
return ret;
@@ -650,7 +650,7 @@ fail:
/* Unwraps keys. All keys unwrapped are not accessible by
* userspace.
*/
-int ncr_key_storage_unwrap(struct list_sem_st* key_lst, void __user* arg)
+int ncr_key_storage_unwrap(struct ncr_lists *lst, void __user* arg)
{
struct ncr_key_storage_wrap_st wrap;
struct key_item_st* wkey = NULL;
@@ -669,7 +669,7 @@ int ret;
return -EFAULT;
}
- ret = ncr_key_item_get_write( &wkey, key_lst, wrap.keytowrap);
+ ret = ncr_key_item_get_write( &wkey, lst, wrap.keytowrap);
if (ret < 0) {
err();
return ret;
diff --git a/crypto/userspace/ncr-key.c b/crypto/userspace/ncr-key.c
index 4ea933cd591..d4f32b1ef85 100644
--- a/crypto/userspace/ncr-key.c
+++ b/crypto/userspace/ncr-key.c
@@ -33,44 +33,26 @@
static void ncr_key_clear(struct key_item_st* item);
-/* must be called with data semaphore down */
-static void _ncr_key_unlink_item(struct key_item_st *item)
+static int key_list_deinit_fn(int id, void *item, void *unused)
{
- list_del(&item->list);
- _ncr_key_item_put( item); /* decrement ref count */
-}
-
-void ncr_key_list_deinit(struct list_sem_st* lst)
-{
- if(lst) {
- struct key_item_st * item, *tmp;
-
- down(&lst->sem);
-
- list_for_each_entry_safe(item, tmp, &lst->list, list) {
- _ncr_key_unlink_item(item);
- }
- up(&lst->sem);
- }
+ (void)unused;
+ _ncr_key_item_put(item);
+ return 0;
}
-/* must be called with data semaphore down
- */
-static ncr_key_t _ncr_key_get_new_desc( struct list_sem_st* lst)
+void ncr_key_list_deinit(struct ncr_lists *lst)
{
-struct key_item_st* item;
-int mx = 1;
-
- list_for_each_entry(item, &lst->list, list) {
- mx = max(mx, item->desc);
- }
- mx++;
-
- return mx;
+ /* The mutex is not necessary, but doesn't hurt and makes it easier to
+ verify locking correctness. */
+ mutex_lock(&lst->key_idr_mutex);
+ idr_for_each(&lst->key_idr, key_list_deinit_fn, NULL);
+ idr_remove_all(&lst->key_idr);
+ idr_destroy(&lst->key_idr);
+ mutex_unlock(&lst->key_idr_mutex);
}
/* returns the data item corresponding to desc */
-int ncr_key_item_get_read(struct key_item_st**st, struct list_sem_st* lst,
+int ncr_key_item_get_read(struct key_item_st**st, struct ncr_lists *lst,
ncr_key_t desc)
{
struct key_item_st* item;
@@ -78,28 +60,27 @@ int ret;
*st = NULL;
- down(&lst->sem);
- list_for_each_entry(item, &lst->list, list) {
- if (item->desc == desc) {
- atomic_inc(&item->refcnt);
-
- if (atomic_read(&item->writer) != 0) {
- /* writer in place busy */
- atomic_dec(&item->refcnt);
- ret = -EBUSY;
- goto exit;
- }
-
- *st = item;
- ret = 0;
- goto exit;
- }
+ mutex_lock(&lst->key_idr_mutex);
+ item = idr_find(&lst->key_idr, desc);
+ if (item == NULL) {
+ err();
+ ret = -EINVAL;
+ goto exit;
}
+ atomic_inc(&item->refcnt);
+
+ if (atomic_read(&item->writer) != 0) {
+ /* writer in place busy */
+ atomic_dec(&item->refcnt);
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ *st = item;
+ ret = 0;
- err();
- ret = -EINVAL;
exit:
- up(&lst->sem);
+ mutex_unlock(&lst->key_idr_mutex);
return ret;
}
@@ -107,42 +88,40 @@ exit:
* is in use.
*/
int ncr_key_item_get_write( struct key_item_st** st,
- struct list_sem_st* lst, ncr_key_t desc)
+ struct ncr_lists *lst, ncr_key_t desc)
{
struct key_item_st* item;
int ret;
*st = NULL;
- down(&lst->sem);
- list_for_each_entry(item, &lst->list, list) {
- if (item->desc == desc) {
- /* do not return items that are in use already */
+ mutex_lock(&lst->key_idr_mutex);
+ item = idr_find(&lst->key_idr, desc);
+ if (item == NULL) {
+ err();
+ ret = -EINVAL;
+ goto exit;
+ }
+ /* do not return items that are in use already */
- if (atomic_add_unless(&item->writer, 1, 1)==0) {
- /* another writer so busy */
- ret = -EBUSY;
- goto exit;
- }
-
- if (atomic_add_unless(&item->refcnt, 1, 2)==0) {
- /* some reader is active so busy */
- atomic_dec(&item->writer);
- ret = -EBUSY;
- goto exit;
- }
+ if (atomic_add_unless(&item->writer, 1, 1)==0) {
+ /* another writer so busy */
+ ret = -EBUSY;
+ goto exit;
+ }
- *st = item;
- ret = 0;
- goto exit;
- }
+ if (atomic_add_unless(&item->refcnt, 1, 2)==0) {
+ /* some reader is active so busy */
+ atomic_dec(&item->writer);
+ ret = -EBUSY;
+ goto exit;
}
- err();
- ret = -EINVAL;
+ *st = item;
+ ret = 0;
exit:
- up(&lst->sem);
+ mutex_unlock(&lst->key_idr_mutex);
return ret;
}
@@ -157,7 +136,21 @@ void _ncr_key_item_put( struct key_item_st* item)
}
}
-int ncr_key_init(struct list_sem_st* lst, void __user* arg)
+static void _ncr_key_remove(struct ncr_lists *lst, ncr_key_t desc)
+{
+ struct key_item_st * item;
+
+ mutex_lock(&lst->key_idr_mutex);
+ item = idr_find(&lst->key_idr, desc);
+ if (item != NULL)
+ idr_remove(&lst->key_idr, desc); /* Steal the reference */
+ mutex_unlock(&lst->key_idr_mutex);
+
+ if (item != NULL)
+ _ncr_key_item_put(item);
+}
+
+int ncr_key_init(struct ncr_lists *lst, void __user* arg)
{
ncr_key_t desc;
struct key_item_st* key;
@@ -180,23 +173,25 @@ int ncr_key_init(struct list_sem_st* lst, void __user* arg)
atomic_set(&key->refcnt, 1);
atomic_set(&key->writer, 0);
-
- down(&lst->sem);
-
- key->desc = _ncr_key_get_new_desc(lst);
key->uid = current_euid();
key->pid = task_pid_nr(current);
- list_add(&key->list, &lst->list);
-
+ mutex_lock(&lst->key_idr_mutex);
+ /* idr_pre_get() should preallocate enough, and, due to key_idr_mutex,
+ nobody else can use the preallocated data. Therefore the loop
+ recommended in idr_get_new() documentation is not necessary. */
+ if (idr_pre_get(&lst->key_idr, GFP_KERNEL) == 0 ||
+ idr_get_new(&lst->key_idr, key, &key->desc) != 0) {
+ mutex_unlock(&lst->key_idr_mutex);
+ _ncr_key_item_put(key);
+ return -ENOMEM;
+ }
desc = key->desc;
- up(&lst->sem);
+ mutex_unlock(&lst->key_idr_mutex);
ret = copy_to_user(arg, &desc, sizeof(desc));
if (unlikely(ret)) {
- down(&lst->sem);
- _ncr_key_unlink_item(key);
- up(&lst->sem);
+ _ncr_key_remove(lst, desc);
return -EFAULT;
}
return ret;
@@ -206,27 +201,16 @@ err_limits:
return ret;
}
-
-int ncr_key_deinit(struct list_sem_st* lst, void __user* arg)
+int ncr_key_deinit(struct ncr_lists *lst, void __user* arg)
{
ncr_key_t desc;
- struct key_item_st * item, *tmp;
if (unlikely(copy_from_user(&desc, arg, sizeof(desc)))) {
err();
return -EFAULT;
}
- down(&lst->sem);
-
- list_for_each_entry_safe(item, tmp, &lst->list, list) {
- if(item->desc == desc) {
- _ncr_key_unlink_item(item);
- break;
- }
- }
-
- up(&lst->sem);
+ _ncr_key_remove(lst, desc);
return 0;
}
@@ -234,7 +218,7 @@ int ncr_key_deinit(struct list_sem_st* lst, void __user* arg)
/* "exports" a key to a data item. If the key is not exportable
* to userspace then the data item will also not be.
*/
-int ncr_key_export(struct list_sem_st* key_lst, void __user* arg)
+int ncr_key_export(struct ncr_lists *lst, void __user* arg)
{
struct ncr_key_data_st data;
struct key_item_st* item = NULL;
@@ -247,7 +231,7 @@ int ret;
return -EFAULT;
}
- ret = ncr_key_item_get_read( &item, key_lst, data.key);
+ ret = ncr_key_item_get_read( &item, lst, data.key);
if (ret < 0) {
err();
return ret;
@@ -329,7 +313,7 @@ fail:
/* "imports" a key from a data item. If the key is not exportable
* to userspace then the key item will also not be.
*/
-int ncr_key_import(struct list_sem_st* key_lst, void __user* arg)
+int ncr_key_import(struct ncr_lists *lst, void __user* arg)
{
struct ncr_key_data_st data;
struct key_item_st* item = NULL;
@@ -342,7 +326,7 @@ size_t tmp_size;
return -EFAULT;
}
- ret = ncr_key_item_get_write( &item, key_lst, data.key);
+ ret = ncr_key_item_get_write( &item, lst, data.key);
if (ret < 0) {
err();
return ret;
@@ -438,7 +422,7 @@ static void ncr_key_clear(struct key_item_st* item)
/* Generate a secret key
*/
-int ncr_key_generate(struct list_sem_st* lst, void __user* arg)
+int ncr_key_generate(struct ncr_lists *lst, void __user* arg)
{
struct ncr_key_generate_st gen;
struct key_item_st* item = NULL;
@@ -500,7 +484,7 @@ fail:
return ret;
}
-int ncr_key_info(struct list_sem_st* lst, void __user* arg)
+int ncr_key_info(struct ncr_lists *lst, void __user* arg)
{
struct ncr_key_info_st info;
struct key_item_st* item = NULL;
@@ -535,7 +519,7 @@ fail:
return ret;
}
-int ncr_key_generate_pair(struct list_sem_st* lst, void __user* arg)
+int ncr_key_generate_pair(struct ncr_lists *lst, void __user* arg)
{
struct ncr_key_generate_st gen;
struct key_item_st* private = NULL;
@@ -602,7 +586,7 @@ fail:
/* "exports" a key to a data item. If the key is not exportable
* to userspace then the data item will also not be.
*/
-int ncr_key_derive(struct list_sem_st* key_lst, void __user* arg)
+int ncr_key_derive(struct ncr_lists *lst, void __user* arg)
{
struct ncr_key_derivation_params_st data;
int ret;
@@ -614,13 +598,13 @@ struct key_item_st* newkey = NULL;
return -EFAULT;
}
- ret = ncr_key_item_get_read( &key, key_lst, data.key);
+ ret = ncr_key_item_get_read( &key, lst, data.key);
if (ret < 0) {
err();
return ret;
}
- ret = ncr_key_item_get_write( &newkey, key_lst, data.newkey);
+ ret = ncr_key_item_get_write( &newkey, lst, data.newkey);
if (ret < 0) {
err();
goto fail;
diff --git a/crypto/userspace/ncr-limits.c b/crypto/userspace/ncr-limits.c
index a1ad7e36411..ff8ff59876f 100644
--- a/crypto/userspace/ncr-limits.c
+++ b/crypto/userspace/ncr-limits.c
@@ -22,6 +22,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <linux/hash.h>
+#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/highmem.h>
@@ -44,53 +46,76 @@ static unsigned int max_per_process[] = {
};
struct limit_user_item_st {
- struct list_head list;
+ struct hlist_node hlist;
uid_t uid;
- limits_type_t type;
- atomic_t cnt;
+ atomic_t cnt[NUM_LIMIT_TYPES];
};
struct limit_process_item_st {
- struct list_head list;
+ struct hlist_node hlist;
pid_t pid;
- limits_type_t type;
- atomic_t cnt;
+ atomic_t cnt[NUM_LIMIT_TYPES];
};
-struct limit_st {
- struct list_sem_st users;
- struct list_sem_st processes;
-};
+static struct mutex user_limit_mutex;
+#define USER_LIMIT_HASH_BITS 7
+#define USER_LIMIT_TABLE_SIZE (1 << USER_LIMIT_HASH_BITS)
+static struct hlist_head user_limit_table[USER_LIMIT_TABLE_SIZE];
-static struct limit_st limits;
+static struct hlist_head *user_limit_hash(uid_t uid)
+{
+ return &user_limit_table[hash_long(uid, USER_LIMIT_HASH_BITS)];
+}
+
+static struct mutex process_limit_mutex;
+#define PROCESS_LIMIT_HASH_BITS 9
+#define PROCESS_LIMIT_TABLE_SIZE (1 << PROCESS_LIMIT_HASH_BITS)
+static struct hlist_head process_limit_table[PROCESS_LIMIT_TABLE_SIZE];
+
+static struct hlist_head *process_limit_hash(pid_t pid)
+{
+ return &process_limit_table[hash_long(pid, PROCESS_LIMIT_HASH_BITS)];
+}
void ncr_limits_init(void)
{
- init_MUTEX(&limits.users.sem);
- INIT_LIST_HEAD(&limits.users.list);
+ size_t i;
- init_MUTEX(&limits.processes.sem);
- INIT_LIST_HEAD(&limits.processes.list);
+ mutex_init(&user_limit_mutex);
+ for (i = 0; i < USER_LIMIT_TABLE_SIZE; i++)
+ INIT_HLIST_HEAD(&user_limit_table[i]);
+
+ mutex_init(&process_limit_mutex);
+ for (i = 0; i < PROCESS_LIMIT_TABLE_SIZE; i++)
+ INIT_HLIST_HEAD(&process_limit_table[i]);
}
void ncr_limits_deinit(void)
{
-struct limit_process_item_st* pitem, *ptmp;
-struct limit_user_item_st* uitem, *utmp;
-
- down(&limits.users.sem);
- list_for_each_entry_safe(uitem, utmp, &limits.users.list, list) {
- list_del(&uitem->list);
- kfree(uitem);
+struct limit_process_item_st* pitem;
+struct limit_user_item_st* uitem;
+struct hlist_node *pos, *tmp;
+size_t i;
+
+ mutex_lock(&user_limit_mutex);
+ for (i = 0; i < USER_LIMIT_TABLE_SIZE; i++) {
+ hlist_for_each_entry_safe(uitem, pos, tmp, &user_limit_table[i],
+ hlist) {
+ hlist_del(&uitem->hlist);
+ kfree(uitem);
+ }
}
- up(&limits.users.sem);
+ mutex_unlock(&user_limit_mutex);
- down(&limits.processes.sem);
- list_for_each_entry_safe(pitem, ptmp, &limits.processes.list, list) {
- list_del(&pitem->list);
- kfree(pitem);
+ mutex_lock(&process_limit_mutex);
+ for (i = 0; i < PROCESS_LIMIT_TABLE_SIZE; i++) {
+ hlist_for_each_entry_safe(pitem, pos, tmp,
+ &process_limit_table[i], hlist) {
+ hlist_del(&pitem->hlist);
+ kfree(pitem);
+ }
}
- up(&limits.processes.sem);
+ mutex_unlock(&process_limit_mutex);
}
@@ -98,79 +123,94 @@ int ncr_limits_add_and_check(uid_t uid, pid_t pid, limits_type_t type)
{
struct limit_process_item_st* pitem;
struct limit_user_item_st* uitem;
+struct hlist_head *user_head, *process_head;
+struct hlist_node *pos;
int add = 1;
int ret;
+ BUG_ON(type >= NUM_LIMIT_TYPES);
- down(&limits.users.sem);
- list_for_each_entry(uitem, &limits.users.list, list) {
- if (uitem->uid == uid && uitem->type == type) {
+ user_head = user_limit_hash(uid);
+ mutex_lock(&user_limit_mutex);
+ hlist_for_each_entry(uitem, pos, user_head, hlist) {
+ if (uitem->uid == uid) {
add = 0;
- if (atomic_add_unless(&uitem->cnt, 1, max_per_user[type])==0) {
+ if (atomic_add_unless(&uitem->cnt[type], 1, max_per_user[type])==0) {
err();
- up(&limits.users.sem);
+ mutex_unlock(&user_limit_mutex);
return -EPERM;
}
+ break;
}
}
if (add) {
+ size_t i;
+
uitem = kmalloc( sizeof(*uitem), GFP_KERNEL);
if (uitem == NULL) {
err();
- up(&limits.users.sem);
+ mutex_unlock(&user_limit_mutex);
return -ENOMEM;
}
uitem->uid = uid;
- uitem->type = type;
- atomic_set(&uitem->cnt, 1);
+ for (i = 0; i < NUM_LIMIT_TYPES; i++)
+ atomic_set(&uitem->cnt[i], 0);
+ atomic_set(&uitem->cnt[type], 1);
- list_add(&uitem->list, &limits.users.list);
+ hlist_add_head(&uitem->hlist, user_head);
}
- up(&limits.users.sem);
+ mutex_unlock(&user_limit_mutex);
add = 1;
/* check process limits */
- down(&limits.processes.sem);
- list_for_each_entry(pitem, &limits.processes.list, list) {
- if (pitem->pid == pid && pitem->type == type) {
+ process_head = process_limit_hash(uid);
+ mutex_lock(&process_limit_mutex);
+ hlist_for_each_entry(pitem, pos, process_head, hlist) {
+ if (pitem->pid == pid) {
add = 0;
- if (atomic_add_unless(&pitem->cnt, 1, max_per_process[type])==0) {
+ if (atomic_add_unless(&pitem->cnt[type], 1, max_per_process[type])==0) {
err();
- up(&limits.processes.sem);
+ mutex_unlock(&process_limit_mutex);
ret = -EPERM;
goto restore_user;
}
+ break;
}
}
if (add) {
+ size_t i;
+
pitem = kmalloc(sizeof(*pitem), GFP_KERNEL);
if (pitem == NULL) {
err();
- up(&limits.processes.sem);
+ mutex_unlock(&process_limit_mutex);
ret = -ENOMEM;
goto restore_user;
}
pitem->pid = pid;
- pitem->type = type;
- atomic_set(&pitem->cnt, 1);
+ for (i = 0; i < NUM_LIMIT_TYPES; i++)
+ atomic_set(&pitem->cnt[i], 0);
+ atomic_set(&pitem->cnt[type], 1);
- list_add(&pitem->list, &limits.processes.list);
+ hlist_add_head(&pitem->hlist, process_head);
}
- up(&limits.processes.sem);
+ mutex_unlock(&process_limit_mutex);
return 0;
restore_user:
- down(&limits.users.sem);
- list_for_each_entry(uitem, &limits.users.list, list) {
- if (uitem->uid == uid && uitem->type == type)
- atomic_dec(&uitem->cnt);
+ mutex_lock(&user_limit_mutex);
+ hlist_for_each_entry(uitem, pos, user_head, hlist) {
+ if (uitem->uid == uid) {
+ atomic_dec(&uitem->cnt[type]);
+ break;
+ }
}
- up(&limits.users.sem);
+ mutex_unlock(&user_limit_mutex);
return ret;
}
@@ -178,23 +218,30 @@ void ncr_limits_remove(uid_t uid, pid_t pid, limits_type_t type)
{
struct limit_process_item_st* pitem;
struct limit_user_item_st* uitem;
-
- down(&limits.users.sem);
- list_for_each_entry(uitem, &limits.users.list, list) {
- if (uitem->uid == uid && uitem->type == type) {
- atomic_dec(&uitem->cnt);
+struct hlist_head *hhead;
+struct hlist_node *pos;
+
+ BUG_ON(type >= NUM_LIMIT_TYPES);
+ hhead = user_limit_hash(uid);
+ mutex_lock(&user_limit_mutex);
+ hlist_for_each_entry(uitem, pos, hhead, hlist) {
+ if (uitem->uid == uid) {
+ atomic_dec(&uitem->cnt[type]);
+ break;
}
}
- up(&limits.users.sem);
+ mutex_unlock(&user_limit_mutex);
/* check process limits */
- down(&limits.processes.sem);
- list_for_each_entry(pitem, &limits.processes.list, list) {
- if (pitem->pid == pid && pitem->type == type) {
- atomic_dec(&pitem->cnt);
+ hhead = process_limit_hash(uid);
+ mutex_lock(&process_limit_mutex);
+ hlist_for_each_entry(pitem, pos, hhead, hlist) {
+ if (pitem->pid == pid) {
+ atomic_dec(&pitem->cnt[type]);
+ break;
}
}
- up(&limits.processes.sem);
+ mutex_unlock(&process_limit_mutex);
return;
}
diff --git a/crypto/userspace/ncr-pk.c b/crypto/userspace/ncr-pk.c
index e4529b30d7f..0a394a2b7a6 100644
--- a/crypto/userspace/ncr-pk.c
+++ b/crypto/userspace/ncr-pk.c
@@ -614,6 +614,10 @@ void * input, *output;
switch(ctx->algorithm->algo) {
case NCR_ALG_RSA:
+ if (ctx->sign_hash == NULL) {
+ err();
+ return -EINVAL;
+ }
cret = rsa_sign_hash_ex( input, isg_size, output, &osize,
ctx->type, ctx->sign_hash, ctx->salt_len, &ctx->key->key.pk.rsa);
if (cret != CRYPT_OK) {
@@ -674,6 +678,10 @@ uint8_t* sig;
switch(ctx->algorithm->algo) {
case NCR_ALG_RSA:
+ if (ctx->sign_hash == NULL) {
+ err();
+ return -EINVAL;
+ }
cret = rsa_verify_hash_ex( sig, sign_sg_size,
hash, hash_size, ctx->type, ctx->sign_hash,
ctx->salt_len, &stat, &ctx->key->key.pk.rsa);
diff --git a/crypto/userspace/ncr-sessions.c b/crypto/userspace/ncr-sessions.c
index 365935fe2bf..3109292cfc2 100644
--- a/crypto/userspace/ncr-sessions.c
+++ b/crypto/userspace/ncr-sessions.c
@@ -31,53 +31,39 @@
#include <linux/scatterlist.h>
static int _ncr_session_update_key(struct ncr_lists* lists, struct ncr_session_op_st* op);
-static void _ncr_session_remove(struct list_sem_st* lst, ncr_session_t desc);
+static void _ncr_session_remove(struct ncr_lists *lst, ncr_session_t desc);
-void ncr_sessions_list_deinit(struct list_sem_st* lst)
+static int session_list_deinit_fn(int id, void *item, void *unused)
{
- if(lst) {
- struct session_item_st * item, *tmp;
-
- down(&lst->sem);
-
- list_for_each_entry_safe(item, tmp, &lst->list, list) {
- list_del(&item->list);
- _ncr_sessions_item_put( item); /* decrement ref count */
- }
- up(&lst->sem);
-
- }
+ (void)unused;
+ _ncr_sessions_item_put(item);
+ return 0;
}
-/* must be called with data semaphore down
- */
-static ncr_session_t _ncr_sessions_get_new_desc( struct list_sem_st* lst)
+void ncr_sessions_list_deinit(struct ncr_lists *lst)
{
-struct session_item_st* item;
-int mx = 1;
-
- list_for_each_entry(item, &lst->list, list) {
- mx = max(mx, item->desc);
- }
- mx++;
-
- return mx;
+ /* The mutex is not necessary, but doesn't hurt and makes it easier to
+ verify locking correctness. */
+ mutex_lock(&lst->session_idr_mutex);
+ idr_for_each(&lst->session_idr, session_list_deinit_fn, NULL);
+ idr_remove_all(&lst->session_idr);
+ idr_destroy(&lst->session_idr);
+ mutex_unlock(&lst->session_idr_mutex);
}
/* returns the data item corresponding to desc */
-struct session_item_st* ncr_sessions_item_get( struct list_sem_st* lst, ncr_session_t desc)
+struct session_item_st* ncr_sessions_item_get(struct ncr_lists *lst, ncr_session_t desc)
{
struct session_item_st* item;
- down(&lst->sem);
- list_for_each_entry(item, &lst->list, list) {
- if (item->desc == desc) {
- atomic_inc(&item->refcnt);
- up(&lst->sem);
- return item;
- }
+ mutex_lock(&lst->session_idr_mutex);
+ item = idr_find(&lst->session_idr, desc);
+ if (item != NULL) {
+ atomic_inc(&item->refcnt);
+ mutex_unlock(&lst->session_idr_mutex);
+ return item;
}
- up(&lst->sem);
+ mutex_unlock(&lst->session_idr_mutex);
err();
return NULL;
@@ -97,7 +83,7 @@ void _ncr_sessions_item_put( struct session_item_st* item)
}
}
-struct session_item_st* ncr_session_new(struct list_sem_st* lst)
+struct session_item_st* ncr_session_new(struct ncr_lists *lst)
{
struct session_item_st* sess;
@@ -114,23 +100,31 @@ struct session_item_st* ncr_session_new(struct list_sem_st* lst)
sizeof(struct scatterlist), GFP_KERNEL);
if (sess->sg == NULL || sess->pages == NULL) {
err();
- kfree(sess->sg);
- kfree(sess->pages);
- kfree(sess);
- return NULL;
+ goto err_sess;
}
init_MUTEX(&sess->mem_mutex);
atomic_set(&sess->refcnt, 2); /* One for lst->list, one for "sess" */
- down(&lst->sem);
-
- sess->desc = _ncr_sessions_get_new_desc(lst);
- list_add(&sess->list, &lst->list);
-
- up(&lst->sem);
+ mutex_lock(&lst->session_idr_mutex);
+ /* idr_pre_get() should preallocate enough, and, due to
+ session_idr_mutex, nobody else can use the preallocated data.
+ Therefore the loop recommended in idr_get_new() documentation is not
+ necessary. */
+ if (idr_pre_get(&lst->session_idr, GFP_KERNEL) == 0 ||
+ idr_get_new(&lst->session_idr, sess, &sess->desc) != 0) {
+ mutex_unlock(&lst->session_idr_mutex);
+ goto err_sess;
+ }
+ mutex_unlock(&lst->session_idr_mutex);
return sess;
+
+err_sess:
+ kfree(sess->sg);
+ kfree(sess->pages);
+ kfree(sess);
+ return NULL;
}
static const struct algo_properties_st algo_properties[] = {
@@ -226,7 +220,7 @@ static int _ncr_session_init(struct ncr_lists* lists, struct ncr_session_st* ses
int ret;
const struct algo_properties_st *sign_hash;
- ns = ncr_session_new(&lists->sessions);
+ ns = ncr_session_new(lists);
if (ns == NULL) {
err();
return -ENOMEM;
@@ -250,7 +244,7 @@ static int _ncr_session_init(struct ncr_lists* lists, struct ncr_session_st* ses
}
/* read key */
- ret = ncr_key_item_get_read( &ns->key, &lists->key, session->key);
+ ret = ncr_key_item_get_read( &ns->key, lists, session->key);
if (ret < 0) {
err();
goto fail;
@@ -319,7 +313,7 @@ static int _ncr_session_init(struct ncr_lists* lists, struct ncr_session_st* ses
} else {
/* read key */
- ret = ncr_key_item_get_read( &ns->key, &lists->key, session->key);
+ ret = ncr_key_item_get_read( &ns->key, lists, session->key);
if (ret < 0) {
err();
goto fail;
@@ -390,7 +384,7 @@ static int _ncr_session_init(struct ncr_lists* lists, struct ncr_session_st* ses
fail:
if (ret < 0) {
- _ncr_session_remove(&lists->sessions, ns->desc);
+ _ncr_session_remove(lists, ns->desc);
}
_ncr_sessions_item_put(ns);
@@ -416,7 +410,7 @@ int ncr_session_init(struct ncr_lists* lists, void __user* arg)
ret = copy_to_user( arg, &session, sizeof(session));
if (unlikely(ret)) {
err();
- _ncr_session_remove(&lists->sessions, session.ses);
+ _ncr_session_remove(lists, session.ses);
return -EFAULT;
}
return ret;
@@ -479,23 +473,18 @@ int ret;
return 0;
}
-static void _ncr_session_remove(struct list_sem_st* lst, ncr_session_t desc)
+static void _ncr_session_remove(struct ncr_lists *lst, ncr_session_t desc)
{
- struct session_item_st * item, *tmp;
+ struct session_item_st * item;
- down(&lst->sem);
-
- list_for_each_entry_safe(item, tmp, &lst->list, list) {
- if(item->desc == desc) {
- list_del(&item->list);
- _ncr_sessions_item_put( item); /* decrement ref count */
- break;
- }
- }
-
- up(&lst->sem);
+ mutex_lock(&lst->session_idr_mutex);
+ item = idr_find(&lst->session_idr, desc);
+ if (item != NULL)
+ idr_remove(&lst->session_idr, desc); /* Steal the reference */
+ mutex_unlock(&lst->session_idr_mutex);
- return;
+ if (item != NULL)
+ _ncr_sessions_item_put(item);
}
static int _ncr_session_grow_pages(struct session_item_st *ses, int pagecount)
@@ -630,7 +619,7 @@ static int _ncr_session_update(struct ncr_lists* lists, struct ncr_session_op_st
unsigned osg_cnt=0, isg_cnt=0;
size_t isg_size, osg_size;
- sess = ncr_sessions_item_get( &lists->sessions, op->ses);
+ sess = ncr_sessions_item_get(lists, op->ses);
if (sess == NULL) {
err();
return -EINVAL;
@@ -750,7 +739,7 @@ static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st*
void __user * udata = NULL;
size_t *udata_size;
- sess = ncr_sessions_item_get( &lists->sessions, op->ses);
+ sess = ncr_sessions_item_get(lists, op->ses);
if (sess == NULL) {
err();
return -EINVAL;
@@ -900,7 +889,7 @@ fail:
}
_ncr_sessions_item_put(sess);
- _ncr_session_remove(&lists->sessions, op->ses);
+ _ncr_session_remove(lists, op->ses);
return ret;
}
@@ -913,14 +902,14 @@ static int _ncr_session_update_key(struct ncr_lists* lists, struct ncr_session_o
struct session_item_st* sess;
struct key_item_st* key = NULL;
- sess = ncr_sessions_item_get( &lists->sessions, op->ses);
+ sess = ncr_sessions_item_get(lists, op->ses);
if (sess == NULL) {
err();
return -EINVAL;
}
/* read key */
- ret = ncr_key_item_get_read( &key, &lists->key, op->data.kdata.input);
+ ret = ncr_key_item_get_read( &key, lists, op->data.kdata.input);
if (ret < 0) {
err();
goto fail;
diff --git a/crypto/userspace/ncr.c b/crypto/userspace/ncr.c
index 7608312ed7b..d4eb83fb2b0 100644
--- a/crypto/userspace/ncr.c
+++ b/crypto/userspace/ncr.c
@@ -52,11 +52,11 @@ void* ncr_init_lists(void)
memset(lst, 0, sizeof(*lst));
- init_MUTEX(&lst->key.sem);
- INIT_LIST_HEAD(&lst->key.list);
+ mutex_init(&lst->key_idr_mutex);
+ idr_init(&lst->key_idr);
- init_MUTEX(&lst->sessions.sem);
- INIT_LIST_HEAD(&lst->sessions.list);
+ mutex_init(&lst->session_idr_mutex);
+ idr_init(&lst->session_idr);
return lst;
}
@@ -64,8 +64,8 @@ void* ncr_init_lists(void)
void ncr_deinit_lists(struct ncr_lists *lst)
{
if(lst) {
- ncr_key_list_deinit(&lst->key);
- ncr_sessions_list_deinit(&lst->sessions);
+ ncr_key_list_deinit(lst);
+ ncr_sessions_list_deinit(lst);
kfree(lst);
}
}
@@ -127,25 +127,25 @@ ncr_ioctl(struct ncr_lists* lst, struct file *filp,
switch (cmd) {
case NCRIO_KEY_INIT:
- return ncr_key_init(&lst->key, arg);
+ return ncr_key_init(lst, arg);
case NCRIO_KEY_DEINIT:
- return ncr_key_deinit(&lst->key, arg);
+ return ncr_key_deinit(lst, arg);
case NCRIO_KEY_GENERATE:
- return ncr_key_generate(&lst->key, arg);
+ return ncr_key_generate(lst, arg);
case NCRIO_KEY_EXPORT:
- return ncr_key_export(&lst->key, arg);
+ return ncr_key_export(lst, arg);
case NCRIO_KEY_IMPORT:
- return ncr_key_import(&lst->key, arg);
+ return ncr_key_import(lst, arg);
case NCRIO_KEY_GET_INFO:
- return ncr_key_info(&lst->key, arg);
+ return ncr_key_info(lst, arg);
case NCRIO_KEY_WRAP:
- return ncr_key_wrap(&lst->key, arg);
+ return ncr_key_wrap(lst, arg);
case NCRIO_KEY_UNWRAP:
- return ncr_key_unwrap(&lst->key, arg);
+ return ncr_key_unwrap(lst, arg);
case NCRIO_KEY_STORAGE_WRAP:
- return ncr_key_storage_wrap(&lst->key, arg);
+ return ncr_key_storage_wrap(lst, arg);
case NCRIO_KEY_STORAGE_UNWRAP:
- return ncr_key_storage_unwrap(&lst->key, arg);
+ return ncr_key_storage_unwrap(lst, arg);
case NCRIO_SESSION_INIT:
return ncr_session_init(lst, arg);
case NCRIO_SESSION_UPDATE:
@@ -158,9 +158,9 @@ ncr_ioctl(struct ncr_lists* lst, struct file *filp,
case NCRIO_MASTER_KEY_SET:
return ncr_master_key_set(arg);
case NCRIO_KEY_GENERATE_PAIR:
- return ncr_key_generate_pair(&lst->key, arg);
+ return ncr_key_generate_pair(lst, arg);
case NCRIO_KEY_DERIVE:
- return ncr_key_derive(&lst->key, arg);
+ return ncr_key_derive(lst, arg);
default:
return -EINVAL;
}