From f4746d714f17b00e0c10f0a67e3fbee9b378de43 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Thu, 6 Sep 2018 16:15:41 -0700 Subject: [PATCH] ion: Ensure non-HLOS memory cannot be mapped by CPU Currently it is possible for an ION client to allocate non-HLOS memory (ie memory which isn't assigned to the HLOS vmid), map this memory, and then attempt to access this memory from the CPU. Attempting to access non-HLOS memory from the CPU will cause a stage-2 fault. Fix ION so that non-HLOS memory cannot be mapped by the CPU. Change-Id: Ifb51de2eabc076cddc744c13f01ef97b4a7c6874 Signed-off-by: Liam Mark --- drivers/staging/android/ion/ion_cma_heap.c | 27 +++++++++++++++++-- drivers/staging/android/ion/ion_system_heap.c | 12 +++++++++ .../android/ion/ion_system_secure_heap.c | 10 ++++--- drivers/staging/android/ion/msm/msm_ion.c | 15 +++++++++++ drivers/staging/android/ion/msm/msm_ion.h | 9 ++++++- 5 files changed, 66 insertions(+), 7 deletions(-) diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index 77bc25dfd562..bd481af4035c 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -313,14 +313,37 @@ err: return ret; } +static void *ion_secure_cma_map_kernel(struct ion_heap *heap, + struct ion_buffer *buffer) +{ + if (!is_buffer_hlos_assigned(buffer)) { + pr_info("%s: Mapping non-HLOS accessible buffer disallowed\n", + __func__); + return NULL; + } + return ion_cma_map_kernel(heap, buffer); +} + +static int ion_secure_cma_map_user(struct ion_heap *mapper, + struct ion_buffer *buffer, + struct vm_area_struct *vma) +{ + if (!is_buffer_hlos_assigned(buffer)) { + pr_info("%s: Mapping non-HLOS accessible buffer disallowed\n", + __func__); + return -EINVAL; + } + return ion_cma_mmap(mapper, buffer, vma); +} + static struct ion_heap_ops ion_secure_cma_ops = { .allocate = ion_secure_cma_allocate, .free = ion_secure_cma_free, .map_dma = ion_cma_heap_map_dma, .unmap_dma = ion_cma_heap_unmap_dma, .phys = ion_cma_phys, - .map_user = ion_cma_mmap, - .map_kernel = ion_cma_map_kernel, + .map_user = ion_secure_cma_map_user, + .map_kernel = ion_secure_cma_map_kernel, .unmap_kernel = ion_cma_unmap_kernel, .print_debug = ion_cma_print_debug, }; diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index a2ead280ac4e..403dadea5bb2 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -99,6 +99,11 @@ size_t ion_system_heap_secure_page_pool_total(struct ion_heap *heap, return total << PAGE_SHIFT; } +static int ion_heap_is_system_heap_type(enum ion_heap_type type) +{ + return type == ((enum ion_heap_type)ION_HEAP_TYPE_SYSTEM); +} + static struct page *alloc_buffer_page(struct ion_system_heap *heap, struct ion_buffer *buffer, unsigned long order, @@ -352,6 +357,13 @@ static int ion_system_heap_allocate(struct ion_heap *heap, int vmid = get_secure_vmid(buffer->flags); struct device *dev = heap->priv; + if (ion_heap_is_system_heap_type(buffer->heap->type) && + is_secure_vmid_valid(vmid)) { + pr_info("%s: System heap doesn't support secure allocations\n", + __func__); + return -EINVAL; + } + if (align > PAGE_SIZE) return -EINVAL; diff --git a/drivers/staging/android/ion/ion_system_secure_heap.c b/drivers/staging/android/ion/ion_system_secure_heap.c index 803811597f37..c7585118a41c 100644 --- a/drivers/staging/android/ion/ion_system_secure_heap.c +++ b/drivers/staging/android/ion/ion_system_secure_heap.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -170,14 +170,15 @@ out: sys_heap->ops->free(&buffer); } -static void process_one_shrink(struct ion_heap *sys_heap, +static void process_one_shrink(struct ion_system_secure_heap *secure_heap, + struct ion_heap *sys_heap, struct prefetch_info *info) { struct ion_buffer buffer; size_t pool_size, size; int ret; - buffer.heap = sys_heap; + buffer.heap = &secure_heap->heap; buffer.flags = info->vmid; pool_size = ion_system_heap_secure_page_pool_total(sys_heap, @@ -192,6 +193,7 @@ static void process_one_shrink(struct ion_heap *sys_heap, } buffer.private_flags = ION_PRIV_FLAG_SHRINKER_FREE; + buffer.heap = sys_heap; sys_heap->ops->free(&buffer); } @@ -211,7 +213,7 @@ static void ion_system_secure_heap_prefetch_work(struct work_struct *work) spin_unlock_irqrestore(&secure_heap->work_lock, flags); if (info->shrink) - process_one_shrink(sys_heap, info); + process_one_shrink(secure_heap, sys_heap, info); else process_one_prefetch(sys_heap, info); diff --git a/drivers/staging/android/ion/msm/msm_ion.c b/drivers/staging/android/ion/msm/msm_ion.c index 7326aa46a8f6..116a6fecaac5 100644 --- a/drivers/staging/android/ion/msm/msm_ion.c +++ b/drivers/staging/android/ion/msm/msm_ion.c @@ -678,6 +678,21 @@ int get_secure_vmid(unsigned long flags) return VMID_CP_SPSS_SP_SHARED; return -EINVAL; } + +bool is_buffer_hlos_assigned(struct ion_buffer *buffer) +{ + bool is_hlos = false; + + if (buffer->heap->type == (enum ion_heap_type)ION_HEAP_TYPE_HYP_CMA && + (buffer->flags & ION_FLAG_CP_HLOS)) + is_hlos = true; + + if (get_secure_vmid(buffer->flags) <= 0) + is_hlos = true; + + return is_hlos; +} + /* fix up the cases where the ioctl direction bits are incorrect */ static unsigned int msm_ion_ioctl_dir(unsigned int cmd) { diff --git a/drivers/staging/android/ion/msm/msm_ion.h b/drivers/staging/android/ion/msm/msm_ion.h index 098104d56fdb..f0f01f92c05c 100644 --- a/drivers/staging/android/ion/msm/msm_ion.h +++ b/drivers/staging/android/ion/msm/msm_ion.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -175,6 +175,8 @@ int msm_ion_do_cache_offset_op( void *vaddr, unsigned int offset, unsigned long len, unsigned int cmd); +bool is_buffer_hlos_assigned(struct ion_buffer *buffer); + #else static inline struct ion_client *msm_ion_client_create(const char *name) { @@ -202,6 +204,11 @@ int msm_ion_do_cache_offset_op( return -ENODEV; } +static bool is_buffer_hlos_assigned(struct ion_buffer *buffer) +{ + return true; +} + #endif /* CONFIG_ION */ #endif