msm: adsprpc: Handle out of bounds access
Add check for channel ID in fastrpc_buf_alloc to fix out of bounds access. Change-Id: I92f2717edcc91c19309589ce7c11c91c8129b71a Acked-by: Abhinav Parihar <parihar@qti.qualcomm.com> Signed-off-by: Vamsi Krishna Gattupalli <quic_vgattupa@quicinc.com>
This commit is contained in:
1 parent
34bb42eb71
commit
8b6c930e3c
1 file changed
+114
-39
+114
-39
@@ -655,7 +655,7 @@ static inline int poll_on_early_response(struct smq_invoke_ctx *ctx)
|
||||
static void fastrpc_buf_free(struct fastrpc_buf *buf, int cache)
|
||||
{
|
||||
struct fastrpc_file *fl = buf == NULL ? NULL : buf->fl;
|
||||
int vmid, err = 0;
|
||||
int vmid, err = 0, cid = -1;
|
||||
|
||||
if (!fl)
|
||||
return;
|
||||
@@ -681,14 +681,22 @@ static void fastrpc_buf_free(struct fastrpc_buf *buf, int cache)
|
||||
goto bail;
|
||||
if (fl->sctx->smmu.cb)
|
||||
buf->phys &= ~((uint64_t)fl->sctx->smmu.cb << 32);
|
||||
vmid = fl->apps->channel[fl->cid].vmid;
|
||||
cid = fl->cid;
|
||||
VERIFY(err, cid >= ADSP_DOMAIN_ID && cid < NUM_CHANNELS);
|
||||
if (err) {
|
||||
err = -ECHRNG;
|
||||
pr_err("invalid channel 0x%zx set for session\n",
|
||||
cid);
|
||||
goto bail;
|
||||
}
|
||||
vmid = fl->apps->channel[cid].vmid;
|
||||
if (vmid) {
|
||||
int srcVM[2] = {VMID_HLOS, vmid};
|
||||
|
||||
hyp_assign_phys(buf->phys, buf_page_size(buf->size),
|
||||
srcVM, 2, destVM, destVMperm, 1);
|
||||
}
|
||||
trace_fastrpc_dma_free(fl->cid, buf->phys, buf->size);
|
||||
trace_fastrpc_dma_free(cid, buf->phys, buf->size);
|
||||
dma_free_attrs(fl->sctx->smmu.dev, buf->size, buf->virt,
|
||||
buf->phys, buf->dma_attr);
|
||||
}
|
||||
@@ -920,7 +928,7 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags)
|
||||
(dma_addr_t)map->phys, (unsigned long)map->attr);
|
||||
}
|
||||
} else if (map->flags == FASTRPC_DMAHANDLE_NOMAP) {
|
||||
trace_fastrpc_dma_unmap(fl->cid, map->phys, map->size);
|
||||
trace_fastrpc_dma_unmap(cid, map->phys, map->size);
|
||||
if (!IS_ERR_OR_NULL(map->table))
|
||||
dma_buf_unmap_attachment(map->attach, map->table,
|
||||
DMA_BIDIRECTIONAL);
|
||||
@@ -937,14 +945,14 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags)
|
||||
else
|
||||
sess = fl->sctx;
|
||||
|
||||
vmid = fl->apps->channel[fl->cid].vmid;
|
||||
vmid = fl->apps->channel[cid].vmid;
|
||||
if (vmid && map->phys) {
|
||||
int srcVM[2] = {VMID_HLOS, vmid};
|
||||
|
||||
hyp_assign_phys(map->phys, buf_page_size(map->size),
|
||||
srcVM, 2, destVM, destVMperm, 1);
|
||||
}
|
||||
trace_fastrpc_dma_unmap(fl->cid, map->phys, map->size);
|
||||
trace_fastrpc_dma_unmap(cid, map->phys, map->size);
|
||||
if (!IS_ERR_OR_NULL(map->table))
|
||||
dma_buf_unmap_attachment(map->attach, map->table,
|
||||
DMA_BIDIRECTIONAL);
|
||||
@@ -966,7 +974,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd,
|
||||
struct fastrpc_apps *me = &gfa;
|
||||
struct fastrpc_session_ctx *sess;
|
||||
struct fastrpc_apps *apps = fl->apps;
|
||||
int cid = fl->cid;
|
||||
int cid = -1;
|
||||
struct fastrpc_channel_ctx *chan = NULL;
|
||||
struct fastrpc_mmap *map = NULL;
|
||||
dma_addr_t region_phys = 0;
|
||||
@@ -975,6 +983,12 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd,
|
||||
int err = 0, vmid, sgl_index = 0;
|
||||
struct scatterlist *sgl = NULL;
|
||||
|
||||
if (!fl) {
|
||||
err = -EBADF;
|
||||
goto bail;
|
||||
}
|
||||
cid = fl->cid;
|
||||
|
||||
VERIFY(err, cid >= ADSP_DOMAIN_ID && cid < NUM_CHANNELS);
|
||||
if (err)
|
||||
goto bail;
|
||||
@@ -1035,7 +1049,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd,
|
||||
goto bail;
|
||||
map->phys = sg_dma_address(map->table->sgl);
|
||||
map->size = len;
|
||||
trace_fastrpc_dma_map(fl->cid, fd, map->phys, map->size,
|
||||
trace_fastrpc_dma_map(cid, fd, map->phys, map->size,
|
||||
len, mflags, map->attach->dma_map_attrs);
|
||||
} else {
|
||||
if (map->attr && (map->attr & FASTRPC_ATTR_KEEP_MAP)) {
|
||||
@@ -1112,7 +1126,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd,
|
||||
} else {
|
||||
map->size = buf_page_size(len);
|
||||
}
|
||||
trace_fastrpc_dma_map(fl->cid, fd, map->phys, map->size,
|
||||
trace_fastrpc_dma_map(cid, fd, map->phys, map->size,
|
||||
len, mflags, map->attach->dma_map_attrs);
|
||||
|
||||
VERIFY(err, map->size >= len && map->size < me->max_size_limit);
|
||||
@@ -1123,7 +1137,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd,
|
||||
goto bail;
|
||||
}
|
||||
|
||||
vmid = fl->apps->channel[fl->cid].vmid;
|
||||
vmid = fl->apps->channel[cid].vmid;
|
||||
if (!sess->smmu.enabled && !vmid) {
|
||||
VERIFY(err, map->phys >= me->range.addr &&
|
||||
map->phys + map->size <=
|
||||
@@ -1167,6 +1181,14 @@ static int fastrpc_buf_alloc(struct fastrpc_file *fl, size_t size,
|
||||
struct fastrpc_apps *me = &gfa;
|
||||
struct fastrpc_buf *buf = NULL, *fr = NULL;
|
||||
struct hlist_node *n;
|
||||
int cid = -1;
|
||||
|
||||
cid = fl->cid;
|
||||
VERIFY(err, cid >= ADSP_DOMAIN_ID && cid < NUM_CHANNELS);
|
||||
if (err) {
|
||||
err = -ECHRNG;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
VERIFY(err, size > 0 && size < me->max_size_limit);
|
||||
if (err) {
|
||||
@@ -1230,10 +1252,10 @@ static int fastrpc_buf_alloc(struct fastrpc_file *fl, size_t size,
|
||||
}
|
||||
if (fl->sctx->smmu.cb)
|
||||
buf->phys += ((uint64_t)fl->sctx->smmu.cb << 32);
|
||||
trace_fastrpc_dma_alloc(fl->cid, buf->phys, size,
|
||||
trace_fastrpc_dma_alloc(cid, buf->phys, size,
|
||||
dma_attr, (int)rflags);
|
||||
|
||||
vmid = fl->apps->channel[fl->cid].vmid;
|
||||
vmid = fl->apps->channel[cid].vmid;
|
||||
if (vmid) {
|
||||
int srcVM[1] = {VMID_HLOS};
|
||||
int destVM[2] = {VMID_HLOS, vmid};
|
||||
@@ -2156,7 +2178,10 @@ static int fastrpc_invoke_send(struct smq_invoke_ctx *ctx,
|
||||
struct fastrpc_channel_ctx *channel_ctx = NULL;
|
||||
int err = 0, cid = -1;
|
||||
|
||||
channel_ctx = &fl->apps->channel[fl->cid];
|
||||
if (!fl) {
|
||||
err = -EBADF;
|
||||
goto bail;
|
||||
}
|
||||
cid = fl->cid;
|
||||
VERIFY(err, cid >= ADSP_DOMAIN_ID && cid < NUM_CHANNELS);
|
||||
if (err) {
|
||||
@@ -2164,6 +2189,7 @@ static int fastrpc_invoke_send(struct smq_invoke_ctx *ctx,
|
||||
goto bail;
|
||||
}
|
||||
|
||||
channel_ctx = &fl->apps->channel[cid];
|
||||
mutex_lock(&channel_ctx->smd_mutex);
|
||||
msg->pid = fl->tgid;
|
||||
msg->tid = current->pid;
|
||||
@@ -2192,7 +2218,7 @@ static int fastrpc_invoke_send(struct smq_invoke_ctx *ctx,
|
||||
goto bail;
|
||||
}
|
||||
err = rpmsg_send(channel_ctx->rpdev->ept, (void *)msg, sizeof(*msg));
|
||||
trace_fastrpc_rpmsg_send(fl->cid, (uint64_t)ctx, msg->invoke.header.ctx,
|
||||
trace_fastrpc_rpmsg_send(cid, (uint64_t)ctx, msg->invoke.header.ctx,
|
||||
handle, ctx->sc, msg->invoke.page.addr, msg->invoke.page.size);
|
||||
LOG_FASTRPC_GLINK_MSG(channel_ctx->ipc_log_ctx,
|
||||
"sent pkt %pK (sz %d): ctx 0x%llx, handle 0x%x, sc 0x%x (rpmsg err %d)",
|
||||
@@ -2829,14 +2855,24 @@ static int fastrpc_send_cpuinfo_to_dsp(struct fastrpc_file *fl)
|
||||
struct fastrpc_apps *me = &gfa;
|
||||
struct fastrpc_ioctl_invoke_crc ioctl;
|
||||
remote_arg_t ra[2];
|
||||
int cid = -1;
|
||||
|
||||
VERIFY(err, fl && fl->cid >= ADSP_DOMAIN_ID && fl->cid < NUM_CHANNELS);
|
||||
if (err)
|
||||
if (!fl) {
|
||||
err = -EBADF;
|
||||
goto bail;
|
||||
}
|
||||
cid = fl->cid;
|
||||
|
||||
cpuinfo = me->channel[fl->cid].cpuinfo_todsp;
|
||||
VERIFY(err, cid >= ADSP_DOMAIN_ID && cid < NUM_CHANNELS);
|
||||
if (err) {
|
||||
err = -ECHRNG;
|
||||
pr_err("invalid channel 0x%zx set for session\n\n",
|
||||
cid);
|
||||
goto bail;
|
||||
}
|
||||
cpuinfo = me->channel[cid].cpuinfo_todsp;
|
||||
/* return success if already updated to remote processor */
|
||||
if (me->channel[fl->cid].cpuinfo_status)
|
||||
if (me->channel[cid].cpuinfo_status)
|
||||
return 0;
|
||||
|
||||
ra[0].buf.pv = (void *)&cpuinfo;
|
||||
@@ -2851,7 +2887,7 @@ static int fastrpc_send_cpuinfo_to_dsp(struct fastrpc_file *fl)
|
||||
|
||||
err = fastrpc_internal_invoke(fl, FASTRPC_MODE_PARALLEL, 1, &ioctl);
|
||||
if (!err)
|
||||
me->channel[fl->cid].cpuinfo_status = true;
|
||||
me->channel[cid].cpuinfo_status = true;
|
||||
bail:
|
||||
return err;
|
||||
}
|
||||
@@ -2975,17 +3011,27 @@ static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl)
|
||||
struct fastrpc_ioctl_invoke_crc ioctl;
|
||||
remote_arg_t ra[1];
|
||||
int tgid = 0;
|
||||
int cid = -1;
|
||||
|
||||
VERIFY(err, fl->cid >= ADSP_DOMAIN_ID && fl->cid < NUM_CHANNELS);
|
||||
if (err)
|
||||
if (!fl) {
|
||||
err = -EBADF;
|
||||
goto bail;
|
||||
}
|
||||
cid = fl->cid;
|
||||
|
||||
VERIFY(err, cid >= ADSP_DOMAIN_ID && cid < NUM_CHANNELS);
|
||||
if (err) {
|
||||
err = -ECHRNG;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
VERIFY(err, fl->sctx != NULL);
|
||||
if (err)
|
||||
goto bail;
|
||||
VERIFY(err, fl->apps->channel[fl->cid].rpdev != NULL);
|
||||
VERIFY(err, fl->apps->channel[cid].rpdev != NULL);
|
||||
if (err)
|
||||
goto bail;
|
||||
VERIFY(err, fl->apps->channel[fl->cid].issubsystemup == 1);
|
||||
VERIFY(err, fl->apps->channel[cid].issubsystemup == 1);
|
||||
if (err) {
|
||||
wait_for_completion(&fl->shutdown);
|
||||
goto bail;
|
||||
@@ -3062,7 +3108,13 @@ static int fastrpc_mmap_on_dsp(struct fastrpc_file *fl, uint32_t flags,
|
||||
struct {
|
||||
uintptr_t vaddrout;
|
||||
} routargs;
|
||||
int cid = -1;
|
||||
|
||||
if (!fl) {
|
||||
err = -EBADF;
|
||||
goto bail;
|
||||
}
|
||||
cid = fl->cid;
|
||||
inargs.pid = fl->tgid;
|
||||
inargs.vaddrin = (uintptr_t)va;
|
||||
inargs.flags = flags;
|
||||
@@ -3091,12 +3143,21 @@ static int fastrpc_mmap_on_dsp(struct fastrpc_file *fl, uint32_t flags,
|
||||
*raddr = (uintptr_t)routargs.vaddrout;
|
||||
if (err)
|
||||
goto bail;
|
||||
if (flags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
|
||||
VERIFY(err, cid >= ADSP_DOMAIN_ID && cid < NUM_CHANNELS);
|
||||
if (err) {
|
||||
err = -ECHRNG;
|
||||
pr_err("invalid channel 0x%zx set for session\n",
|
||||
cid);
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
if (flags == ADSP_MMAP_REMOTE_HEAP_ADDR
|
||||
&& me->channel[fl->cid].rhvm.vmid) {
|
||||
&& me->channel[cid].rhvm.vmid) {
|
||||
err = hyp_assign_phys(phys, (uint64_t)size,
|
||||
hlosvm, 1, me->channel[fl->cid].rhvm.vmid,
|
||||
me->channel[fl->cid].rhvm.vmperm,
|
||||
me->channel[fl->cid].rhvm.vmcount);
|
||||
hlosvm, 1, me->channel[cid].rhvm.vmid,
|
||||
me->channel[cid].rhvm.vmperm,
|
||||
me->channel[cid].rhvm.vmcount);
|
||||
if (err) {
|
||||
pr_err("adsprpc: %s: %s: rh hyp assign failed with %d for phys 0x%llx, size %zd\n",
|
||||
__func__, current->comm,
|
||||
@@ -3123,18 +3184,28 @@ static int fastrpc_munmap_on_dsp_rh(struct fastrpc_file *fl, uint64_t phys,
|
||||
int tgid = 0;
|
||||
int destVM[1] = {VMID_HLOS};
|
||||
int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC};
|
||||
int cid = -1;
|
||||
|
||||
if (!fl) {
|
||||
err = -EBADF;
|
||||
goto bail;
|
||||
}
|
||||
cid = fl->cid;
|
||||
VERIFY(err, cid >= ADSP_DOMAIN_ID && cid < NUM_CHANNELS);
|
||||
if (err) {
|
||||
err = -ECHRNG;
|
||||
pr_err("invalid channel 0x%zx set for session\n",
|
||||
cid);
|
||||
goto bail;
|
||||
}
|
||||
if (flags == ADSP_MMAP_HEAP_ADDR) {
|
||||
struct fastrpc_ioctl_invoke_crc ioctl;
|
||||
remote_arg_t ra[2];
|
||||
int err = 0, cid = 0;
|
||||
int err = 0;
|
||||
struct {
|
||||
uint8_t skey;
|
||||
} routargs;
|
||||
|
||||
if (fl == NULL)
|
||||
goto bail;
|
||||
cid = fl->cid;
|
||||
tgid = fl->tgid;
|
||||
ra[0].buf.pv = (void *)&tgid;
|
||||
ra[0].buf.len = sizeof(tgid);
|
||||
@@ -3162,11 +3233,11 @@ static int fastrpc_munmap_on_dsp_rh(struct fastrpc_file *fl, uint64_t phys,
|
||||
if (err)
|
||||
goto bail;
|
||||
} else if (flags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
|
||||
if (me->channel[fl->cid].rhvm.vmid) {
|
||||
if (me->channel[cid].rhvm.vmid) {
|
||||
err = hyp_assign_phys(phys,
|
||||
(uint64_t)size,
|
||||
me->channel[fl->cid].rhvm.vmid,
|
||||
me->channel[fl->cid].rhvm.vmcount,
|
||||
me->channel[cid].rhvm.vmid,
|
||||
me->channel[cid].rhvm.vmcount,
|
||||
destVM, destVMperm, 1);
|
||||
if (err) {
|
||||
pr_err("adsprpc: %s: %s: rh hyp unassign failed with %d for phys 0x%llx, size %zd\n",
|
||||
@@ -3258,6 +3329,10 @@ static int fastrpc_mmap_remove_pdr(struct fastrpc_file *fl)
|
||||
struct fastrpc_apps *me = &gfa;
|
||||
int session = 0, err = 0, cid = -1;
|
||||
|
||||
if (!fl) {
|
||||
err = -EBADF;
|
||||
goto bail;
|
||||
}
|
||||
err = fastrpc_get_spd_session(fl->servloc_name,
|
||||
&session, &cid);
|
||||
if (err)
|
||||
@@ -3265,18 +3340,18 @@ static int fastrpc_mmap_remove_pdr(struct fastrpc_file *fl)
|
||||
VERIFY(err, cid == fl->cid);
|
||||
if (err)
|
||||
goto bail;
|
||||
if (!me->channel[fl->cid].spd[session].ispdup) {
|
||||
if (!me->channel[cid].spd[session].ispdup) {
|
||||
err = -ENOTCONN;
|
||||
goto bail;
|
||||
}
|
||||
if (me->channel[fl->cid].spd[session].pdrcount !=
|
||||
me->channel[fl->cid].spd[session].prevpdrcount) {
|
||||
if (me->channel[cid].spd[session].pdrcount !=
|
||||
me->channel[cid].spd[session].prevpdrcount) {
|
||||
err = fastrpc_mmap_remove_ssr(fl, 0);
|
||||
if (err)
|
||||
pr_warn("adsprpc: %s: %s: failed to unmap remote heap (err %d)\n",
|
||||
__func__, current->comm, err);
|
||||
me->channel[fl->cid].spd[session].prevpdrcount =
|
||||
me->channel[fl->cid].spd[session].pdrcount;
|
||||
me->channel[cid].spd[session].prevpdrcount =
|
||||
me->channel[cid].spd[session].pdrcount;
|
||||
}
|
||||
bail:
|
||||
return err;
|
||||
|
||||
Reference in new issue
Block a user