thermal: rockchip: rk3368: ajust tsadc's data path according request of qos
[firefly-linux-kernel-4.4.55.git] / drivers / android / binder.c
index a39e85f9efa98854768f39b01502274401673957..6c24673990bbf16fa8267f1c9d3333eabbe4bb24 100644 (file)
@@ -50,14 +50,13 @@ static DEFINE_MUTEX(binder_main_lock);
 static DEFINE_MUTEX(binder_deferred_lock);
 static DEFINE_MUTEX(binder_mmap_lock);
 
+static HLIST_HEAD(binder_devices);
 static HLIST_HEAD(binder_procs);
 static HLIST_HEAD(binder_deferred_list);
 static HLIST_HEAD(binder_dead_nodes);
 
 static struct dentry *binder_debugfs_dir_entry_root;
 static struct dentry *binder_debugfs_dir_entry_proc;
-static struct binder_node *binder_context_mgr_node;
-static kuid_t binder_context_mgr_uid = INVALID_UID;
 static int binder_last_id;
 static struct workqueue_struct *binder_deferred_workqueue;
 
@@ -116,6 +115,9 @@ module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO);
 static bool binder_debug_no_lock;
 module_param_named(proc_no_lock, binder_debug_no_lock, bool, S_IWUSR | S_IRUGO);
 
+static char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES;
+module_param_named(devices, binder_devices_param, charp, S_IRUGO);
+
 static DECLARE_WAIT_QUEUE_HEAD(binder_user_error_wait);
 static int binder_stop_on_user_error;
 
@@ -146,6 +148,17 @@ module_param_call(stop_on_user_error, binder_set_stop_on_user_error,
                        binder_stop_on_user_error = 2; \
        } while (0)
 
