mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 01:08:13 -04:00
rust_binder: use a u64 stride when cleaning up the offsets array
Allocation's Drop walks the offsets array (binder_size_t = u64 entries),
cleaning up the objects, but it used usize instead of u64 for both the
stride and the per-entry read.
On 64-bit kernels (usize == u64) this is harmless, but on 32-bit kernels
it walks the 8-byte entries in 4-byte steps, iterating an N-entry array
2N times, and reads the always-zero high word as offset 0, cleaning up
the object at offset 0 N extra times. As a result the referenced node or
handle ends up with a lower reference count than it actually has (a
refcount over-decrement), and binder's reference accounting is corrupted;
for example, the owner can be notified of a strong reference release
(BR_RELEASE) even though references still remain.
Change the stride to u64, and read each entry as a u64, narrowing it to
usize with try_into().
On 32-bit ARM, when this over-decrement would drive a count below zero,
the driver's existing refcount guard refuses it and fires:
rust_binder: Failure: refcount underflow!
Cc: stable <stable@kernel.org>
Fixes: eafedbc7c0 ("rust_binder: add Rust Binder driver")
Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
Acked-by: Carlos Llamas <cmllamas@google.com>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://patch.msgid.link/ahw3tFhLz9bMMJAO@v4bel
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
f223d27a54
commit
803c8a9502
@@ -259,7 +259,7 @@ fn drop(&mut self) {
|
||||
|
||||
if let Some(offsets) = info.offsets.clone() {
|
||||
let view = AllocationView::new(self, offsets.start);
|
||||
for i in offsets.step_by(size_of::<usize>()) {
|
||||
for i in offsets.step_by(size_of::<u64>()) {
|
||||
if view.cleanup_object(i).is_err() {
|
||||
pr_warn!("Error cleaning up object at offset {}\n", i)
|
||||
}
|
||||
@@ -420,7 +420,8 @@ pub(crate) fn transfer_binder_object(
|
||||
}
|
||||
|
||||
fn cleanup_object(&self, index_offset: usize) -> Result {
|
||||
let offset = self.alloc.read(index_offset)?;
|
||||
let offset = self.alloc.read::<u64>(index_offset)?;
|
||||
let offset: usize = offset.try_into().map_err(|_| EINVAL)?;
|
||||
let header = self.read::<BinderObjectHeader>(offset)?;
|
||||
match header.type_ {
|
||||
BINDER_TYPE_WEAK_BINDER | BINDER_TYPE_BINDER => {
|
||||
|
||||
Reference in New Issue
Block a user