Skip to content

Commit b0e7d3f

Browse files
committed
Merge tag 'char-misc-6.19-final' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull binder fixes from Greg KH: "Here are some small, last-minute binder C and Rust driver fixes for reported issues. They include a number of fixes for reported crashes and other problems. All of these have been in linux-next this week, and longer" * tag 'char-misc-6.19-final' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: binderfs: fix ida_alloc_max() upper bound rust_binderfs: fix ida_alloc_max() upper bound binder: fix BR_FROZEN_REPLY error log rust_binder: add additional alignment checks binder: fix UAF in binder_netlink_report() rust_binder: correctly handle FDA objects of length zero
2 parents dda5df9 + ec4ddc9 commit b0e7d3f

File tree

4 files changed

+94
-50
lines changed

4 files changed

+94
-50
lines changed

drivers/android/binder.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2991,6 +2991,10 @@ static void binder_set_txn_from_error(struct binder_transaction *t, int id,
29912991
* @t: the binder transaction that failed
29922992
* @data_size: the user provided data size for the transaction
29932993
* @error: enum binder_driver_return_protocol returned to sender
2994+
*
2995+
* Note that t->buffer is not safe to access here, as it may have been
2996+
* released (or not yet allocated). Callers should guarantee all the
2997+
* transaction items used here are safe to access.
29942998
*/
29952999
static void binder_netlink_report(struct binder_proc *proc,
29963000
struct binder_transaction *t,
@@ -3780,6 +3784,14 @@ static void binder_transaction(struct binder_proc *proc,
37803784
goto err_dead_proc_or_thread;
37813785
}
37823786
} else {
3787+
/*
3788+
* Make a transaction copy. It is not safe to access 't' after
3789+
* binder_proc_transaction() reported a pending frozen. The
3790+
* target could thaw and consume the transaction at any point.
3791+
* Instead, use a safe 't_copy' for binder_netlink_report().
3792+
*/
3793+
struct binder_transaction t_copy = *t;
3794+
37833795
BUG_ON(target_node == NULL);
37843796
BUG_ON(t->buffer->async_transaction != 1);
37853797
return_error = binder_proc_transaction(t, target_proc, NULL);
@@ -3790,7 +3802,7 @@ static void binder_transaction(struct binder_proc *proc,
37903802
*/
37913803
if (return_error == BR_TRANSACTION_PENDING_FROZEN) {
37923804
tcomplete->type = BINDER_WORK_TRANSACTION_PENDING;
3793-
binder_netlink_report(proc, t, tr->data_size,
3805+
binder_netlink_report(proc, &t_copy, tr->data_size,
37943806
return_error);
37953807
}
37963808
binder_enqueue_thread_work(thread, tcomplete);
@@ -3812,8 +3824,9 @@ static void binder_transaction(struct binder_proc *proc,
38123824
return;
38133825

38143826
err_dead_proc_or_thread:
3815-
binder_txn_error("%d:%d dead process or thread\n",
3816-
thread->pid, proc->pid);
3827+
binder_txn_error("%d:%d %s process or thread\n",
3828+
proc->pid, thread->pid,
3829+
return_error == BR_FROZEN_REPLY ? "frozen" : "dead");
38173830
return_error_line = __LINE__;
38183831
binder_dequeue_work(proc, tcomplete);
38193832
err_translate_failed:

drivers/android/binder/rust_binderfs.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ static int binderfs_binder_device_create(struct inode *ref_inode,
132132
mutex_lock(&binderfs_minors_mutex);
133133
if (++info->device_count <= info->mount_opts.max)
134134
minor = ida_alloc_max(&binderfs_minors,
135-
use_reserve ? BINDERFS_MAX_MINOR :
136-
BINDERFS_MAX_MINOR_CAPPED,
135+
use_reserve ? BINDERFS_MAX_MINOR - 1 :
136+
BINDERFS_MAX_MINOR_CAPPED - 1,
137137
GFP_KERNEL);
138138
else
139139
minor = -ENOSPC;
@@ -399,8 +399,8 @@ static int binderfs_binder_ctl_create(struct super_block *sb)
399399
/* Reserve a new minor number for the new device. */
400400
mutex_lock(&binderfs_minors_mutex);
401401
minor = ida_alloc_max(&binderfs_minors,
402-
use_reserve ? BINDERFS_MAX_MINOR :
403-
BINDERFS_MAX_MINOR_CAPPED,
402+
use_reserve ? BINDERFS_MAX_MINOR - 1 :
403+
BINDERFS_MAX_MINOR_CAPPED - 1,
404404
GFP_KERNEL);
405405
mutex_unlock(&binderfs_minors_mutex);
406406
if (minor < 0) {

drivers/android/binder/thread.rs

Lines changed: 70 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ use core::{
3939
sync::atomic::{AtomicU32, Ordering},
4040
};
4141

42+
fn is_aligned(value: usize, to: usize) -> bool {
43+
value % to == 0
44+
}
45+
4246
/// Stores the layout of the scatter-gather entries. This is used during the `translate_objects`
4347
/// call and is discarded when it returns.
4448
struct ScatterGatherState {
@@ -69,17 +73,24 @@ struct ScatterGatherEntry {
6973
}
7074

7175
/// This entry specifies that a fixup should happen at `target_offset` of the
72-
/// buffer. If `skip` is nonzero, then the fixup is a `binder_fd_array_object`
73-
/// and is applied later. Otherwise if `skip` is zero, then the size of the
74-
/// fixup is `sizeof::<u64>()` and `pointer_value` is written to the buffer.
75-
struct PointerFixupEntry {
76-
/// The number of bytes to skip, or zero for a `binder_buffer_object` fixup.
77-
skip: usize,
78-
/// The translated pointer to write when `skip` is zero.
79-
pointer_value: u64,
80-
/// The offset at which the value should be written. The offset is relative
81-
/// to the original buffer.
82-
target_offset: usize,
76+
/// buffer.
77+
enum PointerFixupEntry {
78+
/// A fixup for a `binder_buffer_object`.
79+
Fixup {
80+
/// The translated pointer to write.
81+
pointer_value: u64,
82+
/// The offset at which the value should be written. The offset is relative
83+
/// to the original buffer.
84+
target_offset: usize,
85+
},
86+
/// A skip for a `binder_fd_array_object`.
87+
Skip {
88+
/// The number of bytes to skip.
89+
skip: usize,
90+
/// The offset at which the skip should happen. The offset is relative
91+
/// to the original buffer.
92+
target_offset: usize,
93+
},
8394
}
8495

8596
/// Return type of `apply_and_validate_fixup_in_parent`.
@@ -762,8 +773,7 @@ impl Thread {
762773

763774
parent_entry.fixup_min_offset = info.new_min_offset;
764775
parent_entry.pointer_fixups.push(
765-
PointerFixupEntry {
766-
skip: 0,
776+
PointerFixupEntry::Fixup {
767777
pointer_value: buffer_ptr_in_user_space,
768778
target_offset: info.target_offset,
769779
},
@@ -789,6 +799,10 @@ impl Thread {
789799
let num_fds = usize::try_from(obj.num_fds).map_err(|_| EINVAL)?;
790800
let fds_len = num_fds.checked_mul(size_of::<u32>()).ok_or(EINVAL)?;
791801

802+
if !is_aligned(parent_offset, size_of::<u32>()) {
803+
return Err(EINVAL.into());
804+
}
805+
792806
let info = sg_state.validate_parent_fixup(parent_index, parent_offset, fds_len)?;
793807
view.alloc.info_add_fd_reserve(num_fds)?;
794808

@@ -803,13 +817,16 @@ impl Thread {
803817
}
804818
};
805819

820+
if !is_aligned(parent_entry.sender_uaddr, size_of::<u32>()) {
821+
return Err(EINVAL.into());
822+
}
823+
806824
parent_entry.fixup_min_offset = info.new_min_offset;
807825
parent_entry
808826
.pointer_fixups
809827
.push(
810-
PointerFixupEntry {
828+
PointerFixupEntry::Skip {
811829
skip: fds_len,
812-
pointer_value: 0,
813830
target_offset: info.target_offset,
814831
},
815832
GFP_KERNEL,
@@ -820,6 +837,7 @@ impl Thread {
820837
.sender_uaddr
821838
.checked_add(parent_offset)
822839
.ok_or(EINVAL)?;
840+
823841
let mut fda_bytes = KVec::new();
824842
UserSlice::new(UserPtr::from_addr(fda_uaddr as _), fds_len)
825843
.read_all(&mut fda_bytes, GFP_KERNEL)?;
@@ -871,17 +889,21 @@ impl Thread {
871889
let mut reader =
872890
UserSlice::new(UserPtr::from_addr(sg_entry.sender_uaddr), sg_entry.length).reader();
873891
for fixup in &mut sg_entry.pointer_fixups {
874-
let fixup_len = if fixup.skip == 0 {
875-
size_of::<u64>()
876-
} else {
877-
fixup.skip
892+
let (fixup_len, fixup_offset) = match fixup {
893+
PointerFixupEntry::Fixup { target_offset, .. } => {
894+
(size_of::<u64>(), *target_offset)
895+
}
896+
PointerFixupEntry::Skip {
897+
skip,
898+
target_offset,
899+
} => (*skip, *target_offset),
878900
};
879901

880-
let target_offset_end = fixup.target_offset.checked_add(fixup_len).ok_or(EINVAL)?;
881-
if fixup.target_offset < end_of_previous_fixup || offset_end < target_offset_end {
902+
let target_offset_end = fixup_offset.checked_add(fixup_len).ok_or(EINVAL)?;
903+
if fixup_offset < end_of_previous_fixup || offset_end < target_offset_end {
882904
pr_warn!(
883905
"Fixups oob {} {} {} {}",
884-
fixup.target_offset,
906+
fixup_offset,
885907
end_of_previous_fixup,
886908
offset_end,
887909
target_offset_end
@@ -890,13 +912,13 @@ impl Thread {
890912
}
891913

892914
let copy_off = end_of_previous_fixup;
893-
let copy_len = fixup.target_offset - end_of_previous_fixup;
915+
let copy_len = fixup_offset - end_of_previous_fixup;
894916
if let Err(err) = alloc.copy_into(&mut reader, copy_off, copy_len) {
895917
pr_warn!("Failed copying into alloc: {:?}", err);
896918
return Err(err.into());
897919
}
898-
if fixup.skip == 0 {
899-
let res = alloc.write::<u64>(fixup.target_offset, &fixup.pointer_value);
920+
if let PointerFixupEntry::Fixup { pointer_value, .. } = fixup {
921+
let res = alloc.write::<u64>(fixup_offset, pointer_value);
900922
if let Err(err) = res {
901923
pr_warn!("Failed copying ptr into alloc: {:?}", err);
902924
return Err(err.into());
@@ -949,25 +971,30 @@ impl Thread {
949971

950972
let data_size = trd.data_size.try_into().map_err(|_| EINVAL)?;
951973
let aligned_data_size = ptr_align(data_size).ok_or(EINVAL)?;
952-
let offsets_size = trd.offsets_size.try_into().map_err(|_| EINVAL)?;
953-
let aligned_offsets_size = ptr_align(offsets_size).ok_or(EINVAL)?;
954-
let buffers_size = tr.buffers_size.try_into().map_err(|_| EINVAL)?;
955-
let aligned_buffers_size = ptr_align(buffers_size).ok_or(EINVAL)?;
974+
let offsets_size: usize = trd.offsets_size.try_into().map_err(|_| EINVAL)?;
975+
let buffers_size: usize = tr.buffers_size.try_into().map_err(|_| EINVAL)?;
956976
let aligned_secctx_size = match secctx.as_ref() {
957977
Some((_offset, ctx)) => ptr_align(ctx.len()).ok_or(EINVAL)?,
958978
None => 0,
959979
};
960980

981+
if !is_aligned(offsets_size, size_of::<u64>()) {
982+
return Err(EINVAL.into());
983+
}
984+
if !is_aligned(buffers_size, size_of::<u64>()) {
985+
return Err(EINVAL.into());
986+
}
987+
961988
// This guarantees that at least `sizeof(usize)` bytes will be allocated.
962989
let len = usize::max(
963990
aligned_data_size
964-
.checked_add(aligned_offsets_size)
965-
.and_then(|sum| sum.checked_add(aligned_buffers_size))
991+
.checked_add(offsets_size)
992+
.and_then(|sum| sum.checked_add(buffers_size))
966993
.and_then(|sum| sum.checked_add(aligned_secctx_size))
967994
.ok_or(ENOMEM)?,
968-
size_of::<usize>(),
995+
size_of::<u64>(),
969996
);
970-
let secctx_off = aligned_data_size + aligned_offsets_size + aligned_buffers_size;
997+
let secctx_off = aligned_data_size + offsets_size + buffers_size;
971998
let mut alloc =
972999
match to_process.buffer_alloc(debug_id, len, is_oneway, self.process.task.pid()) {
9731000
Ok(alloc) => alloc,
@@ -999,13 +1026,13 @@ impl Thread {
9991026
}
10001027

10011028
let offsets_start = aligned_data_size;
1002-
let offsets_end = aligned_data_size + aligned_offsets_size;
1029+
let offsets_end = aligned_data_size + offsets_size;
10031030

10041031
// This state is used for BINDER_TYPE_PTR objects.
10051032
let sg_state = sg_state.insert(ScatterGatherState {
10061033
unused_buffer_space: UnusedBufferSpace {
10071034
offset: offsets_end,
1008-
limit: len,
1035+
limit: offsets_end + buffers_size,
10091036
},
10101037
sg_entries: KVec::new(),
10111038
ancestors: KVec::new(),
@@ -1014,12 +1041,16 @@ impl Thread {
10141041
// Traverse the objects specified.
10151042
let mut view = AllocationView::new(&mut alloc, data_size);
10161043
for (index, index_offset) in (offsets_start..offsets_end)
1017-
.step_by(size_of::<usize>())
1044+
.step_by(size_of::<u64>())
10181045
.enumerate()
10191046
{
1020-
let offset = view.alloc.read(index_offset)?;
1047+
let offset: usize = view
1048+
.alloc
1049+
.read::<u64>(index_offset)?
1050+
.try_into()
1051+
.map_err(|_| EINVAL)?;
10211052

1022-
if offset < end_of_previous_object {
1053+
if offset < end_of_previous_object || !is_aligned(offset, size_of::<u32>()) {
10231054
pr_warn!("Got transaction with invalid offset.");
10241055
return Err(EINVAL.into());
10251056
}
@@ -1051,7 +1082,7 @@ impl Thread {
10511082
}
10521083

10531084
// Update the indexes containing objects to clean up.
1054-
let offset_after_object = index_offset + size_of::<usize>();
1085+
let offset_after_object = index_offset + size_of::<u64>();
10551086
view.alloc
10561087
.set_info_offsets(offsets_start..offset_after_object);
10571088
}

drivers/android/binderfs.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ static int binderfs_binder_device_create(struct inode *ref_inode,
132132
mutex_lock(&binderfs_minors_mutex);
133133
if (++info->device_count <= info->mount_opts.max)
134134
minor = ida_alloc_max(&binderfs_minors,
135-
use_reserve ? BINDERFS_MAX_MINOR :
136-
BINDERFS_MAX_MINOR_CAPPED,
135+
use_reserve ? BINDERFS_MAX_MINOR - 1 :
136+
BINDERFS_MAX_MINOR_CAPPED - 1,
137137
GFP_KERNEL);
138138
else
139139
minor = -ENOSPC;
@@ -408,8 +408,8 @@ static int binderfs_binder_ctl_create(struct super_block *sb)
408408
/* Reserve a new minor number for the new device. */
409409
mutex_lock(&binderfs_minors_mutex);
410410
minor = ida_alloc_max(&binderfs_minors,
411-
use_reserve ? BINDERFS_MAX_MINOR :
412-
BINDERFS_MAX_MINOR_CAPPED,
411+
use_reserve ? BINDERFS_MAX_MINOR - 1 :
412+
BINDERFS_MAX_MINOR_CAPPED - 1,
413413
GFP_KERNEL);
414414
mutex_unlock(&binderfs_minors_mutex);
415415
if (minor < 0) {

0 commit comments

Comments
 (0)