summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2018-01-12 05:05:06 +0300
committerOlof Johansson <olof@lixom.net>2018-01-12 05:05:06 +0300
commitffdc98c4f25b1f4fb96cd9190917b53a760f3fec (patch)
tree7bb4bb58ac4efa60c4263e72394557e39c74ec02
parentbe60566ea9b07c61c1b3cc586a95c1927cdaf3fb (diff)
parent2490cdf6435b1d3cac0dbf710cd752487c67c296 (diff)
downloadlinux-ffdc98c4f25b1f4fb96cd9190917b53a760f3fec.tar.xz
Merge tag 'tee-drv-dynamic-shm+fixes-for-v4.16' of https://git.linaro.org/people/jens.wiklander/linux-tee into next/drivers
This pull request updates the previous tee-drv-dynamic-shm-for-v4.16 pull request with five new patches fixing review comments and errors. Apart from three small fixes there's two larger patches that in the end checks that memory to be registered really is normal cached memory. * tag 'tee-drv-dynamic-shm+fixes-for-v4.16' of https://git.linaro.org/people/jens.wiklander/linux-tee: tee: shm: Potential NULL dereference calling tee_shm_register() tee: shm: don't put_page on null shm->pages tee: shm: make function __tee_shm_alloc static tee: optee: check type of registered shared memory tee: add start argument to shm_register callback Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r--drivers/tee/optee/call.c49
-rw-r--r--drivers/tee/optee/optee_private.h6
-rw-r--r--drivers/tee/tee_shm.c18
-rw-r--r--include/linux/tee_drv.h3
4 files changed, 61 insertions, 15 deletions
diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c
index 0f38b3827457..a5afbe6dee68 100644
--- a/drivers/tee/optee/call.c
+++ b/drivers/tee/optee/call.c
@@ -535,18 +535,58 @@ void optee_free_pages_list(void *list, size_t num_entries)
free_pages_exact(list, get_pages_list_size(num_entries));
}
+static bool is_normal_memory(pgprot_t p)
+{
+#if defined(CONFIG_ARM)
+ return (pgprot_val(p) & L_PTE_MT_MASK) == L_PTE_MT_WRITEALLOC;
+#elif defined(CONFIG_ARM64)
+ return (pgprot_val(p) & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL);
+#else
+#error "Unuspported architecture"
+#endif
+}
+
+static int __check_mem_type(struct vm_area_struct *vma, unsigned long end)
+{
+ while (vma && is_normal_memory(vma->vm_page_prot)) {
+ if (vma->vm_end >= end)
+ return 0;
+ vma = vma->vm_next;
+ }
+
+ return -EINVAL;
+}
+
+static int check_mem_type(unsigned long start, size_t num_pages)
+{
+ struct mm_struct *mm = current->mm;
+ int rc;
+
+ down_read(&mm->mmap_sem);
+ rc = __check_mem_type(find_vma(mm, start),
+ start + num_pages * PAGE_SIZE);
+ up_read(&mm->mmap_sem);
+
+ return rc;
+}
+
int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
- struct page **pages, size_t num_pages)
+ struct page **pages, size_t num_pages,
+ unsigned long start)
{
struct tee_shm *shm_arg = NULL;
struct optee_msg_arg *msg_arg;
u64 *pages_list;
phys_addr_t msg_parg;
- int rc = 0;
+ int rc;
if (!num_pages)
return -EINVAL;
+ rc = check_mem_type(start, num_pages);
+ if (rc)
+ return rc;
+
pages_list = optee_allocate_pages_list(num_pages);
if (!pages_list)
return -ENOMEM;
@@ -606,13 +646,14 @@ int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm)
}
int optee_shm_register_supp(struct tee_context *ctx, struct tee_shm *shm,
- struct page **pages, size_t num_pages)
+ struct page **pages, size_t num_pages,
+ unsigned long start)
{
/*
* We don't want to register supplicant memory in OP-TEE.
* Instead information about it will be passed in RPC code.
*/
- return 0;
+ return check_mem_type(start, num_pages);
}
int optee_shm_unregister_supp(struct tee_context *ctx, struct tee_shm *shm)
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index a85a24725e31..35e79386c556 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -162,11 +162,13 @@ void optee_enable_shm_cache(struct optee *optee);
void optee_disable_shm_cache(struct optee *optee);
int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
- struct page **pages, size_t num_pages);
+ struct page **pages, size_t num_pages,
+ unsigned long start);
int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm);
int optee_shm_register_supp(struct tee_context *ctx, struct tee_shm *shm,
- struct page **pages, size_t num_pages);
+ struct page **pages, size_t num_pages,
+ unsigned long start);
int optee_shm_unregister_supp(struct tee_context *ctx, struct tee_shm *shm);
int optee_from_msg_param(struct tee_param *params, size_t num_params,
diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
index 04e1b8b37046..556960a1bab3 100644
--- a/drivers/tee/tee_shm.c
+++ b/drivers/tee/tee_shm.c
@@ -112,9 +112,9 @@ static const struct dma_buf_ops tee_shm_dma_buf_ops = {
.mmap = tee_shm_op_mmap,
};
-struct tee_shm *__tee_shm_alloc(struct tee_context *ctx,
- struct tee_device *teedev,
- size_t size, u32 flags)
+static struct tee_shm *__tee_shm_alloc(struct tee_context *ctx,
+ struct tee_device *teedev,
+ size_t size, u32 flags)
{
struct tee_shm_pool_mgr *poolm = NULL;
struct tee_shm *shm;
@@ -283,7 +283,7 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
if (rc > 0)
shm->num_pages = rc;
if (rc != num_pages) {
- if (rc > 0)
+ if (rc >= 0)
rc = -ENOMEM;
ret = ERR_PTR(rc);
goto err;
@@ -299,7 +299,7 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
}
rc = teedev->desc->ops->shm_register(ctx, shm, shm->pages,
- shm->num_pages);
+ shm->num_pages, start);
if (rc) {
ret = ERR_PTR(rc);
goto err;
@@ -335,9 +335,11 @@ err:
idr_remove(&teedev->idr, shm->id);
mutex_unlock(&teedev->mutex);
}
- for (n = 0; n < shm->num_pages; n++)
- put_page(shm->pages[n]);
- kfree(shm->pages);
+ if (shm->pages) {
+ for (n = 0; n < shm->num_pages; n++)
+ put_page(shm->pages[n]);
+ kfree(shm->pages);
+ }
}
kfree(shm);
teedev_ctx_put(ctx);
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
index 41bd4bded28c..a2b3dfcee0b5 100644
--- a/include/linux/tee_drv.h
+++ b/include/linux/tee_drv.h
@@ -108,7 +108,8 @@ struct tee_driver_ops {
int (*supp_send)(struct tee_context *ctx, u32 ret, u32 num_params,
struct tee_param *param);
int (*shm_register)(struct tee_context *ctx, struct tee_shm *shm,
- struct page **pages, size_t num_pages);
+ struct page **pages, size_t num_pages,
+ unsigned long start);
int (*shm_unregister)(struct tee_context *ctx, struct tee_shm *shm);
};