[PATCH 2/4] binder: reject duplicate BC_ENTER_LOOPER commands
From: Yunseong Kim
Date: Wed Jun 03 2026 - 14:08:31 EST
BC_ENTER_LOOPER can be sent multiple times by a userspace process
without any error. The handler unconditionally ORs in the
BINDER_LOOPER_STATE_ENTERED flag without checking if already set.
While the existing code checks for the REGISTERED→ENTERED conflict,
it does not check for ENTERED→ENTERED. Sending BC_ENTER_LOOPER twice
corrupts the thread pool accounting because the kernel believes it has
more available looper threads than actually exist.
Add a check: if BINDER_LOOPER_STATE_ENTERED is already set, mark the
thread as INVALID and break without re-entering.
kcov-dataflow tracking (before):
ENTRY binder_thread_write(cmd=BC_ENTER_LOOPER)
thread->looper |= LOOPER_ENTERED
RET binder_thread_write() = 0 ← first call, OK
ENTRY binder_thread_write(cmd=BC_ENTER_LOOPER)
thread->looper |= LOOPER_ENTERED ← duplicate, no check!
RET binder_thread_write() = 0 ← silently accepted
kcov-dataflow tracking (after):
ENTRY binder_thread_write(cmd=BC_ENTER_LOOPER)
thread->looper |= LOOPER_ENTERED
RET binder_thread_write() = 0 ← first call, OK
ENTRY binder_thread_write(cmd=BC_ENTER_LOOPER)
thread->looper |= LOOPER_INVALID ← marked invalid, break
RET binder_thread_write() = 0 ← logged, thread invalidated
Reproduction:
$ ./To-Ulimit-and-Beyond
First BC_ENTER_LOOPER: ret=0
Second BC_ENTER_LOOPER: ret=0 ← both succeed (should reject 2nd)
Fixes: 457b9a6f09f0 ("Staging: android: add binder driver")
Link: https://lore.kernel.org/all/20260603-kcov-dataflow-next-20260603-v2-0-fee0939de2c4@xxxxxxxx/
Signed-off-by: Yunseong Kim <yunseong.kim@xxxxxxxx>
---
drivers/android/binder.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 0f3fc293cdf0..0430be814175 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -4365,6 +4365,12 @@ static int binder_thread_write(struct binder_proc *proc,
binder_user_error("%d:%d ERROR: BC_ENTER_LOOPER called after BC_REGISTER_LOOPER\n",
proc->pid, thread->pid);
}
+ if (thread->looper & BINDER_LOOPER_STATE_ENTERED) {
+ thread->looper |= BINDER_LOOPER_STATE_INVALID;
+ binder_user_error("%d:%d ERROR: BC_ENTER_LOOPER called twice\n",
+ proc->pid, thread->pid);
+ break;
+ }
thread->looper |= BINDER_LOOPER_STATE_ENTERED;
break;
case BC_EXIT_LOOPER:
--
2.43.0