Skip to content

Commit 5c75125

Browse files
committed
Merge tag 'char-misc-7.0-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char / misc / IIO driver fixes from Greg KH: "Here are some char/misc/iio/binder fixes for 7.0-rc4. Nothing major in here, just the usual: - lots of iio driver fixes for reported issues - rust binder fixes for problems found - gpib driver binding to the wrong device fix - firmware driver fix All of these have been in linux-next with no reported issues" * tag 'char-misc-7.0-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (28 commits) gpib: lpvo_usb: fix unintended binding of FTDI 8U232AM devices firmware: stratix10-svc: Add Multi SVC clients support rust_binder: use lock_vma_under_rcu() in use_page_slow() rust_binder: call set_notification_done() without proc lock rust_binder: avoid reading the written value in offsets array rust_binder: check ownership before using vma rust_binder: fix oneway spam detection firmware: stratix10-rsu: Fix NULL pointer dereference when RSU is disabled iio: imu: adis: Fix NULL pointer dereference in adis_init iio: imu: inv_icm45600: fix regulator put warning when probe fails iio: buffer: Fix wait_queue not being removed iio: gyro: mpu3050-core: fix pm_runtime error handling iio: gyro: mpu3050-i2c: fix pm_runtime error handling iio: adc: ad7768-1: Fix ERR_PTR dereference in ad7768_fill_scale_tbl iio: chemical: sps30_serial: fix buffer size in sps30_serial_read_meas() iio: chemical: sps30_i2c: fix buffer size in sps30_i2c_read_meas() iio: magnetometer: tlv493d: remove erroneous shift in X-axis data iio: proximity: hx9023s: Protect against division by zero in set_samp_freq iio: proximity: hx9023s: fix assignment order for __counted_by iio: chemical: bme680: Fix measurement wait duration calculation ...
2 parents 4dad25a + 163cc46 commit 5c75125

32 files changed

Lines changed: 325 additions & 181 deletions

drivers/android/binder/page_range.rs

Lines changed: 64 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,30 @@ pub(crate) struct ShrinkablePageRange {
142142
_pin: PhantomPinned,
143143
}
144144

