mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-07 20:33:58 -04:00
ion: Check for valid vmids for msm system heap
Add a check for valid vmids before doing an allocation for msm system heap. This check does a hyp_assign on a page, stores the vmids and mark them as valid or invalid based on hyp_assign result. If vmid is invalid it returns or if its valid then proceeds with the allocation. So, this prevents ion pages leak in cases where hyp_assign fails. Also add a check for ion_hyp_assign_sg return value to prevent leak. Change-Id: Ibbc150490daf69d27b36db0e45a3c58496e6b9bd Signed-off-by: Vijayanand Jitta <vjitta@codeaurora.org>
This commit is contained in:
parent
58329ca148
commit
cae595f476
1 changed files with 64 additions and 7 deletions
|
|
@ -34,6 +34,8 @@ static gfp_t low_order_gfp_flags = GFP_HIGHUSER | __GFP_ZERO;
|
|||
static bool pool_auto_refill_en __read_mostly =
|
||||
IS_ENABLED(CONFIG_ION_POOL_AUTO_REFILL);
|
||||
|
||||
static bool valid_vmids[VMID_LAST];
|
||||
|
||||
int order_to_index(unsigned int order)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -274,6 +276,42 @@ static void process_info(struct page_info *info,
|
|||
kfree(info);
|
||||
}
|
||||
|
||||
static bool check_valid_vmid(int dest_vmid, struct ion_msm_system_heap *sys_heap)
|
||||
{
|
||||
phys_addr_t addr;
|
||||
struct page *page;
|
||||
int ret;
|
||||
bool from_pool = true;
|
||||
u32 source_vmid = VMID_HLOS;
|
||||
u32 dest_perms = msm_secure_get_vmid_perms(dest_vmid);
|
||||
int order_ind = order_to_index(0);
|
||||
|
||||
if (valid_vmids[dest_vmid])
|
||||
return true;
|
||||
|
||||
page = ion_msm_page_pool_alloc(sys_heap->uncached_pools[order_ind],
|
||||
&from_pool);
|
||||
if (!page)
|
||||
return false;
|
||||
|
||||
if (!from_pool)
|
||||
ion_pages_sync_for_device(sys_heap->heap.dev,
|
||||
page, PAGE_SIZE,
|
||||
DMA_BIDIRECTIONAL);
|
||||
addr = page_to_phys(page);
|
||||
ret = hyp_assign_phys(addr, PAGE_SIZE, &source_vmid, 1,
|
||||
&dest_vmid, &dest_perms, 1);
|
||||
if (ret) {
|
||||
ion_msm_page_pool_free(sys_heap->uncached_pools[order_ind],
|
||||
page);
|
||||
return false;
|
||||
}
|
||||
valid_vmids[dest_vmid] = true;
|
||||
ion_msm_page_pool_free(sys_heap->secure_pools[dest_vmid][order_ind],
|
||||
page);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ion_msm_system_heap_allocate(struct ion_heap *heap,
|
||||
struct ion_buffer *buffer,
|
||||
unsigned long size,
|
||||
|
|
@ -306,6 +344,19 @@ static int ion_msm_system_heap_allocate(struct ion_heap *heap,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* check if vmid is valid and skip this
|
||||
* check for trusted vm vmids (i.e; for
|
||||
* vmids > VMID_LAST) assuming vmids for
|
||||
* trusted vm are already validated.
|
||||
*/
|
||||
if (vmid > 0 && vmid < VMID_LAST &&
|
||||
!check_valid_vmid(vmid, sys_heap)) {
|
||||
pr_err("%s: VMID: %d not valid\n",
|
||||
__func__, vmid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&pages);
|
||||
INIT_LIST_HEAD(&pages_from_pool);
|
||||
|
||||
|
|
@ -392,8 +443,10 @@ static int ion_msm_system_heap_allocate(struct ion_heap *heap,
|
|||
if (nents_sync) {
|
||||
if (vmid > 0) {
|
||||
ret = ion_hyp_assign_sg(&table_sync, &vmid, 1, true);
|
||||
if (ret)
|
||||
if (ret == -EADDRNOTAVAIL)
|
||||
goto err_free_sg2;
|
||||
else if (ret < 0)
|
||||
goto err_free;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -412,16 +465,20 @@ static int ion_msm_system_heap_allocate(struct ion_heap *heap,
|
|||
return 0;
|
||||
|
||||
err_free_sg2:
|
||||
/* We failed to zero buffers. Bypass pool */
|
||||
buffer->private_flags |= ION_PRIV_FLAG_SHRINKER_FREE;
|
||||
|
||||
if (vmid > 0)
|
||||
if (ion_hyp_unassign_sg(table, &vmid, 1, true))
|
||||
if (ion_hyp_unassign_sg(&table_sync, &vmid, 1, true))
|
||||
goto err_free_table_sync;
|
||||
|
||||
for_each_sg(table->sgl, sg, table->nents, i)
|
||||
err_free:
|
||||
for_each_sg(table->sgl, sg, table->nents, i) {
|
||||
if (!PagePrivate(sg_page(sg))) {
|
||||
/* Pages from buddy are not zeroed. Bypass pool */
|
||||
buffer->private_flags |= ION_PRIV_FLAG_SHRINKER_FREE;
|
||||
} else {
|
||||
buffer->private_flags &= ~ION_PRIV_FLAG_SHRINKER_FREE;
|
||||
}
|
||||
free_buffer_page(sys_heap, buffer, sg_page(sg),
|
||||
get_order(sg->length));
|
||||
}
|
||||
err_free_table_sync:
|
||||
if (nents_sync)
|
||||
sg_free_table(&table_sync);
|
||||
|
|
|
|||
Loading…
Reference in a new issue