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:
parent
5659dd095d
commit
58d4f78866
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue