On 12/19/18 5:39 PM, Zengtao (B) wrote:
> Hi laura:
>
>> -----Original Message-----
>> From: Laura Abbott [mailto:labbott@redhat.com]
>> Sent: Thursday, December 20, 2018 2:10 AM
>> To: Zengtao (B) <prime.zeng(a)hisilicon.com>; sumit.semwal(a)linaro.org
>> Cc: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>; Arve Hjønnevåg
>> <arve(a)android.com>; Todd Kjos <tkjos(a)android.com>; Martijn Coenen
>> <maco(a)android.com>; Joel Fernandes <joel(a)joelfernandes.org>;
>> devel(a)driverdev.osuosl.org; dri-devel(a)lists.freedesktop.org;
>> linaro-mm-sig(a)lists.linaro.org; linux-kernel(a)vger.kernel.org
>> Subject: Re: [PATCH] staging: android: ion: add buffer flag update ioctl
>>
>> On 12/19/18 9:19 AM, Zeng Tao wrote:
>>> In some usecases, the buffer cached attribute is not determined at
>>> allocation time, it's determined just before the real cpu mapping.
>>> And from the memory view of point, a buffer should not have the
>> cached
>>> attribute util is really mapped by the cpu. So in this patch, we
>>> introduced the new ioctl command to target the requirement.
>>>
>>
>> This is racy and error prone. Can you explain more what problem you are
>> trying to solve?
>
> My use case is like this:
> 1. There are two process A and B, A takes case of ion buffer allocation, and
> pass the buffer fd to B, then B maps and uses it.
> 2. Process B need to map the buffer with different cached attribute for
> different use case, for example, if the buffer is used for pure software algorithm,
> then we need to map it as cached, otherwise non-cached, and B needs to deal
> with both cases.
> And unfortunately the mmap syscall takes no cached flags and we can't decide
> the cache attribute when we are doing the mmap, so I introduce new the ioctl
> even though I think the solution is not as good.
>
>
Thanks for the explanation, this was about the use case I expected.
I'm pretty sure I had this exact problem once upon a time and we
didn't come up with a solution. I'd still like to get rid of
uncached buffers in general and just use cached buffers
(see http://driverdev.linuxdriverproject.org/pipermail/driverdev-devel/2018-Nove…)
What's your usecase for uncached buffers?
>>
>>> Signed-off-by: Zeng Tao <prime.zeng(a)hisilicon.com>
>>> ---
>>> drivers/staging/android/ion/ion-ioctl.c | 4 ++++
>>> drivers/staging/android/ion/ion.c | 17 +++++++++++++++++
>>> drivers/staging/android/ion/ion.h | 1 +
>>> drivers/staging/android/uapi/ion.h | 22
>> ++++++++++++++++++++++
>>> 4 files changed, 44 insertions(+)
>>>
>>> diff --git a/drivers/staging/android/ion/ion-ioctl.c
>>> b/drivers/staging/android/ion/ion-ioctl.c
>>> index a8d3cc4..60bb702 100644
>>> --- a/drivers/staging/android/ion/ion-ioctl.c
>>> +++ b/drivers/staging/android/ion/ion-ioctl.c
>>> @@ -12,6 +12,7 @@
>>>
>>> union ion_ioctl_arg {
>>> struct ion_allocation_data allocation;
>>> + struct ion_buffer_flag_data update;
>>> struct ion_heap_query query;
>>> };
>>>
>>> @@ -83,6 +84,9 @@ long ion_ioctl(struct file *filp, unsigned int cmd,
>>> unsigned long arg)
>>>
>>> break;
>>> }
>>> + case ION_IOC_BUFFER_UPDATE:
>>> + ret = ion_buffer_update(data.update.fd, data.update.flags);
>>> + break;
>>> case ION_IOC_HEAP_QUERY:
>>> ret = ion_query_heaps(&data.query);
>>> break;
>>> diff --git a/drivers/staging/android/ion/ion.c
>>> b/drivers/staging/android/ion/ion.c
>>> index 9907332..f1404dc 100644
>>> --- a/drivers/staging/android/ion/ion.c
>>> +++ b/drivers/staging/android/ion/ion.c
>>> @@ -436,6 +436,23 @@ int ion_alloc(size_t len, unsigned int
>> heap_id_mask, unsigned int flags)
>>> return fd;
>>> }
>>>
>>> +int ion_buffer_update(unsigned int fd, unsigned int flags) {
>>> + struct dma_buf *dmabuf;
>>> + struct ion_buffer *buffer;
>>> +
>>> + dmabuf = dma_buf_get(fd);
>>> +
>>> + if (!dmabuf)
>>> + return -EINVAL;
>>> +
>>> + buffer = dmabuf->priv;
>>> + buffer->flags = flags;
>>> + dma_buf_put(dmabuf);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> int ion_query_heaps(struct ion_heap_query *query)
>>> {
>>> struct ion_device *dev = internal_dev; diff --git
>>> a/drivers/staging/android/ion/ion.h
>>> b/drivers/staging/android/ion/ion.h
>>> index c006fc1..99bf9ab 100644
>>> --- a/drivers/staging/android/ion/ion.h
>>> +++ b/drivers/staging/android/ion/ion.h
>>> @@ -199,6 +199,7 @@ int ion_heap_pages_zero(struct page *page,
>> size_t size, pgprot_t pgprot);
>>> int ion_alloc(size_t len,
>>> unsigned int heap_id_mask,
>>> unsigned int flags);
>>> +int ion_buffer_update(unsigned int fd, unsigned int flags);
>>>
>>> /**
>>> * ion_heap_init_shrinker
>>> diff --git a/drivers/staging/android/uapi/ion.h
>>> b/drivers/staging/android/uapi/ion.h
>>> index 5d70098..99753fc 100644
>>> --- a/drivers/staging/android/uapi/ion.h
>>> +++ b/drivers/staging/android/uapi/ion.h
>>> @@ -74,6 +74,20 @@ struct ion_allocation_data {
>>> __u32 unused;
>>> };
>>>
>>> +/**
>>> + * struct ion_buffer_flag_data - metadata passed from userspace for
>>> +update
>>> + * buffer flags
>>> + * @fd: file descriptor of the buffer
>>> + * @flags: flags passed to the buffer
>>> + *
>>> + * Provided by userspace as an argument to the ioctl */
>>> +
>>> +struct ion_buffer_flag_data {
>>> + __u32 fd;
>>> + __u32 flags;
>>> +}
>>> +
>>> #define MAX_HEAP_NAME 32
>>>
>>> /**
>>> @@ -116,6 +130,14 @@ struct ion_heap_query {
>>> struct ion_allocation_data)
>>>
>>> /**
>>> + * DOC: ION_IOC_BUFFER_UPDATE - update the specified ion buffer
>> flags
>>> + *
>>> + * Takes an ion_buffer_flag_data structure and returns the result of
>>> +the
>>> + * buffer flag update operation.
>>> + */
>>> +#define ION_IOC_BUFFER_UPDATE _IOWR(ION_IOC_MAGIC, 1, \
>>> + struct ion_buffer_flag_data)
>>> +/**
>>> * DOC: ION_IOC_HEAP_QUERY - information about available heaps
>>> *
>>> * Takes an ion_heap_query structure and populates information
>> about
>>>
>
The issue:
Currently in ION if you allocate uncached memory it is possible that there
are still dirty lines in the cache. And often these dirty lines in the
cache are the zeros which were meant to clear out any sensitive kernel
data.
What this means is that if you allocate uncached memory from ION, and then
subsequently write to that buffer (using the uncached mapping you are
provided by ION) then the data you have written could be corrupted at some
point in the future if a dirty line is evicted from the cache.
Also this means there is a potential security issue. If an un-privileged
userspace user allocated uncached memory (for example from the system heap)
and then if they were to read from that buffer (through the un-cached
mapping they are provided by ION), and if some of the zeros which were
written to that memory are still in the cache then this un-privileged
userspace user could read potentially sensitive kernel data.
An unacceptable fix:
I have included some sample code which should resolve this issue for the
system heap and the cma heap on some architectures, however this code
would not be acceptable for upstreaming since it uses hacks to clean
the cache.
Similar changes would need to be made to carveout heap and chunk heap.
I would appreciate some feedback on the proper way for ION to clean the
caches for memory it has allocated that is intended for uncached access.
I realize that it may be tempting, as a solution to this problem, to
simply strip uncached support from ION. I hope that we can try to find a
solution which preserves uncached memory support as ION uncached memory
is often used (though perhaps not in upstreamed code) in cases such as
multimedia use cases where there is no CPU access required, in secure
heap allocations, and in some cases where there is minimal CPU access
and therefore uncached memory performs better.
Signed-off-by: Liam Mark <lmark(a)codeaurora.org>
---
drivers/staging/android/ion/ion.c | 16 ++++++++++++++++
drivers/staging/android/ion/ion.h | 5 ++++-
drivers/staging/android/ion/ion_cma_heap.c | 3 +++
drivers/staging/android/ion/ion_page_pool.c | 8 ++++++--
drivers/staging/android/ion/ion_system_heap.c | 7 ++++++-
5 files changed, 35 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 57e0d8035b2e..10e967b0a0f4 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -38,6 +38,22 @@ bool ion_buffer_cached(struct ion_buffer *buffer)
return !!(buffer->flags & ION_FLAG_CACHED);
}
+void ion_pages_sync_for_device(struct page *page, size_t size,
+ enum dma_data_direction dir)
+{
+ struct scatterlist sg;
+ struct device dev = {0};
+
+ /* hack, use dummy device */
+ arch_setup_dma_ops(&dev, 0, 0, NULL, false);
+
+ sg_init_table(&sg, 1);
+ sg_set_page(&sg, page, size, 0);
+ /* hack, use phys address for dma address */
+ sg_dma_address(&sg) = page_to_phys(page);
+ dma_sync_sg_for_device(&dev, &sg, 1, dir);
+}
+
/* this function should only be called while dev->lock is held */
static void ion_buffer_add(struct ion_device *dev,
struct ion_buffer *buffer)
diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h
index a238f23c9116..227b9928d185 100644
--- a/drivers/staging/android/ion/ion.h
+++ b/drivers/staging/android/ion/ion.h
@@ -192,6 +192,9 @@ struct ion_heap {
*/
bool ion_buffer_cached(struct ion_buffer *buffer);
+void ion_pages_sync_for_device(struct page *page, size_t size,
+ enum dma_data_direction dir);
+
/**
* ion_buffer_fault_user_mappings - fault in user mappings of this buffer
* @buffer: buffer
@@ -333,7 +336,7 @@ struct ion_page_pool {
struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
bool cached);
void ion_page_pool_destroy(struct ion_page_pool *pool);
-struct page *ion_page_pool_alloc(struct ion_page_pool *pool);
+struct page *ion_page_pool_alloc(struct ion_page_pool *pool, bool *from_pool);
void ion_page_pool_free(struct ion_page_pool *pool, struct page *page);
/** ion_page_pool_shrink - shrinks the size of the memory cached in the pool
diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c
index 49718c96bf9e..82e80621d114 100644
--- a/drivers/staging/android/ion/ion_cma_heap.c
+++ b/drivers/staging/android/ion/ion_cma_heap.c
@@ -59,6 +59,9 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
memset(page_address(pages), 0, size);
}
+ if (!ion_buffer_cached(buffer))
+ ion_pages_sync_for_device(pages, size, DMA_BIDIRECTIONAL);
+
table = kmalloc(sizeof(*table), GFP_KERNEL);
if (!table)
goto err;
diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c
index b3017f12835f..169a321778ed 100644
--- a/drivers/staging/android/ion/ion_page_pool.c
+++ b/drivers/staging/android/ion/ion_page_pool.c
@@ -63,7 +63,7 @@ static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high)
return page;
}
-struct page *ion_page_pool_alloc(struct ion_page_pool *pool)
+struct page *ion_page_pool_alloc(struct ion_page_pool *pool, bool *from_pool)
{
struct page *page = NULL;
@@ -76,8 +76,12 @@ struct page *ion_page_pool_alloc(struct ion_page_pool *pool)
page = ion_page_pool_remove(pool, false);
mutex_unlock(&pool->mutex);
- if (!page)
+ if (!page) {
page = ion_page_pool_alloc_pages(pool);
+ *from_pool = false;
+ } else {
+ *from_pool = true;
+ }
return page;
}
diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c
index bc19cdd30637..3bb4604e032b 100644
--- a/drivers/staging/android/ion/ion_system_heap.c
+++ b/drivers/staging/android/ion/ion_system_heap.c
@@ -57,13 +57,18 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap,
bool cached = ion_buffer_cached(buffer);
struct ion_page_pool *pool;
struct page *page;
+ bool from_pool;
if (!cached)
pool = heap->uncached_pools[order_to_index(order)];
else
pool = heap->cached_pools[order_to_index(order)];
- page = ion_page_pool_alloc(pool);
+ page = ion_page_pool_alloc(pool, &from_pool);
+
+ if (!from_pool && !ion_buffer_cached(buffer))
+ ion_pages_sync_for_device(page, PAGE_SIZE << order,
+ DMA_BIDIRECTIONAL);
return page;
}
--
1.8.5.2
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project