From: Arve Hjønnevåg <a...@android.com>

3.12-stable review patch.  If anyone has any objections, please let me know.

===============

commit 0a3ffab93fe52530602fe47cd74802cffdb19c05 upstream.

Prevent using a binder_ref with only weak references where a strong
reference is required.

Signed-off-by: Arve Hjønnevåg <a...@android.com>
Signed-off-by: Martijn Coenen <m...@android.com>
Signed-off-by: Jiri Slaby <jsl...@suse.cz>
---
 drivers/staging/android/binder.c | 30 +++++++++++++++++++++---------
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 69fd236345cb..8a436dae9b77 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -994,7 +994,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;
@@ -1002,12 +1002,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;
 }
@@ -1270,7 +1274,10 @@ static void binder_transaction_buffer_release(struct 
binder_proc *proc,
                } break;
                case BINDER_TYPE_HANDLE:
                case BINDER_TYPE_WEAK_HANDLE: {
-                       struct binder_ref *ref = binder_get_ref(proc, 
fp->handle);
+                       struct binder_ref *ref;
+
+                       ref = binder_get_ref(proc, fp->handle,
+                                            fp->type == BINDER_TYPE_HANDLE);
                        if (ref == NULL) {
                                pr_err("transaction release %d bad handle %d\n",
                                 debug_id, fp->handle);
@@ -1362,7 +1369,7 @@ static void binder_transaction(struct binder_proc *proc,
        } else {
                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);
@@ -1546,7 +1553,10 @@ static void binder_transaction(struct binder_proc *proc,
                } break;
                case BINDER_TYPE_HANDLE:
                case BINDER_TYPE_WEAK_HANDLE: {
-                       struct binder_ref *ref = binder_get_ref(proc, 
fp->handle);
+                       struct binder_ref *ref;
+
+                       ref = binder_get_ref(proc, fp->handle,
+                                            fp->type == BINDER_TYPE_HANDLE);
                        if (ref == NULL) {
                                binder_user_error("%d:%d got transaction with 
invalid handle, %d\n",
                                                proc->pid,
@@ -1739,7 +1749,9 @@ int binder_thread_write(struct binder_proc *proc, struct 
binder_thread *thread,
                                                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);
@@ -1934,7 +1946,7 @@ int binder_thread_write(struct binder_proc *proc, struct 
binder_thread *thread,
                        if (get_user(cookie, (void __user * __user *)ptr))
                                return -EFAULT;
                        ptr += sizeof(void *);
-                       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,
-- 
2.10.2

Reply via email to