diff options
Diffstat (limited to 'drivers/staging/android/binder.c')
-rw-r--r-- | drivers/staging/android/binder.c | 1045 |
1 files changed, 335 insertions, 710 deletions
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index d6331c132b87..55195ea28de6 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -38,7 +38,6 @@ #include <linux/slab.h> #include <linux/pid_namespace.h> #include <linux/security.h> -#include <linux/compat.h> #include "binder.h" #include "binder_trace.h" @@ -142,87 +141,6 @@ module_param_call(stop_on_user_error, binder_set_stop_on_user_error, binder_stop_on_user_error = 2; \ } while (0) -#ifdef CONFIG_COMPAT -static inline void writeback_flat_binder_object(struct flat_binder_object *fp, - void __user *ptr) -{ - struct compat_flat_binder_object *tmp_fp; - - tmp_fp = (struct compat_flat_binder_object *) ptr; - tmp_fp->type = fp->type; - tmp_fp->flags = fp->flags; - tmp_fp->binder = ptr_to_compat(fp->binder); - tmp_fp->cookie = ptr_to_compat(fp->cookie); -} - -static inline struct flat_binder_object *copy_flat_binder_object(void __user *ptr) -{ - struct flat_binder_object *fp; - struct compat_flat_binder_object *tmp_fp; - - if (!is_compat_task()) - return (struct flat_binder_object *) ptr; - - fp = kzalloc(sizeof(*fp), GFP_KERNEL); - if (fp == NULL) - return NULL; - - tmp_fp = (struct compat_flat_binder_object *) ptr; - /* copy compat struct */ - fp->type = tmp_fp->type; - fp->flags = tmp_fp->flags; - fp->binder = compat_ptr(tmp_fp->binder); - fp->cookie = compat_ptr(tmp_fp->cookie); - - return fp; -} - -static inline uint32_t compat_change_size(uint32_t cmd, size_t size) -{ - uint32_t compat_cmd; - - compat_cmd = cmd & ~IOCSIZE_MASK; - compat_cmd = compat_cmd | ((size << _IOC_SIZESHIFT) & IOCSIZE_MASK); - return compat_cmd; -} - -#define align_helper(x) ( \ - is_compat_task() ? \ - ALIGN(x, sizeof(compat_uptr_t)) : \ - ALIGN(x, sizeof(void *)) \ - ) - -#define deref_helper(x) ( \ - is_compat_task() ? \ - (size_t) *(compat_size_t *)x : \ - *(size_t *)x \ - ) - -#define size_helper(x) ({ \ - size_t __size; \ - if (!is_compat_task()) \ - __size = sizeof(x); \ - else if (sizeof(x) == sizeof(struct flat_binder_object)) \ - __size = sizeof(struct compat_flat_binder_object); \ - else if (sizeof(x) == sizeof(struct binder_transaction_data)) \ - __size = sizeof(struct compat_binder_transaction_data); \ - else if (sizeof(x) == sizeof(size_t)) \ - __size = sizeof(compat_size_t); \ - else \ - BUG(); \ - __size; \ - }) -#else -#define align_helper(ptr) ALIGN(ptr, sizeof(void *)) -#define deref_helper(ptr) (*(typeof(size_t *))ptr) -#define size_helper(x) sizeof(x) - -static inline struct flat_binder_object *copy_flat_binder_object(void __user *ptr) -{ - return (struct flat_binder_object *)ptr; -} -#endif - enum binder_stat_types { BINDER_STAT_PROC, BINDER_STAT_THREAD, @@ -311,8 +229,8 @@ struct binder_node { int internal_strong_refs; int local_weak_refs; int local_strong_refs; - void __user *ptr; - void __user *cookie; + binder_uintptr_t ptr; + binder_uintptr_t cookie; unsigned has_strong_ref:1; unsigned pending_strong_ref:1; unsigned has_weak_ref:1; @@ -325,7 +243,7 @@ struct binder_node { struct binder_ref_death { struct binder_work work; - void __user *cookie; + binder_uintptr_t cookie; }; struct binder_ref { @@ -598,14 +516,14 @@ static void binder_insert_allocated_buffer(struct binder_proc *proc, } static struct binder_buffer *binder_buffer_lookup(struct binder_proc *proc, - void __user *user_ptr) + uintptr_t user_ptr) { struct rb_node *n = proc->allocated_buffers.rb_node; struct binder_buffer *buffer; struct binder_buffer *kern_ptr; - kern_ptr = user_ptr - proc->user_buffer_offset - - offsetof(struct binder_buffer, data); + kern_ptr = (struct binder_buffer *)(user_ptr - proc->user_buffer_offset + - offsetof(struct binder_buffer, data)); while (n) { buffer = rb_entry(n, struct binder_buffer, rb_node); @@ -939,7 +857,7 @@ static void binder_free_buf(struct binder_proc *proc, } static struct binder_node *binder_get_node(struct binder_proc *proc, - void __user *ptr) + binder_uintptr_t ptr) { struct rb_node *n = proc->nodes.rb_node; struct binder_node *node; @@ -958,8 +876,8 @@ static struct binder_node *binder_get_node(struct binder_proc *proc, } static struct binder_node *binder_new_node(struct binder_proc *proc, - void __user *ptr, - void __user *cookie) + binder_uintptr_t ptr, + binder_uintptr_t cookie) { struct rb_node **p = &proc->nodes.rb_node; struct rb_node *parent = NULL; @@ -991,9 +909,9 @@ static struct binder_node *binder_new_node(struct binder_proc *proc, INIT_LIST_HEAD(&node->work.entry); INIT_LIST_HEAD(&node->async_todo); binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%p c%p created\n", + "%d:%d node %d u%016llx c%016llx created\n", proc->pid, current->pid, node->debug_id, - node->ptr, node->cookie); + (u64)node->ptr, (u64)node->cookie); return node; } @@ -1309,9 +1227,9 @@ static void binder_send_failed_reply(struct binder_transaction *t, static void binder_transaction_buffer_release(struct binder_proc *proc, struct binder_buffer *buffer, - size_t *failed_at) + binder_size_t *failed_at) { - void *offp, *off_end; + binder_size_t *offp, *off_end; int debug_id = buffer->debug_id; binder_debug(BINDER_DEBUG_TRANSACTION, @@ -1322,33 +1240,34 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, if (buffer->target_node) binder_dec_node(buffer->target_node, 1, 0); - offp = (size_t *)(buffer->data + align_helper(buffer->data_size)); + offp = (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 += size_helper(size_t)) { - struct flat_binder_object *fp = NULL; - if (deref_helper(offp) > buffer->data_size - size_helper(*fp) || - buffer->data_size < size_helper(*fp) || - !IS_ALIGNED(deref_helper(offp), sizeof(u32))) { - pr_err("transaction release %d bad offset %zd, size %zd\n", - debug_id, deref_helper(offp), buffer->data_size); + for (; offp < off_end; offp++) { + struct flat_binder_object *fp; + 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", + debug_id, (u64)*offp, buffer->data_size); continue; } - fp = copy_flat_binder_object(buffer->data + deref_helper(offp)); + fp = (struct flat_binder_object *)(buffer->data + *offp); switch (fp->type) { case BINDER_TYPE_BINDER: case BINDER_TYPE_WEAK_BINDER: { struct binder_node *node = binder_get_node(proc, fp->binder); if (node == NULL) { - pr_err("transaction release %d bad node %p\n", - debug_id, fp->binder); + pr_err("transaction release %d bad node %016llx\n", + debug_id, (u64)fp->binder); break; } binder_debug(BINDER_DEBUG_TRANSACTION, - " node %d u%p\n", - node->debug_id, node->ptr); + " node %d u%016llx\n", + node->debug_id, (u64)node->ptr); binder_dec_node(node, fp->type == BINDER_TYPE_BINDER, 0); } break; case BINDER_TYPE_HANDLE: @@ -1377,8 +1296,6 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, debug_id, fp->type); break; } - if (is_compat_task()) - kfree(fp); } } @@ -1388,7 +1305,8 @@ static void binder_transaction(struct binder_proc *proc, { struct binder_transaction *t; struct binder_work *tcomplete; - void *offp, *off_end; + binder_size_t *offp, *off_end; + binder_size_t off_min; struct binder_proc *target_proc; struct binder_thread *target_thread = NULL; struct binder_node *target_node = NULL; @@ -1397,7 +1315,6 @@ 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 flat_binder_object *fp = NULL; e = binder_transaction_log_add(&binder_transaction_log); e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY); @@ -1522,18 +1439,20 @@ static void binder_transaction(struct binder_proc *proc, if (reply) binder_debug(BINDER_DEBUG_TRANSACTION, - "%d:%d BC_REPLY %d -> %d:%d, data %p-%p size %zd-%zd\n", + "%d:%d BC_REPLY %d -> %d:%d, data %016llx-%016llx size %lld-%lld\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_thread->pid, - tr->data.ptr.buffer, tr->data.ptr.offsets, - tr->data_size, tr->offsets_size); + (u64)tr->data.ptr.buffer, + (u64)tr->data.ptr.offsets, + (u64)tr->data_size, (u64)tr->offsets_size); else binder_debug(BINDER_DEBUG_TRANSACTION, - "%d:%d BC_TRANSACTION %d -> %d - node %d, data %p-%p size %zd-%zd\n", + "%d:%d BC_TRANSACTION %d -> %d - node %d, data %016llx-%016llx size %lld-%lld\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_node->debug_id, - tr->data.ptr.buffer, tr->data.ptr.offsets, - tr->data_size, tr->offsets_size); + (u64)tr->data.ptr.buffer, + (u64)tr->data.ptr.offsets, + (u64)tr->data_size, (u64)tr->offsets_size); if (!reply && !(tr->flags & TF_ONE_WAY)) t->from = thread; @@ -1562,37 +1481,47 @@ static void binder_transaction(struct binder_proc *proc, if (target_node) binder_inc_node(target_node, 1, 0, NULL); - offp = (size_t *)(t->buffer->data + align_helper(tr->data_size)); + offp = (binder_size_t *)(t->buffer->data + + ALIGN(tr->data_size, sizeof(void *))); - if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) { + if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t) + tr->data.ptr.buffer, tr->data_size)) { binder_user_error("%d:%d got transaction with invalid data ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed; } - if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) { + if (copy_from_user(offp, (const void __user *)(uintptr_t) + tr->data.ptr.offsets, tr->offsets_size)) { 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; } - if (!IS_ALIGNED(tr->offsets_size, size_helper(size_t))) { - binder_user_error("%d:%d got transaction with invalid offsets size, %zd\n", - proc->pid, thread->pid, tr->offsets_size); + if (!IS_ALIGNED(tr->offsets_size, sizeof(binder_size_t))) { + binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n", + proc->pid, thread->pid, (u64)tr->offsets_size); return_error = BR_FAILED_REPLY; goto err_bad_offset; } off_end = (void *)offp + tr->offsets_size; - for (; offp < off_end; offp += size_helper(size_t)) { - if (deref_helper(offp) > t->buffer->data_size - size_helper(*fp) || - t->buffer->data_size < size_helper(*fp) || - !IS_ALIGNED(deref_helper(offp), sizeof(u32))) { - binder_user_error("%d:%d got transaction with invalid offset, %zd\n", - proc->pid, thread->pid, deref_helper(offp)); + off_min = 0; + for (; offp < off_end; offp++) { + struct flat_binder_object *fp; + if (*offp > t->buffer->data_size - sizeof(*fp) || + *offp < off_min || + t->buffer->data_size < sizeof(*fp) || + !IS_ALIGNED(*offp, sizeof(u32))) { + binder_user_error("%d:%d got transaction with invalid offset, %lld (min %lld, max %lld)\n", + proc->pid, thread->pid, (u64)*offp, + (u64)off_min, + (u64)(t->buffer->data_size - + sizeof(*fp))); return_error = BR_FAILED_REPLY; goto err_bad_offset; } - fp = copy_flat_binder_object(t->buffer->data + deref_helper(offp)); + fp = (struct flat_binder_object *)(t->buffer->data + *offp); + off_min = *offp + sizeof(struct flat_binder_object); switch (fp->type) { case BINDER_TYPE_BINDER: case BINDER_TYPE_WEAK_BINDER: { @@ -1608,10 +1537,10 @@ static void binder_transaction(struct binder_proc *proc, node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); } if (fp->cookie != node->cookie) { - binder_user_error("%d:%d sending u%p node %d, cookie mismatch %p != %p\n", + binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, - fp->binder, node->debug_id, - fp->cookie, node->cookie); + (u64)fp->binder, node->debug_id, + (u64)fp->cookie, (u64)node->cookie); goto err_binder_get_ref_for_node_failed; } if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { @@ -1633,9 +1562,9 @@ static void binder_transaction(struct binder_proc *proc, trace_binder_transaction_node_to_ref(t, node, ref); binder_debug(BINDER_DEBUG_TRANSACTION, - " node %d u%p -> ref %d desc %d\n", - node->debug_id, node->ptr, ref->debug_id, - ref->desc); + " 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: { @@ -1661,9 +1590,9 @@ static void binder_transaction(struct binder_proc *proc, 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%p\n", + " ref %d desc %d -> node %d u%016llx\n", ref->debug_id, ref->desc, ref->node->debug_id, - ref->node->ptr); + (u64)ref->node->ptr); } else { struct binder_ref *new_ref; new_ref = binder_get_ref_for_node(target_proc, ref->node); @@ -1732,12 +1661,6 @@ static void binder_transaction(struct binder_proc *proc, return_error = BR_FAILED_REPLY; goto err_bad_object_type; } -#ifdef CONFIG_COMPAT - if (is_compat_task()) { - writeback_flat_binder_object(fp, t->buffer->data + deref_helper(offp)); - kfree(fp); - } -#endif } if (reply) { BUG_ON(t->buffer->async_transaction != 0); @@ -1773,8 +1696,6 @@ err_binder_new_node_failed: err_bad_object_type: err_bad_offset: err_copy_data_failed: - if (is_compat_task()) - kfree(fp); trace_binder_transaction_failed_buffer_release(t->buffer); binder_transaction_buffer_release(target_proc, t->buffer, offp); t->buffer->transaction = NULL; @@ -1792,9 +1713,9 @@ err_dead_binder: err_invalid_target_handle: err_no_context_mgr_node: binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "%d:%d transaction failed %d, size %zd-%zd\n", + "%d:%d transaction failed %d, size %lld-%lld\n", proc->pid, thread->pid, return_error, - tr->data_size, tr->offsets_size); + (u64)tr->data_size, (u64)tr->offsets_size); { struct binder_transaction_log_entry *fe; @@ -1810,311 +1731,12 @@ err_no_context_mgr_node: thread->return_error = return_error; } -static void bc_increfs_done(struct binder_proc *proc, - struct binder_thread *thread, bool acquire, - void __user *node_ptr, void __user *cookie) -{ - struct binder_node *node; - - node = binder_get_node(proc, node_ptr); - if (node == NULL) { - binder_user_error("%d:%d %s u%p no match\n", - proc->pid, thread->pid, - acquire ? - "BC_ACQUIRE_DONE" : - "BC_INCREFS_DONE", - node_ptr); - return; - } - if (cookie != node->cookie) { - binder_user_error("%d:%d %s u%p node %d cookie mismatch %p != %p\n", - proc->pid, thread->pid, - acquire ? - "BC_ACQUIRE_DONE" : "BC_INCREFS_DONE", - node_ptr, node->debug_id, - cookie, node->cookie); - return; - } - if (acquire) { - if (node->pending_strong_ref == 0) { - binder_user_error("%d:%d BC_ACQUIRE_DONE node %d has no pending acquire request\n", - proc->pid, thread->pid, - node->debug_id); - return; - } - node->pending_strong_ref = 0; - } else { - if (node->pending_weak_ref == 0) { - binder_user_error("%d:%d BC_INCREFS_DONE node %d has no pending increfs request\n", - proc->pid, thread->pid, - node->debug_id); - return; - } - node->pending_weak_ref = 0; - } - binder_dec_node(node, acquire, 0); - binder_debug(BINDER_DEBUG_USER_REFS, - "%d:%d %s node %d ls %d lw %d\n", - proc->pid, thread->pid, - acquire ? - "BC_ACQUIRE_DONE" : - "BC_INCREFS_DONE", - node->debug_id, node->local_strong_refs, - node->local_weak_refs); - return; -} - -static void bc_free_buffer(struct binder_proc *proc, - struct binder_thread *thread, void __user *data_ptr) -{ - struct binder_buffer *buffer; - - buffer = binder_buffer_lookup(proc, data_ptr); - if (buffer == NULL) { - binder_user_error("%d:%d BC_FREE_BUFFER u%p no match\n", - proc->pid, thread->pid, data_ptr); - return; - } - if (!buffer->allow_user_free) { - binder_user_error("%d:%d BC_FREE_BUFFER u%p matched unreturned buffer\n", - proc->pid, thread->pid, data_ptr); - return; - } - binder_debug(BINDER_DEBUG_FREE_BUFFER, - "%d:%d BC_FREE_BUFFER u%p found buffer %d for %s transaction\n", - proc->pid, thread->pid, data_ptr, buffer->debug_id, - buffer->transaction ? "active" : "finished"); - - if (buffer->transaction) { - buffer->transaction->buffer = NULL; - buffer->transaction = NULL; - } - if (buffer->async_transaction && buffer->target_node) { - BUG_ON(!buffer->target_node->has_async_transaction); - if (list_empty(&buffer->target_node->async_todo)) - buffer->target_node->has_async_transaction = 0; - else - list_move_tail(buffer->target_node->async_todo.next, &thread->todo); - } - trace_binder_transaction_buffer_release(buffer); - binder_transaction_buffer_release(proc, buffer, NULL); - binder_free_buf(proc, buffer); - return; -} - -static void bc_clear_death_notif(struct binder_proc *proc, - struct binder_thread *thread, bool request, - uint32_t target, void __user *cookie) -{ - struct binder_ref *ref; - struct binder_ref_death *death; - - ref = binder_get_ref(proc, target); - if (ref == NULL) { - binder_user_error("%d:%d %s invalid ref %d\n", - proc->pid, thread->pid, - request ? - "BC_REQUEST_DEATH_NOTIFICATION" : - "BC_CLEAR_DEATH_NOTIFICATION", - target); - return; - } - - binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, - "%d:%d %s %p ref %d desc %d s %d w %d for node %d\n", - proc->pid, thread->pid, - request ? - "BC_REQUEST_DEATH_NOTIFICATION" : - "BC_CLEAR_DEATH_NOTIFICATION", - cookie, ref->debug_id, ref->desc, - ref->strong, ref->weak, ref->node->debug_id); - - if (request) { - if (ref->death) { - binder_user_error("%d:%d BC_REQUEST_DEATH_NOTIFICATION death notification already set\n", - proc->pid, thread->pid); - return; - } - death = kzalloc(sizeof(*death), GFP_KERNEL); - if (death == NULL) { - thread->return_error = BR_ERROR; - binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n", - proc->pid, thread->pid); - return; - } - binder_stats_created(BINDER_STAT_DEATH); - INIT_LIST_HEAD(&death->work.entry); - death->cookie = cookie; - ref->death = death; - if (ref->node->proc == NULL) { - ref->death->work.type = BINDER_WORK_DEAD_BINDER; - if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { - list_add_tail(&ref->death->work.entry, &thread->todo); - } else { - list_add_tail(&ref->death->work.entry, &proc->todo); - wake_up_interruptible(&proc->wait); - } - } - } else { - if (ref->death == NULL) { - binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification not active\n", - proc->pid, thread->pid); - return; - } - death = ref->death; - if (death->cookie != cookie) { - binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %p != %p\n", - proc->pid, thread->pid, - death->cookie, cookie); - return; - } - ref->death = NULL; - if (list_empty(&death->work.entry)) { - death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; - if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { - list_add_tail(&death->work.entry, &thread->todo); - } else { - list_add_tail(&death->work.entry, &proc->todo); - wake_up_interruptible(&proc->wait); - } - } else { - BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER); - death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR; - } - } - return; -} - -static void bc_dead_binder_done(struct binder_proc *proc, - struct binder_thread *thread, void __user *cookie) -{ - struct binder_work *w; - struct binder_ref_death *death = NULL; - - list_for_each_entry(w, &proc->delivered_death, entry) { - struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work); - if (tmp_death->cookie == cookie) { - death = tmp_death; - return; - } - } - binder_debug(BINDER_DEBUG_DEAD_BINDER, - "%d:%d BC_DEAD_BINDER_DONE %p found %p\n", - proc->pid, thread->pid, cookie, death); - if (death == NULL) { - binder_user_error("%d:%d BC_DEAD_BINDER_DONE %p not found\n", - proc->pid, thread->pid, cookie); - return; - } - - list_del_init(&death->work.entry); - if (death->work.type == BINDER_WORK_DEAD_BINDER_AND_CLEAR) { - death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; - if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { - list_add_tail(&death->work.entry, &thread->todo); - } else { - list_add_tail(&death->work.entry, &proc->todo); - wake_up_interruptible(&proc->wait); - } - } - return; -} - -#ifdef CONFIG_COMPAT -static int compat_binder_thread_write(struct binder_proc *proc, - struct binder_thread *thread, uint32_t cmd, - void __user **ptr) -{ - BUG_ON(!is_compat_task()); - switch (cmd) { - case COMPAT_BC_INCREFS_DONE: - case COMPAT_BC_ACQUIRE_DONE: { - compat_uptr_t node_ptr; - compat_uptr_t cookie; - - if (get_user(node_ptr, (compat_uptr_t __user *)*ptr)) - return -EFAULT; - *ptr += sizeof(compat_uptr_t); - if (get_user(cookie, (compat_uptr_t __user *)*ptr)) - return -EFAULT; - *ptr += sizeof(compat_uptr_t); - bc_increfs_done(proc, thread, cmd == COMPAT_BC_ACQUIRE_DONE, - compat_ptr(node_ptr), compat_ptr(cookie)); - break; - } - - case COMPAT_BC_FREE_BUFFER: { - compat_uptr_t data_ptr; - - if (get_user(data_ptr, (compat_uptr_t __user *)*ptr)) - return -EFAULT; - *ptr += sizeof(compat_uptr_t); - bc_free_buffer(proc, thread, compat_ptr(data_ptr)); - break; - } - - case COMPAT_BC_TRANSACTION: - case COMPAT_BC_REPLY: { - struct binder_transaction_data tr; - struct compat_binder_transaction_data tmp_tr; - - if (copy_from_user(&tmp_tr, *ptr, sizeof(tmp_tr))) - return -EFAULT; - *ptr += sizeof(tmp_tr); - - memset(&tr, 0, sizeof(tr)); - /* copy from compat struct */ - tr.target.ptr = compat_ptr(tmp_tr.target.ptr); - tr.cookie = compat_ptr(tmp_tr.cookie); - tr.code = tmp_tr.code; - tr.flags = tmp_tr.flags; - tr.sender_pid = tmp_tr.sender_pid; - tr.sender_euid = tmp_tr.sender_euid; - tr.data_size = (size_t) tmp_tr.data_size; - tr.offsets_size = (size_t) tmp_tr.offsets_size; - tr.data.ptr.buffer = compat_ptr(tmp_tr.data.ptr.buffer); - tr.data.ptr.offsets = compat_ptr(tmp_tr.data.ptr.offsets); - - binder_transaction(proc, thread, &tr, cmd == COMPAT_BC_REPLY); - break; - } - case COMPAT_BC_REQUEST_DEATH_NOTIFICATION: - case COMPAT_BC_CLEAR_DEATH_NOTIFICATION: { - uint32_t target; - compat_uptr_t cookie; - - if (get_user(target, (uint32_t __user *)*ptr)) - return -EFAULT; - *ptr += sizeof(uint32_t); - if (get_user(cookie, (compat_uptr_t __user *)*ptr)) - return -EFAULT; - *ptr += sizeof(compat_uptr_t); - bc_clear_death_notif(proc, thread, cmd == COMPAT_BC_REQUEST_DEATH_NOTIFICATION, - target, compat_ptr(cookie)); - break; - } - case COMPAT_BC_DEAD_BINDER_DONE: { - compat_uptr_t cookie; - - if (get_user(cookie, (compat_uptr_t __user *)*ptr)) - return -EFAULT; - *ptr += sizeof(compat_uptr_t); - bc_dead_binder_done(proc, thread, compat_ptr(cookie)); - break; - } - default: - return -EINVAL; - } - return 0; -} -#endif - -static int binder_thread_write(struct binder_proc *proc, - struct binder_thread *thread, - void __user *buffer, size_t size, size_t *consumed) +int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, + binder_uintptr_t binder_buffer, size_t size, + binder_size_t *consumed) { uint32_t cmd; + void __user *buffer = (void __user *)(uintptr_t)binder_buffer; void __user *ptr = buffer + *consumed; void __user *end = buffer + size; @@ -2183,16 +1805,58 @@ static int binder_thread_write(struct binder_proc *proc, } case BC_INCREFS_DONE: case BC_ACQUIRE_DONE: { - void __user *node_ptr; - void __user *cookie; + binder_uintptr_t node_ptr; + binder_uintptr_t cookie; + struct binder_node *node; - if (get_user(node_ptr, (void * __user *)ptr)) + if (get_user(node_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); - if (get_user(cookie, (void * __user *)ptr)) + ptr += sizeof(binder_uintptr_t); + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); - bc_increfs_done(proc, thread, cmd == BC_ACQUIRE_DONE, node_ptr, cookie); + ptr += sizeof(binder_uintptr_t); + node = binder_get_node(proc, node_ptr); + if (node == NULL) { + binder_user_error("%d:%d %s u%016llx no match\n", + proc->pid, thread->pid, + cmd == BC_INCREFS_DONE ? + "BC_INCREFS_DONE" : + "BC_ACQUIRE_DONE", + (u64)node_ptr); + break; + } + if (cookie != node->cookie) { + binder_user_error("%d:%d %s u%016llx node %d cookie mismatch %016llx != %016llx\n", + proc->pid, thread->pid, + cmd == BC_INCREFS_DONE ? + "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", + (u64)node_ptr, node->debug_id, + (u64)cookie, (u64)node->cookie); + break; + } + if (cmd == BC_ACQUIRE_DONE) { + if (node->pending_strong_ref == 0) { + binder_user_error("%d:%d BC_ACQUIRE_DONE node %d has no pending acquire request\n", + proc->pid, thread->pid, + node->debug_id); + break; + } + node->pending_strong_ref = 0; + } else { + if (node->pending_weak_ref == 0) { + binder_user_error("%d:%d BC_INCREFS_DONE node %d has no pending increfs request\n", + proc->pid, thread->pid, + node->debug_id); + break; + } + node->pending_weak_ref = 0; + } + binder_dec_node(node, cmd == BC_ACQUIRE_DONE, 0); + binder_debug(BINDER_DEBUG_USER_REFS, + "%d:%d %s node %d ls %d lw %d\n", + proc->pid, thread->pid, + cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", + node->debug_id, node->local_strong_refs, node->local_weak_refs); break; } case BC_ATTEMPT_ACQUIRE: @@ -2203,12 +1867,43 @@ static int binder_thread_write(struct binder_proc *proc, return -EINVAL; case BC_FREE_BUFFER: { - void __user *data_ptr; + binder_uintptr_t data_ptr; + struct binder_buffer *buffer; - if (get_user(data_ptr, (void * __user *)ptr)) + if (get_user(data_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); - bc_free_buffer(proc, thread, data_ptr); + ptr += sizeof(binder_uintptr_t); + + buffer = binder_buffer_lookup(proc, data_ptr); + if (buffer == NULL) { + binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n", + proc->pid, thread->pid, (u64)data_ptr); + break; + } + if (!buffer->allow_user_free) { + binder_user_error("%d:%d BC_FREE_BUFFER u%016llx matched unreturned buffer\n", + proc->pid, thread->pid, (u64)data_ptr); + break; + } + binder_debug(BINDER_DEBUG_FREE_BUFFER, + "%d:%d BC_FREE_BUFFER u%016llx found buffer %d for %s transaction\n", + proc->pid, thread->pid, (u64)data_ptr, buffer->debug_id, + buffer->transaction ? "active" : "finished"); + + if (buffer->transaction) { + buffer->transaction->buffer = NULL; + buffer->transaction = NULL; + } + if (buffer->async_transaction && buffer->target_node) { + BUG_ON(!buffer->target_node->has_async_transaction); + if (list_empty(&buffer->target_node->async_todo)) + buffer->target_node->has_async_transaction = 0; + else + list_move_tail(buffer->target_node->async_todo.next, &thread->todo); + } + trace_binder_transaction_buffer_release(buffer); + binder_transaction_buffer_release(proc, buffer, NULL); + binder_free_buf(proc, buffer); break; } @@ -2262,32 +1957,128 @@ static int binder_thread_write(struct binder_proc *proc, case BC_REQUEST_DEATH_NOTIFICATION: case BC_CLEAR_DEATH_NOTIFICATION: { uint32_t target; - void __user *cookie; + binder_uintptr_t cookie; + struct binder_ref *ref; + struct binder_ref_death *death; if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (get_user(cookie, (void __user * __user *)ptr)) + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); - bc_clear_death_notif(proc, thread, cmd == BC_REQUEST_DEATH_NOTIFICATION, - target, cookie); - break; - } - case BC_DEAD_BINDER_DONE: { - void __user *cookie; + ptr += sizeof(binder_uintptr_t); + ref = binder_get_ref(proc, target); + if (ref == NULL) { + binder_user_error("%d:%d %s invalid ref %d\n", + proc->pid, thread->pid, + cmd == BC_REQUEST_DEATH_NOTIFICATION ? + "BC_REQUEST_DEATH_NOTIFICATION" : + "BC_CLEAR_DEATH_NOTIFICATION", + target); + break; + } - if (get_user(cookie, (void __user * __user *)ptr)) + binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, + "%d:%d %s %016llx ref %d desc %d s %d w %d for node %d\n", + proc->pid, thread->pid, + cmd == BC_REQUEST_DEATH_NOTIFICATION ? + "BC_REQUEST_DEATH_NOTIFICATION" : + "BC_CLEAR_DEATH_NOTIFICATION", + (u64)cookie, ref->debug_id, ref->desc, + ref->strong, ref->weak, ref->node->debug_id); + + if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { + if (ref->death) { + binder_user_error("%d:%d BC_REQUEST_DEATH_NOTIFICATION death notification already set\n", + proc->pid, thread->pid); + break; + } + death = kzalloc(sizeof(*death), GFP_KERNEL); + if (death == NULL) { + thread->return_error = BR_ERROR; + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, + "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n", + proc->pid, thread->pid); + break; + } + binder_stats_created(BINDER_STAT_DEATH); + INIT_LIST_HEAD(&death->work.entry); + death->cookie = cookie; + ref->death = death; + if (ref->node->proc == NULL) { + ref->death->work.type = BINDER_WORK_DEAD_BINDER; + if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { + list_add_tail(&ref->death->work.entry, &thread->todo); + } else { + list_add_tail(&ref->death->work.entry, &proc->todo); + wake_up_interruptible(&proc->wait); + } + } + } else { + if (ref->death == NULL) { + binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification not active\n", + proc->pid, thread->pid); + break; + } + death = ref->death; + if (death->cookie != cookie) { + binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %016llx != %016llx\n", + proc->pid, thread->pid, + (u64)death->cookie, (u64)cookie); + break; + } + ref->death = NULL; + if (list_empty(&death->work.entry)) { + death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; + if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { + list_add_tail(&death->work.entry, &thread->todo); + } else { + list_add_tail(&death->work.entry, &proc->todo); + wake_up_interruptible(&proc->wait); + } + } else { + BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER); + death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR; + } + } + } break; + case BC_DEAD_BINDER_DONE: { + struct binder_work *w; + binder_uintptr_t cookie; + struct binder_ref_death *death = NULL; + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; + ptr += sizeof(void *); - bc_dead_binder_done(proc, thread, cookie); - break; - } - default: -#ifdef CONFIG_COMPAT - if (is_compat_task() && (!compat_binder_thread_write(proc, thread, cmd, &ptr))) + list_for_each_entry(w, &proc->delivered_death, entry) { + struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work); + if (tmp_death->cookie == cookie) { + death = tmp_death; + break; + } + } + binder_debug(BINDER_DEBUG_DEAD_BINDER, + "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n", + proc->pid, thread->pid, (u64)cookie, death); + if (death == NULL) { + binder_user_error("%d:%d BC_DEAD_BINDER_DONE %016llx not found\n", + proc->pid, thread->pid, (u64)cookie); break; -#endif + } + + list_del_init(&death->work.entry); + if (death->work.type == BINDER_WORK_DEAD_BINDER_AND_CLEAR) { + death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; + if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { + list_add_tail(&death->work.entry, &thread->todo); + } else { + list_add_tail(&death->work.entry, &proc->todo); + wake_up_interruptible(&proc->wait); + } + } + } break; + + default: pr_err("%d:%d unknown command %d\n", proc->pid, thread->pid, cmd); return -EINVAL; @@ -2321,121 +2112,12 @@ static int binder_has_thread_work(struct binder_thread *thread) (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); } -#ifdef CONFIG_COMPAT -static int binder_copy_to_user(uint32_t cmd, void *parcel, - void __user **ptr, size_t size) -{ - if (!is_compat_task()) { - if (put_user(cmd, (uint32_t __user *)*ptr)) - return -EFAULT; - *ptr += sizeof(uint32_t); - if (copy_to_user(*ptr, parcel, size)) - return -EFAULT; - *ptr += size; - return 0; - } - switch (cmd) { - case BR_INCREFS: - case BR_ACQUIRE: - case BR_RELEASE: - case BR_DECREFS: { - struct binder_ptr_cookie *fp; - struct compat_binder_ptr_cookie tmp; - - cmd = compat_change_size(cmd, sizeof(tmp)); - BUG_ON((cmd != COMPAT_BR_INCREFS) && - (cmd != COMPAT_BR_ACQUIRE) && - (cmd != COMPAT_BR_RELEASE) && - (cmd != COMPAT_BR_DECREFS)); - - fp = (struct binder_ptr_cookie *) parcel; - tmp.ptr = ptr_to_compat(fp->ptr); - tmp.cookie = ptr_to_compat(fp->cookie); - if (put_user(cmd, (uint32_t __user *)*ptr)) - return -EFAULT; - *ptr += sizeof(uint32_t); - if (copy_to_user(*ptr, &tmp, sizeof(tmp))) - return -EFAULT; - *ptr += sizeof(tmp); - - break; - } - case BR_DEAD_BINDER: - case BR_CLEAR_DEATH_NOTIFICATION_DONE: { - compat_uptr_t tmp; - - cmd = compat_change_size(cmd, sizeof(tmp)); - BUG_ON((cmd != COMPAT_BR_DEAD_BINDER) && - (cmd != COMPAT_BR_CLEAR_DEATH_NOTIFICATION_DONE)); - - tmp = ptr_to_compat((void *)*(uintptr_t *) parcel); - if (put_user(cmd, (uint32_t __user *)*ptr)) - return -EFAULT; - *ptr += sizeof(uint32_t); - if (copy_to_user(*ptr, &tmp, sizeof(tmp))) - return -EFAULT; - *ptr += sizeof(tmp); - - break; - } - case BR_REPLY: - case BR_TRANSACTION: { - struct binder_transaction_data *fp; - struct compat_binder_transaction_data tmp; - - memset(&tmp, 0, sizeof(tmp)); - cmd = compat_change_size(cmd, sizeof(tmp)); - BUG_ON((cmd != COMPAT_BR_REPLY) && - (cmd != COMPAT_BR_TRANSACTION)); - - fp = (struct binder_transaction_data *) parcel; - /* copy to compat struct */ - tmp.target.ptr = ptr_to_compat(fp->target.ptr); - tmp.cookie = ptr_to_compat(fp->cookie); - tmp.code = fp->code; - tmp.flags = fp->flags; - tmp.sender_pid = fp->sender_pid; - tmp.sender_euid = fp->sender_euid; - tmp.data_size = (compat_size_t) fp->data_size; - tmp.offsets_size = (compat_size_t) fp->offsets_size; - tmp.data.ptr.buffer = ptr_to_compat((void *)fp->data.ptr.buffer); - tmp.data.ptr.offsets = ptr_to_compat((void *)fp->data.ptr.offsets); - - if (put_user(cmd, (uint32_t __user *)*ptr)) - return -EFAULT; - *ptr += sizeof(uint32_t); - if (copy_to_user(*ptr, &tmp, sizeof(tmp))) - return -EFAULT; - *ptr += sizeof(tmp); - - break; - } - default: - pr_err("unexpected user copy, cmd %d, ptr %p\n", - cmd, (void *)*(uintptr_t *)ptr); - return -EFAULT; - } - return 0; -} -#else -static int binder_copy_to_user(uint32_t cmd, void *parcel, - void __user **ptr, size_t size) -{ - if (put_user(cmd, (uint32_t __user *)*ptr)) - return -EFAULT; - *ptr += sizeof(uint32_t); - if (copy_to_user(*ptr, parcel, size)) - return -EFAULT; - *ptr += size; - return 0; -} -#endif - static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, - void __user *buffer, size_t size, - size_t *consumed, int non_block) + binder_uintptr_t binder_buffer, size_t size, + binder_size_t *consumed, int non_block) { + void __user *buffer = (void __user *)(uintptr_t)binder_buffer; void __user *ptr = buffer + *consumed; void __user *end = buffer + size; @@ -2527,7 +2209,7 @@ retry: break; } - if (end - ptr < size_helper(tr) + 4) + if (end - ptr < sizeof(tr) + 4) break; switch (w->type) { @@ -2577,32 +2259,39 @@ retry: node->has_weak_ref = 0; } if (cmd != BR_NOOP) { - struct binder_ptr_cookie tmp; - - tmp.ptr = node->ptr; - tmp.cookie = node->cookie; - if (binder_copy_to_user(cmd, &tmp, &ptr, sizeof(struct binder_ptr_cookie))) + if (put_user(cmd, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + if (put_user(node->ptr, + (binder_uintptr_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(binder_uintptr_t); + if (put_user(node->cookie, + (binder_uintptr_t __user *)ptr)) return -EFAULT; + ptr += sizeof(binder_uintptr_t); binder_stat_br(proc, thread, cmd); binder_debug(BINDER_DEBUG_USER_REFS, - "%d:%d %s %d u%p c%p\n", - proc->pid, thread->pid, cmd_name, node->debug_id, node->ptr, node->cookie); + "%d:%d %s %d u%016llx c%016llx\n", + proc->pid, thread->pid, cmd_name, + node->debug_id, + (u64)node->ptr, (u64)node->cookie); } else { list_del_init(&w->entry); if (!weak && !strong) { binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%p c%p deleted\n", + "%d:%d node %d u%016llx c%016llx deleted\n", proc->pid, thread->pid, node->debug_id, - node->ptr, node->cookie); + (u64)node->ptr, (u64)node->cookie); rb_erase(&node->rb_node, &proc->nodes); kfree(node); binder_stats_deleted(BINDER_STAT_NODE); } else { binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%p c%p state unchanged\n", - proc->pid, thread->pid, node->debug_id, node->ptr, - node->cookie); + "%d:%d node %d u%016llx c%016llx state unchanged\n", + proc->pid, thread->pid, node->debug_id, + (u64)node->ptr, (u64)node->cookie); } } } break; @@ -2617,18 +2306,21 @@ retry: cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE; else cmd = BR_DEAD_BINDER; - - if (binder_copy_to_user(cmd, &death->cookie, &ptr, sizeof(void *))) + if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; - + ptr += sizeof(uint32_t); + if (put_user(death->cookie, + (binder_uintptr_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(binder_uintptr_t); binder_stat_br(proc, thread, cmd); binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, - "%d:%d %s %p\n", + "%d:%d %s %016llx\n", proc->pid, thread->pid, cmd == BR_DEAD_BINDER ? "BR_DEAD_BINDER" : "BR_CLEAR_DEATH_NOTIFICATION_DONE", - death->cookie); + (u64)death->cookie); if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) { list_del(&w->entry); @@ -2658,8 +2350,8 @@ retry: binder_set_nice(target_node->min_priority); cmd = BR_TRANSACTION; } else { - tr.target.ptr = NULL; - tr.cookie = NULL; + tr.target.ptr = 0; + tr.cookie = 0; cmd = BR_REPLY; } tr.code = t->code; @@ -2676,25 +2368,31 @@ retry: tr.data_size = t->buffer->data_size; tr.offsets_size = t->buffer->offsets_size; - tr.data.ptr.buffer = (void *)t->buffer->data + - proc->user_buffer_offset; + tr.data.ptr.buffer = (binder_uintptr_t)( + (uintptr_t)t->buffer->data + + proc->user_buffer_offset); tr.data.ptr.offsets = tr.data.ptr.buffer + - align_helper(t->buffer->data_size); + ALIGN(t->buffer->data_size, + sizeof(void *)); - if (binder_copy_to_user(cmd, &tr, &ptr, sizeof(struct binder_transaction_data))) + if (put_user(cmd, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + if (copy_to_user(ptr, &tr, sizeof(tr))) return -EFAULT; + ptr += sizeof(tr); trace_binder_transaction_received(t); binder_stat_br(proc, thread, cmd); binder_debug(BINDER_DEBUG_TRANSACTION, - "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %p-%p\n", + "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n", proc->pid, thread->pid, (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : "BR_REPLY", t->debug_id, t->from ? t->from->proc->pid : 0, t->from ? t->from->pid : 0, cmd, t->buffer->data_size, t->buffer->offsets_size, - tr.data.ptr.buffer, tr.data.ptr.offsets); + (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets); list_del(&t->work.entry); t->buffer->allow_user_free = 1; @@ -2764,8 +2462,8 @@ static void binder_release_work(struct list_head *list) death = container_of(w, struct binder_ref_death, work); binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, - "undelivered death notification, %p\n", - death->cookie); + "undelivered death notification, %016llx\n", + (u64)death->cookie); kfree(death); binder_stats_deleted(BINDER_STAT_DEATH); } break; @@ -2921,12 +2619,13 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) goto err; } binder_debug(BINDER_DEBUG_READ_WRITE, - "%d:%d write %zd at %016lx, read %zd at %016lx\n", - proc->pid, thread->pid, bwr.write_size, - bwr.write_buffer, bwr.read_size, bwr.read_buffer); + "%d:%d write %lld at %016llx, read %lld at %016llx\n", + proc->pid, thread->pid, + (u64)bwr.write_size, (u64)bwr.write_buffer, + (u64)bwr.read_size, (u64)bwr.read_buffer); if (bwr.write_size > 0) { - ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed); + ret = binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size, &bwr.write_consumed); trace_binder_write_done(ret); if (ret < 0) { bwr.read_consumed = 0; @@ -2936,7 +2635,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } } if (bwr.read_size > 0) { - ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); + ret = binder_thread_read(proc, thread, bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); trace_binder_read_done(ret); if (!list_empty(&proc->todo)) wake_up_interruptible(&proc->wait); @@ -2947,9 +2646,10 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } } binder_debug(BINDER_DEBUG_READ_WRITE, - "%d:%d wrote %zd of %zd, read return %zd of %zd\n", - proc->pid, thread->pid, bwr.write_consumed, bwr.write_size, - bwr.read_consumed, bwr.read_size); + "%d:%d wrote %lld of %lld, read return %lld of %lld\n", + proc->pid, thread->pid, + (u64)bwr.write_consumed, (u64)bwr.write_size, + (u64)bwr.read_consumed, (u64)bwr.read_size); if (copy_to_user(ubuf, &bwr, sizeof(bwr))) { ret = -EFAULT; goto err; @@ -2981,7 +2681,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } } else binder_context_mgr_uid = current->cred->euid; - binder_context_mgr_node = binder_new_node(proc, NULL, NULL); + binder_context_mgr_node = binder_new_node(proc, 0, 0); if (binder_context_mgr_node == NULL) { ret = -ENOMEM; goto err; @@ -3024,80 +2724,6 @@ err_unlocked: return ret; } -/* TODO: add tracepoint */ -#ifdef CONFIG_COMPAT -static long compat_binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - int ret = 0; - struct binder_thread *thread; - struct compat_binder_write_read bwr; - struct binder_proc *proc = filp->private_data; - void __user *ubuf = compat_ptr(arg); - - /* pr_info("compat_binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg); */ - - if (cmd != COMPAT_BINDER_WRITE_READ) - return binder_ioctl(filp, cmd, arg); - - BUG_ON(!is_compat_task()); - binder_lock(__func__); - thread = binder_get_thread(proc); - if (thread == NULL) { - ret = -ENOMEM; - goto err; - } - - /* COMPAT_BINDER_WRITE_READ */ - if (copy_from_user(&bwr, ubuf, sizeof(bwr))) { - ret = -EFAULT; - goto err; - } - binder_debug(BINDER_DEBUG_READ_WRITE, - "compat: %d:%d write %d at %016x, read %d at %016x\n", - proc->pid, thread->pid, bwr.write_size, - bwr.write_buffer, bwr.read_size, bwr.read_buffer); - - if (bwr.write_size > 0) { - size_t tmp_write_consumed = (size_t)bwr.write_consumed; - ret = binder_thread_write(proc, thread, compat_ptr(bwr.write_buffer), (size_t)bwr.write_size, &tmp_write_consumed); - bwr.write_consumed = (compat_size_t)tmp_write_consumed; - if (ret < 0) { - bwr.read_consumed = 0; - if (copy_to_user(ubuf, &bwr, sizeof(bwr))) - ret = -EFAULT; - goto err; - } - } - - if (bwr.read_size > 0) { - size_t tmp_read_consumed = (size_t)bwr.read_consumed; - ret = binder_thread_read(proc, thread, compat_ptr(bwr.read_buffer), (size_t)bwr.read_size, &tmp_read_consumed, filp->f_flags & O_NONBLOCK); - bwr.read_consumed = (compat_size_t)tmp_read_consumed; - if (!list_empty(&proc->todo)) - wake_up_interruptible(&proc->wait); - if (ret < 0) { - if (copy_to_user(ubuf, &bwr, sizeof(bwr))) - ret = -EFAULT; - goto err; - } - } - binder_debug(BINDER_DEBUG_READ_WRITE, - "compat: %d:%d wrote %d of %d, read return %d of %d\n", - proc->pid, thread->pid, bwr.write_consumed, bwr.write_size, - bwr.read_consumed, bwr.read_size); - if (copy_to_user(ubuf, &bwr, sizeof(bwr))) - ret = -EFAULT; - -err: - if (thread) - thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN; - binder_unlock(__func__); - if (ret && ret != -ERESTARTSYS) - pr_info("%d:%d compat ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); - return ret; -} -#endif - static void binder_vma_open(struct vm_area_struct *vma) { struct binder_proc *proc = vma->vm_private_data; @@ -3550,8 +3176,9 @@ static void print_binder_work(struct seq_file *m, const char *prefix, break; case BINDER_WORK_NODE: node = container_of(w, struct binder_node, work); - seq_printf(m, "%snode work %d: u%p c%p\n", - prefix, node->debug_id, node->ptr, node->cookie); + seq_printf(m, "%snode work %d: u%016llx c%016llx\n", + prefix, node->debug_id, + (u64)node->ptr, (u64)node->cookie); break; case BINDER_WORK_DEAD_BINDER: seq_printf(m, "%shas dead binder\n", prefix); @@ -3611,8 +3238,8 @@ static void print_binder_node(struct seq_file *m, struct binder_node *node) hlist_for_each_entry(ref, &node->refs, node_entry) count++; - seq_printf(m, " node %d: u%p c%p hs %d hw %d ls %d lw %d is %d iw %d", - node->debug_id, node->ptr, node->cookie, + seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d", + node->debug_id, (u64)node->ptr, (u64)node->cookie, node->has_strong_ref, node->has_weak_ref, node->local_strong_refs, node->local_weak_refs, node->internal_strong_refs, count); @@ -3914,9 +3541,7 @@ static const struct file_operations binder_fops = { .owner = THIS_MODULE, .poll = binder_poll, .unlocked_ioctl = binder_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = compat_binder_ioctl, -#endif + .compat_ioctl = binder_ioctl, .mmap = binder_mmap, .open = binder_open, .flush = binder_flush, |