|
@@ -1,8 +1,8 @@
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
|
|
/*
|
|
|
- * zcrypt 2.1.0
|
|
|
+ * zcrypt 2.2.0
|
|
|
*
|
|
|
- * Copyright IBM Corp. 2001, 2012
|
|
|
+ * Copyright IBM Corp. 2001, 2018
|
|
|
* Author(s): Robert Burroughs
|
|
|
* Eric Rossman (edrossma@us.ibm.com)
|
|
|
* Cornelia Huck <cornelia.huck@de.ibm.com>
|
|
@@ -11,6 +11,7 @@
|
|
|
* Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
|
|
|
* Ralph Wuerthner <rwuerthn@de.ibm.com>
|
|
|
* MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com>
|
|
|
+ * Multiple device nodes: Harald Freudenberger <freude@linux.ibm.com>
|
|
|
*/
|
|
|
|
|
|
#include <linux/module.h>
|
|
@@ -24,6 +25,8 @@
|
|
|
#include <linux/uaccess.h>
|
|
|
#include <linux/hw_random.h>
|
|
|
#include <linux/debugfs.h>
|
|
|
+#include <linux/cdev.h>
|
|
|
+#include <linux/ctype.h>
|
|
|
#include <asm/debug.h>
|
|
|
|
|
|
#define CREATE_TRACE_POINTS
|
|
@@ -108,6 +111,375 @@ struct zcrypt_ops *zcrypt_msgtype(unsigned char *name, int variant)
|
|
|
}
|
|
|
EXPORT_SYMBOL(zcrypt_msgtype);
|
|
|
|
|
|
+/*
|
|
|
+ * Multi device nodes extension functions.
|
|
|
+ */
|
|
|
+
|
|
|
+#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
|
|
|
+
|
|
|
+struct zcdn_device;
|
|
|
+
|
|
|
+static struct class *zcrypt_class;
|
|
|
+static dev_t zcrypt_devt;
|
|
|
+static struct cdev zcrypt_cdev;
|
|
|
+
|
|
|
+struct zcdn_device {
|
|
|
+ struct device device;
|
|
|
+ struct ap_perms perms;
|
|
|
+};
|
|
|
+
|
|
|
+#define to_zcdn_dev(x) container_of((x), struct zcdn_device, device)
|
|
|
+
|
|
|
+#define ZCDN_MAX_NAME 32
|
|
|
+
|
|
|
+static int zcdn_create(const char *name);
|
|
|
+static int zcdn_destroy(const char *name);
|
|
|
+
|
|
|
+/* helper function, matches the name for find_zcdndev_by_name() */
|
|
|
+static int __match_zcdn_name(struct device *dev, const void *data)
|
|
|
+{
|
|
|
+ return strcmp(dev_name(dev), (const char *)data) == 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* helper function, matches the devt value for find_zcdndev_by_devt() */
|
|
|
+static int __match_zcdn_devt(struct device *dev, const void *data)
|
|
|
+{
|
|
|
+ return dev->devt == *((dev_t *) data);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Find zcdn device by name.
|
|
|
+ * Returns reference to the zcdn device which needs to be released
|
|
|
+ * with put_device() after use.
|
|
|
+ */
|
|
|
+static inline struct zcdn_device *find_zcdndev_by_name(const char *name)
|
|
|
+{
|
|
|
+ struct device *dev =
|
|
|
+ class_find_device(zcrypt_class, NULL,
|
|
|
+ (void *) name,
|
|
|
+ __match_zcdn_name);
|
|
|
+
|
|
|
+ return dev ? to_zcdn_dev(dev) : NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Find zcdn device by devt value.
|
|
|
+ * Returns reference to the zcdn device which needs to be released
|
|
|
+ * with put_device() after use.
|
|
|
+ */
|
|
|
+static inline struct zcdn_device *find_zcdndev_by_devt(dev_t devt)
|
|
|
+{
|
|
|
+ struct device *dev =
|
|
|
+ class_find_device(zcrypt_class, NULL,
|
|
|
+ (void *) &devt,
|
|
|
+ __match_zcdn_devt);
|
|
|
+
|
|
|
+ return dev ? to_zcdn_dev(dev) : NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t ioctlmask_show(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ int i, rc;
|
|
|
+ struct zcdn_device *zcdndev = to_zcdn_dev(dev);
|
|
|
+
|
|
|
+ if (mutex_lock_interruptible(&ap_perms_mutex))
|
|
|
+ return -ERESTARTSYS;
|
|
|
+
|
|
|
+ buf[0] = '0';
|
|
|
+ buf[1] = 'x';
|
|
|
+ for (i = 0; i < sizeof(zcdndev->perms.ioctlm) / sizeof(long); i++)
|
|
|
+ snprintf(buf + 2 + 2 * i * sizeof(long),
|
|
|
+ PAGE_SIZE - 2 - 2 * i * sizeof(long),
|
|
|
+ "%016lx", zcdndev->perms.ioctlm[i]);
|
|
|
+ buf[2 + 2 * i * sizeof(long)] = '\n';
|
|
|
+ buf[2 + 2 * i * sizeof(long) + 1] = '\0';
|
|
|
+ rc = 2 + 2 * i * sizeof(long) + 1;
|
|
|
+
|
|
|
+ mutex_unlock(&ap_perms_mutex);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t ioctlmask_store(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ const char *buf, size_t count)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+ struct zcdn_device *zcdndev = to_zcdn_dev(dev);
|
|
|
+
|
|
|
+ rc = ap_parse_mask_str(buf, zcdndev->perms.ioctlm,
|
|
|
+ AP_IOCTLS, &ap_perms_mutex);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static DEVICE_ATTR_RW(ioctlmask);
|
|
|
+
|
|
|
+static ssize_t apmask_show(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ int i, rc;
|
|
|
+ struct zcdn_device *zcdndev = to_zcdn_dev(dev);
|
|
|
+
|
|
|
+ if (mutex_lock_interruptible(&ap_perms_mutex))
|
|
|
+ return -ERESTARTSYS;
|
|
|
+
|
|
|
+ buf[0] = '0';
|
|
|
+ buf[1] = 'x';
|
|
|
+ for (i = 0; i < sizeof(zcdndev->perms.apm) / sizeof(long); i++)
|
|
|
+ snprintf(buf + 2 + 2 * i * sizeof(long),
|
|
|
+ PAGE_SIZE - 2 - 2 * i * sizeof(long),
|
|
|
+ "%016lx", zcdndev->perms.apm[i]);
|
|
|
+ buf[2 + 2 * i * sizeof(long)] = '\n';
|
|
|
+ buf[2 + 2 * i * sizeof(long) + 1] = '\0';
|
|
|
+ rc = 2 + 2 * i * sizeof(long) + 1;
|
|
|
+
|
|
|
+ mutex_unlock(&ap_perms_mutex);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t apmask_store(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ const char *buf, size_t count)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+ struct zcdn_device *zcdndev = to_zcdn_dev(dev);
|
|
|
+
|
|
|
+ rc = ap_parse_mask_str(buf, zcdndev->perms.apm,
|
|
|
+ AP_DEVICES, &ap_perms_mutex);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static DEVICE_ATTR_RW(apmask);
|
|
|
+
|
|
|
+static ssize_t aqmask_show(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ int i, rc;
|
|
|
+ struct zcdn_device *zcdndev = to_zcdn_dev(dev);
|
|
|
+
|
|
|
+ if (mutex_lock_interruptible(&ap_perms_mutex))
|
|
|
+ return -ERESTARTSYS;
|
|
|
+
|
|
|
+ buf[0] = '0';
|
|
|
+ buf[1] = 'x';
|
|
|
+ for (i = 0; i < sizeof(zcdndev->perms.aqm) / sizeof(long); i++)
|
|
|
+ snprintf(buf + 2 + 2 * i * sizeof(long),
|
|
|
+ PAGE_SIZE - 2 - 2 * i * sizeof(long),
|
|
|
+ "%016lx", zcdndev->perms.aqm[i]);
|
|
|
+ buf[2 + 2 * i * sizeof(long)] = '\n';
|
|
|
+ buf[2 + 2 * i * sizeof(long) + 1] = '\0';
|
|
|
+ rc = 2 + 2 * i * sizeof(long) + 1;
|
|
|
+
|
|
|
+ mutex_unlock(&ap_perms_mutex);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t aqmask_store(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ const char *buf, size_t count)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+ struct zcdn_device *zcdndev = to_zcdn_dev(dev);
|
|
|
+
|
|
|
+ rc = ap_parse_mask_str(buf, zcdndev->perms.aqm,
|
|
|
+ AP_DOMAINS, &ap_perms_mutex);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static DEVICE_ATTR_RW(aqmask);
|
|
|
+
|
|
|
+static struct attribute *zcdn_dev_attrs[] = {
|
|
|
+ &dev_attr_ioctlmask.attr,
|
|
|
+ &dev_attr_apmask.attr,
|
|
|
+ &dev_attr_aqmask.attr,
|
|
|
+ NULL
|
|
|
+};
|
|
|
+
|
|
|
+static struct attribute_group zcdn_dev_attr_group = {
|
|
|
+ .attrs = zcdn_dev_attrs
|
|
|
+};
|
|
|
+
|
|
|
+static const struct attribute_group *zcdn_dev_attr_groups[] = {
|
|
|
+ &zcdn_dev_attr_group,
|
|
|
+ NULL
|
|
|
+};
|
|
|
+
|
|
|
+static ssize_t zcdn_create_store(struct class *class,
|
|
|
+ struct class_attribute *attr,
|
|
|
+ const char *buf, size_t count)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+ char name[ZCDN_MAX_NAME];
|
|
|
+
|
|
|
+ strncpy(name, skip_spaces(buf), sizeof(name));
|
|
|
+ name[sizeof(name) - 1] = '\0';
|
|
|
+
|
|
|
+ rc = zcdn_create(strim(name));
|
|
|
+
|
|
|
+ return rc ? rc : count;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct class_attribute class_attr_zcdn_create =
|
|
|
+ __ATTR(create, 0600, NULL, zcdn_create_store);
|
|
|
+
|
|
|
+static ssize_t zcdn_destroy_store(struct class *class,
|
|
|
+ struct class_attribute *attr,
|
|
|
+ const char *buf, size_t count)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+ char name[ZCDN_MAX_NAME];
|
|
|
+
|
|
|
+ strncpy(name, skip_spaces(buf), sizeof(name));
|
|
|
+ name[sizeof(name) - 1] = '\0';
|
|
|
+
|
|
|
+ rc = zcdn_destroy(strim(name));
|
|
|
+
|
|
|
+ return rc ? rc : count;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct class_attribute class_attr_zcdn_destroy =
|
|
|
+ __ATTR(destroy, 0600, NULL, zcdn_destroy_store);
|
|
|
+
|
|
|
+static void zcdn_device_release(struct device *dev)
|
|
|
+{
|
|
|
+ struct zcdn_device *zcdndev = to_zcdn_dev(dev);
|
|
|
+
|
|
|
+ ZCRYPT_DBF(DBF_INFO, "releasing zcdn device %d:%d\n",
|
|
|
+ MAJOR(dev->devt), MINOR(dev->devt));
|
|
|
+
|
|
|
+ kfree(zcdndev);
|
|
|
+}
|
|
|
+
|
|
|
+static int zcdn_create(const char *name)
|
|
|
+{
|
|
|
+ dev_t devt;
|
|
|
+ int i, rc = 0;
|
|
|
+ char nodename[ZCDN_MAX_NAME];
|
|
|
+ struct zcdn_device *zcdndev;
|
|
|
+
|
|
|
+ if (mutex_lock_interruptible(&ap_perms_mutex))
|
|
|
+ return -ERESTARTSYS;
|
|
|
+
|
|
|
+ /* check if device node with this name already exists */
|
|
|
+ if (name[0]) {
|
|
|
+ zcdndev = find_zcdndev_by_name(name);
|
|
|
+ if (zcdndev) {
|
|
|
+ put_device(&zcdndev->device);
|
|
|
+ rc = -EEXIST;
|
|
|
+ goto unlockout;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* find an unused minor number */
|
|
|
+ for (i = 0; i < ZCRYPT_MAX_MINOR_NODES; i++) {
|
|
|
+ devt = MKDEV(MAJOR(zcrypt_devt), MINOR(zcrypt_devt) + i);
|
|
|
+ zcdndev = find_zcdndev_by_devt(devt);
|
|
|
+ if (zcdndev)
|
|
|
+ put_device(&zcdndev->device);
|
|
|
+ else
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (i == ZCRYPT_MAX_MINOR_NODES) {
|
|
|
+ rc = -ENOSPC;
|
|
|
+ goto unlockout;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* alloc and prepare a new zcdn device */
|
|
|
+ zcdndev = kzalloc(sizeof(*zcdndev), GFP_KERNEL);
|
|
|
+ if (!zcdndev) {
|
|
|
+ rc = -ENOMEM;
|
|
|
+ goto unlockout;
|
|
|
+ }
|
|
|
+ zcdndev->device.release = zcdn_device_release;
|
|
|
+ zcdndev->device.class = zcrypt_class;
|
|
|
+ zcdndev->device.devt = devt;
|
|
|
+ zcdndev->device.groups = zcdn_dev_attr_groups;
|
|
|
+ if (name[0])
|
|
|
+ strncpy(nodename, name, sizeof(nodename));
|
|
|
+ else
|
|
|
+ snprintf(nodename, sizeof(nodename),
|
|
|
+ ZCRYPT_NAME "_%d", (int) MINOR(devt));
|
|
|
+ nodename[sizeof(nodename)-1] = '\0';
|
|
|
+ if (dev_set_name(&zcdndev->device, nodename)) {
|
|
|
+ rc = -EINVAL;
|
|
|
+ goto unlockout;
|
|
|
+ }
|
|
|
+ rc = device_register(&zcdndev->device);
|
|
|
+ if (rc) {
|
|
|
+ put_device(&zcdndev->device);
|
|
|
+ goto unlockout;
|
|
|
+ }
|
|
|
+
|
|
|
+ ZCRYPT_DBF(DBF_INFO, "created zcdn device %d:%d\n",
|
|
|
+ MAJOR(devt), MINOR(devt));
|
|
|
+
|
|
|
+unlockout:
|
|
|
+ mutex_unlock(&ap_perms_mutex);
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+static int zcdn_destroy(const char *name)
|
|
|
+{
|
|
|
+ int rc = 0;
|
|
|
+ struct zcdn_device *zcdndev;
|
|
|
+
|
|
|
+ if (mutex_lock_interruptible(&ap_perms_mutex))
|
|
|
+ return -ERESTARTSYS;
|
|
|
+
|
|
|
+ /* try to find this zcdn device */
|
|
|
+ zcdndev = find_zcdndev_by_name(name);
|
|
|
+ if (!zcdndev) {
|
|
|
+ rc = -ENOENT;
|
|
|
+ goto unlockout;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The zcdn device is not hard destroyed. It is subject to
|
|
|
+ * reference counting and thus just needs to be unregistered.
|
|
|
+ */
|
|
|
+ put_device(&zcdndev->device);
|
|
|
+ device_unregister(&zcdndev->device);
|
|
|
+
|
|
|
+unlockout:
|
|
|
+ mutex_unlock(&ap_perms_mutex);
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+static void zcdn_destroy_all(void)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ dev_t devt;
|
|
|
+ struct zcdn_device *zcdndev;
|
|
|
+
|
|
|
+ mutex_lock(&ap_perms_mutex);
|
|
|
+ for (i = 0; i < ZCRYPT_MAX_MINOR_NODES; i++) {
|
|
|
+ devt = MKDEV(MAJOR(zcrypt_devt), MINOR(zcrypt_devt) + i);
|
|
|
+ zcdndev = find_zcdndev_by_devt(devt);
|
|
|
+ if (zcdndev) {
|
|
|
+ put_device(&zcdndev->device);
|
|
|
+ device_unregister(&zcdndev->device);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ mutex_unlock(&ap_perms_mutex);
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
/**
|
|
|
* zcrypt_read (): Not supported beyond zcrypt 1.3.1.
|
|
|
*
|
|
@@ -137,6 +509,23 @@ static ssize_t zcrypt_write(struct file *filp, const char __user *buf,
|
|
|
*/
|
|
|
static int zcrypt_open(struct inode *inode, struct file *filp)
|
|
|
{
|
|
|
+ struct ap_perms *perms = &ap_perms;
|
|
|
+
|
|
|
+#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
|
|
|
+ if (filp->f_inode->i_cdev == &zcrypt_cdev) {
|
|
|
+ struct zcdn_device *zcdndev;
|
|
|
+
|
|
|
+ if (mutex_lock_interruptible(&ap_perms_mutex))
|
|
|
+ return -ERESTARTSYS;
|
|
|
+ zcdndev = find_zcdndev_by_devt(filp->f_inode->i_rdev);
|
|
|
+ /* find returns a reference, no get_device() needed */
|
|
|
+ mutex_unlock(&ap_perms_mutex);
|
|
|
+ if (zcdndev)
|
|
|
+ perms = &zcdndev->perms;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ filp->private_data = (void *) perms;
|
|
|
+
|
|
|
atomic_inc(&zcrypt_open_count);
|
|
|
return nonseekable_open(inode, filp);
|
|
|
}
|
|
@@ -148,10 +537,55 @@ static int zcrypt_open(struct inode *inode, struct file *filp)
|
|
|
*/
|
|
|
static int zcrypt_release(struct inode *inode, struct file *filp)
|
|
|
{
|
|
|
+#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
|
|
|
+ if (filp->f_inode->i_cdev == &zcrypt_cdev) {
|
|
|
+ struct zcdn_device *zcdndev;
|
|
|
+
|
|
|
+ if (mutex_lock_interruptible(&ap_perms_mutex))
|
|
|
+ return -ERESTARTSYS;
|
|
|
+ zcdndev = find_zcdndev_by_devt(filp->f_inode->i_rdev);
|
|
|
+ mutex_unlock(&ap_perms_mutex);
|
|
|
+ if (zcdndev) {
|
|
|
+ /* 2 puts here: one for find, one for open */
|
|
|
+ put_device(&zcdndev->device);
|
|
|
+ put_device(&zcdndev->device);
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
atomic_dec(&zcrypt_open_count);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static inline int zcrypt_check_ioctl(struct ap_perms *perms,
|
|
|
+ unsigned int cmd)
|
|
|
+{
|
|
|
+ int rc = -EPERM;
|
|
|
+ int ioctlnr = (cmd & _IOC_NRMASK) >> _IOC_NRSHIFT;
|
|
|
+
|
|
|
+ if (ioctlnr > 0 && ioctlnr < AP_IOCTLS) {
|
|
|
+ if (test_bit_inv(ioctlnr, perms->ioctlm))
|
|
|
+ rc = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (rc)
|
|
|
+ ZCRYPT_DBF(DBF_WARN,
|
|
|
+ "ioctl check failed: ioctlnr=0x%04x rc=%d\n",
|
|
|
+ ioctlnr, rc);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+static inline bool zcrypt_check_card(struct ap_perms *perms, int card)
|
|
|
+{
|
|
|
+ return test_bit_inv(card, perms->apm) ? true : false;
|
|
|
+}
|
|
|
+
|
|
|
+static inline bool zcrypt_check_queue(struct ap_perms *perms, int queue)
|
|
|
+{
|
|
|
+ return test_bit_inv(queue, perms->aqm) ? true : false;
|
|
|
+}
|
|
|
+
|
|
|
static inline struct zcrypt_queue *zcrypt_pick_queue(struct zcrypt_card *zc,
|
|
|
struct zcrypt_queue *zq,
|
|
|
unsigned int weight)
|
|
@@ -213,7 +647,8 @@ static inline bool zcrypt_queue_compare(struct zcrypt_queue *zq,
|
|
|
/*
|
|
|
* zcrypt ioctls.
|
|
|
*/
|
|
|
-static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
|
|
|
+static long zcrypt_rsa_modexpo(struct ap_perms *perms,
|
|
|
+ struct ica_rsa_modexpo *mex)
|
|
|
{
|
|
|
struct zcrypt_card *zc, *pref_zc;
|
|
|
struct zcrypt_queue *zq, *pref_zq;
|
|
@@ -250,6 +685,9 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
|
|
|
if (zc->min_mod_size > mex->inputdatalength ||
|
|
|
zc->max_mod_size < mex->inputdatalength)
|
|
|
continue;
|
|
|
+ /* check if device node has admission for this card */
|
|
|
+ if (!zcrypt_check_card(perms, zc->card->id))
|
|
|
+ continue;
|
|
|
/* get weight index of the card device */
|
|
|
weight = zc->speed_rating[func_code];
|
|
|
if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
|
|
@@ -258,6 +696,10 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
|
|
|
/* check if device is online and eligible */
|
|
|
if (!zq->online || !zq->ops->rsa_modexpo)
|
|
|
continue;
|
|
|
+ /* check if device node has admission for this queue */
|
|
|
+ if (!zcrypt_check_queue(perms,
|
|
|
+ AP_QID_QUEUE(zq->queue->qid)))
|
|
|
+ continue;
|
|
|
if (zcrypt_queue_compare(zq, pref_zq,
|
|
|
weight, pref_weight))
|
|
|
continue;
|
|
@@ -287,7 +729,8 @@ out:
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
|
|
|
+static long zcrypt_rsa_crt(struct ap_perms *perms,
|
|
|
+ struct ica_rsa_modexpo_crt *crt)
|
|
|
{
|
|
|
struct zcrypt_card *zc, *pref_zc;
|
|
|
struct zcrypt_queue *zq, *pref_zq;
|
|
@@ -324,6 +767,9 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
|
|
|
if (zc->min_mod_size > crt->inputdatalength ||
|
|
|
zc->max_mod_size < crt->inputdatalength)
|
|
|
continue;
|
|
|
+ /* check if device node has admission for this card */
|
|
|
+ if (!zcrypt_check_card(perms, zc->card->id))
|
|
|
+ continue;
|
|
|
/* get weight index of the card device */
|
|
|
weight = zc->speed_rating[func_code];
|
|
|
if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
|
|
@@ -332,6 +778,10 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
|
|
|
/* check if device is online and eligible */
|
|
|
if (!zq->online || !zq->ops->rsa_modexpo_crt)
|
|
|
continue;
|
|
|
+ /* check if device node has admission for this queue */
|
|
|
+ if (!zcrypt_check_queue(perms,
|
|
|
+ AP_QID_QUEUE(zq->queue->qid)))
|
|
|
+ continue;
|
|
|
if (zcrypt_queue_compare(zq, pref_zq,
|
|
|
weight, pref_weight))
|
|
|
continue;
|
|
@@ -361,7 +811,8 @@ out:
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-long zcrypt_send_cprb(struct ica_xcRB *xcRB)
|
|
|
+static long _zcrypt_send_cprb(struct ap_perms *perms,
|
|
|
+ struct ica_xcRB *xcRB)
|
|
|
{
|
|
|
struct zcrypt_card *zc, *pref_zc;
|
|
|
struct zcrypt_queue *zq, *pref_zq;
|
|
@@ -389,6 +840,9 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB)
|
|
|
if (xcRB->user_defined != AUTOSELECT &&
|
|
|
xcRB->user_defined != zc->card->id)
|
|
|
continue;
|
|
|
+ /* check if device node has admission for this card */
|
|
|
+ if (!zcrypt_check_card(perms, zc->card->id))
|
|
|
+ continue;
|
|
|
/* get weight index of the card device */
|
|
|
weight = speed_idx_cca(func_code) * zc->speed_rating[SECKEY];
|
|
|
if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
|
|
@@ -400,6 +854,10 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB)
|
|
|
((*domain != (unsigned short) AUTOSELECT) &&
|
|
|
(*domain != AP_QID_QUEUE(zq->queue->qid))))
|
|
|
continue;
|
|
|
+ /* check if device node has admission for this queue */
|
|
|
+ if (!zcrypt_check_queue(perms,
|
|
|
+ AP_QID_QUEUE(zq->queue->qid)))
|
|
|
+ continue;
|
|
|
if (zcrypt_queue_compare(zq, pref_zq,
|
|
|
weight, pref_weight))
|
|
|
continue;
|
|
@@ -433,6 +891,11 @@ out:
|
|
|
AP_QID_CARD(qid), AP_QID_QUEUE(qid));
|
|
|
return rc;
|
|
|
}
|
|
|
+
|
|
|
+long zcrypt_send_cprb(struct ica_xcRB *xcRB)
|
|
|
+{
|
|
|
+ return _zcrypt_send_cprb(NULL, xcRB);
|
|
|
+}
|
|
|
EXPORT_SYMBOL(zcrypt_send_cprb);
|
|
|
|
|
|
static bool is_desired_ep11_card(unsigned int dev_id,
|
|
@@ -459,7 +922,8 @@ static bool is_desired_ep11_queue(unsigned int dev_qid,
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
|
|
|
+static long zcrypt_send_ep11_cprb(struct ap_perms *perms,
|
|
|
+ struct ep11_urb *xcrb)
|
|
|
{
|
|
|
struct zcrypt_card *zc, *pref_zc;
|
|
|
struct zcrypt_queue *zq, *pref_zq;
|
|
@@ -510,6 +974,9 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
|
|
|
if (targets &&
|
|
|
!is_desired_ep11_card(zc->card->id, target_num, targets))
|
|
|
continue;
|
|
|
+ /* check if device node has admission for this card */
|
|
|
+ if (!zcrypt_check_card(perms, zc->card->id))
|
|
|
+ continue;
|
|
|
/* get weight index of the card device */
|
|
|
weight = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY];
|
|
|
if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
|
|
@@ -522,6 +989,10 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
|
|
|
!is_desired_ep11_queue(zq->queue->qid,
|
|
|
target_num, targets)))
|
|
|
continue;
|
|
|
+ /* check if device node has admission for this queue */
|
|
|
+ if (!zcrypt_check_queue(perms,
|
|
|
+ AP_QID_QUEUE(zq->queue->qid)))
|
|
|
+ continue;
|
|
|
if (zcrypt_queue_compare(zq, pref_zq,
|
|
|
weight, pref_weight))
|
|
|
continue;
|
|
@@ -788,7 +1259,13 @@ static int zcrypt_requestq_count(void)
|
|
|
static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|
|
unsigned long arg)
|
|
|
{
|
|
|
- int rc = 0;
|
|
|
+ int rc;
|
|
|
+ struct ap_perms *perms =
|
|
|
+ (struct ap_perms *) filp->private_data;
|
|
|
+
|
|
|
+ rc = zcrypt_check_ioctl(perms, cmd);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
|
|
|
switch (cmd) {
|
|
|
case ICARSAMODEXPO: {
|
|
@@ -798,12 +1275,12 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|
|
if (copy_from_user(&mex, umex, sizeof(mex)))
|
|
|
return -EFAULT;
|
|
|
do {
|
|
|
- rc = zcrypt_rsa_modexpo(&mex);
|
|
|
+ rc = zcrypt_rsa_modexpo(perms, &mex);
|
|
|
} while (rc == -EAGAIN);
|
|
|
/* on failure: retry once again after a requested rescan */
|
|
|
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
|
|
|
do {
|
|
|
- rc = zcrypt_rsa_modexpo(&mex);
|
|
|
+ rc = zcrypt_rsa_modexpo(perms, &mex);
|
|
|
} while (rc == -EAGAIN);
|
|
|
if (rc) {
|
|
|
ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSAMODEXPO rc=%d\n", rc);
|
|
@@ -818,12 +1295,12 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|
|
if (copy_from_user(&crt, ucrt, sizeof(crt)))
|
|
|
return -EFAULT;
|
|
|
do {
|
|
|
- rc = zcrypt_rsa_crt(&crt);
|
|
|
+ rc = zcrypt_rsa_crt(perms, &crt);
|
|
|
} while (rc == -EAGAIN);
|
|
|
/* on failure: retry once again after a requested rescan */
|
|
|
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
|
|
|
do {
|
|
|
- rc = zcrypt_rsa_crt(&crt);
|
|
|
+ rc = zcrypt_rsa_crt(perms, &crt);
|
|
|
} while (rc == -EAGAIN);
|
|
|
if (rc) {
|
|
|
ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSACRT rc=%d\n", rc);
|
|
@@ -838,12 +1315,12 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|
|
if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB)))
|
|
|
return -EFAULT;
|
|
|
do {
|
|
|
- rc = zcrypt_send_cprb(&xcRB);
|
|
|
+ rc = _zcrypt_send_cprb(perms, &xcRB);
|
|
|
} while (rc == -EAGAIN);
|
|
|
/* on failure: retry once again after a requested rescan */
|
|
|
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
|
|
|
do {
|
|
|
- rc = zcrypt_send_cprb(&xcRB);
|
|
|
+ rc = _zcrypt_send_cprb(perms, &xcRB);
|
|
|
} while (rc == -EAGAIN);
|
|
|
if (rc)
|
|
|
ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDCPRB rc=%d\n", rc);
|
|
@@ -858,12 +1335,12 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|
|
if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb)))
|
|
|
return -EFAULT;
|
|
|
do {
|
|
|
- rc = zcrypt_send_ep11_cprb(&xcrb);
|
|
|
+ rc = zcrypt_send_ep11_cprb(perms, &xcrb);
|
|
|
} while (rc == -EAGAIN);
|
|
|
/* on failure: retry once again after a requested rescan */
|
|
|
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
|
|
|
do {
|
|
|
- rc = zcrypt_send_ep11_cprb(&xcrb);
|
|
|
+ rc = zcrypt_send_ep11_cprb(perms, &xcrb);
|
|
|
} while (rc == -EAGAIN);
|
|
|
if (rc)
|
|
|
ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDEP11CPRB rc=%d\n", rc);
|
|
@@ -989,8 +1466,8 @@ struct compat_ica_rsa_modexpo {
|
|
|
compat_uptr_t n_modulus;
|
|
|
};
|
|
|
|
|
|
-static long trans_modexpo32(struct file *filp, unsigned int cmd,
|
|
|
- unsigned long arg)
|
|
|
+static long trans_modexpo32(struct ap_perms *perms, struct file *filp,
|
|
|
+ unsigned int cmd, unsigned long arg)
|
|
|
{
|
|
|
struct compat_ica_rsa_modexpo __user *umex32 = compat_ptr(arg);
|
|
|
struct compat_ica_rsa_modexpo mex32;
|
|
@@ -1006,12 +1483,12 @@ static long trans_modexpo32(struct file *filp, unsigned int cmd,
|
|
|
mex64.b_key = compat_ptr(mex32.b_key);
|
|
|
mex64.n_modulus = compat_ptr(mex32.n_modulus);
|
|
|
do {
|
|
|
- rc = zcrypt_rsa_modexpo(&mex64);
|
|
|
+ rc = zcrypt_rsa_modexpo(perms, &mex64);
|
|
|
} while (rc == -EAGAIN);
|
|
|
/* on failure: retry once again after a requested rescan */
|
|
|
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
|
|
|
do {
|
|
|
- rc = zcrypt_rsa_modexpo(&mex64);
|
|
|
+ rc = zcrypt_rsa_modexpo(perms, &mex64);
|
|
|
} while (rc == -EAGAIN);
|
|
|
if (rc)
|
|
|
return rc;
|
|
@@ -1031,8 +1508,8 @@ struct compat_ica_rsa_modexpo_crt {
|
|
|
compat_uptr_t u_mult_inv;
|
|
|
};
|
|
|
|
|
|
-static long trans_modexpo_crt32(struct file *filp, unsigned int cmd,
|
|
|
- unsigned long arg)
|
|
|
+static long trans_modexpo_crt32(struct ap_perms *perms, struct file *filp,
|
|
|
+ unsigned int cmd, unsigned long arg)
|
|
|
{
|
|
|
struct compat_ica_rsa_modexpo_crt __user *ucrt32 = compat_ptr(arg);
|
|
|
struct compat_ica_rsa_modexpo_crt crt32;
|
|
@@ -1051,12 +1528,12 @@ static long trans_modexpo_crt32(struct file *filp, unsigned int cmd,
|
|
|
crt64.nq_prime = compat_ptr(crt32.nq_prime);
|
|
|
crt64.u_mult_inv = compat_ptr(crt32.u_mult_inv);
|
|
|
do {
|
|
|
- rc = zcrypt_rsa_crt(&crt64);
|
|
|
+ rc = zcrypt_rsa_crt(perms, &crt64);
|
|
|
} while (rc == -EAGAIN);
|
|
|
/* on failure: retry once again after a requested rescan */
|
|
|
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
|
|
|
do {
|
|
|
- rc = zcrypt_rsa_crt(&crt64);
|
|
|
+ rc = zcrypt_rsa_crt(perms, &crt64);
|
|
|
} while (rc == -EAGAIN);
|
|
|
if (rc)
|
|
|
return rc;
|
|
@@ -1084,8 +1561,8 @@ struct compat_ica_xcRB {
|
|
|
unsigned int status;
|
|
|
} __packed;
|
|
|
|
|
|
-static long trans_xcRB32(struct file *filp, unsigned int cmd,
|
|
|
- unsigned long arg)
|
|
|
+static long trans_xcRB32(struct ap_perms *perms, struct file *filp,
|
|
|
+ unsigned int cmd, unsigned long arg)
|
|
|
{
|
|
|
struct compat_ica_xcRB __user *uxcRB32 = compat_ptr(arg);
|
|
|
struct compat_ica_xcRB xcRB32;
|
|
@@ -1115,12 +1592,12 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd,
|
|
|
xcRB64.priority_window = xcRB32.priority_window;
|
|
|
xcRB64.status = xcRB32.status;
|
|
|
do {
|
|
|
- rc = zcrypt_send_cprb(&xcRB64);
|
|
|
+ rc = _zcrypt_send_cprb(perms, &xcRB64);
|
|
|
} while (rc == -EAGAIN);
|
|
|
/* on failure: retry once again after a requested rescan */
|
|
|
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
|
|
|
do {
|
|
|
- rc = zcrypt_send_cprb(&xcRB64);
|
|
|
+ rc = _zcrypt_send_cprb(perms, &xcRB64);
|
|
|
} while (rc == -EAGAIN);
|
|
|
xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length;
|
|
|
xcRB32.reply_data_length = xcRB64.reply_data_length;
|
|
@@ -1133,12 +1610,20 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd,
|
|
|
static long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
|
|
|
unsigned long arg)
|
|
|
{
|
|
|
+ int rc;
|
|
|
+ struct ap_perms *perms =
|
|
|
+ (struct ap_perms *) filp->private_data;
|
|
|
+
|
|
|
+ rc = zcrypt_check_ioctl(perms, cmd);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+
|
|
|
if (cmd == ICARSAMODEXPO)
|
|
|
- return trans_modexpo32(filp, cmd, arg);
|
|
|
+ return trans_modexpo32(perms, filp, cmd, arg);
|
|
|
if (cmd == ICARSACRT)
|
|
|
- return trans_modexpo_crt32(filp, cmd, arg);
|
|
|
+ return trans_modexpo_crt32(perms, filp, cmd, arg);
|
|
|
if (cmd == ZSECSENDCPRB)
|
|
|
- return trans_xcRB32(filp, cmd, arg);
|
|
|
+ return trans_xcRB32(perms, filp, cmd, arg);
|
|
|
return zcrypt_unlocked_ioctl(filp, cmd, arg);
|
|
|
}
|
|
|
#endif
|
|
@@ -1256,6 +1741,67 @@ void zcrypt_debug_exit(void)
|
|
|
debug_unregister(zcrypt_dbf_info);
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
|
|
|
+
|
|
|
+static int __init zcdn_init(void)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ /* create a new class 'zcrypt' */
|
|
|
+ zcrypt_class = class_create(THIS_MODULE, ZCRYPT_NAME);
|
|
|
+ if (IS_ERR(zcrypt_class)) {
|
|
|
+ rc = PTR_ERR(zcrypt_class);
|
|
|
+ goto out_class_create_failed;
|
|
|
+ }
|
|
|
+ zcrypt_class->dev_release = zcdn_device_release;
|
|
|
+
|
|
|
+ /* alloc device minor range */
|
|
|
+ rc = alloc_chrdev_region(&zcrypt_devt,
|
|
|
+ 0, ZCRYPT_MAX_MINOR_NODES,
|
|
|
+ ZCRYPT_NAME);
|
|
|
+ if (rc)
|
|
|
+ goto out_alloc_chrdev_failed;
|
|
|
+
|
|
|
+ cdev_init(&zcrypt_cdev, &zcrypt_fops);
|
|
|
+ zcrypt_cdev.owner = THIS_MODULE;
|
|
|
+ rc = cdev_add(&zcrypt_cdev, zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
|
|
|
+ if (rc)
|
|
|
+ goto out_cdev_add_failed;
|
|
|
+
|
|
|
+ /* need some class specific sysfs attributes */
|
|
|
+ rc = class_create_file(zcrypt_class, &class_attr_zcdn_create);
|
|
|
+ if (rc)
|
|
|
+ goto out_class_create_file_1_failed;
|
|
|
+ rc = class_create_file(zcrypt_class, &class_attr_zcdn_destroy);
|
|
|
+ if (rc)
|
|
|
+ goto out_class_create_file_2_failed;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+out_class_create_file_2_failed:
|
|
|
+ class_remove_file(zcrypt_class, &class_attr_zcdn_create);
|
|
|
+out_class_create_file_1_failed:
|
|
|
+ cdev_del(&zcrypt_cdev);
|
|
|
+out_cdev_add_failed:
|
|
|
+ unregister_chrdev_region(zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
|
|
|
+out_alloc_chrdev_failed:
|
|
|
+ class_destroy(zcrypt_class);
|
|
|
+out_class_create_failed:
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+static void zcdn_exit(void)
|
|
|
+{
|
|
|
+ class_remove_file(zcrypt_class, &class_attr_zcdn_create);
|
|
|
+ class_remove_file(zcrypt_class, &class_attr_zcdn_destroy);
|
|
|
+ zcdn_destroy_all();
|
|
|
+ cdev_del(&zcrypt_cdev);
|
|
|
+ unregister_chrdev_region(zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
|
|
|
+ class_destroy(zcrypt_class);
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
/**
|
|
|
* zcrypt_api_init(): Module initialization.
|
|
|
*
|
|
@@ -1269,15 +1815,27 @@ int __init zcrypt_api_init(void)
|
|
|
if (rc)
|
|
|
goto out;
|
|
|
|
|
|
+#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
|
|
|
+ rc = zcdn_init();
|
|
|
+ if (rc)
|
|
|
+ goto out;
|
|
|
+#endif
|
|
|
+
|
|
|
/* Register the request sprayer. */
|
|
|
rc = misc_register(&zcrypt_misc_device);
|
|
|
if (rc < 0)
|
|
|
- goto out;
|
|
|
+ goto out_misc_register_failed;
|
|
|
|
|
|
zcrypt_msgtype6_init();
|
|
|
zcrypt_msgtype50_init();
|
|
|
+
|
|
|
return 0;
|
|
|
|
|
|
+out_misc_register_failed:
|
|
|
+#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
|
|
|
+ zcdn_exit();
|
|
|
+#endif
|
|
|
+ zcrypt_debug_exit();
|
|
|
out:
|
|
|
return rc;
|
|
|
}
|
|
@@ -1289,6 +1847,9 @@ out:
|
|
|
*/
|
|
|
void __exit zcrypt_api_exit(void)
|
|
|
{
|
|
|
+#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
|
|
|
+ zcdn_exit();
|
|
|
+#endif
|
|
|
misc_deregister(&zcrypt_misc_device);
|
|
|
zcrypt_msgtype6_exit();
|
|
|
zcrypt_msgtype50_exit();
|