Skip to content

Commit 512cf46

Browse files
Todd Kjosgregkh
authored andcommitted
binder: fix use-after-free in binder_transaction()
User-space normally keeps the node alive when creating a transaction since it has a reference to the target. The local strong ref keeps it alive if the sending process dies before the target process processes the transaction. If the source process is malicious or has a reference counting bug, this can fail. In this case, when we attempt to decrement the node in the failure path, the node has already been freed. This is fixed by taking a tmpref on the node while constructing the transaction. To avoid re-acquiring the node lock and inner proc lock to increment the proc's tmpref, a helper is used that does the ref increments on both the node and proc. Signed-off-by: Todd Kjos <[email protected]> Cc: stable <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 192b2d7 commit 512cf46

File tree

1 file changed

+66
-27
lines changed

1 file changed

+66
-27
lines changed

drivers/android/binder.c

Lines changed: 66 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2582,6 +2582,48 @@ static bool binder_proc_transaction(struct binder_transaction *t,
25822582
return true;
25832583
}
25842584

2585+
/**
2586+
* binder_get_node_refs_for_txn() - Get required refs on node for txn
2587+
* @node: struct binder_node for which to get refs
2588+
* @proc: returns @node->proc if valid
2589+
* @error: if no @proc then returns BR_DEAD_REPLY
2590+
*
2591+
* User-space normally keeps the node alive when creating a transaction
2592+
* since it has a reference to the target. The local strong ref keeps it
2593+
* alive if the sending process dies before the target process processes
2594+
* the transaction. If the source process is malicious or has a reference
2595+
* counting bug, relying on the local strong ref can fail.
2596+
*
2597+
* Since user-space can cause the local strong ref to go away, we also take
2598+
* a tmpref on the node to ensure it survives while we are constructing
2599+
* the transaction. We also need a tmpref on the proc while we are
2600+
* constructing the transaction, so we take that here as well.
2601+
*
2602+
* Return: The target_node with refs taken or NULL if no @node->proc is NULL.
2603+
* Also sets @proc if valid. If the @node->proc is NULL indicating that the
2604+
* target proc has died, @error is set to BR_DEAD_REPLY
2605+
*/
2606+
static struct binder_node *binder_get_node_refs_for_txn(
2607+
struct binder_node *node,
2608+
struct binder_proc **procp,
2609+
uint32_t *error)
2610+
{
2611+
struct binder_node *target_node = NULL;
2612+
2613+
binder_node_inner_lock(node);
2614+
if (node->proc) {
2615+
target_node = node;
2616+
binder_inc_node_nilocked(node, 1, 0, NULL);
2617+
binder_inc_node_tmpref_ilocked(node);
2618+
node->proc->tmp_ref++;
2619+
*procp = node->proc;
2620+
} else
2621+
*error = BR_DEAD_REPLY;
2622+
binder_node_inner_unlock(node);
2623+
2624+
return target_node;
2625+
}
2626+
25852627
static void binder_transaction(struct binder_proc *proc,
25862628
struct binder_thread *thread,
25872629
struct binder_transaction_data *tr, int reply,
@@ -2685,43 +2727,35 @@ static void binder_transaction(struct binder_proc *proc,
26852727
ref = binder_get_ref_olocked(proc, tr->target.handle,
26862728
true);
26872729
if (ref) {
2688-
binder_inc_node(ref->node, 1, 0, NULL);
2689-
target_node = ref->node;
2690-
}
2691-
binder_proc_unlock(proc);
2692-
if (target_node == NULL) {
2730+
target_node = binder_get_node_refs_for_txn(
2731+
ref->node, &target_proc,
2732+
&return_error);
2733+
} else {
26932734
binder_user_error("%d:%d got transaction to invalid handle\n",
2694-
proc->pid, thread->pid);
2735+
proc->pid, thread->pid);
26952736
return_error = BR_FAILED_REPLY;
2696-
return_error_param = -EINVAL;
2697-
return_error_line = __LINE__;
2698-
goto err_invalid_target_handle;
26992737
}
2738+
binder_proc_unlock(proc);
27002739
} else {
27012740
mutex_lock(&context->context_mgr_node_lock);
27022741
target_node = context->binder_context_mgr_node;
2703-
if (target_node == NULL) {
2742+
if (target_node)
2743+
target_node = binder_get_node_refs_for_txn(
2744+
target_node, &target_proc,
2745+
&return_error);
2746+
else
27042747
return_error = BR_DEAD_REPLY;
2705-
mutex_unlock(&context->context_mgr_node_lock);
2706-
return_error_line = __LINE__;
2707-
goto err_no_context_mgr_node;
2708-
}
2709-
binder_inc_node(target_node, 1, 0, NULL);
27102748
mutex_unlock(&context->context_mgr_node_lock);
27112749
}
2712-
e->to_node = target_node->debug_id;
2713-
binder_node_lock(target_node);
2714-
target_proc = target_node->proc;
2715-
if (target_proc == NULL) {
2716-
binder_node_unlock(target_node);
2717-
return_error = BR_DEAD_REPLY;
2750+
if (!target_node) {
2751+
/*
2752+
* return_error is set above
2753+
*/
2754+
return_error_param = -EINVAL;
27182755
return_error_line = __LINE__;
27192756
goto err_dead_binder;
27202757
}
2721-
binder_inner_proc_lock(target_proc);
2722-
target_proc->tmp_ref++;
2723-
binder_inner_proc_unlock(target_proc);
2724-
binder_node_unlock(target_node);
2758+
e->to_node = target_node->debug_id;
27252759
if (security_binder_transaction(proc->tsk,
27262760
target_proc->tsk) < 0) {
27272761
return_error = BR_FAILED_REPLY;
@@ -3071,6 +3105,8 @@ static void binder_transaction(struct binder_proc *proc,
30713105
if (target_thread)
30723106
binder_thread_dec_tmpref(target_thread);
30733107
binder_proc_dec_tmpref(target_proc);
3108+
if (target_node)
3109+
binder_dec_node_tmpref(target_node);
30743110
/*
30753111
* write barrier to synchronize with initialization
30763112
* of log entry
@@ -3090,6 +3126,8 @@ static void binder_transaction(struct binder_proc *proc,
30903126
err_copy_data_failed:
30913127
trace_binder_transaction_failed_buffer_release(t->buffer);
30923128
binder_transaction_buffer_release(target_proc, t->buffer, offp);
3129+
if (target_node)
3130+
binder_dec_node_tmpref(target_node);
30933131
target_node = NULL;
30943132
t->buffer->transaction = NULL;
30953133
binder_alloc_free_buf(&target_proc->alloc, t->buffer);
@@ -3104,13 +3142,14 @@ static void binder_transaction(struct binder_proc *proc,
31043142
err_empty_call_stack:
31053143
err_dead_binder:
31063144
err_invalid_target_handle:
3107-
err_no_context_mgr_node:
31083145
if (target_thread)
31093146
binder_thread_dec_tmpref(target_thread);
31103147
if (target_proc)
31113148
binder_proc_dec_tmpref(target_proc);
3112-
if (target_node)
3149+
if (target_node) {
31133150
binder_dec_node(target_node, 1, 0);
3151+
binder_dec_node_tmpref(target_node);
3152+
}
31143153

31153154
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
31163155
"%d:%d transaction failed %d/%d, size %lld-%lld line %d\n",

0 commit comments

Comments
 (0)