145+
// We do not define any ops. For now, used only to check identity of vmas.
146+
static BINDER_VM_OPS: bindings::vm_operations_struct = pin_init::zeroed();
147+
148+
// To ensure that we do not accidentally install pages into or zap pages from the wrong vma, we
149+
// check its vm_ops and private data before using it.
150+
fn check_vma(vma: &virt::VmaRef, owner: *const ShrinkablePageRange) -> Option<&virt::VmaMixedMap> {
151+
// SAFETY: Just reading the vm_ops pointer of any active vma is safe.
152+
let vm_ops = unsafe { (*vma.as_ptr()).vm_ops };
153+
if !ptr::eq(vm_ops, &BINDER_VM_OPS) {
154+
return None;
155+
}
156+
157+
// SAFETY: Reading the vm_private_data pointer of a binder-owned vma is safe.
158+
let vm_private_data = unsafe { (*vma.as_ptr()).vm_private_data };
159+
// The ShrinkablePageRange is only dropped when the Process is dropped, which only happens once
160+
// the file's ->release handler is invoked, which means the ShrinkablePageRange outlives any
161+
// VMA associated with it, so there can't be any false positives due to pointer reuse here.
162+
if !ptr::eq(vm_private_data, owner.cast()) {
163+
return None;
164+
}
165+
166+
vma.as_mixedmap_vma()
167+
}
168+
145169
struct Inner {
146170
/// Array of pages.
147171
///
@@ -308,6 +332,18 @@ impl ShrinkablePageRange {
308332
inner.size = num_pages;
309333
inner.vma_addr = vma.start();
310334

335+
// This pointer is only used for comparison - it's not dereferenced.
336+
//
337+
// SAFETY: We own the vma, and we don't use any methods on VmaNew that rely on
338+
// `vm_private_data`.
339+
unsafe {
340+
(*vma.as_ptr()).vm_private_data = ptr::from_ref(self).cast_mut().cast::<c_void>()
341+
};
342+
343+
// SAFETY: We own the vma, and we don't use any methods on VmaNew that rely on
344+
// `vm_ops`.
345+
unsafe { (*vma.as_ptr()).vm_ops = &BINDER_VM_OPS };
346+
311347
Ok(num_pages)
312348
}
313349

@@ -399,22 +435,25 @@ impl ShrinkablePageRange {
399435
//
400436
// Using `mmput_async` avoids this, because then the `mm` cleanup is instead queued to a
401437
// workqueue.
402-
MmWithUser::into_mmput_async(self.mm.mmget_not_zero().ok_or(ESRCH)?)
403-
.mmap_read_lock()
404-
.vma_lookup(vma_addr)
405-
.ok_or(ESRCH)?
406-
.as_mixedmap_vma()
407-
.ok_or(ESRCH)?
408-
.vm_insert_page(user_page_addr, &new_page)
409-
.inspect_err(|err| {
410-
pr_warn!(
411-
"Failed to vm_insert_page({}): vma_addr:{} i:{} err:{:?}",
412-
user_page_addr,
413-
vma_addr,
414-
i,
415-
err
416-
)
417-
})?;
438+
let mm = MmWithUser::into_mmput_async(self.mm.mmget_not_zero().ok_or(ESRCH)?);
439+
{
440+
let vma_read;
441+
let mmap_read;
442+
let vma = if let Some(ret) = mm.lock_vma_under_rcu(vma_addr) {
443+
vma_read = ret;
444+
check_vma(&vma_read, self)
445+
} else {
446+
mmap_read = mm.mmap_read_lock();
447+
mmap_read
448+
.vma_lookup(vma_addr)
449+
.and_then(|vma| check_vma(vma, self))
450+
};
451+
452+
match vma {
453+
Some(vma) => vma.vm_insert_page(user_page_addr, &new_page)?,
454+
None => return Err(ESRCH),
455+
}
456+
}
418457

419458
let inner = self.lock.lock();
420459

@@ -667,12 +706,15 @@ unsafe extern "C" fn rust_shrink_free_page(
667706
let mmap_read;
668707
let mm_mutex;
669708
let vma_addr;
709+
let range_ptr;
670710

671711
{
672712
// CAST: The `list_head` field is first in `PageInfo`.
673713
let info = item as *mut PageInfo;
674714
// SAFETY: The `range` field of `PageInfo` is immutable.
675-
let range = unsafe { &*((*info).range) };
715+
range_ptr = unsafe { (*info).range };
716+
// SAFETY: The `range` outlives its `PageInfo` values.
717+
let range = unsafe { &*range_ptr };
676718

677719
mm = match range.mm.mmget_not_zero() {
678720
Some(mm) => MmWithUser::into_mmput_async(mm),
@@ -717,9 +759,11 @@ unsafe extern "C" fn rust_shrink_free_page(
717759
// SAFETY: The lru lock is locked when this method is called.
718760
unsafe { bindings::spin_unlock(&raw mut (*lru).lock) };
719761

720-
if let Some(vma) = mmap_read.vma_lookup(vma_addr) {
721-
let user_page_addr = vma_addr + (page_index << PAGE_SHIFT);
722-
vma.zap_page_range_single(user_page_addr, PAGE_SIZE);
762+
if let Some(unchecked_vma) = mmap_read.vma_lookup(vma_addr) {
763+
if let Some(vma) = check_vma(unchecked_vma, range_ptr) {
764+
let user_page_addr = vma_addr + (page_index << PAGE_SHIFT);
765+
vma.zap_page_range_single(user_page_addr, PAGE_SIZE);
766+
}
723767
}
724768

725769
drop(mmap_read);

drivers/android/binder/process.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1295,7 +1295,8 @@ impl Process {
12951295
}
12961296

12971297
pub(crate) fn dead_binder_done(&self, cookie: u64, thread: &Thread) {
1298-
if let Some(death) = self.inner.lock().pull_delivered_death(cookie) {
1298+
let death = self.inner.lock().pull_delivered_death(cookie);
1299+
if let Some(death) = death {
12991300
death.set_notification_done(thread);
13001301
}
13011302
}

drivers/android/binder/range_alloc/array.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ impl<T> ArrayRangeAllocator<T> {
118118
size: usize,
119119
is_oneway: bool,
120120
pid: Pid,
121-
) -> Result<usize> {
121+
) -> Result<(usize, bool)> {
122122
// Compute new value of free_oneway_space, which is set only on success.
123123
let new_oneway_space = if is_oneway {
124124
match self.free_oneway_space.checked_sub(size) {
@@ -146,7 +146,38 @@ impl<T> ArrayRangeAllocator<T> {
146146
.ok()
147147
.unwrap();
148148

149-
Ok(insert_at_offset)
149+
// Start detecting spammers once we have less than 20%
150+
// of async space left (which is less than 10% of total
151+
// buffer size).
152+
//
153+
// (This will short-circuit, so `low_oneway_space` is
154+
// only called when necessary.)
155+
let oneway_spam_detected =
156+
is_oneway && new_oneway_space < self.size / 10 && self.low_oneway_space(pid);
157+
158+
Ok((insert_at_offset, oneway_spam_detected))
159+
}
160+
161+
/// Find the amount and size of buffers allocated by the current caller.
162+
///
163+
/// The idea is that once we cross the threshold, whoever is responsible
164+
/// for the low async space is likely to try to send another async transaction,
165+
/// and at some point we'll catch them in the act. This is more efficient
166+
/// than keeping a map per pid.
167+
fn low_oneway_space(&self, calling_pid: Pid) -> bool {
168+
let mut total_alloc_size = 0;
169+
let mut num_buffers = 0;
170+
171+
// Warn if this pid has more than 50 transactions, or more than 50% of
172+
// async space (which is 25% of total buffer size). Oneway spam is only
173+
// detected when the threshold is exceeded.
174+
for range in &self.ranges {
175+
if range.state.is_oneway() && range.state.pid() == calling_pid {
176+
total_alloc_size += range.size;
177+
num_buffers += 1;
178+
}
179+
}
180+
num_buffers > 50 || total_alloc_size > self.size / 4
150181
}
151182

152183
pub(crate) fn reservation_abort(&mut self, offset: usize) -> Result<FreedRange> {

drivers/android/binder/range_alloc/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,11 @@ impl<T> RangeAllocator<T> {
188188
self.reserve_new(args)
189189
}
190190
Impl::Array(array) => {
191-
let offset =
191+
let (offset, oneway_spam_detected) =
192192
array.reserve_new(args.debug_id, args.size, args.is_oneway, args.pid)?;
193193
Ok(ReserveNew::Success(ReserveNewSuccess {
194194
offset,
195-
oneway_spam_detected: false,
195+
oneway_spam_detected,
196196
_empty_array_alloc: args.empty_array_alloc,
197197
_new_tree_alloc: args.new_tree_alloc,
198198
_tree_alloc: args.tree_alloc,

drivers/android/binder/range_alloc/tree.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -164,15 +164,6 @@ impl<T> TreeRangeAllocator<T> {
164164
self.free_oneway_space
165165
};
166166

167-
// Start detecting spammers once we have less than 20%
168-
// of async space left (which is less than 10% of total
169-
// buffer size).
170-
//
171-
// (This will short-circut, so `low_oneway_space` is
172-
// only called when necessary.)
173-
let oneway_spam_detected =
174-
is_oneway && new_oneway_space < self.size / 10 && self.low_oneway_space(pid);
175-
176167
let (found_size, found_off, tree_node, free_tree_node) = match self.find_best_match(size) {
177168
None => {
178169
pr_warn!("ENOSPC from range_alloc.reserve_new - size: {}", size);
@@ -203,6 +194,15 @@ impl<T> TreeRangeAllocator<T> {
203194
self.free_tree.insert(free_tree_node);
204195
}
205196

197+
// Start detecting spammers once we have less than 20%
198+
// of async space left (which is less than 10% of total
199+
// buffer size).
200+
//
201+
// (This will short-circuit, so `low_oneway_space` is
202+
// only called when necessary.)
203+
let oneway_spam_detected =
204+
is_oneway && new_oneway_space < self.size / 10 && self.low_oneway_space(pid);
205+
206206
Ok((found_off, oneway_spam_detected))
207207
}
208208

drivers/android/binder/thread.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,12 +1015,9 @@ impl Thread {
10151015

10161016
// Copy offsets if there are any.
10171017
if offsets_size > 0 {
1018-
{
1019-
let mut reader =
1020-
UserSlice::new(UserPtr::from_addr(trd_data_ptr.offsets as _), offsets_size)
1021-
.reader();
1022-
alloc.copy_into(&mut reader, aligned_data_size, offsets_size)?;
1023-
}
1018+
let mut offsets_reader =
1019+
UserSlice::new(UserPtr::from_addr(trd_data_ptr.offsets as _), offsets_size)
1020+
.reader();
10241021

10251022
let offsets_start = aligned_data_size;
10261023
let offsets_end = aligned_data_size + offsets_size;
@@ -1041,11 +1038,9 @@ impl Thread {
10411038
.step_by(size_of::<u64>())
10421039
.enumerate()
10431040
{
1044-
let offset: usize = view
1045-
.alloc
1046-
.read::<u64>(index_offset)?
1047-
.try_into()
1048-
.map_err(|_| EINVAL)?;
1041+
let offset = offsets_reader.read::<u64>()?;
1042+
view.alloc.write(index_offset, &offset)?;
1043+
let offset: usize = offset.try_into().map_err(|_| EINVAL)?;
10491044

10501045
if offset < end_of_previous_object || !is_aligned(offset, size_of::<u32>()) {
10511046
pr_warn!("Got transaction with invalid offset.");

drivers/firmware/stratix10-rsu.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,9 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
768768
rsu_async_status_callback);
769769
if (ret) {
770770
dev_err(dev, "Error, getting RSU status %i\n", ret);
771+
stratix10_svc_remove_async_client(priv->chan);
771772
stratix10_svc_free_channel(priv->chan);
773+
return ret;
772774
}
773775

774776
/* get DCMF version from firmware */

0 commit comments

Comments
 (0)