+#define to_flat_binder_object(hdr) \
+       container_of(hdr, struct flat_binder_object, hdr)
+
+#define to_binder_fd_object(hdr) container_of(hdr, struct binder_fd_object, hdr)
+
+#define to_binder_buffer_object(hdr) \
+       container_of(hdr, struct binder_buffer_object, hdr)
+
+#define to_binder_fd_array_object(hdr) \
+       container_of(hdr, struct binder_fd_array_object, hdr)
+
 enum binder_stat_types {
        BINDER_STAT_PROC,
        BINDER_STAT_THREAD,
@@ -159,7 +172,7 @@ enum binder_stat_types {
 
 struct binder_stats {
        int br[_IOC_NR(BR_FAILED_REPLY) + 1];
-       int bc[_IOC_NR(BC_DEAD_BINDER_DONE) + 1];
+       int bc[_IOC_NR(BC_REPLY_SG) + 1];
        int obj_created[BINDER_STAT_COUNT];
        int obj_deleted[BINDER_STAT_COUNT];
 };
@@ -187,6 +200,7 @@ struct binder_transaction_log_entry {
        int to_node;
        int data_size;
        int offsets_size;
+       const char *context_name;
 };
 struct binder_transaction_log {
        int next;
@@ -211,6 +225,18 @@ static struct binder_transaction_log_entry *binder_transaction_log_add(
        return e;
 }
 
+struct binder_context {
+       struct binder_node *binder_context_mgr_node;
+       kuid_t binder_context_mgr_uid;
+       const char *name;
+};
+
+struct binder_device {
+       struct hlist_node hlist;
+       struct miscdevice miscdev;
+       struct binder_context context;
+};
+
 struct binder_work {
        struct list_head entry;
        enum {
@@ -283,6 +309,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];
 };
 
@@ -326,6 +353,7 @@ struct binder_proc {
        int ready_threads;
        long default_priority;
        struct dentry *debugfs_entry;
+       struct binder_context *context;
 };
 
 enum {
@@ -649,7 +677,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;
@@ -657,7 +687,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",
@@ -665,15 +695,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,
@@ -742,6 +777,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);
@@ -816,7 +852,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",
@@ -930,8 +967,10 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal,
                if (internal) {
                        if (target_list == NULL &&
                            node->internal_strong_refs == 0 &&
-                           !(node == binder_context_mgr_node &&
-                           node->has_strong_ref)) {
+                           !(node->proc &&
+                             node == node->proc->context->
+                                     binder_context_mgr_node &&
+                             node->has_strong_ref)) {
                                pr_err("invalid inc strong node for %d\n",
                                        node->debug_id);
                                return -EINVAL;
@@ -1003,7 +1042,7 @@ static int binder_dec_node(struct binder_node *node, int strong, int internal)
 
 
 static struct binder_ref *binder_get_ref(struct binder_proc *proc,
-                                        uint32_t desc)
+                                        u32 desc, bool need_strong_ref)
 {
        struct rb_node *n = proc->refs_by_desc.rb_node;
        struct binder_ref *ref;
@@ -1011,12 +1050,16 @@ static struct binder_ref *binder_get_ref(struct binder_proc *proc,
        while (n) {
                ref = rb_entry(n, struct binder_ref, rb_node_desc);
 
-               if (desc < ref->desc)
+               if (desc < ref->desc) {
                        n = n->rb_left;
-               else if (desc > ref->desc)
+               } else if (desc > ref->desc) {
                        n = n->rb_right;
-               else
+               } else if (need_strong_ref && !ref->strong) {
+                       binder_user_error("tried to use weak ref as strong ref\n");
+                       return NULL;
+               } else {
                        return ref;
+               }
        }
        return NULL;
 }
@@ -1028,6 +1071,7 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc,
        struct rb_node **p = &proc->refs_by_node.rb_node;
        struct rb_node *parent = NULL;
        struct binder_ref *ref, *new_ref;
+       struct binder_context *context = proc->context;
 
        while (*p) {
                parent = *p;
@@ -1050,7 +1094,7 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc,
        rb_link_node(&new_ref->rb_node_node, parent, p);
        rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node);
 
-       new_ref->desc = (node == binder_context_mgr_node) ? 0 : 1;
+       new_ref->desc = (node == context->binder_context_mgr_node) ? 0 : 1;
        for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) {
                ref = rb_entry(n, struct binder_ref, rb_node_desc);
                if (ref->desc > new_ref->desc)
@@ -1237,11 +1281,158 @@ static void binder_send_failed_reply(struct binder_transaction *t,
        }
 }
 
+/**
+ * binder_validate_object() - checks for a valid metadata object in a buffer.
+ * @buffer:    binder_buffer that we're parsing.
+ * @offset:    offset in the buffer at which to validate an object.
+ *
+ * Return:     If there's a valid metadata object at @offset in @buffer, the
+ *             size of that object. Otherwise, it returns zero.
+ */
+static size_t binder_validate_object(struct binder_buffer *buffer, u64 offset)
+{
+       /* Check if we can read a header first */
+       struct binder_object_header *hdr;
+       size_t object_size = 0;
+
+       if (offset > buffer->data_size - sizeof(*hdr) ||
+           buffer->data_size < sizeof(*hdr) ||
+           !IS_ALIGNED(offset, sizeof(u32)))
+               return 0;
+
+       /* Ok, now see if we can read a complete object. */
+       hdr = (struct binder_object_header *)(buffer->data + offset);
+       switch (hdr->type) {
+       case BINDER_TYPE_BINDER:
+       case BINDER_TYPE_WEAK_BINDER:
+       case BINDER_TYPE_HANDLE:
+       case BINDER_TYPE_WEAK_HANDLE:
+               object_size = sizeof(struct flat_binder_object);
+               break;
+       case BINDER_TYPE_FD:
+               object_size = sizeof(struct binder_fd_object);
+               break;
+       case BINDER_TYPE_PTR:
+               object_size = sizeof(struct binder_buffer_object);
+               break;
+       case BINDER_TYPE_FDA:
+               object_size = sizeof(struct binder_fd_array_object);
+               break;
+       default:
+               return 0;
+       }
+       if (offset <= buffer->data_size - object_size &&
+           buffer->data_size >= object_size)
+               return object_size;
+       else
+               return 0;
+}
+
+/**
+ * binder_validate_ptr() - validates binder_buffer_object in a binder_buffer.
+ * @b:         binder_buffer containing the object
+ * @index:     index in offset array at which the binder_buffer_object is
+ *             located
+ * @start:     points to the start of the offset array
+ * @num_valid: the number of valid offsets in the offset array
+ *
+ * Return:     If @index is within the valid range of the offset array
+ *             described by @start and @num_valid, and if there's a valid
+ *             binder_buffer_object at the offset found in index @index
+ *             of the offset array, that object is returned. Otherwise,
+ *             %NULL is returned.
+ *             Note that the offset found in index @index itself is not
+ *             verified; this function assumes that @num_valid elements
+ *             from @start were previously verified to have valid offsets.
+ */
+static struct binder_buffer_object *binder_validate_ptr(struct binder_buffer *b,
+                                                       binder_size_t index,
+                                                       binder_size_t *start,
+                                                       binder_size_t num_valid)
+{
+       struct binder_buffer_object *buffer_obj;
+       binder_size_t *offp;
+
+       if (index >= num_valid)
+               return NULL;
+
+       offp = start + index;
+       buffer_obj = (struct binder_buffer_object *)(b->data + *offp);
+       if (buffer_obj->hdr.type != BINDER_TYPE_PTR)
+               return NULL;
+
+       return buffer_obj;
+}
+
+/**
+ * binder_validate_fixup() - validates pointer/fd fixups happen in order.
+ * @b:                 transaction buffer
+ * @objects_start      start of objects buffer
+ * @buffer:            binder_buffer_object in which to fix up
+ * @offset:            start offset in @buffer to fix up
+ * @last_obj:          last binder_buffer_object that we fixed up in
+ * @last_min_offset:   minimum fixup offset in @last_obj
+ *
+ * Return:             %true if a fixup in buffer @buffer at offset @offset is
+ *                     allowed.
+ *
+ * For safety reasons, we only allow fixups inside a buffer to happen
+ * at increasing offsets; additionally, we only allow fixup on the last
+ * buffer object that was verified, or one of its parents.
+ *
+ * Example of what is allowed:
+ *
+ * A
+ *   B (parent = A, offset = 0)
+ *   C (parent = A, offset = 16)
+ *     D (parent = C, offset = 0)
+ *   E (parent = A, offset = 32) // min_offset is 16 (C.parent_offset)
+ *
+ * Examples of what is not allowed:
+ *
+ * Decreasing offsets within the same parent:
+ * A
+ *   C (parent = A, offset = 16)
+ *   B (parent = A, offset = 0) // decreasing offset within A
+ *
+ * Referring to a parent that wasn't the last object or any of its parents:
+ * A
+ *   B (parent = A, offset = 0)
+ *   C (parent = A, offset = 0)
+ *   C (parent = A, offset = 16)
+ *     D (parent = B, offset = 0) // B is not A or any of A's parents
+ */
+static bool binder_validate_fixup(struct binder_buffer *b,
+                                 binder_size_t *objects_start,
+                                 struct binder_buffer_object *buffer,
+                                 binder_size_t fixup_offset,
+                                 struct binder_buffer_object *last_obj,
+                                 binder_size_t last_min_offset)
+{
+       if (!last_obj) {
+               /* Nothing to fix up in */
+               return false;
+       }
+
+       while (last_obj != buffer) {
+               /*
+                * Safe to retrieve the parent of last_obj, since it
+                * was already previously verified by the driver.
+                */
+               if ((last_obj->flags & BINDER_BUFFER_FLAG_HAS_PARENT) == 0)
+                       return false;
+               last_min_offset = last_obj->parent_offset + sizeof(uintptr_t);
+               last_obj = (struct binder_buffer_object *)
+                       (b->data + *(objects_start + last_obj->parent));
+       }
+       return (fixup_offset >= last_min_offset);
+}
+
 static void binder_transaction_buffer_release(struct binder_proc *proc,
                                              struct binder_buffer *buffer,
                                              binder_size_t *failed_at)
 {
-       binder_size_t *offp, *off_end;
+       binder_size_t *offp, *off_start, *off_end;
        int debug_id = buffer->debug_id;
 
        binder_debug(BINDER_DEBUG_TRANSACTION,
@@ -1252,28 +1443,30 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
        if (buffer->target_node)
                binder_dec_node(buffer->target_node, 1, 0);
 
-       offp = (binder_size_t *)(buffer->data +
-                                ALIGN(buffer->data_size, sizeof(void *)));
+       off_start = (binder_size_t *)(buffer->data +
+                                     ALIGN(buffer->data_size, sizeof(void *)));
        if (failed_at)
                off_end = failed_at;
        else
-               off_end = (void *)offp + buffer->offsets_size;
-       for (; offp < off_end; offp++) {
-               struct flat_binder_object *fp;
+               off_end = (void *)off_start + buffer->offsets_size;
+       for (offp = off_start; offp < off_end; offp++) {
+               struct binder_object_header *hdr;
+               size_t object_size = binder_validate_object(buffer, *offp);
 
-               if (*offp > buffer->data_size - sizeof(*fp) ||
-                   buffer->data_size < sizeof(*fp) ||
-                   !IS_ALIGNED(*offp, sizeof(u32))) {
-                       pr_err("transaction release %d bad offset %lld, size %zd\n",
+               if (object_size == 0) {
+                       pr_err("transaction release %d bad object at offset %lld, size %zd\n",
                               debug_id, (u64)*offp, buffer->data_size);
                        continue;
                }
-               fp = (struct flat_binder_object *)(buffer->data + *offp);
-               switch (fp->type) {
+               hdr = (struct binder_object_header *)(buffer->data + *offp);
+               switch (hdr->type) {
                case BINDER_TYPE_BINDER:
                case BINDER_TYPE_WEAK_BINDER: {
-                       struct binder_node *node = binder_get_node(proc, fp->binder);
+                       struct flat_binder_object *fp;
+                       struct binder_node *node;
 
+                       fp = to_flat_binder_object(hdr);
+                       node = binder_get_node(proc, fp->binder);
                        if (node == NULL) {
                                pr_err("transaction release %d bad node %016llx\n",
                                       debug_id, (u64)fp->binder);
@@ -1282,11 +1475,17 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
                        binder_debug(BINDER_DEBUG_TRANSACTION,
                                     "        node %d u%016llx\n",
                                     node->debug_id, (u64)node->ptr);
-                       binder_dec_node(node, fp->type == BINDER_TYPE_BINDER, 0);
+                       binder_dec_node(node, hdr->type == BINDER_TYPE_BINDER,
+                                       0);
                } break;
                case BINDER_TYPE_HANDLE:
                case BINDER_TYPE_WEAK_HANDLE: {
-                       struct binder_ref *ref = binder_get_ref(proc, fp->handle);
+                       struct flat_binder_object *fp;
+                       struct binder_ref *ref;
+
+                       fp = to_flat_binder_object(hdr);
+                       ref = binder_get_ref(proc, fp->handle,
+                                            hdr->type == BINDER_TYPE_HANDLE);
 
                        if (ref == NULL) {
                                pr_err("transaction release %d bad handle %d\n",
@@ -1296,31 +1495,348 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
                        binder_debug(BINDER_DEBUG_TRANSACTION,
                                     "        ref %d desc %d (node %d)\n",
                                     ref->debug_id, ref->desc, ref->node->debug_id);
-                       binder_dec_ref(ref, fp->type == BINDER_TYPE_HANDLE);
+                       binder_dec_ref(ref, hdr->type == BINDER_TYPE_HANDLE);
                } break;
 
-               case BINDER_TYPE_FD:
+               case BINDER_TYPE_FD: {
+                       struct binder_fd_object *fp = to_binder_fd_object(hdr);
+
                        binder_debug(BINDER_DEBUG_TRANSACTION,
-                                    "        fd %d\n", fp->handle);
+                                    "        fd %d\n", fp->fd);
                        if (failed_at)
-                               task_close_fd(proc, fp->handle);
+                               task_close_fd(proc, fp->fd);
+               } break;
+               case BINDER_TYPE_PTR:
+                       /*
+                        * Nothing to do here, this will get cleaned up when the
+                        * transaction buffer gets freed
+                        */
                        break;
-
+               case BINDER_TYPE_FDA: {
+                       struct binder_fd_array_object *fda;
+                       struct binder_buffer_object *parent;
+                       uintptr_t parent_buffer;
+                       u32 *fd_array;
+                       size_t fd_index;
+                       binder_size_t fd_buf_size;
+
+                       fda = to_binder_fd_array_object(hdr);
+                       parent = binder_validate_ptr(buffer, fda->parent,
+                                                    off_start,
+                                                    offp - off_start);
+                       if (!parent) {
+                               pr_err("transaction release %d bad parent offset",
+                                      debug_id);
+                               continue;
+                       }
+                       /*
+                        * Since the parent was already fixed up, convert it
+                        * back to kernel address space to access it
+                        */
+                       parent_buffer = parent->buffer -
+                               proc->user_buffer_offset;
+
+                       fd_buf_size = sizeof(u32) * fda->num_fds;
+                       if (fda->num_fds >= SIZE_MAX / sizeof(u32)) {
+                               pr_err("transaction release %d invalid number of fds (%lld)\n",
+                                      debug_id, (u64)fda->num_fds);
+                               continue;
+                       }
+                       if (fd_buf_size > parent->length ||
+                           fda->parent_offset > parent->length - fd_buf_size) {
+                               /* No space for all file descriptors here. */
+                               pr_err("transaction release %d not enough space for %lld fds in buffer\n",
+                                      debug_id, (u64)fda->num_fds);
+                               continue;
+                       }
+                       fd_array = (u32 *)(parent_buffer + fda->parent_offset);
+                       for (fd_index = 0; fd_index < fda->num_fds; fd_index++)
+                               task_close_fd(proc, fd_array[fd_index]);
+               } break;
                default:
                        pr_err("transaction release %d bad object type %x\n",
-                               debug_id, fp->type);
+                               debug_id, hdr->type);
                        break;
                }
        }
 }
 
+static int binder_translate_binder(struct flat_binder_object *fp,
+                                  struct binder_transaction *t,
+                                  struct binder_thread *thread)
+{
+       struct binder_node *node;
+       struct binder_ref *ref;
+       struct binder_proc *proc = thread->proc;
+       struct binder_proc *target_proc = t->to_proc;
+
+       node = binder_get_node(proc, fp->binder);
+       if (!node) {
+               node = binder_new_node(proc, fp->binder, fp->cookie);
+               if (!node)
+                       return -ENOMEM;
+
+               node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
+               node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
+       }
+       if (fp->cookie != node->cookie) {
+               binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n",
+                                 proc->pid, thread->pid, (u64)fp->binder,
+                                 node->debug_id, (u64)fp->cookie,
+                                 (u64)node->cookie);
+               return -EINVAL;
+       }
+       if (security_binder_transfer_binder(proc->tsk, target_proc->tsk))
+               return -EPERM;
+
+       ref = binder_get_ref_for_node(target_proc, node);
+       if (!ref)
+               return -EINVAL;
+
+       if (fp->hdr.type == BINDER_TYPE_BINDER)
+               fp->hdr.type = BINDER_TYPE_HANDLE;
+       else
+               fp->hdr.type = BINDER_TYPE_WEAK_HANDLE;
+       fp->binder = 0;
+       fp->handle = ref->desc;
+       fp->cookie = 0;
+       binder_inc_ref(ref, fp->hdr.type == BINDER_TYPE_HANDLE, &thread->todo);
+
+       trace_binder_transaction_node_to_ref(t, node, ref);
+       binder_debug(BINDER_DEBUG_TRANSACTION,
+                    "        node %d u%016llx -> ref %d desc %d\n",
+                    node->debug_id, (u64)node->ptr,
+                    ref->debug_id, ref->desc);
+
+       return 0;
+}
+
+static int binder_translate_handle(struct flat_binder_object *fp,
+                                  struct binder_transaction *t,
+                                  struct binder_thread *thread)
+{
+       struct binder_ref *ref;
+       struct binder_proc *proc = thread->proc;
+       struct binder_proc *target_proc = t->to_proc;
+
+       ref = binder_get_ref(proc, fp->handle,
+                            fp->hdr.type == BINDER_TYPE_HANDLE);
+       if (!ref) {
+               binder_user_error("%d:%d got transaction with invalid handle, %d\n",
+                                 proc->pid, thread->pid, fp->handle);
+               return -EINVAL;
+       }
+       if (security_binder_transfer_binder(proc->tsk, target_proc->tsk))
+               return -EPERM;
+
+       if (ref->node->proc == target_proc) {
+               if (fp->hdr.type == BINDER_TYPE_HANDLE)
+                       fp->hdr.type = BINDER_TYPE_BINDER;
+               else
+                       fp->hdr.type = BINDER_TYPE_WEAK_BINDER;
+               fp->binder = ref->node->ptr;
+               fp->cookie = ref->node->cookie;
+               binder_inc_node(ref->node, fp->hdr.type == BINDER_TYPE_BINDER,
+                               0, NULL);
+               trace_binder_transaction_ref_to_node(t, ref);
+               binder_debug(BINDER_DEBUG_TRANSACTION,
+                            "        ref %d desc %d -> node %d u%016llx\n",
+                            ref->debug_id, ref->desc, ref->node->debug_id,
+                            (u64)ref->node->ptr);
+       } else {
+               struct binder_ref *new_ref;
+
+               new_ref = binder_get_ref_for_node(target_proc, ref->node);
+               if (!new_ref)
+                       return -EINVAL;
+
+               fp->binder = 0;
+               fp->handle = new_ref->desc;
+               fp->cookie = 0;
+               binder_inc_ref(new_ref, fp->hdr.type == BINDER_TYPE_HANDLE,
+                              NULL);
+               trace_binder_transaction_ref_to_ref(t, ref, new_ref);
+               binder_debug(BINDER_DEBUG_TRANSACTION,
+                            "        ref %d desc %d -> ref %d desc %d (node %d)\n",
+                            ref->debug_id, ref->desc, new_ref->debug_id,
+                            new_ref->desc, ref->node->debug_id);
+       }
+       return 0;
+}
+
+static int binder_translate_fd(int fd,
+                              struct binder_transaction *t,
+                              struct binder_thread *thread,
+                              struct binder_transaction *in_reply_to)
+{
+       struct binder_proc *proc = thread->proc;
+       struct binder_proc *target_proc = t->to_proc;
+       int target_fd;
+       struct file *file;
+       int ret;
+       bool target_allows_fd;
+
+       if (in_reply_to)
+               target_allows_fd = !!(in_reply_to->flags & TF_ACCEPT_FDS);
+       else
+               target_allows_fd = t->buffer->target_node->accept_fds;
+       if (!target_allows_fd) {
+               binder_user_error("%d:%d got %s with fd, %d, but target does not allow fds\n",
+                                 proc->pid, thread->pid,
+                                 in_reply_to ? "reply" : "transaction",
+                                 fd);
+               ret = -EPERM;
+               goto err_fd_not_accepted;
+       }
+
+       file = fget(fd);
+       if (!file) {
+               binder_user_error("%d:%d got transaction with invalid fd, %d\n",
+                                 proc->pid, thread->pid, fd);
+               ret = -EBADF;
+               goto err_fget;
+       }
+       ret = security_binder_transfer_file(proc->tsk, target_proc->tsk, file);
+       if (ret < 0) {
+               ret = -EPERM;
+               goto err_security;
+       }
+
+       target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
+       if (target_fd < 0) {
+               ret = -ENOMEM;
+               goto err_get_unused_fd;
+       }
+       task_fd_install(target_proc, target_fd, file);
+       trace_binder_transaction_fd(t, fd, target_fd);
+       binder_debug(BINDER_DEBUG_TRANSACTION, "        fd %d -> %d\n",
+                    fd, target_fd);
+
+       return target_fd;
+
+err_get_unused_fd:
+err_security:
+       fput(file);
+err_fget:
+err_fd_not_accepted:
+       return ret;
+}
+
+static int binder_translate_fd_array(struct binder_fd_array_object *fda,
+                                    struct binder_buffer_object *parent,
+                                    struct binder_transaction *t,
+                                    struct binder_thread *thread,
+                                    struct binder_transaction *in_reply_to)
+{
+       binder_size_t fdi, fd_buf_size, num_installed_fds;
+       int target_fd;
+       uintptr_t parent_buffer;
+       u32 *fd_array;
+       struct binder_proc *proc = thread->proc;
+       struct binder_proc *target_proc = t->to_proc;
+
+       fd_buf_size = sizeof(u32) * fda->num_fds;
+       if (fda->num_fds >= SIZE_MAX / sizeof(u32)) {
+               binder_user_error("%d:%d got transaction with invalid number of fds (%lld)\n",
+                                 proc->pid, thread->pid, (u64)fda->num_fds);
+               return -EINVAL;
+       }
+       if (fd_buf_size > parent->length ||
+           fda->parent_offset > parent->length - fd_buf_size) {
+               /* No space for all file descriptors here. */
+               binder_user_error("%d:%d not enough space to store %lld fds in buffer\n",
+                                 proc->pid, thread->pid, (u64)fda->num_fds);
+               return -EINVAL;
+       }
+       /*
+        * Since the parent was already fixed up, convert it
+        * back to the kernel address space to access it
+        */
+       parent_buffer = parent->buffer - target_proc->user_buffer_offset;
+       fd_array = (u32 *)(parent_buffer + fda->parent_offset);
+       if (!IS_ALIGNED((unsigned long)fd_array, sizeof(u32))) {
+               binder_user_error("%d:%d parent offset not aligned correctly.\n",
+                                 proc->pid, thread->pid);
+               return -EINVAL;
+       }
+       for (fdi = 0; fdi < fda->num_fds; fdi++) {
+               target_fd = binder_translate_fd(fd_array[fdi], t, thread,
+                                               in_reply_to);
+               if (target_fd < 0)
+                       goto err_translate_fd_failed;
+               fd_array[fdi] = target_fd;
+       }
+       return 0;
+
+err_translate_fd_failed:
+       /*
+        * Failed to allocate fd or security error, free fds
+        * installed so far.
+        */
+       num_installed_fds = fdi;
+       for (fdi = 0; fdi < num_installed_fds; fdi++)
+               task_close_fd(target_proc, fd_array[fdi]);
+       return target_fd;
+}
+
+static int binder_fixup_parent(struct binder_transaction *t,
+                              struct binder_thread *thread,
+                              struct binder_buffer_object *bp,
+                              binder_size_t *off_start,
+                              binder_size_t num_valid,
+                              struct binder_buffer_object *last_fixup_obj,
+                              binder_size_t last_fixup_min_off)
+{
+       struct binder_buffer_object *parent;
+       u8 *parent_buffer;
+       struct binder_buffer *b = t->buffer;
+       struct binder_proc *proc = thread->proc;
+       struct binder_proc *target_proc = t->to_proc;
+
+       if (!(bp->flags & BINDER_BUFFER_FLAG_HAS_PARENT))
+               return 0;
+
+       parent = binder_validate_ptr(b, bp->parent, off_start, num_valid);
+       if (!parent) {
+               binder_user_error("%d:%d got transaction with invalid parent offset or type\n",
+                                 proc->pid, thread->pid);
+               return -EINVAL;
+       }
+
+       if (!binder_validate_fixup(b, off_start,
+                                  parent, bp->parent_offset,
+                                  last_fixup_obj,
+                                  last_fixup_min_off)) {
+               binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n",
+                                 proc->pid, thread->pid);
+               return -EINVAL;
+       }
+
+       if (parent->length < sizeof(binder_uintptr_t) ||
+           bp->parent_offset > parent->length - sizeof(binder_uintptr_t)) {
+               /* No space for a pointer here! */
+               binder_user_error("%d:%d got transaction with invalid parent offset\n",
+                                 proc->pid, thread->pid);
+               return -EINVAL;
+       }
+       parent_buffer = (u8 *)(parent->buffer -
+                              target_proc->user_buffer_offset);
+       *(binder_uintptr_t *)(parent_buffer + bp->parent_offset) = bp->buffer;
+
+       return 0;
+}
+
 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;
        struct binder_work *tcomplete;
-       binder_size_t *offp, *off_end;
+       binder_size_t *offp, *off_end, *off_start;
+       binder_size_t off_min;
+       u8 *sg_bufp, *sg_buf_end;
        struct binder_proc *target_proc;
        struct binder_thread *target_thread = NULL;
        struct binder_node *target_node = NULL;
@@ -1329,6 +1845,9 @@ static void binder_transaction(struct binder_proc *proc,
        struct binder_transaction *in_reply_to = NULL;
        struct binder_transaction_log_entry *e;
        uint32_t return_error;
+       struct binder_buffer_object *last_fixup_obj = NULL;
+       binder_size_t last_fixup_min_off = 0;
+       struct binder_context *context = proc->context;
 
        e = binder_transaction_log_add(&binder_transaction_log);
        e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY);
@@ -1337,6 +1856,7 @@ static void binder_transaction(struct binder_proc *proc,
        e->target_handle = tr->target.handle;
        e->data_size = tr->data_size;
        e->offsets_size = tr->offsets_size;
+       e->context_name = proc->context->name;
 
        if (reply) {
                in_reply_to = thread->transaction_stack;
@@ -1380,7 +1900,7 @@ static void binder_transaction(struct binder_proc *proc,
                if (tr->target.handle) {
                        struct binder_ref *ref;
 
-                       ref = binder_get_ref(proc, tr->target.handle);
+                       ref = binder_get_ref(proc, tr->target.handle, true);
                        if (ref == NULL) {
                                binder_user_error("%d:%d got transaction to invalid handle\n",
                                        proc->pid, thread->pid);
@@ -1389,7 +1909,7 @@ static void binder_transaction(struct binder_proc *proc,
                        }
                        target_node = ref->node;
                } else {
-                       target_node = binder_context_mgr_node;
+                       target_node = context->binder_context_mgr_node;
                        if (target_node == NULL) {
                                return_error = BR_DEAD_REPLY;
                                goto err_no_context_mgr_node;
@@ -1456,20 +1976,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;
@@ -1485,7 +2007,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;
@@ -1498,8 +2021,9 @@ static void binder_transaction(struct binder_proc *proc,
        if (target_node)
                binder_inc_node(target_node, 1, 0, NULL);
 
-       offp = (binder_size_t *)(t->buffer->data +
-                                ALIGN(tr->data_size, sizeof(void *)));
+       off_start = (binder_size_t *)(t->buffer->data +
+                                     ALIGN(tr->data_size, sizeof(void *)));
+       offp = off_start;
 
        if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
                           tr->data.ptr.buffer, tr->data_size)) {
@@ -1521,163 +2045,138 @@ static void binder_transaction(struct binder_proc *proc,
                return_error = BR_FAILED_REPLY;
                goto err_bad_offset;
        }
-       off_end = (void *)offp + tr->offsets_size;
+       if (!IS_ALIGNED(extra_buffers_size, sizeof(u64))) {
+               binder_user_error("%d:%d got transaction with unaligned buffers size, %lld\n",
+                                 proc->pid, thread->pid,
+                                 (u64)extra_buffers_size);
+               return_error = BR_FAILED_REPLY;
+               goto err_bad_offset;
+       }
+       off_end = (void *)off_start + tr->offsets_size;
+       sg_bufp = (u8 *)(PTR_ALIGN(off_end, sizeof(void *)));
+       sg_buf_end = sg_bufp + extra_buffers_size;
+       off_min = 0;
        for (; offp < off_end; offp++) {
-               struct flat_binder_object *fp;
-
-               if (*offp > t->buffer->data_size - sizeof(*fp) ||
-                   t->buffer->data_size < sizeof(*fp) ||
-                   !IS_ALIGNED(*offp, sizeof(u32))) {
-                       binder_user_error("%d:%d got transaction with invalid offset, %lld\n",
-                                         proc->pid, thread->pid, (u64)*offp);
+               struct binder_object_header *hdr;
+               size_t object_size = binder_validate_object(t->buffer, *offp);
+
+               if (object_size == 0 || *offp < off_min) {
+                       binder_user_error("%d:%d got transaction with invalid offset (%lld, min %lld max %lld) or object.\n",
+                                         proc->pid, thread->pid, (u64)*offp,
+                                         (u64)off_min,
+                                         (u64)t->buffer->data_size);
                        return_error = BR_FAILED_REPLY;
                        goto err_bad_offset;
                }
-               fp = (struct flat_binder_object *)(t->buffer->data + *offp);
-               switch (fp->type) {
+
+               hdr = (struct binder_object_header *)(t->buffer->data + *offp);
+               off_min = *offp + object_size;
+               switch (hdr->type) {
                case BINDER_TYPE_BINDER:
                case BINDER_TYPE_WEAK_BINDER: {
-                       struct binder_ref *ref;
-                       struct binder_node *node = binder_get_node(proc, fp->binder);
+                       struct flat_binder_object *fp;
 
-                       if (node == NULL) {
-                               node = binder_new_node(proc, fp->binder, fp->cookie);
-                               if (node == NULL) {
-                                       return_error = BR_FAILED_REPLY;
-                                       goto err_binder_new_node_failed;
-                               }
-                               node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
-                               node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
-                       }
-                       if (fp->cookie != node->cookie) {
-                               binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n",
-                                       proc->pid, thread->pid,
-                                       (u64)fp->binder, node->debug_id,
-                                       (u64)fp->cookie, (u64)node->cookie);
-                               return_error = BR_FAILED_REPLY;
-                               goto err_binder_get_ref_for_node_failed;
-                       }
-                       if (security_binder_transfer_binder(proc->tsk,
-                                                           target_proc->tsk)) {
-                               return_error = BR_FAILED_REPLY;
-                               goto err_binder_get_ref_for_node_failed;
-                       }
-                       ref = binder_get_ref_for_node(target_proc, node);
-                       if (ref == NULL) {
+                       fp = to_flat_binder_object(hdr);
+                       ret = binder_translate_binder(fp, t, thread);
+                       if (ret < 0) {
                                return_error = BR_FAILED_REPLY;
-                               goto err_binder_get_ref_for_node_failed;
+                               goto err_translate_failed;
                        }
-                       if (fp->type == BINDER_TYPE_BINDER)
-                               fp->type = BINDER_TYPE_HANDLE;
-                       else
-                               fp->type = BINDER_TYPE_WEAK_HANDLE;
-                       fp->handle = ref->desc;
-                       binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
-                                      &thread->todo);
-
-                       trace_binder_transaction_node_to_ref(t, node, ref);
-                       binder_debug(BINDER_DEBUG_TRANSACTION,
-                                    "        node %d u%016llx -> ref %d desc %d\n",
-                                    node->debug_id, (u64)node->ptr,
-                                    ref->debug_id, ref->desc);
                } break;
                case BINDER_TYPE_HANDLE:
                case BINDER_TYPE_WEAK_HANDLE: {
-                       struct binder_ref *ref = binder_get_ref(proc, fp->handle);
+                       struct flat_binder_object *fp;
 
-                       if (ref == NULL) {
-                               binder_user_error("%d:%d got transaction with invalid handle, %d\n",
-                                               proc->pid,
-                                               thread->pid, fp->handle);
+                       fp = to_flat_binder_object(hdr);
+                       ret = binder_translate_handle(fp, t, thread);
+                       if (ret < 0) {
                                return_error = BR_FAILED_REPLY;
-                               goto err_binder_get_ref_failed;
-                       }
-                       if (security_binder_transfer_binder(proc->tsk,
-                                                           target_proc->tsk)) {
-                               return_error = BR_FAILED_REPLY;
-                               goto err_binder_get_ref_failed;
-                       }
-                       if (ref->node->proc == target_proc) {
-                               if (fp->type == BINDER_TYPE_HANDLE)
-                                       fp->type = BINDER_TYPE_BINDER;
-                               else
-                                       fp->type = BINDER_TYPE_WEAK_BINDER;
-                               fp->binder = ref->node->ptr;
-                               fp->cookie = ref->node->cookie;
-                               binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
-                               trace_binder_transaction_ref_to_node(t, ref);
-                               binder_debug(BINDER_DEBUG_TRANSACTION,
-                                            "        ref %d desc %d -> node %d u%016llx\n",
-                                            ref->debug_id, ref->desc, ref->node->debug_id,
-                                            (u64)ref->node->ptr);
-                       } else {
-                               struct binder_ref *new_ref;
-
-                               new_ref = binder_get_ref_for_node(target_proc, ref->node);
-                               if (new_ref == NULL) {
-                                       return_error = BR_FAILED_REPLY;
-                                       goto err_binder_get_ref_for_node_failed;
-                               }
-                               fp->handle = new_ref->desc;
-                               binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
-                               trace_binder_transaction_ref_to_ref(t, ref,
-                                                                   new_ref);
-                               binder_debug(BINDER_DEBUG_TRANSACTION,
-                                            "        ref %d desc %d -> ref %d desc %d (node %d)\n",
-                                            ref->debug_id, ref->desc, new_ref->debug_id,
-                                            new_ref->desc, ref->node->debug_id);
+                               goto err_translate_failed;
                        }
                } break;
 
                case BINDER_TYPE_FD: {
-                       int target_fd;
-                       struct file *file;
-
-                       if (reply) {
-                               if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {
-                                       binder_user_error("%d:%d got reply with fd, %d, but target does not allow fds\n",
-                                               proc->pid, thread->pid, fp->handle);
-                                       return_error = BR_FAILED_REPLY;
-                                       goto err_fd_not_allowed;
-                               }
-                       } else if (!target_node->accept_fds) {
-                               binder_user_error("%d:%d got transaction with fd, %d, but target does not allow fds\n",
-                                       proc->pid, thread->pid, fp->handle);
+                       struct binder_fd_object *fp = to_binder_fd_object(hdr);
+                       int target_fd = binder_translate_fd(fp->fd, t, thread,
+                                                           in_reply_to);
+
+                       if (target_fd < 0) {
                                return_error = BR_FAILED_REPLY;
-                               goto err_fd_not_allowed;
+                               goto err_translate_failed;
                        }
-
-                       file = fget(fp->handle);
-                       if (file == NULL) {
-                               binder_user_error("%d:%d got transaction with invalid fd, %d\n",
-                                       proc->pid, thread->pid, fp->handle);
+                       fp->pad_binder = 0;
+                       fp->fd = target_fd;
+               } break;
+               case BINDER_TYPE_FDA: {
+                       struct binder_fd_array_object *fda =
+                               to_binder_fd_array_object(hdr);
+                       struct binder_buffer_object *parent =
+                               binder_validate_ptr(t->buffer, fda->parent,
+                                                   off_start,
+                                                   offp - off_start);
+                       if (!parent) {
+                               binder_user_error("%d:%d got transaction with invalid parent offset or type\n",
+                                                 proc->pid, thread->pid);
                                return_error = BR_FAILED_REPLY;
-                               goto err_fget_failed;
+                               goto err_bad_parent;
                        }
-                       if (security_binder_transfer_file(proc->tsk,
-                                                         target_proc->tsk,
-                                                         file) < 0) {
-                               fput(file);
+                       if (!binder_validate_fixup(t->buffer, off_start,
+                                                  parent, fda->parent_offset,
+                                                  last_fixup_obj,
+                                                  last_fixup_min_off)) {
+                               binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n",
+                                                 proc->pid, thread->pid);
                                return_error = BR_FAILED_REPLY;
-                               goto err_get_unused_fd_failed;
+                               goto err_bad_parent;
                        }
-                       target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
-                       if (target_fd < 0) {
-                               fput(file);
+                       ret = binder_translate_fd_array(fda, parent, t, thread,
+                                                       in_reply_to);
+                       if (ret < 0) {
                                return_error = BR_FAILED_REPLY;
-                               goto err_get_unused_fd_failed;
+                               goto err_translate_failed;
                        }
-                       task_fd_install(target_proc, target_fd, file);
-                       trace_binder_transaction_fd(t, fp->handle, target_fd);
-                       binder_debug(BINDER_DEBUG_TRANSACTION,
-                                    "        fd %d -> %d\n", fp->handle, target_fd);
-                       /* TODO: fput? */
-                       fp->handle = target_fd;
+                       last_fixup_obj = parent;
+                       last_fixup_min_off =
+                               fda->parent_offset + sizeof(u32) * fda->num_fds;
+               } break;
+               case BINDER_TYPE_PTR: {
+                       struct binder_buffer_object *bp =
+                               to_binder_buffer_object(hdr);
+                       size_t buf_left = sg_buf_end - sg_bufp;
+
+                       if (bp->length > buf_left) {
+                               binder_user_error("%d:%d got transaction with too large buffer\n",
+                                                 proc->pid, thread->pid);
+                               return_error = BR_FAILED_REPLY;
+                               goto err_bad_offset;
+                       }
+                       if (copy_from_user(sg_bufp,
+                                          (const void __user *)(uintptr_t)
+                                          bp->buffer, bp->length)) {
+                               binder_user_error("%d:%d got transaction with invalid offsets ptr\n",
+                                                 proc->pid, thread->pid);
+                               return_error = BR_FAILED_REPLY;
+                               goto err_copy_data_failed;
+                       }
+                       /* Fixup buffer pointer to target proc address space */
+                       bp->buffer = (uintptr_t)sg_bufp +
+                               target_proc->user_buffer_offset;
+                       sg_bufp += ALIGN(bp->length, sizeof(u64));
+
+                       ret = binder_fixup_parent(t, thread, bp, off_start,
+                                                 offp - off_start,
+                                                 last_fixup_obj,
+                                                 last_fixup_min_off);
+                       if (ret < 0) {
+                               return_error = BR_FAILED_REPLY;
+                               goto err_translate_failed;
+                       }
+                       last_fixup_obj = bp;
+                       last_fixup_min_off = 0;
                } break;
-
                default:
                        binder_user_error("%d:%d got transaction with invalid object type, %x\n",
-                               proc->pid, thread->pid, fp->type);
+                               proc->pid, thread->pid, hdr->type);
                        return_error = BR_FAILED_REPLY;
                        goto err_bad_object_type;
                }
@@ -1707,14 +2206,10 @@ static void binder_transaction(struct binder_proc *proc,
                wake_up_interruptible(target_wait);
        return;
 
-err_get_unused_fd_failed:
-err_fget_failed:
-err_fd_not_allowed:
-err_binder_get_ref_for_node_failed:
-err_binder_get_ref_failed:
-err_binder_new_node_failed:
+err_translate_failed:
 err_bad_object_type:
 err_bad_offset:
+err_bad_parent:
 err_copy_data_failed:
        trace_binder_transaction_failed_buffer_release(t->buffer);
        binder_transaction_buffer_release(target_proc, t->buffer, offp);
@@ -1758,6 +2253,7 @@ static int binder_thread_write(struct binder_proc *proc,
                        binder_size_t *consumed)
 {
        uint32_t cmd;
+       struct binder_context *context = proc->context;
        void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
        void __user *ptr = buffer + *consumed;
        void __user *end = buffer + size;
@@ -1784,17 +2280,19 @@ static int binder_thread_write(struct binder_proc *proc,
                        if (get_user(target, (uint32_t __user *)ptr))
                                return -EFAULT;
                        ptr += sizeof(uint32_t);
-                       if (target == 0 && binder_context_mgr_node &&
+                       if (target == 0 && context->binder_context_mgr_node &&
                            (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) {
                                ref = binder_get_ref_for_node(proc,
-                                              binder_context_mgr_node);
+                                       context->binder_context_mgr_node);
                                if (ref->desc != target) {
                                        binder_user_error("%d:%d tried to acquire reference to desc 0, got %d instead\n",
                                                proc->pid, thread->pid,
                                                ref->desc);
                                }
                        } else
-                               ref = binder_get_ref(proc, target);
+                               ref = binder_get_ref(proc, target,
+                                                    cmd == BC_ACQUIRE ||
+                                                    cmd == BC_RELEASE);
                        if (ref == NULL) {
                                binder_user_error("%d:%d refcount change on invalid ref %d\n",
                                        proc->pid, thread->pid, target);
@@ -1930,6 +2428,17 @@ static int binder_thread_write(struct binder_proc *proc,
                        break;
                }
 
+               case BC_TRANSACTION_SG:
+               case BC_REPLY_SG: {
+                       struct binder_transaction_data_sg tr;
+
+                       if (copy_from_user(&tr, ptr, sizeof(tr)))
+                               return -EFAULT;
+                       ptr += sizeof(tr);
+                       binder_transaction(proc, thread, &tr.transaction_data,
+                                          cmd == BC_REPLY_SG, tr.buffers_size);
+                       break;
+               }
                case BC_TRANSACTION:
                case BC_REPLY: {
                        struct binder_transaction_data tr;
@@ -1937,7 +2446,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;
                }
 
@@ -1990,7 +2500,7 @@ static int binder_thread_write(struct binder_proc *proc,
                        if (get_user(cookie, (binder_uintptr_t __user *)ptr))
                                return -EFAULT;
                        ptr += sizeof(binder_uintptr_t);
-                       ref = binder_get_ref(proc, target);
+                       ref = binder_get_ref(proc, target, false);
                        if (ref == NULL) {
                                binder_user_error("%d:%d %s invalid ref %d\n",
                                        proc->pid, thread->pid,
@@ -2074,7 +2584,7 @@ static int binder_thread_write(struct binder_proc *proc,
                        if (get_user(cookie, (binder_uintptr_t __user *)ptr))
                                return -EFAULT;
 
-                       ptr += sizeof(void *);
+                       ptr += sizeof(cookie);
                        list_for_each_entry(w, &proc->delivered_death, entry) {
                                struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work);
 
@@ -2691,9 +3201,11 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp)
 {
        int ret = 0;
        struct binder_proc *proc = filp->private_data;
+       struct binder_context *context = proc->context;
+
        kuid_t curr_euid = current_euid();
 
-       if (binder_context_mgr_node != NULL) {
+       if (context->binder_context_mgr_node) {
                pr_err("BINDER_SET_CONTEXT_MGR already set\n");
                ret = -EBUSY;
                goto out;
@@ -2701,27 +3213,27 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp)
        ret = security_binder_set_context_mgr(proc->tsk);
        if (ret < 0)
                goto out;
-       if (uid_valid(binder_context_mgr_uid)) {
-               if (!uid_eq(binder_context_mgr_uid, curr_euid)) {
+       if (uid_valid(context->binder_context_mgr_uid)) {
+               if (!uid_eq(context->binder_context_mgr_uid, curr_euid)) {
                        pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
                               from_kuid(&init_user_ns, curr_euid),
                               from_kuid(&init_user_ns,
-                                       binder_context_mgr_uid));
+                                        context->binder_context_mgr_uid));
                        ret = -EPERM;
                        goto out;
                }
        } else {
-               binder_context_mgr_uid = curr_euid;
+               context->binder_context_mgr_uid = curr_euid;
        }
-       binder_context_mgr_node = binder_new_node(proc, 0, 0);
-       if (binder_context_mgr_node == NULL) {
+       context->binder_context_mgr_node = binder_new_node(proc, 0, 0);
+       if (!context->binder_context_mgr_node) {
                ret = -ENOMEM;
                goto out;
        }
-       binder_context_mgr_node->local_weak_refs++;
-       binder_context_mgr_node->local_strong_refs++;
-       binder_context_mgr_node->has_strong_ref = 1;
-       binder_context_mgr_node->has_weak_ref = 1;
+       context->binder_context_mgr_node->local_weak_refs++;
+       context->binder_context_mgr_node->local_strong_refs++;
+       context->binder_context_mgr_node->has_strong_ref = 1;
+       context->binder_context_mgr_node->has_weak_ref = 1;
 out:
        return ret;
 }
@@ -2942,6 +3454,7 @@ err_bad_arg:
 static int binder_open(struct inode *nodp, struct file *filp)
 {
        struct binder_proc *proc;
+       struct binder_device *binder_dev;
 
        binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n",
                     current->group_leader->pid, current->pid);
@@ -2954,6 +3467,9 @@ static int binder_open(struct inode *nodp, struct file *filp)
        INIT_LIST_HEAD(&proc->todo);
        init_waitqueue_head(&proc->wait);
        proc->default_priority = task_nice(current);
+       binder_dev = container_of(filp->private_data, struct binder_device,
+                                 miscdev);
+       proc->context = &binder_dev->context;
 
        binder_lock(__func__);
 
@@ -2969,8 +3485,17 @@ static int binder_open(struct inode *nodp, struct file *filp)
                char strbuf[11];
 
                snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
+               /*
+                * proc debug entries are shared between contexts, so
+                * this will fail if the process tries to open the driver
+                * again with a different context. The priting code will
+                * anyway print all contexts that a given PID has, so this
+                * is not a problem.
+                */
                proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,
-                       binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);
+                       binder_debugfs_dir_entry_proc,
+                       (void *)(unsigned long)proc->pid,
+                       &binder_proc_fops);
        }
 
        return 0;
@@ -3063,6 +3588,7 @@ static int binder_node_release(struct binder_node *node, int refs)
 static void binder_deferred_release(struct binder_proc *proc)
 {
        struct binder_transaction *t;
+       struct binder_context *context = proc->context;
        struct rb_node *n;
        int threads, nodes, incoming_refs, outgoing_refs, buffers,
                active_transactions, page_count;
@@ -3072,11 +3598,12 @@ static void binder_deferred_release(struct binder_proc *proc)
 
        hlist_del(&proc->proc_node);
 
-       if (binder_context_mgr_node && binder_context_mgr_node->proc == proc) {
+       if (context->binder_context_mgr_node &&
+           context->binder_context_mgr_node->proc == proc) {
                binder_debug(BINDER_DEBUG_DEAD_BINDER,
                             "%s: %d context_mgr_node gone\n",
                             __func__, proc->pid);
-               binder_context_mgr_node = NULL;
+               context->binder_context_mgr_node = NULL;
        }
 
        threads = 0;
@@ -3363,6 +3890,7 @@ static void print_binder_proc(struct seq_file *m,
        size_t header_pos;
 
        seq_printf(m, "proc %d\n", proc->pid);
+       seq_printf(m, "context %s\n", proc->context->name);
        header_pos = m->count;
 
        for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n))
@@ -3432,7 +3960,9 @@ static const char * const binder_command_strings[] = {
        "BC_EXIT_LOOPER",
        "BC_REQUEST_DEATH_NOTIFICATION",
        "BC_CLEAR_DEATH_NOTIFICATION",
-       "BC_DEAD_BINDER_DONE"
+       "BC_DEAD_BINDER_DONE",
+       "BC_TRANSACTION_SG",
+       "BC_REPLY_SG",
 };
 
 static const char * const binder_objstat_strings[] = {
@@ -3487,6 +4017,7 @@ static void print_binder_proc_stats(struct seq_file *m,
        int count, strong, weak;
 
        seq_printf(m, "proc %d\n", proc->pid);
+       seq_printf(m, "context %s\n", proc->context->name);
        count = 0;
        for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n))
                count++;
@@ -3593,13 +4124,19 @@ static int binder_transactions_show(struct seq_file *m, void *unused)
 
 static int binder_proc_show(struct seq_file *m, void *unused)
 {
-       struct binder_proc *proc = m->private;
+       struct binder_proc *itr;
+       int pid = (unsigned long)m->private;
        int do_lock = !binder_debug_no_lock;
 
        if (do_lock)
                binder_lock(__func__);
-       seq_puts(m, "binder proc state:\n");
-       print_binder_proc(m, proc, 1);
+
+       hlist_for_each_entry(itr, &binder_procs, proc_node) {
+               if (itr->pid == pid) {
+                       seq_puts(m, "binder proc state:\n");
+                       print_binder_proc(m, itr, 1);
+               }
+       }
        if (do_lock)
                binder_unlock(__func__);
        return 0;
@@ -3609,11 +4146,11 @@ static void print_binder_transaction_log_entry(struct seq_file *m,
                                        struct binder_transaction_log_entry *e)
 {
        seq_printf(m,
-                  "%d: %s from %d:%d to %d:%d node %d handle %d size %d:%d\n",
+                  "%d: %s from %d:%d to %d:%d context %s node %d handle %d size %d:%d\n",
                   e->debug_id, (e->call_type == 2) ? "reply" :
                   ((e->call_type == 1) ? "async" : "call "), e->from_proc,
-                  e->from_thread, e->to_proc, e->to_thread, e->to_node,
-                  e->target_handle, e->data_size, e->offsets_size);
+                  e->from_thread, e->to_proc, e->to_thread, e->context_name,
+                  e->to_node, e->target_handle, e->data_size, e->offsets_size);
 }
 
 static int binder_transaction_log_show(struct seq_file *m, void *unused)
@@ -3641,20 +4178,44 @@ static const struct file_operations binder_fops = {
        .release = binder_release,
 };
 
-static struct miscdevice binder_miscdev = {
-       .minor = MISC_DYNAMIC_MINOR,
-       .name = "binder",
-       .fops = &binder_fops
-};
-
 BINDER_DEBUG_ENTRY(state);
 BINDER_DEBUG_ENTRY(stats);
 BINDER_DEBUG_ENTRY(transactions);
 BINDER_DEBUG_ENTRY(transaction_log);
 
+static int __init init_binder_device(const char *name)
+{
+       int ret;
+       struct binder_device *binder_device;
+
+       binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL);
+       if (!binder_device)
+               return -ENOMEM;
+
+       binder_device->miscdev.fops = &binder_fops;
+       binder_device->miscdev.minor = MISC_DYNAMIC_MINOR;
+       binder_device->miscdev.name = name;
+
+       binder_device->context.binder_context_mgr_uid = INVALID_UID;
+       binder_device->context.name = name;
+
+       ret = misc_register(&binder_device->miscdev);
+       if (ret < 0) {
+               kfree(binder_device);
+               return ret;
+       }
+
+       hlist_add_head(&binder_device->hlist, &binder_devices);
+
+       return ret;
+}
+
 static int __init binder_init(void)
 {
        int ret;
+       char *device_name, *device_names;
+       struct binder_device *device;
+       struct hlist_node *tmp;
 
        binder_deferred_workqueue = create_singlethread_workqueue("binder");
        if (!binder_deferred_workqueue)
@@ -3664,7 +4225,7 @@ static int __init binder_init(void)
        if (binder_debugfs_dir_entry_root)
                binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",
                                                 binder_debugfs_dir_entry_root);
-       ret = misc_register(&binder_miscdev);
+
        if (binder_debugfs_dir_entry_root) {
                debugfs_create_file("state",
                                    S_IRUGO,
@@ -3692,6 +4253,37 @@ static int __init binder_init(void)
                                    &binder_transaction_log_failed,
                                    &binder_transaction_log_fops);
        }
+
+       /*
+        * Copy the module_parameter string, because we don't want to
+        * tokenize it in-place.
+        */
+       device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL);
+       if (!device_names) {
+               ret = -ENOMEM;
+               goto err_alloc_device_names_failed;
+       }
+       strcpy(device_names, binder_devices_param);
+
+       while ((device_name = strsep(&device_names, ","))) {
+               ret = init_binder_device(device_name);
+               if (ret)
+                       goto err_init_binder_device_failed;
+       }
+
+       return ret;
+
+err_init_binder_device_failed:
+       hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) {
+               misc_deregister(&device->miscdev);
+               hlist_del(&device->hlist);
+               kfree(device);
+       }
+err_alloc_device_names_failed:
+       debugfs_remove_recursive(binder_debugfs_dir_entry_root);
+
+       destroy_workqueue(binder_deferred_workqueue);
+
        return ret;
 }