summaryrefslogtreecommitdiffstats
path: root/crypto/userspace/ncr.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/userspace/ncr.c')
-rw-r--r--crypto/userspace/ncr.c414
1 files changed, 363 insertions, 51 deletions
diff --git a/crypto/userspace/ncr.c b/crypto/userspace/ncr.c
index 4cf79b3a025..e643fe139a0 100644
--- a/crypto/userspace/ncr.c
+++ b/crypto/userspace/ncr.c
@@ -22,6 +22,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <linux/compat.h>
#include <linux/crypto.h>
#include <linux/ioctl.h>
#include <linux/mm.h>
@@ -32,7 +33,9 @@
#include <linux/cred.h>
#include <linux/capability.h>
#include <linux/ncr.h>
+#include <net/netlink.h>
#include "ncr-int.h"
+#include "utils.h"
#include <linux/workqueue.h>
/* This is the master wrapping key for storage of keys
@@ -74,26 +77,20 @@ void ncr_master_key_reset(void)
memset(&master_key, 0, sizeof(master_key));
}
-static int ncr_master_key_set(void __user *arg)
+static int ncr_master_key_set(const struct ncr_master_key_set *st,
+ struct nlattr *tb[])
{
-struct ncr_master_key_st st;
-
- if (current_euid() != 0 && !capable(CAP_SYS_ADMIN)) {
+ if (!capable(CAP_SYS_ADMIN)) {
err();
return -EPERM;
}
- if (unlikely(copy_from_user(&st, arg, sizeof(st)))) {
- err();
- return -EFAULT;
- }
-
- if (st.key_size > sizeof(master_key.key.secret.data)) {
+ if (st->key_size > sizeof(master_key.key.secret.data)) {
err();
return -EINVAL;
}
- if (st.key_size != 16 && st.key_size != 24 && st.key_size != 32) {
+ 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");
return -EINVAL;
}
@@ -102,7 +99,8 @@ struct ncr_master_key_st st;
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))) {
+ if (unlikely(copy_from_user(master_key.key.secret.data, st->key,
+ st->key_size))) {
err();
return -EFAULT;
}
@@ -110,56 +108,370 @@ struct ncr_master_key_st st;
dprintk(0, KERN_INFO, "Initializing master key.\n");
master_key.type = NCR_KEY_TYPE_SECRET;
- master_key.key.secret.size = st.key_size;
+ master_key.key.secret.size = st->key_size;
return 0;
}
-int
+long
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:
- return ncr_key_init(lst, arg);
- case NCRIO_KEY_DEINIT:
- return ncr_key_deinit(lst, arg);
- case NCRIO_KEY_GENERATE:
- return ncr_key_generate(lst, arg);
- case NCRIO_KEY_EXPORT:
- return ncr_key_export(lst, arg);
- case NCRIO_KEY_IMPORT:
- return ncr_key_import(lst, arg);
- case NCRIO_KEY_GET_INFO:
- return ncr_key_info(lst, arg);
- case NCRIO_KEY_WRAP:
- return ncr_key_wrap(lst, arg);
- case NCRIO_KEY_UNWRAP:
- return ncr_key_unwrap(lst, arg);
- case NCRIO_KEY_STORAGE_WRAP:
- return ncr_key_storage_wrap(lst, arg);
- case NCRIO_KEY_STORAGE_UNWRAP:
- return ncr_key_storage_unwrap(lst, arg);
- case NCRIO_SESSION_INIT:
- return ncr_session_init(lst, arg);
- case NCRIO_SESSION_UPDATE:
- return ncr_session_update(lst, arg);
- case NCRIO_SESSION_FINAL:
- return ncr_session_final(lst, arg);
- case NCRIO_SESSION_ONCE:
- return ncr_session_once(lst, arg);
-
- case NCRIO_MASTER_KEY_SET:
- return ncr_master_key_set(arg);
- case NCRIO_KEY_GENERATE_PAIR:
- return ncr_key_generate_pair(lst, arg);
- case NCRIO_KEY_DERIVE:
- return ncr_key_derive(lst, arg);
- default:
- return -EINVAL;
+ 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)
+{
+ if (unlikely(nla == NULL))
+ return -EINVAL;
+#ifdef CONFIG_COMPAT
+ if (!compat) {
+#endif
+ if (unlikely(nla_len(nla) < sizeof(dest)))
+ return -ERANGE; /* nla_validate would return -ERANGE. */
+ memcpy(dest, nla_data(nla), sizeof(*dest));
+#ifdef CONFIG_COMPAT
+ } else {
+ struct compat_ncr_session_input_data old;
+
+ if (unlikely(nla_len(nla) < sizeof(old)))
+ return -ERANGE;
+ memcpy(&old, nla_data(nla), sizeof(old));
+ dest->data = compat_ptr(old.data);
+ dest->data_size = old.data_size;
+ }
+#endif
+ return 0;
+}
+
+int ncr_session_output_buffer_from_nla(struct ncr_session_output_buffer *dest,
+ const struct nlattr *nla, int compat)
+{
+ if (unlikely(nla == NULL))
+ return -EINVAL;
+#ifdef CONFIG_COMPAT
+ if (!compat) {
+#endif
+ if (unlikely(nla_len(nla) < sizeof(dest)))
+ return -ERANGE; /* nla_validate would return -ERANGE. */
+ memcpy(dest, nla_data(nla), sizeof(*dest));
+#ifdef CONFIG_COMPAT
+ } else {
+ struct compat_ncr_session_output_buffer old;
+
+ if (unlikely(nla_len(nla) < sizeof(old)))
+ return -ERANGE;
+ memcpy(&old, nla_data(nla), sizeof(old));
+ dest->buffer = compat_ptr(old.buffer);
+ dest->buffer_size = old.buffer_size;
+ dest->result_size_ptr = compat_ptr(old.result_size_ptr);
+ }
+#endif
+ return 0;
+}
+
+
+int ncr_session_output_buffer_set_size(const struct ncr_session_output_buffer *dest,
+ size_t size, int compat)
+{
+#ifdef CONFIG_COMPAT
+ if (!compat)
+#endif
+ return put_user(size, dest->result_size_ptr);
+#ifdef CONFIG_COMPAT
+ else {
+ compat_size_t old;
+
+ old = size;
+ return put_user(old,
+ (compat_size_t __user *)dest->result_size_ptr);
}
+#endif
}