android: binder: support multiple context managers.
authorMartijn Coenen <maco@google.com>
Fri, 30 Sep 2016 13:51:48 +0000 (15:51 +0200)
committerMartijn Coenen <maco@android.com>
Mon, 31 Oct 2016 14:14:59 +0000 (15:14 +0100)
Move the context manager state into a separate
struct context, and allow for each process to have
its own context associated with it.

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

index 50cc56f3d0cc991d4ece4bcfd3875245f0cf0d81..93780d1cc19901617faae8d3a708ffd18981dedd 100644 (file)
@@ -56,8 +56,6 @@ 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;
 
@@ -216,6 +214,15 @@ 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;
+};
+
+static struct binder_context global_context = {
+       .binder_context_mgr_uid = INVALID_UID,
+};
+
 struct binder_work {
        struct list_head entry;
        enum {
@@ -331,6 +338,7 @@ struct binder_proc {
        int ready_threads;
        long default_priority;
        struct dentry *debugfs_entry;
+       struct binder_context *context;
 };
 
 enum {
@@ -935,8 +943,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;
@@ -1037,6 +1047,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;
@@ -1059,7 +1070,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)
@@ -1389,6 +1400,7 @@ 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_context *context = proc->context;
 
        e = binder_transaction_log_add(&binder_transaction_log);
        e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY);
@@ -1449,7 +1461,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;
@@ -1840,6 +1852,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;
@@ -1866,10 +1879,10 @@ 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,
@@ -2775,9 +2788,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;
@@ -2785,27 +2800,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;
 }
@@ -3035,6 +3050,7 @@ static int binder_open(struct inode *nodp, struct file *filp)
                return -ENOMEM;
        get_task_struct(current);
        proc->tsk = current;
+       proc->context = &global_context;
        INIT_LIST_HEAD(&proc->todo);
        init_waitqueue_head(&proc->wait);
        proc->default_priority = task_nice(current);
@@ -3147,6 +3163,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;
@@ -3156,11 +3173,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;