Add helper functions for manipulating the transaction stack, and for validating the transaction stack during binder transactions and replies. Signed-off-by: Riley Andrews <riandrews@xxxxxxxxxxx> --- drivers/android/binder.c | 126 +++++++++++++++++++++++++++++------------------ 1 file changed, 79 insertions(+), 47 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 99a3270..ed94121 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1167,14 +1167,20 @@ static int binder_dec_ref(struct binder_ref *ref, int strong) return 0; } +static void binder_push_transaction(struct binder_thread *thread, + struct binder_transaction *t) +{ + t->from_parent = thread->transaction_stack; + thread->transaction_stack = t; +} + static void binder_pop_transaction(struct binder_thread *target_thread, struct binder_transaction *t) { if (target_thread) { BUG_ON(target_thread->transaction_stack != t); BUG_ON(target_thread->transaction_stack->from != target_thread); - target_thread->transaction_stack = - target_thread->transaction_stack->from_parent; + target_thread->transaction_stack = t->from_parent; t->from = NULL; } t->need_reply = 0; @@ -1184,6 +1190,24 @@ static void binder_pop_transaction(struct binder_thread *target_thread, binder_stats_deleted(BINDER_STAT_TRANSACTION); } +static void binder_dst_save_transaction(struct binder_thread *thread, + struct binder_transaction *t) +{ + t->to_parent = thread->transaction_stack; + thread->transaction_stack = t; +} + +static struct binder_transaction * +binder_dst_restore_transaction(struct binder_thread *thread) +{ + struct binder_transaction *t = thread->transaction_stack; + + if (!t) + return NULL; + thread->transaction_stack = t->to_parent; + return t; +} + static void binder_send_failed_reply(struct binder_transaction *t, uint32_t error_code) { @@ -1559,6 +1583,47 @@ static int binder_get_tr_target_node(struct binder_thread *thread, return BR_OK; } +static int binder_reply_validate_stack(struct binder_thread *thread) +{ + struct binder_proc *proc = thread->proc; + struct binder_transaction *in_reply_to = NULL; + + in_reply_to = thread->transaction_stack; + if (!in_reply_to) { + binder_user_error("%d:%d got reply transaction with no transaction stack\n", + proc->pid, thread->pid); + return BR_FAILED_REPLY; + } + if (in_reply_to->to_thread != thread) { + binder_user_error("%d:%d got reply transaction with bad transaction stack, transaction %d has target %d:%d\n", + proc->pid, thread->pid, in_reply_to->debug_id, + in_reply_to->to_proc ? + in_reply_to->to_proc->pid : 0, + in_reply_to->to_thread ? + in_reply_to->to_thread->pid : 0); + return BR_FAILED_REPLY; + } + return BR_OK; +} + +static int binder_tr_validate_stack(struct binder_thread *thread) +{ + struct binder_transaction *prior = thread->transaction_stack; + struct binder_proc *proc = thread->proc; + + if (prior->to_thread != thread) { + binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%d\n", + proc->pid, thread->pid, + prior->debug_id, + prior->to_proc ? + prior->to_proc->pid : 0, + prior->to_thread ? + prior->to_thread->pid : 0); + return BR_FAILED_REPLY; + } + return BR_OK; +} + static void binder_transaction(struct binder_thread *thread, struct binder_transaction_data *tr, int reply) { @@ -1584,42 +1649,17 @@ static void binder_transaction(struct binder_thread *thread, e->offsets_size = tr->offsets_size; if (reply) { - in_reply_to = thread->transaction_stack; - if (in_reply_to == NULL) { - binder_user_error("%d:%d got reply transaction with no transaction stack\n", - proc->pid, thread->pid); - return_error = BR_FAILED_REPLY; - goto err_empty_call_stack; - } - binder_set_nice(in_reply_to->saved_priority); - if (in_reply_to->to_thread != thread) { - binder_user_error("%d:%d got reply transaction with bad transaction stack, transaction %d has target %d:%d\n", - proc->pid, thread->pid, in_reply_to->debug_id, - in_reply_to->to_proc ? - in_reply_to->to_proc->pid : 0, - in_reply_to->to_thread ? - in_reply_to->to_thread->pid : 0); - return_error = BR_FAILED_REPLY; - in_reply_to = NULL; + return_error = binder_reply_validate_stack(thread); + if (return_error != BR_OK) goto err_bad_call_stack; - } - thread->transaction_stack = in_reply_to->to_parent; + in_reply_to = binder_dst_restore_transaction(thread); + binder_set_nice(in_reply_to->saved_priority); target_thread = in_reply_to->from; - if (target_thread == NULL) { + if (!target_thread) { return_error = BR_DEAD_REPLY; goto err_dead_binder; } - if (target_thread->transaction_stack != in_reply_to) { - binder_user_error("%d:%d got reply transaction with bad target transaction stack %d, expected %d\n", - proc->pid, thread->pid, - target_thread->transaction_stack ? - target_thread->transaction_stack->debug_id : 0, - in_reply_to->debug_id); - return_error = BR_FAILED_REPLY; - in_reply_to = NULL; - target_thread = NULL; - goto err_dead_binder; - } + BUG_ON(target_thread->transaction_stack != in_reply_to); target_proc = target_thread->proc; } else { return_error = binder_get_tr_target_node(thread, tr, @@ -1640,16 +1680,11 @@ static void binder_transaction(struct binder_thread *thread, if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { struct binder_transaction *tmp; - tmp = thread->transaction_stack; - if (tmp->to_thread != thread) { - binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%d\n", - proc->pid, thread->pid, tmp->debug_id, - tmp->to_proc ? tmp->to_proc->pid : 0, - tmp->to_thread ? - tmp->to_thread->pid : 0); - return_error = BR_FAILED_REPLY; + return_error = binder_tr_validate_stack(thread); + if (return_error != BR_OK) goto err_bad_call_stack; - } + + tmp = thread->transaction_stack; while (tmp) { if (tmp->from && tmp->from->proc == target_proc) target_thread = tmp->from; @@ -1755,8 +1790,7 @@ static void binder_transaction(struct binder_thread *thread, } else if (!(t->flags & TF_ONE_WAY)) { BUG_ON(t->buffer->async_transaction != 0); t->need_reply = 1; - t->from_parent = thread->transaction_stack; - thread->transaction_stack = t; + binder_push_transaction(thread, t); } else { BUG_ON(target_node == NULL); BUG_ON(t->buffer->async_transaction != 1); @@ -1786,7 +1820,6 @@ err_alloc_tcomplete_failed: binder_stats_deleted(BINDER_STAT_TRANSACTION); err_alloc_t_failed: err_bad_call_stack: -err_empty_call_stack: err_dead_binder: err_invalid_target_handle: binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, @@ -2579,9 +2612,8 @@ retry: list_del(&t->work.entry); t->buffer->allow_user_free = 1; if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) { - t->to_parent = thread->transaction_stack; t->to_thread = thread; - thread->transaction_stack = t; + binder_dst_save_transaction(thread, t); } else { t->buffer->transaction = NULL; kfree(t); -- 2.2.0.rc0.207.ga3a616c _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel