Re: [PATCH] android: binder: no outgoing transaction when thread todo has transaction

2018-08-14 Thread Martijn Coenen
Sherry, this was found by syzkaller, right? In that case, can you add
the  tag so the issue gets closed automatically when this
gets merged?


On Tue, Aug 14, 2018 at 2:28 AM, Sherry Yang  wrote:
> When a process dies, failed reply is sent to the sender of any transaction
> queued on a dead thread's todo list. The sender asserts that the
> received failed reply corresponds to the head of the transaction stack.
> This assert can fail if the dead thread is allowed to send outgoing
> transactions when there is already a transaction on its todo list,
> because this new transaction can end up on the transaction stack of the
> original sender. The following steps illustrate how this assertion can
> fail.
>
> 1. Thread1 sends txn19 to Thread2
>(T1->transaction_stack=txn19, T2->todo+=txn19)
> 2. Without processing todo list, Thread2 sends txn20 to Thread1
>(T1->todo+=txn20, T2->transaction_stack=txn20)
> 3. T1 processes txn20 on its todo list
>(T1->transaction_stack=txn20->txn19, T1->todo=)
> 4. T2 dies, T2->todo cleanup attempts to send failed reply for txn19, but
>T1->transaction_stack points to txn20 -- assertion failes
>
> Step 2. is the incorrect behavior. When there is a transaction on a
> thread's todo list, this thread should not be able to send any outgoing
> synchronous transactions. Only the head of the todo list needs to be
> checked because only threads that are waiting for proc work can directly
> receive work from another thread, and no work is allowed to be queued
> on such a thread without waking up the thread. This patch also enforces
> that a thread is not waiting for proc work when a work is directly
> enqueued to its todo list.
>
> Acked-by: Arve Hjønnevåg 
> Signed-off-by: Sherry Yang 

Reviewed-by: Martijn Coenen 

Thanks,
Martijn

