UPSTREAM: binder: add flag to clear buffer on txn complete
Add a per-transaction flag to indicate that the buffer must be cleared when the transaction is complete to prevent copies of sensitive data from being preserved in memory. Signed-off-by: Todd Kjos <tkjos@google.com> Link: https://lore.kernel.org/r/20201120233743.3617529-1-tkjos@google.com Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Bug: 171501513 Change-Id: Ic9338c85cbe3b11ab6f2bda55dce9964bb48447a (cherry picked from commit 0f966cba95c78029f491b433ea95ff38f414a761) Signed-off-by: Todd Kjos <tkjos@google.com>
This commit is contained in:
@@ -696,6 +696,8 @@ static void binder_free_buf_locked(struct binder_alloc *alloc,
|
||||
binder_insert_free_buffer(alloc, buffer);
|
||||
}
|
||||
|
||||
static void binder_alloc_clear_buf(struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffer);
|
||||
/**
|
||||
* binder_alloc_free_buf() - free a binder buffer
|
||||
* @alloc: binder_alloc for this proc
|
||||
@@ -706,6 +708,18 @@ static void binder_free_buf_locked(struct binder_alloc *alloc,
|
||||
void binder_alloc_free_buf(struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffer)
|
||||
{
|
||||
/*
|
||||
* We could eliminate the call to binder_alloc_clear_buf()
|
||||
* from binder_alloc_deferred_release() by moving this to
|
||||
* binder_alloc_free_buf_locked(). However, that could
|
||||
* increase contention for the alloc mutex if clear_on_free
|
||||
* is used frequently for large buffers. The mutex is not
|
||||
* needed for correctness here.
|
||||
*/
|
||||
if (buffer->clear_on_free) {
|
||||
binder_alloc_clear_buf(alloc, buffer);
|
||||
buffer->clear_on_free = false;
|
||||
}
|
||||
mutex_lock(&alloc->mutex);
|
||||
binder_free_buf_locked(alloc, buffer);
|
||||
mutex_unlock(&alloc->mutex);
|
||||
@@ -802,6 +816,10 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)
|
||||
/* Transaction should already have been freed */
|
||||
BUG_ON(buffer->transaction);
|
||||
|
||||
if (buffer->clear_on_free) {
|
||||
binder_alloc_clear_buf(alloc, buffer);
|
||||
buffer->clear_on_free = false;
|
||||
}
|
||||
binder_free_buf_locked(alloc, buffer);
|
||||
buffers++;
|
||||
}
|
||||
@@ -1135,6 +1153,36 @@ static struct page *binder_alloc_get_page(struct binder_alloc *alloc,
|
||||
return lru_page->page_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* binder_alloc_clear_buf() - zero out buffer
|
||||
* @alloc: binder_alloc for this proc
|
||||
* @buffer: binder buffer to be cleared
|
||||
*
|
||||
* memset the given buffer to 0
|
||||
*/
|
||||
static void binder_alloc_clear_buf(struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffer)
|
||||
{
|
||||
size_t bytes = binder_alloc_buffer_size(alloc, buffer);
|
||||
binder_size_t buffer_offset = 0;
|
||||
|
||||
while (bytes) {
|
||||
unsigned long size;
|
||||
struct page *page;
|
||||
pgoff_t pgoff;
|
||||
void *kptr;
|
||||
|
||||
page = binder_alloc_get_page(alloc, buffer,
|
||||
buffer_offset, &pgoff);
|
||||
size = min_t(size_t, bytes, PAGE_SIZE - pgoff);
|
||||
kptr = kmap(page) + pgoff;
|
||||
memset(kptr, 0, size);
|
||||
kunmap(page);
|
||||
bytes -= size;
|
||||
buffer_offset += size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* binder_alloc_copy_user_to_buffer() - copy src user to tgt user
|
||||
* @alloc: binder_alloc for this proc
|
||||
|
Reference in New Issue
Block a user