From 79539b14bebc86335a35a7260983ea5fc6bc8a70 Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Mon, 17 Feb 2020 22:28:21 -0800 Subject: [PATCH] crypto: msm: add compat_qcedev to support 32bit process add snapshot of compat_qcedev.c and compat_qcedev.h from msm-4.19 commit 52d84be6ae6e151ba ("crypto: msm: qcrypto: Fix null pointer dereference error in qcrypto driver") with changes to comply with msm-5.4 format requirement. Change-Id: Ib80bc4fdec58392246bfcec1b08620dcde0a6608 Signed-off-by: Zhen Kong --- drivers/crypto/msm/Makefile | 1 + drivers/crypto/msm/compat_qcedev.c | 531 +++++++++++++++++++++++++++++ drivers/crypto/msm/compat_qcedev.h | 202 +++++++++++ drivers/crypto/msm/qcedev.c | 8 +- 4 files changed, 739 insertions(+), 3 deletions(-) create mode 100644 drivers/crypto/msm/compat_qcedev.c create mode 100644 drivers/crypto/msm/compat_qcedev.h diff --git a/drivers/crypto/msm/Makefile b/drivers/crypto/msm/Makefile index a3fb58f3fcfb..34725428d4fb 100644 --- a/drivers/crypto/msm/Makefile +++ b/drivers/crypto/msm/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_CRYPTO_DEV_QCOM_MSM_QCE) += qce50.o obj-$(CONFIG_CRYPTO_DEV_QCEDEV) += qcedev-mod.o qcedev-mod-y = qcedev.o qcedev_smmu.o +qcedev-mod-$(CONFIG_COMPAT) += compat_qcedev.o obj-$(CONFIG_CRYPTO_DEV_QCRYPTO) += qcrypto-msm.o qcrypto-msm-y = qcrypto.o diff --git a/drivers/crypto/msm/compat_qcedev.c b/drivers/crypto/msm/compat_qcedev.c new file mode 100644 index 000000000000..c0ae9e3460d2 --- /dev/null +++ b/drivers/crypto/msm/compat_qcedev.c @@ -0,0 +1,531 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * QTI CE 32-bit compatibility syscall for 64-bit systems + * + * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "compat_qcedev.h" + +static int compat_get_qcedev_pmem_info( + struct compat_qcedev_pmem_info __user *pmem32, + struct qcedev_pmem_info __user *pmem) +{ + compat_ulong_t offset; + compat_int_t fd_src; + compat_int_t fd_dst; + int err, i; + uint32_t len; + + err = get_user(fd_src, &pmem32->fd_src); + err |= put_user(fd_src, &pmem->fd_src); + + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + err |= get_user(offset, &pmem32->src[i].offset); + err |= put_user(offset, &pmem->src[i].offset); + err |= get_user(len, &pmem32->src[i].len); + err |= put_user(len, &pmem->src[i].len); + } + + err |= get_user(fd_dst, &pmem32->fd_dst); + err |= put_user(fd_dst, &pmem->fd_dst); + + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + err |= get_user(offset, &pmem32->dst[i].offset); + err |= put_user(offset, &pmem->dst[i].offset); + err |= get_user(len, &pmem32->dst[i].len); + err |= put_user(len, &pmem->dst[i].len); + } + + return err; +} + +static int compat_put_qcedev_pmem_info( + struct compat_qcedev_pmem_info __user *pmem32, + struct qcedev_pmem_info __user *pmem) +{ + compat_ulong_t offset; + compat_int_t fd_src; + compat_int_t fd_dst; + int err, i; + uint32_t len; + + err = get_user(fd_src, &pmem->fd_src); + err |= put_user(fd_src, &pmem32->fd_src); + + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + err |= get_user(offset, &pmem->src[i].offset); + err |= put_user(offset, &pmem32->src[i].offset); + err |= get_user(len, &pmem->src[i].len); + err |= put_user(len, &pmem32->src[i].len); + } + + err |= get_user(fd_dst, &pmem->fd_dst); + err |= put_user(fd_dst, &pmem32->fd_dst); + + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + err |= get_user(offset, &pmem->dst[i].offset); + err |= put_user(offset, &pmem32->dst[i].offset); + err |= get_user(len, &pmem->dst[i].len); + err |= put_user(len, &pmem32->dst[i].len); + } + + return err; +} + +static int compat_get_qcedev_vbuf_info( + struct compat_qcedev_vbuf_info __user *vbuf32, + struct qcedev_vbuf_info __user *vbuf) +{ + compat_uptr_t vaddr; + int err = 0, i; + uint32_t len; + + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + err |= get_user(vaddr, &vbuf32->src[i].vaddr); + err |= put_user(vaddr, + (compat_uptr_t __user *)&vbuf->src[i].vaddr); + err |= get_user(len, &vbuf32->src[i].len); + err |= put_user(len, &vbuf->src[i].len); + } + + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + err |= get_user(vaddr, &vbuf32->dst[i].vaddr); + err |= put_user(vaddr, + (compat_uptr_t __user *)&vbuf->dst[i].vaddr); + err |= get_user(len, &vbuf32->dst[i].len); + err |= put_user(len, &vbuf->dst[i].len); + } + return err; +} + +static int compat_put_qcedev_vbuf_info( + struct compat_qcedev_vbuf_info __user *vbuf32, + struct qcedev_vbuf_info __user *vbuf) +{ + compat_uptr_t vaddr; + int err = 0, i; + uint32_t len; + + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + err |= get_user(vaddr, + (compat_uptr_t __user *)&vbuf->src[i].vaddr); + err |= put_user(vaddr, &vbuf32->src[i].vaddr); + err |= get_user(len, &vbuf->src[i].len); + err |= put_user(len, &vbuf32->src[i].len); + } + + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + err |= get_user(vaddr, + (compat_uptr_t __user *)&vbuf->dst[i].vaddr); + err |= put_user(vaddr, &vbuf32->dst[i].vaddr); + err |= get_user(len, &vbuf->dst[i].len); + err |= put_user(len, &vbuf32->dst[i].len); + } + return err; +} + +static int compat_get_qcedev_cipher_op_req( + struct compat_qcedev_cipher_op_req __user *data32, + struct qcedev_cipher_op_req __user *data) +{ + enum qcedev_cipher_mode_enum mode; + enum qcedev_cipher_alg_enum alg; + compat_ulong_t byteoffset; + enum qcedev_oper_enum op; + compat_ulong_t data_len; + compat_ulong_t encklen; + compat_ulong_t entries; + compat_ulong_t ivlen; + uint8_t in_place_op; + int err, i; + uint8_t use_pmem; + uint8_t enckey; + uint8_t iv; + + err = get_user(use_pmem, &data32->use_pmem); + err |= put_user(use_pmem, &data->use_pmem); + + if (use_pmem) + err |= compat_get_qcedev_pmem_info(&data32->pmem, &data->pmem); + else + err |= compat_get_qcedev_vbuf_info(&data32->vbuf, &data->vbuf); + + err |= get_user(entries, &data32->entries); + err |= put_user(entries, &data->entries); + err |= get_user(data_len, &data32->data_len); + err |= put_user(data_len, &data->data_len); + err |= get_user(in_place_op, &data32->in_place_op); + err |= put_user(in_place_op, &data->in_place_op); + + for (i = 0; i < QCEDEV_MAX_KEY_SIZE; i++) { + err |= get_user(enckey, &(data32->enckey[i])); + err |= put_user(enckey, &(data->enckey[i])); + } + + err |= get_user(encklen, &data32->encklen); + err |= put_user(encklen, &data->encklen); + + for (i = 0; i < QCEDEV_MAX_IV_SIZE; i++) { + err |= get_user(iv, &(data32->iv[i])); + err |= put_user(iv, &(data->iv[i])); + } + + err |= get_user(ivlen, &data32->ivlen); + err |= put_user(ivlen, &data->ivlen); + err |= get_user(byteoffset, &data32->byteoffset); + err |= put_user(byteoffset, &data->byteoffset); + err |= get_user(alg, &data32->alg); + err |= put_user(alg, &data->alg); + err |= get_user(mode, &data32->mode); + err |= put_user(mode, &data->mode); + err |= get_user(op, &data32->op); + err |= put_user(op, &data->op); + + return err; +} + +static int compat_put_qcedev_cipher_op_req( + struct compat_qcedev_cipher_op_req __user *data32, + struct qcedev_cipher_op_req __user *data) +{ + enum qcedev_cipher_mode_enum mode; + enum qcedev_cipher_alg_enum alg; + compat_ulong_t byteoffset; + enum qcedev_oper_enum op; + compat_ulong_t data_len; + compat_ulong_t encklen; + compat_ulong_t entries; + compat_ulong_t ivlen; + uint8_t in_place_op; + int err, i; + uint8_t use_pmem; + uint8_t enckey; + uint8_t iv; + + err = get_user(use_pmem, &data->use_pmem); + err |= put_user(use_pmem, &data32->use_pmem); + + if (use_pmem) + err |= compat_put_qcedev_pmem_info(&data32->pmem, &data->pmem); + else + err |= compat_put_qcedev_vbuf_info(&data32->vbuf, &data->vbuf); + + err |= get_user(entries, &data->entries); + err |= put_user(entries, &data32->entries); + err |= get_user(data_len, &data->data_len); + err |= put_user(data_len, &data32->data_len); + err |= get_user(in_place_op, &data->in_place_op); + err |= put_user(in_place_op, &data32->in_place_op); + + for (i = 0; i < QCEDEV_MAX_KEY_SIZE; i++) { + err |= get_user(enckey, &(data->enckey[i])); + err |= put_user(enckey, &(data32->enckey[i])); + } + + err |= get_user(encklen, &data->encklen); + err |= put_user(encklen, &data32->encklen); + + for (i = 0; i < QCEDEV_MAX_IV_SIZE; i++) { + err |= get_user(iv, &(data->iv[i])); + err |= put_user(iv, &(data32->iv[i])); + } + + err |= get_user(ivlen, &data->ivlen); + err |= put_user(ivlen, &data32->ivlen); + err |= get_user(byteoffset, &data->byteoffset); + err |= put_user(byteoffset, &data32->byteoffset); + err |= get_user(alg, &data->alg); + err |= put_user(alg, &data32->alg); + err |= get_user(mode, &data->mode); + err |= put_user(mode, &data32->mode); + err |= get_user(op, &data->op); + err |= put_user(op, &data32->op); + + return err; +} + +static int compat_xfer_qcedev_map_buf_req( + struct compat_qcedev_map_buf_req __user *data32, + struct qcedev_map_buf_req __user *data, bool to_get) +{ + int rc = 0, i, fd = -1; + uint32_t fd_size, fd_offset, num_fds, buf_vaddr; + + if (to_get) { + /* copy from compat struct */ + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + rc |= get_user(fd, &data32->fd[i]); + rc |= put_user(fd, &data->fd[i]); + rc |= get_user(fd_size, &data32->fd_size[i]); + rc |= put_user(fd_size, &data->fd_size[i]); + rc |= get_user(fd_offset, &data32->fd_offset[i]); + rc |= put_user(fd_offset, &data->fd_offset[i]); + rc |= get_user(buf_vaddr, &data32->buf_vaddr[i]); + rc |= put_user(buf_vaddr, &data->buf_vaddr[i]); + } + + rc |= get_user(num_fds, &data32->num_fds); + rc |= put_user(num_fds, &data->num_fds); + } else { + /* copy to compat struct */ + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + rc |= get_user(fd, &data->fd[i]); + rc |= put_user(fd, &data32->fd[i]); + rc |= get_user(fd_size, &data->fd_size[i]); + rc |= put_user(fd_size, &data32->fd_size[i]); + rc |= get_user(fd_offset, &data->fd_offset[i]); + rc |= put_user(fd_offset, &data32->fd_offset[i]); + rc |= get_user(buf_vaddr, &data->buf_vaddr[i]); + rc |= put_user(buf_vaddr, &data32->buf_vaddr[i]); + } + rc |= get_user(num_fds, &data->num_fds); + rc |= put_user(num_fds, &data32->num_fds); + } + + return rc; +} + +static int compat_xfer_qcedev_unmap_buf_req( + struct compat_qcedev_unmap_buf_req __user *data32, + struct qcedev_unmap_buf_req __user *data, bool to_get) +{ + int i, rc = 0, fd = -1; + uint32_t num_fds; + + if (to_get) { + /* copy from compat struct */ + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + rc |= get_user(fd, &data32->fd[i]); + rc |= put_user(fd, &data->fd[i]); + } + rc |= get_user(num_fds, &data32->num_fds); + rc |= put_user(num_fds, &data->num_fds); + } else { + /* copy to compat struct */ + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + rc |= get_user(fd, &data->fd[i]); + rc |= put_user(fd, &data32->fd[i]); + } + rc |= get_user(num_fds, &data->num_fds); + rc |= put_user(num_fds, &data32->num_fds); + } + return rc; +} + + +static int compat_get_qcedev_sha_op_req( + struct compat_qcedev_sha_op_req __user *data32, + struct qcedev_sha_op_req __user *data) +{ + enum qcedev_sha_alg_enum alg; + compat_ulong_t authklen; + compat_ulong_t data_len; + compat_ulong_t entries; + compat_ulong_t diglen; + compat_uptr_t authkey; + compat_uptr_t vaddr; + int err = 0, i; + uint8_t digest; + uint32_t len; + + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + err |= get_user(vaddr, &data32->data[i].vaddr); + err |= put_user(vaddr, + (compat_uptr_t __user *)&data->data[i].vaddr); + err |= get_user(len, &data32->data[i].len); + err |= put_user(len, &data->data[i].len); + } + + err |= get_user(entries, &data32->entries); + err |= put_user(entries, &data->entries); + err |= get_user(data_len, &data32->data_len); + err |= put_user(data_len, &data->data_len); + + for (i = 0; i < QCEDEV_MAX_SHA_DIGEST; i++) { + err |= get_user(digest, &(data32->digest[i])); + err |= put_user(digest, &(data->digest[i])); + } + + err |= get_user(diglen, &data32->diglen); + err |= put_user(diglen, &data->diglen); + err |= get_user(authkey, &data32->authkey); + err |= put_user(authkey, (compat_uptr_t __user *)&data->authkey); + err |= get_user(authklen, &data32->authklen); + err |= put_user(authklen, &data->authklen); + err |= get_user(alg, &data32->alg); + err |= put_user(alg, &data->alg); + + return err; +} + +static int compat_put_qcedev_sha_op_req( + struct compat_qcedev_sha_op_req __user *data32, + struct qcedev_sha_op_req __user *data) +{ + enum qcedev_sha_alg_enum alg; + compat_ulong_t authklen; + compat_ulong_t data_len; + compat_ulong_t entries; + compat_ulong_t diglen; + compat_uptr_t authkey; + compat_uptr_t vaddr; + int err = 0, i; + uint8_t digest; + uint32_t len; + + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + err |= get_user(vaddr, + (compat_uptr_t __user *)&data->data[i].vaddr); + err |= put_user(vaddr, &data32->data[i].vaddr); + err |= get_user(len, &data->data[i].len); + err |= put_user(len, &data32->data[i].len); + } + + err |= get_user(entries, &data->entries); + err |= put_user(entries, &data32->entries); + err |= get_user(data_len, &data->data_len); + err |= put_user(data_len, &data32->data_len); + + for (i = 0; i < QCEDEV_MAX_SHA_DIGEST; i++) { + err |= get_user(digest, &(data->digest[i])); + err |= put_user(digest, &(data32->digest[i])); + } + + err |= get_user(diglen, &data->diglen); + err |= put_user(diglen, &data32->diglen); + err |= get_user(authkey, + (compat_uptr_t __user *)&data->authkey); + err |= put_user(authkey, &data32->authkey); + err |= get_user(authklen, &data->authklen); + err |= put_user(authklen, &data32->authklen); + err |= get_user(alg, &data->alg); + err |= put_user(alg, &data32->alg); + + return err; +} + +static unsigned int convert_cmd(unsigned int cmd) +{ + switch (cmd) { + case COMPAT_QCEDEV_IOCTL_ENC_REQ: + return QCEDEV_IOCTL_ENC_REQ; + case COMPAT_QCEDEV_IOCTL_DEC_REQ: + return QCEDEV_IOCTL_DEC_REQ; + case COMPAT_QCEDEV_IOCTL_SHA_INIT_REQ: + return QCEDEV_IOCTL_SHA_INIT_REQ; + case COMPAT_QCEDEV_IOCTL_SHA_UPDATE_REQ: + return QCEDEV_IOCTL_SHA_UPDATE_REQ; + case COMPAT_QCEDEV_IOCTL_SHA_FINAL_REQ: + return QCEDEV_IOCTL_SHA_FINAL_REQ; + case COMPAT_QCEDEV_IOCTL_GET_SHA_REQ: + return QCEDEV_IOCTL_GET_SHA_REQ; + case COMPAT_QCEDEV_IOCTL_GET_CMAC_REQ: + return QCEDEV_IOCTL_GET_CMAC_REQ; + case COMPAT_QCEDEV_IOCTL_MAP_BUF_REQ: + return QCEDEV_IOCTL_MAP_BUF_REQ; + case COMPAT_QCEDEV_IOCTL_UNMAP_BUF_REQ: + return QCEDEV_IOCTL_UNMAP_BUF_REQ; + default: + return cmd; + } + +} + +long compat_qcedev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long ret; + + switch (cmd) { + case COMPAT_QCEDEV_IOCTL_ENC_REQ: + case COMPAT_QCEDEV_IOCTL_DEC_REQ: { + struct compat_qcedev_cipher_op_req __user *data32; + struct qcedev_cipher_op_req __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (!data) + return -EFAULT; + + err = compat_get_qcedev_cipher_op_req(data32, data); + if (err) + return err; + + ret = qcedev_ioctl(file, convert_cmd(cmd), (unsigned long)data); + err = compat_put_qcedev_cipher_op_req(data32, data); + return ret ? ret : err; + } + case COMPAT_QCEDEV_IOCTL_SHA_INIT_REQ: + case COMPAT_QCEDEV_IOCTL_SHA_UPDATE_REQ: + case COMPAT_QCEDEV_IOCTL_SHA_FINAL_REQ: + case COMPAT_QCEDEV_IOCTL_GET_CMAC_REQ: + case COMPAT_QCEDEV_IOCTL_GET_SHA_REQ: { + struct compat_qcedev_sha_op_req __user *data32; + struct qcedev_sha_op_req __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (!data) + return -EFAULT; + + err = compat_get_qcedev_sha_op_req(data32, data); + if (err) + return err; + + ret = qcedev_ioctl(file, convert_cmd(cmd), (unsigned long)data); + err = compat_put_qcedev_sha_op_req(data32, data); + return ret ? ret : err; + } + case COMPAT_QCEDEV_IOCTL_MAP_BUF_REQ: { + struct compat_qcedev_map_buf_req __user *data32; + struct qcedev_map_buf_req __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (!data) + return -EINVAL; + + err = compat_xfer_qcedev_map_buf_req(data32, data, true); + if (err) + return err; + + ret = qcedev_ioctl(file, convert_cmd(cmd), (unsigned long)data); + err = compat_xfer_qcedev_map_buf_req(data32, data, false); + return ret ? ret : err; + + break; + } + case COMPAT_QCEDEV_IOCTL_UNMAP_BUF_REQ: { + struct compat_qcedev_unmap_buf_req __user *data32; + struct qcedev_unmap_buf_req __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (!data) + return -EINVAL; + + err = compat_xfer_qcedev_unmap_buf_req(data32, data, true); + if (err) + return err; + + ret = qcedev_ioctl(file, convert_cmd(cmd), (unsigned long)data); + err = compat_xfer_qcedev_unmap_buf_req(data32, data, false); + return ret ? ret : err; + + break; + } + default: + return -ENOIOCTLCMD; + } + return 0; +} diff --git a/drivers/crypto/msm/compat_qcedev.h b/drivers/crypto/msm/compat_qcedev.h new file mode 100644 index 000000000000..9d1cab8e3991 --- /dev/null +++ b/drivers/crypto/msm/compat_qcedev.h @@ -0,0 +1,202 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2014,2017-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _UAPI_COMPAT_QCEDEV__H +#define _UAPI_COMPAT_QCEDEV__H + +#include +#include + +#if IS_ENABLED(CONFIG_COMPAT) +#include + +/** + * struct compat_buf_info - Buffer information + * @offset: Offset from the base address of the buffer + * (Used when buffer is allocated using PMEM) + * @vaddr: Virtual buffer address pointer + * @len: Size of the buffer + */ +struct compat_buf_info { + union { + compat_ulong_t offset; + compat_uptr_t vaddr; + }; + compat_ulong_t len; +}; + +/** + * struct compat_qcedev_vbuf_info - Source and destination Buffer information + * @src: Array of buf_info for input/source + * @dst: Array of buf_info for output/destination + */ +struct compat_qcedev_vbuf_info { + struct compat_buf_info src[QCEDEV_MAX_BUFFERS]; + struct compat_buf_info dst[QCEDEV_MAX_BUFFERS]; +}; + +/** + * struct compat_qcedev_pmem_info - Stores PMEM buffer information + * @fd_src: Handle to /dev/adsp_pmem used to allocate + * memory for input/src buffer + * @src: Array of buf_info for input/source + * @fd_dst: Handle to /dev/adsp_pmem used to allocate + * memory for output/dst buffer + * @dst: Array of buf_info for output/destination + * @pmem_src_offset: The offset from input/src buffer + * (allocated by PMEM) + */ +struct compat_qcedev_pmem_info { + compat_int_t fd_src; + struct compat_buf_info src[QCEDEV_MAX_BUFFERS]; + compat_int_t fd_dst; + struct compat_buf_info dst[QCEDEV_MAX_BUFFERS]; +}; + +/** + * struct compat_qcedev_cipher_op_req - Holds the ciphering request information + * @use_pmem (IN): Flag to indicate if buffer source is PMEM + * QCEDEV_USE_PMEM/QCEDEV_NO_PMEM + * @pmem (IN): Stores PMEM buffer information. + * Refer struct qcedev_pmem_info + * @vbuf (IN/OUT): Stores Source and destination Buffer information + * Refer to struct qcedev_vbuf_info + * @data_len (IN): Total Length of input/src and output/dst in bytes + * @in_place_op (IN): Indicates whether the operation is inplace where + * source == destination + * When using PMEM allocated memory, must set this to 1 + * @enckey (IN): 128 bits of confidentiality key + * enckey[0] bit 127-120, enckey[1] bit 119-112,.. + * enckey[15] bit 7-0 + * @encklen (IN): Length of the encryption key(set to 128 bits/16 + * bytes in the driver) + * @iv (IN/OUT): Initialization vector data + * This is updated by the driver, incremented by + * number of blocks encrypted/decrypted. + * @ivlen (IN): Length of the IV + * @byteoffset (IN): Offset in the Cipher BLOCK (applicable and to be set + * for AES-128 CTR mode only) + * @alg (IN): Type of ciphering algorithm: AES/DES/3DES + * @mode (IN): Mode use when using AES algorithm: ECB/CBC/CTR + * Applicable when using AES algorithm only + * @op (IN): Type of operation: QCEDEV_OPER_DEC/QCEDEV_OPER_ENC or + * QCEDEV_OPER_ENC_NO_KEY/QCEDEV_OPER_DEC_NO_KEY + * + * If use_pmem is set to 0, the driver assumes that memory was not allocated + * via PMEM, and kernel will need to allocate memory and copy data from user + * space buffer (data_src/dta_dst) and process accordingly and copy data back + * to the user space buffer + * + * If use_pmem is set to 1, the driver assumes that memory was allocated via + * PMEM. + * The kernel driver will use the fd_src to determine the kernel virtual address + * base that maps to the user space virtual address base for the buffer + * allocated in user space. + * The final input/src and output/dst buffer pointer will be determined + * by adding the offsets to the kernel virtual addr. + * + * If use of hardware key is supported in the target, user can configure the + * key parameters (encklen, enckey) to use the hardware key. + * In order to use the hardware key, set encklen to 0 and set the enckey + * data array to 0. + */ +struct compat_qcedev_cipher_op_req { + uint8_t use_pmem; + union { + struct compat_qcedev_pmem_info pmem; + struct compat_qcedev_vbuf_info vbuf; + }; + compat_ulong_t entries; + compat_ulong_t data_len; + uint8_t in_place_op; + uint8_t enckey[QCEDEV_MAX_KEY_SIZE]; + compat_ulong_t encklen; + uint8_t iv[QCEDEV_MAX_IV_SIZE]; + compat_ulong_t ivlen; + compat_ulong_t byteoffset; + enum qcedev_cipher_alg_enum alg; + enum qcedev_cipher_mode_enum mode; + enum qcedev_oper_enum op; +}; + +/** + * struct qcedev_sha_op_req - Holds the hashing request information + * @data (IN): Array of pointers to the data to be hashed + * @entries (IN): Number of buf_info entries in the data array + * @data_len (IN): Length of data to be hashed + * @digest (IN/OUT): Returns the hashed data information + * @diglen (OUT): Size of the hashed/digest data + * @authkey (IN): Pointer to authentication key for HMAC + * @authklen (IN): Size of the authentication key + * @alg (IN): Secure Hash algorithm + */ +struct compat_qcedev_sha_op_req { + struct compat_buf_info data[QCEDEV_MAX_BUFFERS]; + compat_ulong_t entries; + compat_ulong_t data_len; + uint8_t digest[QCEDEV_MAX_SHA_DIGEST]; + compat_ulong_t diglen; + compat_uptr_t authkey; + compat_ulong_t authklen; + enum qcedev_sha_alg_enum alg; +}; + +/** + * struct compact_qcedev_map_buf_req - Holds the mapping request information + * fd (IN): Array of fds. + * num_fds (IN): Number of fds in fd[]. + * fd_size (IN): Array of sizes corresponding to each fd in fd[]. + * fd_offset (IN): Array of offset corresponding to each fd in fd[]. + * vaddr (OUT): Array of mapped virtual address corresponding to + * each fd in fd[]. + */ +struct compat_qcedev_map_buf_req { + compat_long_t fd[QCEDEV_MAX_BUFFERS]; + compat_ulong_t num_fds; + compat_ulong_t fd_size[QCEDEV_MAX_BUFFERS]; + compat_ulong_t fd_offset[QCEDEV_MAX_BUFFERS]; + compat_u64 buf_vaddr[QCEDEV_MAX_BUFFERS]; +}; + +/** + * struct compat_qcedev_unmap_buf_req - Holds the hashing request information + * fd (IN): Array of fds to unmap + * num_fds (IN): Number of fds in fd[]. + */ +struct compat_qcedev_unmap_buf_req { + compat_long_t fd[QCEDEV_MAX_BUFFERS]; + compat_ulong_t num_fds; +}; + +struct file; +long qcedev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); +long compat_qcedev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); + +#define COMPAT_QCEDEV_IOCTL_ENC_REQ \ + _IOWR(QCEDEV_IOC_MAGIC, 1, struct compat_qcedev_cipher_op_req) +#define COMPAT_QCEDEV_IOCTL_DEC_REQ \ + _IOWR(QCEDEV_IOC_MAGIC, 2, struct compat_qcedev_cipher_op_req) +#define COMPAT_QCEDEV_IOCTL_SHA_INIT_REQ \ + _IOWR(QCEDEV_IOC_MAGIC, 3, struct compat_qcedev_sha_op_req) +#define COMPAT_QCEDEV_IOCTL_SHA_UPDATE_REQ \ + _IOWR(QCEDEV_IOC_MAGIC, 4, struct compat_qcedev_sha_op_req) +#define COMPAT_QCEDEV_IOCTL_SHA_FINAL_REQ \ + _IOWR(QCEDEV_IOC_MAGIC, 5, struct compat_qcedev_sha_op_req) +#define COMPAT_QCEDEV_IOCTL_GET_SHA_REQ \ + _IOWR(QCEDEV_IOC_MAGIC, 6, struct compat_qcedev_sha_op_req) +#define COMPAT_QCEDEV_IOCTL_LOCK_CE \ + _IO(QCEDEV_IOC_MAGIC, 7) +#define COMPAT_QCEDEV_IOCTL_UNLOCK_CE \ + _IO(QCEDEV_IOC_MAGIC, 8) +#define COMPAT_QCEDEV_IOCTL_GET_CMAC_REQ \ + _IOWR(QCEDEV_IOC_MAGIC, 9, struct compat_qcedev_sha_op_req) +#define COMPAT_QCEDEV_IOCTL_MAP_BUF_REQ \ + _IOWR(QCEDEV_IOC_MAGIC, 10, struct compat_qcedev_map_buf_req) +#define COMPAT_QCEDEV_IOCTL_UNMAP_BUF_REQ \ + _IOWR(QCEDEV_IOC_MAGIC, 11, struct compat_qcedev_unmap_buf_req) +#endif /* CONFIG_COMPAT */ +#endif /* _UAPI_COMPAT_QCEDEV__H */ diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index 4b0cd0d6023f..ad41874173e4 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -30,6 +30,7 @@ #include "qcedevi.h" #include "qce.h" #include "qcedev_smmu.h" +#include "compat_qcedev.h" #include @@ -185,12 +186,13 @@ static int qcedev_open(struct inode *inode, struct file *file); static int qcedev_release(struct inode *inode, struct file *file); static int start_cipher_req(struct qcedev_control *podev); static int start_sha_req(struct qcedev_control *podev); -static inline long qcedev_ioctl(struct file *file, - unsigned int cmd, unsigned long arg); static const struct file_operations qcedev_fops = { .owner = THIS_MODULE, .unlocked_ioctl = qcedev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = compat_qcedev_ioctl, +#endif .open = qcedev_open, .release = qcedev_release, }; @@ -1664,7 +1666,7 @@ sha_error: return -EINVAL; } -static inline long qcedev_ioctl(struct file *file, +long qcedev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int err = 0;