> ---
>  drivers/android/binder.c | 44 +---
>  1 file changed, 32 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/android/binder.c b/drivers/android/binder.c
> index d58763b6b009..f2081934eb8b 100644
> --- a/drivers/android/binder.c
> +++ b/drivers/android/binder.c
> @@ -822,6 +822,7 @@ static void
>  binder_enqueue_deferred_thread_work_ilocked(struct binder_thread *thread,
> struct binder_work *work)
>  {
> +   WARN_ON(!list_empty(>waiting_thread_node));
> binder_enqueue_work_ilocked(work, >todo);
>  }
>
> @@ -839,6 +840,7 @@ static void
>  binder_enqueue_thread_work_ilocked(struct binder_thread *thread,
>struct binder_work *work)
>  {
> +   WARN_ON(!list_empty(>waiting_thread_node));
> binder_enqueue_work_ilocked(work, >todo);
> thread->process_todo = true;
>  }
> @@ -1270,19 +1272,12 @@ static int binder_inc_node_nilocked(struct 
> binder_node *node, int strong,
> } else
> node->local_strong_refs++;
> if (!node->has_strong_ref && target_list) {
> +   struct binder_thread *thread = 
> container_of(target_list,
> +   struct binder_thread, 
> todo);
> binder_dequeue_work_ilocked(>work);
> -   /*
> -* Note: this function is the only place where we 
> queue
> -* directly to a thread->todo without using the
> -* corresponding binder_enqueue_thread_work() helper
> -* functions; in this case it's ok to not set the
> -* process_todo flag, since we know this node work 
> will
> -* always be followed by other work that starts queue
> -* processing: in case of synchronous transactions, a
> -* BR_REPLY or BR_ERROR; in case of oneway
> -* transactions, a BR_TRANSACTION_COMPLETE.
> -*/
> -   binder_enqueue_work_ilocked(>work, target_list);
> +   BUG_ON(>todo != target_list);
> +   binder_enqueue_deferred_thread_work_ilocked(thread,
> +  
> >work);
> }
> } else {
> if (!internal)
> @@ -2723,6 +2718,7 @@ static void binder_transaction(struct binder_proc *proc,
>  {
> int ret;
> struct binder_transaction *t;
> +   struct binder_work *w;
> struct binder_work *tcomplete;
> binder_size_t *offp, *off_end, *off_start;
> binder_size_t off_min;
> @@ -2864,6 +2860,29 @@ static void binder_transaction(struct binder_proc 
> *proc,
> goto err_invalid_target_handle;
> }
> binder_inner_proc_lock(proc);
> +
> +   w = list_first_entry_or_null(>todo,
> +struct binder_work, entry);
> +   if 

Re: [PATCH] android: binder: no outgoing transaction when thread todo has transaction

2018-08-14 Thread Martijn Coenen
Sherry, this was found by syzkaller, right? In that case, can you add
the  tag so the issue gets closed automatically when this
gets merged?


On Tue, Aug 14, 2018 at 2:28 AM, Sherry Yang  wrote:
> When a process dies, failed reply is sent to the sender of any transaction
> queued on a dead thread's todo list. The sender asserts that the
> received failed reply corresponds to the head of the transaction stack.
> This assert can fail if the dead thread is allowed to send outgoing
> transactions when there is already a transaction on its todo list,
> because this new transaction can end up on the transaction stack of the
> original sender. The following steps illustrate how this assertion can
> fail.
>
> 1. Thread1 sends txn19 to Thread2
>(T1->transaction_stack=txn19, T2->todo+=txn19)
> 2. Without processing todo list, Thread2 sends txn20 to Thread1
>(T1->todo+=txn20, T2->transaction_stack=txn20)
> 3. T1 processes txn20 on its todo list
>(T1->transaction_stack=txn20->txn19, T1->todo=)
> 4. T2 dies, T2->todo cleanup attempts to send failed reply for txn19, but
>T1->transaction_stack points to txn20 -- assertion failes
>
> Step 2. is the incorrect behavior. When there is a transaction on a
> thread's todo list, this thread should not be able to send any outgoing
> synchronous transactions. Only the head of the todo list needs to be
> checked because only threads that are waiting for proc work can directly
> receive work from another thread, and no work is allowed to be queued
> on such a thread without waking up the thread. This patch also enforces
> that a thread is not waiting for proc work when a work is directly
> enqueued to its todo list.
>
> Acked-by: Arve Hjønnevåg 
> Signed-off-by: Sherry Yang 

Reviewed-by: Martijn Coenen 

Thanks,
Martijn

> ---
>  drivers/android/binder.c | 44 +---
>  1 file changed, 32 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/android/binder.c b/drivers/android/binder.c
> index d58763b6b009..f2081934eb8b 100644
> --- a/drivers/android/binder.c
> +++ b/drivers/android/binder.c
> @@ -822,6 +822,7 @@ static void
>  binder_enqueue_deferred_thread_work_ilocked(struct binder_thread *thread,
> struct binder_work *work)
>  {
> +   WARN_ON(!list_empty(>waiting_thread_node));
> binder_enqueue_work_ilocked(work, >todo);
>  }
>
> @@ -839,6 +840,7 @@ static void
>  binder_enqueue_thread_work_ilocked(struct binder_thread *thread,
>struct binder_work *work)
>  {
> +   WARN_ON(!list_empty(>waiting_thread_node));
> binder_enqueue_work_ilocked(work, >todo);
> thread->process_todo = true;
>  }
> @@ -1270,19 +1272,12 @@ static int binder_inc_node_nilocked(struct 
> binder_node *node, int strong,
> } else
> node->local_strong_refs++;
> if (!node->has_strong_ref && target_list) {
> +   struct binder_thread *thread = 
> container_of(target_list,
> +   struct binder_thread, 
> todo);
> binder_dequeue_work_ilocked(>work);
> -   /*
> -* Note: this function is the only place where we 
> queue
> -* directly to a thread->todo without using the
> -* corresponding binder_enqueue_thread_work() helper
> -* functions; in this case it's ok to not set the
> -* process_todo flag, since we know this node work 
> will
> -* always be followed by other work that starts queue
> -* processing: in case of synchronous transactions, a
> -* BR_REPLY or BR_ERROR; in case of oneway
> -* transactions, a BR_TRANSACTION_COMPLETE.
> -*/
> -   binder_enqueue_work_ilocked(>work, target_list);
> +   BUG_ON(>todo != target_list);
> +   binder_enqueue_deferred_thread_work_ilocked(thread,
> +  
> >work);
> }
> } else {
> if (!internal)
> @@ -2723,6 +2718,7 @@ static void binder_transaction(struct binder_proc *proc,
>  {
> int ret;
> struct binder_transaction *t;
> +   struct binder_work *w;
> struct binder_work *tcomplete;
> binder_size_t *offp, *off_end, *off_start;
> binder_size_t off_min;
> @@ -2864,6 +2860,29 @@ static void binder_transaction(struct binder_proc 
> *proc,
> goto err_invalid_target_handle;
> }
> binder_inner_proc_lock(proc);
> +
> +   w = list_first_entry_or_null(>todo,
> +struct binder_work, entry);
> +   if 

[PATCH] android: binder: no outgoing transaction when thread todo has transaction

2018-08-13 Thread Sherry Yang
When a process dies, failed reply is sent to the sender of any transaction
queued on a dead thread's todo list. The sender asserts that the
received failed reply corresponds to the head of the transaction stack.
This assert can fail if the dead thread is allowed to send outgoing
transactions when there is already a transaction on its todo list,
because this new transaction can end up on the transaction stack of the
original sender. The following steps illustrate how this assertion can
fail.

1. Thread1 sends txn19 to Thread2
   (T1->transaction_stack=txn19, T2->todo+=txn19)
2. Without processing todo list, Thread2 sends txn20 to Thread1
   (T1->todo+=txn20, T2->transaction_stack=txn20)
3. T1 processes txn20 on its todo list
   (T1->transaction_stack=txn20->txn19, T1->todo=)
4. T2 dies, T2->todo cleanup attempts to send failed reply for txn19, but
   T1->transaction_stack points to txn20 -- assertion failes

Step 2. is the incorrect behavior. When there is a transaction on a
thread's todo list, this thread should not be able to send any outgoing
synchronous transactions. Only the head of the todo list needs to be
checked because only threads that are waiting for proc work can directly
receive work from another thread, and no work is allowed to be queued
on such a thread without waking up the thread. This patch also enforces
that a thread is not waiting for proc work when a work is directly
enqueued to its todo list.

Acked-by: Arve Hjønnevåg 
Signed-off-by: Sherry Yang 
---
 drivers/android/binder.c | 44 +---
 1 file changed, 32 insertions(+), 12 deletions(-)

diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index d58763b6b009..f2081934eb8b 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -822,6 +822,7 @@ static void
 binder_enqueue_deferred_thread_work_ilocked(struct binder_thread *thread,
struct binder_work *work)
 {
+   WARN_ON(!list_empty(>waiting_thread_node));
binder_enqueue_work_ilocked(work, >todo);
 }
 
@@ -839,6 +840,7 @@ static void
 binder_enqueue_thread_work_ilocked(struct binder_thread *thread,
   struct binder_work *work)
 {
+   WARN_ON(!list_empty(>waiting_thread_node));
binder_enqueue_work_ilocked(work, >todo);
thread->process_todo = true;
 }
@@ -1270,19 +1272,12 @@ static int binder_inc_node_nilocked(struct binder_node 
*node, int strong,
} else
node->local_strong_refs++;
if (!node->has_strong_ref && target_list) {
+   struct binder_thread *thread = container_of(target_list,
+   struct binder_thread, todo);
binder_dequeue_work_ilocked(>work);
-   /*
-* Note: this function is the only place where we queue
-* directly to a thread->todo without using the
-* corresponding binder_enqueue_thread_work() helper
-* functions; in this case it's ok to not set the
-* process_todo flag, since we know this node work will
-* always be followed by other work that starts queue
-* processing: in case of synchronous transactions, a
-* BR_REPLY or BR_ERROR; in case of oneway
-* transactions, a BR_TRANSACTION_COMPLETE.
-*/
-   binder_enqueue_work_ilocked(>work, target_list);
+   BUG_ON(>todo != target_list);
+   binder_enqueue_deferred_thread_work_ilocked(thread,
+  >work);
}
} else {
if (!internal)
@@ -2723,6 +2718,7 @@ static void binder_transaction(struct binder_proc *proc,
 {
int ret;
struct binder_transaction *t;
+   struct binder_work *w;
struct binder_work *tcomplete;
binder_size_t *offp, *off_end, *off_start;
binder_size_t off_min;
@@ -2864,6 +2860,29 @@ static void binder_transaction(struct binder_proc *proc,
goto err_invalid_target_handle;
}
binder_inner_proc_lock(proc);
+
+   w = list_first_entry_or_null(>todo,
+struct binder_work, entry);
+   if (!(tr->flags & TF_ONE_WAY) && w &&
+   w->type == BINDER_WORK_TRANSACTION) {
+   /*
+* Do not allow new outgoing transaction from a
+* thread that has a transaction at the head of
+* its todo list. Only need to check the head
+* because binder_select_thread_ilocked picks a
+* thread from 

[PATCH] android: binder: no outgoing transaction when thread todo has transaction

2018-08-13 Thread Sherry Yang
When a process dies, failed reply is sent to the sender of any transaction
queued on a dead thread's todo list. The sender asserts that the
received failed reply corresponds to the head of the transaction stack.
This assert can fail if the dead thread is allowed to send outgoing
transactions when there is already a transaction on its todo list,
because this new transaction can end up on the transaction stack of the
original sender. The following steps illustrate how this assertion can
fail.

1. Thread1 sends txn19 to Thread2
   (T1->transaction_stack=txn19, T2->todo+=txn19)
2. Without processing todo list, Thread2 sends txn20 to Thread1
   (T1->todo+=txn20, T2->transaction_stack=txn20)
3. T1 processes txn20 on its todo list
   (T1->transaction_stack=txn20->txn19, T1->todo=)
4. T2 dies, T2->todo cleanup attempts to send failed reply for txn19, but
   T1->transaction_stack points to txn20 -- assertion failes

Step 2. is the incorrect behavior. When there is a transaction on a
thread's todo list, this thread should not be able to send any outgoing
synchronous transactions. Only the head of the todo list needs to be
checked because only threads that are waiting for proc work can directly
receive work from another thread, and no work is allowed to be queued
on such a thread without waking up the thread. This patch also enforces
that a thread is not waiting for proc work when a work is directly
enqueued to its todo list.

Acked-by: Arve Hjønnevåg 
Signed-off-by: Sherry Yang 
---
 drivers/android/binder.c | 44 +---
 1 file changed, 32 insertions(+), 12 deletions(-)

diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index d58763b6b009..f2081934eb8b 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -822,6 +822,7 @@ static void
 binder_enqueue_deferred_thread_work_ilocked(struct binder_thread *thread,
struct binder_work *work)
 {
+   WARN_ON(!list_empty(>waiting_thread_node));
binder_enqueue_work_ilocked(work, >todo);
 }
 
@@ -839,6 +840,7 @@ static void
 binder_enqueue_thread_work_ilocked(struct binder_thread *thread,
   struct binder_work *work)
 {
+   WARN_ON(!list_empty(>waiting_thread_node));
binder_enqueue_work_ilocked(work, >todo);
thread->process_todo = true;
 }
@@ -1270,19 +1272,12 @@ static int binder_inc_node_nilocked(struct binder_node 
*node, int strong,
} else
node->local_strong_refs++;
if (!node->has_strong_ref && target_list) {
+   struct binder_thread *thread = container_of(target_list,
+   struct binder_thread, todo);
binder_dequeue_work_ilocked(>work);
-   /*
-* Note: this function is the only place where we queue
-* directly to a thread->todo without using the
-* corresponding binder_enqueue_thread_work() helper
-* functions; in this case it's ok to not set the
-* process_todo flag, since we know this node work will
-* always be followed by other work that starts queue
-* processing: in case of synchronous transactions, a
-* BR_REPLY or BR_ERROR; in case of oneway
-* transactions, a BR_TRANSACTION_COMPLETE.
-*/
-   binder_enqueue_work_ilocked(>work, target_list);
+   BUG_ON(>todo != target_list);
+   binder_enqueue_deferred_thread_work_ilocked(thread,
+  >work);
}
} else {
if (!internal)
@@ -2723,6 +2718,7 @@ static void binder_transaction(struct binder_proc *proc,
 {
int ret;
struct binder_transaction *t;
+   struct binder_work *w;
struct binder_work *tcomplete;
binder_size_t *offp, *off_end, *off_start;
binder_size_t off_min;
@@ -2864,6 +2860,29 @@ static void binder_transaction(struct binder_proc *proc,
goto err_invalid_target_handle;
}
binder_inner_proc_lock(proc);
+
+   w = list_first_entry_or_null(>todo,
+struct binder_work, entry);
+   if (!(tr->flags & TF_ONE_WAY) && w &&
+   w->type == BINDER_WORK_TRANSACTION) {
+   /*
+* Do not allow new outgoing transaction from a
+* thread that has a transaction at the head of
+* its todo list. Only need to check the head
+* because binder_select_thread_ilocked picks a
+* thread from