android: binder: add extra size to allocator.
authorMartijn Coenen <maco@google.com>
Fri, 30 Sep 2016 12:05:40 +0000 (14:05 +0200)
committerMartijn Coenen <maco@android.com>
Mon, 31 Oct 2016 14:14:59 +0000 (15:14 +0100)
The binder_buffer allocator currently only allocates
space for the data and offsets buffers of a Parcel.
This change allows for requesting an additional chunk
of data in the buffer, which can for example be used
to hold additional meta-data about the transaction
(eg a security context).

Change-Id: I58ab9c383a2e1a3057aae6adaa596ce867f1b157
Signed-off-by: Martijn Coenen <maco@google.com>
drivers/android/binder.c

index ef42b10c41ad69a932d59b0322e7d2bbe856e793..83a6c1bbbad59ff17c369a508eb618c873b204cf 100644 (file)
@@ -303,6 +303,7 @@ struct binder_buffer {
        struct binder_node *target_node;
        size_t data_size;
        size_t offsets_size;
+       size_t extra_buffers_size;
        uint8_t data[0];
 };
 
@@ -670,7 +671,9 @@ err_no_vma:
 
 static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc,
                                              size_t data_size,
-                                             size_t offsets_size, int is_async)
+                                             size_t offsets_size,
+                                             size_t extra_buffers_size,
+                                             int is_async)
 {
        struct rb_node *n = proc->free_buffers.rb_node;
        struct binder_buffer *buffer;
@@ -678,7 +681,7 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc,
        struct rb_node *best_fit = NULL;
        void *has_page_addr;
        void *end_page_addr;
-       size_t size;
+       size_t size, data_offsets_size;
 
        if (proc->vma == NULL) {
                pr_err("%d: binder_alloc_buf, no vma\n",
@@ -686,15 +689,20 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc,
                return NULL;
        }
 
-       size = ALIGN(data_size, sizeof(void *)) +
+       data_offsets_size = ALIGN(data_size, sizeof(void *)) +
                ALIGN(offsets_size, sizeof(void *));
 
-       if (size < data_size || size < offsets_size) {
+       if (data_offsets_size < data_size || data_offsets_size < offsets_size) {
                binder_user_error("%d: got transaction with invalid size %zd-%zd\n",
                                proc->pid, data_size, offsets_size);
                return NULL;
        }
-
+       size = data_offsets_size + ALIGN(extra_buffers_size, sizeof(void *));
+       if (size < data_offsets_size || size < extra_buffers_size) {
+               binder_user_error("%d: got transaction with invalid extra_buffers_size %zd\n",
+                                 proc->pid, extra_buffers_size);
+               return NULL;
+       }
        if (is_async &&
            proc->free_async_space < size + sizeof(struct binder_buffer)) {
                binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
@@ -763,6 +771,7 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc,
                      proc->pid, size, buffer);
        buffer->data_size = data_size;
        buffer->offsets_size = offsets_size;
+       buffer->extra_buffers_size = extra_buffers_size;
        buffer->async_transaction = is_async;
        if (is_async) {
                proc->free_async_space -= size + sizeof(struct binder_buffer);
@@ -837,7 +846,8 @@ static void binder_free_buf(struct binder_proc *proc,
        buffer_size = binder_buffer_size(proc, buffer);
 
        size = ALIGN(buffer->data_size, sizeof(void *)) +
-               ALIGN(buffer->offsets_size, sizeof(void *));
+               ALIGN(buffer->offsets_size, sizeof(void *)) +
+               ALIGN(buffer->extra_buffers_size, sizeof(void *));
 
        binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
                     "%d: binder_free_buf %p size %zd buffer_size %zd\n",
@@ -1555,7 +1565,8 @@ err_fd_not_accepted:
 
 static void binder_transaction(struct binder_proc *proc,
                               struct binder_thread *thread,
-                              struct binder_transaction_data *tr, int reply)
+                              struct binder_transaction_data *tr, int reply,
+                              binder_size_t extra_buffers_size)
 {
        int ret;
        struct binder_transaction *t;
@@ -1699,20 +1710,22 @@ static void binder_transaction(struct binder_proc *proc,
 
        if (reply)
                binder_debug(BINDER_DEBUG_TRANSACTION,
-                            "%d:%d BC_REPLY %d -> %d:%d, data %016llx-%016llx size %lld-%lld\n",
+                            "%d:%d BC_REPLY %d -> %d:%d, data %016llx-%016llx size %lld-%lld-%lld\n",
                             proc->pid, thread->pid, t->debug_id,
                             target_proc->pid, target_thread->pid,
                             (u64)tr->data.ptr.buffer,
                             (u64)tr->data.ptr.offsets,
-                            (u64)tr->data_size, (u64)tr->offsets_size);
+                            (u64)tr->data_size, (u64)tr->offsets_size,
+                            (u64)extra_buffers_size);
        else
                binder_debug(BINDER_DEBUG_TRANSACTION,
-                            "%d:%d BC_TRANSACTION %d -> %d - node %d, data %016llx-%016llx size %lld-%lld\n",
+                            "%d:%d BC_TRANSACTION %d -> %d - node %d, data %016llx-%016llx size %lld-%lld-%lld\n",
                             proc->pid, thread->pid, t->debug_id,
                             target_proc->pid, target_node->debug_id,
                             (u64)tr->data.ptr.buffer,
                             (u64)tr->data.ptr.offsets,
-                            (u64)tr->data_size, (u64)tr->offsets_size);
+                            (u64)tr->data_size, (u64)tr->offsets_size,
+                            (u64)extra_buffers_size);
 
        if (!reply && !(tr->flags & TF_ONE_WAY))
                t->from = thread;
@@ -1728,7 +1741,8 @@ static void binder_transaction(struct binder_proc *proc,
        trace_binder_transaction(reply, t, target_node);
 
        t->buffer = binder_alloc_buf(target_proc, tr->data_size,
-               tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
+               tr->offsets_size, extra_buffers_size,
+               !reply && (t->flags & TF_ONE_WAY));
        if (t->buffer == NULL) {
                return_error = BR_FAILED_REPLY;
                goto err_binder_alloc_buf_failed;
@@ -2078,7 +2092,8 @@ static int binder_thread_write(struct binder_proc *proc,
                        if (copy_from_user(&tr, ptr, sizeof(tr)))
                                return -EFAULT;
                        ptr += sizeof(tr);
-                       binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
+                       binder_transaction(proc, thread, &tr,
+                                          cmd == BC_REPLY, 0);
                        break;
                }