For user passed fd buffer, map is created using DMA calls. The
map related information is stored in fastrpc_map structure. The
actual DMA size is not stored in the structure. Store the actual
size of buffer and check it against the user passed size.

Fixes: c68cfb718c8f ("misc: fastrpc: Add support for context Invoke method")
Cc: stable <sta...@kernel.org>
Signed-off-by: Ekansh Gupta <quic_ekang...@quicinc.com>
---
 drivers/misc/fastrpc.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 5204fda51da3..bcfb8ce1a0e3 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -322,11 +322,11 @@ static void fastrpc_free_map(struct kref *ref)
 
                        perm.vmid = QCOM_SCM_VMID_HLOS;
                        perm.perm = QCOM_SCM_PERM_RWX;
-                       err = qcom_scm_assign_mem(map->phys, map->size,
+                       err = qcom_scm_assign_mem(map->phys, map->len,
                                &src_perms, &perm, 1);
                        if (err) {
                                dev_err(map->fl->sctx->dev, "Failed to assign 
memory phys 0x%llx size 0x%llx err %d\n",
-                                               map->phys, map->size, err);
+                                               map->phys, map->len, err);
                                return;
                        }
                }
@@ -757,7 +757,8 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int 
fd,
        struct fastrpc_session_ctx *sess = fl->sctx;
        struct fastrpc_map *map = NULL;
        struct sg_table *table;
-       int err = 0;
+       struct scatterlist *sgl = NULL;
+       int err = 0, sgl_index = 0;
 
        if (!fastrpc_map_lookup(fl, fd, ppmap, true))
                return 0;
@@ -797,7 +798,15 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int 
fd,
                map->phys = sg_dma_address(map->table->sgl);
                map->phys += ((u64)fl->sctx->sid << 32);
        }
-       map->size = len;
+       for_each_sg(map->table->sgl, sgl, map->table->nents,
+               sgl_index)
+               map->size += sg_dma_len(sgl);
+       if (len > map->size) {
+               dev_dbg(sess->dev, "Bad size passed len 0x%llx map size 
0x%llx\n",
+                               len, map->size);
+               err = -EINVAL;
+               goto map_err;
+       }
        map->va = sg_virt(map->table->sgl);
        map->len = len;
 
@@ -814,10 +823,10 @@ static int fastrpc_map_create(struct fastrpc_user *fl, 
int fd,
                dst_perms[1].vmid = fl->cctx->vmperms[0].vmid;
                dst_perms[1].perm = QCOM_SCM_PERM_RWX;
                map->attr = attr;
-               err = qcom_scm_assign_mem(map->phys, (u64)map->size, 
&src_perms, dst_perms, 2);
+               err = qcom_scm_assign_mem(map->phys, (u64)map->len, &src_perms, 
dst_perms, 2);
                if (err) {
                        dev_err(sess->dev, "Failed to assign memory with phys 
0x%llx size 0x%llx err %d\n",
-                                       map->phys, map->size, err);
+                                       map->phys, map->len, err);
                        goto map_err;
                }
        }
@@ -2044,7 +2053,7 @@ static int fastrpc_req_mem_map(struct fastrpc_user *fl, 
char __user *argp)
        args[0].length = sizeof(req_msg);
 
        pages.addr = map->phys;
-       pages.size = map->size;
+       pages.size = map->len;
 
        args[1].ptr = (u64) (uintptr_t) &pages;
        args[1].length = sizeof(pages);
@@ -2059,7 +2068,7 @@ static int fastrpc_req_mem_map(struct fastrpc_user *fl, 
char __user *argp)
        err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc, 
&args[0]);
        if (err) {
                dev_err(dev, "mem mmap error, fd %d, vaddr %llx, size %lld\n",
-                       req.fd, req.vaddrin, map->size);
+                       req.fd, req.vaddrin, map->len);
                goto err_invoke;
        }
 
@@ -2072,7 +2081,7 @@ static int fastrpc_req_mem_map(struct fastrpc_user *fl, 
char __user *argp)
        if (copy_to_user((void __user *)argp, &req, sizeof(req))) {
                /* unmap the memory and release the buffer */
                req_unmap.vaddr = (uintptr_t) rsp_msg.vaddr;
-               req_unmap.length = map->size;
+               req_unmap.length = map->len;
                fastrpc_req_mem_unmap_impl(fl, &req_unmap);
                return -EFAULT;
        }
-- 
2.34.1

Reply via email to