rust_binder: use KVVec for files_to_translate

From: scadastrangelove

Date: Tue Aug 25 2026 - 12:18:04 EST


From: Sergey Gordeychik <scadastrangelove@xxxxxxxxx>

The num_fds value in a binder_fd_array_object is bounded by the
transaction buffer. However, its in-kernel metadata is larger than the
u32 array on the wire.

On 64-bit systems, FileEntry occupies 24 bytes. About 900,000 entries
therefore make files_to_translate request roughly 20.6 MiB of
physically contiguous memory, triggering a warning in
__alloc_frozen_pages_noprof.

translate_fds() later allocates Reservation entries from the same
count. At 16 bytes per entry, this requires another 13.7 MiB contiguous
allocation.

Neither vector requires physical contiguity. Use KVVec for both so
large allocations can fall back to vmalloc.

Keep close_on_free as KVec because its u32 storage matches the wire
representation and does not reach the allocation sizes above.

Tested under QEMU/KVM. The 900,000-entry reproducer no longer triggers
a page allocator warning, and a 300,000-entry transaction that repeats
one valid fd reaches translate_fds() without WARN or BUG.

Suggested-by: rust-in-peace agentic pipeline
Signed-off-by: Sergey Gordeychik <scadastrangelove@xxxxxxxxx>
---
drivers/android/binder/allocation.rs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/android/binder/allocation.rs b/drivers/android/binder/allocation.rs
index ea5846e4d..6a95298f2 100644
--- a/drivers/android/binder/allocation.rs
+++ b/drivers/android/binder/allocation.rs
@@ -208,7 +208,7 @@ pub(crate) fn translate_fds(&mut self) -> Result<TranslatedFds> {
let num_close_on_free = files.iter().filter(|entry| entry.close_on_free).count();
let mut close_on_free = KVec::with_capacity(num_close_on_free, GFP_KERNEL)?;

- let mut reservations = KVec::with_capacity(files.len(), GFP_KERNEL)?;
+ let mut reservations = KVVec::with_capacity(files.len(), GFP_KERNEL)?;
for file_info in files {
let res = FileDescriptorReservation::get_unused_fd_flags(bindings::O_CLOEXEC)?;
let fd = res.reserved_fd();
@@ -567,7 +567,7 @@ fn type_to_size(type_: u32) -> Option<usize> {

#[derive(Default)]
struct FileList {
- files_to_translate: KVec<FileEntry>,
+ files_to_translate: KVVec<FileEntry>,
close_on_free: KVec<u32>,
}

@@ -581,7 +581,7 @@ struct FileEntry {
}

pub(crate) struct TranslatedFds {
- reservations: KVec<Reservation>,
+ reservations: KVVec<Reservation>,
/// If commit is called, then these fds should be closed. (If commit is not called, then they
/// shouldn't be closed.)
close_on_free: FdsCloseOnFree,
@@ -595,7 +595,7 @@ struct Reservation {
impl TranslatedFds {
pub(crate) fn new() -> Self {
Self {
- reservations: KVec::new(),
+ reservations: KVVec::new(),
close_on_free: FdsCloseOnFree(KVec::new()),
}
}
--
2.43.0