new:在fork时拷贝signal和sighand (#91)

* refcount初始化

* new: 实现copy_sighand
del: 删除sighand_struct的wqh, 待将来有需要时,替换成rust版本的

* new: 拷贝signal
bugfix: 解决拷贝sighand时的uaf问题
This commit is contained in:
login
2022-11-23 20:18:22 +08:00
committed by GitHub
parent 66f67c6a95
commit c8025a8879
13 changed files with 226 additions and 62 deletions

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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],
};

View File

@ -1,8 +1,8 @@
#pragma once
#include <stdint.h>
#include <DragonOS/signal.h>
#include <common/wait_queue.h>
#include <stdint.h>
// 进程最大可拥有的文件描述符数量
#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