[PATCH] binder: fix sender fd 0 close and file refcount leak on TF_UPDATE_TXN

From: Hui Peng

Date: Sat Sep 19 2026 - 17:38:34 EST


In `binder_proc_transaction()`, when a oneway transaction with
`TF_UPDATE_TXN` supersedes an outdated pending transaction
(`t_outdated`), the driver calls `binder_release_entire_buffer(proc,
NULL, buffer, false)` and `kfree(t_outdated)`.

Passing `is_failure = false` while `buffer->transaction` has already
been set to `NULL` causes two bugs when `t_outdated` contained
`BINDER_TYPE_FDA` or `BINDER_TYPE_FD` objects:

1. For `BINDER_TYPE_FDA`, `binder_translate_fd_array()` never wrote
recipient file descriptors into the buffer (it only appended `struct
file *` entries to `t_outdated->fd_fixups`), so the FD array in
`buffer` still contains zeros (or sender-supplied offsets). Because
`is_failure` is `false`, `binder_transaction_buffer_release()`
executes the `!is_failure` branch on `BINDER_TYPE_FDA` and calls
`binder_deferred_fd_close(fd)` (closing `fd 0` in `current->files`,
which is the **sender** process!).
2. `t_outdated` is freed via `kfree(t_outdated)` without calling
`binder_free_txn_fixups(t_outdated)`, permanently leaking every
translated `struct file` reference in `t_outdated->fd_fixups`.

Pass `is_failure = true` to `binder_release_entire_buffer()` and call
`binder_free_txn_fixups(t_outdated)` before freeing `t_outdated`.

Fixes: 9864bb480133 ("Binder: add TF_UPDATE_TXN to replace outdated txn")
Fixes: bdc1c5fac982 ("binder: fix UAF caused by faulty buffer cleanup")
Assisted-by: LLM
Signed-off-by: Hui Peng <benquike@xxxxxxxxx>

---
drivers/android/binder.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 8f2ef1bd539f..bc8bc9ee43a5 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -2930,8 +2930,9 @@ static int binder_proc_transaction(struct binder_transaction *t,
t_outdated->buffer = NULL;
buffer->transaction = NULL;
trace_binder_transaction_update_buffer_release(buffer);
- binder_release_entire_buffer(proc, NULL, buffer, false);
+ binder_release_entire_buffer(proc, NULL, buffer, true);
binder_alloc_free_buf(&proc->alloc, buffer);
+ binder_free_txn_fixups(t_outdated);
kfree(t_outdated);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
}
--
2.55.0.1082.g2b9226bbc0-goog