msm: crypto: fix issues on digest buf and copy_from_user in qcedev.c

Make the digest length not larger than the size of the buffer
qcedev_areq.sha_op_req.digest; and use the checked variants of
the copy_from/to_user() APIs to avoid small race window of their
unchecked variants.

Change-Id: I3db0c20ac5fa47ed278f3d60368c406f472430c1
Signed-off-by: Zhen Kong <zkong@codeaurora.org>
This commit is contained in:
Zhen Kong 2016-10-31 15:23:19 -07:00 committed by Mallikarjuna Reddy Amireddy
parent 5659dd095d
commit 58d4f78866
1 changed files with 29 additions and 102 deletions

View File

@ -630,7 +630,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq,
while (len > 0) {
user_src =
(void __user *)qcedev_areq->sha_op_req.data[i].vaddr;
if (user_src && __copy_from_user(k_src,
if (user_src && copy_from_user(k_src,
(void __user *)user_src,
qcedev_areq->sha_op_req.data[i].len))
return -EFAULT;
@ -666,7 +666,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq,
/* Copy data from user src(s) */
user_src = (void __user *)qcedev_areq->sha_op_req.data[0].vaddr;
if (user_src && __copy_from_user(k_src,
if (user_src && copy_from_user(k_src,
(void __user *)user_src,
qcedev_areq->sha_op_req.data[0].len)) {
kzfree(k_buf_src);
@ -675,7 +675,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq,
k_src += qcedev_areq->sha_op_req.data[0].len;
for (i = 1; i < qcedev_areq->sha_op_req.entries; i++) {
user_src = (void __user *)qcedev_areq->sha_op_req.data[i].vaddr;
if (user_src && __copy_from_user(k_src,
if (user_src && copy_from_user(k_src,
(void __user *)user_src,
qcedev_areq->sha_op_req.data[i].len)) {
kzfree(k_buf_src);
@ -729,13 +729,6 @@ static int qcedev_sha_update(struct qcedev_async_req *qcedev_areq,
return -EINVAL;
}
/* verify address src(s) */
for (i = 0; i < qcedev_areq->sha_op_req.entries; i++)
if (!access_ok(VERIFY_READ,
(void __user *)qcedev_areq->sha_op_req.data[i].vaddr,
qcedev_areq->sha_op_req.data[i].len))
return -EFAULT;
if (qcedev_areq->sha_op_req.data_len > QCE_MAX_OPER_DATA) {
struct qcedev_sha_op_req *saved_req;
@ -895,19 +888,7 @@ static int qcedev_hash_cmac(struct qcedev_async_req *qcedev_areq,
total = qcedev_areq->sha_op_req.data_len;
/* verify address src(s) */
for (i = 0; i < qcedev_areq->sha_op_req.entries; i++)
if (!access_ok(VERIFY_READ,
(void __user *)qcedev_areq->sha_op_req.data[i].vaddr,
qcedev_areq->sha_op_req.data[i].len))
return -EFAULT;
/* Verify Source Address */
if (!access_ok(VERIFY_READ,
(void __user *)qcedev_areq->sha_op_req.authkey,
qcedev_areq->sha_op_req.authklen))
return -EFAULT;
if (__copy_from_user(&handle->sha_ctxt.authkey[0],
if (copy_from_user(&handle->sha_ctxt.authkey[0],
(void __user *)qcedev_areq->sha_op_req.authkey,
qcedev_areq->sha_op_req.authklen))
return -EFAULT;
@ -927,7 +908,7 @@ static int qcedev_hash_cmac(struct qcedev_async_req *qcedev_areq,
for (i = 0; i < qcedev_areq->sha_op_req.entries; i++) {
user_src =
(void __user *)qcedev_areq->sha_op_req.data[i].vaddr;
if (user_src && __copy_from_user(k_src, (void __user *)user_src,
if (user_src && copy_from_user(k_src, (void __user *)user_src,
qcedev_areq->sha_op_req.data[i].len)) {
kzfree(k_buf_src);
return -EFAULT;
@ -955,12 +936,7 @@ static int qcedev_set_hmac_auth_key(struct qcedev_async_req *areq,
if (areq->sha_op_req.authklen <= QCEDEV_MAX_KEY_SIZE) {
qcedev_sha_init(areq, handle);
/* Verify Source Address */
if (!access_ok(VERIFY_READ,
(void __user *)areq->sha_op_req.authkey,
areq->sha_op_req.authklen))
return -EFAULT;
if (__copy_from_user(&handle->sha_ctxt.authkey[0],
if (copy_from_user(&handle->sha_ctxt.authkey[0],
(void __user *)areq->sha_op_req.authkey,
areq->sha_op_req.authklen))
return -EFAULT;
@ -1173,7 +1149,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
byteoffset = areq->cipher_op_req.byteoffset;
user_src = (void __user *)areq->cipher_op_req.vbuf.src[0].vaddr;
if (user_src && __copy_from_user((k_align_src + byteoffset),
if (user_src && copy_from_user((k_align_src + byteoffset),
(void __user *)user_src,
areq->cipher_op_req.vbuf.src[0].len))
return -EFAULT;
@ -1183,7 +1159,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
for (i = 1; i < areq->cipher_op_req.entries; i++) {
user_src =
(void __user *)areq->cipher_op_req.vbuf.src[i].vaddr;
if (user_src && __copy_from_user(k_align_src,
if (user_src && copy_from_user(k_align_src,
(void __user *)user_src,
areq->cipher_op_req.vbuf.src[i].len)) {
return -EFAULT;
@ -1215,7 +1191,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
while (creq->data_len > 0) {
if (creq->vbuf.dst[dst_i].len <= creq->data_len) {
if (err == 0 && __copy_to_user(
if (err == 0 && copy_to_user(
(void __user *)creq->vbuf.dst[dst_i].vaddr,
(k_align_dst + byteoffset),
creq->vbuf.dst[dst_i].len))
@ -1226,7 +1202,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
creq->data_len -= creq->vbuf.dst[dst_i].len;
dst_i++;
} else {
if (err == 0 && __copy_to_user(
if (err == 0 && copy_to_user(
(void __user *)creq->vbuf.dst[dst_i].vaddr,
(k_align_dst + byteoffset),
creq->data_len))
@ -1558,36 +1534,6 @@ static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req,
__func__, total, req->data_len);
goto error;
}
/* Verify Source Address's */
for (i = 0, total = 0; i < req->entries; i++) {
if (total < req->data_len) {
if (!access_ok(VERIFY_READ,
(void __user *)req->vbuf.src[i].vaddr,
req->vbuf.src[i].len)) {
pr_err("%s:SRC RD_VERIFY err %d=0x%lx\n",
__func__, i, (uintptr_t)
req->vbuf.src[i].vaddr);
goto error;
}
total += req->vbuf.src[i].len;
}
}
/* Verify Destination Address's */
for (i = 0, total = 0; i < QCEDEV_MAX_BUFFERS; i++) {
if ((req->vbuf.dst[i].vaddr != 0) &&
(total < req->data_len)) {
if (!access_ok(VERIFY_WRITE,
(void __user *)req->vbuf.dst[i].vaddr,
req->vbuf.dst[i].len)) {
pr_err("%s:DST WR_VERIFY err %d=0x%lx\n",
__func__, i, (uintptr_t)
req->vbuf.dst[i].vaddr);
goto error;
}
total += req->vbuf.dst[i].len;
}
}
return 0;
error:
return -EINVAL;
@ -1683,11 +1629,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
switch (cmd) {
case QCEDEV_IOCTL_ENC_REQ:
case QCEDEV_IOCTL_DEC_REQ:
if (!access_ok(VERIFY_WRITE, (void __user *)arg,
sizeof(struct qcedev_cipher_op_req)))
return -EFAULT;
if (__copy_from_user(&qcedev_areq.cipher_op_req,
if (copy_from_user(&qcedev_areq.cipher_op_req,
(void __user *)arg,
sizeof(struct qcedev_cipher_op_req)))
return -EFAULT;
@ -1700,20 +1642,17 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
err = qcedev_vbuf_ablk_cipher(&qcedev_areq, handle);
if (err)
return err;
if (__copy_to_user((void __user *)arg,
if (copy_to_user((void __user *)arg,
&qcedev_areq.cipher_op_req,
sizeof(struct qcedev_cipher_op_req)))
return -EFAULT;
return -EFAULT;
break;
case QCEDEV_IOCTL_SHA_INIT_REQ:
{
struct scatterlist sg_src;
if (!access_ok(VERIFY_WRITE, (void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
if (__copy_from_user(&qcedev_areq.sha_op_req,
if (copy_from_user(&qcedev_areq.sha_op_req,
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@ -1723,9 +1662,9 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
err = qcedev_hash_init(&qcedev_areq, handle, &sg_src);
if (err)
return err;
if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
return -EFAULT;
}
handle->sha_ctxt.init_done = true;
break;
@ -1735,11 +1674,8 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
case QCEDEV_IOCTL_SHA_UPDATE_REQ:
{
struct scatterlist sg_src;
if (!access_ok(VERIFY_WRITE, (void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
if (__copy_from_user(&qcedev_areq.sha_op_req,
if (copy_from_user(&qcedev_areq.sha_op_req,
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@ -1761,10 +1697,15 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
return err;
}
if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) {
pr_err("Invalid sha_ctxt.diglen %d\n",
handle->sha_ctxt.diglen);
return -EINVAL;
}
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
}
@ -1776,11 +1717,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
pr_err("%s Init was not called\n", __func__);
return -EINVAL;
}
if (!access_ok(VERIFY_WRITE, (void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
if (__copy_from_user(&qcedev_areq.sha_op_req,
if (copy_from_user(&qcedev_areq.sha_op_req,
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@ -1794,7 +1731,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
handle->sha_ctxt.init_done = false;
@ -1803,11 +1740,8 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
case QCEDEV_IOCTL_GET_SHA_REQ:
{
struct scatterlist sg_src;
if (!access_ok(VERIFY_WRITE, (void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
if (__copy_from_user(&qcedev_areq.sha_op_req,
if (copy_from_user(&qcedev_areq.sha_op_req,
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@ -1825,7 +1759,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
}
@ -1839,11 +1773,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
if (is_fips_qcedev_integritytest_done)
return -EPERM;
if (!access_ok(VERIFY_WRITE, (void __user *)arg,
sizeof(enum fips_status)))
return -EFAULT;
if (__copy_from_user(&status, (void __user *)arg,
if (copy_from_user(&status, (void __user *)arg,
sizeof(enum fips_status)))
return -EFAULT;
@ -1872,12 +1802,9 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
case QCEDEV_IOCTL_QUERY_FIPS_STATUS:
{
enum fips_status status;
if (!access_ok(VERIFY_WRITE, (void __user *)arg,
sizeof(enum fips_status)))
return -EFAULT;
status = g_fips140_status;
if (__copy_to_user((void __user *)arg, &status,
if (copy_to_user((void __user *)arg, &status,
sizeof(enum fips_status)))
return -EFAULT;