mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 20:51:03 +02:00
binder: Refactor binder_transact()
Moved handling of fixup for binder objects, handles and file descriptors into separate functions. Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Martijn Coenen <maco@google.com> Cc: Arve Hjønnevåg <arve@android.com> Cc: Amit Pundir <amit.pundir@linaro.org> Cc: Serban Constantinescu <serban.constantinescu@arm.com> Cc: Dmitry Shmidt <dimitrysh@google.com> Cc: Rom Lemarchand <romlem@google.com> Cc: Android Kernel Team <kernel-team@android.com> Signed-off-by: Martijn Coenen <maco@google.com> Signed-off-by: John Stultz <john.stultz@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
ac4812c5ff
commit
a056af4203
@@ -1390,10 +1390,172 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int binder_translate_binder(struct flat_binder_object *fp,
|
||||||
|
struct binder_transaction *t,
|
||||||
|
struct binder_thread *thread)
|
||||||
|
{
|
||||||
|
struct binder_node *node;
|
||||||
|
struct binder_ref *ref;
|
||||||
|
struct binder_proc *proc = thread->proc;
|
||||||
|
struct binder_proc *target_proc = t->to_proc;
|
||||||
|
|
||||||
|
node = binder_get_node(proc, fp->binder);
|
||||||
|
if (!node) {
|
||||||
|
node = binder_new_node(proc, fp->binder, fp->cookie);
|
||||||
|
if (!node)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
|
||||||
|
node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
|
||||||
|
}
|
||||||
|
if (fp->cookie != node->cookie) {
|
||||||
|
binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n",
|
||||||
|
proc->pid, thread->pid, (u64)fp->binder,
|
||||||
|
node->debug_id, (u64)fp->cookie,
|
||||||
|
(u64)node->cookie);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (security_binder_transfer_binder(proc->tsk, target_proc->tsk))
|
||||||
|
return -EPERM;
|
||||||
|
|
||||||
|
ref = binder_get_ref_for_node(target_proc, node);
|
||||||
|
if (!ref)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (fp->hdr.type == BINDER_TYPE_BINDER)
|
||||||
|
fp->hdr.type = BINDER_TYPE_HANDLE;
|
||||||
|
else
|
||||||
|
fp->hdr.type = BINDER_TYPE_WEAK_HANDLE;
|
||||||
|
fp->binder = 0;
|
||||||
|
fp->handle = ref->desc;
|
||||||
|
fp->cookie = 0;
|
||||||
|
binder_inc_ref(ref, fp->hdr.type == BINDER_TYPE_HANDLE, &thread->todo);
|
||||||
|
|
||||||
|
trace_binder_transaction_node_to_ref(t, node, ref);
|
||||||
|
binder_debug(BINDER_DEBUG_TRANSACTION,
|
||||||
|
" node %d u%016llx -> ref %d desc %d\n",
|
||||||
|
node->debug_id, (u64)node->ptr,
|
||||||
|
ref->debug_id, ref->desc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int binder_translate_handle(struct flat_binder_object *fp,
|
||||||
|
struct binder_transaction *t,
|
||||||
|
struct binder_thread *thread)
|
||||||
|
{
|
||||||
|
struct binder_ref *ref;
|
||||||
|
struct binder_proc *proc = thread->proc;
|
||||||
|
struct binder_proc *target_proc = t->to_proc;
|
||||||
|
|
||||||
|
ref = binder_get_ref(proc, fp->handle,
|
||||||
|
fp->hdr.type == BINDER_TYPE_HANDLE);
|
||||||
|
if (!ref) {
|
||||||
|
binder_user_error("%d:%d got transaction with invalid handle, %d\n",
|
||||||
|
proc->pid, thread->pid, fp->handle);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (security_binder_transfer_binder(proc->tsk, target_proc->tsk))
|
||||||
|
return -EPERM;
|
||||||
|
|
||||||
|
if (ref->node->proc == target_proc) {
|
||||||
|
if (fp->hdr.type == BINDER_TYPE_HANDLE)
|
||||||
|
fp->hdr.type = BINDER_TYPE_BINDER;
|
||||||
|
else
|
||||||
|
fp->hdr.type = BINDER_TYPE_WEAK_BINDER;
|
||||||
|
fp->binder = ref->node->ptr;
|
||||||
|
fp->cookie = ref->node->cookie;
|
||||||
|
binder_inc_node(ref->node, fp->hdr.type == BINDER_TYPE_BINDER,
|
||||||
|
0, NULL);
|
||||||
|
trace_binder_transaction_ref_to_node(t, ref);
|
||||||
|
binder_debug(BINDER_DEBUG_TRANSACTION,
|
||||||
|
" ref %d desc %d -> node %d u%016llx\n",
|
||||||
|
ref->debug_id, ref->desc, ref->node->debug_id,
|
||||||
|
(u64)ref->node->ptr);
|
||||||
|
} else {
|
||||||
|
struct binder_ref *new_ref;
|
||||||
|
|
||||||
|
new_ref = binder_get_ref_for_node(target_proc, ref->node);
|
||||||
|
if (!new_ref)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
fp->binder = 0;
|
||||||
|
fp->handle = new_ref->desc;
|
||||||
|
fp->cookie = 0;
|
||||||
|
binder_inc_ref(new_ref, fp->hdr.type == BINDER_TYPE_HANDLE,
|
||||||
|
NULL);
|
||||||
|
trace_binder_transaction_ref_to_ref(t, ref, new_ref);
|
||||||
|
binder_debug(BINDER_DEBUG_TRANSACTION,
|
||||||
|
" ref %d desc %d -> ref %d desc %d (node %d)\n",
|
||||||
|
ref->debug_id, ref->desc, new_ref->debug_id,
|
||||||
|
new_ref->desc, ref->node->debug_id);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int binder_translate_fd(int fd,
|
||||||
|
struct binder_transaction *t,
|
||||||
|
struct binder_thread *thread,
|
||||||
|
struct binder_transaction *in_reply_to)
|
||||||
|
{
|
||||||
|
struct binder_proc *proc = thread->proc;
|
||||||
|
struct binder_proc *target_proc = t->to_proc;
|
||||||
|
int target_fd;
|
||||||
|
struct file *file;
|
||||||
|
int ret;
|
||||||
|
bool target_allows_fd;
|
||||||
|
|
||||||
|
if (in_reply_to)
|
||||||
|
target_allows_fd = !!(in_reply_to->flags & TF_ACCEPT_FDS);
|
||||||
|
else
|
||||||
|
target_allows_fd = t->buffer->target_node->accept_fds;
|
||||||
|
if (!target_allows_fd) {
|
||||||
|
binder_user_error("%d:%d got %s with fd, %d, but target does not allow fds\n",
|
||||||
|
proc->pid, thread->pid,
|
||||||
|
in_reply_to ? "reply" : "transaction",
|
||||||
|
fd);
|
||||||
|
ret = -EPERM;
|
||||||
|
goto err_fd_not_accepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
file = fget(fd);
|
||||||
|
if (!file) {
|
||||||
|
binder_user_error("%d:%d got transaction with invalid fd, %d\n",
|
||||||
|
proc->pid, thread->pid, fd);
|
||||||
|
ret = -EBADF;
|
||||||
|
goto err_fget;
|
||||||
|
}
|
||||||
|
ret = security_binder_transfer_file(proc->tsk, target_proc->tsk, file);
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = -EPERM;
|
||||||
|
goto err_security;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
|
||||||
|
if (target_fd < 0) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto err_get_unused_fd;
|
||||||
|
}
|
||||||
|
task_fd_install(target_proc, target_fd, file);
|
||||||
|
trace_binder_transaction_fd(t, fd, target_fd);
|
||||||
|
binder_debug(BINDER_DEBUG_TRANSACTION, " fd %d -> %d\n",
|
||||||
|
fd, target_fd);
|
||||||
|
|
||||||
|
return target_fd;
|
||||||
|
|
||||||
|
err_get_unused_fd:
|
||||||
|
err_security:
|
||||||
|
fput(file);
|
||||||
|
err_fget:
|
||||||
|
err_fd_not_accepted:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void binder_transaction(struct binder_proc *proc,
|
static void binder_transaction(struct binder_proc *proc,
|
||||||
struct binder_thread *thread,
|
struct binder_thread *thread,
|
||||||
struct binder_transaction_data *tr, int reply)
|
struct binder_transaction_data *tr, int reply)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
struct binder_transaction *t;
|
struct binder_transaction *t;
|
||||||
struct binder_work *tcomplete;
|
struct binder_work *tcomplete;
|
||||||
binder_size_t *offp, *off_end;
|
binder_size_t *offp, *off_end;
|
||||||
@@ -1621,157 +1783,35 @@ static void binder_transaction(struct binder_proc *proc,
|
|||||||
case BINDER_TYPE_BINDER:
|
case BINDER_TYPE_BINDER:
|
||||||
case BINDER_TYPE_WEAK_BINDER: {
|
case BINDER_TYPE_WEAK_BINDER: {
|
||||||
struct flat_binder_object *fp;
|
struct flat_binder_object *fp;
|
||||||
struct binder_node *node;
|
|
||||||
struct binder_ref *ref;
|
|
||||||
|
|
||||||
fp = to_flat_binder_object(hdr);
|
fp = to_flat_binder_object(hdr);
|
||||||
node = binder_get_node(proc, fp->binder);
|
ret = binder_translate_binder(fp, t, thread);
|
||||||
if (node == NULL) {
|
if (ret < 0) {
|
||||||
node = binder_new_node(proc, fp->binder, fp->cookie);
|
|
||||||
if (node == NULL) {
|
|
||||||
return_error = BR_FAILED_REPLY;
|
|
||||||
goto err_binder_new_node_failed;
|
|
||||||
}
|
|
||||||
node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
|
|
||||||
node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
|
|
||||||
}
|
|
||||||
if (fp->cookie != node->cookie) {
|
|
||||||
binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n",
|
|
||||||
proc->pid, thread->pid,
|
|
||||||
(u64)fp->binder, node->debug_id,
|
|
||||||
(u64)fp->cookie, (u64)node->cookie);
|
|
||||||
return_error = BR_FAILED_REPLY;
|
return_error = BR_FAILED_REPLY;
|
||||||
goto err_binder_get_ref_for_node_failed;
|
goto err_translate_failed;
|
||||||
}
|
}
|
||||||
if (security_binder_transfer_binder(proc->tsk,
|
|
||||||
target_proc->tsk)) {
|
|
||||||
return_error = BR_FAILED_REPLY;
|
|
||||||
goto err_binder_get_ref_for_node_failed;
|
|
||||||
}
|
|
||||||
ref = binder_get_ref_for_node(target_proc, node);
|
|
||||||
if (ref == NULL) {
|
|
||||||
return_error = BR_FAILED_REPLY;
|
|
||||||
goto err_binder_get_ref_for_node_failed;
|
|
||||||
}
|
|
||||||
if (hdr->type == BINDER_TYPE_BINDER)
|
|
||||||
hdr->type = BINDER_TYPE_HANDLE;
|
|
||||||
else
|
|
||||||
hdr->type = BINDER_TYPE_WEAK_HANDLE;
|
|
||||||
fp->binder = 0;
|
|
||||||
fp->handle = ref->desc;
|
|
||||||
fp->cookie = 0;
|
|
||||||
binder_inc_ref(ref, hdr->type == BINDER_TYPE_HANDLE,
|
|
||||||
&thread->todo);
|
|
||||||
|
|
||||||
trace_binder_transaction_node_to_ref(t, node, ref);
|
|
||||||
binder_debug(BINDER_DEBUG_TRANSACTION,
|
|
||||||
" node %d u%016llx -> ref %d desc %d\n",
|
|
||||||
node->debug_id, (u64)node->ptr,
|
|
||||||
ref->debug_id, ref->desc);
|
|
||||||
} break;
|
} break;
|
||||||
case BINDER_TYPE_HANDLE:
|
case BINDER_TYPE_HANDLE:
|
||||||
case BINDER_TYPE_WEAK_HANDLE: {
|
case BINDER_TYPE_WEAK_HANDLE: {
|
||||||
struct flat_binder_object *fp;
|
struct flat_binder_object *fp;
|
||||||
struct binder_ref *ref;
|
|
||||||
|
|
||||||
fp = to_flat_binder_object(hdr);
|
fp = to_flat_binder_object(hdr);
|
||||||
ref = binder_get_ref(proc, fp->handle,
|
ret = binder_translate_handle(fp, t, thread);
|
||||||
hdr->type == BINDER_TYPE_HANDLE);
|
if (ret < 0) {
|
||||||
if (ref == NULL) {
|
|
||||||
binder_user_error("%d:%d got transaction with invalid handle, %d\n",
|
|
||||||
proc->pid,
|
|
||||||
thread->pid, fp->handle);
|
|
||||||
return_error = BR_FAILED_REPLY;
|
return_error = BR_FAILED_REPLY;
|
||||||
goto err_binder_get_ref_failed;
|
goto err_translate_failed;
|
||||||
}
|
|
||||||
if (security_binder_transfer_binder(proc->tsk,
|
|
||||||
target_proc->tsk)) {
|
|
||||||
return_error = BR_FAILED_REPLY;
|
|
||||||
goto err_binder_get_ref_failed;
|
|
||||||
}
|
|
||||||
if (ref->node->proc == target_proc) {
|
|
||||||
if (hdr->type == BINDER_TYPE_HANDLE)
|
|
||||||
hdr->type = BINDER_TYPE_BINDER;
|
|
||||||
else
|
|
||||||
hdr->type = BINDER_TYPE_WEAK_BINDER;
|
|
||||||
fp->binder = ref->node->ptr;
|
|
||||||
fp->cookie = ref->node->cookie;
|
|
||||||
binder_inc_node(ref->node,
|
|
||||||
hdr->type == BINDER_TYPE_BINDER,
|
|
||||||
0, NULL);
|
|
||||||
trace_binder_transaction_ref_to_node(t, ref);
|
|
||||||
binder_debug(BINDER_DEBUG_TRANSACTION,
|
|
||||||
" ref %d desc %d -> node %d u%016llx\n",
|
|
||||||
ref->debug_id, ref->desc, ref->node->debug_id,
|
|
||||||
(u64)ref->node->ptr);
|
|
||||||
} else {
|
|
||||||
struct binder_ref *new_ref;
|
|
||||||
|
|
||||||
new_ref = binder_get_ref_for_node(target_proc, ref->node);
|
|
||||||
if (new_ref == NULL) {
|
|
||||||
return_error = BR_FAILED_REPLY;
|
|
||||||
goto err_binder_get_ref_for_node_failed;
|
|
||||||
}
|
|
||||||
fp->binder = 0;
|
|
||||||
fp->handle = new_ref->desc;
|
|
||||||
fp->cookie = 0;
|
|
||||||
binder_inc_ref(new_ref,
|
|
||||||
hdr->type == BINDER_TYPE_HANDLE,
|
|
||||||
NULL);
|
|
||||||
trace_binder_transaction_ref_to_ref(t, ref,
|
|
||||||
new_ref);
|
|
||||||
binder_debug(BINDER_DEBUG_TRANSACTION,
|
|
||||||
" ref %d desc %d -> ref %d desc %d (node %d)\n",
|
|
||||||
ref->debug_id, ref->desc, new_ref->debug_id,
|
|
||||||
new_ref->desc, ref->node->debug_id);
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case BINDER_TYPE_FD: {
|
case BINDER_TYPE_FD: {
|
||||||
int target_fd;
|
|
||||||
struct file *file;
|
|
||||||
struct binder_fd_object *fp = to_binder_fd_object(hdr);
|
struct binder_fd_object *fp = to_binder_fd_object(hdr);
|
||||||
|
int target_fd = binder_translate_fd(fp->fd, t, thread,
|
||||||
|
in_reply_to);
|
||||||
|
|
||||||
if (reply) {
|
|
||||||
if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {
|
|
||||||
binder_user_error("%d:%d got reply with fd, %d, but target does not allow fds\n",
|
|
||||||
proc->pid, thread->pid, fp->fd);
|
|
||||||
return_error = BR_FAILED_REPLY;
|
|
||||||
goto err_fd_not_allowed;
|
|
||||||
}
|
|
||||||
} else if (!target_node->accept_fds) {
|
|
||||||
binder_user_error("%d:%d got transaction with fd, %d, but target does not allow fds\n",
|
|
||||||
proc->pid, thread->pid, fp->fd);
|
|
||||||
return_error = BR_FAILED_REPLY;
|
|
||||||
goto err_fd_not_allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
file = fget(fp->fd);
|
|
||||||
if (file == NULL) {
|
|
||||||
binder_user_error("%d:%d got transaction with invalid fd, %d\n",
|
|
||||||
proc->pid, thread->pid, fp->fd);
|
|
||||||
return_error = BR_FAILED_REPLY;
|
|
||||||
goto err_fget_failed;
|
|
||||||
}
|
|
||||||
if (security_binder_transfer_file(proc->tsk,
|
|
||||||
target_proc->tsk,
|
|
||||||
file) < 0) {
|
|
||||||
fput(file);
|
|
||||||
return_error = BR_FAILED_REPLY;
|
|
||||||
goto err_get_unused_fd_failed;
|
|
||||||
}
|
|
||||||
target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
|
|
||||||
if (target_fd < 0) {
|
if (target_fd < 0) {
|
||||||
fput(file);
|
|
||||||
return_error = BR_FAILED_REPLY;
|
return_error = BR_FAILED_REPLY;
|
||||||
goto err_get_unused_fd_failed;
|
goto err_translate_failed;
|
||||||
}
|
}
|
||||||
task_fd_install(target_proc, target_fd, file);
|
|
||||||
trace_binder_transaction_fd(t, fp->fd, target_fd);
|
|
||||||
binder_debug(BINDER_DEBUG_TRANSACTION,
|
|
||||||
" fd %d -> %d\n", fp->fd,
|
|
||||||
target_fd);
|
|
||||||
/* TODO: fput? */
|
|
||||||
fp->pad_binder = 0;
|
fp->pad_binder = 0;
|
||||||
fp->fd = target_fd;
|
fp->fd = target_fd;
|
||||||
} break;
|
} break;
|
||||||
@@ -1808,12 +1848,7 @@ static void binder_transaction(struct binder_proc *proc,
|
|||||||
wake_up_interruptible(target_wait);
|
wake_up_interruptible(target_wait);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
err_get_unused_fd_failed:
|
err_translate_failed:
|
||||||
err_fget_failed:
|
|
||||||
err_fd_not_allowed:
|
|
||||||
err_binder_get_ref_for_node_failed:
|
|
||||||
err_binder_get_ref_failed:
|
|
||||||
err_binder_new_node_failed:
|
|
||||||
err_bad_object_type:
|
err_bad_object_type:
|
||||||
err_bad_offset:
|
err_bad_offset:
|
||||||
err_copy_data_failed:
|
err_copy_data_failed:
|
||||||
|
Reference in New Issue
Block a user