Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

修正rwlock有的地方由于未使用ManuallyDrop导致的use after free && spinlock守卫新增leak,spinlock新增force unlock功能. #329

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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