Skip to content

Commit

Permalink
修正rwlock有的地方由于未使用ManuallyDrop导致的use after free && spinlock守卫新增leak,sp…
Browse files Browse the repository at this point in the history
…inlock新增force unlock功能.(#329)

1.修正rwlock有的地方由于未使用ManuallyDrop导致的use after free
2. spinlock守卫新增leak,spinlock新增force unlock功能.
  • Loading branch information
fslongjin authored Aug 13, 2023
1 parent c3dad00 commit 90a0a49
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 9 deletions.
39 changes: 30 additions & 9 deletions kernel/src/libs/rwlock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,12 +292,19 @@ impl<T> From<T> for RwLock<T> {
}

impl<'rwlock, T> RwLockReadGuard<'rwlock, T> {
/// @brief 释放守卫,获得保护的值的不可变引用
///
/// ## Safety
///
/// 由于这样做可能导致守卫在另一个线程中被释放,从而导致pcb的preempt count不正确,
/// 因此必须小心的手动维护好preempt count。
///
/// 并且,leak还可能导致锁的状态不正确。因此请仔细考虑是否真的需要使用这个函数。
#[allow(dead_code)]
#[inline]
/// @brief 释放守卫,获得保护的值的不可变引用
pub fn leak(this: Self) -> &'rwlock T {
let Self { data, .. } = this;
return unsafe { &*data };
pub unsafe fn leak(this: Self) -> &'rwlock T {
let this = ManuallyDrop::new(this);
return unsafe { &*this.data };
}
}

Expand Down Expand Up @@ -363,9 +370,16 @@ impl<'rwlock, T> RwLockUpgradableGuard<'rwlock, T> {

#[allow(dead_code)]
#[inline]
/// @brief 返回内部数据的引用,消除锁
pub fn leak(this: Self) -> &'rwlock T {
let this = ManuallyDrop::new(this);
/// @brief 返回内部数据的引用,消除守卫
///
/// ## Safety
///
/// 由于这样做可能导致守卫在另一个线程中被释放,从而导致pcb的preempt count不正确,
/// 因此必须小心的手动维护好preempt count。
///
/// 并且,leak还可能导致锁的状态不正确。因此请仔细考虑是否真的需要使用这个函数。
pub unsafe fn leak(this: Self) -> &'rwlock T {
let this: ManuallyDrop<RwLockUpgradableGuard<'_, T>> = ManuallyDrop::new(this);

unsafe { &*this.data }
}
Expand All @@ -374,8 +388,15 @@ impl<'rwlock, T> RwLockUpgradableGuard<'rwlock, T> {
impl<'rwlock, T> RwLockWriteGuard<'rwlock, T> {
#[allow(dead_code)]
#[inline]
/// @brief 返回内部数据的引用,消除锁
pub fn leak(this: Self) -> &'rwlock T {
/// @brief 返回内部数据的引用,消除守卫
///
/// ## Safety
///
/// 由于这样做可能导致守卫在另一个线程中被释放,从而导致pcb的preempt count不正确,
/// 因此必须小心的手动维护好preempt count。
///
/// 并且,leak还可能导致锁的状态不正确。因此请仔细考虑是否真的需要使用这个函数。
pub unsafe fn leak(this: Self) -> &'rwlock T {
let this = ManuallyDrop::new(this);

return unsafe { &*this.data };
Expand Down
34 changes: 34 additions & 0 deletions kernel/src/libs/spinlock.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![allow(dead_code)]
use core::cell::UnsafeCell;
use core::mem::ManuallyDrop;
use core::ops::{Deref, DerefMut};
use core::ptr::read_volatile;

Expand Down Expand Up @@ -107,6 +108,11 @@ impl RawSpinlock {
self.0.store(false, Ordering::Release);
}

/// 解锁,但是不更改preempt count
unsafe fn unlock_no_preempt(&self) {
self.0.store(false, Ordering::Release);
}

/// @brief 放锁并开中断
pub fn unlock_irq(&self) {
self.unlock();
Expand Down Expand Up @@ -170,6 +176,24 @@ pub struct SpinLockGuard<'a, T: 'a> {
flag: usize,
}

impl<'a, T: 'a> SpinLockGuard<'a, T> {
/// 泄露自旋锁的守卫,返回一个可变的引用
///
/// ## Safety
///
/// 由于这样做可能导致守卫在另一个线程中被释放,从而导致pcb的preempt count不正确,
/// 因此必须小心的手动维护好preempt count。
///
/// 并且,leak还可能导致锁的状态不正确。因此请仔细考虑是否真的需要使用这个函数。
#[inline]
pub unsafe fn leak(this: Self) -> &'a mut T {
// Use ManuallyDrop to avoid stacked-borrow invalidation
let this = ManuallyDrop::new(this);
// We know statically that only we are referencing data
unsafe { &mut *this.lock.data.get() }
}
}

/// 向编译器保证,SpinLock在线程之间是安全的.
/// 其中要求类型T实现了Send这个Trait
unsafe impl<T> Sync for SpinLock<T> where T: Send {}
Expand Down Expand Up @@ -223,6 +247,16 @@ impl<T> SpinLock<T> {
}
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
}

/// 强制解锁,并且不更改preempt count
///
/// ## Safety
///
/// 由于这样做可能导致preempt count不正确,因此必须小心的手动维护好preempt count。
/// 如非必要,请不要使用这个函数。
pub unsafe fn force_unlock(&self) {
self.lock.unlock_no_preempt();
}
}

/// 实现Deref trait,支持通过获取SpinLockGuard来获取临界区数据的不可变引用
Expand Down

0 comments on commit 90a0a49

Please sign in to comment.