From c8025a88798dc57ecc5d7f20ad69de695445638f Mon Sep 17 00:00:00 2001 From: login Date: Wed, 23 Nov 2022 20:18:22 +0800 Subject: [PATCH] =?UTF-8?q?new:=E5=9C=A8fork=E6=97=B6=E6=8B=B7=E8=B4=9Dsig?= =?UTF-8?q?nal=E5=92=8Csighand=20(#91)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refcount初始化 * new: 实现copy_sighand del: 删除sighand_struct的wqh, 待将来有需要时,替换成rust版本的 * new: 拷贝signal bugfix: 解决拷贝sighand时的uaf问题 --- kernel/src/include/DragonOS/signal.h | 3 +- kernel/src/include/DragonOS/signal.rs | 42 +++++++++++- kernel/src/ipc/signal.rs | 38 ++++++----- kernel/src/libs/atomic.rs | 23 +++++-- kernel/src/libs/list.rs | 15 +++++ kernel/src/libs/mod.rs | 4 +- kernel/src/libs/refcount.rs | 9 ++- kernel/src/libs/spinlock.rs | 6 ++ kernel/src/libs/wait_queue.rs | 12 ++++ kernel/src/process/fork.c | 19 +++--- kernel/src/process/fork.rs | 93 ++++++++++++++++++++++++--- kernel/src/process/initial_proc.rs | 11 +--- kernel/src/process/proc-types.h | 13 ++-- 13 files changed, 226 insertions(+), 62 deletions(-) create mode 100644 kernel/src/libs/list.rs create mode 100644 kernel/src/libs/wait_queue.rs diff --git a/kernel/src/include/DragonOS/signal.h b/kernel/src/include/DragonOS/signal.h index b4b3c1d1..86057324 100644 --- a/kernel/src/include/DragonOS/signal.h +++ b/kernel/src/include/DragonOS/signal.h @@ -108,13 +108,12 @@ struct signal_struct /** * @brief 信号处理结构体,位于pcb之中。 - * + * 请注意,该结构体需要与rust的版本一致,且以rust的为准 */ struct sighand_struct { spinlock_t siglock; refcount_t count; - wait_queue_head_t signal_fd_wqh; // 为每个信号注册的处理函数的结构体 struct sigaction action[MAX_SIG_NUM]; }; diff --git a/kernel/src/include/DragonOS/signal.rs b/kernel/src/include/DragonOS/signal.rs index 2eab511a..4d5613f6 100644 --- a/kernel/src/include/DragonOS/signal.rs +++ b/kernel/src/include/DragonOS/signal.rs @@ -4,7 +4,6 @@ // todo: 将这里更换为手动编写的ffi绑定 use crate::include::bindings::bindings::atomic_t; use crate::include::bindings::bindings::spinlock_t; -use crate::include::bindings::bindings::wait_queue_head_t; use crate::libs::ffi_convert::FFIBind2Rust; use crate::libs::ffi_convert::__convert_mut; use crate::libs::ffi_convert::__convert_ref; @@ -27,6 +26,12 @@ pub struct signal_struct { pub sig_cnt: atomic_t, } +impl Default for signal_struct{ + fn default() -> Self { + Self { sig_cnt: Default::default() } + } +} + /** * sigaction中的信号处理函数结构体 * 分为两种处理函数 @@ -50,6 +55,13 @@ impl core::fmt::Debug for sigaction__union_u{ } } + +impl Default for sigaction__union_u { + fn default() -> Self { + Self{_sa_handler:None} + } +} + /** * @brief 信号处理结构体 */ @@ -62,6 +74,13 @@ pub struct sigaction { pub sa_restorer: ::core::option::Option, // 暂时未实现该函数 } +impl Default for sigaction{ + fn default() -> Self { + Self { _u: Default::default(), sa_flags: Default::default(), sa_mask: Default::default(), sa_restorer: Default::default() } + } +} + + /** * 信号消息的结构体,作为参数传入sigaction结构体中指向的处理函数 @@ -115,10 +134,15 @@ pub struct __sifields__kill { pub struct sighand_struct { pub siglock: spinlock_t, pub count: RefCount, - pub signal_fd_wqh: wait_queue_head_t, pub action: [sigaction; MAX_SIG_NUM as usize], } +impl Default for sighand_struct{ + fn default() -> Self { + Self { siglock: Default::default(), count: Default::default(), action: [Default::default();MAX_SIG_NUM as usize] } + } +} + /** * @brief 正在等待的信号的标志位 */ @@ -319,4 +343,18 @@ impl FFIBind2Rust for sighan ) -> Option<&'a Self> { return __convert_ref(src) } +} + +/// @brief 将给定的来自bindgen的sigaction解析为Rust的signal.rs中定义的sigaction的引用 +impl FFIBind2Rust for sigaction{ + fn convert_mut<'a>( + src: *mut crate::include::bindings::bindings::sigaction, + ) -> Option<&'a mut Self> { + return __convert_mut(src); + } + fn convert_ref<'a>( + src: *const crate::include::bindings::bindings::sigaction, + ) -> Option<&'a Self> { + return __convert_ref(src) + } } \ No newline at end of file diff --git a/kernel/src/ipc/signal.rs b/kernel/src/ipc/signal.rs index 0501fa34..b6011fe6 100644 --- a/kernel/src/ipc/signal.rs +++ b/kernel/src/ipc/signal.rs @@ -7,8 +7,8 @@ use crate::{ ENOTSUP, ESRCH, PF_EXITING, PF_KTHREAD, PF_WAKEKILL, PROC_INTERRUPTIBLE, }, DragonOS::signal::{ - si_code_val, sighand_struct, siginfo, signal_struct, sigpending, sigset_t, - SignalNumber, MAX_SIG_NUM, sigaction, sigaction__union_u, + si_code_val, sigaction, sigaction__union_u, sighand_struct, siginfo, signal_struct, + sigpending, sigset_t, SignalNumber, MAX_SIG_NUM, }, }, kBUG, kdebug, kwarn, @@ -26,13 +26,11 @@ use crate::{ use crate::include::DragonOS::signal::{__siginfo_union, __siginfo_union_data}; /// 默认信号处理程序占位符(用于在sighand结构体中的action数组中占位) -pub static DEFAULT_SIGACTION: sigaction = sigaction{ - _u: sigaction__union_u{ - _sa_handler: None, - }, - sa_flags:0, - sa_mask:0, - sa_restorer:None +pub static DEFAULT_SIGACTION: sigaction = sigaction { + _u: sigaction__union_u { _sa_handler: None }, + sa_flags: 0, + sa_mask: 0, + sa_restorer: None, }; /// @brief kill系统调用,向指定的进程发送信号 @@ -142,7 +140,7 @@ fn signal_send_sig_info( if !lock_process_sighand(target_pcb, &mut flags).is_none() { // 发送信号 retval = send_signal_locked(sig, info, target_pcb, PidType::PID); - + kdebug!("flags=0x{:016x}", flags); // 对sighand放锁 unlock_process_sighand(target_pcb, &flags); @@ -159,22 +157,20 @@ fn lock_process_sighand<'a>( flags: &mut u64, ) -> Option<&'a mut sighand_struct> { kdebug!("lock_process_sighand"); - let x = unsafe { &mut *pcb.sighand }; let sighand_ptr = sighand_struct::convert_mut(unsafe { &mut *pcb.sighand }); // kdebug!("sighand_ptr={:?}", &sighand_ptr); if !sighand_ptr.is_some() { kBUG!("Sighand ptr of process {pid} is NULL!", pid = pcb.pid); return None; - }else{ - + } else { kdebug!("7777"); } - let lock = {&mut sighand_ptr.unwrap().siglock}; + let lock = { &mut sighand_ptr.unwrap().siglock }; kdebug!("123"); - kdebug!("lock={}", unsafe{*(lock as *mut spinlock_t as *mut i8)}); + kdebug!("lock={}", unsafe { *(lock as *mut spinlock_t as *mut i8) }); spin_lock_irqsave(lock, flags); - kdebug!("lock={}", unsafe{*(lock as *mut spinlock_t as *mut i8)}); + kdebug!("lock={}", unsafe { *(lock as *mut spinlock_t as *mut i8) }); kdebug!("locked"); let ret = unsafe { ((*pcb).sighand as *mut sighand_struct).as_mut() }; @@ -186,10 +182,10 @@ fn lock_process_sighand<'a>( /// @param flags 用来保存rflags的变量,将这个值恢复到rflags寄存器中 fn unlock_process_sighand(pcb: &mut process_control_block, flags: &u64) { kdebug!("unlock_process_sighand"); - let lock = unsafe{&mut (*pcb.sighand).siglock}; + let lock = unsafe { &mut (*pcb.sighand).siglock }; kdebug!("lock={:?}", lock); spin_unlock_irqrestore(lock, flags); - kdebug!("lock={}", unsafe{*(lock as *mut spinlock_t as *mut i8)}); + kdebug!("lock={}", unsafe { *(lock as *mut spinlock_t as *mut i8) }); kdebug!("123443"); } @@ -238,7 +234,10 @@ fn __send_signal_locked( let mut retval = 0; // 判断该进入该函数时,是否已经持有了锁 - println!("locked={}",spin_is_locked(unsafe { &(*pcb.sighand).siglock })); + println!( + "locked={}", + spin_is_locked(unsafe { &(*pcb.sighand).siglock }) + ); kdebug!("1234"); let _pending: Option<&mut sigpending> = sigpending::convert_mut(&mut pcb.sig_pending); kdebug!("567"); @@ -399,4 +398,3 @@ fn signal_wake_up_state(pcb: &mut process_control_block, state: u64) { process_kick(pcb); } } - diff --git a/kernel/src/libs/atomic.rs b/kernel/src/libs/atomic.rs index 010dca1b..ac5eb5b4 100644 --- a/kernel/src/libs/atomic.rs +++ b/kernel/src/libs/atomic.rs @@ -1,11 +1,26 @@ -use core::ptr::read_volatile; +#![allow(dead_code)] +use core::ptr::{read_volatile, write_volatile}; use crate::include::bindings::bindings::atomic_t; /// @brief 原子的读取指定的原子变量的值 #[inline] -pub fn atomic_read(ato:*const atomic_t)-> i64{ - unsafe{ +pub fn atomic_read(ato: *const atomic_t) -> i64 { + unsafe { return read_volatile(&(*ato).value); } -} \ No newline at end of file +} + +/// @brief 原子的设置原子变量的值 +#[inline] +pub fn atomic_set(ato: *mut atomic_t, value:i64) { + unsafe{ + write_volatile(&mut (*ato).value, value); + } +} + +impl Default for atomic_t { + fn default() -> Self { + Self { value: 0 } + } +} diff --git a/kernel/src/libs/list.rs b/kernel/src/libs/list.rs new file mode 100644 index 00000000..6f324e6d --- /dev/null +++ b/kernel/src/libs/list.rs @@ -0,0 +1,15 @@ +use crate::include::bindings::bindings::List; + +/// @brief 初始化链表 +#[inline] +pub fn list_init(list: *mut List) { + unsafe{*list}.prev = list; + unsafe{*list}.next = list; +} + +impl Default for List{ + fn default() -> Self { + let x= Self { prev: 0 as *mut List, next: 0 as *mut List }; + return x; + } +} \ No newline at end of file diff --git a/kernel/src/libs/mod.rs b/kernel/src/libs/mod.rs index 0070fb09..310fb132 100644 --- a/kernel/src/libs/mod.rs +++ b/kernel/src/libs/mod.rs @@ -3,4 +3,6 @@ pub mod spinlock; pub mod ffi_convert; #[macro_use] pub mod refcount; -pub mod atomic; \ No newline at end of file +pub mod atomic; +pub mod wait_queue; +pub mod list; \ No newline at end of file diff --git a/kernel/src/libs/refcount.rs b/kernel/src/libs/refcount.rs index a3c7e14a..95b3fff0 100644 --- a/kernel/src/libs/refcount.rs +++ b/kernel/src/libs/refcount.rs @@ -7,6 +7,12 @@ pub struct RefCount { pub refs: atomic_t, } +impl Default for RefCount{ + fn default() -> Self { + Self { refs: atomic_t { value: 1 }} + } +} + /// @brief 将给定的来自bindgen的refcount_t解析为Rust的RefCount的引用 impl FFIBind2Rust for RefCount{ fn convert_mut<'a>( @@ -21,10 +27,11 @@ impl FFIBind2Rust for RefCo } } +/// @brief 以指定的值初始化refcount macro_rules! REFCOUNT_INIT { ($x:expr) => { $crate::libs::refcount::RefCount { - refs: atomic_t { value: 0 }, + refs: $crate::include::bindings::bindings::atomic_t { value: $x }, } }; } diff --git a/kernel/src/libs/spinlock.rs b/kernel/src/libs/spinlock.rs index c6fc8235..8d4e6c9d 100644 --- a/kernel/src/libs/spinlock.rs +++ b/kernel/src/libs/spinlock.rs @@ -28,3 +28,9 @@ pub fn spin_is_locked(lock: &spinlock_t) -> bool { return if val == 0 { true } else { false }; } + +impl Default for spinlock_t { + fn default() -> Self { + Self { lock: 1 } + } +} \ No newline at end of file diff --git a/kernel/src/libs/wait_queue.rs b/kernel/src/libs/wait_queue.rs new file mode 100644 index 00000000..230c235c --- /dev/null +++ b/kernel/src/libs/wait_queue.rs @@ -0,0 +1,12 @@ +use crate::include::bindings::bindings::{wait_queue_head_t}; + +use super::{list::list_init}; + + +impl Default for wait_queue_head_t{ + fn default() -> Self { + let mut x = Self { wait_list: Default::default(), lock: Default::default() }; + list_init(&mut x.wait_list); + return x; + } +} \ No newline at end of file diff --git a/kernel/src/process/fork.c b/kernel/src/process/fork.c index 52b3ba45..b074bee1 100644 --- a/kernel/src/process/fork.c +++ b/kernel/src/process/fork.c @@ -12,11 +12,12 @@ int process_copy_files(uint64_t clone_flags, struct process_control_block *pcb); int process_copy_flags(uint64_t clone_flags, struct process_control_block *pcb); int process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb); int process_copy_thread(uint64_t clone_flags, struct process_control_block *pcb, uint64_t stack_start, - uint64_t stack_size, struct pt_regs *current_regs); - -extern int process_copy_sighand(uint64_t clone_flags, struct process_control_block * pcb); -extern int process_copy_signal(uint64_t clone_flags, struct process_control_block * pcb); + uint64_t stack_size, struct pt_regs *current_regs); +extern int process_copy_sighand(uint64_t clone_flags, struct process_control_block *pcb); +extern int process_copy_signal(uint64_t clone_flags, struct process_control_block *pcb); +extern void process_exit_sighand(struct process_control_block *pcb); +extern void process_exit_signal(struct process_control_block *pcb); /** * @brief fork当前进程 @@ -111,14 +112,14 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned retval = process_copy_files(clone_flags, tsk); if (retval) goto copy_files_failed; - + // 拷贝信号处理函数 retval = process_copy_sighand(clone_flags, tsk); - if(retval) + if (retval) goto copy_sighand_failed; - + retval = process_copy_signal(clone_flags, tsk); - if(retval) + if (retval) goto copy_signal_failed; // 拷贝线程结构体 @@ -338,7 +339,7 @@ static int process_rewrite_rbp(struct pt_regs *new_regs, struct process_control_ * @return uint64_t */ int process_copy_thread(uint64_t clone_flags, struct process_control_block *pcb, uint64_t stack_start, - uint64_t stack_size, struct pt_regs *current_regs) + uint64_t stack_size, struct pt_regs *current_regs) { // 将线程结构体放置在pcb后方 struct thread_struct *thd = (struct thread_struct *)(pcb + 1); diff --git a/kernel/src/process/fork.rs b/kernel/src/process/fork.rs index 34538934..f6c2e842 100644 --- a/kernel/src/process/fork.rs +++ b/kernel/src/process/fork.rs @@ -1,27 +1,102 @@ -use crate::{include::bindings::bindings::{process_control_block, CLONE_SIGHAND}, kdebug, libs::{refcount::{refcount_inc, RefCount}, ffi_convert::FFIBind2Rust}, arch::x86_64::asm::current::current_pcb}; +use core::ptr::null_mut; + +use alloc::boxed::Box; + +use crate::{ + arch::x86_64::asm::current::current_pcb, + include::{ + bindings::bindings::{ + process_control_block, CLONE_CLEAR_SIGHAND, CLONE_SIGHAND, CLONE_THREAD, ENOMEM, + }, + DragonOS::signal::{sigaction, sighand_struct, signal_struct}, + }, + ipc::signal::DEFAULT_SIGACTION, + kdebug, + libs::{ + ffi_convert::FFIBind2Rust, + refcount::{refcount_inc, RefCount}, + spinlock::{spin_lock_irqsave, spin_unlock_irqrestore}, atomic::atomic_set, + }, +}; #[no_mangle] pub extern "C" fn process_copy_sighand(clone_flags: u64, pcb: *mut process_control_block) -> i32 { kdebug!("process_copy_sighand"); - if(clone_flags & (CLONE_SIGHAND as u64)) != 0{ - let r = RefCount::convert_mut(unsafe{&mut (*((current_pcb().sighand))).count}).unwrap(); - refcount_inc(r); + if (clone_flags & (CLONE_SIGHAND as u64)) != 0 { + let r = RefCount::convert_mut(unsafe { &mut (*(current_pcb().sighand)).count }).unwrap(); + refcount_inc(r); } - 0 + // 在这里使用Box::leak将动态申请的内存的生命周期转换为static的 + let mut sig: &mut sighand_struct = Box::leak(Box::new(sighand_struct::default())); + if (sig as *mut sighand_struct) == null_mut() { + return -(ENOMEM as i32); + } + // 将新的sighand赋值给pcb + unsafe { + (*pcb).sighand = sig as *mut sighand_struct as usize + as *mut crate::include::bindings::bindings::sighand_struct; + } + + // 拷贝sigaction + let mut flags: u64 = 0; + spin_lock_irqsave(unsafe { &mut (*current_pcb().sighand).siglock }, &mut flags); + for (index, x) in unsafe { (*current_pcb().sighand).action } + .iter() + .enumerate() + { + if !(x as *const crate::include::bindings::bindings::sigaction).is_null() { + sig.action[index] = + *sigaction::convert_ref(x as *const crate::include::bindings::bindings::sigaction) + .unwrap(); + } else { + sig.action[index] = DEFAULT_SIGACTION; + } + } + + spin_unlock_irqrestore(unsafe { &mut (*current_pcb().sighand).siglock }, &flags); + + // 将所有屏蔽的信号的处理函数设置为default + if (clone_flags & (CLONE_CLEAR_SIGHAND as u64)) != 0 { + todo!(); + } + + return 0; } #[no_mangle] pub extern "C" fn process_copy_signal(clone_flags: u64, pcb: *mut process_control_block) -> i32 { kdebug!("process_copy_signal"); - 0 + // 如果克隆的是线程,则不拷贝信号(同一进程的各个线程之间共享信号) + if (clone_flags & (CLONE_THREAD as u64)) != 0 { + return 0; + } + let sig: &mut signal_struct = Box::leak(Box::new(signal_struct::default())); + if (sig as *mut signal_struct) == null_mut() { + return -(ENOMEM as i32); + } + atomic_set(&mut sig.sig_cnt, 1); + // 将sig赋值给pcb中的字段 + unsafe { + (*pcb).signal = sig as *mut signal_struct as usize + as *mut crate::include::bindings::bindings::signal_struct; + } + return 0; } #[no_mangle] -pub extern "C" fn process_exit_signal(pcb: *mut process_control_block){ - // todo: 回收进程的信号结构体 +pub extern "C" fn process_exit_signal(pcb: *mut process_control_block) { + // 回收进程的信号结构体 + unsafe { + drop((*pcb).sighand as *mut sighand_struct); + (*pcb).sighand = 0 as *mut crate::include::bindings::bindings::sighand_struct; + } } #[no_mangle] -pub extern "C" fn process_exit_sighand(pcb: *mut process_control_block){ +pub extern "C" fn process_exit_sighand(pcb: *mut process_control_block) { // todo: 回收进程的sighand结构体 + unsafe { + drop((*pcb).signal as *mut signal_struct); + (*pcb).signal = 0 as *mut crate::include::bindings::bindings::signal_struct; + } } diff --git a/kernel/src/process/initial_proc.rs b/kernel/src/process/initial_proc.rs index 7b3fc3bb..c887dd46 100644 --- a/kernel/src/process/initial_proc.rs +++ b/kernel/src/process/initial_proc.rs @@ -1,26 +1,21 @@ use crate::{ include::{ - bindings::bindings::{atomic_t, spinlock_t, wait_queue_head_t, List}, + bindings::bindings::{atomic_t, spinlock_t}, DragonOS::signal::{sighand_struct, signal_struct, MAX_SIG_NUM}, }, ipc::signal::DEFAULT_SIGACTION, }; +/// @brief 初始进程的signal结构体 #[no_mangle] pub static INITIAL_SIGNALS: signal_struct = signal_struct { sig_cnt: atomic_t { value: 0 }, }; +/// @brief 初始进程的sighand结构体 #[no_mangle] pub static mut INITIAL_SIGHAND: sighand_struct = sighand_struct { count: REFCOUNT_INIT!(1), siglock: spinlock_t { lock: 1 }, - signal_fd_wqh: wait_queue_head_t { - lock: spinlock_t { lock: 1 }, - wait_list: List { - prev: unsafe { &INITIAL_SIGHAND.signal_fd_wqh.wait_list as *const List } as *mut List, - next: unsafe { &INITIAL_SIGHAND.signal_fd_wqh.wait_list as *const List } as *mut List, - }, - }, action: [DEFAULT_SIGACTION; MAX_SIG_NUM as usize], }; diff --git a/kernel/src/process/proc-types.h b/kernel/src/process/proc-types.h index 5ec91ef5..77c22ef5 100644 --- a/kernel/src/process/proc-types.h +++ b/kernel/src/process/proc-types.h @@ -1,8 +1,8 @@ #pragma once -#include #include #include +#include // 进程最大可拥有的文件描述符数量 #define PROC_MAX_FD_NUM 16 @@ -32,11 +32,12 @@ #define USER_DS (0x30) // 进程初始化时的数据拷贝标志位 -#define CLONE_FS (1UL << 0) // 在进程间共享打开的文件 -#define CLONE_SIGNAL (1UL << 1) // 克隆时,与父进程共享信号结构体 -#define CLONE_VM (1UL << 2) // 在进程间共享虚拟内存空间 -#define CLONE_SIGHAND (1UL << 3) // 克隆时,与父进程共享信号处理结构体 - +#define CLONE_FS (1UL << 0) // 在进程间共享打开的文件 +#define CLONE_SIGNAL (1UL << 1) // 克隆时,与父进程共享信号结构体 +#define CLONE_VM (1UL << 2) // 在进程间共享虚拟内存空间 +#define CLONE_SIGHAND (1UL << 3) // 克隆时,与父进程共享信号处理结构体 +#define CLONE_CLEAR_SIGHAND (1UL << 4) // 克隆时,将原本被设置为SIG_IGNORE的信号,设置回SIG_DEFAULT +#define CLONE_THREAD (1UL << 5) // 拷贝线程 #define PCB_NAME_LEN 16 struct thread_struct