[PATCH 18/19] Add ioctl handlers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add ioctl and compat_ioctl handling.  This is the only file that
directly accesses structured data from userspace (other files may access
unformated data such as cipher input or multiple-precision integers).

Also add the last operation, ncr_master_key_set.
---
 crypto/userspace/ncr.c |  405 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 405 insertions(+), 0 deletions(-)

diff --git a/crypto/userspace/ncr.c b/crypto/userspace/ncr.c
index 9fb56ad..ee812ab 100644
--- a/crypto/userspace/ncr.c
+++ b/crypto/userspace/ncr.c
@@ -44,6 +44,411 @@
  */
 struct key_item_st master_key;
 
+static struct mutex lists_ida_mutex;
+static DEFINE_IDA(lists_ida);
+
+struct ncr_lists *ncr_init_lists(void)
+{
+	struct ncr_lists *lst;
+
+	lst = kmalloc(sizeof(*lst), GFP_KERNEL);
+	if(!lst) {
+		err();
+		return NULL;
+	}
+
+	memset(lst, 0, sizeof(*lst));
+
+	mutex_init(&lists_ida_mutex);
+	mutex_lock(&lists_ida_mutex);
+	/* ida_pre_get() should preallocate enough, and, due to lists_ida_mutex,
+	   nobody else can use the preallocated data.  Therefore the loop
+	   recommended in idr_get_new() documentation is not necessary. */
+	if (ida_pre_get(&lists_ida, GFP_KERNEL) == 0 ||
+	    ida_get_new(&lists_ida, &lst->id) != 0) {
+		mutex_unlock(&lists_ida_mutex);
+		kfree(lst);
+		return NULL;
+	}
+	mutex_unlock(&lists_ida_mutex);
+
+	mutex_init(&lst->key_idr_mutex);
+	idr_init(&lst->key_idr);
+
+	mutex_init(&lst->session_idr_mutex);
+	idr_init(&lst->session_idr);
+
+	return lst;
+}
+
+void ncr_deinit_lists(struct ncr_lists *lst)
+{
+	if(lst) {
+		ncr_key_list_deinit(lst);
+		ncr_sessions_list_deinit(lst);
+
+		mutex_lock(&lists_ida_mutex);
+		ida_remove(&lists_ida, lst->id);
+		mutex_unlock(&lists_ida_mutex);
+
+		kfree(lst);
+	}
+}
+
+void ncr_master_key_reset(void)
+{
+	memset(&master_key, 0, sizeof(master_key));
+}
+
+static int ncr_master_key_set(const struct ncr_master_key_set *st,
+			      struct nlattr *tb[])
+{
+struct audit_buffer *ab;
+int ret;
+
+	/* This will also cause auditing of the syscall, including information
+	   about the process, and success/failure indication.  Note that on
+	   error the AUDIT_CRYPTO_STORAGE_KEY record will be empty. */
+	ab = audit_log_start(current->audit_context, GFP_KERNEL,
+			     AUDIT_CRYPTO_STORAGE_KEY);
+
+	if (current_euid() != 0 && !capable(CAP_SYS_ADMIN)) {
+		err();
+		ret = -EPERM;
+		goto end;
+	}
+
+	if (st->key_size > sizeof(master_key.key.secret.data)) {
+		err();
+		ret = -EINVAL;
+		goto end;
+	}
+
+	if (st->key_size != 16 && st->key_size != 24 && st->key_size != 32) {
+		dprintk(0, KERN_DEBUG, "Master key size must be 16,24 or 32.\n");
+		ret = -EINVAL;
+		goto end;
+	}
+
+	if (master_key.type != NCR_KEY_TYPE_INVALID) {
+		dprintk(0, KERN_DEBUG, "Master key was previously initialized.\n");
+	}
+
+	if (unlikely(copy_from_user(master_key.key.secret.data, st->key,
+				    st->key_size))) {
+		err();
+		ret = -EFAULT;
+		goto end;
+	}
+
+	dprintk(0, KERN_INFO, "Initializing master key.\n");
+	/* Not much we can reveal... */
+	audit_log_format(ab, "key_size=%u", (unsigned)st->key_size);
+
+	master_key.type = NCR_KEY_TYPE_SECRET;
+	master_key.key.secret.size = st->key_size;
+
+	ret = 0;
+
+end:
+	audit_log_end(ab);
+
+	return ret;
+}
+
+int
+ncr_ioctl(struct ncr_lists *lst, unsigned int cmd, unsigned long arg_)
+{
+	void __user *arg = (void __user *)arg_;
+	struct nlattr *tb[NCR_ATTR_MAX + 1];
+	void *attr_buf;
+	int ret;
+
+	if (unlikely(!lst))
+		BUG();
+
+	switch (cmd) {
+#define CASE_(LABEL, STRUCT, FUNCTION, ARGS)				\
+	case (LABEL): {							\
+		struct STRUCT data;					\
+									\
+		attr_buf = NCR_GET_INPUT_ARGS_NO_OUTPUT(&data, tb, arg); \
+		if (IS_ERR(attr_buf)) {					\
+			err();						\
+			return PTR_ERR(attr_buf);			\
+		}							\
+		ret = (FUNCTION)ARGS;					\
+		break;							\
+	}
+#define CASE_NO_OUTPUT(LABEL, STRUCT, FUNCTION)				\
+		CASE_(LABEL, STRUCT, FUNCTION, (lst, &data, tb))
+#define CASE_NO_OUTPUT_COMPAT(LABEL, STRUCT, FUNCTION)			\
+		CASE_(LABEL, STRUCT, FUNCTION, (lst, &data, tb, 0))
+
+	case NCRIO_KEY_INIT:
+		return ncr_key_init(lst);
+	CASE_NO_OUTPUT(NCRIO_KEY_GENERATE, ncr_key_generate, ncr_key_generate);
+	CASE_NO_OUTPUT(NCRIO_KEY_GENERATE_PAIR, ncr_key_generate_pair,
+		       ncr_key_generate_pair);
+	CASE_NO_OUTPUT(NCRIO_KEY_DERIVE, ncr_key_derive, ncr_key_derive);
+	case NCRIO_KEY_GET_INFO: {
+		struct ncr_key_get_info data;
+		struct ncr_out out;
+
+		attr_buf = NCR_GET_INPUT_ARGS(&data, tb, arg);
+		if (IS_ERR(attr_buf)) {
+			err();
+			return PTR_ERR(attr_buf);
+		}
+		ret = NCR_OUT_INIT(&out, &data, arg);
+		if (ret != 0) {
+			err();
+			break;
+		}
+		ret = ncr_key_get_info(lst, &out, &data, tb);
+		ncr_out_free(&out);
+		break;
+	}
+	CASE_NO_OUTPUT(NCRIO_KEY_EXPORT, ncr_key_export, ncr_key_export);
+	CASE_NO_OUTPUT(NCRIO_KEY_IMPORT, ncr_key_import, ncr_key_import);
+	case NCRIO_KEY_DEINIT: {
+		ncr_key_t key;
+
+		ret = get_user(key, (const ncr_key_t __user *)arg);
+		if (unlikely(ret)) {
+			err();
+			return ret;
+		}
+		return ncr_key_deinit(lst, key);
+	}
+	CASE_NO_OUTPUT(NCRIO_KEY_WRAP, ncr_key_wrap, ncr_key_wrap);
+	CASE_NO_OUTPUT(NCRIO_KEY_UNWRAP, ncr_key_unwrap, ncr_key_unwrap);
+	CASE_NO_OUTPUT(NCRIO_KEY_STORAGE_WRAP, ncr_key_storage_wrap,
+		       ncr_key_storage_wrap);
+	CASE_NO_OUTPUT(NCRIO_KEY_STORAGE_UNWRAP, ncr_key_storage_unwrap,
+		       ncr_key_storage_unwrap);
+	CASE_NO_OUTPUT(NCRIO_SESSION_INIT, ncr_session_init, ncr_session_init);
+	CASE_NO_OUTPUT_COMPAT(NCRIO_SESSION_UPDATE, ncr_session_update,
+			      ncr_session_update);
+	CASE_NO_OUTPUT_COMPAT(NCRIO_SESSION_FINAL, ncr_session_final,
+			      ncr_session_final);
+	CASE_NO_OUTPUT_COMPAT(NCRIO_SESSION_ONCE, ncr_session_once,
+			      ncr_session_once);
+	CASE_(NCRIO_MASTER_KEY_SET, ncr_master_key_set, ncr_master_key_set,
+	      (&data, tb));
+	default:
+		return -EINVAL;
+#undef CASE_
+#undef CASE_NO_OUTPUT
+#undef CASE_NO_OUTPUT_COMPAT
+	}
+	kfree(attr_buf);
+	return ret;
+}
+
+#ifdef CONFIG_COMPAT
+struct compat_ncr_key_export {
+	__u32 input_size, output_size;
+	ncr_key_t key;
+	compat_uptr_t buffer;
+	compat_int_t buffer_size;
+	__NL_ATTRIBUTES;
+};
+#define COMPAT_NCRIO_KEY_EXPORT _IOWR('c', 209, struct compat_ncr_key_export)
+
+static void convert_ncr_key_export(struct ncr_key_export *new,
+				   const struct compat_ncr_key_export *old)
+{
+	new->key = old->key;
+	new->buffer = compat_ptr(old->buffer);
+	new->buffer_size = old->buffer_size;
+}
+
+struct compat_ncr_key_import {
+	__u32 input_size, output_size;
+	ncr_key_t key;
+	compat_uptr_t data;
+	__u32 data_size;
+	__NL_ATTRIBUTES;
+};
+#define COMPAT_NCRIO_KEY_IMPORT _IOWR('c', 210, struct compat_ncr_key_import)
+
+static void convert_ncr_key_import(struct ncr_key_import *new,
+				   const struct compat_ncr_key_import *old)
+{
+	new->key = old->key;
+	new->data = compat_ptr(old->data);
+	new->data_size = old->data_size;
+}
+
+struct compat_ncr_key_wrap {
+	__u32 input_size, output_size;
+	ncr_key_t wrapping_key;
+	ncr_key_t source_key;
+	compat_uptr_t buffer;
+	compat_int_t buffer_size;
+	__NL_ATTRIBUTES;
+};
+#define COMPAT_NCRIO_KEY_WRAP _IOWR('c', 250, struct compat_ncr_key_wrap)
+
+static void convert_ncr_key_wrap(struct ncr_key_wrap *new,
+				 const struct compat_ncr_key_wrap *old)
+{
+	new->wrapping_key = old->wrapping_key;
+	new->source_key = old->source_key;
+	new->buffer = compat_ptr(old->buffer);
+	new->buffer_size = old->buffer_size;
+}
+
+struct compat_ncr_key_unwrap {
+	__u32 input_size, output_size;
+	ncr_key_t wrapping_key;
+	ncr_key_t dest_key;
+	compat_uptr_t data;
+	__u32 data_size;
+	__NL_ATTRIBUTES;
+};
+#define COMPAT_NCRIO_KEY_UNWRAP _IOWR('c', 251, struct compat_ncr_key_unwrap)
+
+static void convert_ncr_key_unwrap(struct ncr_key_unwrap *new,
+				   const struct compat_ncr_key_unwrap *old)
+{
+	new->wrapping_key = old->wrapping_key;
+	new->dest_key = old->dest_key;
+	new->data = compat_ptr(old->data);
+	new->data_size = old->data_size;
+}
+
+struct compat_ncr_key_storage_wrap {
+	__u32 input_size, output_size;
+	ncr_key_t key;
+	compat_uptr_t buffer;
+	compat_int_t buffer_size;
+	__NL_ATTRIBUTES;
+};
+#define COMPAT_NCRIO_KEY_STORAGE_WRAP				\
+	_IOWR('c', 261, struct compat_ncr_key_storage_wrap)
+
+static void convert_ncr_key_storage_wrap(struct ncr_key_storage_wrap *new,
+					 const struct compat_ncr_key_storage_wrap *old)
+{
+	new->key = old->key;
+	new->buffer = compat_ptr(old->buffer);
+	new->buffer_size = old->buffer_size;
+}
+
+struct compat_ncr_key_storage_unwrap {
+	__u32 input_size, output_size;
+	ncr_key_t key;
+	compat_uptr_t data;
+	__u32 data_size;
+	__NL_ATTRIBUTES;
+};
+#define COMPAT_NCRIO_KEY_STORAGE_UNWRAP				\
+	_IOWR('c', 262, struct compat_ncr_key_storage_wrap)
+
+static void convert_ncr_key_storage_unwrap(struct ncr_key_storage_unwrap *new,
+					   const struct compat_ncr_key_storage_unwrap *old)
+{
+	new->key = old->key;
+	new->data = compat_ptr(old->data);
+	new->data_size = old->data_size;
+}
+
+struct compat_ncr_master_key_set {
+	__u32 input_size, output_size;
+	compat_uptr_t key;
+	__u32 key_size;
+	__NL_ATTRIBUTES;
+};
+#define COMPAT_NCRIO_MASTER_KEY_SET				\
+	_IOWR('c', 260, struct compat_ncr_master_key_set)
+
+static void convert_ncr_master_key_set(struct ncr_master_key_set *new,
+				       const struct compat_ncr_master_key_set *old)
+{
+	new->key = compat_ptr(old->key);
+	new->key_size = old->key_size;
+}
+
+long
+ncr_compat_ioctl(struct ncr_lists *lst, unsigned int cmd, unsigned long arg_)
+{
+	void __user *arg = (void __user *)arg_;
+	struct nlattr *tb[NCR_ATTR_MAX + 1];
+	void *attr_buf;
+	int ret;
+
+	if (unlikely(!lst))
+		BUG();
+
+	switch (cmd) {
+	case NCRIO_KEY_INIT:
+	case NCRIO_KEY_GENERATE:
+	case NCRIO_KEY_GENERATE_PAIR:
+	case NCRIO_KEY_DERIVE:
+	case NCRIO_KEY_GET_INFO:
+	case NCRIO_KEY_DEINIT:
+	case NCRIO_SESSION_INIT:
+		return ncr_ioctl(lst, cmd, arg_);
+
+#define CASE_(LABEL, STRUCT, FUNCTION, ARGS)				\
+	case (LABEL): {							\
+		struct compat_##STRUCT old;				\
+		struct STRUCT new;					\
+									\
+		attr_buf = NCR_GET_INPUT_ARGS_NO_OUTPUT(&old, tb, arg);	\
+		if (IS_ERR(attr_buf)) {					\
+			err();						\
+			return PTR_ERR(attr_buf);			\
+		}							\
+		convert_##STRUCT(&new, &old);				\
+		ret = (FUNCTION)ARGS;					\
+		break;							\
+	}
+#define CASE_NO_OUTPUT(LABEL, STRUCT, FUNCTION)			\
+		CASE_(LABEL, STRUCT, FUNCTION, (lst, &new, tb))
+
+#define CASE_COMPAT_ONLY(LABEL, STRUCT, FUNCTION)			\
+	case (LABEL): {							\
+		struct STRUCT data;					\
+									\
+		attr_buf = NCR_GET_INPUT_ARGS_NO_OUTPUT(&data, tb, arg); \
+		if (IS_ERR(attr_buf)) {					\
+			err();						\
+			return PTR_ERR(attr_buf);			\
+		}							\
+		ret = (FUNCTION)(lst, &data, tb, 1);			\
+		break;							\
+	}
+
+	CASE_NO_OUTPUT(COMPAT_NCRIO_KEY_EXPORT, ncr_key_export, ncr_key_export);
+	CASE_NO_OUTPUT(COMPAT_NCRIO_KEY_IMPORT, ncr_key_import, ncr_key_import);
+	CASE_NO_OUTPUT(COMPAT_NCRIO_KEY_WRAP, ncr_key_wrap, ncr_key_wrap);
+	CASE_NO_OUTPUT(COMPAT_NCRIO_KEY_UNWRAP, ncr_key_unwrap, ncr_key_unwrap);
+	CASE_NO_OUTPUT(COMPAT_NCRIO_KEY_STORAGE_WRAP, ncr_key_storage_wrap,
+		       ncr_key_storage_wrap);
+	CASE_NO_OUTPUT(COMPAT_NCRIO_KEY_STORAGE_UNWRAP, ncr_key_storage_unwrap,
+		       ncr_key_storage_unwrap);
+	CASE_COMPAT_ONLY(NCRIO_SESSION_UPDATE, ncr_session_update,
+			 ncr_session_update);
+	CASE_COMPAT_ONLY(NCRIO_SESSION_FINAL, ncr_session_final,
+			 ncr_session_final);
+	CASE_COMPAT_ONLY(NCRIO_SESSION_ONCE, ncr_session_once,
+			 ncr_session_once);
+	CASE_(COMPAT_NCRIO_MASTER_KEY_SET, ncr_master_key_set,
+	      ncr_master_key_set, (&new, tb));
+	default:
+		return -EINVAL;
+#undef CASE_
+#undef CASE_NO_OUTPUT
+#undef CASE_COMPAT_ONLY
+	}
+	kfree(attr_buf);
+	return ret;
+}
+#endif
+
 int ncr_session_input_data_from_nla(struct ncr_session_input_data *dest,
 				    const struct nlattr *nla, int compat)
 {
-- 
1.7.2.1

--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]

  Powered by Linux