summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--ncr-data.c256
-rw-r--r--ncr.c220
-rw-r--r--ncr_int.h10
4 files changed, 270 insertions, 219 deletions
diff --git a/Makefile b/Makefile
index a038e32e0aa..909baaf38ce 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,8 @@
KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build
VERSION = 0.1
-cryptodev-objs = cryptodev_main.o cryptodev_cipher.o ncr.o
+cryptodev-objs = cryptodev_main.o cryptodev_cipher.o ncr.o \
+ ncr-data.o
obj-m += cryptodev.o
diff --git a/ncr-data.c b/ncr-data.c
new file mode 100644
index 00000000000..ea10f8b10ee
--- /dev/null
+++ b/ncr-data.c
@@ -0,0 +1,256 @@
+/*
+ * New driver for /dev/crypto device (aka CryptoDev)
+
+ * Copyright (c) 2010 Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * cryptodev is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cryptodev is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/crypto.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/random.h>
+#include "cryptodev.h"
+#include <asm/uaccess.h>
+#include <asm/ioctl.h>
+#include <linux/scatterlist.h>
+#include "ncr.h"
+#include "ncr_int.h"
+
+#define err() printk(KERN_DEBUG"ncr: %s: %d\n", __func__, __LINE__)
+
+static void _ncr_data_item_put( struct data_item* item);
+
+void ncr_data_list_deinit(struct ncr_lists *lst)
+{
+ if(lst) {
+ struct data_item * item, *tmp;
+
+ down(&lst->data_sem);
+
+ list_for_each_entry_safe(item, tmp, &lst->data_list, list) {
+ list_del(&item->list);
+ _ncr_data_item_put( item); /* decrement ref count */
+ }
+ up(&lst->data_sem);
+
+ }
+}
+
+/* must be called with data semaphore down
+ */
+static ncr_data_t _ncr_data_get_new_desc( struct ncr_lists* lst)
+{
+struct data_item* item;
+int mx = 0;
+
+ list_for_each_entry(item, &lst->data_list, list) {
+ mx = max(mx, item->desc);
+ }
+ mx++;
+
+ return mx;
+}
+
+/* returns the data item corresponding to desc */
+static struct data_item* ncr_data_item_get( struct ncr_lists* lst, ncr_data_t desc)
+{
+struct data_item* item;
+
+ down(&lst->data_sem);
+ list_for_each_entry(item, &lst->data_list, list) {
+ if (item->desc == desc) {
+ atomic_inc(&item->refcnt);
+ up(&lst->data_sem);
+ return item;
+ }
+ }
+ up(&lst->data_sem);
+
+ err();
+ return NULL;
+}
+
+static void* data_alloc(unsigned int uid, size_t size)
+{
+ /* FIXME: enforce a maximum memory limit per user */
+ if (size > 64*1024) {
+ err();
+ return NULL;
+ }
+ return kmalloc(size, GFP_KERNEL);
+}
+
+static void data_free(struct data_item * data)
+{
+ /* FIXME: enforce a maximum memory limit per user */
+ kfree(data->data);
+}
+
+static void _ncr_data_item_put( struct data_item* item)
+{
+ if (atomic_dec_and_test(&item->refcnt)) {
+ data_free(item);
+ kfree(item);
+ }
+}
+
+int ncr_data_new(unsigned int uid, struct ncr_lists* lst, void __user* arg)
+{
+ struct ncr_data_init_st init;
+ struct data_item* data;
+
+ copy_from_user( &init, arg, sizeof(init));
+
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if (data == NULL) {
+ err();
+ return -ENOMEM;
+ }
+
+ memset(data, 0, sizeof(*data));
+
+ data->flags = init.flags;
+ atomic_set(&data->refcnt, 1);
+
+ data->data = data_alloc(uid, init.max_object_size);
+ if (data->data == NULL) {
+ kfree(data);
+ err();
+ return -ENOMEM;
+ }
+ data->max_data_size = init.max_object_size;
+
+ down(&lst->data_sem);
+
+ data->desc = _ncr_data_get_new_desc(lst);
+ data->uid = uid;
+
+ if (init.initial_data != NULL) {
+ copy_from_user(data->data, init.initial_data, init.initial_data_size);
+ data->data_size = init.initial_data_size;
+ }
+
+ list_add(&data->list, &lst->data_list);
+
+ up(&lst->data_sem);
+
+ init.desc = data->desc;
+ copy_to_user(arg, &init, sizeof(init));
+
+ return 0;
+}
+
+
+int ncr_data_deinit(struct ncr_lists* lst, void __user* arg)
+{
+ ncr_data_t desc;
+ struct data_item * item, *tmp;
+
+ copy_from_user( &desc, arg, sizeof(desc));
+
+ down(&lst->data_sem);
+
+ list_for_each_entry_safe(item, tmp, &lst->data_list, list) {
+ if(item->desc == desc) {
+ list_del(&item->list);
+ _ncr_data_item_put( item); /* decrement ref count */
+ break;
+ }
+ }
+
+ up(&lst->data_sem);
+
+ return 0;
+}
+
+int ncr_data_get(struct ncr_lists* lst, void __user* arg)
+{
+ struct ncr_data_st get;
+ struct data_item * data;
+ size_t len;
+
+ copy_from_user( &get, arg, sizeof(get));
+
+ data = ncr_data_item_get( lst, get.desc);
+
+ if (data == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ if (!(data->flags & NCR_DATA_FLAG_EXPORTABLE)) {
+ err();
+ return -EPERM;
+ }
+
+ len = min(get.data_size, data->data_size);
+
+ /* update length */
+ get.data_size = len;
+ copy_to_user(arg, &get, sizeof(get));
+
+ if (len > 0)
+ copy_to_user(get.data, data->data, len);
+
+ _ncr_data_item_put( data);
+
+ return 0;
+}
+
+int ncr_data_set(struct ncr_lists* lst, void __user* arg)
+{
+ struct ncr_data_st get;
+ struct data_item * data;
+ int ret;
+
+ copy_from_user( &get, arg, sizeof(get));
+
+ data = ncr_data_item_get( lst, get.desc);
+
+ if (data == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ if ((get.data_size > data->max_data_size) ||
+ (get.data == NULL && get.data_size != 0)) {
+ err();
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (!get.append_flag) {
+ if (get.data != NULL)
+ copy_from_user(data->data, get.data, get.data_size);
+ data->data_size = get.data_size;
+ } else {
+ if (get.data_size+data->data_size > data->max_data_size) {
+ err();
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ if (get.data != NULL)
+ copy_from_user(&data->data[data->data_size], get.data, get.data_size);
+ data->data_size += get.data_size;
+ }
+ ret = 0;
+
+cleanup:
+ _ncr_data_item_put( data);
+
+ return ret;
+}
diff --git a/ncr.c b/ncr.c
index 26cf7f34eb8..b91e7dc41ec 100644
--- a/ncr.c
+++ b/ncr.c
@@ -1,7 +1,7 @@
/*
* New driver for /dev/crypto device (aka CryptoDev)
- * Copyright (c) 2009,2010 Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ * Copyright (c) 2010 Nikos Mavrogiannopoulos <nmav@gnutls.org>
*
* This file is part of linux cryptodev.
*
@@ -32,8 +32,6 @@
#define err() printk(KERN_DEBUG"ncr: %s: %d\n", __func__, __LINE__)
-static void _ncr_data_item_put( struct data_item* item);
-
void* ncr_init_lists(void)
{
struct ncr_lists *lst;
@@ -55,224 +53,10 @@ void* ncr_init_lists(void)
void ncr_deinit_lists(struct ncr_lists *lst)
{
if(lst) {
- struct data_item * item, *tmp;
-
- down(&lst->data_sem);
-
- list_for_each_entry_safe(item, tmp, &lst->data_list, list) {
- list_del(&item->list);
- _ncr_data_item_put( item); /* decrement ref count */
- }
- up(&lst->data_sem);
+ ncr_data_list_deinit(lst);
kfree(lst);
}
-
-}
-
-/* must be called with data semaphore down
- */
-static ncr_data_t _ncr_data_get_new_desc( struct ncr_lists* lst)
-{
-struct data_item* item;
-int mx = 0;
-
- list_for_each_entry(item, &lst->data_list, list) {
- mx = max(mx, item->desc);
- }
- mx++;
-
- return mx;
-}
-
-/* returns the data item corresponding to desc */
-static struct data_item* ncr_data_item_get( struct ncr_lists* lst, ncr_data_t desc)
-{
-struct data_item* item;
-
- down(&lst->data_sem);
- list_for_each_entry(item, &lst->data_list, list) {
- if (item->desc == desc) {
- atomic_inc(&item->refcnt);
- up(&lst->data_sem);
- return item;
- }
- }
- up(&lst->data_sem);
-
- err();
- return NULL;
-}
-
-static void* data_alloc(unsigned int uid, size_t size)
-{
- /* FIXME: enforce a maximum memory limit per user */
- if (size > 64*1024) {
- err();
- return NULL;
- }
- return kmalloc(size, GFP_KERNEL);
-}
-
-static void data_free(struct data_item * data)
-{
- /* FIXME: enforce a maximum memory limit per user */
- kfree(data->data);
-}
-
-static void _ncr_data_item_put( struct data_item* item)
-{
- if (atomic_dec_and_test(&item->refcnt)) {
- data_free(item);
- kfree(item);
- }
-}
-
-static int ncr_data_new(unsigned int uid, struct ncr_lists* lst, void __user* arg)
-{
- struct ncr_data_init_st init;
- struct data_item* data;
-
- copy_from_user( &init, arg, sizeof(init));
-
- data = kmalloc(sizeof(*data), GFP_KERNEL);
- if (data == NULL) {
- err();
- return -ENOMEM;
- }
-
- memset(data, 0, sizeof(*data));
-
- data->flags = init.flags;
- atomic_set(&data->refcnt, 1);
-
- data->data = data_alloc(uid, init.max_object_size);
- if (data->data == NULL) {
- kfree(data);
- err();
- return -ENOMEM;
- }
- data->max_data_size = init.max_object_size;
-
- down(&lst->data_sem);
-
- data->desc = _ncr_data_get_new_desc(lst);
- data->uid = uid;
-
- if (init.initial_data != NULL) {
- copy_from_user(data->data, init.initial_data, init.initial_data_size);
- data->data_size = init.initial_data_size;
- }
-
- list_add(&data->list, &lst->data_list);
-
- up(&lst->data_sem);
-
- init.desc = data->desc;
- copy_to_user(arg, &init, sizeof(init));
-
- return 0;
-}
-
-
-static int ncr_data_deinit(struct ncr_lists* lst, void __user* arg)
-{
- ncr_data_t desc;
- struct data_item * item, *tmp;
-
- copy_from_user( &desc, arg, sizeof(desc));
-
- down(&lst->data_sem);
-
- list_for_each_entry_safe(item, tmp, &lst->data_list, list) {
- if(item->desc == desc) {
- list_del(&item->list);
- _ncr_data_item_put( item); /* decrement ref count */
- break;
- }
- }
-
- up(&lst->data_sem);
-
- return 0;
-}
-
-static int ncr_data_get(struct ncr_lists* lst, void __user* arg)
-{
- struct ncr_data_st get;
- struct data_item * data;
- size_t len;
-
- copy_from_user( &get, arg, sizeof(get));
-
- data = ncr_data_item_get( lst, get.desc);
-
- if (data == NULL) {
- err();
- return -EINVAL;
- }
-
- if (!(data->flags & NCR_DATA_FLAG_EXPORTABLE)) {
- err();
- return -EPERM;
- }
-
- len = min(get.data_size, data->data_size);
-
- /* update length */
- get.data_size = len;
- copy_to_user(arg, &get, sizeof(get));
-
- if (len > 0)
- copy_to_user(get.data, data->data, len);
-
- _ncr_data_item_put( data);
-
- return 0;
-}
-
-static int ncr_data_set(struct ncr_lists* lst, void __user* arg)
-{
- struct ncr_data_st get;
- struct data_item * data;
- int ret;
-
- copy_from_user( &get, arg, sizeof(get));
-
- data = ncr_data_item_get( lst, get.desc);
-
- if (data == NULL) {
- err();
- return -EINVAL;
- }
-
- if ((get.data_size > data->max_data_size) ||
- (get.data == NULL && get.data_size != 0)) {
- err();
- ret = -EINVAL;
- goto cleanup;
- }
-
- if (!get.append_flag) {
- if (get.data != NULL)
- copy_from_user(data->data, get.data, get.data_size);
- data->data_size = get.data_size;
- } else {
- if (get.data_size+data->data_size > data->max_data_size) {
- err();
- ret = -EINVAL;
- goto cleanup;
- }
- if (get.data != NULL)
- copy_from_user(&data->data[data->data_size], get.data, get.data_size);
- data->data_size += get.data_size;
- }
- ret = 0;
-
-cleanup:
- _ncr_data_item_put( data);
-
- return ret;
}
int
diff --git a/ncr_int.h b/ncr_int.h
index e6f42955e42..7d78ac8a1e9 100644
--- a/ncr_int.h
+++ b/ncr_int.h
@@ -6,6 +6,10 @@
struct data_item {
struct list_head list;
+ /* This object is not protected from concurrent access.
+ * I see no reason to allow concurrent writes (reads are
+ * not an issue).
+ */
uint8_t* data;
size_t data_size;
size_t max_data_size;
@@ -34,4 +38,10 @@ int
ncr_ioctl(unsigned int uid, struct ncr_lists* lst,
unsigned int cmd, unsigned long arg);
+int ncr_data_set(struct ncr_lists* lst, void __user* arg);
+int ncr_data_get(struct ncr_lists* lst, void __user* arg);
+int ncr_data_deinit(struct ncr_lists* lst, void __user* arg);
+int ncr_data_new(unsigned int uid, struct ncr_lists* lst, void __user* arg);
+void ncr_data_list_deinit(struct ncr_lists *lst);
+
#endif