aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBintian Wang <bintian.wang@linaro.org>2013-10-09 18:52:57 +0800
committerMark Brown <broonie@linaro.org>2014-01-22 15:36:17 +0000
commit56373a4736117e97330ebd049e235f9baca381c8 (patch)
tree9e46acb2144d720142ecfee2213c6206298caa86
parente986cff7970bb3de117c92db44cf3618848ddb25 (diff)
Android: Add support for 32-bit Binder calls in a 64-bit kernel
Android's IPC, Binder, does not support calls from a 32-bit userspace in a 64 bit kernel. This patch adds support for syscalls coming from a 32-bit userspace in a 64-bit kernel. Most of the changes were applied to types that change sizes between 32 and 64 bit world. This will also fix some of the issues around checking the size of an incoming transaction package in the ioctl switch. Since the transaction's ioctl number are generated using _IOC(dir,type,nr,size), a different userspace size will generate a different ioctl number, thus switching by _IOC_NR is a better solution. The patch has been successfully tested on ARMv8 AEM and Versatile Express V2P-CA9. [Fixed up several conflicts with upstream -- broonie] Signed-off-by: Serban Constantinescu <serban.constantinescu@arm.com> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r--drivers/staging/android/binder.c275
-rw-r--r--drivers/staging/android/binder.h308
2 files changed, 456 insertions, 127 deletions
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index f8d5b03f5444..87f1e1ca8dc5 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -229,8 +229,8 @@ struct binder_node {
int internal_strong_refs;
int local_weak_refs;
int local_strong_refs;
- void __user *ptr;
- void __user *cookie;
+ userptr32_t ptr;
+ userptr32_t cookie;
unsigned has_strong_ref:1;
unsigned pending_strong_ref:1;
unsigned has_weak_ref:1;
@@ -243,7 +243,7 @@ struct binder_node {
struct binder_ref_death {
struct binder_work work;
- void __user *cookie;
+ userptr32_t cookie;
};
struct binder_ref {
@@ -318,7 +318,7 @@ struct binder_proc {
int requested_threads;
int requested_threads_started;
int ready_threads;
- long default_priority;
+ int default_priority;
struct dentry *debugfs_entry;
};
@@ -360,8 +360,8 @@ struct binder_transaction {
struct binder_buffer *buffer;
unsigned int code;
unsigned int flags;
- long priority;
- long saved_priority;
+ int priority;
+ int saved_priority;
kuid_t sender_euid;
};
@@ -430,16 +430,16 @@ static inline void binder_unlock(const char *tag)
mutex_unlock(&binder_main_lock);
}
-static void binder_set_nice(long nice)
+static void binder_set_nice(int nice)
{
- long min_nice;
+ int min_nice;
if (can_nice(current, nice)) {
set_user_nice(current, nice);
return;
}
min_nice = 20 - current->signal->rlim[RLIMIT_NICE].rlim_cur;
binder_debug(BINDER_DEBUG_PRIORITY_CAP,
- "%d: nice value %ld not allowed use %ld instead\n",
+ "%d: nice value %d not allowed use %d instead\n",
current->pid, nice, min_nice);
set_user_nice(current, min_nice);
if (min_nice < 20)
@@ -516,13 +516,13 @@ 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)
+ userptr32_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
+ kern_ptr = (void *)(unsigned long)user_ptr - proc->user_buffer_offset
- offsetof(struct binder_buffer, data);
while (n) {
@@ -660,8 +660,8 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc,
return NULL;
}
- size = ALIGN(data_size, sizeof(void *)) +
- ALIGN(offsets_size, sizeof(void *));
+ size = ALIGN(data_size, sizeof(userptr32_t)) +
+ ALIGN(offsets_size, sizeof(userptr32_t));
if (size < data_size || size < offsets_size) {
binder_user_error("%d: got transaction with invalid size %zd-%zd\n",
@@ -809,8 +809,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 *));
+ size = ALIGN(buffer->data_size, sizeof(userptr32_t)) +
+ ALIGN(buffer->offsets_size, sizeof(userptr32_t));
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: binder_free_buf %p size %zd buffer_size %zd\n",
@@ -857,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)
+ userptr32_t ptr)
{
struct rb_node *n = proc->nodes.rb_node;
struct binder_node *node;
@@ -876,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)
+ userptr32_t ptr,
+ userptr32_t cookie)
{
struct rb_node **p = &proc->nodes.rb_node;
struct rb_node *parent = NULL;
@@ -909,7 +909,7 @@ 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%x c%x created\n",
proc->pid, current->pid, node->debug_id,
node->ptr, node->cookie);
return node;
@@ -1227,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)
+ uint32_t *failed_at)
{
- size_t *offp, *off_end;
+ uint32_t *offp, *off_end;
int debug_id = buffer->debug_id;
binder_debug(BINDER_DEBUG_TRANSACTION,
@@ -1240,17 +1240,18 @@ 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(buffer->data_size, sizeof(void *)));
+ offp = (uint32_t *)(buffer->data +
+ ALIGN(buffer->data_size, sizeof(userptr32_t)));
if (failed_at)
off_end = failed_at;
else
- off_end = (void *)offp + buffer->offsets_size;
+ off_end = (uint32_t *)offp + (buffer->offsets_size/4);
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(void *))) {
- pr_err("transaction release %d bad offset %zd, size %zd\n",
+ !IS_ALIGNED(*offp, sizeof(userptr32_t))) {
+ pr_err("transaction release %d bad offset %x, size %zd\n",
debug_id, *offp, buffer->data_size);
continue;
}
@@ -1260,12 +1261,11 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
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 %x\n", debug_id, fp->binder);
break;
}
binder_debug(BINDER_DEBUG_TRANSACTION,
- " node %d u%p\n",
+ " node %d u%x\n",
node->debug_id, node->ptr);
binder_dec_node(node, fp->type == BINDER_TYPE_BINDER, 0);
} break;
@@ -1304,7 +1304,7 @@ static void binder_transaction(struct binder_proc *proc,
{
struct binder_transaction *t;
struct binder_work *tcomplete;
- size_t *offp, *off_end;
+ uint32_t *offp, *off_end;
struct binder_proc *target_proc;
struct binder_thread *target_thread = NULL;
struct binder_node *target_node = NULL;
@@ -1437,14 +1437,14 @@ 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 %x-%x size %d-%d\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);
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 %x-%x size %d-%d\n",
proc->pid, thread->pid, t->debug_id,
target_proc->pid, target_node->debug_id,
tr->data.ptr.buffer, tr->data.ptr.offsets,
@@ -1477,33 +1477,34 @@ 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(tr->data_size, sizeof(void *)));
+ offp = (uint32_t *)(t->buffer->data +
+ ALIGN(tr->data_size, sizeof(userptr32_t)));
- if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {
+ if (copy_from_user(t->buffer->data, (void *)(unsigned long)(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, (void *)(unsigned long)(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, sizeof(size_t))) {
- binder_user_error("%d:%d got transaction with invalid offsets size, %zd\n",
+ if (!IS_ALIGNED(tr->offsets_size, sizeof(uint32_t))) {
+ binder_user_error("%d:%d got transaction with invalid offsets size, %d\n",
proc->pid, thread->pid, tr->offsets_size);
return_error = BR_FAILED_REPLY;
goto err_bad_offset;
}
- off_end = (void *)offp + tr->offsets_size;
+ off_end = (uint32_t *)offp + (tr->offsets_size/4);
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(void *))) {
- binder_user_error("%d:%d got transaction with invalid offset, %zd\n",
+ !IS_ALIGNED(*offp, sizeof(userptr32_t))) {
+ binder_user_error("%d:%d got transaction with invalid offset, %x\n",
proc->pid, thread->pid, *offp);
return_error = BR_FAILED_REPLY;
goto err_bad_offset;
@@ -1524,7 +1525,7 @@ 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%x node %d, cookie mismatch %x != %x\n",
proc->pid, thread->pid,
fp->binder, node->debug_id,
fp->cookie, node->cookie);
@@ -1549,7 +1550,7 @@ 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 %d u%x -> ref %d desc %d\n",
node->debug_id, node->ptr, ref->debug_id,
ref->desc);
} break;
@@ -1577,7 +1578,7 @@ 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%x\n",
ref->debug_id, ref->desc, ref->node->debug_id,
ref->node->ptr);
} else {
@@ -1700,7 +1701,7 @@ 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 %d-%d\n",
proc->pid, thread->pid, return_error,
tr->data_size, tr->offsets_size);
@@ -1719,7 +1720,7 @@ err_no_context_mgr_node:
}
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
- void __user *buffer, int size, signed long *consumed)
+ void __user *buffer, int size, int *consumed)
{
uint32_t cmd;
void __user *ptr = buffer + *consumed;
@@ -1735,11 +1736,16 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
proc->stats.bc[_IOC_NR(cmd)]++;
thread->stats.bc[_IOC_NR(cmd)]++;
}
- switch (cmd) {
- case BC_INCREFS:
- case BC_ACQUIRE:
- case BC_RELEASE:
- case BC_DECREFS: {
+ /*
+ * since the transaction's IOCTL number are generated using
+ * _IOC(dir,type,nr,size), a different userspace size will not
+ * fall through
+ */
+ switch (_IOC_NR(cmd)) {
+ case _IOC_NR(BC_INCREFS):
+ case _IOC_NR(BC_ACQUIRE):
+ case _IOC_NR(BC_RELEASE):
+ case _IOC_NR(BC_DECREFS): {
uint32_t target;
struct binder_ref *ref;
const char *debug_string;
@@ -1763,20 +1769,20 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
proc->pid, thread->pid, target);
break;
}
- switch (cmd) {
- case BC_INCREFS:
+ switch (_IOC_NR(cmd)) {
+ case _IOC_NR(BC_INCREFS):
debug_string = "IncRefs";
binder_inc_ref(ref, 0, NULL);
break;
- case BC_ACQUIRE:
+ case _IOC_NR(BC_ACQUIRE):
debug_string = "Acquire";
binder_inc_ref(ref, 1, NULL);
break;
- case BC_RELEASE:
+ case _IOC_NR(BC_RELEASE):
debug_string = "Release";
binder_dec_ref(ref, 1);
break;
- case BC_DECREFS:
+ case _IOC_NR(BC_DECREFS):
default:
debug_string = "DecRefs";
binder_dec_ref(ref, 0);
@@ -1788,21 +1794,25 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
ref->desc, ref->strong, ref->weak, ref->node->debug_id);
break;
}
- case BC_INCREFS_DONE:
- case BC_ACQUIRE_DONE: {
- void __user *node_ptr;
- void *cookie;
+ case _IOC_NR(BC_INCREFS_DONE):
+ case _IOC_NR(BC_ACQUIRE_DONE): {
+ userptr32_t node_ptr;
+ userptr32_t cookie;
struct binder_node *node;
- if (get_user(node_ptr, (void * __user *)ptr))
+ if (_IOC_SIZE(cmd) != sizeof(struct binder_ptr_cookie)) {
+ pr_err("binder: tranzaction structure size differs\n");
return -EFAULT;
- ptr += sizeof(void *);
- if (get_user(cookie, (void * __user *)ptr))
+ }
+ if (get_user(node_ptr, (userptr32_t __user *)ptr))
+ return -EFAULT;
+ ptr += sizeof(userptr32_t);
+ if (get_user(cookie, (userptr32_t __user *)ptr))
return -EFAULT;
- ptr += sizeof(void *);
+ ptr += sizeof(userptr32_t);
node = binder_get_node(proc, node_ptr);
if (node == NULL) {
- binder_user_error("%d:%d %s u%p no match\n",
+ binder_user_error("%d:%d %s u%x no match\n",
proc->pid, thread->pid,
cmd == BC_INCREFS_DONE ?
"BC_INCREFS_DONE" :
@@ -1811,7 +1821,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
break;
}
if (cookie != node->cookie) {
- binder_user_error("%d:%d %s u%p node %d cookie mismatch %p != %p\n",
+ binder_user_error("%d:%d %s u%x node %d cookie mismatch %x != %x\n",
proc->pid, thread->pid,
cmd == BC_INCREFS_DONE ?
"BC_INCREFS_DONE" : "BC_ACQUIRE_DONE",
@@ -1844,34 +1854,34 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
node->debug_id, node->local_strong_refs, node->local_weak_refs);
break;
}
- case BC_ATTEMPT_ACQUIRE:
+ case _IOC_NR(BC_ATTEMPT_ACQUIRE):
pr_err("BC_ATTEMPT_ACQUIRE not supported\n");
return -EINVAL;
- case BC_ACQUIRE_RESULT:
+ case _IOC_NR(BC_ACQUIRE_RESULT):
pr_err("BC_ACQUIRE_RESULT not supported\n");
return -EINVAL;
- case BC_FREE_BUFFER: {
- void __user *data_ptr;
+ case _IOC_NR(BC_FREE_BUFFER): {
+ userptr32_t data_ptr;
struct binder_buffer *buffer;
- if (get_user(data_ptr, (void * __user *)ptr))
+ if (get_user(data_ptr, (userptr32_t __user *)ptr))
return -EFAULT;
- ptr += sizeof(void *);
+ ptr += sizeof(userptr32_t);
buffer = binder_buffer_lookup(proc, data_ptr);
if (buffer == NULL) {
- binder_user_error("%d:%d BC_FREE_BUFFER u%p no match\n",
+ binder_user_error("%d:%d BC_FREE_BUFFER u%x no match\n",
proc->pid, thread->pid, data_ptr);
break;
}
if (!buffer->allow_user_free) {
- binder_user_error("%d:%d BC_FREE_BUFFER u%p matched unreturned buffer\n",
+ binder_user_error("%d:%d BC_FREE_BUFFER u%x matched unreturned buffer\n",
proc->pid, thread->pid, data_ptr);
break;
}
binder_debug(BINDER_DEBUG_FREE_BUFFER,
- "%d:%d BC_FREE_BUFFER u%p found buffer %d for %s transaction\n",
+ "%d:%d BC_FREE_BUFFER u%x found buffer %d for %s transaction\n",
proc->pid, thread->pid, data_ptr, buffer->debug_id,
buffer->transaction ? "active" : "finished");
@@ -1892,10 +1902,14 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
break;
}
- case BC_TRANSACTION:
- case BC_REPLY: {
+ case _IOC_NR(BC_TRANSACTION):
+ case _IOC_NR(BC_REPLY): {
struct binder_transaction_data tr;
+ if (_IOC_SIZE(cmd) != sizeof(tr)) {
+ pr_err("binder: tranzaction structure size differs\n");
+ return -EFAULT;
+ }
if (copy_from_user(&tr, ptr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
@@ -1903,7 +1917,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
break;
}
- case BC_REGISTER_LOOPER:
+ case _IOC_NR(BC_REGISTER_LOOPER):
binder_debug(BINDER_DEBUG_THREADS,
"%d:%d BC_REGISTER_LOOPER\n",
proc->pid, thread->pid);
@@ -1921,7 +1935,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
}
thread->looper |= BINDER_LOOPER_STATE_REGISTERED;
break;
- case BC_ENTER_LOOPER:
+ case _IOC_NR(BC_ENTER_LOOPER):
binder_debug(BINDER_DEBUG_THREADS,
"%d:%d BC_ENTER_LOOPER\n",
proc->pid, thread->pid);
@@ -1932,26 +1946,26 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
}
thread->looper |= BINDER_LOOPER_STATE_ENTERED;
break;
- case BC_EXIT_LOOPER:
+ case _IOC_NR(BC_EXIT_LOOPER):
binder_debug(BINDER_DEBUG_THREADS,
"%d:%d BC_EXIT_LOOPER\n",
proc->pid, thread->pid);
thread->looper |= BINDER_LOOPER_STATE_EXITED;
break;
- case BC_REQUEST_DEATH_NOTIFICATION:
- case BC_CLEAR_DEATH_NOTIFICATION: {
+ case _IOC_NR(BC_REQUEST_DEATH_NOTIFICATION):
+ case _IOC_NR(BC_CLEAR_DEATH_NOTIFICATION): {
uint32_t target;
- void __user *cookie;
+ userptr32_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, (userptr32_t __user *)ptr))
return -EFAULT;
- ptr += sizeof(void *);
+ ptr += sizeof(userptr32_t);
ref = binder_get_ref(proc, target);
if (ref == NULL) {
binder_user_error("%d:%d %s invalid ref %d\n",
@@ -1964,7 +1978,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
}
binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION,
- "%d:%d %s %p ref %d desc %d s %d w %d for node %d\n",
+ "%d:%d %s %x 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" :
@@ -2007,7 +2021,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
}
death = ref->death;
if (death->cookie != cookie) {
- binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %p != %p\n",
+ binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %x != %x\n",
proc->pid, thread->pid,
death->cookie, cookie);
break;
@@ -2027,14 +2041,13 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
}
}
} break;
- case BC_DEAD_BINDER_DONE: {
+ case _IOC_NR(BC_DEAD_BINDER_DONE): {
struct binder_work *w;
- void __user *cookie;
+ userptr32_t cookie;
struct binder_ref_death *death = NULL;
- if (get_user(cookie, (void __user * __user *)ptr))
+ if (get_user(cookie, (userptr32_t __user *)ptr))
return -EFAULT;
-
- ptr += sizeof(void *);
+ ptr += sizeof(userptr32_t);
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) {
@@ -2043,10 +2056,10 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
}
}
binder_debug(BINDER_DEBUG_DEAD_BINDER,
- "%d:%d BC_DEAD_BINDER_DONE %p found %p\n",
+ "%d:%d BC_DEAD_BINDER_DONE %x 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",
+ binder_user_error("%d:%d BC_DEAD_BINDER_DONE %x not found\n",
proc->pid, thread->pid, cookie);
break;
}
@@ -2100,7 +2113,7 @@ static int binder_has_thread_work(struct binder_thread *thread)
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
void __user *buffer, int size,
- signed long *consumed, int non_block)
+ int *consumed, int non_block)
{
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
@@ -2246,22 +2259,22 @@ retry:
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
- if (put_user(node->ptr, (void * __user *)ptr))
+ if (put_user((unsigned long)node->ptr, (userptr32_t __user *)ptr))
return -EFAULT;
- ptr += sizeof(void *);
- if (put_user(node->cookie, (void * __user *)ptr))
+ ptr += sizeof(userptr32_t);
+ if (put_user((unsigned long)node->cookie, (userptr32_t __user *)ptr))
return -EFAULT;
- ptr += sizeof(void *);
+ ptr += sizeof(userptr32_t);
binder_stat_br(proc, thread, cmd);
binder_debug(BINDER_DEBUG_USER_REFS,
- "%d:%d %s %d u%p c%p\n",
+ "%d:%d %s %d u%x c%x\n",
proc->pid, thread->pid, cmd_name, node->debug_id, node->ptr, 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%x c%x deleted\n",
proc->pid, thread->pid, node->debug_id,
node->ptr, node->cookie);
rb_erase(&node->rb_node, &proc->nodes);
@@ -2269,7 +2282,7 @@ retry:
binder_stats_deleted(BINDER_STAT_NODE);
} else {
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
- "%d:%d node %d u%p c%p state unchanged\n",
+ "%d:%d node %d u%x c%x state unchanged\n",
proc->pid, thread->pid, node->debug_id, node->ptr,
node->cookie);
}
@@ -2289,12 +2302,12 @@ retry:
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
- if (put_user(death->cookie, (void * __user *)ptr))
+ if (put_user((unsigned long)death->cookie, (userptr32_t __user *)ptr))
return -EFAULT;
- ptr += sizeof(void *);
+ ptr += sizeof(userptr32_t);
binder_stat_br(proc, thread, cmd);
binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION,
- "%d:%d %s %p\n",
+ "%d:%d %s %x\n",
proc->pid, thread->pid,
cmd == BR_DEAD_BINDER ?
"BR_DEAD_BINDER" :
@@ -2329,8 +2342,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;
@@ -2345,13 +2358,14 @@ retry:
tr.sender_pid = 0;
}
- 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.offsets = tr.data.ptr.buffer +
+ tr.data_size = (userptr32_t)t->buffer->data_size;
+ tr.offsets_size = (userptr32_t)t->buffer->offsets_size;
+ tr.data.ptr.buffer = (unsigned long)((void *)t->buffer->data +
+ proc->user_buffer_offset);
+
+ tr.data.ptr.offsets = (userptr32_t)(tr.data.ptr.buffer +
ALIGN(t->buffer->data_size,
- sizeof(void *));
+ sizeof(userptr32_t)));
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
@@ -2363,7 +2377,7 @@ retry:
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 %x-%x\n",
proc->pid, thread->pid,
(cmd == BR_TRANSACTION) ? "BR_TRANSACTION" :
"BR_REPLY",
@@ -2585,10 +2599,16 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
goto err;
}
- switch (cmd) {
- case BINDER_WRITE_READ: {
+ /*
+ * since the transaction's IOCTL number are generated using
+ * _IOC(dir,type,nr,size), a different userspace size will not
+ * fall through
+ */
+ switch (_IOC_NR(cmd)) {
+ case _IOC_NR(BINDER_WRITE_READ): {
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {
+ pr_err("binder: BINDER_WRITE_READ transaction size differs\n");
ret = -EINVAL;
goto err;
}
@@ -2597,12 +2617,12 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
goto err;
}
binder_debug(BINDER_DEBUG_READ_WRITE,
- "%d:%d write %ld at %08lx, read %ld at %08lx\n",
+ "%d:%d write %d at %08x, read %d at %08x\n",
proc->pid, thread->pid, bwr.write_size,
bwr.write_buffer, bwr.read_size, 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, (void __user *)(unsigned long)(bwr.write_buffer), bwr.write_size, &bwr.write_consumed);
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
@@ -2612,7 +2632,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, (void __user *)(unsigned long)(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);
@@ -2623,7 +2643,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
}
binder_debug(BINDER_DEBUG_READ_WRITE,
- "%d:%d wrote %ld of %ld, read return %ld of %ld\n",
+ "%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))) {
@@ -2632,13 +2652,13 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
break;
}
- case BINDER_SET_MAX_THREADS:
+ case _IOC_NR(BINDER_SET_MAX_THREADS):
if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
ret = -EINVAL;
goto err;
}
break;
- case BINDER_SET_CONTEXT_MGR:
+ case _IOC_NR(BINDER_SET_CONTEXT_MGR):
if (binder_context_mgr_node != NULL) {
pr_err("BINDER_SET_CONTEXT_MGR already set\n");
ret = -EBUSY;
@@ -2657,7 +2677,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;
@@ -2667,14 +2687,15 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
binder_context_mgr_node->has_strong_ref = 1;
binder_context_mgr_node->has_weak_ref = 1;
break;
- case BINDER_THREAD_EXIT:
+ case _IOC_NR(BINDER_THREAD_EXIT):
binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n",
proc->pid, thread->pid);
binder_free_thread(proc, thread);
thread = NULL;
break;
- case BINDER_VERSION:
+ case _IOC_NR(BINDER_VERSION):
if (size != sizeof(struct binder_version)) {
+ pr_err("binder: BINDER_VERSION size differs\n");
ret = -EINVAL;
goto err;
}
@@ -2684,6 +2705,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
break;
default:
+ pr_err("binder: IOCTL No. not found\n");
ret = -EINVAL;
goto err;
}
@@ -3108,7 +3130,7 @@ static void print_binder_transaction(struct seq_file *m, const char *prefix,
struct binder_transaction *t)
{
seq_printf(m,
- "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d",
+ "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %d r%d",
prefix, t->debug_id, t,
t->from ? t->from->proc->pid : 0,
t->from ? t->from->pid : 0,
@@ -3153,7 +3175,7 @@ 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",
+ seq_printf(m, "%snode work %d: u%x c%x\n",
prefix, node->debug_id, node->ptr, node->cookie);
break;
case BINDER_WORK_DEAD_BINDER:
@@ -3214,7 +3236,7 @@ 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",
+ seq_printf(m, " node %d: u%x c%x hs %d hw %d ls %d lw %d is %d iw %d",
node->debug_id, node->ptr, node->cookie,
node->has_strong_ref, node->has_weak_ref,
node->local_strong_refs, node->local_weak_refs,
@@ -3517,6 +3539,7 @@ static const struct file_operations binder_fops = {
.owner = THIS_MODULE,
.poll = binder_poll,
.unlocked_ioctl = binder_ioctl,
+ .compat_ioctl = binder_ioctl, /* handler for 32-bit compat layer */
.mmap = binder_mmap,
.open = binder_open,
.flush = binder_flush,
diff --git a/drivers/staging/android/binder.h b/drivers/staging/android/binder.h
index d4101a671718..f514f30db1a6 100644
--- a/drivers/staging/android/binder.h
+++ b/drivers/staging/android/binder.h
@@ -20,7 +20,313 @@
#ifndef _LINUX_BINDER_H
#define _LINUX_BINDER_H
-#include "uapi/binder.h"
+#include <linux/ioctl.h>
+
+#define B_PACK_CHARS(c1, c2, c3, c4) \
+ ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
+#define B_TYPE_LARGE 0x85
+
+typedef uint32_t userptr32_t;
+
+enum {
+ BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
+ BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
+ BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
+ BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
+ BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
+};
+
+enum {
+ FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff,
+ FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100,
+};
+
+/*
+ * This is the flattened representation of a Binder object for transfer
+ * between processes. The 'offsets' supplied as part of a binder transaction
+ * contains offsets into the data where these structures occur. The Binder
+ * driver takes care of re-writing the structure type and data as it moves
+ * between processes.
+ */
+struct flat_binder_object {
+ /* 8 bytes for large_flat_header. */
+ uint32_t type;
+ uint32_t flags;
+
+ /* 8 bytes of data. */
+ union {
+ userptr32_t binder; /* local object */
+ int32_t handle; /* remote object */
+ };
+
+ /* extra data associated with local object */
+ userptr32_t cookie;
+};
+
+/*
+ * On 64-bit platforms where user code may run in 32-bits the driver must
+ * translate the buffer (and local binder) addresses appropriately.
+ */
+
+struct binder_write_read {
+ int32_t write_size; /* bytes to write */
+ int32_t write_consumed; /* bytes consumed by driver */
+ uint32_t write_buffer;
+ int32_t read_size; /* bytes to read */
+ int32_t read_consumed; /* bytes consumed by driver */
+ uint32_t read_buffer;
+};
+
+/* Use with BINDER_VERSION, driver fills in fields. */
+struct binder_version {
+ /* driver protocol version -- increment with incompatible change */
+ int32_t protocol_version;
+};
+
+/* This is the current protocol version. */
+#define BINDER_CURRENT_PROTOCOL_VERSION 7
+
+#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
+#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64)
+#define BINDER_SET_MAX_THREADS _IOW('b', 5, uint32_t)
+#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32)
+#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
+#define BINDER_THREAD_EXIT _IOW('b', 8, __s32)
+#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
+
+/*
+ * NOTE: Two special error codes you should check for when calling
+ * in to the driver are:
+ *
+ * EINTR -- The operation has been interupted. This should be
+ * handled by retrying the ioctl() until a different error code
+ * is returned.
+ *
+ * ECONNREFUSED -- The driver is no longer accepting operations
+ * from your process. That is, the process is being destroyed.
+ * You should handle this by exiting from your process. Note
+ * that once this error code is returned, all further calls to
+ * the driver from any thread will return this same code.
+ */
+
+enum transaction_flags {
+ TF_ONE_WAY = 0x01, /* this is a one-way call: async, no return */
+ TF_ROOT_OBJECT = 0x04, /* contents are the component's root object */
+ TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */
+ TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */
+};
+
+struct binder_transaction_data {
+ /* The first two are only used for bcTRANSACTION and brTRANSACTION,
+ * identifying the target and contents of the transaction.
+ */
+ union {
+ uint32_t handle; /* target descriptor of command transaction */
+ userptr32_t ptr; /* target descriptor of return transaction */
+ } target;
+ userptr32_t cookie; /* target object cookie */
+ unsigned int code; /* transaction command */
+
+ /* General information about the transaction. */
+ __u32 flags;
+ pid_t sender_pid;
+ uid_t sender_euid;
+ uint32_t data_size; /* number of bytes of data */
+ uint32_t offsets_size; /* number of bytes of offsets */
+
+ /* If this transaction is inline, the data immediately
+ * follows here; otherwise, it ends with a pointer to
+ * the data buffer.
+ */
+ union {
+ struct {
+ /* transaction data */
+ userptr32_t buffer;
+ /* offsets from buffer to flat_binder_object structs */
+ userptr32_t offsets;
+ } ptr;
+ __u8 buf[8];
+ } data;
+};
+
+struct binder_ptr_cookie {
+ userptr32_t tr;
+ userptr32_t cookie;
+};
+
+struct binder_pri_desc {
+ __s32 priority;
+ __u32 desc;
+};
+
+struct binder_pri_ptr_cookie {
+ int priority;
+ userptr32_t ptr;
+ userptr32_t cookie;
+};
+
+enum binder_driver_return_protocol {
+ BR_ERROR = _IOR('r', 0, __s32),
+ /*
+ * int: error code
+ */
+
+ BR_OK = _IO('r', 1),
+ /* No parameters! */
+
+ BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data),
+ BR_REPLY = _IOR('r', 3, struct binder_transaction_data),
+ /*
+ * binder_transaction_data: the received command.
+ */
+
+ BR_ACQUIRE_RESULT = _IOR('r', 4, __s32),
+ /*
+ * not currently supported
+ * int: 0 if the last bcATTEMPT_ACQUIRE was not successful.
+ * Else the remote object has acquired a primary reference.
+ */
+
+ BR_DEAD_REPLY = _IO('r', 5),
+ /*
+ * The target of the last transaction (either a bcTRANSACTION or
+ * a bcATTEMPT_ACQUIRE) is no longer with us. No parameters.
+ */
+
+ BR_TRANSACTION_COMPLETE = _IO('r', 6),
+ /*
+ * No parameters... always refers to the last transaction requested
+ * (including replies). Note that this will be sent even for
+ * asynchronous transactions.
+ */
+
+ BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie),
+ BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie),
+ BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie),
+ BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie),
+ /*
+ * void *: ptr to binder
+ * void *: cookie for binder
+ */
+
+ BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cookie),
+ /*
+ * not currently supported
+ * int: priority
+ * void *: ptr to binder
+ * void *: cookie for binder
+ */
+
+ BR_NOOP = _IO('r', 12),
+ /*
+ * No parameters. Do nothing and examine the next command. It exists
+ * primarily so that we can replace it with a BR_SPAWN_LOOPER command.
+ */
+
+ BR_SPAWN_LOOPER = _IO('r', 13),
+ /*
+ * No parameters. The driver has determined that a process has no
+ * threads waiting to service incoming transactions. When a process
+ * receives this command, it must spawn a new service thread and
+ * register it via bcENTER_LOOPER.
+ */
+
+ BR_FINISHED = _IO('r', 14),
+ /*
+ * not currently supported
+ * stop threadpool thread
+ */
+
+ BR_DEAD_BINDER = _IOR('r', 15, userptr32_t),
+ /*
+ * void *: cookie
+ */
+ BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, userptr32_t),
+ /*
+ * void *: cookie
+ */
+
+ BR_FAILED_REPLY = _IO('r', 17),
+ /*
+ * The the last transaction (either a bcTRANSACTION or
+ * a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters.
+ */
+};
+
+enum binder_driver_command_protocol {
+ BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data),
+ BC_REPLY = _IOW('c', 1, struct binder_transaction_data),
+ /*
+ * binder_transaction_data: the sent command.
+ */
+
+ BC_ACQUIRE_RESULT = _IOW('c', 2, __s32),
+ /*
+ * not currently supported
+ * int: 0 if the last BR_ATTEMPT_ACQUIRE was not successful.
+ * Else you have acquired a primary reference on the object.
+ */
+
+ BC_FREE_BUFFER = _IOW('c', 3, void *),
+ /*
+ * void *: ptr to transaction data received on a read
+ */
+
+ BC_INCREFS = _IOW('c', 4, __u32),
+ BC_ACQUIRE = _IOW('c', 5, __u32),
+ BC_RELEASE = _IOW('c', 6, __u32),
+ BC_DECREFS = _IOW('c', 7, __u32),
+ /*
+ * int: descriptor
+ */
+
+ BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie),
+ BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie),
+ /*
+ * void *: ptr to binder
+ * void *: cookie for binder
+ */
+
+ BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc),
+ /*
+ * not currently supported
+ * int: priority
+ * int: descriptor
+ */
+
+ BC_REGISTER_LOOPER = _IO('c', 11),
+ /*
+ * No parameters.
+ * Register a spawned looper thread with the device.
+ */
+
+ BC_ENTER_LOOPER = _IO('c', 12),
+ BC_EXIT_LOOPER = _IO('c', 13),
+ /*
+ * No parameters.
+ * These two commands are sent as an application-level thread
+ * enters and exits the binder loop, respectively. They are
+ * used so the binder can have an accurate count of the number
+ * of looping threads it has available.
+ */
+
+ BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_ptr_cookie),
+ /*
+ * void *: ptr to binder
+ * void *: cookie
+ */
+
+ BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_ptr_cookie),
+ /*
+ * void *: ptr to binder
+ * void *: cookie
+ */
+
+ BC_DEAD_BINDER_DONE = _IOW('c', 16, userptr32_t),
+ /*
+ * void *: cookie
+ */
+};
#endif /* _LINUX_BINDER_H */