aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartijn Coenen <maco@android.com>2017-08-31 10:04:29 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-09-01 09:22:50 +0200
commit3a6430ce462172caac7c73f4afd550ab0f105737 (patch)
treead1d092efa48605dec38922b1747c2947a74e2e0
parentbb74562a7f8398231be20a5c9d36225301a9be31 (diff)
ANDROID: binder: don't queue async transactions to thread.
This can cause issues with processes using the poll() interface: 1) client sends two oneway transactions 2) the second one gets queued on async_todo (because the server didn't handle the first one yet) 3) server returns from poll(), picks up the first transaction and does transaction work 4) server is done with the transaction, sends BC_FREE_BUFFER, and the second transaction gets moved to thread->todo 5) libbinder's handlePolledCommands() only handles the commands in the current data buffer, so doesn't see the new transaction 6) the server continues running and issues a new outgoing transaction. Now, it suddenly finds the incoming oneway transaction on its thread todo, and returns that to userspace. 7) userspace does not expect this to happen; it may be holding a lock while making the outgoing transaction, and if handling the incoming trasnaction requires taking the same lock, userspace will deadlock. By queueing the async transaction to the proc workqueue, we make sure it's only picked up when a thread is ready for proc work. Signed-off-by: Martijn Coenen <maco@android.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/android/binder.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index b0f039500d80..d055b3f2a207 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -3351,11 +3351,13 @@ static int binder_thread_write(struct binder_proc *proc,
BUG_ON(buf_node->proc != proc);
w = binder_dequeue_work_head_ilocked(
&buf_node->async_todo);
- if (!w)
+ if (!w) {
buf_node->has_async_transaction = 0;
- else
+ } else {
binder_enqueue_work_ilocked(
- w, &thread->todo);
+ w, &proc->todo);
+ binder_wakeup_proc_ilocked(proc);
+ }
binder_node_inner_unlock(buf_node);
}
trace_binder_transaction_buffer_release(buffer);