summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile3
-rw-r--r--cryptodev_main.c10
-rw-r--r--examples/Makefile6
-rw-r--r--examples/cipher.c2
-rw-r--r--examples/hmac.c2
-rw-r--r--examples/new.c126
-rw-r--r--ncr.c167
-rw-r--r--ncr.h4
-rw-r--r--ncr_int.h6
10 files changed, 304 insertions, 23 deletions
diff --git a/.gitignore b/.gitignore
index 740ebd5..51f27fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,5 +9,6 @@ Module.symvers
modules.order
examples/cipher
examples/hmac
+examples/new
releases
scripts
diff --git a/Makefile b/Makefile
index 9b8d965..a038e32 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-KERNEL_DIR = /lib/modules/$(shell uname -r)/build
+KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build
VERSION = 0.1
cryptodev-objs = cryptodev_main.o cryptodev_cipher.o ncr.o
@@ -12,6 +12,7 @@ install:
make -C $(KERNEL_DIR) SUBDIRS=`pwd` modules_install
@echo "Installing cryptodev.h in /usr/include/crypto ..."
@install -D cryptodev.h /usr/include/crypto/cryptodev.h
+ @install -D ncr.h /usr/include/crypto/ncr.h
clean:
make -C $(KERNEL_DIR) SUBDIRS=`pwd` clean
diff --git a/cryptodev_main.c b/cryptodev_main.c
index 09aa5bf..fabda2e 100644
--- a/cryptodev_main.c
+++ b/cryptodev_main.c
@@ -40,6 +40,7 @@
#include <linux/scatterlist.h>
#include "cryptodev_int.h"
#include "ncr_int.h"
+#include <linux/version.h>
MODULE_AUTHOR("Nikos Mavrogiannopoulos <nmav@gnutls.org>");
MODULE_DESCRIPTION("CryptoDev driver");
@@ -561,6 +562,13 @@ cryptodev_ioctl(struct inode *inode, struct file *filp,
struct fcrypt * fcr;
uint32_t ses;
int ret, fd;
+ unsigned int uid;
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27)
+ uid = filp->f_uid;
+#else
+ uid = filp->f_cred->fsuid;
+#endif
if (unlikely(!pcr))
BUG();
@@ -596,7 +604,7 @@ cryptodev_ioctl(struct inode *inode, struct file *filp,
return copy_to_user((void*)arg, &cop, sizeof(cop));
default:
- return ncr_ioctl(filp->f_cred->fsuid, pcr->ncr, cmd, arg);
+ return ncr_ioctl(uid, pcr->ncr, cmd, arg);
}
}
diff --git a/examples/Makefile b/examples/Makefile
index 601fb07..3190c4a 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -1,12 +1,14 @@
KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build
-hostprogs := cipher hmac
+hostprogs := cipher hmac new
example-cipher-objs := cipher.o
example-hmac-objs := hmac.o
+new-objs := new.o
check: $(hostprogs)
+ ./new
./cipher
./hmac
clean:
- rm -f *.o *~ hmac cipher
+ rm -f *.o *~ hmac cipher new
diff --git a/examples/cipher.c b/examples/cipher.c
index d7982ae..c7ce2c2 100644
--- a/examples/cipher.c
+++ b/examples/cipher.c
@@ -10,7 +10,7 @@
#include <fcntl.h>
#include <sys/ioctl.h>
-#include <crypto/cryptodev.h>
+#include "../cryptodev.h"
#define DATA_SIZE 4096
#define BLOCK_SIZE 16
diff --git a/examples/hmac.c b/examples/hmac.c
index 9975792..9757f90 100644
--- a/examples/hmac.c
+++ b/examples/hmac.c
@@ -10,7 +10,7 @@
#include <fcntl.h>
#include <sys/ioctl.h>
-#include <crypto/cryptodev.h>
+#include "../cryptodev.h"
#define DATA_SIZE 4096
#define BLOCK_SIZE 16
diff --git a/examples/new.c b/examples/new.c
new file mode 100644
index 0000000..60f9437
--- /dev/null
+++ b/examples/new.c
@@ -0,0 +1,126 @@
+/*
+ * Demo on how to use /dev/crypto device for HMAC.
+ *
+ * Placed under public domain.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/ioctl.h>
+#include "../ncr.h"
+#include <stdlib.h>
+
+#define DATA_SIZE 4096
+
+static void randomize_data(uint8_t * data, size_t data_size)
+{
+int i;
+
+ srand(time(0)*getpid());
+ for (i=0;i<data_size;i++) {
+ data[i] = rand() & 0xff;
+ }
+}
+
+static int
+test_ncr_data(int cfd)
+{
+ struct ncr_data_init_st init;
+ struct ncr_data_st kdata;
+ uint8_t data[DATA_SIZE];
+ uint8_t data_bak[DATA_SIZE];
+ int i;
+
+ randomize_data(data, sizeof(data));
+ memcpy(data_bak, data, sizeof(data));
+
+ init.max_object_size = DATA_SIZE;
+ init.flags = NCR_DATA_FLAG_EXPORTABLE;
+ init.initial_data = data;
+ init.initial_data_size = sizeof(data);
+
+ if (ioctl(cfd, NCRIO_DATA_INIT, &init)) {
+ perror("ioctl(NCRIO_DATA_INIT)");
+ return 1;
+ }
+
+ memset(data, 0, sizeof(data));
+
+ kdata.desc = init.desc;
+ kdata.data = data;
+ kdata.data_size = sizeof(data);
+ kdata.append_flag = 0;
+
+ if (ioctl(cfd, NCRIO_DATA_GET, &kdata)) {
+ perror("ioctl(NCRIO_DATA_GET)");
+ return 1;
+ }
+
+ if (memcmp(data, data_bak, sizeof(data))!=0) {
+ fprintf(stderr, "data returned but differ!\n");
+ return 1;
+ }
+
+ /* test set */
+ memset(data, 0xf1, sizeof(data));
+
+ kdata.desc = init.desc;
+ kdata.data = data;
+ kdata.data_size = sizeof(data);
+ kdata.append_flag = 0;
+
+ if (ioctl(cfd, NCRIO_DATA_SET, &kdata)) {
+ perror("ioctl(NCRIO_DATA_SET)");
+ return 1;
+ }
+
+ /* test get after set */
+ memset(data, 0, sizeof(data));
+
+ kdata.desc = init.desc;
+ kdata.data = data;
+ kdata.data_size = sizeof(data);
+ kdata.append_flag = 0;
+
+ if (ioctl(cfd, NCRIO_DATA_GET, &kdata)) {
+ perror("ioctl(NCRIO_DATA_GET)");
+ return 1;
+ }
+
+ for(i=0;i<kdata.data_size;i++) {
+ if (((uint8_t*)kdata.data)[i] != 0xf1) {
+ fprintf(stderr, "data returned but differ!\n");
+ return 1;
+ }
+ }
+
+ return 0; /* ok */
+}
+
+int
+main()
+{
+ int fd = -1, cfd = -1;
+
+ /* Open the crypto device */
+ fd = open("/dev/crypto", O_RDWR, 0);
+ if (fd < 0) {
+ perror("open(/dev/crypto)");
+ return 1;
+ }
+
+ /* Run the test itself */
+ if (test_ncr_data(cfd))
+ return 1;
+
+ /* Close the original descriptor */
+ if (close(fd)) {
+ perror("close(fd)");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/ncr.c b/ncr.c
index 2d8436e..a190d5a 100644
--- a/ncr.c
+++ b/ncr.c
@@ -64,7 +64,7 @@ static ncr_data_t _ncr_data_get_new_desc( struct ncr_lists* lst)
struct data_item* item;
int mx = 0;
- list_for_each(item, &lst->data_list) {
+ list_for_each_entry(item, &lst->data_list, list) {
mx = max(mx, item->desc);
}
mx++;
@@ -72,54 +72,190 @@ int mx = 0;
return mx;
}
-void* data_alloc(unsigned int uid, size_t size)
+/* returns the data item corresponding to desc */
+static struct data_item* _ncr_data_item_get( struct ncr_lists* lst, ncr_data_t desc)
{
- /* FIXME: implement a maximum memory limit per user */
+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);
+
+ return NULL;
+}
+
+static void* data_alloc(unsigned int uid, size_t size)
+{
+ /* FIXME: enforce a maximum memory limit per user */
if (size > 64*1024) {
return NULL;
}
- return kmalloc(GPF_KERNEL, size);
+ return kmalloc(GFP_KERNEL, size);
+}
+
+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 ncr_lists* lst, 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)
+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(GPF_KERNEL, sizeof(*data));
+ data = kmalloc(GFP_KERNEL, sizeof(*data));
if (data == NULL) {
return -ENOMEM;
}
memset(data, 0, sizeof(*data));
- init_MUTEX(&data->sem);
data->flags = init.flags;
+ atomic_set(&data->refcnt, 1);
- data->data = data_alloc(uid, init.max_data_size);
+ data->data = data_alloc(uid, init.max_object_size);
if (data->data == NULL) {
kfree(data);
return -ENOMEM;
}
- data->max_data_size = init.max_data_size;
+ data->max_data_size = init.max_object_size;
- down(lst->data_sem);
+ down(&lst->data_sem);
data->desc = _ncr_data_get_new_desc(lst);
+ data->uid = uid;
- list_add(data, &list->data_list);
+ 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);
+ 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( lst, 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) {
+ return -EINVAL;
+ }
+
+ if (!(data->flags & NCR_DATA_FLAG_EXPORTABLE)) {
+ 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( lst, 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) {
+ return -EINVAL;
+ }
+
+ if ((get.data_size > data->max_data_size) ||
+ (get.data == NULL && get.data_size != 0)) {
+ 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) {
+ 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( lst, data);
+
+ return ret;
}
int
ncr_ioctl(unsigned int uid, struct ncr_lists* lst,
- unsigned int cmd, unsigned long arg)
+ unsigned int cmd, unsigned long __user arg)
{
if (unlikely(!lst))
@@ -127,10 +263,13 @@ ncr_ioctl(unsigned int uid, struct ncr_lists* lst,
switch (cmd) {
case NCRIO_DATA_INIT:
- return ncr_data_new(uid, lst, arg);
+ return ncr_data_new(uid, lst, (void*)arg);
case NCRIO_DATA_GET:
+ return ncr_data_get(lst, (void*)arg);
case NCRIO_DATA_SET:
+ return ncr_data_set(lst, (void*)arg);
case NCRIO_DATA_DEINIT:
+ return ncr_data_deinit(lst, (void*)arg);
default:
return -EINVAL;
}
diff --git a/ncr.h b/ncr.h
index c3094b9..aa5e73d 100644
--- a/ncr.h
+++ b/ncr.h
@@ -45,12 +45,14 @@ struct ncr_data_init_st {
ncr_data_t desc;
size_t max_object_size;
unsigned int flags;
+ void* initial_data; /* can be null */
+ size_t initial_data_size;
};
struct ncr_data_st {
ncr_data_t desc;
void* data;
- size_t data_size;
+ size_t data_size; /* rw in get */
unsigned int append_flag; /* only when used with NCRIO_DATA_SET */
};
diff --git a/ncr_int.h b/ncr_int.h
index 1e0b7af..e6f4295 100644
--- a/ncr_int.h
+++ b/ncr_int.h
@@ -2,14 +2,16 @@
# define NCR_INT_H
#include "ncr.h"
+#include <asm/atomic.h>
struct data_item {
struct list_head list;
- void* data;
+ uint8_t* data;
size_t data_size;
size_t max_data_size;
- struct semaphore sem;
unsigned int flags;
+ atomic_t refcnt;
+ unsigned int uid;
ncr_data_t desc;
};