From 03c6a60d9e488f075b819e47c6d10ae758138fb1 Mon Sep 17 00:00:00 2001 From: aLinChe <1129332011@qq.com> Date: Thu, 24 Jul 2025 14:55:54 +0800 Subject: [PATCH 01/15] =?UTF-8?q?feat(ptrace):=20=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit strace & RawPid Signed-off-by: aLinChe <1129332011@qq.com> --- kernel/src/arch/x86_64/ipc/signal.rs | 71 +++ kernel/src/arch/x86_64/mm/fault.rs | 4 +- kernel/src/ipc/generic_signal.rs | 9 +- kernel/src/ipc/kill.rs | 5 +- kernel/src/ipc/pipe.rs | 4 +- kernel/src/ipc/signal.rs | 9 +- kernel/src/ipc/signal_types.rs | 26 +- kernel/src/ipc/syscall/sys_restart.rs | 9 +- kernel/src/process/execve.rs | 9 +- kernel/src/process/exit.rs | 45 +- kernel/src/process/mod.rs | 138 ++++- kernel/src/process/ptrace.rs | 650 +++++++++++++++++++++++ kernel/src/process/syscall/mod.rs | 3 + kernel/src/process/syscall/sys_ptrace.rs | 300 +++++++++++ kernel/src/process/syscall/sys_tkill.rs | 50 ++ kernel/src/process/timer.rs | 3 +- user/apps/c_unitest/test-ptrace.c | 264 +++++++++ user/apps/strace/.gitignore | 1 + user/apps/strace/Makefile | 20 + user/apps/strace/main.cpp | 106 ++++ user/apps/strace/strace_format.h | 504 ++++++++++++++++++ user/dadk/config/strace-0.1.0.toml | 40 ++ 22 files changed, 2220 insertions(+), 50 deletions(-) create mode 100644 kernel/src/process/ptrace.rs create mode 100644 kernel/src/process/syscall/sys_ptrace.rs create mode 100644 kernel/src/process/syscall/sys_tkill.rs create mode 100644 user/apps/c_unitest/test-ptrace.c create mode 100644 user/apps/strace/.gitignore create mode 100644 user/apps/strace/Makefile create mode 100644 user/apps/strace/main.cpp create mode 100644 user/apps/strace/strace_format.h create mode 100644 user/dadk/config/strace-0.1.0.toml diff --git a/kernel/src/arch/x86_64/ipc/signal.rs b/kernel/src/arch/x86_64/ipc/signal.rs index 8b0b791e4..cbc654b23 100644 --- a/kernel/src/arch/x86_64/ipc/signal.rs +++ b/kernel/src/arch/x86_64/ipc/signal.rs @@ -334,6 +334,77 @@ impl UserUContext { } } +/// siginfo中的si_code的可选值 +/// 请注意,当这个值小于0时,表示siginfo来自用户态,否则来自内核态 +#[derive(Copy, Debug, Clone, PartialEq, Eq)] +pub enum SigCode { + /// 描述通用来源 + Origin(OriginCode), + /// 描述 SIGCHLD 的具体原因 + SigChld(ChldCode), +} + +/// 信号的通用来源码 (SI_*) +#[derive(Copy, Debug, Clone, PartialEq, Eq)] +#[repr(i32)] +pub enum OriginCode { + /// sent by kill, sigsend, raise + User = 0, + /// sent by kernel from somewhere + Kernel = 0x80, + /// 通过sigqueue发送 + Queue = -1, + /// 定时器过期时发送 + Timer = -2, + /// 当实时消息队列的状态发生改变时发送 + Mesgq = -3, + /// 当异步IO完成时发送 + AsyncIO = -4, + /// sent by queued SIGIO + SigIO = -5, +} + +/// SIGCHLD 专用原因码 (CLD_*) +#[derive(Copy, Debug, Clone, PartialEq, Eq)] +#[repr(i32)] +pub enum ChldCode { + Exited = 1, + Killed = 2, + Dumped = 3, + Trapped = 4, + Stopped = 5, + Continued = 6, +} + +impl SigCode { + /// 为SigCode这个枚举类型实现从i32转换到枚举类型的转换函数 + #[allow(dead_code)] + pub fn from_i32(signal: Signal, code: i32) -> SigCode { + match signal { + Signal::SIGCHLD => match code { + 1 => SigCode::SigChld(ChldCode::Exited), + 2 => SigCode::SigChld(ChldCode::Killed), + 3 => SigCode::SigChld(ChldCode::Dumped), + 4 => SigCode::SigChld(ChldCode::Trapped), + 5 => SigCode::SigChld(ChldCode::Stopped), + 6 => SigCode::SigChld(ChldCode::Continued), + _ => panic!("signal code not valid in {:?}", signal), + }, + // 对于其他信号,尝试匹配通用码 + _ => match code { + 0 => SigCode::Origin(OriginCode::User), + 0x80 => SigCode::Origin(OriginCode::Kernel), + -1 => SigCode::Origin(OriginCode::Queue), + -2 => SigCode::Origin(OriginCode::Timer), + -3 => SigCode::Origin(OriginCode::Mesgq), + -4 => SigCode::Origin(OriginCode::AsyncIO), + -5 => SigCode::Origin(OriginCode::SigIO), + _ => panic!("signal code not valid in {:?}", signal), + }, + } + } +} + bitflags! { #[repr(C,align(8))] #[derive(Default)] diff --git a/kernel/src/arch/x86_64/mm/fault.rs b/kernel/src/arch/x86_64/mm/fault.rs index 83b9c5873..a33bc91d6 100644 --- a/kernel/src/arch/x86_64/mm/fault.rs +++ b/kernel/src/arch/x86_64/mm/fault.rs @@ -9,7 +9,7 @@ use x86::{bits64::rflags::RFlags, controlregs::Cr4}; use crate::{ arch::{ interrupt::{trap::X86PfErrorCode, TrapFrame}, - ipc::signal::Signal, + ipc::signal::{OriginCode, SigCode, Signal}, mm::{MemoryManagementArch, X86_64MMArch}, CurrentIrqArch, MMArch, }, @@ -291,7 +291,7 @@ impl X86_64MMArch { let send_segv = || { let pid = ProcessManager::current_pid(); - let mut info = SigInfo::new(Signal::SIGSEGV, 0, SigCode::User, SigType::Kill(pid)); + let mut info = SigInfo::new(Signal::SIGSEGV, 0, SigCode::Origin(OriginCode::User), SigType::Kill(pid)); Signal::SIGSEGV .send_signal_info(Some(&mut info), pid) .expect("failed to send SIGSEGV to process"); diff --git a/kernel/src/ipc/generic_signal.rs b/kernel/src/ipc/generic_signal.rs index 82febe125..ddbb53c29 100644 --- a/kernel/src/ipc/generic_signal.rs +++ b/kernel/src/ipc/generic_signal.rs @@ -9,9 +9,10 @@ use crate::{ CurrentIrqArch, }, exception::InterruptArch, - process::ProcessManager, + process::{ptrace::handle_ptrace_signal_stop, ProcessFlags, ProcessManager}, sched::{schedule, SchedMode}, }; +use num_traits::FromPrimitive; /// 信号处理的栈的栈指针的最小对齐 #[allow(dead_code)] @@ -432,8 +433,12 @@ fn sig_stop(sig: Signal) { // 标记停止事件,供 waitid(WSTOPPED) 可见 pcb.sighand().flags_insert(SignalFlags::CLD_STOPPED); pcb.sighand().flags_insert(SignalFlags::STOP_STOPPED); + if pcb.flags().contains(ProcessFlags::PTRACED) { + log::debug!("sig_stop"); + handle_ptrace_signal_stop(¤t_pcb, sig); + } } - ProcessManager::mark_stop().unwrap_or_else(|e| { + ProcessManager::mark_stop(sig).unwrap_or_else(|e| { log::error!( "sleep error :{:?},failed to sleep process :{:?}, with signal :{:?}", e, diff --git a/kernel/src/ipc/kill.rs b/kernel/src/ipc/kill.rs index 250a39259..0d1d3888d 100644 --- a/kernel/src/ipc/kill.rs +++ b/kernel/src/ipc/kill.rs @@ -1,3 +1,4 @@ +use crate::arch::ipc::signal::{OriginCode, SigCode, Signal}; use crate::ipc::signal_types::{SigInfo, SigType}; use crate::process::pid::{Pid, PidType}; use crate::process::{ProcessControlBlock, ProcessManager, RawPid}; @@ -9,7 +10,7 @@ use system_error::SystemError; /// ### 杀死一个进程 pub fn kill_process(pid: RawPid, sig: Signal) -> Result { // 初始化signal info - let mut info = SigInfo::new(sig, 0, SigCode::User, SigType::Kill(pid)); + let mut info = SigInfo::new(sig, 0, SigCode::Origin(OriginCode::User), SigType::Kill(pid)); compiler_fence(core::sync::atomic::Ordering::SeqCst); let ret = sig @@ -28,7 +29,7 @@ pub fn kill_process_by_pcb( sig: Signal, ) -> Result { // 初始化signal info - let mut info = SigInfo::new(sig, 0, SigCode::User, SigType::Kill(pcb.raw_pid())); + let mut info = SigInfo::new(sig, 0, SigCode::Origin(OriginCode::User), SigType::Kill(pcb.raw_pid())); return sig .send_signal_info_to_pcb(Some(&mut info), pcb) diff --git a/kernel/src/ipc/pipe.rs b/kernel/src/ipc/pipe.rs index 2c73238fc..596ecb264 100644 --- a/kernel/src/ipc/pipe.rs +++ b/kernel/src/ipc/pipe.rs @@ -1,5 +1,5 @@ use crate::{ - arch::ipc::signal::Signal, + arch::ipc::signal::{OriginCode, SigCode, Signal}, filesystem::{ epoll::{ event_poll::{EventPoll, LockedEPItemLinkedList}, @@ -407,7 +407,7 @@ impl IndexNode for LockedPipeInode { let mut info = SigInfo::new( sig, 0, - SigCode::Kernel, + SigCode::Origin(OriginCode::Kernel), SigType::Kill(ProcessManager::current_pcb().task_pid_vnr()), ); compiler_fence(core::sync::atomic::Ordering::SeqCst); diff --git a/kernel/src/ipc/signal.rs b/kernel/src/ipc/signal.rs index 673c3756e..87c013e51 100644 --- a/kernel/src/ipc/signal.rs +++ b/kernel/src/ipc/signal.rs @@ -8,8 +8,7 @@ use log::warn; use system_error::SystemError; use crate::{ - arch::ipc::signal::{SigSet, Signal}, - ipc::signal_types::SigCode, + arch::ipc::signal::{OriginCode, SigCode, SigFlags, SigSet, Signal}, ipc::signal_types::SigactionType, mm::VirtAddr, process::{ @@ -127,7 +126,7 @@ impl Signal { // signal的信息为空 if let Some(ref siginfo) = info { - force_send = matches!(siginfo.sig_code(), SigCode::Kernel); + force_send = matches!(siginfo.sig_code(), SigCode::Origin(OriginCode::Kernel)); } else { // todo: 判断signal是否来自于一个祖先进程的namespace,如果是,则强制发送信号 //详见 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/signal.c?r=&mo=32170&fi=1220#1226 @@ -166,7 +165,7 @@ impl Signal { SigInfo::new( *self, 0, - SigCode::User, + SigCode::Origin(OriginCode::User), SigType::Kill(ProcessManager::current_pcb().raw_pid()), ) } @@ -381,7 +380,7 @@ impl Signal { fn signal_wake_up(pcb: Arc, fatal: bool) { // 如果是 fatal 的话就唤醒 stop 和 block 的进程来响应,因为唤醒后就会终止 // 如果不是 fatal 的就只唤醒 stop 的进程来响应 - // debug!("signal_wake_up"); + log::debug!("signal_wake_up"); // 如果目标进程已经在运行,则发起一个ipi,使得它陷入内核 let state = pcb.sched_info().inner_lock_read_irqsave().state(); let mut wakeup_ok = true; diff --git a/kernel/src/ipc/signal_types.rs b/kernel/src/ipc/signal_types.rs index 85b371eb6..41494a5c7 100644 --- a/kernel/src/ipc/signal_types.rs +++ b/kernel/src/ipc/signal_types.rs @@ -7,7 +7,7 @@ use crate::{ arch::{ asm::bitops::ffz, interrupt::TrapFrame, - ipc::signal::{SigFlags, SigSet, Signal, MAX_SIG_NUM}, + ipc::signal::{OriginCode, SigCode, SigFlags, SigSet, Signal, MAX_SIG_NUM}, }, mm::VirtAddr, process::{ProcessManager, RawPid}, @@ -173,7 +173,7 @@ impl SaHandlerType { #[derive(Debug, Copy, Clone)] pub struct Sigaction { action: SigactionType, - flags: SigFlags, + pub(crate) flags: SigFlags, mask: SigSet, // 为了可扩展性而设置的sa_mask /// 信号处理函数执行结束后,将会跳转到这个函数内进行执行,然后执行sigreturn系统调用 restorer: Option, @@ -469,15 +469,31 @@ impl SigInfo { pub enum SigType { Kill(RawPid), Alarm(RawPid), + SigFault(SigFaultInfo), + SigChld(SigChldInfo), // 后续完善下列中的具体字段 // Timer, // Rt, - // SigChild, - // SigFault, // SigPoll, // SigSys, } +#[derive(Copy, Clone, Debug)] +pub struct SigFaultInfo { + pub addr: usize, + pub trapno: i32, + // 对于某些架构,可能有额外的字段 +} + +#[derive(Copy, Clone, Debug)] +pub struct SigChldInfo { + pub pid: RawPid, + pub uid: usize, + pub status: i32, + pub utime: u64, + pub stime: u64, +} + impl SigInfo { pub fn new(sig: Signal, sig_errno: i32, sig_code: SigCode, sig_type: SigType) -> Self { Self { @@ -556,7 +572,7 @@ impl SigPending { return info; } else { // 信号不在sigqueue中,这意味着当前信号是来自快速路径,因此直接把siginfo设置为0即可。 - let mut ret = SigInfo::new(sig, 0, SigCode::User, SigType::Kill(RawPid::from(0))); + let mut ret = SigInfo::new(sig, 0, SigCode::Origin(OriginCode::User), SigType::Kill(RawPid::from(0))); ret.set_sig_type(SigType::Kill(RawPid::new(0))); return ret; } diff --git a/kernel/src/ipc/syscall/sys_restart.rs b/kernel/src/ipc/syscall/sys_restart.rs index e47bab6c0..c95385b87 100644 --- a/kernel/src/ipc/syscall/sys_restart.rs +++ b/kernel/src/ipc/syscall/sys_restart.rs @@ -2,7 +2,7 @@ use super::super::signal_types::{SigInfo, SigType}; use crate::arch::interrupt::TrapFrame; use crate::{ alloc::vec::Vec, - arch::ipc::signal::Signal, + arch::ipc::signal::{OriginCode, SigCode, Signal}, arch::syscall::nr::SYS_RESTART_SYSCALL, ipc::signal_types::SigCode, process::{ProcessManager, RawPid}, @@ -25,7 +25,12 @@ pub(super) fn do_kernel_restart_syscall() -> Result { // 不应该走到这里,因此kill掉当前进程及同组的进程 let pid = RawPid::new(0); let sig = Signal::SIGKILL; - let mut info = SigInfo::new(sig, 0, SigCode::Kernel, SigType::Kill(pid)); + let mut info = SigInfo::new( + sig, + 0, + SigCode::Origin(OriginCode::Kernel), + SigType::Kill(pid), + ); sig.send_signal_info(Some(&mut info), pid) .expect("Failed to kill "); diff --git a/kernel/src/process/execve.rs b/kernel/src/process/execve.rs index 309dad189..ff5775957 100644 --- a/kernel/src/process/execve.rs +++ b/kernel/src/process/execve.rs @@ -2,8 +2,9 @@ use crate::arch::CurrentIrqArch; use crate::exception::InterruptArch; use crate::filesystem::vfs::IndexNode; use crate::process::exec::{load_binary_file, ExecParam, ExecParamFlags}; -use crate::process::ProcessManager; +use crate::process::{ProcessFlags, ProcessManager}; use crate::syscall::Syscall; +use crate::process::ptrace::PtraceEvent; use crate::{libs::rand::rand_bytes, mm::ucontext::AddressSpace}; use crate::arch::interrupt::TrapFrame; @@ -28,6 +29,12 @@ pub fn do_execve( } })?; + let current_pcb = ProcessManager::current_pcb(); + if current_pcb.flags().contains(ProcessFlags::PTRACED) { + log::debug!("ptrace_event Exec"); + current_pcb.ptrace_event(PtraceEvent::Exec, current_pcb.task_pid_vnr().data()); + } + // log::debug!("load binary file done"); // debug!("argv: {:?}, envp: {:?}", argv, envp); param.init_info_mut().args = argv; diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs index e2598c613..42dc4bb0f 100644 --- a/kernel/src/process/exit.rs +++ b/kernel/src/process/exit.rs @@ -522,28 +522,28 @@ fn do_waitpid( // 而不是立即返回0。只有当子进程真正退出时才应该返回。 return None; } - ProcessState::Stopped => { - // 非 ptrace 停止:报告 stopsig=SIGSTOP - let exitcode = Signal::SIGSTOP as i32; - // 由于目前不支持ptrace,因此这个值为false - let ptrace = false; - - if (!ptrace) && (!kwo.options.contains(WaitOption::WSTOPPED)) { - // 调用方未请求 WSTOPPED,按照 Linux 语义应当继续等待其它事件 - // 而不是返回 0 并写回空的 siginfo。 - return None; + ProcessState::Stopped(stop_signal) => { + // todo: 在stopped里面,添加code字段,表示停止的原因 + if stop_signal <= 0 || stop_signal >= Signal::SIGRTMAX.into() { + return Some(Err(SystemError::EINVAL)); } - - // 填充 waitid 信息 - // log::debug!("do_waitpid: report CLD_STOPPED for pid={:?}", child_pcb.raw_pid()); - kwo.ret_info = Some(WaitIdInfo { - pid: child_pcb.task_pid_vnr(), - status: exitcode, - cause: SigChildCode::Stopped.into(), - }); - if !kwo.options.contains(WaitOption::WNOWAIT) { - // 消费一次停止事件标志(若存在) - child_pcb.sighand().flags_remove(SignalFlags::CLD_STOPPED); + let exitcode = stop_signal as i32; + let ptrace = child_pcb.is_traced(); + // 对于被跟踪的进程,总是报告停止状态,无论 WUNTRACED 是否设置 + // 对于非跟踪进程,只有在设置了 WUNTRACED 时才报告停止状态 + if (!ptrace) && (!kwo.options.contains(WaitOption::WUNTRACED)) { + kwo.ret_status = 0; + return Some(Ok(0)); + } + if likely(!(kwo.options.contains(WaitOption::WNOWAIT))) { + kwo.ret_status = (exitcode << 8) | 0x7f; + } + if let Some(infop) = &mut kwo.ret_info { + *infop = WaitIdInfo { + pid: child_pcb.raw_pid(), + status: exitcode, + cause: SigChildCode::Stopped.into(), + }; } return Some(Ok(child_pcb.raw_pid().data())); @@ -574,7 +574,8 @@ fn do_waitpid( drop(child_pcb); } return Some(Ok(pid.into())); - } + }, + ProcessState::TracedStopped => todo!() }; return None; diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 9588a05ec..f53629cf7 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -86,6 +86,7 @@ pub mod namespace; pub mod pid; pub mod preempt; pub mod process_group; +pub mod ptrace; pub mod resource; pub mod session; pub mod signal; @@ -273,10 +274,10 @@ impl ProcessManager { pub fn wakeup_stop(pcb: &Arc) -> Result<(), SystemError> { let _guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; let state = pcb.sched_info().inner_lock_read_irqsave().state(); - if let ProcessState::Stopped = state { + if let ProcessState::Stopped(_) = state { let mut writer = pcb.sched_info().inner_lock_write_irqsave(); let state = writer.state(); - if let ProcessState::Stopped = state { + if let ProcessState::Stopped(_) = state { writer.set_state(ProcessState::Runnable); // avoid deadlock drop(writer); @@ -359,7 +360,7 @@ impl ProcessManager { /// /// - 进入当前函数之前,不能持有sched_info的锁 /// - 进入当前函数之前,必须关闭中断 - pub fn mark_stop() -> Result<(), SystemError> { + pub fn mark_stop(sig: Signal) -> Result<(), SystemError> { assert!( !CurrentIrqArch::is_irq_enabled(), "interrupt must be disabled before enter ProcessManager::mark_stop()" @@ -368,7 +369,7 @@ impl ProcessManager { let pcb = ProcessManager::current_pcb(); let mut writer = pcb.sched_info().inner_lock_write_irqsave(); if !matches!(writer.state(), ProcessState::Exited(_)) { - writer.set_state(ProcessState::Stopped); + writer.set_state(ProcessState::Stopped(sig.into())); pcb.flags().insert(ProcessFlags::NEED_SCHEDULE); drop(writer); @@ -707,7 +708,9 @@ pub enum ProcessState { /// - 如果该bool为false,那么,这个进程必须被显式的唤醒,才能重新进入Runnable状态。 Blocked(bool), /// 进程被信号终止 - Stopped, + Stopped(usize), + /// 用于ptrace跟踪停止的状态 + TracedStopped, /// 进程已经退出,usize表示进程的退出码 Exited(usize), } @@ -740,7 +743,7 @@ impl ProcessState { /// [`Stopped`]: ProcessState::Stopped #[inline(always)] pub fn is_stopped(&self) -> bool { - matches!(self, ProcessState::Stopped) + matches!(self, ProcessState::Stopped(_)) } /// Returns exit code if the process state is [`Exited`]. @@ -753,6 +756,26 @@ impl ProcessState { } } +/// ptrace 系统调用的请求类型 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(i32)] +pub enum PtraceRequest { + PtraceTraceme = 0, // PTRACE_TRACEME + PtraceAttach = 16, // PTRACE_ATTACH + PtraceDetach = 17, // PTRACE_DETACH + PtraceSyscall = 24, // PTRACE_SYSCALL + PtraceSinglestep = 9, // PTRACE_SINGLESTEP + PtraceCont = 7, // PTRACE_CONT + PtraceGetregs = 12, // PTRACE_GETREGS + PtraceSetregs = 13, // PTRACE_SETREGS + PtracePeekuser = 3, // PTRACE_PEEKUSER + PtracePeekdata = 2, // PTRACE_PEEKDATA + PtracePokedata = 5, // PTRACE_POKEDATA + PtraceGetsiginfo = 0x4202, // PTRACE_GETSIGINFO + PtraceSetoptions = 0x4200, // PTRACE_SETOPTIONS + // ... 其他可能的请求 +} + bitflags! { /// pcb的标志位 pub struct ProcessFlags: usize { @@ -781,6 +804,24 @@ bitflags! { const RESTORE_SIG_MASK = 1 << 10; /// Forked but didn't exec const FORKNOEXEC = 1 << 11; + /// 进程当前停止 + const STOPPED = 1 << 14; + /// 进程当前由ptrace跟踪 + const PTRACED = 1 << 15; + /// 跟踪器已发出PTRACE_SYSCALL请求 + const TRACE_SYSCALL = 1 << 16; + /// 跟踪器已发出PTRACE_SINGLESTEP请求 + const TRACE_SINGLESTEP = 1 << 17; + /// 跟踪器设置了TRACE_EXIT选项 + const TRACE_EXIT = 1 << 18; + /// 跟踪器设置了TRACE_FORK/CLONE选项 + const TRACE_FORK = 1 << 19; + /// 跟踪器设置了TRACE_VFORK选项 + const TRACE_VFORK = 1 << 20; + /// 跟踪器设置了TRACE_EXEC选项 + const TRACE_EXEC = 1 << 21; + /// 系统调用正在中断点(入口或出口) + const SYSCALL_INTERRUPT = 1 << 22; } } @@ -833,6 +874,83 @@ pub struct ProcessItimers { pub prof: CpuItimer, // 用于 ITIMER_PROF } +/// 进程被跟踪的状态信息 +#[derive(Debug, Default)] +struct PtraceState { + /// 跟踪此进程的进程PID + tracer: Option, + /// 挂起的信号(等待调试器处理) + pending_signals: Vec, + /// 系统调用信息 (用于 PTRACE_SYSCALL) + syscall_info: Option, + /// ptrace选项位 + options: PtraceOptions, + /// 停止状态的状态字 + exit_code: usize, + /// 用于存储事件消息 + event_message: usize, +} +impl PtraceState { + pub fn new() -> Self { + Self { + tracer: None, + pending_signals: Vec::new(), + syscall_info: None, + options: PtraceOptions::empty(), + exit_code: 0, + event_message: 0, + } + } + + /// 获取停止状态的状态字 + pub fn status_code(&self) -> usize { + // 根据信号和状态生成状态码 + if let Some(signal) = self.pending_signals.first() { + (*signal as usize) << 8 + } else { + 0 + } + } + /// 检查是否有挂起的信号 + pub fn has_pending_signals(&self) -> bool { + !self.pending_signals.is_empty() + } + /// 添加挂起信号 + pub fn add_pending_signal(&mut self, signal: Signal) { + self.pending_signals.push(signal); + } + /// 获取下一个挂起信号 + pub fn next_pending_signal(&mut self) -> Option { + if self.pending_signals.is_empty() { + None + } else { + Some(self.pending_signals.remove(0)) + } + } +} + +#[derive(Debug, Default)] +pub struct SyscallInfo { + /// 系统调用入口信息(系统调用号、参数、返回值) + syscall_num: usize, + args: [usize; 6], + result: isize, +} +bitflags::bitflags! { + /// Ptrace选项(PTRACE_O_*) + #[derive(Default)] + pub struct PtraceOptions: usize { + const TRACESYSGOOD = 1 << 0; + const TRACEFORK = 1 << 1; + const TRACEVFORK = 1 << 2; + const TRACECLONE = 1 << 3; + const TRACEEXEC = 1 << 4; + const TRACEVFORKDONE = 1 << 5; + const TRACEEXIT = 1 << 6; + const TRACESECCOMP = 1 << 7; + } +} + #[derive(Debug)] pub struct ProcessControlBlock { /// 当前进程的pid @@ -911,6 +1029,11 @@ pub struct ProcessControlBlock { executable_path: RwLock, /// 资源限制(rlimit)数组 rlimits: RwLock<[RLimit64; RLimitID::Nlimits as usize]>, + + /// ptrace跟踪状态 + ptrace_state: SpinLock, + /// 被ptrace跟踪的进程列表(跟踪器跟踪了哪些进程) + ptraced_list: RwLock>, } impl ProcessControlBlock { @@ -995,6 +1118,7 @@ impl ProcessControlBlock { let ppcb: Weak = ProcessManager::find_task_by_vpid(ppid) .map(|p| Arc::downgrade(&p)) .unwrap_or_default(); + let ptrace_state = SpinLock::new(PtraceState::default()); // 使用 Arc::new_cyclic 避免在栈上创建巨大的结构体 let pcb = Arc::new_cyclic(|weak| { @@ -1034,6 +1158,8 @@ impl ProcessControlBlock { restart_block: SpinLock::new(None), executable_path: RwLock::new(name), rlimits: RwLock::new(Self::default_rlimits()), + ptrace_state, + ptraced_list: RwLock::new(Vec::new()), }; pcb.sig_info.write().set_tty(tty); diff --git a/kernel/src/process/ptrace.rs b/kernel/src/process/ptrace.rs new file mode 100644 index 000000000..8fed5ab1c --- /dev/null +++ b/kernel/src/process/ptrace.rs @@ -0,0 +1,650 @@ +use crate::arch::ipc::signal::{ChldCode, OriginCode, SigCode, SigFlags, Signal}; +use crate::arch::CurrentIrqArch; +use crate::exception::InterruptArch; +use crate::ipc::signal_types::{SigChldInfo, SigFaultInfo, SigInfo, SigType, SignalFlags}; +use crate::process::{ + ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState, PtraceOptions, PtraceRequest, + RawPid, +}; +use crate::sched::{schedule, DequeueFlag, EnqueueFlag, SchedMode}; +use alloc::{sync::Arc, vec::Vec}; +use core::{intrinsics::unlikely, sync::atomic::Ordering}; +use system_error::SystemError; + +/// ptrace 系统调用的事件类型 +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum PtraceEvent { + Fork = 1, + VFork, + Clone, + Exec, + VForkDone, + Exit, + Seccomp, + Stop = 128, // 信号或单步执行导致的停止 +} + +pub fn do_notify_parent(child: &ProcessControlBlock, signal: Signal) -> Result { + let parent = match child.parent_pcb() { + Some(p) => p, + None => { + // 父进程已经退出,子进程已被 `init` 收养 + return Err(SystemError::ESRCH); + } + }; + // debug_assert!(!child.is_stopped_or_traced()); + // todo WARN_ON_ONCE(!tsk->ptrace && (tsk->group_leader != tsk || !thread_group_empty(tsk))); + let mut autoreap = false; + let mut effective_signal = Some(signal); + // 检查父进程的信号处理方式以确定是否自动回收 + { + let sighand_lock = parent.sig_struct_irqsave(); + let sa = &sighand_lock.handlers[Signal::SIGCHLD as usize]; + // 这里简化了 !ptrace 的检查 + if signal == Signal::SIGCHLD { + if sa.action().is_ignore() { + // 父进程忽略 SIGCHLD,子进程应被自动回收 + autoreap = true; + // 并且不发送信号 + effective_signal = None; + } else if sa.flags.contains(SigFlags::SA_NOCLDWAIT) { + // 父进程不等待子进程,子进程应被自动回收 + autoreap = true; + // 但根据POSIX,信号仍然可以发送 + } + } + } + if let Some(sig) = effective_signal { + let mut info = SigInfo::new( + sig, + 0, + SigCode::Origin(OriginCode::Kernel), + SigType::SigChld(SigChldInfo { + pid: child.task_pid_vnr(), + uid: child.cred().uid.data(), + status: 0, // todo + utime: 0, // 可以根据需要填充实际值 + stime: 0, // 可以根据需要填充实际值 + }), + ); + let _ = sig.send_signal_info_to_pcb(Some(&mut info), parent); + } + // 因为即使父进程忽略信号,也可能在 wait() 中阻塞,需要被唤醒以返回 -ECHILD + child.wake_up_parent(None); + Ok(autoreap) +} + +pub fn handle_ptrace_signal_stop(current_pcb: &Arc, sig: Signal) { + let mut ptrace_state = current_pcb.ptrace_state.lock(); + // ptrace_data.stop_reason = PtraceStopReason::SignalStop(sig); + log::debug!( + "PID {} stopping due to ptrace on signal {:?}", + current_pcb.raw_pid(), + sig + ); + ptrace_state.exit_code = sig as usize; + // if let Some(tracer_pid) = ptrace_state.tracer { + // if let Some(tracer) = ProcessManager::find(tracer_pid) { + // let mut info = SigInfo::new( + // sig, + // 0, + // SigCode::Origin(OriginCode::Kernel), + // SigType::SigChld(SigChldInfo { + // pid: current_pcb.raw_pid(), + // uid: current_pcb.cred().uid.data(), + // status: sig as i32, + // utime: 0, // 可以根据需要填充实际值 + // stime: 0, // 可以根据需要填充实际值 + // }), + // ); + // let _ = Signal::SIGCHLD.send_signal_info_to_pcb(Some(&mut info), tracer); + // } + // } + current_pcb.set_state(ProcessState::TracedStopped); +} + +impl ProcessControlBlock { + /// 设置ptrace跟踪器 + pub fn set_tracer(&self, tracer: RawPid) -> Result<(), SystemError> { + // 确保当前没有被追踪 + if self.ptrace_state.lock().tracer.is_some() { + return Err(SystemError::EPERM); + } + // 设置跟踪关系 + let mut state = self.ptrace_state.lock(); + state.tracer = Some(tracer); + // 设置 PTRACED 标志 + self.flags().insert(ProcessFlags::PTRACED); + Ok(()) + } + + /// 移除ptrace跟踪器 + pub fn clear_tracer(&self) { + self.ptrace_state.lock().tracer = None; + self.flags() + .remove(ProcessFlags::PTRACED | ProcessFlags::TRACE_SYSCALL); + } + + /// 获取ptrace跟踪器 + pub fn tracer(&self) -> Option { + self.ptrace_state.lock().tracer.clone() + } + + pub fn is_traced(&self) -> bool { + self.ptrace_state.lock().tracer.is_some() + } + + pub fn is_traced_by(&self, tracer: &Arc) -> bool { + match self.tracer() { + Some(tracer_pid) => tracer_pid == tracer.raw_pid(), + None => false, + } + } + + pub fn set_state(&self, state: ProcessState) { + let mut sched_info = self.sched_info.inner_lock_write_irqsave(); + sched_info.set_state(state); + } + + /// 获取原始父进程 PID(非跟踪器) + pub fn real_parent_pid(&self) -> Option { + // 这里需要根据您的实际实现返回原始父进程 PID + // 假设有一个字段存储原始父进程 + self.parent_pcb().map(|p| p.raw_pid()) + } + + /// 获取父进程 PID(确保总是返回有效值) + pub fn parent_pid(&self) -> RawPid { + // 1. 尝试从直接父进程引用获取 + if let Some(tracer) = self.tracer() { + return tracer; + } + if let Some(parent) = self.parent_pcb() { + return parent.raw_pid(); + } + // // 2. 尝试从进程基本信息中的 ppid 字段获取 + // if self.basic().ppid != Pid(0) { + // return Pid::new(self.basic().ppid.data() as u32); + // } + // // 3. 如果都没有,则返回 init 进程的 PID (1) + self.raw_pid() + } + + pub fn set_parent(&self, new_parent: &Arc) -> Result<(), SystemError> { + if new_parent.raw_pid() == self.raw_pid() { + return Err(SystemError::EINVAL); // 不能将自己设为父进程 + } + if new_parent.is_exited() { + return Err(SystemError::ESRCH); // 父进程不能是退出状态或僵尸状态 + } + *(self.parent_pcb.write()) = Arc::downgrade(new_parent); + Ok(()) + } + + /// 获取停止状态的状态字 + pub fn ptrace_status_code(&self) -> usize { + self.ptrace_state.lock().status_code() + } + + /// 添加信号到队列 + pub fn enqueue_signal(&self, signal: Signal) { + let mut info = self.sig_info.write(); + info.sig_pending.signal_mut().insert(signal.into()); + } + /// 从队列获取信号 + // pub fn dequeue_signal(&self) -> Option { + // let mut info = self.sig_info.write(); + // info.dequeue_signal(signal, self) + // } + + /// 恢复进程执行 + // todo + pub fn ptrace_resume(&self, request: PtraceRequest, sig: Signal) { + if request == PtraceRequest::PtraceSyscall { + } else { + } + if request == PtraceRequest::PtraceSyscall { + // arch::user_enable_single_step(self); + } else { + // arch::user_disable_single_step(self); + } + let mut sched_info = self.sched_info.inner_lock_write_irqsave(); + // 清除停止/阻塞标志 + self.exit_signal.store(sig, Ordering::SeqCst); + self.flags().remove(ProcessFlags::STOPPED); + // 设置为可运行状态 + sched_info.set_state(ProcessState::Runnable); + // 加入调度队列 + if let Some(strong_ref) = self.self_ref.upgrade() { + let rq = self.sched_info.sched_entity().cfs_rq().rq(); + let (rq, _guard) = rq.self_lock(); + rq.enqueue_task( + strong_ref.clone(), + EnqueueFlag::ENQUEUE_RESTORE | EnqueueFlag::ENQUEUE_WAKEUP, + ); + } else { + log::warn!("ptrace_runnable: pid={} self_ref is dead", self.raw_pid()); + } + } + + /// 唤醒父进程的等待队列 + fn wake_up_parent(&self, state: Option) { + if let Some(parent) = self.parent_pcb() { + parent.wait_queue.wakeup(state); + } + } + + /// 通知父进程(调试器)发送 SIGTRAP 信号并设置适当的退出代码。 + pub fn ptrace_notify(exit_code: usize) -> Result<(), SystemError> { + let current_pcb = ProcessManager::current_pcb(); + if (exit_code & (0x7f | !0xffff)) != Signal::SIGTRAP as usize { + return Err(SystemError::EINVAL); + } + // 获取信号处理锁 + let sighand_lock = current_pcb.sig_struct_irqsave(); + let result = Self::ptrace_do_notify(Signal::SIGTRAP, exit_code, None); + drop(sighand_lock); + result + } + + /// 发送信号并通知父进程 + fn ptrace_do_notify( + signal: Signal, + exit_code: usize, + _reason: Option, // todo + ) -> Result<(), SystemError> { + let current_pcb: Arc = ProcessManager::current_pcb(); + // current_pcb.set_exit_code(exit_code); + let mut info = SigInfo::new( + signal, + 0, + SigCode::Origin(OriginCode::Kernel), + SigType::SigChld(SigChldInfo { + pid: current_pcb.raw_pid(), + uid: current_pcb.cred().uid.data(), + status: exit_code as i32, + utime: 0, // 可以根据需要填充实际值 + stime: 0, // 可以根据需要填充实际值 + }), + ); + signal.send_signal_info(Some(&mut info), current_pcb.raw_pid())?; + Ok(()) + } + + fn ptrace_event_enabled(&self, event: PtraceEvent) -> bool { + let event_flag = 1 << (event as u32 + 3); + self.ptrace_state.lock().event_message == event_flag && event_flag != 0; + true + } + + pub fn ptrace_event(&self, event: PtraceEvent, message: usize) { + if unlikely(self.ptrace_event_enabled(event)) { + self.ptrace_state.lock().event_message = message; + let _ = Self::ptrace_notify((event as usize) << 8 | Signal::SIGTRAP as usize); + } else if event == PtraceEvent::Exec { + // if (ptrace_flags & (PT_PTRACED | PT_SEIZED)) == PT_PTRACED { + log::debug!("ProcessFlags::PTRACED"); + let sig = Signal::SIGTRAP; + let mut info = SigInfo::new( + sig, + 0, + SigCode::Origin(OriginCode::Kernel), + SigType::SigFault(SigFaultInfo { addr: 0, trapno: 0 }), + ); + let _ = sig.send_signal_info_to_pcb(Some(&mut info), self.self_ref.upgrade().unwrap()); + // } + } + let wait_status = ((event as usize) << 8) | (Signal::SIGTRAP as usize); + self.ptrace_stop(wait_status); + self.set_state(ProcessState::Runnable); + } + /// 设置进程为停止状态 + fn ptrace_stop(&self, wait_status: usize) { + self.set_state(ProcessState::Stopped(wait_status)); + if let Some(tracer) = self.parent_pcb() { + tracer.wait_queue.wakeup(None); + } else { + log::error!("PID {} is traced but has no parent tracer!", self.raw_pid()); + } + schedule(SchedMode::SM_NONE); + } + + /// 设置进程为停止状态 + pub fn _stop_process(&self, signal: Signal) { + let status_code = signal.into(); + { + let mut sched_info = self.sched_info.inner_lock_write_irqsave(); + sched_info.set_state(ProcessState::Stopped(status_code)); + // 设置进程标志 + self.flags().insert(ProcessFlags::STOPPED); + if let Some(tracer) = self.tracer() { + self.wake_up_parent(Some(ProcessState::Stopped(status_code))); + } else { + let mut info = SigInfo::new( + signal, + 0, + SigCode::Origin(OriginCode::Kernel), + SigType::SigFault(SigFaultInfo { addr: 0, trapno: 0 }), + ); + let _ = signal.send_signal_info(Some(&mut info), self.parent_pid()); + } + } + log::debug!("Process {} stopped by signal {:?}", self.raw_pid(), signal); + // 唤醒父进程 + self.wake_up_parent(None); + // 移出调度队列 + if let Some(strong_ref) = self.self_ref.upgrade() { + let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; + { + let rq = self.sched_info.sched_entity().cfs_rq().rq(); + let (rq, _guard) = rq.self_lock(); + rq.dequeue_task(strong_ref.clone(), DequeueFlag::DEQUEUE_SAVE); + } + drop(irq_guard); + } + schedule(SchedMode::SM_NONE); + self.flags().remove(ProcessFlags::STOPPED); + let signal_to_deliver = { + let mut ptrace_state = self.ptrace_state.lock(); + ptrace_state.next_pending_signal() + }; + } + + /// 检查进程是否可以被指定进程跟踪 + pub fn has_permission_to_trace(&self, _tracee: &Self) -> bool { + // // 1. 超级用户可以跟踪任何进程 + // if self.is_superuser() { + // return true; + // } + // // 2. 检查是否拥有CAP_SYS_PTRACE权限 + // if self.cred().has_cap(Capability::CAP_SYS_PTRACE) { + // return true; + // } + // // 3. 检查用户ID是否相同 + // if self.basic().uid() == tracee.basic().uid() { + // return true; + // } + // false + true + } + + pub fn ptrace_link(&self, tracer: &Arc) -> Result<(), SystemError> { + if !tracer.has_permission_to_trace(self) { + return Err(SystemError::EPERM); + } + // 将子进程添加到父进程的跟踪列表 + // let mut ptrace_list = tracer.ptraced_list.write(); + // let child_pid = self.raw_pid(); + // if ptrace_list.iter().any(|&pid| pid == child_pid) { + // return Err(SystemError::EALREADY); + // } + // ptrace_list.push(child_pid); + self.set_tracer(tracer.raw_pid())?; + self.ptrace_state.lock().tracer = Some(tracer.raw_pid()); + *self.cred.lock() = tracer.cred().clone(); + Ok(()) + } + + pub fn ptrace_unlink(&self) -> Result<(), SystemError> { + // 确保当前进程确实被跟踪 + if !self.is_traced() { + return Err(SystemError::EINVAL); + } + // 清除系统调用跟踪相关工作 + // self.clear_syscall_trace_work(); + // 恢复父进程为真实父进程 + let real_parent = self.real_parent_pcb().ok_or(SystemError::ESRCH)?; + let _ = self.set_parent(&real_parent); + // 从跟踪器的跟踪列表中移除当前进程 + // let mut ptrace_list = tracer.ptraced_list.write(); + // if let Some(pos) = ptrace_list.iter().position(|&pid| pid == self.raw_pid()) { + // ptrace_list.remove(pos); + // } + // 清理凭证信息 + { + let mut cred = self.cred.lock(); + // todo *cred = self.original_cred().clone(); + } + // 获取信号锁保护信号相关操作 + let sighand_lock = self.sig_struct_irqsave(); + self.clear_tracer(); + self.flags() + .remove(ProcessFlags::PTRACED | ProcessFlags::TRACE_SYSCALL); + // 清除所有挂起的陷阱和TRAPPING状态 + // self.clear_jobctl_pending(JobCtl::TRAP_MASK); // 假设有JobCtl枚举和clear_jobctl_pending方法 + // self.clear_jobctl_trapping(); // 假设有clear_jobctl_trapping方法 + // 如果进程没有退出且有停止信号或组停止计数,重新设置停止挂起标志 + // if !self.is_exiting() + // && (self.signal_flags().contains(SignalFlags::STOP_STOPPED) + // || self.group_stop_count() > 0) + // { + // self.set_jobctl_pending(JobCtl::STOP_PENDING); + // // 如果没有设置停止信号掩码,默认使用SIGSTOP + // if !self.jobctl().contains(JobCtl::STOP_SIGMASK) { + // self.set_jobctl_pending(JobCtl::from_signal(Signal::SIGSTOP)); // 假设有from_signal方法 + // } + // } + // 如果有停止挂起或任务处于被跟踪状态,唤醒进程 + // if self.jobctl().contains(JobCtl::STOP_PENDING) || self.is_traced() { + // self.ptrace_signal_wake_up(true); // 假设有ptrace_signal_wake_up方法 + // } + drop(sighand_lock); + Ok(()) + } + + /// 处理PTRACE_TRACEME请求 + pub fn traceme(&self) -> Result { + if self.is_traced() { + return Err(SystemError::EPERM); + } + let parent = self.real_parent_pcb().ok_or(SystemError::ESRCH)?; + self.flags().insert(ProcessFlags::PTRACED); + self.ptrace_link(&parent)?; + Ok(0) + } + + /// 处理PTRACE_ATTACH请求 + pub fn attach(&self, tracer: &Arc) -> Result { + // 验证权限(简化版) + if !tracer.has_permission_to_trace(self) + || self.flags().contains(ProcessFlags::KTHREAD) + || ProcessManager::same_thread_group(tracer, &self.self_ref) + { + return Err(SystemError::EPERM); + } + log::info!("attach by Tracer: {}", tracer.raw_pid()); + self.flags().insert(ProcessFlags::PTRACED); + self.ptrace_link(tracer)?; + let sig = Signal::SIGSTOP; + let mut info = SigInfo::new( + sig, + 0, + SigCode::Origin(OriginCode::Kernel), + SigType::SigFault(SigFaultInfo { addr: 0, trapno: 0 }), + ); + if let Err(e) = + sig.send_signal_info_to_pcb(Some(&mut info), self.self_ref.upgrade().unwrap()) + { + // 回滚ptrace设置 + self.flags().remove(ProcessFlags::PTRACED); + let _ = self.ptrace_unlink()?; + return Err(e); + } + // { + // let guard = tracer.sig_struct_irqsave(); + // signal_wake_up(self.self_ref.upgrade().unwrap(), guard, false); + // } + Ok(0) + } + + /// 处理PTRACE_DETACH请求 + pub fn detach(&self, signal: Option) -> Result { + // 验证调用者是跟踪器 + let current_pcb = ProcessManager::current_pcb(); + if !self.is_traced_by(¤t_pcb) { + return Err(SystemError::EPERM); + } + self.ptrace_unlink()?; + let mut dead = !self.is_thread_group_leader(); + if !dead { + let real_parent = self.real_parent_pcb().ok_or(SystemError::ESRCH)?; + if !ProcessManager::same_thread_group(&real_parent, &self.self_ref) { + dead = do_notify_parent(self, signal.unwrap())?; // todo + return Ok(0); + } else if self.sig_struct_irqsave().handlers[Signal::SIGCHLD as usize] + .action() + .is_ignore() + { + self.wake_up_parent(None); + dead = true; + } + } + Ok(0) + } + + /// 处理 PTRACE_CONT 请求 + pub fn ptrace_cont(&self, signal: Option) -> Result { + log::info!( + "PTRACE_CONT for process {}, signal: {:?}", + self.raw_pid(), + signal + ); + if signal == None { + return Ok(0); + } + let mut sig = Signal::SIGCONT; + if signal != None { + sig = Signal::from(signal.unwrap() as i32); + } + // 检查当前进程是否有权限操作目标进程 + let current = ProcessManager::current_pcb(); + if self.tracer() != Some(current.raw_pid()) { + return Err(SystemError::EPERM); + } + // 检查进程是否被跟踪 + if !self.flags().contains(ProcessFlags::PTRACED) { + return Err(SystemError::ESRCH); + } + // 检查进程是否处于停止状态 + if !self.flags().contains(ProcessFlags::STOPPED) { + return Err(SystemError::EINVAL); + } + self.ptrace_resume(PtraceRequest::PtraceCont, sig); + Ok(0) + } + + // 处理PTRACE_SYSCALL请求 + pub fn trace_syscall(&self) -> Result { + // 设置系统调用跟踪标志 + self.flags().insert(ProcessFlags::TRACE_SYSCALL); + self.flags().remove(ProcessFlags::TRACE_SINGLESTEP); + // 恢复进程运行 + let mut sched_info = self.sched_info.inner_lock_write_irqsave(); + if let ProcessState::Stopped(_signal) = sched_info.state() { + sched_info.set_state(ProcessState::Runnable); + } + Ok(0) + } + + /// 处理PTRACE_SINGLESTEP请求 + pub fn single_step(&self) -> Result { + // 设置单步执行标志 + self.flags().insert(ProcessFlags::TRACE_SINGLESTEP); + self.flags().remove(ProcessFlags::TRACE_SYSCALL); + + // 在CPU层面启用单步执行 + // if let Some(context) = self.context_mut() { + // context.enable_single_step(); + // } + + // 恢复进程运行 + let mut sched_info = self.sched_info.inner_lock_write_irqsave(); + if let ProcessState::Stopped(_signal) = sched_info.state() { + sched_info.set_state(ProcessState::Runnable); + } + + Ok(0) + } + + /// 启用单步执行 + pub fn enable_single_step(&self) { + // 实际实现中需要设置CPU标志 + } + + /// 启用系统调用跟踪 + pub fn enable_syscall_tracing(&self) { + self.flags().insert(ProcessFlags::TRACE_SYSCALL); + } + + /// 在系统调用入口处理 + pub fn on_syscall_entry(&self, num: usize, args: &[usize]) { + // 实际实现中需要记录系统调用信息 + } + + /// 在系统调用出口处理 + pub fn on_syscall_exit(&self, result: isize) { + // 实际实现中需要记录系统调用结果 + } + + /// 处理 PTRACE_PEEKUSER 请求 + pub fn peek_user(&self, addr: usize) -> Result { + // // 验证地址是否在用户空间范围内 + // if !self.memory.is_user_address(addr) { + // return Err(SystemError::EFAULT); + // } + // // 使用正确的寄存器偏移量 + // let offset = syscall_number_offset(); + // let reg_addr = offset * core::mem::size_of::(); + // // 确保访问的是寄存器区域 + // if addr != reg_addr { + // return Err(SystemError::EFAULT); + // } + // // 获取当前线程的寄存器值 + // let thread = self.current_thread().ok_or(SystemError::ESRCH)?; + // let regs = thread.get_registers(); + // // 返回系统调用号 + // Ok(regs.syscall_number() as isize) + Ok(0) + } + + /// 设置PTRACE选项 + pub fn set_ptrace_options(&self, options: PtraceOptions) -> Result<(), SystemError> { + let mut state = self.ptrace_state.lock(); + state.options = options; + Ok(()) + } + + /// 清空待处理信号 + pub fn clear_ptrace(&self) { + let mut ptrace_state = self.ptrace_state.lock(); + + // 清除跟踪关系 + ptrace_state.tracer = None; + // ptrace_state.siginfo = None; + ptrace_state.pending_signals = Vec::new(); + // ptrace_state.signal_queue.clear(); + + // 清除标志位 + self.flags().remove( + ProcessFlags::PTRACED | ProcessFlags::TRACE_SYSCALL | ProcessFlags::TRACE_SINGLESTEP, + ); + } + + fn decode_exit_code_for_siginfo(exit_code: i32) -> (SigCode, i32) { + if (exit_code & 0x7f) == 0 { + // 正常退出: exit() + let status = (exit_code >> 8) & 0xff; + (SigCode::SigChld(ChldCode::Exited), status) + } else { + // 因信号终止 + let signal_num = exit_code & 0x7f; + if (exit_code & 0x80) != 0 { + // 生成了 core dump + (SigCode::SigChld(ChldCode::Dumped), signal_num) + } else { + // 未生成 core dump + (SigCode::SigChld(ChldCode::Killed), signal_num) + } + } + } +} diff --git a/kernel/src/process/syscall/mod.rs b/kernel/src/process/syscall/mod.rs index 5b3e6d04b..8a3c4b96e 100644 --- a/kernel/src/process/syscall/mod.rs +++ b/kernel/src/process/syscall/mod.rs @@ -20,6 +20,8 @@ mod sys_groups; mod sys_pidfdopen; mod sys_prctl; pub mod sys_prlimit64; +mod sys_prlimit64; +mod sys_ptrace; mod sys_set_tid_address; mod sys_setdomainname; mod sys_setfsgid; @@ -31,6 +33,7 @@ mod sys_setresgid; mod sys_setresuid; mod sys_setsid; mod sys_setuid; +mod sys_tkill; mod sys_uname; mod sys_unshare; mod sys_wait4; diff --git a/kernel/src/process/syscall/sys_ptrace.rs b/kernel/src/process/syscall/sys_ptrace.rs new file mode 100644 index 000000000..a08cfe2ac --- /dev/null +++ b/kernel/src/process/syscall/sys_ptrace.rs @@ -0,0 +1,300 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::ipc::signal::Signal; +use crate::arch::syscall::nr::{SYS_EXIT, SYS_PTRACE}; +use crate::process::syscall::sys_exit::SysExit; +use crate::process::{ + ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState, PtraceOptions, PtraceRequest, + RawPid, +}; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use alloc::sync::Arc; +use alloc::vec::Vec; +use system_error::SystemError; + +impl TryFrom for PtraceRequest { + type Error = SystemError; + + fn try_from(value: usize) -> Result { + match value { + 0 => Ok(PtraceRequest::PtraceTraceme), + 16 => Ok(PtraceRequest::PtraceAttach), + 17 => Ok(PtraceRequest::PtraceDetach), + 24 => Ok(PtraceRequest::PtraceSyscall), + 9 => Ok(PtraceRequest::PtraceSinglestep), + 7 => Ok(PtraceRequest::PtraceCont), + 12 => Ok(PtraceRequest::PtraceGetregs), + 13 => Ok(PtraceRequest::PtraceSetregs), + 2 => Ok(PtraceRequest::PtracePeekdata), + 5 => Ok(PtraceRequest::PtracePokedata), + 0x4202 => Ok(PtraceRequest::PtraceGetsiginfo), + 0x4200 => Ok(PtraceRequest::PtraceSetoptions), + _ => Err(SystemError::EINVAL), + } + } +} + +/// ptrace 系统调用实现 +pub struct SysPtrace; + +impl SysPtrace { + fn request(args: &[usize]) -> Result { + PtraceRequest::try_from(args[0]).map_err(|_| SystemError::EINVAL) + } + + fn pid(args: &[usize]) -> RawPid { + RawPid(args[1]) + } + + fn addr(args: &[usize]) -> usize { + args[2] + } + + fn data(args: &[usize]) -> usize { + args[3] + } + + /// 处理 PTRACE_TRACEME 请求(当前进程请求被跟踪) + fn handle_traceme(tracer: &Arc) -> Result { + tracer.traceme() + } + + /// 处理 PTRACE_ATTACH 请求(附加到目标进程) + fn handle_attach( + tracer: &Arc, + tracee_pid: RawPid, + ) -> Result { + let tracee = ProcessManager::find(tracee_pid).ok_or(SystemError::ESRCH)?; + tracee.attach(tracer) + } + + /// 处理 PTRACE_DETACH 请求(分离目标进程) + fn handle_detach( + tracee: &Arc, + signal: Option, + ) -> Result { + // 验证调用者是跟踪器 + if ProcessManager::current_pcb().raw_pid() != tracee.tracer().unwrap() { + return Err(SystemError::EPERM); + } + tracee.detach(signal) + } + + /// 处理 PTRACE_CONT 请求 + fn handle_cont( + tracee: &ProcessControlBlock, + signal: Option, + ) -> Result { + tracee.ptrace_cont(signal) + } + + /// 处理 PTRACE_SYSCALL 请求(在系统调用入口和出口暂停) + fn handle_syscall(tracee: &Arc) -> Result { + // 检查调用者是否是该进程的跟踪器 + if ProcessManager::current_pcb().raw_pid() != tracee.tracer().unwrap() { + // TODO + return Err(SystemError::ESRCH); + } + // 设置系统调用跟踪标志 + tracee.enable_syscall_tracing(); + tracee.trace_syscall() + } + + /// 处理 PTRACE_SETOPTIONS 请求(设置跟踪选项) + fn handle_set_options( + tracee: &Arc, + data: usize, + ) -> Result { + let options = PtraceOptions::from_bits_truncate(data); + // 设置跟踪选项 + tracee.set_ptrace_options(options)?; + + Ok(0) + } + + /// 处理 PTRACE_GETSIGINFO 请求(获取信号信息) + fn handle_get_siginfo(_tracee: &Arc) -> Result { + // 在实际实现中,你需要获取并返回信号信息 + // 这里仅返回占位值 + Ok(0) + } + + /// 处理 PTRACE_PEEKUSER 请求 + fn handle_peek_user( + tracee: &Arc, + addr: usize, + ) -> Result { + let value = tracee.peek_user(addr)?; + Ok(value as isize) + } + + /// 处理 PTRACE_PEEKDATA 请求(读取进程内存) + fn handle_peek_data( + tracee: &Arc, + addr: usize, + ) -> Result { + // // 检查地址是否在用户空间范围 + // if !tracee.memory.is_valid_user(addr) { + // return Err(SystemError::EFAULT); + // } + // // 安全读取内存 + // let value = tracee.memory.read(addr)?; + // Ok(value as isize) + todo!() + } + + /// 处理 PTRACE_SINGLESTEP 请求 (单步执行) + fn handle_single_step(tracee: &Arc) -> Result { + // 检查调用者是否是该进程的跟踪器 + if ProcessManager::current_pcb().raw_pid() != tracee.tracer().unwrap() { + // TODO + return Err(SystemError::ESRCH); + } + // 设置 EFLAGS 的 TF 标志 + tracee.enable_single_step(); + // 恢复进程运行 + let mut sched_info = tracee.sched_info.inner_lock_write_irqsave(); + if let ProcessState::Stopped(_signal) = sched_info.state() { + sched_info.set_state(ProcessState::Runnable); + } + Ok(0) + } + + /// 处理 PTRACE_GETREGS 请求 (获取寄存器值) + fn handle_get_regs(tracee: &Arc) -> Result { + // let tf = tracee.context().trap_frame.as_ref(); + Ok(0) // 实际应返回寄存器结构体 + } + + /// 处理 PTRACE_SETREGS 请求 (设置寄存器值) + fn handle_set_regs( + _tracee: &Arc, + _data: usize, + ) -> Result { + // 从用户空间复制寄存器结构体 + Ok(0) + } + + // 在系统调用处理之前 + fn before_handle_syscall(num: usize, args: &[usize]) { + let current = ProcessManager::current_pcb(); + // 检查进程是否被跟踪并且启用了系统调用跟踪 + if current + .flags() + .contains(ProcessFlags::PTRACED | ProcessFlags::TRACE_SYSCALL) + { + // 保存系统调用信息 + current.on_syscall_entry(num, args); + // 暂停进程等待跟踪器 + current.set_state(ProcessState::Stopped(1)); + // Scheduler::schedule(SchedMode::SM_NONE); // 切换到其他进程 + } + } + + // 在系统调用处理之后 + fn after_handle_syscall(num: usize, result: isize) { + let current = ProcessManager::current_pcb(); + // 检查进程是否被跟踪并且启用了系统调用跟踪 + if current + .flags() + .contains(ProcessFlags::PTRACED | ProcessFlags::TRACE_SYSCALL) + { + // 保存系统调用结果 + current.on_syscall_exit(result); + // 暂停进程等待跟踪器 + current.set_state(ProcessState::Stopped(1)); + // Scheduler::schedule(SchedMode::SM_NONE); // 切换到其他进程 + } + } + + // 在系统调用分发函数中 + fn dispatch_syscall( + num: usize, + args: &[usize], + frame: &mut TrapFrame, + ) -> Result { + Self::before_handle_syscall(num, args); + + // 执行实际的系统调用处理 + let result = match num { + SYS_EXIT => SysExit.handle(args, frame)?, + // ... 其他系统调用 ... + _ => Err(SystemError::ENOSYS)?, + }; + + Self::after_handle_syscall(num, result as isize); + Ok(result) + } +} + +impl Syscall for SysPtrace { + fn num_args(&self) -> usize { + 4 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + if args.len() < 4 { + return Err(SystemError::EINVAL); + } + + let request = Self::request(args)?; + let pid = Self::pid(args); + let addr = Self::addr(args); + let data = Self::data(args); + + let tracer = ProcessManager::current_pcb(); + if request == PtraceRequest::PtraceTraceme { + return Self::handle_traceme(&tracer).map(|r| r as usize); + } + let tracee: Arc = + ProcessManager::find(pid).ok_or(SystemError::ESRCH)?; + let signal: Option = if data == 0 { + None // 表示无信号 + } else { + Some(Signal::try_from(data as i32).map_err(|_| SystemError::EINVAL)?) + }; + + let result: isize = match request { + // 附加到目标进程 + PtraceRequest::PtraceAttach => Self::handle_attach(&tracer, pid)?, + // 分离目标进程 + PtraceRequest::PtraceDetach => Self::handle_detach(&tracee, signal)?, + // 继续执行目标进程 + PtraceRequest::PtraceCont => Self::handle_cont(&tracee, signal)?, + // 在系统调用入口和出口暂停 + PtraceRequest::PtraceSyscall => Self::handle_syscall(&tracee)?, + // 设置跟踪选项 + PtraceRequest::PtraceSetoptions => Self::handle_set_options(&tracee, data)?, + // 获取信号信息 + PtraceRequest::PtraceGetsiginfo => Self::handle_get_siginfo(&tracee)?, + // 读取用户寄存器 + PtraceRequest::PtracePeekuser => Self::handle_peek_user(&tracee, addr)?, + // 读取进程内存 + PtraceRequest::PtracePeekdata => Self::handle_peek_data(&tracee, addr)?, + PtraceRequest::PtraceSinglestep => todo!(), + // 其他请求类型 + _ => { + log::warn!("Unimplemented ptrace request: {:?}", request); + 0 + } + }; + + Ok(result as usize) + } + + fn entry_format(&self, args: &[usize]) -> Vec { + let request_name = match PtraceRequest::try_from(args[0]) { + Ok(req) => format!("{:?}", req), + Err(_) => format!("{:#x}", args[0]), + }; + + vec![ + FormattedSyscallParam::new("request", request_name), + FormattedSyscallParam::new("pid", format!("{}", args[1])), + FormattedSyscallParam::new("addr", format!("{:#x}", args[2])), + FormattedSyscallParam::new("data", format!("{:#x}", args[3])), + ] + } +} + +// 注册系统调用 +syscall_table_macros::declare_syscall!(SYS_PTRACE, SysPtrace); diff --git a/kernel/src/process/syscall/sys_tkill.rs b/kernel/src/process/syscall/sys_tkill.rs new file mode 100644 index 000000000..a4413bd29 --- /dev/null +++ b/kernel/src/process/syscall/sys_tkill.rs @@ -0,0 +1,50 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::ipc::signal::Signal; +use crate::arch::syscall::nr::SYS_TKILL; +use crate::process::ProcessManager; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use alloc::vec::Vec; +use system_error::SystemError; + +pub struct SysTkill; + +impl SysTkill { + fn thread_id(args: &[usize]) -> usize { + args[0] + } + + fn signal(args: &[usize]) -> usize { + args[1] as usize + } +} + +impl Syscall for SysTkill { + fn num_args(&self) -> usize { + 2 + } + + fn handle(&self, args: &[usize], _tf: &mut TrapFrame) -> Result { + let tid = Self::thread_id(args); + let sig = Self::signal(args); + // 当前只支持向当前进程的线程发送信号 + let current = ProcessManager::current_pcb(); + // 检查线程ID是否有效(目前简化处理) + if tid != 0 && tid != current.raw_pid().data() { + return Err(SystemError::ESRCH); + } + if sig > Signal::SIGRTMAX as usize { + return Err(SystemError::EINVAL); + } + // current.stop_process(sig.into()); + Ok(0) + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("tid", format!("{}", Self::thread_id(args))), + FormattedSyscallParam::new("sig", format!("{}", Self::signal(args))), + ] + } +} + +syscall_table_macros::declare_syscall!(SYS_TKILL, SysTkill); diff --git a/kernel/src/process/timer.rs b/kernel/src/process/timer.rs index f6e186e58..6d4260994 100644 --- a/kernel/src/process/timer.rs +++ b/kernel/src/process/timer.rs @@ -1,3 +1,4 @@ +use crate::arch::ipc::signal::{OriginCode, SigCode, Signal}; use crate::exception::InterruptArch; use crate::ipc::signal_types::SigType; use crate::process::CurrentIrqArch; @@ -130,7 +131,7 @@ impl TimerFunction for AlarmTimerFunc { fn run(&mut self) -> Result<(), SystemError> { let sig = Signal::SIGALRM; // 初始化signal info - let mut info = SigInfo::new(sig, 0, SigCode::Timer, SigType::Alarm(self.pid)); + let mut info = SigInfo::new(sig, 0, SigCode::Origin(OriginCode::Timer), SigType::Alarm(self.pid)); compiler_fence(core::sync::atomic::Ordering::SeqCst); let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; diff --git a/user/apps/c_unitest/test-ptrace.c b/user/apps/c_unitest/test-ptrace.c new file mode 100644 index 000000000..11e8efebf --- /dev/null +++ b/user/apps/c_unitest/test-ptrace.c @@ -0,0 +1,264 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 根据CPU架构定义系统调用号位置 +#if defined(__x86_64__) || defined(_M_X64) +#define ORIG_RAX 15 // ORIG_RAX在user_regs_struct中的偏移 + +#elif defined(__aarch64__) || defined(_M_ARM64) +#define ORIG_RAX 8 // ARM64上系统调用号在regs[8] + +#elif defined(__riscv) || defined(__riscv__) +#define ORIG_RAX 0 // RISC-V上系统调用号在a7寄存器 + +#else +#error "Unsupported architecture for PTRACE_SYSCALL test" +#endif + +#define CHK_SYSCALL(call) \ + do { \ + if ((call) == -1) { \ + fprintf(stderr, "Error at %s:%d: %s failed: %s\n", __FILE__, __LINE__, #call, strerror(errno)); \ + exit(EXIT_FAILURE); \ + } \ + } while (0) + +static void sigcont_handler(int signum) { + printf("target received SIGCONT\n"); + exit(EXIT_SUCCESS); +} + +// 测试 PTRACE_TRACEME 功能 +void test_trace_me() { + printf("=== Testing PTRACE_TRACEME ===\n"); + pid_t child = fork(); + if (child == 0) { + // 子进程请求被跟踪 + CHK_SYSCALL(ptrace(PTRACE_TRACEME, 0, NULL, NULL)); + // 强制产生一个信号/系统调用事件 + printf("Child ready for tracing\n"); + getpid(); + raise(SIGSTOP); + // 正常退出 + exit(EXIT_SUCCESS); + } else { + // 等待子进程停止 + int status; + CHK_SYSCALL(waitpid(child, &status, 0)); + if (WIFSTOPPED(status)) { + int sig = WSTOPSIG(status); + printf("Child stopped by signal %d (%s)\n", sig, strsignal(sig)); + // // 获取停止原因 + // long request = ptrace(PTRACE_PEEKUSER, child, (void*)ORIG_RAX, NULL); + // printf("System call: %ld\n", request); + // 恢复子进程执行 + CHK_SYSCALL(ptrace(PTRACE_CONT, child, NULL, NULL)); + // 等待子进程退出 + CHK_SYSCALL(waitpid(child, &status, 0)); + + if (WIFEXITED(status)) { + printf("Child exited with status %d\n", WEXITSTATUS(status)); + } else { + printf("Child did not exit normally (status=%d)\n", status); + } + } else if (WIFEXITED(status)) { + printf("Child exited without stopping (status=%d)\n", WEXITSTATUS(status)); + } else { + printf("Child did not stop as expected (status=%d)\n", status); + } + } +} + +// 测试 PTRACE_ATTACH/DETACH 功能x +void test_attach_detach() { + printf("=== Testing PTRACE_ATTACH/DETACH ===\n"); + pid_t target = fork(); + if (target == 0) { + // 目标进程暂停自己 + printf("target process %d waiting...\n", getpid()); + // 确保分离后有信号处理 + if (signal(SIGCONT, sigcont_handler) == SIG_ERR) { + perror("Error setting SIGCONT handler"); + exit(EXIT_FAILURE); + } + sleep(10); + // pause(); // 等待信号 + // 永远不会到达这里 + printf("target process resumed\n"); + exit(EXIT_SUCCESS); + } else { + // 给目标进程时间进入pause状态 + sleep(1); + printf("Tracer attaching to target %d\n", target); + // 父进程附加到目标进程 + CHK_SYSCALL(ptrace(PTRACE_ATTACH, target, NULL, NULL)); + // 等待目标进程停止 + int status; + CHK_SYSCALL(waitpid(target, &status, 0)); + + if (WIFSTOPPED(status)) { + int sig = WSTOPSIG(status); + printf("target stopped by signal %d (%s)\n", sig, strsignal(sig)); + // 分离目标进程并发送SIGCONT唤醒它 + printf("Tracer detaching from target\n"); + CHK_SYSCALL(ptrace(PTRACE_DETACH, target, NULL, (void*)(long)SIGCONT)); + // 等待目标进程退出 + CHK_SYSCALL(waitpid(target, &status, 0)); + if (WIFEXITED(status)) { + printf("target exited with status %d\n", WEXITSTATUS(status)); + } else { + printf("target did not exit normally (status=%d)\n", status); + } + } else { + printf("target did not stop as expected (status=%d)\n", status); + } + } +} + +// 测试 PTRACE_SYSCALL 功能 +void test_syscall_tracing() { + printf("=== Testing PTRACE_SYSCALL ===\n"); + pid_t child = fork(); + if (child == 0) { + // 子进程请求被跟踪 + CHK_SYSCALL(ptrace(PTRACE_TRACEME, 0, NULL, NULL)); + // 触发系统调用 + raise(SIGSTOP); + printf("Child calling getpid()\n"); + getpid(); + exit(EXIT_SUCCESS); + } else { + // 等待子进程第一次停止 + int status; + CHK_SYSCALL(waitpid(child, &status, 0)); + + if (!WIFSTOPPED(status)) { + printf("Child did not stop as expected (status=%d)\n", status); + return; + } + printf("Child initial stop by signal %d\n", WSTOPSIG(status)); + // 启用系统调用跟踪 + CHK_SYSCALL(ptrace(PTRACE_SYSCALL, child, NULL, NULL)); + // 等待系统调用入口事件 + CHK_SYSCALL(waitpid(child, &status, 0)); + + if (WIFSTOPPED(status)) { + printf("Syscall entry detected\n"); + // 继续执行 + CHK_SYSCALL(ptrace(PTRACE_SYSCALL, child, NULL, NULL)); + // 等待系统调用出口事件 + CHK_SYSCALL(waitpid(child, &status, 0)); + if (WIFSTOPPED(status)) { + printf("Syscall exit detected\n"); + } + } + + // 恢复子进程执行 + CHK_SYSCALL(ptrace(PTRACE_CONT, child, NULL, NULL)); + // 等待子进程退出 + CHK_SYSCALL(waitpid(child, &status, 0)); + if (WIFEXITED(status)) { + printf("Child exited normally\n"); + } + } +} + +// 测试内存读取功能 +void test_peek_data() { + printf("=== Testing PTRACE_PEEKDATA ===\n"); + pid_t child = fork(); + if (child == 0) { + const char* message = "PTRACE_PEEKDATA_testing"; + long* heap_data = (long*)malloc(sizeof(long)); + *heap_data = 0x66CCFF; + // 直接写入共享内存结构 + struct { + const char* msg; + long* heap; + } addr_info = {message, heap_data}; + asm volatile("mov %0, %%r14" : : "r"(&addr_info)); + printf("Child: msg_addr=%p, heap_addr=%p, heap_val=%#lx\n", addr_info.msg, addr_info.heap, *addr_info.heap); + CHK_SYSCALL(ptrace(PTRACE_TRACEME, 0, NULL, NULL)); + raise(SIGSTOP); // 父进程检查点 + pause(); + exit(EXIT_SUCCESS); // 不会执行 + + } else { + int status; + struct user_regs_struct regs; + CHK_SYSCALL(waitpid(child, &status, 0)); + if (WIFSTOPPED(status)) { + CHK_SYSCALL(ptrace(PTRACE_GETREGS, child, NULL, ®s)); + uintptr_t addr_info_addr = regs.r14; + struct { + const char* msg; + long* heap; + } addr_info; + for (size_t i = 0; i < sizeof(addr_info) / sizeof(long); ++i) { + long* dest = ((long*)&addr_info) + i; + *dest = ptrace(PTRACE_PEEKDATA, child, (void*)(addr_info_addr + i * sizeof(long)), 0); + } + uintptr_t msg_addr = (uintptr_t)addr_info.msg; + uintptr_t heap_addr = (uintptr_t)addr_info.heap; + printf("Parent: msg_addr=%#lx, heap_addr=%#lx\n", msg_addr, heap_addr); + printf("Read message: "); + int bytes_printed = 0; + for (const char* p = (const char*)msg_addr;; p++) { + long data = ptrace(PTRACE_PEEKDATA, child, p, 0); + if (data == -1) { + perror("Error reading char"); + break; + } + char c = (char)(data & 0xFF); + if (c == '\0') { + break; + } + if (++bytes_printed > 128) { + printf("... (truncated)"); + break; + } + if (c >= ' ' && c <= '~') { // 可打印字符 + putchar(c); + } else if (c == '\n') { // 特殊字符转义 + fputs("\\n", stdout); + } else if (c == '\t') { + fputs("\\t", stdout); + } else { // 不可打印字符 + printf("\\x%02x", (unsigned char)c); + } + } + printf("\n"); + + // 读取并修改堆内存 + long heap_value = ptrace(PTRACE_PEEKDATA, child, (void*)heap_addr, 0); + printf("Original heap value: %#lx\n", heap_value); + ptrace(PTRACE_POKEDATA, child, (void*)heap_addr, (void*)0xEE0000); + long new_value = ptrace(PTRACE_PEEKDATA, child, (void*)heap_addr, 0); + printf("Modified heap value: %#lx\n", new_value); + } + // 结束子进程 + kill(child, SIGKILL); + waitpid(child, &status, 0); + } +} + +int main() { + printf("===== Starting ptrace tests =====\n\n"); + + test_trace_me(); + test_attach_detach(); + test_syscall_tracing(); + test_peek_data(); + + printf("\n===== All ptrace tests completed =====\n"); + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/user/apps/strace/.gitignore b/user/apps/strace/.gitignore new file mode 100644 index 000000000..9d89263c5 --- /dev/null +++ b/user/apps/strace/.gitignore @@ -0,0 +1 @@ +strace diff --git a/user/apps/strace/Makefile b/user/apps/strace/Makefile new file mode 100644 index 000000000..168b35d0a --- /dev/null +++ b/user/apps/strace/Makefile @@ -0,0 +1,20 @@ +ifeq ($(ARCH), x86_64) + CROSS_COMPILE=x86_64-linux-musl- +else ifeq ($(ARCH), riscv64) + CROSS_COMPILE=riscv64-linux-musl- +endif + +CC=$(CROSS_COMPILE)g++ + +.PHONY: all +all: main.cpp + $(CC) -static -o strace main.cpp + +.PHONY: install clean +install: all + mv strace $(DADK_CURRENT_BUILD_DIR)/strace + +clean: + rm strace *.o + +fmt: diff --git a/user/apps/strace/main.cpp b/user/apps/strace/main.cpp new file mode 100644 index 000000000..29c6eeb9a --- /dev/null +++ b/user/apps/strace/main.cpp @@ -0,0 +1,106 @@ +#include "strace_format.h" + +#include +#include +#include +#include + +using namespace std; + +// 追踪子进程 +int trace_child(pid_t child_pid) { + int status; + bool first_stop = true; + int last_syscall = -1; + + while (true) { + // 等待子进程状态变化 + if (waitpid(child_pid, &status, 0) == -1) { + cerr << "waitpid error: " << strerror(errno) << '\n'; + return 1; + } + // 检查子进程是否退出 + if (WIFEXITED(status)) { + cout << "\n+++ exited with " << WEXITSTATUS(status) << " +++" << '\n'; + return 0; + } + // 检查是否收到信号 + if (WIFSIGNALED(status)) { + cout << "\n+++ killed by " << strsignal(WTERMSIG(status)) << " +++" << '\n'; + return 0; + } + // 首次跟踪需要忽略SIGTRAP + if (first_stop && WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) { + first_stop = false; + ptrace(PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACESYSGOOD); + if (ptrace(PTRACE_SYSCALL, child_pid, 0, 0) == -1) { + cerr << "ptrace(SYSCALL) failed: " << strerror(errno) << '\n'; + return 1; + } + continue; + } + + // 处理系统调用入口事件 + if (WIFSTOPPED(status) && WSTOPSIG(status) == (SIGTRAP | 0x80)) { + user_regs_struct regs; + if (ptrace(PTRACE_GETREGS, child_pid, 0, ®s) == -1) { + cerr << "ptrace(GETREGS) failed: " << strerror(errno) << '\n'; + return 1; + } + if (last_syscall == -1) { + // 获取系统调用号 + int syscall_num = static_cast(SYSCALL_REG(regs)); + last_syscall = syscall_num; + cout << format_arguments( + child_pid, syscall_num, ARG1(regs), ARG2(regs), ARG3(regs), ARG4(regs), ARG5(regs), ARG6(regs)); + } else { + long return_value = RETURN_REG(regs); + cout << format_return_value(return_value) << '\n'; + last_syscall = -1; + } + // 继续执行等待系统调用完成 + if (ptrace(PTRACE_SYSCALL, child_pid, 0, 0) == -1) { + cerr << "ptrace(SYSCALL) failed: " << strerror(errno) << '\n'; + return 1; + } + } else if (WIFSTOPPED(status)) { // 处理其他事件 + // 继续执行子进程 + if (ptrace(PTRACE_SYSCALL, child_pid, 0, WSTOPSIG(status)) == -1) { + cerr << "ptrace(SYSCALL) failed: " << strerror(errno) << '\n'; + return 1; + } + } + } + return 0; +} + +int main(int argc, char* argv[]) { + if (argc < 2) { + cerr << "Usage: " << argv[0] << " must have PROG [ARGS] or -p PID" << '\n'; + return 1; + } + + pid_t pid = fork(); + if (pid == -1) { + cerr << "fork failed: " << strerror(errno) << '\n'; + return 1; + } + // 子进程执行目标程序 + if (pid == 0) { + // 启用跟踪 + ptrace(PTRACE_TRACEME, 0, 0, 0); + // 设置execve参数 + vector args; + for (int i = 1; i < argc; ++i) { + args.push_back(argv[i]); + } + args.push_back(nullptr); + // 执行目标程序 + execvp(args[0], args.data()); + // 若exec失败 + cerr << "execvp failed: " << strerror(errno) << '\n'; + return 1; + } else { // 父进程执行跟踪 + return trace_child(pid); + } +} \ No newline at end of file diff --git a/user/apps/strace/strace_format.h b/user/apps/strace/strace_format.h new file mode 100644 index 000000000..025c776fa --- /dev/null +++ b/user/apps/strace/strace_format.h @@ -0,0 +1,504 @@ +#ifndef _STRACE_FORMAT_H_ +#define _STRACE_FORMAT_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 根据不同架构定义寄存器访问宏 +#if defined(__x86_64__) +#define SYSCALL_REG(regs) (regs.orig_rax) +#define RETURN_REG(regs) (regs.rax) +#define ARG1(regs) (regs.rdi) +#define ARG2(regs) (regs.rsi) +#define ARG3(regs) (regs.rdx) +#define ARG4(regs) (regs.r10) +#define ARG5(regs) (regs.r8) +#define ARG6(regs) (regs.r9) +#elif defined(__i386__) +#define SYSCALL_REG(regs) (regs.orig_eax) +#define RETURN_REG(regs) (regs.eax) +#define ARG1(regs) (regs.ebx) +#define ARG2(regs) (regs.ecx) +#define ARG3(regs) (regs.edx) +#define ARG4(regs) (regs.esi) +#define ARG5(regs) (regs.edi) +#define ARG6(regs) (regs.ebp) +#elif defined(__aarch64__) +#define SYSCALL_REG(regs) (regs.regs[8]) +#define RETURN_REG(regs) (regs.regs[0]) +#define ARG1(regs) (regs.regs[0]) +#define ARG2(regs) (regs.regs[1]) +#define ARG3(regs) (regs.regs[2]) +#define ARG4(regs) (regs.regs[3]) +#define ARG5(regs) (regs.regs[4]) +#define ARG6(regs) (regs.regs[5]) +#else +#error "Unsupported architecture" +#endif + +// 错误码映射 +const std::unordered_map error_names = { + {EPERM, "EPERM"}, {ENOENT, "ENOENT"}, {ESRCH, "ESRCH"}, {EINTR, "EINTR"}, {EIO, "EIO"}, + {ENXIO, "ENXIO"}, {E2BIG, "E2BIG"}, {ENOEXEC, "ENOEXEC"}, {EBADF, "EBADF"}, {ECHILD, "ECHILD"}, + {EAGAIN, "EAGAIN"}, {ENOMEM, "ENOMEM"}, {EACCES, "EACCES"}, {EFAULT, "EFAULT"}, {ENOTBLK, "ENOTBLK"}, + {EBUSY, "EBUSY"}, {EEXIST, "EEXIST"}, {EXDEV, "EXDEV"}, {ENODEV, "ENODEV"}, {ENOTDIR, "ENOTDIR"}, + {EISDIR, "EISDIR"}, {EINVAL, "EINVAL"}, {ENFILE, "ENFILE"}, {EMFILE, "EMFILE"}, {ENOTTY, "ENOTTY"}, + {ETXTBSY, "ETXTBSY"}, {EFBIG, "EFBIG"}, {ENOSPC, "ENOSPC"}, {ESPIPE, "ESPIPE"}, {EROFS, "EROFS"}, + {EMLINK, "EMLINK"}, {EPIPE, "EPIPE"}, {EDOM, "EDOM"}, {ERANGE, "ERANGE"}, +}; + +// 系统调用名称映射 +const std::unordered_map syscall_names = { + {SYS_read, "read"}, + {SYS_write, "write"}, + {SYS_open, "open"}, + {SYS_close, "close"}, + {SYS_stat, "stat"}, + {SYS_fstat, "fstat"}, + {SYS_lstat, "lstat"}, + {SYS_poll, "poll"}, + {SYS_lseek, "lseek"}, + {SYS_mmap, "mmap"}, + {SYS_mprotect, "mprotect"}, + {SYS_munmap, "munmap"}, + {SYS_brk, "brk"}, + {SYS_rt_sigaction, "rt_sigaction"}, + {SYS_ioctl, "ioctl"}, + {SYS_access, "access"}, + {SYS_pipe, "pipe"}, + {SYS_select, "select"}, + {SYS_dup, "dup"}, + {SYS_dup2, "dup2"}, + {SYS_getpid, "getpid"}, + {SYS_socket, "socket"}, + {SYS_connect, "connect"}, + {SYS_bind, "bind"}, + {SYS_listen, "listen"}, + {SYS_accept, "accept"}, + {SYS_execve, "execve"}, + {SYS_exit, "exit"}, + {SYS_wait4, "wait4"}, + {SYS_kill, "kill"}, + {SYS_uname, "uname"}, + {SYS_fcntl, "fcntl"}, + {SYS_fsync, "fsync"}, + {SYS_truncate, "truncate"}, + {SYS_getcwd, "getcwd"}, + {SYS_chdir, "chdir"}, + {SYS_rename, "rename"}, + {SYS_mkdir, "mkdir"}, + {SYS_rmdir, "rmdir"}, + {SYS_creat, "creat"}, + {SYS_link, "link"}, + {SYS_unlink, "unlink"}, + {SYS_readlink, "readlink"}, + {SYS_chmod, "chmod"}, + {SYS_gettimeofday, "gettimeofday"}, + {SYS_getrusage, "getrusage"}, + {SYS_sysinfo, "sysinfo"}, + {SYS_getuid, "getuid"}, + {SYS_getgid, "getgid"}, + {SYS_setuid, "setuid"}, + {SYS_setgid, "setgid"}, + {SYS_geteuid, "geteuid"}, + {SYS_getegid, "getegid"}, + {SYS_setpgid, "setpgid"}, + {SYS_getppid, "getppid"}, + {SYS_arch_prctl, "arch_prctl"}, + {SYS_exit_group, "exit_group"}, + {SYS_openat, "openat"}, + {SYS_newfstatat, "newfstatat"}, + {SYS_unshare, "unshare"}, + {SYS_getrandom, "getrandom"}, +}; + +const std::unordered_map fcntl_flags = { + {FD_CLOEXEC, "FD_CLOEXEC"}, {O_RDONLY, "O_RDONLY"}, {O_WRONLY, "O_WRONLY"}, {O_RDWR, "O_RDWR"}, + {O_CREAT, "O_CREAT"}, {O_EXCL, "O_EXCL"}, {O_NOCTTY, "O_NOCTTY"}, {O_TRUNC, "O_TRUNC"}, + {O_APPEND, "O_APPEND"}, {O_NONBLOCK, "O_NONBLOCK"}, {O_DSYNC, "O_DSYNC"}, {O_ASYNC, "O_ASYNC"}, + {O_DIRECT, "O_DIRECT"}, {O_LARGEFILE, "O_LARGEFILE"}, {O_DIRECTORY, "O_DIRECTORY"}, {O_NOFOLLOW, "O_NOFOLLOW"}, + {O_NOATIME, "O_NOATIME"}, {O_CLOEXEC, "O_CLOEXEC"}, {O_SYNC, "O_SYNC"}, {O_PATH, "O_PATH"}, + {O_TMPFILE, "O_TMPFILE"}, +}; +const std::unordered_map at_flags = { + {AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW"}, + {AT_REMOVEDIR, "AT_REMOVEDIR"}, + {AT_SYMLINK_FOLLOW, "AT_SYMLINK_FOLLOW"}, + {AT_NO_AUTOMOUNT, "AT_NO_AUTOMOUNT"}, + {AT_EMPTY_PATH, "AT_EMPTY_PATH"}, + {AT_STATX_SYNC_TYPE, "AT_STATX_SYNC_TYPE"}, + {AT_STATX_FORCE_SYNC, "AT_STATX_FORCE_SYNC"}, + {AT_STATX_DONT_SYNC, "AT_STATX_DONT_SYNC"}, + {AT_RECURSIVE, "AT_RECURSIVE"}, +}; +const std::unordered_map open_flags = { + {O_RDONLY, "O_RDONLY"}, + {O_WRONLY, "O_WRONLY"}, + {O_RDWR, "O_RDWR"}, + {O_CREAT, "O_CREAT"}, + {O_EXCL, "O_EXCL"}, + {O_TRUNC, "O_TRUNC"}, + {O_APPEND, "O_APPEND"}, + {O_NONBLOCK, "O_NONBLOCK"}, + {O_DIRECTORY, "O_DIRECTORY"}, + {O_NOFOLLOW, "O_NOFOLLOW"}, + {O_CLOEXEC, "O_CLOEXEC"}, + {AT_FDCWD, "AT_FDCWD"}, + {AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW"}, +}; +const std::unordered_map mmap_flags = { + {MAP_SHARED, "MAP_SHARED"}, + {MAP_PRIVATE, "MAP_PRIVATE"}, + {MAP_FIXED, "MAP_FIXED"}, + {MAP_ANONYMOUS, "MAP_ANONYMOUS"}, + {MAP_GROWSDOWN, "MAP_GROWSDOWN"}, + {MAP_DENYWRITE, "MAP_DENYWRITE"}, + {MAP_EXECUTABLE, "MAP_EXECUTABLE"}, + {MAP_LOCKED, "MAP_LOCKED"}, + {MAP_NORESERVE, "MAP_NORESERVE"}, + {MAP_POPULATE, "MAP_POPULATE"}, + {MAP_NONBLOCK, "MAP_NONBLOCK"}, + {MAP_STACK, "MAP_STACK"}, + {MAP_HUGETLB, "MAP_HUGETLB"}, +}; +const std::unordered_map grnd_flags = { + {GRND_NONBLOCK, "GRND_NONBLOCK"}, + {GRND_RANDOM, "GRND_RANDOM"}, +}; + +// 长整型转十六进制字符串 +std::string to_hex_string(unsigned long value) { + std::ostringstream oss; + oss << "0x" << std::hex << value; + return oss.str(); +} +// 从子进程读取字符串 +std::string read_child_string(pid_t pid, unsigned long addr) { + if (addr == 0) + return "NULL"; + std::string str; + long ret; + unsigned long tmp = 0; + + while (true) { + // 使用PTRACE_PEEKDATA读取内存 + errno = 0; + ret = ptrace(PTRACE_PEEKDATA, pid, addr + tmp, nullptr); + if (ret == -1 && errno != 0) { + return ""; + } + + // 逐字节读取,直到遇到空字符 + for (int i = 0; i < sizeof(long); ++i) { + char ch = static_cast((ret >> (i * 8)) & 0xFF); + if (ch == '\0') { + return str; + } + str += ch; + } + tmp += sizeof(long); + } +} +std::string read_child_buffer(pid_t pid, unsigned long addr, size_t len) { + if (addr == 0 || len == 0) + return ""; + + std::string buffer; + long ret; + unsigned long tmp = 0; + const size_t max_length = 256; // 最大读取长度 + + len = std::min(len, max_length); + + for (size_t i = 0; i < len; i += sizeof(long)) { + // 使用PTRACE_PEEKDATA读取内存 + errno = 0; + ret = ptrace(PTRACE_PEEKDATA, pid, addr + tmp, nullptr); + if (ret == -1 && errno != 0) { + return ""; + } + + // 逐字节读取 + for (int j = 0; j < sizeof(long) && (i + j) < len; ++j) { + char ch = static_cast((ret >> (j * 8)) & 0xFF); + buffer += ch; + } + tmp += sizeof(long); + } + return buffer; +} +std::string format_printable_string(const std::string& str) { + std::ostringstream oss; + oss << "\""; + for (char c : str) { + if (c == '\n') + oss << "\\n"; + else if (c == '\t') + oss << "\\t"; + else if (c == '\r') + oss << "\\r"; + else if (c == '\"') + oss << "\\\""; + else if (c == '\\') + oss << "\\\\"; + else if (std::isprint(static_cast(c))) + oss << c; + else + oss << "\\x" << std::hex << std::setw(2) << std::setfill('0') + << static_cast(static_cast(c)); + } + oss << "\""; + return oss.str(); +} +// 从子进程读取字符串数组 +std::vector read_child_string_array(pid_t pid, unsigned long addr) { + std::vector result; + if (addr == 0) + return result; + + unsigned long ptr; + unsigned long tmp = 0; + + while (true) { + // 读取指针值 + errno = 0; + long ret = ptrace(PTRACE_PEEKDATA, pid, addr + tmp, nullptr); + if (ret == -1 && errno != 0) { + break; + } + + ptr = static_cast(ret); + tmp += sizeof(long); + + if (ptr == 0) { + break; // NULL结尾 + } + + result.push_back(read_child_string(pid, ptr)); + } + + return result; +} +// 解析标志位 +std::string parse_flags(const std::unordered_map& flag_map, long flags) { + if (flags == 0) + return "0"; + std::vector flag_list; + for (const auto& flag : flag_map) { + if (flags & flag.first) { + flag_list.push_back(flag.second); + } + } + if (flag_list.empty()) { + return "0x" + to_hex_string(flags); + } + std::ostringstream oss; + for (size_t i = 0; i < flag_list.size(); ++i) { + if (i > 0) + oss << "|"; + oss << flag_list[i]; + } + return oss.str(); +} + +// 格式化参数列表 +std::string +format_arguments(pid_t child_pid, int sys_num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { + // 获取系统调用名称 + std::string syscall_name = "syscall_"; + if (syscall_names.find(sys_num) != syscall_names.end()) { + syscall_name = syscall_names.at(sys_num); + } else { + syscall_name += std::to_string(sys_num); + } + + std::ostringstream oss; + if (sys_num == SYS_execve) { + // 处理execve的特殊格式 + std::string path = read_child_string(child_pid, arg1); + std::vector argv = read_child_string_array(child_pid, arg2); + std::vector envp = read_child_string_array(child_pid, arg3); + + oss << syscall_name << "(\"" << path << "\", ["; + // 格式化argv + for (size_t i = 0; i < argv.size(); ++i) { + if (i > 0) + oss << ", "; + oss << "\"" << argv[i] << "\""; + } + oss << "], "; + // 格式化envp + if (envp.empty()) { + oss << "0x" << std::hex << arg3 << " /* 0 vars */)"; + } else { + oss << "0x" << std::hex << arg3 << " /* " << std::dec << envp.size() << " vars */"; + } + return oss.str(); + } else if (sys_num == SYS_brk) { + oss << syscall_name << "("; + if (arg1 == 0) { + oss << "NULL"; + } else { + oss << to_hex_string(arg1); + } + oss << ")"; + return oss.str(); + } else if (sys_num == SYS_open || sys_num == SYS_openat) { + oss << syscall_name << "("; + if (sys_num == SYS_openat) { + oss << "AT_FDCWD, "; + } + // 读取路径 + oss << "\"" << read_child_string(child_pid, (sys_num == SYS_openat) ? arg2 : arg1) << "\", "; + // 解析标志位 + long flags = (sys_num == SYS_openat) ? arg3 : arg2; + oss << parse_flags(open_flags, flags); + // 文件权限 + if (arg4 != 0) + oss << ", 0" << std::oct << arg4; + return oss.str(); + } else if (sys_num == SYS_write) { + oss << syscall_name << "(" << arg1 << ", "; + std::string buffer = read_child_buffer(child_pid, arg2, arg3); + oss << format_printable_string(buffer) << ", " << arg3 << ")"; + return oss.str(); + } else if (sys_num == SYS_read) { + oss << syscall_name << "(" << arg1 << ", "; + std::string buffer = read_child_buffer(child_pid, arg2, arg3); + oss << format_printable_string(buffer) << ", " << arg3 << ")"; + return oss.str(); + } else if (sys_num == SYS_dup || sys_num == SYS_dup2 || sys_num == SYS_dup3) { + oss << syscall_name << "(" << arg1; + if (sys_num == SYS_dup2 || sys_num == SYS_dup3) + oss << ", " << arg2; + if (sys_num == SYS_dup3) + oss << ", " << parse_flags(fcntl_flags, arg3); + oss << ")"; + return oss.str(); + } else if (sys_num == SYS_newfstatat) { + oss << syscall_name << "("; + // 文件描述符 + if (arg1 == AT_FDCWD) { + oss << "AT_FDCWD"; + } else { + oss << arg1; + } + oss << ", \"" << read_child_string(child_pid, arg2) << "\""; + // stat结构体指针 + oss << ", " << to_hex_string(arg3); + oss << ", " << parse_flags(at_flags, arg4); + oss << ")"; + return oss.str(); + } else if (sys_num == SYS_mmap) { + oss << syscall_name << "(" << to_hex_string(arg1) << ", " << std::dec << arg2 << ", " + << parse_flags(mmap_flags, arg3) << ", " << parse_flags(mmap_flags, arg4) << ", " << arg5 << ", " + << to_hex_string(arg6) << ")"; + return oss.str(); + } else if (sys_num == SYS_arch_prctl) { + oss << syscall_name << "(" << to_hex_string(arg1) << ", " << to_hex_string(arg2) << ")"; + return oss.str(); + } else if (sys_num == SYS_fcntl) { + std::ostringstream oss; + oss << syscall_name << "(" << arg1 << ", "; + if (fcntl_flags.count(static_cast(arg2))) { + oss << fcntl_flags.at(static_cast(arg2)); + } else { + oss << to_hex_string(arg2); + } + // 如果有第三个参数 + if (arg3 != 0) { + oss << ", "; + switch (static_cast(arg2)) { + case F_SETFL: + case F_GETFL: + oss << parse_flags(fcntl_flags, arg3); + break; + default: + oss << to_hex_string(arg3); + } + } + + oss << ")"; + return oss.str(); + } else if (sys_num == SYS_uname) { + // const size_t utsname_size = sizeof(struct utsname); + // const size_t words = (utsname_size + sizeof(long) - 1) / sizeof(long); + // // 分配缓冲区 + // char* buf = new char[words * sizeof(long)](); + // unsigned long addr = arg1; + // // 逐字读取子进程内存 + // for (size_t i = 0; i < words; ++i) { + // errno = 0; + // long ret = ptrace(PTRACE_PEEKDATA, child_pid, addr + i * sizeof(long), nullptr); + // if (ret == -1 && errno != 0) { + // delete[] buf; + // return syscall_name + "(" + to_hex_string(arg1) + ")"; + // } + // memcpy(buf + i * sizeof(long), &ret, sizeof(long)); + // } + // struct utsname* uname_buf = reinterpret_cast(buf); + struct utsname parent_uname; + uname(&parent_uname); + oss << syscall_name << "({"; + oss << "sysname=\"" << parent_uname.sysname << "\", "; + oss << "nodename=\"" << parent_uname.nodename << "\", "; + oss << "release=\"" << parent_uname.release << "\", "; + oss << "version=\"" << parent_uname.version << "\", "; + oss << "machine=\"" << parent_uname.machine << "\""; + oss << "})"; + // delete[] buf; + return oss.str(); + } else if (sys_num == SYS_getrandom) { + oss << syscall_name << "(" << to_hex_string(arg1) << ", " << arg2 << ", " << parse_flags(grnd_flags, arg3) + << ")"; + return oss.str(); + } else if (sys_num == SYS_access) { + return syscall_name + "(\"" + read_child_string(child_pid, arg1) + "\", " + to_hex_string(arg2) + ")"; + } else if (sys_num == SYS_exit || sys_num == SYS_exit_group || sys_num == SYS_close) { + return syscall_name + "(" + std::to_string(arg1) + ")"; + } else { + // 其他系统调用通用处理 + oss << syscall_name << "(" << to_hex_string(arg1); + if (arg2 != 0) + oss << ", " << to_hex_string(arg2); + if (arg3 != 0) + oss << ", " << to_hex_string(arg3); + if (arg4 != 0) + oss << ", " << to_hex_string(arg4); + if (arg5 != 0) + oss << ", " << to_hex_string(arg5); + if (arg6 != 0) + oss << ", " << to_hex_string(arg6); + oss << ")"; + return oss.str(); + } +} +// 格式化返回值 +std::string format_return_value(long ret_val) { + if (ret_val < 0) { + int err = static_cast(-ret_val); + if (error_names.find(err) != error_names.end()) { + return " = -1 " + error_names.at(err) + " (" + strerror(err) + ")"; + } else { + return " = -1 (unknown error)"; + } + } + + return " = " + to_hex_string(ret_val); +} + +#endif // _STRACE_FORMAT_H_ \ No newline at end of file diff --git a/user/dadk/config/strace-0.1.0.toml b/user/dadk/config/strace-0.1.0.toml new file mode 100644 index 000000000..adaf03cdd --- /dev/null +++ b/user/dadk/config/strace-0.1.0.toml @@ -0,0 +1,40 @@ +# 用户程序名称 +name = "strace" +# 版本号 +version = "0.1.0" +# 用户程序描述信息 +description = "一个简单的strace" +# (可选)默认: false 是否只构建一次,如果为true,DADK会在构建成功后,将构建结果缓存起来,下次构建时,直接使用缓存的构建结果 +build-once = false +# (可选) 默认: false 是否只安装一次,如果为true,DADK会在安装成功后,不再重复安装 +install-once = false +# 目标架构 +# 可选值:"x86_64", "aarch64", "riscv64" +target-arch = ["x86_64"] +# 任务源 +[task-source] +# 构建类型 +# 可选值:"build-from-source", "install-from-prebuilt" +type = "build-from-source" +# 构建来源 +# "build_from_source" 可选值:"git", "local", "archive" +# "install_from_prebuilt" 可选值:"local", "archive" +source = "local" +# 路径或URL +source-path = "user/apps/strace" +# 构建相关信息 +[build] +# (可选)构建命令 +build-command = "make install" +# 安装相关信息 +[install] +# (可选)安装到DragonOS的路径 +in-dragonos-path = "/bin" +# 清除相关信息 +[clean] +# (可选)清除命令 +clean-command = "make clean" +# (可选)依赖项 +# 注意:如果没有依赖项,忽略此项,不允许只留一个[[depends]] +# 环境变量 +# 注意:如果没有环境变量,忽略此项,不允许只留一个[[envs]] From d8c07cf3bc22e52b1b7538ec46def3bc1b137abb Mon Sep 17 00:00:00 2001 From: aLinChe <1129332011@qq.com> Date: Sat, 6 Sep 2025 22:52:14 +0800 Subject: [PATCH 02/15] fix sig Signed-off-by: aLinChe <1129332011@qq.com> --- kernel/src/arch/x86_64/ipc/signal.rs | 9 +- kernel/src/arch/x86_64/kprobe.rs | 38 ++ kernel/src/arch/x86_64/mm/fault.rs | 7 +- kernel/src/ipc/kill.rs | 14 +- kernel/src/ipc/signal_types.rs | 9 +- kernel/src/process/execve.rs | 37 +- kernel/src/process/exit.rs | 4 +- kernel/src/process/mod.rs | 116 ++++-- kernel/src/process/ptrace.rs | 357 ++++++++++++------ kernel/src/process/syscall/sys_ptrace.rs | 17 +- kernel/src/process/timer.rs | 7 +- .../{test-ptrace.c => test_ptrace.c} | 8 +- 12 files changed, 442 insertions(+), 181 deletions(-) rename user/apps/c_unitest/{test-ptrace.c => test_ptrace.c} (98%) diff --git a/kernel/src/arch/x86_64/ipc/signal.rs b/kernel/src/arch/x86_64/ipc/signal.rs index cbc654b23..020eb0825 100644 --- a/kernel/src/arch/x86_64/ipc/signal.rs +++ b/kernel/src/arch/x86_64/ipc/signal.rs @@ -11,6 +11,8 @@ pub use crate::ipc::generic_signal::GenericSigSet as SigSet; pub use crate::ipc::generic_signal::GenericSigStackFlags as SigStackFlags; pub use crate::ipc::generic_signal::GenericSignal as Signal; +// 调用一个 ptrace_signal 辅助函数 +use crate::process::{ptrace::ptrace_signal, ProcessFlags}; use crate::{ arch::{ fpu::FpState, @@ -513,7 +515,7 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { return; } - let mut sig_number: Signal; + let mut sig: Signal; let mut info: Option; let mut sigaction: Option; let sig_block: SigSet = *siginfo_read_guard.sig_blocked(); @@ -527,10 +529,10 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { let mut siginfo_mut_guard = siginfo_mut.unwrap(); loop { - (sig_number, info) = siginfo_mut_guard.dequeue_signal(&sig_block, &pcb); + (sig, info) = siginfo_mut_guard.dequeue_signal(&sig_block, &pcb); // 如果信号非法,则直接返回 - if sig_number == Signal::INVALID { + if sig == Signal::INVALID { return; } @@ -732,6 +734,7 @@ fn handle_signal( oldset: &SigSet, frame: &mut TrapFrame, ) -> Result { + log::debug!("handle_signal {:?}", sig); if unsafe { frame.syscall_nr() }.is_some() { if let Some(syscall_err) = unsafe { frame.syscall_error() } { match syscall_err { diff --git a/kernel/src/arch/x86_64/kprobe.rs b/kernel/src/arch/x86_64/kprobe.rs index e998aa993..74389b1f5 100644 --- a/kernel/src/arch/x86_64/kprobe.rs +++ b/kernel/src/arch/x86_64/kprobe.rs @@ -63,3 +63,41 @@ impl From<&TrapFrame> for KProbeContext { } } } + +const AUDIT_ARCH_X86_64: u32 = 0xC000_003E; + +/// 获取当前架构标识 +pub fn syscall_get_arch() -> u32 { + AUDIT_ARCH_X86_64 +} + +/// 从 KProbeContext 获取指令指针 (rip) +pub fn instruction_pointer(ctx: &KProbeContext) -> u64 { + ctx.rip +} + +/// 从 KProbeContext 获取用户栈指针 (rsp) +pub fn user_stack_pointer(ctx: &KProbeContext) -> u64 { + ctx.rsp +} + +/// 从 KProbeContext 获取系统调用号 (rax) +pub fn syscall_get_nr(ctx: &KProbeContext) -> u64 { + ctx.rax +} + +/// 从 KProbeContext 获取系统调用返回值 (rax) +pub fn syscall_get_return_value(ctx: &KProbeContext) -> i64 { + ctx.rax as i64 +} + +/// 从 KProbeContext 获取系统调用的前 6 个参数 +/// (遵循 x86_64 System V ABI) +pub fn syscall_get_arguments(ctx: &KProbeContext, args: &mut [u64; 6]) { + args[0] = ctx.rdi; + args[1] = ctx.rsi; + args[2] = ctx.rdx; + args[3] = ctx.r10; + args[4] = ctx.r8; + args[5] = ctx.r9; +} diff --git a/kernel/src/arch/x86_64/mm/fault.rs b/kernel/src/arch/x86_64/mm/fault.rs index a33bc91d6..d6f873c5c 100644 --- a/kernel/src/arch/x86_64/mm/fault.rs +++ b/kernel/src/arch/x86_64/mm/fault.rs @@ -291,7 +291,12 @@ impl X86_64MMArch { let send_segv = || { let pid = ProcessManager::current_pid(); - let mut info = SigInfo::new(Signal::SIGSEGV, 0, SigCode::Origin(OriginCode::User), SigType::Kill(pid)); + let mut info = SigInfo::new( + Signal::SIGSEGV, + 0, + SigCode::Origin(OriginCode::User), + SigType::Kill(pid), + ); Signal::SIGSEGV .send_signal_info(Some(&mut info), pid) .expect("failed to send SIGSEGV to process"); diff --git a/kernel/src/ipc/kill.rs b/kernel/src/ipc/kill.rs index 0d1d3888d..ae2cd7274 100644 --- a/kernel/src/ipc/kill.rs +++ b/kernel/src/ipc/kill.rs @@ -10,7 +10,12 @@ use system_error::SystemError; /// ### 杀死一个进程 pub fn kill_process(pid: RawPid, sig: Signal) -> Result { // 初始化signal info - let mut info = SigInfo::new(sig, 0, SigCode::Origin(OriginCode::User), SigType::Kill(pid)); + let mut info = SigInfo::new( + sig, + 0, + SigCode::Origin(OriginCode::User), + SigType::Kill(pid), + ); compiler_fence(core::sync::atomic::Ordering::SeqCst); let ret = sig @@ -29,7 +34,12 @@ pub fn kill_process_by_pcb( sig: Signal, ) -> Result { // 初始化signal info - let mut info = SigInfo::new(sig, 0, SigCode::Origin(OriginCode::User), SigType::Kill(pcb.raw_pid())); + let mut info = SigInfo::new( + sig, + 0, + SigCode::Origin(OriginCode::User), + SigType::Kill(pcb.raw_pid()), + ); return sig .send_signal_info_to_pcb(Some(&mut info), pcb) diff --git a/kernel/src/ipc/signal_types.rs b/kernel/src/ipc/signal_types.rs index 41494a5c7..e31fdbe70 100644 --- a/kernel/src/ipc/signal_types.rs +++ b/kernel/src/ipc/signal_types.rs @@ -173,7 +173,7 @@ impl SaHandlerType { #[derive(Debug, Copy, Clone)] pub struct Sigaction { action: SigactionType, - pub(crate) flags: SigFlags, + flags: SigFlags, mask: SigSet, // 为了可扩展性而设置的sa_mask /// 信号处理函数执行结束后,将会跳转到这个函数内进行执行,然后执行sigreturn系统调用 restorer: Option, @@ -572,7 +572,12 @@ impl SigPending { return info; } else { // 信号不在sigqueue中,这意味着当前信号是来自快速路径,因此直接把siginfo设置为0即可。 - let mut ret = SigInfo::new(sig, 0, SigCode::Origin(OriginCode::User), SigType::Kill(RawPid::from(0))); + let mut ret = SigInfo::new( + sig, + 0, + SigCode::Origin(OriginCode::User), + SigType::Kill(RawPid::from(0)), + ); ret.set_sig_type(SigType::Kill(RawPid::new(0))); return ret; } diff --git a/kernel/src/process/execve.rs b/kernel/src/process/execve.rs index ff5775957..8f42a92a1 100644 --- a/kernel/src/process/execve.rs +++ b/kernel/src/process/execve.rs @@ -1,10 +1,12 @@ +use crate::arch::ipc::signal::{ChldCode, SigCode, Signal}; use crate::arch::CurrentIrqArch; use crate::exception::InterruptArch; use crate::filesystem::vfs::IndexNode; +use crate::ipc::signal_types::{SigChldInfo, SigFaultInfo, SigInfo, SigType, SignalFlags}; use crate::process::exec::{load_binary_file, ExecParam, ExecParamFlags}; +use crate::process::PtraceEvent; use crate::process::{ProcessFlags, ProcessManager}; use crate::syscall::Syscall; -use crate::process::ptrace::PtraceEvent; use crate::{libs::rand::rand_bytes, mm::ucontext::AddressSpace}; use crate::arch::interrupt::TrapFrame; @@ -29,12 +31,6 @@ pub fn do_execve( } })?; - let current_pcb = ProcessManager::current_pcb(); - if current_pcb.flags().contains(ProcessFlags::PTRACED) { - log::debug!("ptrace_event Exec"); - current_pcb.ptrace_event(PtraceEvent::Exec, current_pcb.task_pid_vnr().data()); - } - // log::debug!("load binary file done"); // debug!("argv: {:?}, envp: {:?}", argv, envp); param.init_info_mut().args = argv; @@ -66,7 +62,7 @@ pub fn do_execve( // execve 成功后,如果是 vfork 创建的子进程,需要通知父进程继续执行 // 在通知父进程之前,必须先清除 vfork_done,防止子进程退出时再次通知 - let pcb = ProcessManager::current_pcb(); + let pcb = ProcessManager::pcb(); let vfork_done = pcb.thread.write_irqsave().vfork_done.take(); if let Some(completion) = vfork_done { @@ -84,6 +80,29 @@ pub fn do_execve( pcb.flush_signal_handlers(false); *pcb.sig_altstack_mut() = crate::arch::SigStackArch::new(); + if pcb.is_traced() { + if pcb.ptrace_event_enabled(PtraceEvent::Exec) { + log::debug!("ptrace_event Exec"); + pcb.ptrace_event(PtraceEvent::Exec, pcb.task_pid_vnr().data()); + } else { + // 经典 traceme 发送 SIGTRAP + log::debug!("execve hook: classic traceme send SIGTRAP."); + let mut info = SigInfo::new( + Signal::SIGTRAP, + 0, + SigCode::SigChld(ChldCode::Trapped), + SigType::SigChld(SigChldInfo { + pid: pcb.task_pid_vnr(), + uid: pcb.cred().uid.data(), + status: 0, // todo + utime: 0, // 可以根据需要填充实际值 + stime: 0, // 可以根据需要填充实际值 + }), + ); + Signal::SIGTRAP.send_signal_info_to_pcb(Some(&mut info), pcb); + } + } + Syscall::arch_do_execve(regs, ¶m, &load_result, user_sp, argv_ptr) } @@ -102,7 +121,7 @@ pub fn do_execve( fn do_execve_switch_user_vm(new_vm: Arc) -> Option> { // 关中断,防止在设置地址空间的时候,发生中断,然后进调度器,出现错误。 let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; - let pcb = ProcessManager::current_pcb(); + let pcb = ProcessManager::pcb(); // log::debug!( // "pid: {:?} do_execve: path: {:?}, argv: {:?}, envp: {:?}\n", // pcb.pid(), diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs index 42dc4bb0f..a4a679255 100644 --- a/kernel/src/process/exit.rs +++ b/kernel/src/process/exit.rs @@ -574,8 +574,8 @@ fn do_waitpid( drop(child_pcb); } return Some(Ok(pid.into())); - }, - ProcessState::TracedStopped => todo!() + } + ProcessState::TracedStopped => todo!(), }; return None; diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index f53629cf7..767952e35 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -1,17 +1,16 @@ +use alloc::{ + string::{String, ToString}, + sync::{Arc, Weak}, + vec::Vec, +}; use core::{ fmt, hash::Hash, hint::spin_loop, - intrinsics::unlikely, - mem::ManuallyDrop, + intrinsics::{likely, unlikely}, + mem::{ManuallyDrop, MaybeUninit}, sync::atomic::{compiler_fence, fence, AtomicBool, AtomicU64, AtomicUsize, Ordering}, }; - -use alloc::{ - string::{String, ToString}, - sync::{Arc, Weak}, - vec::Vec, -}; use cred::INIT_CRED; use hashbrown::HashMap; use log::{debug, error, info, warn}; @@ -760,20 +759,19 @@ impl ProcessState { #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(i32)] pub enum PtraceRequest { - PtraceTraceme = 0, // PTRACE_TRACEME - PtraceAttach = 16, // PTRACE_ATTACH - PtraceDetach = 17, // PTRACE_DETACH - PtraceSyscall = 24, // PTRACE_SYSCALL - PtraceSinglestep = 9, // PTRACE_SINGLESTEP - PtraceCont = 7, // PTRACE_CONT - PtraceGetregs = 12, // PTRACE_GETREGS - PtraceSetregs = 13, // PTRACE_SETREGS - PtracePeekuser = 3, // PTRACE_PEEKUSER - PtracePeekdata = 2, // PTRACE_PEEKDATA - PtracePokedata = 5, // PTRACE_POKEDATA - PtraceGetsiginfo = 0x4202, // PTRACE_GETSIGINFO - PtraceSetoptions = 0x4200, // PTRACE_SETOPTIONS - // ... 其他可能的请求 + PtraceTraceme = 0, + PtraceAttach = 16, + PtraceDetach = 17, + PtraceSyscall = 24, + PtraceSinglestep = 9, + PtraceCont = 7, + PtraceGetregs = 12, + PtraceSetregs = 13, + PtracePeekuser = 3, + PtracePeekdata = 2, + PtracePokedata = 5, + PtraceGetsiginfo = 0x4202, + PtraceSetoptions = 0x4200, } bitflags! { @@ -874,6 +872,78 @@ pub struct ProcessItimers { pub prof: CpuItimer, // 用于 ITIMER_PROF } +#[repr(u8)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum PtraceSyscallInfoOp { + None = 0, + Entry = 1, + Exit = 2, + Seccomp = 3, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct PtraceSyscallInfoEntry { + pub nr: u64, + pub args: [u64; 6], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct PtraceSyscallInfoExit { + pub rval: i64, + pub is_error: u8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct PtraceSyscallInfoSeccomp { + pub nr: u64, + pub args: [u64; 6], + pub ret_data: u32, +} + +#[repr(C)] +pub union PtraceSyscallInfoData { + pub entry: PtraceSyscallInfoEntry, + pub exit: PtraceSyscallInfoExit, + pub seccomp: PtraceSyscallInfoSeccomp, + _uninit: MaybeUninit<[u8; 64]>, +} + +#[repr(C)] +pub struct PtraceSyscallInfo { + /// PTRACE_SYSCALL_INFO_* + pub op: PtraceSyscallInfoOp, + pub pad: [u8; 3], + pub arch: u32, + pub instruction_pointer: u64, + pub stack_pointer: u64, + /// The union containing event-specific data. + pub data: PtraceSyscallInfoData, +} + +#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] +pub enum PtraceStopReason { + #[default] + None, + SyscallEntry, + SyscallExit, + Signal(Signal), + Event(PtraceEvent), +} + +/// ptrace 系统调用的事件类型 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PtraceEvent { + Fork = 1, + VFork, + Clone, + Exec, + VForkDone, + Exit, + Seccomp, + Stop = 128, // 信号或单步执行导致的停止 +} + /// 进程被跟踪的状态信息 #[derive(Debug, Default)] struct PtraceState { @@ -883,6 +953,7 @@ struct PtraceState { pending_signals: Vec, /// 系统调用信息 (用于 PTRACE_SYSCALL) syscall_info: Option, + stop_reason: PtraceStopReason, /// ptrace选项位 options: PtraceOptions, /// 停止状态的状态字 @@ -896,6 +967,7 @@ impl PtraceState { tracer: None, pending_signals: Vec::new(), syscall_info: None, + stop_reason: PtraceStopReason::None, options: PtraceOptions::empty(), exit_code: 0, event_message: 0, diff --git a/kernel/src/process/ptrace.rs b/kernel/src/process/ptrace.rs index 8fed5ab1c..aaa826711 100644 --- a/kernel/src/process/ptrace.rs +++ b/kernel/src/process/ptrace.rs @@ -1,27 +1,73 @@ +use crate::arch::interrupt::TrapFrame; use crate::arch::ipc::signal::{ChldCode, OriginCode, SigCode, SigFlags, Signal}; +use crate::arch::kprobe; use crate::arch::CurrentIrqArch; use crate::exception::InterruptArch; -use crate::ipc::signal_types::{SigChldInfo, SigFaultInfo, SigInfo, SigType, SignalFlags}; +use crate::ipc::signal_types::{ + SigChldInfo, SigFaultInfo, SigInfo, SigType, Sigaction, SigactionType, SignalFlags, +}; use crate::process::{ - ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState, PtraceOptions, PtraceRequest, - RawPid, + ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState, PtraceEvent, PtraceOptions, + PtraceRequest, PtraceStopReason, PtraceSyscallInfo, PtraceSyscallInfoData, + PtraceSyscallInfoEntry, PtraceSyscallInfoExit, PtraceSyscallInfoOp, RawPid, SyscallInfo, }; use crate::sched::{schedule, DequeueFlag, EnqueueFlag, SchedMode}; use alloc::{sync::Arc, vec::Vec}; -use core::{intrinsics::unlikely, sync::atomic::Ordering}; +use core::{intrinsics::unlikely, mem::MaybeUninit, sync::atomic::Ordering}; use system_error::SystemError; -/// ptrace 系统调用的事件类型 -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum PtraceEvent { - Fork = 1, - VFork, - Clone, - Exec, - VForkDone, - Exit, - Seccomp, - Stop = 128, // 信号或单步执行导致的停止 +/// 在 get_signal 中调用的 ptrace 信号拦截器。 +/// 它会使进程停止,并根据追踪者的指令决定如何处理信号。 +/// 返回值: +/// - Some(Signal): 一个需要立即处理的信号。 +/// - None: 信号被 ptrace 取消或重新排队了,当前无需处理。 +pub fn ptrace_signal( + pcb: &Arc, + original_signal: Signal, + info: &mut Option, +) -> Option { + // todo pcb.jobctl_set(JobControlFlags::STOP_DEQUEUED); + // 核心:调用 ptrace_stop 使进程停止并等待追踪者。 + // ptrace_stop 会返回追踪者注入的信号。 + // 注意:ptrace_stop 内部会处理锁的释放和重新获取。 + let mut signr = pcb.ptrace_stop(original_signal as usize, ChldCode::Trapped, info.as_mut()); + let mut injected_signal = Signal::from(signr); + if injected_signal == Signal::INVALID { + return None; + } + // pcb.set_state(ProcessState::Exited(0)); + + // 如果追踪者注入了不同于原始信号的新信号,更新 siginfo。 + if injected_signal != original_signal { + if let Some(info_ref) = info { + let tracer = pcb.parent_pcb().unwrap(); + *info_ref = SigInfo::new( + injected_signal, + 0, + SigCode::Origin(OriginCode::User), + SigType::SigChld(SigChldInfo { + pid: tracer.raw_pid(), + uid: tracer.cred().uid.data(), + status: 0, + utime: 0, + stime: 0, + }), + ); + } + } + // 检查新信号是否被当前进程的信号掩码阻塞 + let sig_info_guard = pcb.sig_info_irqsave(); + if sig_info_guard + .sig_blocked() + .contains(injected_signal.into()) + { + // 如果被阻塞了,则将信号重新排队,让它在未来被处理。 + injected_signal.send_signal_info_to_pcb(info.as_mut(), Arc::clone(pcb)); + // 告诉 get_signal,当前没有需要立即处理的信号。 + return None; + } + // 如果没有被阻塞,则返回这个新信号,让 get_signal 继续分发和处理它。 + Some(injected_signal) } pub fn do_notify_parent(child: &ProcessControlBlock, signal: Signal) -> Result { @@ -39,7 +85,7 @@ pub fn do_notify_parent(child: &ProcessControlBlock, signal: Signal) -> Result Result Result Result, sig: Signal) { let mut ptrace_state = current_pcb.ptrace_state.lock(); - // ptrace_data.stop_reason = PtraceStopReason::SignalStop(sig); + ptrace_state.stop_reason = PtraceStopReason::Signal(sig); + ptrace_state.exit_code = sig as usize; log::debug!( "PID {} stopping due to ptrace on signal {:?}", current_pcb.raw_pid(), sig ); - ptrace_state.exit_code = sig as usize; // if let Some(tracer_pid) = ptrace_state.tracer { // if let Some(tracer) = ProcessManager::find(tracer_pid) { // let mut info = SigInfo::new( @@ -197,36 +243,6 @@ impl ProcessControlBlock { // info.dequeue_signal(signal, self) // } - /// 恢复进程执行 - // todo - pub fn ptrace_resume(&self, request: PtraceRequest, sig: Signal) { - if request == PtraceRequest::PtraceSyscall { - } else { - } - if request == PtraceRequest::PtraceSyscall { - // arch::user_enable_single_step(self); - } else { - // arch::user_disable_single_step(self); - } - let mut sched_info = self.sched_info.inner_lock_write_irqsave(); - // 清除停止/阻塞标志 - self.exit_signal.store(sig, Ordering::SeqCst); - self.flags().remove(ProcessFlags::STOPPED); - // 设置为可运行状态 - sched_info.set_state(ProcessState::Runnable); - // 加入调度队列 - if let Some(strong_ref) = self.self_ref.upgrade() { - let rq = self.sched_info.sched_entity().cfs_rq().rq(); - let (rq, _guard) = rq.self_lock(); - rq.enqueue_task( - strong_ref.clone(), - EnqueueFlag::ENQUEUE_RESTORE | EnqueueFlag::ENQUEUE_WAKEUP, - ); - } else { - log::warn!("ptrace_runnable: pid={} self_ref is dead", self.raw_pid()); - } - } - /// 唤醒父进程的等待队列 fn wake_up_parent(&self, state: Option) { if let Some(parent) = self.parent_pcb() { @@ -267,11 +283,11 @@ impl ProcessControlBlock { stime: 0, // 可以根据需要填充实际值 }), ); - signal.send_signal_info(Some(&mut info), current_pcb.raw_pid())?; + current_pcb.ptrace_stop(exit_code, ChldCode::Trapped, Some(&mut info)); Ok(()) } - fn ptrace_event_enabled(&self, event: PtraceEvent) -> bool { + pub fn ptrace_event_enabled(&self, event: PtraceEvent) -> bool { let event_flag = 1 << (event as u32 + 3); self.ptrace_state.lock().event_message == event_flag && event_flag != 0; true @@ -295,59 +311,72 @@ impl ProcessControlBlock { // } } let wait_status = ((event as usize) << 8) | (Signal::SIGTRAP as usize); - self.ptrace_stop(wait_status); self.set_state(ProcessState::Runnable); } /// 设置进程为停止状态 - fn ptrace_stop(&self, wait_status: usize) { - self.set_state(ProcessState::Stopped(wait_status)); + pub fn ptrace_stop( + &self, + exit_code: usize, + why: ChldCode, + info: Option<&mut SigInfo>, + ) -> usize { + // self.last_siginfo = info.cloned(); + // self.set_state(ProcessState::Exited(exit_code)); + self.set_state(ProcessState::Stopped(exit_code)); + self.flags().insert(ProcessFlags::PTRACED); if let Some(tracer) = self.parent_pcb() { - tracer.wait_queue.wakeup(None); + self.notify_tracer(&tracer, why); } else { log::error!("PID {} is traced but has no parent tracer!", self.raw_pid()); } - schedule(SchedMode::SM_NONE); - } - - /// 设置进程为停止状态 - pub fn _stop_process(&self, signal: Signal) { - let status_code = signal.into(); - { - let mut sched_info = self.sched_info.inner_lock_write_irqsave(); - sched_info.set_state(ProcessState::Stopped(status_code)); - // 设置进程标志 - self.flags().insert(ProcessFlags::STOPPED); - if let Some(tracer) = self.tracer() { - self.wake_up_parent(Some(ProcessState::Stopped(status_code))); - } else { - let mut info = SigInfo::new( - signal, - 0, - SigCode::Origin(OriginCode::Kernel), - SigType::SigFault(SigFaultInfo { addr: 0, trapno: 0 }), - ); - let _ = signal.send_signal_info(Some(&mut info), self.parent_pid()); - } - } - log::debug!("Process {} stopped by signal {:?}", self.raw_pid(), signal); - // 唤醒父进程 - self.wake_up_parent(None); - // 移出调度队列 - if let Some(strong_ref) = self.self_ref.upgrade() { - let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; - { - let rq = self.sched_info.sched_entity().cfs_rq().rq(); - let (rq, _guard) = rq.self_lock(); - rq.dequeue_task(strong_ref.clone(), DequeueFlag::DEQUEUE_SAVE); - } - drop(irq_guard); + if self.preempt_count() > 0 { + log::warn!( + "PID {} calling schedule with preempt_count={}", + self.raw_pid(), + self.preempt_count() + ); } + // 先释放 sighand_lock 锁,再获取锁 + // 不会写,先手动维护一下 preempt + unsafe { self.sig_struct.force_unlock() }; + self.preempt_count.fetch_sub(1, Ordering::SeqCst); schedule(SchedMode::SM_NONE); - self.flags().remove(ProcessFlags::STOPPED); - let signal_to_deliver = { - let mut ptrace_state = self.ptrace_state.lock(); - ptrace_state.next_pending_signal() + self.preempt_count.fetch_add(1, Ordering::SeqCst); + let sighand_lock = self.sig_struct_irqsave(); + // 为下次stop恢复 + // self.last_siginfo = None; + self.ptrace_state.lock().event_message = 0; + exit_code + } + + fn notify_tracer(&self, tracer: &Arc, why: ChldCode) { + log::debug!("notify_tracer"); + let status = match why { + ChldCode::Stopped => self.exit_code().unwrap_or(0) as i32 & 0x7f, + ChldCode::Trapped => self.exit_code().unwrap_or(0) as i32 & 0x7f, + _ => Signal::SIGCONT as i32, + }; + let mut info = SigInfo::new( + Signal::SIGCHLD, + 0, + SigCode::SigChld(why), + SigType::SigChld(SigChldInfo { + pid: self.raw_pid(), + uid: self.cred().uid.data(), + status, + utime: 0, // todo: 填充时间 + stime: 0, + }), + ); + let should_send = { + let tracer_sighand = tracer.sig_struct_irqsave(); + let sa = &tracer_sighand.handlers[Signal::SIGCHLD as usize - 1]; + !sa.action().is_ignore() && !sa.flags().contains(SigFlags::SA_NOCLDSTOP) }; + if should_send { + Signal::SIGCHLD.send_signal_info_to_pcb(Some(&mut info), Arc::clone(tracer)); + } + tracer.wait_queue.wakeup(None); } /// 检查进程是否可以被指定进程跟踪 @@ -380,7 +409,7 @@ impl ProcessControlBlock { // } // ptrace_list.push(child_pid); self.set_tracer(tracer.raw_pid())?; - self.ptrace_state.lock().tracer = Some(tracer.raw_pid()); + self.set_parent(tracer)?; *self.cred.lock() = tracer.cred().clone(); Ok(()) } @@ -394,7 +423,7 @@ impl ProcessControlBlock { // self.clear_syscall_trace_work(); // 恢复父进程为真实父进程 let real_parent = self.real_parent_pcb().ok_or(SystemError::ESRCH)?; - let _ = self.set_parent(&real_parent); + self.set_parent(&real_parent)?; // 从跟踪器的跟踪列表中移除当前进程 // let mut ptrace_list = tracer.ptraced_list.write(); // if let Some(pos) = ptrace_list.iter().position(|&pid| pid == self.raw_pid()) { @@ -474,6 +503,7 @@ impl ProcessControlBlock { // let guard = tracer.sig_struct_irqsave(); // signal_wake_up(self.self_ref.upgrade().unwrap(), guard, false); // } + // todo proc_ptrace_connector(self, PTRACE_ATTACH); Ok(0) } @@ -485,13 +515,19 @@ impl ProcessControlBlock { return Err(SystemError::EPERM); } self.ptrace_unlink()?; + if let Some(sig) = signal { + self.exit_signal.store(sig, Ordering::SeqCst); + } else { + return Ok(0); + } let mut dead = !self.is_thread_group_leader(); if !dead { let real_parent = self.real_parent_pcb().ok_or(SystemError::ESRCH)?; if !ProcessManager::same_thread_group(&real_parent, &self.self_ref) { - dead = do_notify_parent(self, signal.unwrap())?; // todo + log::debug!("do_notify_parent, sig={:?}", signal.unwrap()); + dead = do_notify_parent(self, signal.unwrap())?; return Ok(0); - } else if self.sig_struct_irqsave().handlers[Signal::SIGCHLD as usize] + } else if self.sig_struct_irqsave().handlers[Signal::SIGCHLD as usize - 1] .action() .is_ignore() { @@ -499,37 +535,53 @@ impl ProcessControlBlock { dead = true; } } + // todo + // if dead { + // self.exit_state.store(EXIT_DEAD, Ordering::SeqCst); + // } + // todo proc_ptrace_connector(self, PtraceRequest::PtraceDetach) Ok(0) } - /// 处理 PTRACE_CONT 请求 - pub fn ptrace_cont(&self, signal: Option) -> Result { - log::info!( - "PTRACE_CONT for process {}, signal: {:?}", - self.raw_pid(), - signal - ); + /// 恢复进程执行 + pub fn ptrace_resume( + &self, + request: PtraceRequest, + signal: Option, + frame: &mut TrapFrame, + ) -> Result { + match request { + PtraceRequest::PtraceSyscall => self.flags().insert(ProcessFlags::TRACE_SYSCALL), + PtraceRequest::PtraceSinglestep => { + self.flags().insert(ProcessFlags::TRACE_SINGLESTEP); + kprobe::setup_single_step(frame, frame.rip as usize); // 架构相关的操作,设置 TF 标志 + } + _ => {} // PTRACE_CONT 不需要特殊标志 + } + log::info!("signal: {:?} to process {}", signal, self.raw_pid()); if signal == None { + self.exit_signal.store(Signal::SIGCONT, Ordering::SeqCst); return Ok(0); } - let mut sig = Signal::SIGCONT; - if signal != None { - sig = Signal::from(signal.unwrap() as i32); - } - // 检查当前进程是否有权限操作目标进程 - let current = ProcessManager::current_pcb(); - if self.tracer() != Some(current.raw_pid()) { - return Err(SystemError::EPERM); - } - // 检查进程是否被跟踪 - if !self.flags().contains(ProcessFlags::PTRACED) { - return Err(SystemError::ESRCH); + let mut sched_info = self.sched_info.inner_lock_write_irqsave(); + // 清除停止/阻塞标志 + if let Some(sig) = signal { + self.exit_signal.store(sig, Ordering::SeqCst); } - // 检查进程是否处于停止状态 - if !self.flags().contains(ProcessFlags::STOPPED) { - return Err(SystemError::EINVAL); + self.flags().remove(ProcessFlags::STOPPED); + // 设置为可运行状态 + sched_info.set_state(ProcessState::Runnable); + // 加入调度队列 + if let Some(strong_ref) = self.self_ref.upgrade() { + let rq = self.sched_info.sched_entity().cfs_rq().rq(); + let (rq, _guard) = rq.self_lock(); + rq.enqueue_task( + strong_ref.clone(), + EnqueueFlag::ENQUEUE_RESTORE | EnqueueFlag::ENQUEUE_WAKEUP, + ); + } else { + log::warn!("ptrace_runnable: pid={} self_ref is dead", self.raw_pid()); } - self.ptrace_resume(PtraceRequest::PtraceCont, sig); Ok(0) } @@ -546,6 +598,67 @@ impl ProcessControlBlock { Ok(0) } + pub fn ptrace_get_syscall_info( + &self, + user_size: usize, + datavp: usize, // Use a raw byte pointer for flexibility + ) -> Result { + // todo let trap_frame = self.task_context(); + let trap_frame = TrapFrame::new(); + let ctx = kprobe::KProbeContext::from(&trap_frame); + let mut info = PtraceSyscallInfo { + op: PtraceSyscallInfoOp::None, + pad: [0; 3], + arch: kprobe::syscall_get_arch(), + instruction_pointer: kprobe::instruction_pointer(&ctx), + stack_pointer: kprobe::user_stack_pointer(&ctx), + data: PtraceSyscallInfoData { + _uninit: MaybeUninit::uninit(), + }, + }; + + let ptrace_state = self.ptrace_state.lock(); + let actual_size = match ptrace_state.stop_reason { + PtraceStopReason::SyscallEntry => { + info.op = PtraceSyscallInfoOp::Entry; + let mut args = [0u64; 6]; + kprobe::syscall_get_arguments(&ctx, &mut args); + info.data.entry = PtraceSyscallInfoEntry { + nr: kprobe::syscall_get_nr(&ctx), + args, + }; + core::mem::size_of::() + } + PtraceStopReason::SyscallExit => { + info.op = PtraceSyscallInfoOp::Exit; + let rval = kprobe::syscall_get_return_value(&ctx); + let is_error = rval >= -4095; // MAX_ERRNO + info.data.exit = PtraceSyscallInfoExit { + rval, + is_error: is_error as u8, + }; + core::mem::size_of::() + } + _ => { + // 如果因为其他原因停止,只返回通用头部信息的大小 + core::mem::offset_of!(PtraceSyscallInfo, data) + } + }; + drop(ptrace_state); + + // 将数据拷贝到用户空间 + let write_size = core::cmp::min(actual_size, user_size); + if write_size > 0 { + // 将结构体视为字节切片进行拷贝 + let info_bytes = + unsafe { core::slice::from_raw_parts(&info as *const _ as *const u8, write_size) }; + // datavp.write_bytes(info_bytes)?; + } + + // 无论拷贝多少,都返回内核准备好的完整数据大小 + Ok(actual_size as isize) + } + /// 处理PTRACE_SINGLESTEP请求 pub fn single_step(&self) -> Result { // 设置单步执行标志 diff --git a/kernel/src/process/syscall/sys_ptrace.rs b/kernel/src/process/syscall/sys_ptrace.rs index a08cfe2ac..9b45b4ea7 100644 --- a/kernel/src/process/syscall/sys_ptrace.rs +++ b/kernel/src/process/syscall/sys_ptrace.rs @@ -79,14 +79,6 @@ impl SysPtrace { tracee.detach(signal) } - /// 处理 PTRACE_CONT 请求 - fn handle_cont( - tracee: &ProcessControlBlock, - signal: Option, - ) -> Result { - tracee.ptrace_cont(signal) - } - /// 处理 PTRACE_SYSCALL 请求(在系统调用入口和出口暂停) fn handle_syscall(tracee: &Arc) -> Result { // 检查调用者是否是该进程的跟踪器 @@ -231,7 +223,7 @@ impl Syscall for SysPtrace { 4 } - fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + fn handle(&self, args: &[usize], frame: &mut TrapFrame) -> Result { if args.len() < 4 { return Err(SystemError::EINVAL); } @@ -259,9 +251,9 @@ impl Syscall for SysPtrace { // 分离目标进程 PtraceRequest::PtraceDetach => Self::handle_detach(&tracee, signal)?, // 继续执行目标进程 - PtraceRequest::PtraceCont => Self::handle_cont(&tracee, signal)?, - // 在系统调用入口和出口暂停 - PtraceRequest::PtraceSyscall => Self::handle_syscall(&tracee)?, + PtraceRequest::PtraceCont + | PtraceRequest::PtraceSinglestep + | PtraceRequest::PtraceSyscall => tracee.ptrace_resume(request, signal, frame)?, // 设置跟踪选项 PtraceRequest::PtraceSetoptions => Self::handle_set_options(&tracee, data)?, // 获取信号信息 @@ -270,7 +262,6 @@ impl Syscall for SysPtrace { PtraceRequest::PtracePeekuser => Self::handle_peek_user(&tracee, addr)?, // 读取进程内存 PtraceRequest::PtracePeekdata => Self::handle_peek_data(&tracee, addr)?, - PtraceRequest::PtraceSinglestep => todo!(), // 其他请求类型 _ => { log::warn!("Unimplemented ptrace request: {:?}", request); diff --git a/kernel/src/process/timer.rs b/kernel/src/process/timer.rs index 6d4260994..8d3a5fe51 100644 --- a/kernel/src/process/timer.rs +++ b/kernel/src/process/timer.rs @@ -131,7 +131,12 @@ impl TimerFunction for AlarmTimerFunc { fn run(&mut self) -> Result<(), SystemError> { let sig = Signal::SIGALRM; // 初始化signal info - let mut info = SigInfo::new(sig, 0, SigCode::Origin(OriginCode::Timer), SigType::Alarm(self.pid)); + let mut info = SigInfo::new( + sig, + 0, + SigCode::Origin(OriginCode::Timer), + SigType::Alarm(self.pid), + ); compiler_fence(core::sync::atomic::Ordering::SeqCst); let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; diff --git a/user/apps/c_unitest/test-ptrace.c b/user/apps/c_unitest/test_ptrace.c similarity index 98% rename from user/apps/c_unitest/test-ptrace.c rename to user/apps/c_unitest/test_ptrace.c index 11e8efebf..e1e97207a 100644 --- a/user/apps/c_unitest/test-ptrace.c +++ b/user/apps/c_unitest/test_ptrace.c @@ -32,8 +32,8 @@ } \ } while (0) -static void sigcont_handler(int signum) { - printf("target received SIGCONT\n"); +void sigcont_handler(int sig) { + printf("target received %d (%s)\n", sig, strsignal(sig)); exit(EXIT_SUCCESS); } @@ -78,7 +78,7 @@ void test_trace_me() { } } -// 测试 PTRACE_ATTACH/DETACH 功能x +// 测试 PTRACE_ATTACH/DETACH 功能 void test_attach_detach() { printf("=== Testing PTRACE_ATTACH/DETACH ===\n"); pid_t target = fork(); @@ -94,7 +94,7 @@ void test_attach_detach() { // pause(); // 等待信号 // 永远不会到达这里 printf("target process resumed\n"); - exit(EXIT_SUCCESS); + exit(EXIT_FAILURE); } else { // 给目标进程时间进入pause状态 sleep(1); From 0128d399c29be1061ed8b726c25cea00d034b2db Mon Sep 17 00:00:00 2001 From: aLinChe <1129332011@qq.com> Date: Thu, 16 Oct 2025 00:04:07 +0800 Subject: [PATCH 03/15] rebase master --- kernel/src/arch/x86_64/ipc/signal.rs | 144 +++++++++++++------------- kernel/src/arch/x86_64/mm/fault.rs | 4 +- kernel/src/ipc/kill.rs | 6 +- kernel/src/ipc/pipe.rs | 4 +- kernel/src/ipc/signal.rs | 7 +- kernel/src/ipc/signal_types.rs | 72 ++++++++++--- kernel/src/ipc/syscall/sys_restart.rs | 4 +- kernel/src/ipc/syscall/sys_tkill.rs | 4 +- kernel/src/process/execve.rs | 6 +- kernel/src/process/ptrace.rs | 50 +++++---- kernel/src/process/syscall/mod.rs | 1 - kernel/src/process/timer.rs | 6 +- 12 files changed, 182 insertions(+), 126 deletions(-) diff --git a/kernel/src/arch/x86_64/ipc/signal.rs b/kernel/src/arch/x86_64/ipc/signal.rs index 020eb0825..fa382531e 100644 --- a/kernel/src/arch/x86_64/ipc/signal.rs +++ b/kernel/src/arch/x86_64/ipc/signal.rs @@ -336,76 +336,76 @@ impl UserUContext { } } -/// siginfo中的si_code的可选值 -/// 请注意,当这个值小于0时,表示siginfo来自用户态,否则来自内核态 -#[derive(Copy, Debug, Clone, PartialEq, Eq)] -pub enum SigCode { - /// 描述通用来源 - Origin(OriginCode), - /// 描述 SIGCHLD 的具体原因 - SigChld(ChldCode), -} - -/// 信号的通用来源码 (SI_*) -#[derive(Copy, Debug, Clone, PartialEq, Eq)] -#[repr(i32)] -pub enum OriginCode { - /// sent by kill, sigsend, raise - User = 0, - /// sent by kernel from somewhere - Kernel = 0x80, - /// 通过sigqueue发送 - Queue = -1, - /// 定时器过期时发送 - Timer = -2, - /// 当实时消息队列的状态发生改变时发送 - Mesgq = -3, - /// 当异步IO完成时发送 - AsyncIO = -4, - /// sent by queued SIGIO - SigIO = -5, -} - -/// SIGCHLD 专用原因码 (CLD_*) -#[derive(Copy, Debug, Clone, PartialEq, Eq)] -#[repr(i32)] -pub enum ChldCode { - Exited = 1, - Killed = 2, - Dumped = 3, - Trapped = 4, - Stopped = 5, - Continued = 6, -} - -impl SigCode { - /// 为SigCode这个枚举类型实现从i32转换到枚举类型的转换函数 - #[allow(dead_code)] - pub fn from_i32(signal: Signal, code: i32) -> SigCode { - match signal { - Signal::SIGCHLD => match code { - 1 => SigCode::SigChld(ChldCode::Exited), - 2 => SigCode::SigChld(ChldCode::Killed), - 3 => SigCode::SigChld(ChldCode::Dumped), - 4 => SigCode::SigChld(ChldCode::Trapped), - 5 => SigCode::SigChld(ChldCode::Stopped), - 6 => SigCode::SigChld(ChldCode::Continued), - _ => panic!("signal code not valid in {:?}", signal), - }, - // 对于其他信号,尝试匹配通用码 - _ => match code { - 0 => SigCode::Origin(OriginCode::User), - 0x80 => SigCode::Origin(OriginCode::Kernel), - -1 => SigCode::Origin(OriginCode::Queue), - -2 => SigCode::Origin(OriginCode::Timer), - -3 => SigCode::Origin(OriginCode::Mesgq), - -4 => SigCode::Origin(OriginCode::AsyncIO), - -5 => SigCode::Origin(OriginCode::SigIO), - _ => panic!("signal code not valid in {:?}", signal), - }, - } - } -} +// /// siginfo中的si_code的可选值 +// /// 请注意,当这个值小于0时,表示siginfo来自用户态,否则来自内核态 +// #[derive(Copy, Debug, Clone, PartialEq, Eq)] +// pub enum SigCode { +// /// 描述通用来源 +// Origin(OriginCode), +// /// 描述 SIGCHLD 的具体原因 +// SigChld(ChldCode), +// } + +// /// 信号的通用来源码 (SI_*) +// #[derive(Copy, Debug, Clone, PartialEq, Eq)] +// #[repr(i32)] +// pub enum OriginCode { +// /// sent by kill, sigsend, raise +// User = 0, +// /// sent by kernel from somewhere +// Kernel = 0x80, +// /// 通过sigqueue发送 +// Queue = -1, +// /// 定时器过期时发送 +// Timer = -2, +// /// 当实时消息队列的状态发生改变时发送 +// Mesgq = -3, +// /// 当异步IO完成时发送 +// AsyncIO = -4, +// /// sent by queued SIGIO +// SigIO = -5, +// } + +// /// SIGCHLD 专用原因码 (CLD_*) +// #[derive(Copy, Debug, Clone, PartialEq, Eq)] +// #[repr(i32)] +// pub enum ChldCode { +// Exited = 1, +// Killed = 2, +// Dumped = 3, +// Trapped = 4, +// Stopped = 5, +// Continued = 6, +// } + +// impl SigCode { +// /// 为SigCode这个枚举类型实现从i32转换到枚举类型的转换函数 +// #[allow(dead_code)] +// pub fn from_i32(signal: Signal, code: i32) -> SigCode { +// match signal { +// Signal::SIGCHLD => match code { +// 1 => SigCode::SigChld(ChldCode::Exited), +// 2 => SigCode::SigChld(ChldCode::Killed), +// 3 => SigCode::SigChld(ChldCode::Dumped), +// 4 => SigCode::SigChld(ChldCode::Trapped), +// 5 => SigCode::SigChld(ChldCode::Stopped), +// 6 => SigCode::SigChld(ChldCode::Continued), +// _ => panic!("signal code not valid in {:?}", signal), +// }, +// // 对于其他信号,尝试匹配通用码 +// _ => match code { +// 0 => SigCode::Origin(OriginCode::User), +// 0x80 => SigCode::Origin(OriginCode::Kernel), +// -1 => SigCode::Origin(OriginCode::Queue), +// -2 => SigCode::Origin(OriginCode::Timer), +// -3 => SigCode::Origin(OriginCode::Mesgq), +// -4 => SigCode::Origin(OriginCode::AsyncIO), +// -5 => SigCode::Origin(OriginCode::SigIO), +// _ => panic!("signal code not valid in {:?}", signal), +// }, +// } +// } +// } bitflags! { #[repr(C,align(8))] @@ -584,7 +584,7 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { if ProcessManager::current_pcb() .sighand() .flags_contains(SignalFlags::UNKILLABLE) - && !sig_number.kernel_only() + && !sig.kernel_only() { continue; } @@ -612,7 +612,7 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { // 注意!由于handle_signal里面可能会退出进程, // 因此这里需要检查清楚:上面所有的锁、arc指针都被释放了。否则会产生资源泄露的问题! let res: Result = - handle_signal(sig_number, &mut sigaction, &info.unwrap(), &oldset, frame); + handle_signal(sig, &mut sigaction, &info.unwrap(), &oldset, frame); compiler_fence(Ordering::SeqCst); if let Err(e) = res { if e != SystemError::EFAULT { diff --git a/kernel/src/arch/x86_64/mm/fault.rs b/kernel/src/arch/x86_64/mm/fault.rs index d6f873c5c..ae7036523 100644 --- a/kernel/src/arch/x86_64/mm/fault.rs +++ b/kernel/src/arch/x86_64/mm/fault.rs @@ -9,12 +9,12 @@ use x86::{bits64::rflags::RFlags, controlregs::Cr4}; use crate::{ arch::{ interrupt::{trap::X86PfErrorCode, TrapFrame}, - ipc::signal::{OriginCode, SigCode, Signal}, + ipc::signal::Signal, mm::{MemoryManagementArch, X86_64MMArch}, CurrentIrqArch, MMArch, }, exception::{extable::ExceptionTableManager, InterruptArch}, - ipc::signal_types::{SigCode, SigInfo, SigType}, + ipc::signal_types::{OriginCode, SigCode, SigInfo, SigType}, mm::{ fault::{FaultFlags, PageFaultHandler, PageFaultMessage}, ucontext::{AddressSpace, LockedVMA}, diff --git a/kernel/src/ipc/kill.rs b/kernel/src/ipc/kill.rs index ae2cd7274..1860d33ce 100644 --- a/kernel/src/ipc/kill.rs +++ b/kernel/src/ipc/kill.rs @@ -1,8 +1,10 @@ -use crate::arch::ipc::signal::{OriginCode, SigCode, Signal}; use crate::ipc::signal_types::{SigInfo, SigType}; use crate::process::pid::{Pid, PidType}; use crate::process::{ProcessControlBlock, ProcessManager, RawPid}; -use crate::{arch::ipc::signal::Signal, ipc::signal_types::SigCode}; +use crate::{ + arch::ipc::signal::Signal, + ipc::signal_types::{OriginCode, SigCode}, +}; use alloc::sync::Arc; use core::sync::atomic::compiler_fence; use system_error::SystemError; diff --git a/kernel/src/ipc/pipe.rs b/kernel/src/ipc/pipe.rs index 596ecb264..3d58c9e61 100644 --- a/kernel/src/ipc/pipe.rs +++ b/kernel/src/ipc/pipe.rs @@ -1,5 +1,5 @@ use crate::{ - arch::ipc::signal::{OriginCode, SigCode, Signal}, + arch::ipc::signal::Signal, filesystem::{ epoll::{ event_poll::{EventPoll, LockedEPItemLinkedList}, @@ -10,7 +10,7 @@ use crate::{ FileSystem, FileType, IndexNode, Metadata, PollableInode, }, }, - ipc::signal_types::SigCode, + ipc::signal_types::{OriginCode, SigCode}, libs::{ spinlock::{SpinLock, SpinLockGuard}, wait_queue::WaitQueue, diff --git a/kernel/src/ipc/signal.rs b/kernel/src/ipc/signal.rs index 87c013e51..8968f91de 100644 --- a/kernel/src/ipc/signal.rs +++ b/kernel/src/ipc/signal.rs @@ -8,8 +8,8 @@ use log::warn; use system_error::SystemError; use crate::{ - arch::ipc::signal::{OriginCode, SigCode, SigFlags, SigSet, Signal}, - ipc::signal_types::SigactionType, + arch::ipc::signal::{SigFlags, SigSet, Signal}, + ipc::signal_types::{OriginCode, SigCode, SigactionType}, mm::VirtAddr, process::{ pid::PidType, ProcessControlBlock, ProcessFlags, ProcessManager, ProcessSignalInfo, RawPid, @@ -195,9 +195,6 @@ impl Signal { // ===== 寻找需要wakeup的目标进程 ===== // 备注:由于当前没有进程组的概念,每个进程只有1个对应的线程,因此不需要通知进程组内的每个进程。 // todo: 当引入进程组的概念后,需要完善这里,使得它能寻找一个目标进程来唤醒,接着执行信号处理的操作。 - - // let _signal = pcb.sig_struct(); - let target_pcb: Option>; // 无论目标进程当前是否屏蔽该信号,均应当将其标记为 pending diff --git a/kernel/src/ipc/signal_types.rs b/kernel/src/ipc/signal_types.rs index e31fdbe70..9f31f5408 100644 --- a/kernel/src/ipc/signal_types.rs +++ b/kernel/src/ipc/signal_types.rs @@ -7,7 +7,7 @@ use crate::{ arch::{ asm::bitops::ffz, interrupt::TrapFrame, - ipc::signal::{OriginCode, SigCode, SigFlags, SigSet, Signal, MAX_SIG_NUM}, + ipc::signal::{SigFlags, SigSet, Signal, MAX_SIG_NUM}, }, mm::VirtAddr, process::{ProcessManager, RawPid}, @@ -19,6 +19,25 @@ use crate::{ #[derive(Copy, Debug, Clone)] #[repr(i32)] pub enum SigCode { + /// 描述通用来源 + Origin(OriginCode), + /// 描述 SIGCHLD 的具体原因 + SigChld(ChldCode), +} + +impl From for i32 { + fn from(code: SigCode) -> i32 { + match code { + SigCode::Origin(origin) => origin as i32, + SigCode::SigChld(chld) => chld as i32, + } + } +} + +/// 信号的通用来源码 (SI_*) +#[derive(Copy, Debug, Clone, PartialEq, Eq)] +#[repr(i32)] +pub enum OriginCode { /// sent by kill, sigsend, raise User = 0, /// sent by kernel from somewhere @@ -37,20 +56,43 @@ pub enum SigCode { Tkill = -6, } +/// SIGCHLD 专用原因码 (CLD_*) +#[derive(Copy, Debug, Clone, PartialEq, Eq)] +#[repr(i32)] +pub enum ChldCode { + Exited = 1, + Killed = 2, + Dumped = 3, + Trapped = 4, + Stopped = 5, + Continued = 6, +} + impl SigCode { /// 为SigCode这个枚举类型实现从i32转换到枚举类型的转换函数 #[allow(dead_code)] - pub fn from_i32(x: i32) -> SigCode { - match x { - 0 => Self::User, - 0x80 => Self::Kernel, - -1 => Self::Queue, - -2 => Self::Timer, - -3 => Self::Mesgq, - -4 => Self::AsyncIO, - -5 => Self::SigIO, - -6 => Self::Tkill, - _ => panic!("signal code not valid"), + pub fn from_i32(signal: Signal, code: i32) -> SigCode { + match signal { + Signal::SIGCHLD => match code { + 1 => SigCode::SigChld(ChldCode::Exited), + 2 => SigCode::SigChld(ChldCode::Killed), + 3 => SigCode::SigChld(ChldCode::Dumped), + 4 => SigCode::SigChld(ChldCode::Trapped), + 5 => SigCode::SigChld(ChldCode::Stopped), + 6 => SigCode::SigChld(ChldCode::Continued), + _ => panic!("signal code not valid in {:?}", signal), + }, + // 对于其他信号,尝试匹配通用码 + _ => match code { + 0 => SigCode::Origin(OriginCode::User), + 0x80 => SigCode::Origin(OriginCode::Kernel), + -1 => SigCode::Origin(OriginCode::Queue), + -2 => SigCode::Origin(OriginCode::Timer), + -3 => SigCode::Origin(OriginCode::Mesgq), + -4 => SigCode::Origin(OriginCode::AsyncIO), + -5 => SigCode::Origin(OriginCode::SigIO), + _ => panic!("signal code not valid in {:?}", signal), + }, } } } @@ -415,8 +457,8 @@ impl SigInfo { match self.sig_type { SigType::Kill(pid) => PosixSigInfo { si_signo: self.sig_no, + si_code: i32::from(self.sig_code), si_errno: self.errno, - si_code: self.sig_code as i32, _sifields: PosixSiginfoFields { _kill: PosixSiginfoKill { si_pid: pid.data() as i32, @@ -426,8 +468,8 @@ impl SigInfo { }, SigType::Alarm(pid) => PosixSigInfo { si_signo: self.sig_no, + si_code: i32::from(self.sig_code), si_errno: self.errno, - si_code: self.sig_code as i32, _sifields: PosixSiginfoFields { _timer: PosixSiginfoTimer { si_tid: pid.data() as i32, @@ -439,6 +481,8 @@ impl SigInfo { }, }, }, + SigType::SigFault(sig_fault_info) => todo!(), + SigType::SigChld(sig_chld_info) => todo!(), } } diff --git a/kernel/src/ipc/syscall/sys_restart.rs b/kernel/src/ipc/syscall/sys_restart.rs index c95385b87..cc76bd0fd 100644 --- a/kernel/src/ipc/syscall/sys_restart.rs +++ b/kernel/src/ipc/syscall/sys_restart.rs @@ -2,9 +2,9 @@ use super::super::signal_types::{SigInfo, SigType}; use crate::arch::interrupt::TrapFrame; use crate::{ alloc::vec::Vec, - arch::ipc::signal::{OriginCode, SigCode, Signal}, + arch::ipc::signal::Signal, arch::syscall::nr::SYS_RESTART_SYSCALL, - ipc::signal_types::SigCode, + ipc::signal_types::{OriginCode, SigCode}, process::{ProcessManager, RawPid}, syscall::table::{FormattedSyscallParam, Syscall}, }; diff --git a/kernel/src/ipc/syscall/sys_tkill.rs b/kernel/src/ipc/syscall/sys_tkill.rs index 2aab96ba0..62fb57639 100644 --- a/kernel/src/ipc/syscall/sys_tkill.rs +++ b/kernel/src/ipc/syscall/sys_tkill.rs @@ -8,7 +8,7 @@ use crate::syscall::table::FormattedSyscallParam; use crate::syscall::table::Syscall; use crate::{ arch::{ipc::signal::Signal, syscall::nr::SYS_TKILL}, - ipc::signal_types::SigCode, + ipc::signal_types::{OriginCode, SigCode}, process::{ProcessControlBlock, ProcessManager, RawPid}, }; use system_error::SystemError; @@ -169,7 +169,7 @@ fn send_signal_to_thread( let mut info = SigInfo::new( sig, 0, - SigCode::Tkill, // 使用SI_TKILL语义 + SigCode::Origin(OriginCode::Tkill), // 使用SI_TKILL语义 SigType::Kill(current_tgid), ); diff --git a/kernel/src/process/execve.rs b/kernel/src/process/execve.rs index 8f42a92a1..2edff1dd1 100644 --- a/kernel/src/process/execve.rs +++ b/kernel/src/process/execve.rs @@ -1,8 +1,10 @@ -use crate::arch::ipc::signal::{ChldCode, SigCode, Signal}; +use crate::arch::ipc::signal::Signal; use crate::arch::CurrentIrqArch; use crate::exception::InterruptArch; use crate::filesystem::vfs::IndexNode; -use crate::ipc::signal_types::{SigChldInfo, SigFaultInfo, SigInfo, SigType, SignalFlags}; +use crate::ipc::signal_types::{ + ChldCode, SigChldInfo, SigCode, SigFaultInfo, SigInfo, SigType, SignalFlags, +}; use crate::process::exec::{load_binary_file, ExecParam, ExecParamFlags}; use crate::process::PtraceEvent; use crate::process::{ProcessFlags, ProcessManager}; diff --git a/kernel/src/process/ptrace.rs b/kernel/src/process/ptrace.rs index aaa826711..78d6e1fa6 100644 --- a/kernel/src/process/ptrace.rs +++ b/kernel/src/process/ptrace.rs @@ -1,10 +1,11 @@ use crate::arch::interrupt::TrapFrame; -use crate::arch::ipc::signal::{ChldCode, OriginCode, SigCode, SigFlags, Signal}; +use crate::arch::ipc::signal::{SigFlags, Signal}; use crate::arch::kprobe; use crate::arch::CurrentIrqArch; use crate::exception::InterruptArch; use crate::ipc::signal_types::{ - SigChldInfo, SigFaultInfo, SigInfo, SigType, Sigaction, SigactionType, SignalFlags, + ChldCode, OriginCode, SigChldInfo, SigCode, SigFaultInfo, SigInfo, SigType, Sigaction, + SigactionType, SignalFlags, }; use crate::process::{ ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState, PtraceEvent, PtraceOptions, @@ -84,16 +85,16 @@ pub fn do_notify_parent(child: &ProcessControlBlock, signal: Signal) -> Result Date: Sun, 4 Jan 2026 22:59:44 +0800 Subject: [PATCH 04/15] rebase 2 master --- kernel/src/arch/x86_64/ipc/signal.rs | 10 ++++----- kernel/src/ipc/generic_signal.rs | 3 +-- .../src/ipc/syscall/sys_pidfd_sendsignal.rs | 4 ++-- kernel/src/process/execve.rs | 4 ++-- kernel/src/process/exit.rs | 4 ++-- kernel/src/process/mod.rs | 2 +- kernel/src/process/ptrace.rs | 15 ++++++++++--- kernel/src/process/syscall/sys_ptrace.rs | 21 +++++++++++++++++++ 8 files changed, 46 insertions(+), 17 deletions(-) diff --git a/kernel/src/arch/x86_64/ipc/signal.rs b/kernel/src/arch/x86_64/ipc/signal.rs index fa382531e..270084693 100644 --- a/kernel/src/arch/x86_64/ipc/signal.rs +++ b/kernel/src/arch/x86_64/ipc/signal.rs @@ -537,10 +537,10 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { } // 对 kernel-only 信号(如 SIGKILL/SIGSTOP)直接使用默认处理,避免任何用户帧构造 - if sig_number.kernel_only() { + if sig.kernel_only() { // log::error!( // "do_signal: kernel-only sig={} for pid={:?} -> default handler (no user frame)", - // sig_number as i32, + // sig as i32, // pcb.raw_pid() // ); // 释放锁,按常规路径在本线程上下文执行默认处理 @@ -548,10 +548,10 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { drop(siginfo_mut_guard); drop(pcb); CurrentIrqArch::interrupt_enable(); - sig_number.handle_default(); + sig.handle_default(); return; } - let sa = pcb.sighand().handler(sig_number).unwrap(); + let sa = pcb.sighand().handler(sig).unwrap(); match sa.action() { SigactionType::SaHandler(action_type) => match action_type { @@ -618,7 +618,7 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { if e != SystemError::EFAULT { error!( "Error occurred when handling signal: {}, pid={:?}, errcode={:?}", - sig_number as i32, + sig as i32, ProcessManager::current_pcb().raw_pid(), &e ); diff --git a/kernel/src/ipc/generic_signal.rs b/kernel/src/ipc/generic_signal.rs index ddbb53c29..854013ca7 100644 --- a/kernel/src/ipc/generic_signal.rs +++ b/kernel/src/ipc/generic_signal.rs @@ -12,7 +12,6 @@ use crate::{ process::{ptrace::handle_ptrace_signal_stop, ProcessFlags, ProcessManager}, sched::{schedule, SchedMode}, }; -use num_traits::FromPrimitive; /// 信号处理的栈的栈指针的最小对齐 #[allow(dead_code)] @@ -435,7 +434,7 @@ fn sig_stop(sig: Signal) { pcb.sighand().flags_insert(SignalFlags::STOP_STOPPED); if pcb.flags().contains(ProcessFlags::PTRACED) { log::debug!("sig_stop"); - handle_ptrace_signal_stop(¤t_pcb, sig); + handle_ptrace_signal_stop(&pcb, sig); } } ProcessManager::mark_stop(sig).unwrap_or_else(|e| { diff --git a/kernel/src/ipc/syscall/sys_pidfd_sendsignal.rs b/kernel/src/ipc/syscall/sys_pidfd_sendsignal.rs index 214bf19c7..cd3b45a73 100644 --- a/kernel/src/ipc/syscall/sys_pidfd_sendsignal.rs +++ b/kernel/src/ipc/syscall/sys_pidfd_sendsignal.rs @@ -1,5 +1,5 @@ use crate::arch::ipc::signal::Signal; -use crate::ipc::signal_types::SigCode; +use crate::ipc::signal_types::{OriginCode, SigCode}; use crate::ipc::signal_types::{SigInfo, SigType}; use alloc::string::ToString; use alloc::vec::Vec; @@ -66,7 +66,7 @@ impl Syscall for SysPidfdSendSignalHandle { let mut info = SigInfo::new( sig, 0, - SigCode::User, + SigCode::Origin(OriginCode::User), SigType::Kill(RawPid::new(pid as usize)), ); diff --git a/kernel/src/process/execve.rs b/kernel/src/process/execve.rs index 2edff1dd1..636e0ab6f 100644 --- a/kernel/src/process/execve.rs +++ b/kernel/src/process/execve.rs @@ -64,7 +64,7 @@ pub fn do_execve( // execve 成功后,如果是 vfork 创建的子进程,需要通知父进程继续执行 // 在通知父进程之前,必须先清除 vfork_done,防止子进程退出时再次通知 - let pcb = ProcessManager::pcb(); + let pcb = ProcessManager::current_pcb(); let vfork_done = pcb.thread.write_irqsave().vfork_done.take(); if let Some(completion) = vfork_done { @@ -123,7 +123,7 @@ pub fn do_execve( fn do_execve_switch_user_vm(new_vm: Arc) -> Option> { // 关中断,防止在设置地址空间的时候,发生中断,然后进调度器,出现错误。 let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; - let pcb = ProcessManager::pcb(); + let pcb = ProcessManager::current_pcb(); // log::debug!( // "pid: {:?} do_execve: path: {:?}, argv: {:?}, envp: {:?}\n", // pcb.pid(), diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs index a4a679255..e7f900ee4 100644 --- a/kernel/src/process/exit.rs +++ b/kernel/src/process/exit.rs @@ -296,7 +296,7 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { all_children_exited = false; } - if matches!(state, ProcessState::Stopped) + if matches!(state, ProcessState::Stopped(_)) && kwo.options.contains(WaitOption::WSTOPPED) && pcb.sighand().flags_contains(SignalFlags::CLD_STOPPED) { @@ -393,7 +393,7 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { all_children_exited = false; } - if matches!(state, ProcessState::Stopped) + if matches!(state, ProcessState::Stopped(_)) && kwo.options.contains(WaitOption::WSTOPPED) && pcb.sighand().flags_contains(SignalFlags::CLD_STOPPED) { diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 767952e35..582f9a0b2 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -320,7 +320,7 @@ impl ProcessManager { let mut writer = pcb.sched_info().inner_lock_write_irqsave(); let state = writer.state(); if !matches!(state, ProcessState::Exited(_)) { - writer.set_state(ProcessState::Stopped); + writer.set_state(ProcessState::Stopped(0)); pcb.flags().insert(ProcessFlags::NEED_SCHEDULE); drop(writer); return Ok(()); diff --git a/kernel/src/process/ptrace.rs b/kernel/src/process/ptrace.rs index 78d6e1fa6..aa2d50017 100644 --- a/kernel/src/process/ptrace.rs +++ b/kernel/src/process/ptrace.rs @@ -94,7 +94,10 @@ pub fn do_notify_parent(child: &ProcessControlBlock, signal: Signal) -> Result, + request: PtraceRequest, + ) -> Result<(), SystemError> { + let current = ProcessManager::current_pcb(); + + if !tracee.is_traced_by(¤t) { + return Err(SystemError::EPERM); + } + // 对于 KILL 请求,不需要目标处于停止状态 (Linux 逻辑) + // 这里我们简化逻辑,要求必须 Stopped + match tracee.sched_info().inner_lock_read_irqsave().state() { + ProcessState::Stopped(_) | ProcessState::TracedStopped => Ok(()), + _ => { + // 如果请求是 KILL,Linux 允许不停止,但这里我们先严格要求 + log::debug!("ptrace_check_attach: process not stopped"); + Err(SystemError::ESRCH) + } + } + } } impl Syscall for SysPtrace { From ac4da9515a9e1827b02fa707eb821c9756a0f437 Mon Sep 17 00:00:00 2001 From: aLinChe <1129332011@qq.com> Date: Tue, 6 Jan 2026 13:08:46 +0800 Subject: [PATCH 05/15] update Signed-off-by: aLinChe <1129332011@qq.com> --- kernel/src/arch/x86_64/mm/fault.rs | 7 ++- kernel/src/filesystem/procfs/pid/stat.rs | 3 +- kernel/src/ipc/kill.rs | 2 +- kernel/src/ipc/pipe.rs | 2 +- kernel/src/ipc/sighand.rs | 10 ++-- kernel/src/ipc/signal.rs | 14 +++-- kernel/src/ipc/signal_types.rs | 56 +++++++++++++------ kernel/src/ipc/syscall/sys_rt_sigqueueinfo.rs | 14 +++-- kernel/src/process/exit.rs | 10 ++-- kernel/src/process/mod.rs | 10 +--- kernel/src/process/posix_timer.rs | 4 +- kernel/src/process/ptrace.rs | 25 ++++++--- 12 files changed, 98 insertions(+), 59 deletions(-) diff --git a/kernel/src/arch/x86_64/mm/fault.rs b/kernel/src/arch/x86_64/mm/fault.rs index 5a2a711b2..948d3ac57 100644 --- a/kernel/src/arch/x86_64/mm/fault.rs +++ b/kernel/src/arch/x86_64/mm/fault.rs @@ -282,7 +282,10 @@ impl X86_64MMArch { Signal::SIGSEGV, 0, SigCode::Origin(OriginCode::User), - SigType::Kill(pid), + SigType::Kill { + pid: ProcessManager::current_pid(), + uid: ProcessManager::current_pcb().cred().uid.data() as u32, + }, ); Signal::SIGSEGV .send_signal_info(Some(&mut info), pid) @@ -472,7 +475,7 @@ impl X86_64MMArch { let mut info = SigInfo::new( sig, 0, - SigCode::User, + SigCode::Origin(OriginCode::User), SigType::Kill { pid: ProcessManager::current_pid(), uid: ProcessManager::current_pcb().cred().uid.data() as u32, diff --git a/kernel/src/filesystem/procfs/pid/stat.rs b/kernel/src/filesystem/procfs/pid/stat.rs index 26751443b..e5cbbf782 100644 --- a/kernel/src/filesystem/procfs/pid/stat.rs +++ b/kernel/src/filesystem/procfs/pid/stat.rs @@ -48,8 +48,9 @@ fn state_to_linux_char(state: ProcessState) -> char { 'D' } } - ProcessState::Stopped => 'T', + ProcessState::Stopped(_) => 'T', ProcessState::Exited(_) => 'Z', + _ => 'X', } } diff --git a/kernel/src/ipc/kill.rs b/kernel/src/ipc/kill.rs index 773c66466..922cee4d9 100644 --- a/kernel/src/ipc/kill.rs +++ b/kernel/src/ipc/kill.rs @@ -103,7 +103,7 @@ pub fn send_signal_to_pgid(pgid: &Arc, sig: Signal) -> Result SigCode { + pub fn try_from_i32(x: i32) -> Option { match x { - 0 => Self::User, - 0x80 => Self::Kernel, - -1 => Self::Queue, - -2 => Self::Timer, - -3 => Self::Mesgq, - -4 => Self::AsyncIO, - -5 => Self::SigIO, - -6 => Self::Tkill, - _ => panic!("signal code not valid"), + 0 => Some(Self::Origin(OriginCode::User)), + 0x80 => Some(Self::Origin(OriginCode::Kernel)), + -1 => Some(Self::Origin(OriginCode::Queue)), + -2 => Some(Self::Origin(OriginCode::Timer)), + -3 => Some(Self::Origin(OriginCode::Mesgq)), + -4 => Some(Self::Origin(OriginCode::AsyncIO)), + -5 => Some(Self::Origin(OriginCode::SigIO)), + -6 => Some(Self::Origin(OriginCode::Tkill)), + _ => None, } } } @@ -571,7 +569,7 @@ impl SigInfo { } => PosixSigInfo { si_signo: self.sig_no, si_errno: self.errno, - si_code: i32::from(self.sig_code), + si_code: i32::from(self.sig_code), _sifields: PosixSiginfoFields { _timer: PosixSiginfoTimer { si_tid: timerid, @@ -622,9 +620,20 @@ pub enum SigType { sigval: PosixSigval, }, Alarm(RawPid), + /// POSIX interval timer 发送的信号(SI_TIMER)。 + /// - `timerid`: 对应用户态 `siginfo_t::si_timerid` + /// - `overrun`: 对应用户态 `siginfo_t::si_overrun` + /// - `sigval`: 对应用户态 `siginfo_t::si_value` + PosixTimer { + timerid: i32, + overrun: i32, + sigval: PosixSigval, + }, // 后续完善下列中的具体字段 // Timer, // Rt, + SigFault(SigFaultInfo), + SigChld(SigChldInfo), // SigPoll, // SigSys, } @@ -685,7 +694,7 @@ impl SigPending { for info in self.queue.q.iter_mut() { // bump(0) 作为“匹配探测”,不会改变值 if info.is_signal(sig) - && info.sig_code() == SigCode::Timer + && info.sig_code() == SigCode::Origin(OriginCode::Timer) && info.bump_posix_timer_overrun(timerid, 0) { return true; @@ -698,7 +707,7 @@ impl SigPending { pub fn posix_timer_bump_overrun(&mut self, sig: Signal, timerid: i32, bump: i32) -> bool { for info in self.queue.q.iter_mut() { if info.is_signal(sig) - && info.sig_code() == SigCode::Timer + && info.sig_code() == SigCode::Origin(OriginCode::Timer) && info.bump_posix_timer_overrun(timerid, bump) { return true; @@ -711,7 +720,7 @@ impl SigPending { pub fn posix_timer_reset_overrun(&mut self, sig: Signal, timerid: i32) -> bool { for info in self.queue.q.iter_mut() { if info.is_signal(sig) - && info.sig_code() == SigCode::Timer + && info.sig_code() == SigCode::Origin(OriginCode::Timer) && info.reset_posix_timer_overrun(timerid) { return true; @@ -763,8 +772,19 @@ impl SigPending { return info; } else { // 信号不在sigqueue中,这意味着当前信号是来自快速路径,因此直接把siginfo设置为0即可。 - let mut ret = SigInfo::new(sig, 0, SigCode::User, SigType::Kill(RawPid::from(0))); - ret.set_sig_type(SigType::Kill(RawPid::new(0))); + let mut ret = SigInfo::new( + sig, + 0, + SigCode::Origin(OriginCode::User), + SigType::Kill { + pid: RawPid::new(0), + uid: 0, + }, + ); + ret.set_sig_type(SigType::Kill { + pid: RawPid::new(0), + uid: 0, + }); return ret; } } diff --git a/kernel/src/ipc/syscall/sys_rt_sigqueueinfo.rs b/kernel/src/ipc/syscall/sys_rt_sigqueueinfo.rs index e289f1f7e..a108c58b4 100644 --- a/kernel/src/ipc/syscall/sys_rt_sigqueueinfo.rs +++ b/kernel/src/ipc/syscall/sys_rt_sigqueueinfo.rs @@ -5,7 +5,7 @@ use core::mem::size_of; use crate::arch::interrupt::TrapFrame; use crate::arch::syscall::nr::SYS_RT_SIGQUEUEINFO; -use crate::ipc::signal_types::{PosixSigInfo, SigCode, SigInfo, SigType}; +use crate::ipc::signal_types::{OriginCode, PosixSigInfo, SigCode, SigInfo, SigType}; use crate::ipc::syscall::sys_kill::check_signal_permission_pcb_with_sig; use crate::process::pid::PidType; use crate::syscall::table::{FormattedSyscallParam, Syscall}; @@ -83,16 +83,18 @@ impl Syscall for SysRtSigqueueinfoHandle { // Linux 6.6: do_rt_sigqueueinfo 权限校验 let si_code = user_info.si_code; - if (si_code >= 0 || si_code == (SigCode::Tkill as i32)) && current_pid != target_pid { + if (si_code >= 0 || si_code == (SigCode::Origin(OriginCode::Tkill)).into()) + && current_pid != target_pid + { return Err(SystemError::EPERM); } // 解析 si_code(未知 code:尽量保持“来自用户态(负值)”的语义,不 panic) let code_enum = SigCode::try_from_i32(si_code).unwrap_or({ if si_code < 0 { - SigCode::Queue + SigCode::Origin(OriginCode::Queue) } else { - SigCode::User + SigCode::Origin(OriginCode::User) } }); @@ -101,7 +103,7 @@ impl Syscall for SysRtSigqueueinfoHandle { // 根据信号来源/布局构造内核 SigInfo let sig_type = match code_enum { - SigCode::Queue => { + SigCode::Origin(OriginCode::Queue) => { let sigval = unsafe { user_info._sifields._rt.si_sigval }; SigType::Rt { pid: sender_pid, @@ -109,7 +111,7 @@ impl Syscall for SysRtSigqueueinfoHandle { sigval, } } - SigCode::Timer => { + SigCode::Origin(OriginCode::Timer) => { let timer = unsafe { user_info._sifields._timer }; SigType::PosixTimer { timerid: timer.si_tid, diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs index a872e0eea..bebaaa004 100644 --- a/kernel/src/process/exit.rs +++ b/kernel/src/process/exit.rs @@ -642,12 +642,12 @@ fn do_waitpid( // 而不是立即返回0。只有当子进程真正退出时才应该返回。 return None; } - ProcessState::Stopped(stop_signal) => { + ProcessState::Stopped(stopsig) => { // todo: 在stopped里面,添加code字段,表示停止的原因 - if stop_signal <= 0 || stop_signal >= Signal::SIGRTMAX.into() { + if stopsig <= 0 || stopsig >= Signal::SIGRTMAX.into() { return Some(Err(SystemError::EINVAL)); } - let stop_signal = stop_signal as i32; + let stopsig = stopsig as i32; let ptrace = child_pcb.is_traced(); // 对于被跟踪的进程,总是报告停止状态,无论 WUNTRACED 是否设置 // 对于非跟踪进程,只有在设置了 WUNTRACED 时才报告停止状态 @@ -657,12 +657,12 @@ fn do_waitpid( return None; } if likely(!(kwo.options.contains(WaitOption::WNOWAIT))) { - kwo.ret_status = (stop_signal << 8) | 0x7f; + kwo.ret_status = (stopsig << 8) | 0x7f; } // if let Some(infop) = &mut kwo.ret_info { // *infop = WaitIdInfo { // pid: child_pcb.raw_pid(), - // status: stop_signal, + // status: stopsig, // cause: SigChildCode::Stopped.into(), // }; // } diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 910ac594c..c5c23939b 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -1,4 +1,5 @@ use alloc::{ + ffi::CString, string::{String, ToString}, sync::{Arc, Weak}, vec::Vec, @@ -7,18 +8,11 @@ use core::{ fmt, hash::Hash, hint::spin_loop, - intrinsics::{likely, unlikely}, + intrinsics::unlikely, mem::{ManuallyDrop, MaybeUninit}, str::FromStr, sync::atomic::{compiler_fence, fence, AtomicBool, AtomicU8, AtomicUsize, Ordering}, }; - -use alloc::{ - ffi::CString, - string::{String, ToString}, - sync::{Arc, Weak}, - vec::Vec, -}; use cred::INIT_CRED; use hashbrown::HashMap; use log::{debug, error, info, warn}; diff --git a/kernel/src/process/posix_timer.rs b/kernel/src/process/posix_timer.rs index 7b17c95bb..48d008ba3 100644 --- a/kernel/src/process/posix_timer.rs +++ b/kernel/src/process/posix_timer.rs @@ -14,7 +14,7 @@ use system_error::SystemError; use crate::{ arch::ipc::signal::Signal, - ipc::signal_types::{PosixSigval, SigCode, SigInfo, SigType}, + ipc::signal_types::{OriginCode, PosixSigval, SigCode, SigInfo, SigType}, process::{pid::PidType, ProcessControlBlock, ProcessFlags, ProcessManager, RawPid}, time::{ jiffies::NSEC_PER_JIFFY, @@ -445,7 +445,7 @@ impl TimerFunction for PosixTimerHelper { let info = SigInfo::new( signo, 0, - SigCode::Timer, + SigCode::Origin(OriginCode::Timer), SigType::PosixTimer { timerid: self.timerid, overrun, diff --git a/kernel/src/process/ptrace.rs b/kernel/src/process/ptrace.rs index aa2d50017..24bd26876 100644 --- a/kernel/src/process/ptrace.rs +++ b/kernel/src/process/ptrace.rs @@ -7,6 +7,7 @@ use crate::ipc::signal_types::{ ChldCode, OriginCode, SigChldInfo, SigCode, SigFaultInfo, SigInfo, SigType, Sigaction, SigactionType, SignalFlags, }; +use crate::process::pid::PidType; use crate::process::{ ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState, PtraceEvent, PtraceOptions, PtraceRequest, PtraceStopReason, PtraceSyscallInfo, PtraceSyscallInfoData, @@ -63,7 +64,7 @@ pub fn ptrace_signal( .contains(injected_signal.into()) { // 如果被阻塞了,则将信号重新排队,让它在未来被处理。 - injected_signal.send_signal_info_to_pcb(info.as_mut(), Arc::clone(pcb)); + injected_signal.send_signal_info_to_pcb(info.as_mut(), Arc::clone(pcb), PidType::PID); // 告诉 get_signal,当前没有需要立即处理的信号。 return None; } @@ -117,7 +118,7 @@ pub fn do_notify_parent(child: &ProcessControlBlock, signal: Signal) -> Result Date: Sat, 10 Jan 2026 18:03:40 +0800 Subject: [PATCH 06/15] feat traceme attach/detach Signed-off-by: aLinChe <1129332011@qq.com> --- kernel/src/arch/x86_64/ipc/signal.rs | 158 ++++- kernel/src/arch/x86_64/syscall/mod.rs | 111 ++- kernel/src/exception/entry.rs | 21 +- kernel/src/ipc/generic_signal.rs | 50 +- kernel/src/ipc/kill.rs | 27 +- kernel/src/ipc/signal.rs | 211 +++++- kernel/src/ipc/syscall/sys_kill.rs | 16 + kernel/src/libs/printk.rs | 6 + kernel/src/process/exit.rs | 160 ++++- kernel/src/process/fork.rs | 20 + kernel/src/process/mod.rs | 299 ++++++-- kernel/src/process/ptrace.rs | 702 ++++++++++++++++--- kernel/src/process/syscall/sys_exit_group.rs | 12 +- kernel/src/process/syscall/sys_getpid.rs | 9 + kernel/src/process/syscall/sys_ptrace.rs | 268 ++++++- user/apps/c_unitest/test_ptrace.c | 27 + 16 files changed, 1860 insertions(+), 237 deletions(-) diff --git a/kernel/src/arch/x86_64/ipc/signal.rs b/kernel/src/arch/x86_64/ipc/signal.rs index f12fa5b90..7cbbfd1c0 100644 --- a/kernel/src/arch/x86_64/ipc/signal.rs +++ b/kernel/src/arch/x86_64/ipc/signal.rs @@ -697,11 +697,77 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { // 如果信号非法,则直接返回 if sig == Signal::INVALID { + log::debug!("[DO_SIGNAL] PID {} no more signals, returning", pcb.raw_pid()); return; } + log::debug!( + "[DO_SIGNAL] PID {} dequeued signal {:?}, PTRACED={}", + pcb.raw_pid(), + sig, + pcb.flags().contains(ProcessFlags::PTRACED) + ); + + // 按照 Linux 6.6.21 的实现: + // 在处理信号之前,如果进程被 ptrace,先调用 ptrace_signal + // ptrace_signal 会让进程停止并等待 tracer 的指令 + // + // 重要:在调用 ptrace_signal 之前必须释放 siginfo_mut_guard 锁 + // 因为 ptrace_stop 内部会调用 schedule(),要求 preempt_count = 0 + // 而 siginfo_mut_guard 持有锁时 preempt_count = 1 + // 按照 Linux 的做法,ptrace_stop 会在内部释放 sighand->siglock, + // 然后在返回前重新获取它(__releases/__acquires 标注) + if pcb.flags().contains(ProcessFlags::PTRACED) { + log::debug!( + "[DO_SIGNAL] PID {} is PTRACED, calling ptrace_signal for {:?}", + pcb.raw_pid(), + sig + ); + + // 保存当前需要的信息 + let _sig_blocked_cache = *siginfo_mut_guard.sig_blocked(); + + // 在调用 ptrace_signal 前释放锁 + drop(siginfo_mut_guard); + + // ptrace_signal 会调用 ptrace_stop 让进程停止 + // 返回需要继续处理的信号(可能被 tracer 修改或取消) + let handled_sig = ptrace_signal(&pcb, sig, &mut info); + + // 重新获取锁 + siginfo_mut_guard = pcb.try_siginfo_mut(5).unwrap(); + + if let Some(handled_sig) = handled_sig { + // tracer 可能注入了新的信号或修改了原信号 + log::debug!( + "[DO_SIGNAL] PID {} ptrace_signal returned {:?}", + pcb.raw_pid(), + handled_sig + ); + sig = handled_sig; + } else { + // 信号被 ptrace 取消或重新排队,继续处理下一个信号 + log::debug!( + "[DO_SIGNAL] PID {} signal was cancelled by ptrace, continuing loop", + pcb.raw_pid() + ); + continue; + } + } + + log::debug!( + "[DO_SIGNAL] PID {} processing signal {:?}, checking if kernel_only", + pcb.raw_pid(), + sig + ); + // 对 kernel-only 信号(如 SIGKILL/SIGSTOP)直接使用默认处理,避免任何用户帧构造 if sig.kernel_only() { + log::debug!( + "[DO_SIGNAL] PID {} signal {:?} is kernel_only, calling handle_default", + pcb.raw_pid(), + sig + ); // log::error!( // "do_signal: kernel-only sig={} for pid={:?} -> default handler (no user frame)", // sig as i32, @@ -715,8 +781,21 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { sig.handle_default(); return; } + + log::debug!( + "[DO_SIGNAL] PID {} getting sigaction for signal {:?}", + pcb.raw_pid(), + sig + ); let sa = pcb.sighand().handler(sig).unwrap(); + log::debug!( + "[DO_SIGNAL] PID {} signal {:?} sigaction: {:?}", + pcb.raw_pid(), + sig, + sa.action() + ); + match sa.action() { SigactionType::SaHandler(action_type) => match action_type { SaHandlerType::Error => { @@ -766,10 +845,10 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { // 做完上面的检查后,开中断 CurrentIrqArch::interrupt_enable(); + log::debug!("[DO_SIGNAL] No signal action to handle, returning without setting up frame"); if sigaction.is_none() { return; } - *got_signal = true; let mut sigaction = sigaction.unwrap(); @@ -777,6 +856,25 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { // 因此这里需要检查清楚:上面所有的锁、arc指针都被释放了。否则会产生资源泄露的问题! let res: Result = handle_signal(sig, &mut sigaction, &info.unwrap(), &oldset, frame); + + // 只有当信号帧真正被设置时(即自定义处理器),才设置 got_signal = true + // 对于默认动作的信号(如 SIGCONT),handle_signal 会调用 handle_default() 并返回 Ok(0), + // 不会设置信号帧。在这种情况下,应该允许系统调用重启。 + if res.is_ok() { + match sigaction.action() { + SigactionType::SaHandler(SaHandlerType::Customized(_)) => { + *got_signal = true; + } + SigactionType::SaSigaction(_) => { + *got_signal = true; + } + _ => { + // Default 或 Ignore 动作不设置用户信号帧,got_signal 保持 false + log::debug!("[DO_SIGNAL] Default/Ignore action, got_signal remains false"); + } + } + } + compiler_fence(Ordering::SeqCst); if let Err(e) = res { if e != SystemError::EFAULT { @@ -796,16 +894,39 @@ fn try_restart_syscall(frame: &mut TrapFrame) { restore_saved_sigmask(); }); + let pcb = ProcessManager::current_pcb(); + let pid = pcb.raw_pid(); + // 关键修复:如果进程已经退出(例如处理了 SIGKILL 等致命信号),不重启系统调用 + let is_exited = pcb.sched_info().inner_lock_read_irqsave().state().is_exited(); + drop(pcb); + + if is_exited { + log::debug!("[TRY_RESTART] PID {}: already exited, not restarting syscall", pid); + return; + } + if unsafe { frame.syscall_nr() }.is_none() { + log::debug!("[TRY_RESTART] PID {}: no syscall, returning", pid); return; } + let syscall_nr = unsafe { frame.syscall_nr() }; + let rax_value = frame.rax; let syscall_err = unsafe { frame.syscall_error() }; if syscall_err.is_none() { + log::debug!("[TRY_RESTART] PID {}: no error, rax={:#x}, returning", pid, rax_value); return; } let syscall_err = syscall_err.unwrap(); + log::debug!( + "[TRY_RESTART] PID {}: syscall_nr={:?}, rax={:#x}, syscall_err={:?}", + pid, + syscall_nr, + rax_value, + syscall_err + ); + let mut restart = false; match syscall_err { SystemError::ERESTARTSYS | SystemError::ERESTARTNOHAND | SystemError::ERESTARTNOINTR => { @@ -820,7 +941,13 @@ fn try_restart_syscall(frame: &mut TrapFrame) { } _ => {} } - log::debug!("try restart syscall: {:?}", restart); + log::debug!( + "[TRY_RESTART] PID {}: restart={}, rip={:#x}, rax={:#x}", + pid, + restart, + frame.rip, + frame.rax + ); } pub struct X86_64SignalArch; @@ -830,12 +957,27 @@ impl SignalArch for X86_64SignalArch { /// /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/arch/x86/kernel/signal.c#865 unsafe fn do_signal_or_restart(frame: &mut TrapFrame) { + let pcb = ProcessManager::current_pcb(); + log::debug!("[DO_SIGNAL_OR_RESTART] PID {} entry, rip={:#x}, rsp={:#x}, state={:?}", + pcb.raw_pid(), frame.rip, frame.rsp, + pcb.sched_info().inner_lock_read_irqsave().state()); + drop(pcb); + let mut got_signal = false; do_signal(frame, &mut got_signal); + let pcb = ProcessManager::current_pcb(); + log::debug!("[DO_SIGNAL_OR_RESTART] PID {} after do_signal, got_signal={}, will_return_to_user={}", + pcb.raw_pid(), got_signal, frame.is_from_user()); + drop(pcb); + if got_signal { + log::debug!("[DO_SIGNAL_OR_RESTART] PID {} got_signal=true, NOT calling try_restart_syscall", + ProcessManager::current_pcb().raw_pid()); return; } + log::debug!("[DO_SIGNAL_OR_RESTART] PID {} got_signal=false, calling try_restart_syscall", + ProcessManager::current_pcb().raw_pid()); try_restart_syscall(frame); } @@ -899,7 +1041,17 @@ fn handle_signal( frame: &mut TrapFrame, ) -> Result { log::debug!("handle_signal {:?}", sig); - if unsafe { frame.syscall_nr() }.is_some() { + + // 只在真正设置信号帧时(即自定义处理器)才修改系统调用错误码 + // 对于 Default 动作的信号,setup_frame 不会设置信号帧,而是调用 handle_default() 直接返回 + // 此时应该保留原始错误码,让 try_restart_syscan 正确处理系统调用重启 + let is_custom_handler = matches!( + sigaction.action(), + SigactionType::SaHandler(SaHandlerType::Customized(_)) + | SigactionType::SaSigaction(_) + ); + + if is_custom_handler && unsafe { frame.syscall_nr() }.is_some() { if let Some(syscall_err) = unsafe { frame.syscall_error() } { match syscall_err { SystemError::ERESTARTNOHAND => { diff --git a/kernel/src/arch/x86_64/syscall/mod.rs b/kernel/src/arch/x86_64/syscall/mod.rs index 2710bea83..246bb4ed6 100644 --- a/kernel/src/arch/x86_64/syscall/mod.rs +++ b/kernel/src/arch/x86_64/syscall/mod.rs @@ -1,14 +1,14 @@ use crate::{ arch::{ - ipc::signal::X86_64SignalArch, + ipc::signal::{Signal, X86_64SignalArch}, syscall::nr::{SYS_ARCH_PRCTL, SYS_RT_SIGRETURN}, CurrentIrqArch, }, exception::InterruptArch, - ipc::signal_types::SignalArch, + ipc::signal_types::{OriginCode, SigCode, SigInfo, SigType, SignalArch}, libs::align::SafeForZero, mm::VirtAddr, - process::ProcessManager, + process::{ProcessFlags, ProcessManager}, syscall::{Syscall, SYS_SCHED}, }; use log::debug; @@ -56,6 +56,20 @@ macro_rules! syscall_return { debug!("syscall return:pid={:?},ret= {:?}\n", pid, ret as isize); } + // 系统调用返回前检查并处理信号 + // 这是 ptrace 和普通信号处理的关键入口 + // 如果 HAS_PENDING_SIGNAL 标志被设置,需要调用 do_signal_or_restart + let pcb = ProcessManager::current_pcb(); + if pcb.flags().contains(ProcessFlags::HAS_PENDING_SIGNAL) { + drop(pcb); + // 调用退出到用户态的处理流程,会检查并处理信号 + // irqentry_exit 会检查 is_from_user() 并调用 exit_to_user_mode_prepare + unsafe { crate::exception::entry::irqentry_exit($regs) }; + // irqentry_exit 已经处理了退出流程,直接返回 + return; + } + drop(pcb); + unsafe { CurrentIrqArch::interrupt_disable(); } @@ -100,6 +114,62 @@ pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) { debug!("syscall: pid: {:?}, num={:?}\n", pid, syscall_num); } + // 检查是否需要 ptrace syscall trace (系统调用入口) + let pcb = ProcessManager::current_pcb(); + let needs_syscall_trace = pcb + .flags() + .contains(ProcessFlags::PTRACED | ProcessFlags::TRACE_SYSCALL); + + if needs_syscall_trace { + // 按照 Linux 6.6.21 的 ptrace_report_syscall_entry 语义: + // 在系统调用入口停止,而不是在系统调用执行后停止 + // + // 实现方式: + // 1. 设置 ERESTARTNOHAND 错误码,让 try_restart_syscall 稍后重启 + // 2. 发送 SIGTRAP 给自己,触发 ptrace 停止 + // 3. 直接返回,不执行系统调用 + // 4. 当 ptrace_stop 返回后,try_restart_syscall 会将 rip -= 2 重新执行系统调用 + // 5. 第二次执行时,由于 needs_syscall_entry_stop 已被设置为 false,执行系统调用并在出口停止 + + let needs_entry_stop = pcb.needs_syscall_entry_stop(); + drop(pcb); + + if needs_entry_stop { + let pcb = ProcessManager::current_pcb(); + // 第一次进入:需要在系统调用入口停止 + // 保存系统调用信息 + pcb.on_syscall_entry(syscall_num, &args); + + // 设置重启条件:使用 ERESTARTNOHAND 让 try_restart_syscall 稍后重启 + frame.rax = system_error::SystemError::ERESTARTNOHAND.to_posix_errno() as u64; + // errcode 已经保存了原始系统调用号(line 69) + + // 标记已经完成入口停止,下次通过时将执行系统调用 + pcb.set_needs_syscall_entry_stop(false); + + // 设置 HAS_PENDING_SIGNAL 标志,确保在返回用户态前处理信号 + pcb.flags().insert(ProcessFlags::HAS_PENDING_SIGNAL); + + // 发送 SIGTRAP 给自己,触发 ptrace 停止 (syscall entry) + let mut info = SigInfo::new( + Signal::SIGTRAP, + 0, // PTRACE_EVENTMSG_SYSCALL_ENTRY + SigCode::Origin(OriginCode::Kernel), + SigType::SigFault(crate::ipc::signal_types::SigFaultInfo { addr: 0, trapno: 0 }), + ); + Signal::SIGTRAP.send_signal_info_to_pcb( + Some(&mut info), + pcb.clone(), + crate::process::pid::PidType::PID, + ); + + // 直接返回,不执行系统调用 + // try_restart_syscall 稍后会在信号处理后重启系统调用 + syscall_return!(frame.rax, frame, show); + } + // needs_entry_stop == false 表示已经完成入口停止,这次应该执行系统调用 + } + // Arch specific syscall match syscall_num { SYS_RT_SIGRETURN => { @@ -120,8 +190,39 @@ pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) { _ => {} } let mut syscall_handle = || -> u64 { - Syscall::catch_handle(syscall_num, &args, frame) - .unwrap_or_else(|e| e.to_posix_errno() as usize) as u64 + let result = Syscall::catch_handle(syscall_num, &args, frame) + .unwrap_or_else(|e| e.to_posix_errno() as usize) as u64; + + // 系统调用出口 ptrace trace + let pcb = ProcessManager::current_pcb(); + if pcb + .flags() + .contains(ProcessFlags::PTRACED | ProcessFlags::TRACE_SYSCALL) + { + // 保存系统调用结果 + pcb.on_syscall_exit(result as isize); + + // 重置入口停止标志,以便下一个系统调用也在入口停止 + pcb.set_needs_syscall_entry_stop(true); + + // 设置 HAS_PENDING_SIGNAL 标志,确保在返回用户态前处理信号 + pcb.flags().insert(ProcessFlags::HAS_PENDING_SIGNAL); + + // 发送 SIGTRAP 给自己,触发 ptrace 停止 (syscall exit) + let mut info = SigInfo::new( + Signal::SIGTRAP, + 1, // PTRACE_EVENTMSG_SYSCALL_EXIT + SigCode::Origin(OriginCode::Kernel), + SigType::SigFault(crate::ipc::signal_types::SigFaultInfo { addr: 0, trapno: 0 }), + ); + Signal::SIGTRAP.send_signal_info_to_pcb( + Some(&mut info), + pcb.clone(), + crate::process::pid::PidType::PID, + ); + } + + result }; syscall_return!(syscall_handle(), frame, show); } diff --git a/kernel/src/exception/entry.rs b/kernel/src/exception/entry.rs index 1625544a6..e65b6b814 100644 --- a/kernel/src/exception/entry.rs +++ b/kernel/src/exception/entry.rs @@ -1,11 +1,11 @@ use crate::{ - arch::{interrupt::TrapFrame, ipc::signal::Signal, CurrentSignalArch}, + arch::{CurrentSignalArch, interrupt::TrapFrame, ipc::signal::Signal}, ipc::signal_types::SignalArch, - process::{rseq::Rseq, ProcessFlags, ProcessManager}, + process::{ProcessFlags, ProcessManager, rseq::Rseq}, }; #[no_mangle] -unsafe extern "C" fn irqentry_exit(frame: &mut TrapFrame) { +pub unsafe extern "C" fn irqentry_exit(frame: &mut TrapFrame) { if frame.is_from_user() { irqentry_exit_to_user_mode(frame); } @@ -37,6 +37,17 @@ unsafe fn exit_to_user_mode_prepare(frame: &mut TrapFrame) { /// 由于这个函数内可能会直接退出进程,因此,在进入函数之前, /// 必须保证所有的栈上的Arc/Box指针等,都已经被释放。否则,可能会导致内存泄漏。 unsafe fn exit_to_user_mode_loop(frame: &mut TrapFrame, mut process_flags_work: ProcessFlags) { + let pcb = ProcessManager::current_pcb(); + // if pcb.raw_pid() > RawPid::from(11) { + // log::debug!( + // "[EXIT_TO_USERMODE] PID {} flags={:?}, HAS_PENDING_SIGNAL={}, NEED_RSEQ={}", + // pcb.raw_pid(), + // process_flags_work, + // process_flags_work.contains(ProcessFlags::HAS_PENDING_SIGNAL), + // process_flags_work.contains(ProcessFlags::NEED_RSEQ) + // ); + // } + while !process_flags_work.exit_to_user_mode_work().is_empty() { // 优先处理 rseq,因为信号递送会保存 trapframe 到 sigframe // rseq 的 IP fixup 必须在信号递送之前完成 @@ -49,6 +60,10 @@ unsafe fn exit_to_user_mode_loop(frame: &mut TrapFrame, mut process_flags_work: } if process_flags_work.contains(ProcessFlags::HAS_PENDING_SIGNAL) { + log::debug!( + "[EXIT_TO_USERMODE] PID {} calling do_signal_or_restart", + pcb.raw_pid() + ); unsafe { CurrentSignalArch::do_signal_or_restart(frame) }; } process_flags_work = *ProcessManager::current_pcb().flags(); diff --git a/kernel/src/ipc/generic_signal.rs b/kernel/src/ipc/generic_signal.rs index 9268808c7..f2791fe0c 100644 --- a/kernel/src/ipc/generic_signal.rs +++ b/kernel/src/ipc/generic_signal.rs @@ -9,7 +9,7 @@ use crate::{ CurrentIrqArch, }, exception::InterruptArch, - process::{ptrace::handle_ptrace_signal_stop, ProcessFlags, ProcessManager}, + process::{ProcessFlags, ProcessManager}, sched::{schedule, SchedMode}, }; @@ -137,6 +137,13 @@ impl GenericSignal { /// 调用信号的默认处理函数 pub fn handle_default(&self) { + let current_pcb = ProcessManager::current_pcb(); + log::debug!( + "[HANDLE_DEFAULT] PID {} handling signal {:?} with default action", + current_pcb.raw_pid(), + self + ); + match self { Self::INVALID => { log::error!("attempting to handler an Invalid"); @@ -426,22 +433,41 @@ fn sig_terminate_dump(sig: Signal) { /// 信号默认处理函数——暂停进程 fn sig_stop(sig: Signal) { // 在接收者上下文设置停止标志,并让当前任务进入 Stopped - let guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; - { - let pcb = ProcessManager::current_pcb(); - // 标记停止事件,供 waitid(WSTOPPED) 可见 - pcb.sighand().flags_insert(SignalFlags::CLD_STOPPED); - pcb.sighand().flags_insert(SignalFlags::STOP_STOPPED); - if pcb.flags().contains(ProcessFlags::PTRACED) { - log::debug!("sig_stop"); - handle_ptrace_signal_stop(&pcb, sig); - } + let pcb = ProcessManager::current_pcb(); + + // 标记停止事件,供 waitid(WSTOPPED) 可见 + pcb.sighand().flags_insert(SignalFlags::CLD_STOPPED); + pcb.sighand().flags_insert(SignalFlags::STOP_STOPPED); + + // 按照 Linux 6.6.21 的实现: + // 如果进程被 ptrace,需要调用 ptrace_stop 来停止进程并通知 tracer + // ptrace_stop 会让进程进入停止状态并等待 tracer 的恢复 + if pcb.flags().contains(ProcessFlags::PTRACED) { + log::debug!("sig_stop: process is ptraced, calling ptrace_stop"); + // 对于 ptrace 进程,SIGSTOP 的默认处理需要真正停止进程 + // 调用 ptrace_stop 使进程停止并等待 tracer + use crate::ipc::signal_types::ChldCode; + let mut info = crate::ipc::signal_types::SigInfo::new( + sig, + 0, + crate::ipc::signal_types::SigCode::Origin(crate::ipc::signal_types::OriginCode::User), + crate::ipc::signal_types::SigType::SigFault(crate::ipc::signal_types::SigFaultInfo { + addr: 0, + trapno: 0, + }), + ); + pcb.ptrace_stop(sig as usize, ChldCode::Stopped, Some(&mut info)); + log::debug!("sig_stop: ptrace_stop returned, process resumed"); + return; } + + // 非 ptrace 进程的停止逻辑 + let guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; ProcessManager::mark_stop(sig).unwrap_or_else(|e| { log::error!( "sleep error :{:?},failed to sleep process :{:?}, with signal :{:?}", e, - ProcessManager::current_pcb().pid(), + pcb.pid(), sig ); }); diff --git a/kernel/src/ipc/kill.rs b/kernel/src/ipc/kill.rs index 922cee4d9..1cd628eec 100644 --- a/kernel/src/ipc/kill.rs +++ b/kernel/src/ipc/kill.rs @@ -14,8 +14,26 @@ use system_error::SystemError; /// ### 向一个进程发送信号 /// kill() 系统调用发送进程级信号,使用 PidType::TGID pub fn send_signal_to_pid(pid: RawPid, sig: Signal) -> Result { + log::debug!( + "[SEND_SIGNAL_TO_PID] ===== ENTRY: Sending signal {:?} to PID {}", + sig, + pid + ); + // 查找目标进程 - let target = ProcessManager::find_task_by_vpid(pid).ok_or(SystemError::ESRCH)?; + let target = ProcessManager::find_task_by_vpid(pid); + + if target.is_none() { + log::debug!("[SEND_SIGNAL_TO_PID] ===== ERROR: Target PID {} not found!", pid); + return Err(SystemError::ESRCH); + } + + let target = target.unwrap(); + + log::debug!( + "[SEND_SIGNAL_TO_PID] Found target PID {}, calling send_signal_info_to_pcb", + pid + ); // 检查权限(传入信号以处理 SIGCONT 特殊情况) check_signal_permission_pcb_with_sig(&target, Some(sig))?; @@ -36,11 +54,18 @@ pub fn send_signal_to_pid(pid: RawPid, sig: Signal) -> Result, pt: PidType) { + log::debug!( + "[COMPLETE_SIGNAL] Sending signal {:?} to PID {}, pt={:?}", + self, + pcb.raw_pid(), + pt + ); + compiler_fence(core::sync::atomic::Ordering::SeqCst); // ===== 寻找需要wakeup的目标进程 ===== // 备注:由于当前没有进程组的概念,每个进程只有1个对应的线程,因此不需要通知进程组内的每个进程。 @@ -262,12 +270,22 @@ impl Signal { // 根据信号类型选择添加到线程级 pending 还是进程级 shared_pending let is_thread_target = matches!(pt, PidType::PID); if is_thread_target { + log::debug!( + "[COMPLETE_SIGNAL] Adding signal {:?} to PID {} thread pending", + self, + pcb.raw_pid() + ); // 线程级信号:添加到线程的 sig_pending pcb.sig_info_mut() .sig_pending_mut() .signal_mut() .insert((*self).into()); } else { + log::debug!( + "[COMPLETE_SIGNAL] Adding signal {:?} to PID {} shared pending", + self, + pcb.raw_pid() + ); // 进程级信号:添加到 shared_pending // 注意:正常路径下(send_signal/enqueue_signal_locked)进程级信号会通过 // shared_pending_push() 同时完成“入队 + 位图置位”。这里仍然保留位图置位, @@ -281,15 +299,54 @@ impl Signal { // 若目标进程存在 signalfd 监听该信号,需要唤醒其等待者/epoll。 crate::ipc::signalfd::notify_signalfd_for_pcb(&pcb, *self); // 判断目标进程是否应该被唤醒以立即处理该信号 + log::debug!( + "[COMPLETE_SIGNAL] Checking if PID {} wants signal {:?}", + pcb.raw_pid(), + self + ); let wants_signal = self.wants_signal(pcb.clone()); - if wants_signal { + + // 按照 Linux 6.6.21 语义: + // 对于被 ptrace 的进程,如果收到 SIGSTOP 信号,需要特殊处理: + // 1. 如果进程处于 Blocked 状态(如在 pause(), sleep() 等),需要唤醒它来处理信号 + // 2. 如果进程处于 Runnable 状态,不需要唤醒(它会自动处理) + // 3. 这样可以避免竞态条件:tracer 在 waitpid 之前 tracee 就被唤醒并继续执行 + let is_ptrace_sigstop = + pcb.flags().contains(ProcessFlags::PTRACED) && *self == Signal::SIGSTOP; + + let should_wake = if is_ptrace_sigstop { + // 对于 ptrace SIGSTOP,只有进程处于 Blocked 状态时才唤醒 + matches!( + pcb.sched_info().inner_lock_read_irqsave().state(), + ProcessState::Blocked(_) + ) + } else { + wants_signal + }; + + if should_wake { + log::debug!( + "[COMPLETE_SIGNAL] PID {} wants signal {:?} (or blocked+ptrace SIGSTOP), will call signal_wake_up", + pcb.raw_pid(), + self + ); target_pcb = Some(pcb.clone()); } else if pt == PidType::PID { + log::debug!( + "[COMPLETE_SIGNAL] PID {} doesn't want signal {:?} (or runnable+ptrace SIGSTOP), pt=PID, returning without wake_up", + pcb.raw_pid(), + self + ); /* * 单线程场景且不需要唤醒:信号已入队,等待合适时机被取走 */ return; } else { + log::debug!( + "[COMPLETE_SIGNAL] PID {} doesn't want signal {:?} (or runnable+ptrace SIGSTOP), returning without wake_up", + pcb.raw_pid(), + self + ); /* * Otherwise try to find a suitable thread. * 由于目前每个进程只有1个线程,因此当前情况可以返回。信号队列的dequeue操作不需要考虑同步阻塞的问题。 @@ -302,6 +359,11 @@ impl Signal { // 统一按既有规则唤醒:STOP 信号需要把阻塞的系统调用唤醒到信号处理路径, // 由目标进程在自身上下文中执行默认处理(sig_stop),从而原地进入 Stopped,避免返回到用户态。 if let Some(target_pcb) = target_pcb { + log::debug!( + "[COMPLETE_SIGNAL] Calling signal_wake_up for PID {} with signal {:?}", + target_pcb.raw_pid(), + self + ); signal_wake_up(target_pcb.clone(), *self == Signal::SIGKILL); } } @@ -312,13 +374,27 @@ impl Signal { /// 这么做是为了防止我们把信号发送给了一个正在或已经退出的进程,或者是不响应该信号的进程。 #[inline] fn wants_signal(&self, pcb: Arc) -> bool { + log::debug!( + "[WANTS_SIGNAL] Checking if PID {} wants signal {:?}", + pcb.raw_pid(), + self + ); + // 若进程正在退出,则不能接收 if pcb.flags().contains(ProcessFlags::EXITING) { + log::debug!( + "[WANTS_SIGNAL] PID {} is exiting, returning false", + pcb.raw_pid() + ); return false; } // SIGKILL 总是唤醒 if *self == Signal::SIGKILL { + log::debug!( + "[WANTS_SIGNAL] SIGKILL for PID {}, returning true", + pcb.raw_pid() + ); return true; } @@ -326,14 +402,31 @@ impl Signal { // 则无论该信号是否在常规 blocked 集内,都应唤醒,由具体系统调用在返回路径上判定。 let state = pcb.sched_info().inner_lock_read_irqsave().state(); + log::debug!("[WANTS_SIGNAL] PID {} state: {:?}", pcb.raw_pid(), state); + // SIGCONT:即便被屏蔽或默认忽略,也应唤醒处于 Stopped 的任务,让其继续运行。 if *self == Signal::SIGCONT && state.is_stopped() { + log::debug!( + "[WANTS_SIGNAL] SIGCONT for stopped PID {}, returning true", + pcb.raw_pid() + ); return true; } let is_blocked_interruptable = state.is_blocked_interruptable(); let has_restore_sig_mask = pcb.flags().contains(ProcessFlags::RESTORE_SIG_MASK); + log::debug!( + "[WANTS_SIGNAL] PID {} is_blocked_interruptable={}, has_restore_sig_mask={}", + pcb.raw_pid(), + is_blocked_interruptable, + has_restore_sig_mask + ); + if is_blocked_interruptable && has_restore_sig_mask { + log::debug!( + "[WANTS_SIGNAL] PID {} blocked_interruptable + RESTORE_SIG_MASK, returning true", + pcb.raw_pid() + ); return true; } @@ -341,17 +434,45 @@ impl Signal { let blocked = *pcb.sig_info_irqsave().sig_blocked(); let is_blocked = blocked.contains((*self).into()); + log::debug!( + "[WANTS_SIGNAL] PID {} signal {:?} blocked={}, sig_blocked_set={:?}", + pcb.raw_pid(), + self, + is_blocked, + blocked + ); + if is_blocked { + log::debug!( + "[WANTS_SIGNAL] PID {} signal {:?} is blocked, returning false", + pcb.raw_pid(), + self + ); return false; } let is_blocked_non_interruptable = state.is_blocked() && (!state.is_blocked_interruptable()); + log::debug!( + "[WANTS_SIGNAL] PID {} is_blocked_non_interruptable={}", + pcb.raw_pid(), + is_blocked_non_interruptable + ); + if is_blocked_non_interruptable { + log::debug!( + "[WANTS_SIGNAL] PID {} is in non-interruptible blocked state, returning false", + pcb.raw_pid() + ); return false; } + log::debug!( + "[WANTS_SIGNAL] PID {} wants signal {:?}, returning true", + pcb.raw_pid(), + self + ); return true; } @@ -413,10 +534,10 @@ impl Signal { } drop(sig_info); - // TODO: ptrace 拦截被忽略的信号 - // if pcb.flags().contains(ProcessFlags::PTRACED) && *self != Signal::SIGKILL { - // return false; - // } + // ptrace 拦截被忽略的信号 + if pcb.flags().contains(ProcessFlags::PTRACED) && *self != Signal::SIGKILL { + return false; + } Self::sig_task_ignored(self, pcb, force) } @@ -464,6 +585,26 @@ impl Signal { let flush: SigSet; if !(self.into_sigset() & SIG_KERNEL_STOP_MASK).is_empty() { flush = Signal::SIGCONT.into_sigset(); + + // 对于 ptrace 进程,SIGSTOP 应该在 do_signal 中由 ptrace_signal 处理 + // 但是,我们仍然需要清理 SIGCONT,保持信号状态的一致性 + if pcb.flags().contains(ProcessFlags::PTRACED) { + log::debug!( + "[PREPARE_SIGNAL] PID {} is ptraced, flushing SIGCONT but skipping stop handling", + pcb.raw_pid() + ); + // 只清理 SIGCONT,不执行停止操作 + // 让信号正常入队,由 ptrace_signal 在 do_signal 中处理 + thread_group_leader + .sighand() + .shared_pending_flush_by_mask(&flush); + for_each_thread_in_group(&mut |t| { + t.sig_info_mut().sig_pending_mut().flush_by_mask(&flush); + }); + return !self.sig_ignored(&pcb, _force); + } + + // 非ptrace进程的正常SIGSTOP处理:立即停止并通知父进程 // Stop 类信号:清理 SIGCONT(共享 + 各线程私有 pending) thread_group_leader .sighand() @@ -486,8 +627,28 @@ impl Signal { }); if let Some(parent) = pcb.parent_pcb() { + log::debug!( + "[SIGSTOP] PID {} sending SIGCHLD to parent={} via parent_pcb", + pcb.raw_pid(), + parent.raw_pid() + ); let _ = crate::ipc::kill::send_signal_to_pcb(parent.clone(), Signal::SIGCHLD); parent.wake_all_waiters(); + } else { + log::debug!( + "[SIGSTOP] PID {} has no parent_pcb, trying real_parent", + pcb.raw_pid() + ); + if let Some(real_parent) = pcb.real_parent_pcb() { + log::debug!( + "[SIGSTOP] PID {} sending SIGCHLD to real_parent={}", + pcb.raw_pid(), + real_parent.raw_pid() + ); + let _ = + crate::ipc::kill::send_signal_to_pcb(real_parent.clone(), Signal::SIGCHLD); + real_parent.wake_all_waiters(); + } } // 唤醒等待在该子进程/线程上的等待者 thread_group_leader.wake_all_waiters(); @@ -540,8 +701,18 @@ impl Signal { .sighand() .flags_remove(SignalFlags::STOP_STOPPED); if let Some(parent) = pcb.parent_pcb() { + log::debug!( + "[SIGCONT] PID {} sending SIGCHLD to parent={} via parent_pcb", + pcb.raw_pid(), + parent.raw_pid() + ); let _ = crate::ipc::kill::send_signal_to_pcb(parent.clone(), Signal::SIGCHLD); parent.wake_all_waiters(); + } else { + log::debug!( + "[SIGCONT] PID {} has no parent_pcb, trying real_parent", + pcb.raw_pid() + ); } // 唤醒等待在该子进程上的等待者 thread_group_leader.wake_all_waiters(); @@ -568,10 +739,15 @@ impl Signal { /// - `_guard` 信号结构体锁守卫,来保证信号结构体已上锁 /// - `fatal` 表明这个信号是不是致命的(会导致进程退出) #[inline] -fn signal_wake_up(pcb: Arc, fatal: bool) { +pub fn signal_wake_up(pcb: Arc, fatal: bool) { // 如果是 fatal 的话就唤醒 stop 和 block 的进程来响应,因为唤醒后就会终止 // 如果不是 fatal 的就只唤醒 stop 的进程来响应 - log::debug!("signal_wake_up"); + log::debug!( + "[signal_wake_up] PID {} state={:?}, fatal={}", + pcb.raw_pid(), + pcb.sched_info().inner_lock_read_irqsave().state(), + fatal + ); // 如果目标进程已经在运行,则发起一个ipi,使得它陷入内核 let state = pcb.sched_info().inner_lock_read_irqsave().state(); let mut wakeup_ok = true; @@ -595,21 +771,14 @@ fn signal_wake_up(pcb: Arc, fatal: bool) { // 强制让目标CPU陷入内核,尽快处理 pending 的信号(包括作业控制停止/继续) // 即使目标任务当前处于 Runnable,也需要 kick 以触发内核路径的 do_signal。 - if wakeup_ok { - // log::debug!( - // "signal_wake_up: target pid={:?}, state={:?}, fatal={} -> kick", - // pcb.raw_pid(), - // state, - // fatal - // ); + // 对于非致命信号(如 SIGSTOP),如果进程在 Runnable 状态,仍然需要 kick + // 以便它在返回用户空间前处理信号 + if !wakeup_ok && !fatal { + // 当Runnable状态的进程从系统调用返回时,会看到 pending 信号并处理它 + ProcessManager::kick(&pcb); + } else if wakeup_ok { ProcessManager::kick(&pcb); } else if fatal { - // log::debug!( - // "signal_wake_up: target pid={:?}, state={:?}, fatal={} -> wakeup+kick", - // pcb.raw_pid(), - // state, - // fatal - // ); let _r = ProcessManager::wakeup(&pcb).map(|_| { ProcessManager::kick(&pcb); }); diff --git a/kernel/src/ipc/syscall/sys_kill.rs b/kernel/src/ipc/syscall/sys_kill.rs index afdeadbef..bc65fb60d 100644 --- a/kernel/src/ipc/syscall/sys_kill.rs +++ b/kernel/src/ipc/syscall/sys_kill.rs @@ -205,6 +205,15 @@ impl Syscall for SysKillHandle { let id = Self::pid(args); let sig_c_int = Self::sig(args); + let current_pcb = ProcessManager::current_pcb(); + + log::debug!( + "[SYS_KILL] PID {} sending signal {} to PID {}", + current_pcb.raw_pid(), + sig_c_int, + id + ); + let converter = PidConverter::from_id(id).ok_or(SystemError::ESRCH)?; // Handle null signal (signal 0) - used for existence and permission checks @@ -221,6 +230,13 @@ impl Syscall for SysKillHandle { return Err(SystemError::EINVAL); } + log::debug!( + "[SYS_KILL] Signal {:?} to PID {}, converter={:?}", + sig, + id, + converter + ); + match converter { PidConverter::Pid(pid) => send_signal_to_pid(pid.pid_vnr(), sig), PidConverter::Pgid(pgid) => send_signal_to_pgid(&pgid.ok_or(SystemError::ESRCH)?, sig), diff --git a/kernel/src/libs/printk.rs b/kernel/src/libs/printk.rs index 91af805cc..a20da3129 100644 --- a/kernel/src/libs/printk.rs +++ b/kernel/src/libs/printk.rs @@ -9,9 +9,13 @@ use crate::{ debug::klog::loglevel::{LogLevel, KERNEL_LOG_LEVEL}, driver::tty::{tty_driver::TtyOperation, virtual_terminal::vc_manager}, filesystem::procfs::{klog::LogMessage, kmsg::KMSG}, + libs::spinlock::SpinLock, time::PosixTimeSpec, }; +/// 全局串口输出锁,防止多进程并发输出导致字符交错 +static SERIAL_OUTPUT_LOCK: SpinLock<()> = SpinLock::new(()); + #[macro_export] macro_rules! print { ($($arg:tt)*) => ($crate::libs::printk::__printk(format_args!($($arg)*))); @@ -36,6 +40,8 @@ impl PrintkWriter { /// 并输出白底黑字 /// @param str: 要写入的字符 pub fn __write_string(&mut self, s: &str) { + // 获取全局串口输出锁,防止多进程并发输出导致字符交错 + let _guard = SERIAL_OUTPUT_LOCK.lock(); if let Some(current_vc) = vc_manager().current_vc() { // tty已经初始化了之后才输出到屏幕 let port = current_vc.port(); diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs index bebaaa004..64dc0c6a6 100644 --- a/kernel/src/process/exit.rs +++ b/kernel/src/process/exit.rs @@ -24,8 +24,9 @@ fn wstatus_to_waitid_status(raw_wstatus: i32) -> i32 { /// 检查子进程的 exit_signal 是否与等待选项匹配 /// -/// 根据 Linux wait 语义: +/// 根据 Linux wait 语义(kernel/exit.c:eligible_child): /// - __WALL: 等待所有子进程,忽略 exit_signal +/// - 如果子进程被 ptrace:总是可以等待,忽略 exit_signal /// - __WCLONE: 只等待"克隆"子进程(exit_signal != SIGCHLD) /// - 默认(无 __WCLONE): 只等待"正常"子进程(exit_signal == SIGCHLD) fn child_matches_wait_options(child_pcb: &Arc, options: WaitOption) -> bool { @@ -33,6 +34,10 @@ fn child_matches_wait_options(child_pcb: &Arc, options: Wai if options.contains(WaitOption::WALL) { return true; } + // 如果子进程被 ptrace,它总是可以被 wait + if child_pcb.is_traced() { + return true; + } let child_exit_signal = child_pcb.exit_signal.load(Ordering::SeqCst); let is_clone_child = child_exit_signal != Signal::SIGCHLD; @@ -85,7 +90,15 @@ pub fn kernel_wait4( // 构造参数 let mut kwo = KernelWaitOption::new(converter, options); - kwo.options.insert(WaitOption::WEXITED); + // 如果调用者没有指定 __WALL 或 __WCLONE,我们自动添加 WEXITED 和 WUNTRACED + // 这样 waitpid() 能够同时等待子进程退出和停止 + if !options.contains(WaitOption::WALL) && !options.contains(WaitOption::WCLONE) { + kwo.options.insert(WaitOption::WEXITED); + kwo.options.insert(WaitOption::WSTOPPED); + } else { + kwo.options.insert(WaitOption::WEXITED); + } + kwo.ret_rusage = rusage_buf; // 调用do_wait,执行等待 @@ -184,20 +197,50 @@ fn is_eligible_child(child_pcb: &Arc, options: WaitOption) let current = ProcessManager::current_pcb(); let current_tgid = current.tgid; - // 获取子进程的 real_parent - let child_parent = match child_pcb.real_parent_pcb() { + // 如果子进程被ptrace,parent指向tracer,real_parent指向原始父进程 + // 我们需要使用real_parent来判断父子关系 + let child_parent = match child_pcb.parent_pcb() { Some(p) => p, - None => return false, + None => match child_pcb.real_parent_pcb() { + Some(p) => p, + None => { + log::debug!( + "[ELIGIBLE_CHILD] child {} has no parent, returning false", + child_pcb.raw_pid() + ); + return false; + } + }, }; + log::debug!( + "[ELIGIBLE_CHILD] child={}, child_parent={}, current={}, current_tgid={}", + child_pcb.raw_pid(), + child_parent.raw_pid(), + current.raw_pid(), + current_tgid + ); + if options.contains(WaitOption::WNOTHREAD) { // 带 __WNOTHREAD:只能等待当前线程自己创建的子进程 - // 检查子进程的 real_parent 是否就是当前线程 - Arc::ptr_eq(&child_parent, ¤t) + // 检查子进程的 parent 是否就是当前线程 + let result = Arc::ptr_eq(&child_parent, ¤t); + log::debug!( + "[ELIGIBLE_CHILD] WNOTHREAD check: parent_eq_current={}", + result + ); + result } else { // 默认情况:线程组中的任何线程都可以等待同一线程组中任何线程创建的子进程 - // 检查子进程的 real_parent 的 tgid 是否与当前线程的 tgid 相同 - child_parent.tgid == current_tgid + // 检查子进程的 parent 的 tgid 是否与当前线程的 tgid 相同 + let result = child_parent.tgid == current_tgid; + log::debug!( + "[ELIGIBLE_CHILD] tgid check: parent_tgid={}, current_tgid={}, equal={}", + child_parent.tgid, + current_tgid, + result + ); + result } } @@ -311,6 +354,13 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { let wait_res = parent.wait_queue.wait_event_interruptible( || { let rd_childen = parent.children.read(); + let children_pids: alloc::vec::Vec = rd_childen.iter().map(|p| p.data()).collect(); + log::debug!( + "[DO_WAIT] PID {} scanning children list, count={}, children={:?}", + parent.raw_pid(), + rd_childen.len(), + children_pids + ); if rd_childen.is_empty() { echild = true; return true; @@ -337,6 +387,16 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { all_children_exited = false; } + log::debug!( + "[DO_WAIT] checking child={}, state={:?}, is_exited={}, WSTOPPED={}, WEXITED={}, CLD_STOPPED={}", + pcb.raw_pid(), + state, + state.is_exited(), + kwo.options.contains(WaitOption::WSTOPPED), + kwo.options.contains(WaitOption::WEXITED), + pcb.sighand().flags_contains(SignalFlags::CLD_STOPPED) + ); + if matches!(state, ProcessState::Stopped(_)) && kwo.options.contains(WaitOption::WSTOPPED) && pcb.sighand().flags_contains(SignalFlags::CLD_STOPPED) @@ -355,6 +415,24 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { scan_result = Some(Ok((*pid).into())); drop(sched_guard); break; + } else if matches!(state, ProcessState::TracedStopped(_)) { + // TracedStopped 状态类似于 Linux 的 TASK_TRACED + // 这是 ptrace 专用的停止状态,总是报告给 tracer + let stopsig = if let ProcessState::TracedStopped(sig) = state { + (sig & 0x7f) as i32 + } else { + Signal::SIGSTOP as i32 + }; + kwo.no_task_error = None; + kwo.ret_info = Some(WaitIdInfo { + pid: pcb.task_pid_vnr(), + status: stopsig, + cause: SigChildCode::Trapped.into(), + }); + kwo.ret_status = (stopsig << 8) | 0x7f; + scan_result = Some(Ok((*pid).into())); + drop(sched_guard); + break; } else if kwo.options.contains(WaitOption::WCONTINUED) && pcb.sighand().flags_contains(SignalFlags::CLD_CONTINUED) { @@ -603,6 +681,15 @@ fn do_waitpid( child_pcb: Arc, kwo: &mut KernelWaitOption, ) -> Option> { + log::debug!( + "[DO_WAITPID] child={}, WEXITED={}, WSTOPPED={}, WUNTRACED={}, WCONTINUED={}", + child_pcb.raw_pid(), + kwo.options.contains(WaitOption::WEXITED), + kwo.options.contains(WaitOption::WSTOPPED), + kwo.options.contains(WaitOption::WUNTRACED), + kwo.options.contains(WaitOption::WCONTINUED) + ); + // 优先处理继续事件:与 Linux 语义一致,只要标志存在即可报告 if kwo.options.contains(WaitOption::WCONTINUED) && child_pcb @@ -630,6 +717,11 @@ fn do_waitpid( } let state = child_pcb.sched_info().inner_lock_read_irqsave().state(); + log::debug!( + "[DO_WAITPID] child={} got state={:?}", + child_pcb.raw_pid(), + state + ); // 获取退出码 match state { ProcessState::Runnable => { @@ -644,10 +736,14 @@ fn do_waitpid( } ProcessState::Stopped(stopsig) => { // todo: 在stopped里面,添加code字段,表示停止的原因 - if stopsig <= 0 || stopsig >= Signal::SIGRTMAX.into() { + // 根据 Linux 6.6.21 的 ptrace 语义,stopsig 的格式可能是: + // - ((signal << 8) | 0x7f) - 普通停止 + // - ((signal << 8) | 0x80) - ptrace 陷阱停止 + // 我们需要提取实际的信号编号 (低 8 位 & 0x7f) + let actual_sig = stopsig & 0x7f; + if actual_sig <= 0 || actual_sig >= Signal::SIGRTMAX.into() { return Some(Err(SystemError::EINVAL)); } - let stopsig = stopsig as i32; let ptrace = child_pcb.is_traced(); // 对于被跟踪的进程,总是报告停止状态,无论 WUNTRACED 是否设置 // 对于非跟踪进程,只有在设置了 WUNTRACED 时才报告停止状态 @@ -657,7 +753,16 @@ fn do_waitpid( return None; } if likely(!(kwo.options.contains(WaitOption::WNOWAIT))) { - kwo.ret_status = (stopsig << 8) | 0x7f; + // 根据 Linux 6.6.21 语义: + // - 普通停止:(signal << 8) | 0x7f + // - ptrace 停止:(signal << 8) | 0x80 + kwo.ret_status = if (stopsig & 0x80) != 0 { + // ptrace 停止,保留 0x80 标志 + ((actual_sig << 8) | 0x80) as i32 + } else { + // 普通停止 + ((actual_sig << 8) | 0x7f) as i32 + }; } // if let Some(infop) = &mut kwo.ret_info { // *infop = WaitIdInfo { @@ -668,12 +773,40 @@ fn do_waitpid( // } kwo.ret_info = Some(WaitIdInfo { pid: child_pcb.task_pid_vnr(), - status: stopsig, + status: actual_sig as i32, cause: SigChildCode::Stopped.into(), }); return Some(Ok(child_pcb.raw_pid().data())); } + ProcessState::TracedStopped(stopsig) => { + // 按照 Linux 6.6.21 的 ptrace 语义: + // TracedStopped 状态类似于 Linux 的 TASK_TRACED + // 这是 ptrace 专用的停止状态,总是报告给 tracer + // 提取实际的信号编号 (低 8 位 & 0x7f) + let actual_sig = stopsig & 0x7f; + log::debug!( + "[DO_WAITPID] child={} is TracedStopped with sig={}, returning Some", + child_pcb.raw_pid(), + actual_sig + ); + if actual_sig <= 0 || actual_sig >= Signal::SIGRTMAX.into() { + return Some(Err(SystemError::EINVAL)); + } + // TracedStopped 状态总是被 ptrace,所以总是报告停止状态 + // 不需要检查 WUNTRACED 标志 + if likely(!(kwo.options.contains(WaitOption::WNOWAIT))) { + // ptrace 停止:(signal << 8) | 0x7f + kwo.ret_status = ((actual_sig << 8) | 0x7f) as i32; + } + kwo.ret_info = Some(WaitIdInfo { + pid: child_pcb.task_pid_vnr(), + status: actual_sig as i32, + cause: SigChildCode::Trapped.into(), + }); + + return Some(Ok(child_pcb.raw_pid().data())); + } ProcessState::Exited(status) => { let pid = child_pcb.task_pid_vnr(); // Linux 语义:若等待集合未包含 WEXITED,则不报告退出事件 @@ -701,7 +834,6 @@ fn do_waitpid( } return Some(Ok(pid.into())); } - ProcessState::TracedStopped => todo!(), }; return None; diff --git a/kernel/src/process/fork.rs b/kernel/src/process/fork.rs index 5634c3d50..0ae03e1b7 100644 --- a/kernel/src/process/fork.rs +++ b/kernel/src/process/fork.rs @@ -686,7 +686,27 @@ impl ProcessManager { } } else { // 新创建的进程,设置其父进程为当前进程 + let current_pid = current_pcb.raw_pid(); + let child_pid = pcb.raw_pid(); + *pcb.real_parent_pcb.write_irqsave() = Arc::downgrade(current_pcb); + + // 同时设置parent_pcb(按照Linux语义,默认parent=real_parent) + *pcb.parent_pcb.write_irqsave() = Arc::downgrade(current_pcb); + + // 验证设置 + let verify_parent = pcb.parent_pcb.read_irqsave(); + let verify_pid = verify_parent + .upgrade() + .map(|p| p.raw_pid()); + + log::debug!( + "[FORK] Set parent: child={}, parent={}, verified parent={:?}", + child_pid, + current_pid, + verify_pid + ); + pcb.exit_signal .store(clone_args.exit_signal, Ordering::SeqCst); } diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index c5c23939b..3d18d21d5 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -36,7 +36,7 @@ use crate::{ ipc::{ kill::send_signal_to_pcb, sighand::SigHand, - signal::RestartBlock, + signal::{signal_wake_up, RestartBlock}, signal_types::{SigInfo, SigPending}, }, libs::{ @@ -243,43 +243,56 @@ impl ProcessManager { } /// 唤醒一个进程 + /// 参考 Linux 6.6.21 的 try_to_wake_up,支持唤醒 Blocked 和 TracedStopped 状态的进程 pub fn wakeup(pcb: &Arc) -> Result<(), SystemError> { let _guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; let state = pcb.sched_info().inner_lock_read_irqsave().state(); - if state.is_blocked() { - let mut writer = pcb.sched_info().inner_lock_write_irqsave(); - let state = writer.state(); - if state.is_blocked() { - writer.set_state(ProcessState::Runnable); - writer.set_wakeup(); - // avoid deadlock - drop(writer); + // 类似 Linux 的 try_to_wake_up,检查任务状态并决定是否唤醒 + // 支持 Blocked 和 TracedStopped 状态 + let should_wake = state.is_blocked() || matches!(state, ProcessState::TracedStopped(_)); - let rq = - cpu_rq(pcb.sched_info().on_cpu().unwrap_or(current_cpu_id()).data() as usize); + if !should_wake { + if state.is_exited() { + return Err(SystemError::EINVAL); + } + return Ok(()); + } - let (rq, _guard) = rq.self_lock(); - rq.update_rq_clock(); - rq.activate_task( - pcb, - EnqueueFlag::ENQUEUE_WAKEUP | EnqueueFlag::ENQUEUE_NOCLOCK, - ); + let mut writer = pcb.sched_info().inner_lock_write_irqsave(); + let current_state = writer.state(); - rq.check_preempt_currnet(pcb, WakeupFlags::empty()); + // 双重检查,防止状态在获取锁之后改变 + let is_target_state = + current_state.is_blocked() || matches!(current_state, ProcessState::TracedStopped(_)); - // sched_enqueue(pcb.clone(), true); - return Ok(()); - } else if state.is_exited() { + if !is_target_state { + drop(writer); + if current_state.is_exited() { return Err(SystemError::EINVAL); - } else { - return Ok(()); } - } else if state.is_exited() { - return Err(SystemError::EINVAL); - } else { return Ok(()); } + + // 将状态改为 Runnable(对应 Linux 的 TASK_RUNNING) + writer.set_state(ProcessState::Runnable); + writer.set_wakeup(); + + // avoid deadlock + drop(writer); + + let rq = cpu_rq(pcb.sched_info().on_cpu().unwrap_or(current_cpu_id()).data() as usize); + + let (rq, _guard) = rq.self_lock(); + rq.update_rq_clock(); + rq.activate_task( + pcb, + EnqueueFlag::ENQUEUE_WAKEUP | EnqueueFlag::ENQUEUE_NOCLOCK, + ); + + rq.check_preempt_currnet(pcb, WakeupFlags::empty()); + + return Ok(()); } /// 唤醒暂停的进程 @@ -416,6 +429,14 @@ impl ProcessManager { #[inline(never)] fn exit_notify() { let current = ProcessManager::current_pcb(); + + log::debug!( + "[EXIT_NOTIFY] PID {} exiting, parent_pcb={:?}, real_parent_pcb={:?}", + current.raw_pid(), + current.parent_pcb().map(|p| p.raw_pid()), + current.real_parent_pcb().map(|p| p.raw_pid()) + ); + // 让INIT进程收养所有子进程 if current.raw_pid() != RawPid(1) { unsafe { @@ -423,24 +444,63 @@ impl ProcessManager { .adopt_childen() .unwrap_or_else(|e| panic!("adopte_childen failed: error: {e:?}")) }; + + // 重新读取parent_pcb,因为adopt_children可能修改了它 + log::debug!( + "[EXIT_NOTIFY] After adopt_children, PID {} parent_pcb={:?}", + current.raw_pid(), + current.parent_pcb().map(|p| p.raw_pid()) + ); + let r = current.parent_pcb.read_irqsave().upgrade(); if r.is_none() { + log::debug!( + "[EXIT_NOTIFY] PID {} parent_pcb is None, cannot send SIGCHLD", + current.raw_pid() + ); return; } let parent_pcb = r.unwrap(); - // 检查子进程的exit_signal,只有在有效时才发送信号 - let exit_signal = current.exit_signal.load(Ordering::SeqCst); - if exit_signal != Signal::INVALID { - let r = crate::ipc::kill::send_signal_to_pcb(parent_pcb.clone(), exit_signal); - if let Err(e) = r { - warn!( - "failed to send kill signal to {:?}'s parent pcb {:?}: {:?}", - current.raw_pid(), - parent_pcb.raw_pid(), - e - ); + log::debug!( + "[EXIT_NOTIFY] PID {} sending exit_signal={:?} to parent={}", + current.raw_pid(), + current.exit_signal.load(Ordering::SeqCst), + parent_pcb.raw_pid() + ); + + // 按照 Linux 6.6.21 的语义: + // 1. 对于被 ptrace 的进程,应该发送 SIGCHLD 给父进程(tracer) + // 即使 exit_signal 被 ptrace 注入覆盖了 + // 2. 对于普通进程,使用 exit_signal 字段决定发送什么信号 + // + // 参考 Linux kernel/exit.c:do_notify_parent() + // 如果进程被 ptrace,忽略 exit_signal,总是发送 SIGCHLD + let is_ptraced = current.flags().contains(ProcessFlags::PTRACED); + let signal_to_send = if is_ptraced { + log::debug!( + "[EXIT_NOTIFY] PID {} is ptraced, sending SIGCHLD regardless of exit_signal", + current.raw_pid() + ); + Signal::SIGCHLD + } else { + let exit_signal = current.exit_signal.load(Ordering::SeqCst); + if exit_signal == Signal::INVALID { + Signal::SIGCHLD + } else { + exit_signal } + }; + + // 发送信号 + let r = crate::ipc::kill::send_signal_to_pcb(parent_pcb.clone(), signal_to_send); + if let Err(e) = r { + warn!( + "failed to send kill signal to {:?}'s parent pcb {:?}: {:?}", + current.raw_pid(), + parent_pcb.raw_pid(), + e + ); } // 无论exit_signal是什么值,都要唤醒父进程的wait_queue @@ -450,6 +510,9 @@ impl ProcessManager { .wait_queue .wakeup_all(Some(ProcessState::Blocked(true))); + // 当子进程退出时,需要唤醒父进程,即使父进程不在 wait() 中睡眠 + parent_pcb.wake_up_process(); + // 根据 Linux wait 语义,线程组中的任何线程都可以等待同一线程组中任何线程创建的子进程。 // 由于子进程被添加到线程组 leader 的 children 列表中, // 因此还需要唤醒线程组 leader 的 wait_queue(如果 leader 不是 parent_pcb 本身)。 @@ -462,6 +525,7 @@ impl ProcessManager { leader .wait_queue .wakeup_all(Some(ProcessState::Blocked(true))); + leader.wake_up_process(); } } // todo: 这里还需要根据线程组的信息,决定信号的发送 @@ -491,6 +555,19 @@ impl ProcessManager { spin_loop(); } } + + // 注意:不再在 exit() 中调用 ptrace_stop + // 按照 Linux 6.6.21 的语义: + // 1. 被 ptrace 的进程在收到信号时会调用 ptrace_stop(通过 ptrace_signal) + // 2. tracer 可以通过 waitpid 查看进程状态 + // 3. 当进程退出时,应该直接退出,不需要再次调用 ptrace_stop + // 4. 这样 tracer 可以通过 waitpid(WEXITED) 回收进程 + // + // 如果在 exit() 中调用 ptrace_stop,会导致: + // - tracer 无法通过 waitpid 回收子进程(因为子进程在 TracedStopped 状态) + // - tracer 收到 ESRCH 错误并退出 + // - 子进程永远等待,形成死锁 + drop(current_pcb); // 关中断 @@ -659,15 +736,32 @@ impl ProcessManager { /// /// 调用此函数前,调用者**不能持有**父进程的 children 锁,否则会死锁。 pub(super) unsafe fn release(pid: RawPid) { + log::debug!("[RELEASE] Releasing PID {}", pid); let pcb = ProcessManager::find(pid); if let Some(ref pcb) = pcb { // 从父进程的 children 列表中移除 if let Some(parent) = pcb.real_parent_pcb() { + log::debug!( + "[RELEASE] Removing PID {} from parent {}'s children list", + pid, + parent.raw_pid() + ); let mut children = parent.children.write(); + let before_count = children.len(); children.retain(|&p| p != pid); + let after_count = children.len(); + log::debug!( + "[RELEASE] Parent {} children count: {} -> {}", + parent.raw_pid(), + before_count, + after_count + ); } ALL_PROCESS.lock_irqsave().as_mut().unwrap().remove(&pid); + log::debug!("[RELEASE] PID {} removed from ALL_PROCESS", pid); + } else { + log::warn!("[RELEASE] PID {} not found in ALL_PROCESS", pid); } } @@ -774,8 +868,9 @@ pub enum ProcessState { Blocked(bool), /// 进程被信号终止 Stopped(usize), - /// 用于ptrace跟踪停止的状态 - TracedStopped, + /// 用于ptrace跟踪停止的状态,携带退出码 + /// 按照 Linux 6.6.21 的 TASK_TRACED 语义实现 + TracedStopped(usize), /// 进程已经退出,usize表示进程的退出码 Exited(usize), } @@ -803,19 +898,24 @@ impl ProcessState { return matches!(self, ProcessState::Exited(_)); } - /// Returns `true` if the process state is [`Stopped`]. + /// Returns `true` if the process state is [`Stopped`] or [`TracedStopped`]. /// /// [`Stopped`]: ProcessState::Stopped + /// [`TracedStopped`]: ProcessState::TracedStopped #[inline(always)] pub fn is_stopped(&self) -> bool { - matches!(self, ProcessState::Stopped(_)) + matches!( + self, + ProcessState::Stopped(_) | ProcessState::TracedStopped(_) + ) } - /// Returns exit code if the process state is [`Exited`]. + /// Returns exit code if the process state is [`Exited`] or [`TracedStopped`]. #[inline(always)] pub fn exit_code(&self) -> Option { match self { ProcessState::Exited(code) => Some(*code), + ProcessState::TracedStopped(code) => Some(*code), _ => None, } } @@ -874,6 +974,8 @@ bitflags! { const STOPPED = 1 << 14; /// 进程当前由ptrace跟踪 const PTRACED = 1 << 15; + /// ptrace 正在停止(用于 attach/stop 的同步) + const TRAPPING = 1 << 13; /// 跟踪器已发出PTRACE_SYSCALL请求 const TRACE_SYSCALL = 1 << 16; /// 跟踪器已发出PTRACE_SINGLESTEP请求 @@ -1005,7 +1107,7 @@ pub enum PtraceEvent { } /// 进程被跟踪的状态信息 -#[derive(Debug, Default)] +#[derive(Debug)] struct PtraceState { /// 跟踪此进程的进程PID tracer: Option, @@ -1020,6 +1122,28 @@ struct PtraceState { exit_code: usize, /// 用于存储事件消息 event_message: usize, + /// tracer 注入的信号(在 ptrace_stop 返回后要处理的信号) + injected_signal: Signal, + /// 是否需要在系统调用入口停止(用于 PTRACE_SYSCALL) + /// true: 需要在系统调用入口停止 + /// false: 已经完成入口停止,应该执行系统调用 + needs_syscall_entry_stop: bool, +} + +impl Default for PtraceState { + fn default() -> Self { + Self { + tracer: None, + pending_signals: Vec::new(), + syscall_info: None, + stop_reason: PtraceStopReason::None, + options: PtraceOptions::empty(), + exit_code: 0, + event_message: 0, + injected_signal: Signal::INVALID, + needs_syscall_entry_stop: true, // 默认需要在入口停止 + } + } } impl PtraceState { pub fn new() -> Self { @@ -1031,6 +1155,8 @@ impl PtraceState { options: PtraceOptions::empty(), exit_code: 0, event_message: 0, + injected_signal: Signal::INVALID, + needs_syscall_entry_stop: true, // 默认需要在入口停止 } } @@ -1733,17 +1859,59 @@ impl ProcessControlBlock { /// 当前进程退出时,让初始进程收养所有子进程 unsafe fn adopt_childen(&self) -> Result<(), SystemError> { - // 取出并清空 children 列表,避免后续 wait/reparent 出现重复。 - let child_pids: Vec = { - let mut children_guard = self.children.write(); - core::mem::take(&mut *children_guard) + // 取出 children 列表(但不清空,我们会选择性地保留 ptraced 子进程) + let all_child_pids: Vec = { + let children_guard = self.children.read(); + children_guard.clone() }; - if child_pids.is_empty() { + if all_child_pids.is_empty() { + return Ok(()); + } + + // 按照 Linux 6.6.21 的 ptrace 语义: + // 如果子进程正在被当前进程 ptrace,则不要转移它 + // tracer 需要能够 wait 这个子进程,即使子进程已经退出 + let mut ptraced_children: Vec = Vec::new(); + let mut children_to_adopt: Vec = Vec::new(); + + for pid in all_child_pids.iter().copied() { + if let Some(child) = ProcessManager::find_task_by_vpid(pid) { + // 检查子进程是否被当前进程 ptrace + // 通过检查子进程的 parent_pcb 是否指向当前进程 + if let Some(child_parent) = child.parent_pcb() { + if Arc::ptr_eq(&child_parent, &self.self_ref.upgrade().unwrap()) { + // 子进程的 parent_pcb 指向当前进程,说明是被 ptrace 的 + // 不转移这个子进程 + log::debug!( + "[ADOPT_CHILDREN] PID {} is being traced by current process {}, keeping in children list", + child.raw_pid(), + self.raw_pid() + ); + ptraced_children.push(pid); + continue; + } + } + children_to_adopt.push(pid); + } + } + + // 只清空并转移非 ptraced 的子进程 + if !children_to_adopt.is_empty() { + // 从当前进程的 children 列表中移除被收养的子进程 + // 保留 ptraced children(不在 children_to_adopt 中) + let mut children_guard = self.children.write(); + children_guard.retain(|pid| !children_to_adopt.contains(pid)); + } else { + log::debug!( + "[ADOPT_CHILDREN] PID {} all children are ptraced, nothing to adopt", + self.raw_pid() + ); + // 所有子进程都是 ptraced 的,不需要转移任何子进程 return Ok(()); } - self.notify_parent_exit_for_children(&child_pids); + self.notify_parent_exit_for_children(&children_to_adopt); let init_pcb = ProcessManager::find_task_by_vpid(RawPid(1)).ok_or(SystemError::ECHILD)?; @@ -1758,7 +1926,7 @@ impl ProcessControlBlock { let parent_init = ProcessManager::find_task_by_pid_ns(RawPid(1), &parent_pcb.active_pid_ns()); if let Some(parent_init) = parent_init { - for pid in child_pids.iter().copied() { + for pid in children_to_adopt.iter().copied() { if let Some(child) = ProcessManager::find_task_by_vpid(pid) { *child.parent_pcb.write_irqsave() = Arc::downgrade(&parent_init); *child.real_parent_pcb.write_irqsave() = Arc::downgrade(&parent_init); @@ -1771,7 +1939,7 @@ impl ProcessControlBlock { return Ok(()); } - // 常规情况:优先 reparent 到“最近祖先 subreaper”,否则 reparent 到 init。 + // 常规情况:优先 reparent 到"最近祖先 subreaper",否则 reparent 到 init。 let mut reaper: Arc = init_pcb.clone(); let mut cursor = self.parent_pcb(); while let Some(p) = cursor { @@ -1793,7 +1961,7 @@ impl ProcessControlBlock { cursor = leader.parent_pcb(); } - for pid in child_pids.iter().copied() { + for pid in children_to_adopt.iter().copied() { if let Some(child) = ProcessManager::find_task_by_vpid(pid) { *child.parent_pcb.write_irqsave() = Arc::downgrade(&reaper); *child.real_parent_pcb.write_irqsave() = Arc::downgrade(&reaper); @@ -1867,6 +2035,33 @@ impl ProcessControlBlock { self.rseq_state.write_irqsave() } + /// 获取 ptrace 状态的可变引用 + #[inline] + pub fn ptrace_state_mut(&self) -> SpinLockGuard<'_, PtraceState> { + self.ptrace_state.lock() + } + + /// 设置是否需要在系统调用入口停止 + #[inline] + pub fn set_needs_syscall_entry_stop(&self, value: bool) { + self.ptrace_state.lock().needs_syscall_entry_stop = value; + } + + /// 唤醒进程(用于子进程退出时唤醒父进程) + /// + /// 当子进程退出时,需要唤醒父进程,即使父进程不在 wait() 中睡眠 + /// 例如:父进程可能在 nanosleep 中,被 SIGCHLD 唤醒后应该处理信号 + #[inline] + pub fn wake_up_process(&self) { + signal_wake_up(self.self_ref.upgrade().unwrap(), false); + } + + /// 获取是否需要在系统调用入口停止 + #[inline] + pub fn needs_syscall_entry_stop(&self) -> bool { + self.ptrace_state.lock().needs_syscall_entry_stop + } + pub fn try_siginfo_mut(&self, times: u8) -> Option> { for _ in 0..times { if let Some(r) = self.sig_info.try_write_irqsave() { diff --git a/kernel/src/process/ptrace.rs b/kernel/src/process/ptrace.rs index 24bd26876..00793775d 100644 --- a/kernel/src/process/ptrace.rs +++ b/kernel/src/process/ptrace.rs @@ -1,21 +1,18 @@ use crate::arch::interrupt::TrapFrame; use crate::arch::ipc::signal::{SigFlags, Signal}; use crate::arch::kprobe; -use crate::arch::CurrentIrqArch; -use crate::exception::InterruptArch; use crate::ipc::signal_types::{ ChldCode, OriginCode, SigChldInfo, SigCode, SigFaultInfo, SigInfo, SigType, Sigaction, SigactionType, SignalFlags, }; -use crate::process::pid::PidType; use crate::process::{ - ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState, PtraceEvent, PtraceOptions, - PtraceRequest, PtraceStopReason, PtraceSyscallInfo, PtraceSyscallInfoData, - PtraceSyscallInfoEntry, PtraceSyscallInfoExit, PtraceSyscallInfoOp, RawPid, SyscallInfo, + pid::PidType, ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState, PtraceEvent, + PtraceOptions, PtraceRequest, PtraceStopReason, PtraceSyscallInfo, PtraceSyscallInfoData, + PtraceSyscallInfoEntry, PtraceSyscallInfoExit, PtraceSyscallInfoOp, RawPid, }; -use crate::sched::{schedule, DequeueFlag, EnqueueFlag, SchedMode}; +use crate::sched::{schedule, DequeueFlag, EnqueueFlag, SchedMode, WakeupFlags}; use alloc::{sync::Arc, vec::Vec}; -use core::{intrinsics::unlikely, mem::MaybeUninit, sync::atomic::Ordering}; +use core::{intrinsics::unlikely, mem::MaybeUninit}; use system_error::SystemError; /// 在 get_signal 中调用的 ptrace 信号拦截器。 @@ -28,47 +25,121 @@ pub fn ptrace_signal( original_signal: Signal, info: &mut Option, ) -> Option { + log::debug!( + "[PTRACE_SIGNAL] PID {} processing signal {:?}", + pcb.raw_pid(), + original_signal + ); + // todo pcb.jobctl_set(JobControlFlags::STOP_DEQUEUED); // 核心:调用 ptrace_stop 使进程停止并等待追踪者。 // ptrace_stop 会返回追踪者注入的信号。 // 注意:ptrace_stop 内部会处理锁的释放和重新获取。 let mut signr = pcb.ptrace_stop(original_signal as usize, ChldCode::Trapped, info.as_mut()); + + log::debug!( + "[PTRACE_SIGNAL] PID {} tracer returned signal {}", + pcb.raw_pid(), + signr + ); + + // 按照 Linux 6.6.21 的 get_signal 语义: + // 如果 signr == 0,表示没有注入信号,应该丢弃原始信号,继续执行 + // 如果 signr != 0,表示注入了新信号,应该处理该信号 + if signr == 0 { + log::debug!( + "[PTRACE_SIGNAL] PID {} no injected signal, discarding original signal {:?}", + pcb.raw_pid(), + original_signal + ); + return None; // 丢弃原始信号,继续处理下一个信号(如果没有,则继续执行) + } + // 将注入的信号转换为 Signal 类型 let mut injected_signal = Signal::from(signr); if injected_signal == Signal::INVALID { + // 这不应该发生,因为 signr != 0 + log::error!( + "[PTRACE_SIGNAL] PID {} invalid signal {}", + pcb.raw_pid(), + signr + ); return None; } - // pcb.set_state(ProcessState::Exited(0)); // 如果追踪者注入了不同于原始信号的新信号,更新 siginfo。 + // 注意:按照 Linux 6.6.21 的 ptrace 语义,注入的信号应该使用 SI_USER 代码 + // 而不是 SigChld 类型,因为这不是真正的子进程状态变化 if injected_signal != original_signal { + log::debug!( + "[PTRACE_SIGNAL] PID {} tracer injected new signal {:?} (was {:?})", + pcb.raw_pid(), + injected_signal, + original_signal + ); if let Some(info_ref) = info { let tracer = pcb.parent_pcb().unwrap(); + // 使用 Kill 类型(SI_USER)而不是 SigChld + // 这样更符合 ptrace 注入信号的语义 *info_ref = SigInfo::new( injected_signal, 0, SigCode::Origin(OriginCode::User), - SigType::SigChld(SigChldInfo { + SigType::Kill { pid: tracer.raw_pid(), - uid: tracer.cred().uid.data(), - status: 0, - utime: 0, - stime: 0, - }), + uid: tracer.cred().uid.data() as u32, + }, ); } } + + // 特殊处理 SIGCONT:需要清除挂起的停止信号,但仍然要传递给用户 + // 按照 Linux 6.6.21 的语义,SIGCONT 应该唤醒进程并传递给用户空间处理 + if injected_signal == Signal::SIGCONT { + log::debug!( + "[PTRACE_SIGNAL] PID {} injected SIGCONT, clearing any pending stop signals", + pcb.raw_pid() + ); + // 清除任何挂起的停止信号(如 SIGSTOP, SIGTSTP 等) + let mut sig_info = pcb.sig_info.write(); + let pending = sig_info.sig_pending_mut().signal_mut(); + // 清除停止信号 + for stop_sig in [ + Signal::SIGSTOP, + Signal::SIGTSTP, + Signal::SIGTTIN, + Signal::SIGTTOU, + ] { + pending.remove(stop_sig.into()); + } + drop(sig_info); + // 返回 Some(injected_signal) 让 SIGCONT 被正常处理 + // 这样用户的信号处理函数(如 sigcont_handler)会被调用 + return Some(injected_signal); + } + // 检查新信号是否被当前进程的信号掩码阻塞 let sig_info_guard = pcb.sig_info_irqsave(); if sig_info_guard .sig_blocked() .contains(injected_signal.into()) { + log::debug!( + "[PTRACE_SIGNAL] PID {} signal {:?} is blocked, requeuing", + pcb.raw_pid(), + injected_signal + ); // 如果被阻塞了,则将信号重新排队,让它在未来被处理。 - injected_signal.send_signal_info_to_pcb(info.as_mut(), Arc::clone(pcb), PidType::PID); + let _ = + injected_signal.send_signal_info_to_pcb(info.as_mut(), Arc::clone(pcb), PidType::PID); // 告诉 get_signal,当前没有需要立即处理的信号。 return None; } // 如果没有被阻塞,则返回这个新信号,让 get_signal 继续分发和处理它。 + log::debug!( + "[PTRACE_SIGNAL] PID {} returning signal {:?} to handle", + pcb.raw_pid(), + injected_signal + ); Some(injected_signal) } @@ -118,7 +189,7 @@ pub fn do_notify_parent(child: &ProcessControlBlock, signal: Signal) -> Result, sig: Si current_pcb.raw_pid(), sig ); - // if let Some(tracer_pid) = ptrace_state.tracer { - // if let Some(tracer) = ProcessManager::find(tracer_pid) { - // let mut info = SigInfo::new( - // sig, - // 0, - // SigCode::Origin(OriginCode::Kernel), - // SigType::SigChld(SigChldInfo { - // pid: current_pcb.raw_pid(), - // uid: current_pcb.cred().uid.data(), - // status: sig as i32, - // utime: 0, // 可以根据需要填充实际值 - // stime: 0, // 可以根据需要填充实际值 - // }), - // ); - // let _ = Signal::SIGCHLD.send_signal_info_to_pcb(Some(&mut info), tracer); - // } - // } - current_pcb.set_state(ProcessState::TracedStopped); + drop(ptrace_state); + + // 调用 ptrace_stop 让进程真正停止并等待跟踪器 + // 这会设置状态、通知跟踪器、并调用 schedule() 让出 CPU + let mut info = SigInfo::new( + sig, + 0, + SigCode::Origin(OriginCode::Kernel), + SigType::SigFault(SigFaultInfo { addr: 0, trapno: 0 }), + ); + current_pcb.ptrace_stop(sig as usize, ChldCode::Stopped, Some(&mut info)); } impl ProcessControlBlock { @@ -228,7 +292,25 @@ impl ProcessControlBlock { if new_parent.is_exited() { return Err(SystemError::ESRCH); // 父进程不能是退出状态或僵尸状态 } + + let old_parent = self.parent_pcb().map(|p| p.raw_pid()); + log::debug!( + "[SET_PARENT] PID {} changing parent from {:?} to {}", + self.raw_pid(), + old_parent, + new_parent.raw_pid() + ); + *(self.parent_pcb.write()) = Arc::downgrade(new_parent); + + // 验证设置是否成功 + let verify_parent = self.parent_pcb().map(|p| p.raw_pid()); + log::debug!( + "[SET_PARENT] PID {} verified parent_pcb={:?}", + self.raw_pid(), + verify_parent + ); + Ok(()) } @@ -329,37 +411,174 @@ impl ProcessControlBlock { why: ChldCode, info: Option<&mut SigInfo>, ) -> usize { + log::debug!( + "[PTRACE_STOP] PID {} stopping: exit_code={}, why={:?}", + self.raw_pid(), + exit_code, + why + ); + + // 按照 Linux 6.6.21 的 ptrace_stop 语义: + // 1. 设置 TRAPPING 标志,表示 tracee 正在停止 + // 2. 设置进程状态为 Stopped + // 3. 唤醒 tracer 的等待队列 + // 4. 进入 schedule() 让出 CPU + // 5. 当 tracer 唤醒 tracee 后,schedule() 返回 + // 6. 清除 TRAPPING 标志 + + // 设置 TRAPPING 标志,表示正在停止 + self.flags().insert(ProcessFlags::TRAPPING); + // self.last_siginfo = info.cloned(); - // self.set_state(ProcessState::Exited(exit_code)); - self.set_state(ProcessState::Stopped(exit_code)); + // 按照 Linux 6.6.21 的 ptrace_stop 语义: + // 使用 TracedStopped 状态(类似于 Linux 的 TASK_TRACED) + // 而不是 Stopped 状态(类似于 Linux 的 TASK_STOPPED) + // 这确保 tracee 只能被 tracer 通过 ptrace_resume 唤醒 + + // 获取 sched_info 锁并设置状态 + let mut sched_info = self.sched_info.inner_lock_write_irqsave(); + sched_info.set_state(ProcessState::TracedStopped(exit_code)); + // 关键:必须设置 sleep 标志,否则调度器不会把进程从运行队列移除 + sched_info.set_sleep(); + drop(sched_info); + self.flags().insert(ProcessFlags::PTRACED); + + log::debug!( + "[PTRACE_STOP] PID {} state set to TracedStopped({}), will call schedule", + self.raw_pid(), + exit_code + ); + + // 为下次stop恢复 + self.ptrace_state.lock().event_message = 0; + + // 按照 Linux 6.6.21 的 ptrace_stop 语义: + // 1. 先通知 tracer (do_notify_parent_cldstop) - 在 schedule() 之前 + // 2. 清除 TRAPPING 标志 + // 3. 确保任务从运行队列移除 + // 4. 调用 schedule() 让出 CPU + // + // 这样 tracer 会被唤醒并可以 wait(),tracee 会进入睡眠状态 + + // 通知跟踪器 - 必须在 schedule() 之前调用! if let Some(tracer) = self.parent_pcb() { + log::debug!( + "[PTRACE_STOP] PID {} notifying tracer={}", + self.raw_pid(), + tracer.raw_pid() + ); self.notify_tracer(&tracer, why); } else { log::error!("PID {} is traced but has no parent tracer!", self.raw_pid()); } - if self.preempt_count() > 0 { - log::warn!( - "PID {} calling schedule with preempt_count={}", - self.raw_pid(), - self.preempt_count() + + // 清除 TRAPPING 标志,表示已经完成停止准备工作 + self.flags().remove(ProcessFlags::TRAPPING); + + // 关键修复:确保任务从运行队列中移除 + // 由于任务可能之前被 signal_wake_up 唤醒并加入运行队列 + // 我们需要确保它现在被移除,否则 schedule() 会立即返回 + { + let rq = crate::sched::cpu_rq(crate::smp::core::smp_get_processor_id().data() as usize); + let (rq, _guard) = rq.self_lock(); + rq.deactivate_task( + self.self_ref.upgrade().unwrap(), + DequeueFlag::DEQUEUE_SLEEP | DequeueFlag::DEQUEUE_NOCLOCK, + ); + log::debug!( + "[PTRACE_STOP] PID {} manually deactivated from run queue", + self.raw_pid() ); } - // // 先释放 sighand_lock 锁,再获取锁 - // // 不会写,先手动维护一下 preempt - // unsafe { self.sig_struct.force_unlock() }; - // self.preempt_count.fetch_sub(1, Ordering::SeqCst); - // schedule(SchedMode::SM_NONE); - // self.preempt_count.fetch_add(1, Ordering::SeqCst); - // let sighand_lock = self.sig_struct_irqsave(); - // 为下次stop恢复 - // self.last_siginfo = None; - self.ptrace_state.lock().event_message = 0; - exit_code + + let preempt_count_before = ProcessManager::current_pcb().preempt_count(); + log::debug!( + "[PTRACE_STOP] PID {} before schedule: preempt_count={}", + self.raw_pid(), + preempt_count_before + ); + + log::debug!( + "[PTRACE_STOP] PID {} scheduling out, waiting for tracer", + self.raw_pid() + ); + + // 调度出去,让出CPU等待跟踪器恢复 + // set_state 已经释放了 sched_info 锁,现在可以安全调用 schedule + let state_before = self.sched_info().inner_lock_read_irqsave().state(); + log::debug!( + "[PTRACE_STOP] PID {} before schedule: state={:?}", + self.raw_pid(), + state_before + ); + drop(state_before); + + schedule(SchedMode::SM_NONE); + + // 从 schedule() 返回后,tracer 已经通过 ptrace_resume 唤醒了我们 + // 状态已经被 ptrace_resume 设置为 Runnable + // 不要在这里手动修改状态!否则会导致竞态条件 + let state_after = self.sched_info().inner_lock_read_irqsave().state(); + log::debug!( + "[PTRACE_STOP] PID {} after schedule: state={:?}", + self.raw_pid(), + state_after + ); + drop(state_after); + + log::debug!( + "[PTRACE_STOP] PID {} resumed by tracer, checking ptrace flag", + self.raw_pid() + ); + + // 按照 Linux 6.6.21 的 ptrace_stop 语义: + // 进程恢复后,应该返回 tracer 注入的信号(data 参数) + // 而不是原始的 exit_code + // 从 ptrace_state.injected_signal 读取 tracer 注入的信号 + let mut ptrace_state = self.ptrace_state.lock(); + let injected_signal = ptrace_state.injected_signal; + + log::debug!( + "[PTRACE_STOP] PID {} injected_signal={:?} (original exit_code={})", + self.raw_pid(), + injected_signal, + exit_code + ); + + // 按照 Linux 6.6.21 的 get_signal/ptrace_stop 语义: + // 1. 如果注入的信号是 INVALID,返回 0,表示没有注入信号 + // 2. get_signal 会检查该信号,如果是 0,会丢弃原始信号并继续执行 + // 如果是非 0 信号,会处理该信号 + let result = if injected_signal == Signal::INVALID { + log::debug!( + "[PTRACE_STOP] PID {} no injected signal, continuing execution", + self.raw_pid() + ); + // 返回 0 表示没有注入信号,get_signal 会继续处理 + 0 + } else { + log::debug!( + "[PTRACE_STOP] PID {} returning injected signal {:?}", + self.raw_pid(), + injected_signal + ); + // 清除注入的信号,因为已经被处理了 + ptrace_state.injected_signal = Signal::INVALID; + injected_signal as usize + }; + drop(ptrace_state); + + result } fn notify_tracer(&self, tracer: &Arc, why: ChldCode) { - log::debug!("notify_tracer"); + log::debug!( + "[NOTIFY_TRACER] Notifying tracer={} about tracee={}, why={:?}", + tracer.raw_pid(), + self.raw_pid(), + why + ); let status = match why { ChldCode::Stopped => self.exit_code().unwrap_or(0) as i32 & 0x7f, ChldCode::Trapped => self.exit_code().unwrap_or(0) as i32 & 0x7f, @@ -391,10 +610,17 @@ impl ProcessControlBlock { Signal::SIGCHLD.send_signal_info_to_pcb( Some(&mut info), Arc::clone(tracer), - PidType::PID, + PidType::TGID, ); } - tracer.wait_queue.wakeup(None); + // 按照 Linux 6.6.21 的 do_notify_parent_cldstop 语义: + // __wake_up_parent 唤醒的是 parent 的 wait_chldexit 队列 + // 而不是 child 的队列 + // 这样 do_wait 中的 wait_event_interruptible 才能被唤醒 + log::debug!("[NOTIFY_TRACER] Waking up tracer's wait_queue"); + tracer + .wait_queue + .wakeup(Some(ProcessState::TracedStopped(status as usize))); } /// 检查进程是否可以被指定进程跟踪 @@ -416,9 +642,22 @@ impl ProcessControlBlock { } pub fn ptrace_link(&self, tracer: &Arc) -> Result<(), SystemError> { + log::debug!( + "[PTRACE_LINK] Linking tracer={} to tracee={}", + tracer.raw_pid(), + self.raw_pid() + ); + if !tracer.has_permission_to_trace(self) { + log::debug!( + "[PTRACE_LINK] Permission denied: tracer={} cannot trace tracee={}", + tracer.raw_pid(), + self.raw_pid() + ); return Err(SystemError::EPERM); } + + log::debug!("[PTRACE_LINK] Setting tracer for tracee={}", self.raw_pid()); // 将子进程添加到父进程的跟踪列表 // let mut ptrace_list = tracer.ptraced_list.write(); // let child_pid = self.raw_pid(); @@ -427,8 +666,26 @@ impl ProcessControlBlock { // } // ptrace_list.push(child_pid); self.set_tracer(tracer.raw_pid())?; + + log::debug!( + "[PTRACE_LINK] Reparenting tracee={} to tracer={}", + self.raw_pid(), + tracer.raw_pid() + ); self.set_parent(tracer)?; + + log::debug!( + "[PTRACE_LINK] Updating credentials for tracee={}", + self.raw_pid() + ); *self.cred.lock() = tracer.cred().clone(); + + log::debug!( + "[PTRACE_LINK] Link completed: tracer={} -> tracee={}", + tracer.raw_pid(), + self.raw_pid() + ); + Ok(()) } @@ -487,22 +744,72 @@ impl ProcessControlBlock { let parent = self.real_parent_pcb().ok_or(SystemError::ESRCH)?; self.flags().insert(ProcessFlags::PTRACED); self.ptrace_link(&parent)?; + + // 注意:不要修改 exit_signal! + // exit_signal 是用来表示进程退出时发送给父进程的信号(通常是 SIGCHLD) + // ptrace 注入的信号应该存储在 ptrace_state.injected_signal 中 + Ok(0) } /// 处理PTRACE_ATTACH请求 pub fn attach(&self, tracer: &Arc) -> Result { + log::debug!( + "[PTRACE_ATTACH] Starting attach: tracer={}, target={}", + tracer.raw_pid(), + self.raw_pid() + ); + // 验证权限(简化版) + // 按照 Linux 6.6.21 的 ptrace_attach 语义: + // 1. 不能 attach 自己 + // 2. 不能 attach 同一个线程组的其他线程 + let is_same_process = tracer.raw_pid() == self.raw_pid(); + let is_same_thread_group = tracer.raw_tgid() == self.raw_tgid(); + + log::debug!( + "[PTRACE_ATTACH] Permission check: tracer_pid={}, tracer_tgid={}, target_pid={}, target_tgid={}, same_process={}, same_thread_group={}", + tracer.raw_pid(), + tracer.raw_tgid(), + self.raw_pid(), + self.raw_tgid(), + is_same_process, + is_same_thread_group + ); + if !tracer.has_permission_to_trace(self) || self.flags().contains(ProcessFlags::KTHREAD) - || ProcessManager::same_thread_group(tracer, &self.self_ref) + || is_same_thread_group { + log::debug!( + "[PTRACE_ATTACH] Permission check failed for target={}", + self.raw_pid() + ); return Err(SystemError::EPERM); } - log::info!("attach by Tracer: {}", tracer.raw_pid()); + + log::debug!( + "[PTRACE_ATTACH] Setting PTRACED flag for target={}", + self.raw_pid() + ); self.flags().insert(ProcessFlags::PTRACED); + + log::debug!( + "[PTRACE_ATTACH] Calling ptrace_link: tracer={}, target={}", + tracer.raw_pid(), + self.raw_pid() + ); self.ptrace_link(tracer)?; + + // 注意:不要修改 exit_signal! + // exit_signal 是用来表示进程退出时发送给父进程的信号(通常是 SIGCHLD) + // ptrace 注入的信号应该存储在 ptrace_state.injected_signal 中 + let sig = Signal::SIGSTOP; + log::debug!( + "[PTRACE_ATTACH] Sending SIGSTOP to target={}", + self.raw_pid() + ); let mut info = SigInfo::new( sig, 0, @@ -514,62 +821,158 @@ impl ProcessControlBlock { self.self_ref.upgrade().unwrap(), PidType::PID, ) { + log::debug!( + "[PTRACE_ATTACH] Failed to send SIGSTOP to target={}, error={:?}", + self.raw_pid(), + e + ); // 回滚ptrace设置 self.flags().remove(ProcessFlags::PTRACED); let _ = self.ptrace_unlink()?; return Err(e); } - // { - // let guard = tracer.sighand(); - // signal_wake_up(self.self_ref.upgrade().unwrap(), guard, false); - // } - // todo proc_ptrace_connector(self, PTRACE_ATTACH); - // 确保目标进程被唤醒以处理 SIGSTOP - // 如果目标正在 sleep (INTERRUPTIBLE),kick 它让它处理信号 - ProcessManager::kick(&self.self_ref.upgrade().unwrap()); + + // 按照 Linux 6.6.21 的 ptrace_attach 语义: + // 发送 SIGSTOP 信号后,不需要手动 kick tracee + // tracee 会在下一次返回用户态时自动调用 do_signal 处理 + // 然后调用 ptrace_stop 并进入 TracedStopped 状态 + // + // 关键:不要调用 kick()!如果调用 kick(),会导致 tracee 被 wake up + // 然后 tracee 调用 schedule() 后可能立即被调度,无法正确进入 TracedStopped 状态 + log::debug!( + "[PTRACE_ATTACH] Sent SIGSTOP to target={}, waiting for it to process signal", + self.raw_pid() + ); + + // 等待 tracee 进入 TracedStopped 状态 + // 按照 Linux 6.6.21 语义:notify_tracer 调用 __wake_up_parent 唤醒 tracer 的 wait_queue + // 所以这里应该等待在 tracer 的 wait_queue 上,而不是 tracee 的 wait_queue + let tracee_ref = self.self_ref.upgrade().unwrap(); + let tracer_clone = tracer.clone(); + log::debug!( + "[PTRACE_ATTACH] Tracer {} entering wait_event_interruptible for tracee {}", + tracer.raw_pid(), + tracee_ref.raw_pid() + ); + let _wait_result = tracer_clone.wait_queue.wait_event_interruptible( + || { + let state = tracee_ref.sched_info().inner_lock_read_irqsave().state(); + let is_stopped = matches!(state, ProcessState::TracedStopped(_)); + log::debug!( + "[PTRACE_ATTACH] Wait check: tracee {} state={:?}, is_stopped={}", + tracee_ref.raw_pid(), + state, + is_stopped + ); + is_stopped + }, + None::, + ); + + log::debug!( + "[PTRACE_ATTACH] Attach completed: tracer={}, target={}", + tracer.raw_pid(), + self.raw_pid() + ); + Ok(0) } /// 处理PTRACE_DETACH请求 pub fn detach(&self, signal: Option) -> Result { + log::debug!( + "[PTRACE_DETACH] Detaching from PID {}, signal={:?}", + self.raw_pid(), + signal + ); + // 验证调用者是跟踪器 let current_pcb = ProcessManager::current_pcb(); if !self.is_traced_by(¤t_pcb) { return Err(SystemError::EPERM); } + + // 按照 Linux 6.6.21 的 ptrace_detach 实现: + // 1. 将 data 参数存储到 ptrace_state.injected_signal + // 2. 调用 __ptrace_detach (ptrace_unlink) + // 3. 恢复进程执行(使用与 ptrace_resume 相同的唤醒逻辑) + // + // 关键:data 参数会被传递给 ptrace_stop,作为恢复后要处理的信号 + // 如果 data 是 0,表示不发送任何信号,继续执行 + let data_signal = signal.unwrap_or(Signal::SIGCONT); + + // 将注入的信号存储到 ptrace_state.injected_signal + // 而不是 exit_signal!exit_signal 是用来表示进程退出时发送给父进程的信号 + let mut ptrace_state = self.ptrace_state.lock(); + ptrace_state.injected_signal = data_signal; + drop(ptrace_state); + + log::debug!( + "[PTRACE_DETACH] Set ptrace_state.injected_signal={:?} for PID {}", + data_signal, + self.raw_pid() + ); + + // 解除跟踪关系 + // ptrace_unlink 会自动恢复父进程为 real_parent + // 并清除 ProcessFlags::PTRACED 和 TRACE_SYSCALL self.ptrace_unlink()?; + + // 按照 Linux 6.6.21 的 ptrace_detach 实现: + // 使用与 ptrace_resume/wakeup_stop 相同的唤醒逻辑 + // Linux: child->jobctl &= ~JOBCTL_TRACED; wake_up_state(child, __TASK_TRACED); + // + // 关键:需要手动将 TracedStopped 状态改为 Runnable 并加入运行队列 + // signal_wake_up 不会唤醒 TracedStopped 状态的任务(它只唤醒 Blocked 状态) let mut sched_info = self.sched_info.inner_lock_write_irqsave(); - if let Some(sig) = signal { - // self.exit_signal.store(sig, Ordering::SeqCst); - self.ptrace_state.lock().exit_code = sig as usize; - } else { - // return Ok(0); - self.ptrace_state.lock().exit_code = 0; - } - let mut dead = !self.is_thread_group_leader(); - if !dead { - let real_parent = self.real_parent_pcb().ok_or(SystemError::ESRCH)?; - if !ProcessManager::same_thread_group(&real_parent, &self.self_ref) { - log::debug!("do_notify_parent, sig={:?}", signal.unwrap()); - dead = do_notify_parent(self, signal.unwrap())?; - return Ok(0); - } else if self - .sighand() - .handler(Signal::SIGCHLD) - .unwrap_or_default() - .action() - .is_ignore() - { - // todo unwrap? - self.wake_up_parent(None); - dead = true; + + // 检查当前状态 + match sched_info.state() { + ProcessState::TracedStopped(_) | ProcessState::Stopped(_) => { + // 将状态设置为 Runnable,让进程可以被调度 + sched_info.set_state(ProcessState::Runnable); + sched_info.set_wakeup(); + log::debug!( + "[PTRACE_DETACH] Set PID {} to Runnable and wakeup", + self.raw_pid() + ); + } + _ => { + // 进程可能已经由于其他原因被唤醒,仍然需要确保 sleep 标志被清除 + sched_info.set_wakeup(); + log::debug!( + "[PTRACE_DETACH] PID {} already runnable, just wakeup", + self.raw_pid() + ); } } - // todo - // if dead { - // self.exit_state.store(EXIT_DEAD, Ordering::SeqCst); - // } - // todo proc_ptrace_connector(self, PtraceRequest::PtraceDetach) + drop(sched_info); + + // 按照 wakeup_stop 的模式,使用 activate_task + check_preempt_currnet + // 确保 on_rq 被正确设置为 Queued + let rq = crate::sched::cpu_rq( + self.sched_info() + .on_cpu() + .unwrap_or(crate::smp::core::smp_get_processor_id()) + .data() as usize, + ); + + let (rq, _guard) = rq.self_lock(); + rq.update_rq_clock(); + let strong_ref = self.self_ref.upgrade().unwrap(); + rq.activate_task( + &strong_ref, + EnqueueFlag::ENQUEUE_WAKEUP | EnqueueFlag::ENQUEUE_NOCLOCK, + ); + + rq.check_preempt_currnet(&strong_ref, WakeupFlags::empty()); + + log::debug!( + "[PTRACE_DETACH] Detached from PID {}, injected {:?}, activated and preempt-checked", + self.raw_pid(), + data_signal + ); + Ok(0) } @@ -588,20 +991,59 @@ impl ProcessControlBlock { } _ => {} // PTRACE_CONT 不需要特殊标志 } - log::info!("signal: {:?} to process {}", signal, self.raw_pid()); - if signal == None { - self.exit_signal.store(Signal::SIGCONT, Ordering::SeqCst); - return Ok(0); - } - let mut sched_info = self.sched_info.inner_lock_write_irqsave(); + + // 按照 Linux 6.6.21 的 ptrace_resume 语义: + // data 参数应该存储到 ptrace_state.injected_signal + // 如果 data=0(signal 为 None),表示不注入任何信号,tracee 继续执行 + // 如果 data != 0,表示注入指定的信号 + let resume_signal = signal.unwrap_or(Signal::INVALID); + log::info!("signal: {:?} to process {}", resume_signal, self.raw_pid()); + // 清除停止/阻塞标志 - if let Some(sig) = signal { - self.exit_signal.store(sig, Ordering::SeqCst); - } self.flags().remove(ProcessFlags::STOPPED); - // 设置为可运行状态 - sched_info.set_state(ProcessState::Runnable); - // 加入调度队列 + + // 将注入的信号存储到 ptrace_state.injected_signal + // 而不是 exit_signal!exit_signal 是用来表示进程退出时发送给父进程的信号 + let mut ptrace_state = self.ptrace_state.lock(); + ptrace_state.injected_signal = resume_signal; + drop(ptrace_state); + + log::debug!( + "[PTRACE_RESUME] Set ptrace_state.injected_signal={:?} for PID {}", + resume_signal, + self.raw_pid() + ); + + // 按照 Linux 6.6.21 的 ptrace_resume 语义: + // 需要将 TracedStopped 状态的进程设置为 Runnable 并加入运行队列 + // + // 注意:必须在唤醒之前设置状态,否则 tracee 可能继续睡眠 + let mut sched_info = self.sched_info.inner_lock_write_irqsave(); + + // 检查当前状态 + match sched_info.state() { + ProcessState::TracedStopped(_) | ProcessState::Stopped(_) => { + // 将状态设置为 Runnable,让进程可以被调度 + sched_info.set_state(ProcessState::Runnable); + sched_info.set_wakeup(); + log::debug!( + "[PTRACE_RESUME] Set PID {} to Runnable and wakeup", + self.raw_pid() + ); + } + _ => { + // 进程可能已经由于其他原因被唤醒,仍然需要确保 sleep 标志被清除 + sched_info.set_wakeup(); + log::debug!( + "[PTRACE_RESUME] PID {} already runnable, just wakeup", + self.raw_pid() + ); + } + } + drop(sched_info); + + // 加入调度队列(如果不在队列中的话) + // enqueue_task 会检查是否已在队列中,避免重复加入 if let Some(strong_ref) = self.self_ref.upgrade() { let rq = self.sched_info.sched_entity().cfs_rq().rq(); let (rq, _guard) = rq.self_lock(); @@ -610,8 +1052,9 @@ impl ProcessControlBlock { EnqueueFlag::ENQUEUE_RESTORE | EnqueueFlag::ENQUEUE_WAKEUP, ); } else { - log::warn!("ptrace_runnable: pid={} self_ref is dead", self.raw_pid()); + log::warn!("ptrace_resume: pid={} self_ref is dead", self.raw_pid()); } + Ok(0) } @@ -622,9 +1065,27 @@ impl ProcessControlBlock { self.flags().remove(ProcessFlags::TRACE_SINGLESTEP); // 恢复进程运行 let mut sched_info = self.sched_info.inner_lock_write_irqsave(); - if let ProcessState::Stopped(_signal) = sched_info.state() { - sched_info.set_state(ProcessState::Runnable); + match sched_info.state() { + ProcessState::TracedStopped(_) | ProcessState::Stopped(_) => { + sched_info.set_state(ProcessState::Runnable); + sched_info.set_wakeup(); + } + _ => { + sched_info.set_wakeup(); + } } + drop(sched_info); + + // 加入调度队列 + if let Some(strong_ref) = self.self_ref.upgrade() { + let rq = self.sched_info.sched_entity().cfs_rq().rq(); + let (rq, _guard) = rq.self_lock(); + rq.enqueue_task( + strong_ref.clone(), + EnqueueFlag::ENQUEUE_RESTORE | EnqueueFlag::ENQUEUE_WAKEUP, + ); + } + Ok(0) } @@ -702,8 +1163,25 @@ impl ProcessControlBlock { // 恢复进程运行 let mut sched_info = self.sched_info.inner_lock_write_irqsave(); - if let ProcessState::Stopped(_signal) = sched_info.state() { - sched_info.set_state(ProcessState::Runnable); + match sched_info.state() { + ProcessState::TracedStopped(_) | ProcessState::Stopped(_) => { + sched_info.set_state(ProcessState::Runnable); + sched_info.set_wakeup(); + } + _ => { + sched_info.set_wakeup(); + } + } + drop(sched_info); + + // 加入调度队列 + if let Some(strong_ref) = self.self_ref.upgrade() { + let rq = self.sched_info.sched_entity().cfs_rq().rq(); + let (rq, _guard) = rq.self_lock(); + rq.enqueue_task( + strong_ref.clone(), + EnqueueFlag::ENQUEUE_RESTORE | EnqueueFlag::ENQUEUE_WAKEUP, + ); } Ok(0) diff --git a/kernel/src/process/syscall/sys_exit_group.rs b/kernel/src/process/syscall/sys_exit_group.rs index cc25a7b95..2058013bb 100644 --- a/kernel/src/process/syscall/sys_exit_group.rs +++ b/kernel/src/process/syscall/sys_exit_group.rs @@ -1,6 +1,6 @@ use crate::arch::interrupt::TrapFrame; use crate::arch::syscall::nr::SYS_EXIT_GROUP; -use crate::process::ProcessManager; +use crate::process::{ProcessFlags, ProcessManager}; use crate::syscall::table::{FormattedSyscallParam, Syscall}; use alloc::vec::Vec; use system_error::SystemError; @@ -20,6 +20,16 @@ impl Syscall for SysExitGroup { fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { let exit_code = Self::exit_code(args); + let pcb = ProcessManager::current_pcb(); + let has_pending = pcb.flags().contains(ProcessFlags::HAS_PENDING_SIGNAL); + let ptraced = pcb.flags().contains(ProcessFlags::PTRACED); + log::debug!( + "[EXIT_GROUP] PID {} exiting with code {}, has_pending={}, ptraced={}", + pcb.raw_pid(), + exit_code, + has_pending, + ptraced + ); // 仿照 Linux sys_exit_group:只取低 8 位并左移 8 位,形成 wstatus 编码, // 然后触发线程组整体退出。 ProcessManager::group_exit((exit_code & 0xff) << 8); diff --git a/kernel/src/process/syscall/sys_getpid.rs b/kernel/src/process/syscall/sys_getpid.rs index f73dc8bde..d7d44ca5f 100644 --- a/kernel/src/process/syscall/sys_getpid.rs +++ b/kernel/src/process/syscall/sys_getpid.rs @@ -15,7 +15,16 @@ impl Syscall for SysGetPid { /// 获取当前进程的tpid fn handle(&self, _args: &[usize], _frame: &mut TrapFrame) -> Result { let current_pcb = ProcessManager::current_pcb(); + log::debug!( + "[SYS_GETPID] PID {} calling getpid", + current_pcb.raw_pid() + ); let tgid = current_pcb.task_tgid_vnr().ok_or(SystemError::ESRCH)?; + log::debug!( + "[SYS_GETPID] PID {} getpid returning {}", + current_pcb.raw_pid(), + tgid.data() + ); Ok(tgid.into()) } diff --git a/kernel/src/process/syscall/sys_ptrace.rs b/kernel/src/process/syscall/sys_ptrace.rs index 4223cdca8..bff065db2 100644 --- a/kernel/src/process/syscall/sys_ptrace.rs +++ b/kernel/src/process/syscall/sys_ptrace.rs @@ -1,16 +1,96 @@ use crate::arch::interrupt::TrapFrame; use crate::arch::ipc::signal::Signal; use crate::arch::syscall::nr::{SYS_EXIT, SYS_PTRACE}; +use crate::mm::{MemoryManagementArch, PageTableKind, VirtAddr}; use crate::process::syscall::sys_exit::SysExit; use crate::process::{ ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState, PtraceOptions, PtraceRequest, RawPid, }; use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use crate::syscall::user_access::UserBufferWriter; use alloc::sync::Arc; use alloc::vec::Vec; use system_error::SystemError; +/// Linux 兼容的用户寄存器结构体 (x86_64) +/// 参考 /usr/include/x86_64-linux-gnu/sys/user.h +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct user_regs_struct { + pub r15: u64, + pub r14: u64, + pub r13: u64, + pub r12: u64, + pub rbp: u64, + pub rbx: u64, + pub r11: u64, + pub r10: u64, + pub r9: u64, + pub r8: u64, + pub rax: u64, + pub rcx: u64, + pub rdx: u64, + pub rsi: u64, + pub rdi: u64, + pub orig_rax: u64, + pub rip: u64, + pub cs: u64, + pub eflags: u64, + pub rsp: u64, + pub ss: u64, + pub fs_base: u64, + pub gs_base: u64, + pub ds: u64, + pub es: u64, + pub fs: u64, + pub gs: u64, +} + +/// 从 TrapFrame 和额外的寄存器信息构建 user_regs_struct +impl user_regs_struct { + /// 从 TrapFrame 转换,需要提供 fs_base 和 gs_base + /// + /// # Safety + /// + /// 调用者必须确保 trap_frame 指向的内存有效 + pub unsafe fn from_trap_frame_extra( + trap_frame: &TrapFrame, + fs_base: u64, + gs_base: u64, + ) -> Self { + Self { + r15: trap_frame.r15, + r14: trap_frame.r14, + r13: trap_frame.r13, + r12: trap_frame.r12, + rbp: trap_frame.rbp, + rbx: trap_frame.rbx, + r11: trap_frame.r11, + r10: trap_frame.r10, + r9: trap_frame.r9, + r8: trap_frame.r8, + rax: trap_frame.rax, + rcx: trap_frame.rcx, + rdx: trap_frame.rdx, + rsi: trap_frame.rsi, + rdi: trap_frame.rdi, + orig_rax: trap_frame.errcode, // syscall number + rip: trap_frame.rip, + cs: trap_frame.cs, + eflags: trap_frame.rflags, + rsp: trap_frame.rsp, + ss: trap_frame.ss, + fs_base, + gs_base, + ds: 0, + es: 0, + fs: 0, + gs: 0, + } + } +} + impl TryFrom for PtraceRequest { type Error = SystemError; @@ -120,18 +200,116 @@ impl SysPtrace { } /// 处理 PTRACE_PEEKDATA 请求(读取进程内存) + /// + /// 按照 Linux 6.6.21 的 ptrace 语义,PTRACE_PEEKDATA 需要从目标进程的地址空间读取数据 fn handle_peek_data( tracee: &Arc, addr: usize, ) -> Result { - // // 检查地址是否在用户空间范围 - // if !tracee.memory.is_valid_user(addr) { - // return Err(SystemError::EFAULT); - // } - // // 安全读取内存 - // let value = tracee.memory.read(addr)?; - // Ok(value as isize) - todo!() + // 获取目标进程的地址空间 + let tracee_vm = tracee.basic().user_vm().ok_or(SystemError::ESRCH)?; + + // 获取目标进程的用户页表物理地址 + let tracee_mapper_paddr = { + let inner = tracee_vm.read_irqsave(); + inner.user_mapper.utable.table().phys() + }; + + // 获取当前进程的用户页表物理地址(用于恢复) + let current_pcb = ProcessManager::current_pcb(); + let current_vm = current_pcb.basic().user_vm().ok_or(SystemError::ESRCH)?; + let current_mapper_paddr = { + let inner = current_vm.read_irqsave(); + inner.user_mapper.utable.table().phys() + }; + + // 切换到目标进程的页表 + unsafe { + ::set_table( + PageTableKind::User, + tracee_mapper_paddr, + ); + } + + // 读取数据 + let mut value: u64 = 0; + let result = unsafe { + crate::syscall::user_access::copy_from_user_protected( + core::slice::from_raw_parts_mut(&mut value as *mut u64 as *mut u8, 8), + VirtAddr::new(addr), + ) + }; + + // 恢复当前进程的页表 + unsafe { + ::set_table( + PageTableKind::User, + current_mapper_paddr, + ); + } + + if result.is_err() { + return Err(SystemError::EIO); + } + + Ok(value as isize) + } + + /// 处理 PTRACE_POKEDATA 请求(写入进程内存) + /// + /// 按照 Linux 6.6.21 的 ptrace 语义,PTRACE_POKEDATA 需要向目标进程的地址空间写入数据 + fn handle_poke_data( + tracee: &Arc, + addr: usize, + data: usize, + ) -> Result { + // 获取目标进程的地址空间 + let tracee_vm = tracee.basic().user_vm().ok_or(SystemError::ESRCH)?; + + // 获取目标进程的用户页表物理地址 + let tracee_mapper_paddr = { + let inner = tracee_vm.read_irqsave(); + inner.user_mapper.utable.table().phys() + }; + + // 获取当前进程的用户页表物理地址(用于恢复) + let current_pcb = ProcessManager::current_pcb(); + let current_vm = current_pcb.basic().user_vm().ok_or(SystemError::ESRCH)?; + let current_mapper_paddr = { + let inner = current_vm.read_irqsave(); + inner.user_mapper.utable.table().phys() + }; + + // 切换到目标进程的页表 + unsafe { + ::set_table( + PageTableKind::User, + tracee_mapper_paddr, + ); + } + + // 写入数据 + let value: u64 = data as u64; + let result = unsafe { + crate::syscall::user_access::copy_to_user_protected( + VirtAddr::new(addr), + core::slice::from_raw_parts(&value as *const u64 as *const u8, 8), + ) + }; + + // 恢复当前进程的页表 + unsafe { + ::set_table( + PageTableKind::User, + current_mapper_paddr, + ); + } + + if result.is_err() { + return Err(SystemError::EIO); + } + + Ok(0) } /// 处理 PTRACE_SINGLESTEP 请求 (单步执行) @@ -152,9 +330,67 @@ impl SysPtrace { } /// 处理 PTRACE_GETREGS 请求 (获取寄存器值) - fn handle_get_regs(tracee: &Arc) -> Result { - // let tf = tracee.context().trap_frame.as_ref(); - Ok(0) // 实际应返回寄存器结构体 + fn handle_get_regs( + tracee: &Arc, + data: usize, + ) -> Result { + // 获取 tracee 的 TrapFrame + // TrapFrame 位于内核栈顶部:kernel_stack.max_address - size_of::() + let kstack = tracee.kernel_stack(); + let trap_frame_vaddr = VirtAddr::new( + kstack.stack_max_address().data() - core::mem::size_of::(), + ); + + // 从 tracee 的内核栈读取 TrapFrame + let trap_frame = + unsafe { &*(trap_frame_vaddr.data() as *const TrapFrame) }; + + // 获取 fs_base 和 gs_base + let arch_info = tracee.arch_info_irqsave(); + let fs_base = arch_info.fsbase() as u64; + let gs_base = arch_info.gsbase() as u64; + drop(arch_info); + + // 构造用户态寄存器结构体 + let user_regs = user_regs_struct { + r15: trap_frame.r15, + r14: trap_frame.r14, + r13: trap_frame.r13, + r12: trap_frame.r12, + rbp: trap_frame.rbp, + rbx: trap_frame.rbx, + r11: trap_frame.r11, + r10: trap_frame.r10, + r9: trap_frame.r9, + r8: trap_frame.r8, + rax: trap_frame.rax, + rcx: trap_frame.rcx, + rdx: trap_frame.rdx, + rsi: trap_frame.rsi, + rdi: trap_frame.rdi, + orig_rax: trap_frame.errcode, // syscall number + rip: trap_frame.rip, + cs: trap_frame.cs, + eflags: trap_frame.rflags, + rsp: trap_frame.rsp, + ss: trap_frame.ss, + fs_base, + gs_base, + ds: 0, + es: 0, + fs: 0, + gs: 0, + }; + + // 拷贝到用户空间 + let mut writer = UserBufferWriter::new( + data as *mut u8, + core::mem::size_of::(), + true, + )?; + writer.copy_one_to_user(&user_regs, 0)?; + + Ok(0) } /// 处理 PTRACE_SETREGS 请求 (设置寄存器值) @@ -219,7 +455,7 @@ impl SysPtrace { fn ptrace_check_attach( tracee: &Arc, - request: PtraceRequest, + _request: PtraceRequest, ) -> Result<(), SystemError> { let current = ProcessManager::current_pcb(); @@ -229,7 +465,7 @@ impl SysPtrace { // 对于 KILL 请求,不需要目标处于停止状态 (Linux 逻辑) // 这里我们简化逻辑,要求必须 Stopped match tracee.sched_info().inner_lock_read_irqsave().state() { - ProcessState::Stopped(_) | ProcessState::TracedStopped => Ok(()), + ProcessState::Stopped(_) | ProcessState::TracedStopped(_) => Ok(()), _ => { // 如果请求是 KILL,Linux 允许不停止,但这里我们先严格要求 log::debug!("ptrace_check_attach: process not stopped"); @@ -279,10 +515,16 @@ impl Syscall for SysPtrace { PtraceRequest::PtraceSetoptions => Self::handle_set_options(&tracee, data)?, // 获取信号信息 PtraceRequest::PtraceGetsiginfo => Self::handle_get_siginfo(&tracee)?, + // 获取寄存器值 + PtraceRequest::PtraceGetregs => Self::handle_get_regs(&tracee, data)?, + // 设置寄存器值 + PtraceRequest::PtraceSetregs => Self::handle_set_regs(&tracee, data)?, // 读取用户寄存器 PtraceRequest::PtracePeekuser => Self::handle_peek_user(&tracee, addr)?, // 读取进程内存 PtraceRequest::PtracePeekdata => Self::handle_peek_data(&tracee, addr)?, + // 写入进程内存 + PtraceRequest::PtracePokedata => Self::handle_poke_data(&tracee, addr, data)?, // 其他请求类型 _ => { log::warn!("Unimplemented ptrace request: {:?}", request); diff --git a/user/apps/c_unitest/test_ptrace.c b/user/apps/c_unitest/test_ptrace.c index e1e97207a..7c77f1164 100644 --- a/user/apps/c_unitest/test_ptrace.c +++ b/user/apps/c_unitest/test_ptrace.c @@ -1,3 +1,30 @@ +/* +# test_ptrace.c测试在Linux下的行为 +=== Testing PTRACE_TRACEME === +Child ready for tracing +Child stopped by signal 19 (Stopped (signal)) +Child exited with status 0 +=== Testing PTRACE_ATTACH/DETACH === +target process 100 waiting... +Tracer attaching to target 100 +target stopped by signal 19 (Stopped (signal)) +Tracer detaching from target +target received 18 (Continued) +target exited with status 0 +=== Testing PTRACE_SYSCALL === +Child initial stop by signal 19 (Stopped (signal)) +Syscall entry detected: nr=39 +Syscall exit detected: nr=39 +Child called getpid() +Child exited normally +=== Testing PTRACE_PEEKDATA === +Child: msg_addr=0x49b643, heap_addr=0x23339c80, heap_val=0x66ccff +Parent: msg_addr=0x49b643, heap_addr=0x23339c80 +Read message: PTRACE_PEEKDATA_testing +Original heap value: 0x66ccff +Modified heap value: 0xee0000 +*/ + #include #include #include From 084ae8ce3bfd6e9cbf89e9c4235be6b60426ede1 Mon Sep 17 00:00:00 2001 From: aLinChe <1129332011@qq.com> Date: Sun, 11 Jan 2026 00:09:14 +0800 Subject: [PATCH 07/15] fix async bug Signed-off-by: aLinChe <1129332011@qq.com> --- kernel/src/arch/x86_64/ipc/signal.rs | 264 ++------ kernel/src/arch/x86_64/syscall/mod.rs | 23 +- kernel/src/exception/entry.rs | 8 +- kernel/src/ipc/generic_signal.rs | 52 +- kernel/src/ipc/kill.rs | 26 +- kernel/src/ipc/signal.rs | 183 +---- kernel/src/ipc/signal_types.rs | 54 +- kernel/src/ipc/syscall/sys_kill.rs | 14 - kernel/src/process/execve.rs | 7 +- kernel/src/process/exit.rs | 60 +- kernel/src/process/fork.rs | 12 +- kernel/src/process/mod.rs | 97 +-- kernel/src/process/ptrace.rs | 638 ++++++------------ kernel/src/process/syscall/sys_exit_group.rs | 7 - kernel/src/process/syscall/sys_getpid.rs | 9 - kernel/src/process/syscall/sys_ptrace.rs | 54 +- kernel/src/process/syscall/sys_tkill.rs | 2 +- .../syscall/gvisor/blocklists/ptrace_test | 16 + 18 files changed, 421 insertions(+), 1105 deletions(-) create mode 100644 user/apps/tests/syscall/gvisor/blocklists/ptrace_test diff --git a/kernel/src/arch/x86_64/ipc/signal.rs b/kernel/src/arch/x86_64/ipc/signal.rs index 7cbbfd1c0..9983f392b 100644 --- a/kernel/src/arch/x86_64/ipc/signal.rs +++ b/kernel/src/arch/x86_64/ipc/signal.rs @@ -11,7 +11,6 @@ pub use crate::ipc::generic_signal::GenericSigSet as SigSet; pub use crate::ipc::generic_signal::GenericSigStackFlags as SigStackFlags; pub use crate::ipc::generic_signal::GenericSignal as Signal; -// 调用一个 ptrace_signal 辅助函数 use crate::process::{ptrace::ptrace_signal, rseq::Rseq, ProcessFlags}; use crate::{ arch::{ @@ -494,77 +493,6 @@ impl UserUContext { } } -// /// siginfo中的si_code的可选值 -// /// 请注意,当这个值小于0时,表示siginfo来自用户态,否则来自内核态 -// #[derive(Copy, Debug, Clone, PartialEq, Eq)] -// pub enum SigCode { -// /// 描述通用来源 -// Origin(OriginCode), -// /// 描述 SIGCHLD 的具体原因 -// SigChld(ChldCode), -// } - -// /// 信号的通用来源码 (SI_*) -// #[derive(Copy, Debug, Clone, PartialEq, Eq)] -// #[repr(i32)] -// pub enum OriginCode { -// /// sent by kill, sigsend, raise -// User = 0, -// /// sent by kernel from somewhere -// Kernel = 0x80, -// /// 通过sigqueue发送 -// Queue = -1, -// /// 定时器过期时发送 -// Timer = -2, -// /// 当实时消息队列的状态发生改变时发送 -// Mesgq = -3, -// /// 当异步IO完成时发送 -// AsyncIO = -4, -// /// sent by queued SIGIO -// SigIO = -5, -// } - -// /// SIGCHLD 专用原因码 (CLD_*) -// #[derive(Copy, Debug, Clone, PartialEq, Eq)] -// #[repr(i32)] -// pub enum ChldCode { -// Exited = 1, -// Killed = 2, -// Dumped = 3, -// Trapped = 4, -// Stopped = 5, -// Continued = 6, -// } - -// impl SigCode { -// /// 为SigCode这个枚举类型实现从i32转换到枚举类型的转换函数 -// #[allow(dead_code)] -// pub fn from_i32(signal: Signal, code: i32) -> SigCode { -// match signal { -// Signal::SIGCHLD => match code { -// 1 => SigCode::SigChld(ChldCode::Exited), -// 2 => SigCode::SigChld(ChldCode::Killed), -// 3 => SigCode::SigChld(ChldCode::Dumped), -// 4 => SigCode::SigChld(ChldCode::Trapped), -// 5 => SigCode::SigChld(ChldCode::Stopped), -// 6 => SigCode::SigChld(ChldCode::Continued), -// _ => panic!("signal code not valid in {:?}", signal), -// }, -// // 对于其他信号,尝试匹配通用码 -// _ => match code { -// 0 => SigCode::Origin(OriginCode::User), -// 0x80 => SigCode::Origin(OriginCode::Kernel), -// -1 => SigCode::Origin(OriginCode::Queue), -// -2 => SigCode::Origin(OriginCode::Timer), -// -3 => SigCode::Origin(OriginCode::Mesgq), -// -4 => SigCode::Origin(OriginCode::AsyncIO), -// -5 => SigCode::Origin(OriginCode::SigIO), -// _ => panic!("signal code not valid in {:?}", signal), -// }, -// } -// } -// } - bitflags! { #[repr(C,align(8))] #[derive(Default)] @@ -692,88 +620,64 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { } let mut siginfo_mut_guard = siginfo_mut.unwrap(); + + // 按照 Linux 6.6.21 kernel/signal.c::get_signal 的语义: + // + // 1. 先检查 ptrace 拦截(所有信号,包括 kernel_only) + // 2. ptrace_signal 可以修改、取消或注入信号 + // 3. 处理 ptrace 返回的信号(可能已被修改) + // 4. 最后查找 sigaction 并根据 disposition 处理 + // + // 关键:ptrace 处理必须在 sigaction 查找之前完成! loop { (sig, info) = siginfo_mut_guard.dequeue_signal(&sig_block, &pcb); // 如果信号非法,则直接返回 if sig == Signal::INVALID { - log::debug!("[DO_SIGNAL] PID {} no more signals, returning", pcb.raw_pid()); return; } - log::debug!( - "[DO_SIGNAL] PID {} dequeued signal {:?}, PTRACED={}", - pcb.raw_pid(), - sig, - pcb.flags().contains(ProcessFlags::PTRACED) - ); - - // 按照 Linux 6.6.21 的实现: - // 在处理信号之前,如果进程被 ptrace,先调用 ptrace_signal - // ptrace_signal 会让进程停止并等待 tracer 的指令 - // - // 重要:在调用 ptrace_signal 之前必须释放 siginfo_mut_guard 锁 - // 因为 ptrace_stop 内部会调用 schedule(),要求 preempt_count = 0 - // 而 siginfo_mut_guard 持有锁时 preempt_count = 1 - // 按照 Linux 的做法,ptrace_stop 会在内部释放 sighand->siglock, - // 然后在返回前重新获取它(__releases/__acquires 标注) - if pcb.flags().contains(ProcessFlags::PTRACED) { - log::debug!( - "[DO_SIGNAL] PID {} is PTRACED, calling ptrace_signal for {:?}", - pcb.raw_pid(), - sig - ); + // ===== 第一步:ptrace 拦截(所有信号统一处理) ===== + // 按照 Linux 6.6.21:不管是 kernel_only 还是普通信号, + // 都先通过 ptrace_signal 让 tracer 决定如何处理 + let is_ptraced = pcb.flags().contains(ProcessFlags::PTRACED); + if is_ptraced { + // 保存 oldset,因为需要释放锁 + let _oldset = *siginfo_mut_guard.sig_blocked(); + // 释放锁,因为 ptrace_stop 内部会调用 schedule() + drop(siginfo_mut_guard); + CurrentIrqArch::interrupt_enable(); - // 保存当前需要的信息 - let _sig_blocked_cache = *siginfo_mut_guard.sig_blocked(); + // ptrace_signal 会: + // 1. 调用 ptrace_stop 停止进程 + // 2. 等待 tracer 的指令 + // 3. 返回 Some(新信号) 或 None(取消) + let result = ptrace_signal(&pcb, sig, &mut info); - // 在调用 ptrace_signal 前释放锁 - drop(siginfo_mut_guard); + // 重新获取锁以继续处理 + let siginfo_mut = pcb.try_siginfo_mut(5); + if siginfo_mut.is_none() { + return; + } + siginfo_mut_guard = siginfo_mut.unwrap(); - // ptrace_signal 会调用 ptrace_stop 让进程停止 - // 返回需要继续处理的信号(可能被 tracer 修改或取消) - let handled_sig = ptrace_signal(&pcb, sig, &mut info); - - // 重新获取锁 - siginfo_mut_guard = pcb.try_siginfo_mut(5).unwrap(); - - if let Some(handled_sig) = handled_sig { - // tracer 可能注入了新的信号或修改了原信号 - log::debug!( - "[DO_SIGNAL] PID {} ptrace_signal returned {:?}", - pcb.raw_pid(), - handled_sig - ); - sig = handled_sig; - } else { - // 信号被 ptrace 取消或重新排队,继续处理下一个信号 - log::debug!( - "[DO_SIGNAL] PID {} signal was cancelled by ptrace, continuing loop", - pcb.raw_pid() - ); - continue; + match result { + Some(new_sig) => { + // tracer 注入了新信号,继续处理 + sig = new_sig; + // 注意:不 continue,需要对新信号查找 sigaction + } + None => { + // tracer 取消了信号,继续下一个信号 + continue; + } } } - log::debug!( - "[DO_SIGNAL] PID {} processing signal {:?}, checking if kernel_only", - pcb.raw_pid(), - sig - ); - - // 对 kernel-only 信号(如 SIGKILL/SIGSTOP)直接使用默认处理,避免任何用户帧构造 + // ===== 第二步:处理 kernel_only 信号(SIGKILL/SIGSTOP) ===== + // 只有在非 ptrace 或 ptrace 返回了信号时才到这里 if sig.kernel_only() { - log::debug!( - "[DO_SIGNAL] PID {} signal {:?} is kernel_only, calling handle_default", - pcb.raw_pid(), - sig - ); - // log::error!( - // "do_signal: kernel-only sig={} for pid={:?} -> default handler (no user frame)", - // sig as i32, - // pcb.raw_pid() - // ); - // 释放锁,按常规路径在本线程上下文执行默认处理 + // kernel_only 信号使用默认处理 let _oldset = *siginfo_mut_guard.sig_blocked(); drop(siginfo_mut_guard); drop(pcb); @@ -782,20 +686,9 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { return; } - log::debug!( - "[DO_SIGNAL] PID {} getting sigaction for signal {:?}", - pcb.raw_pid(), - sig - ); + // ===== 第三步:查找 sigaction(普通信号) ===== let sa = pcb.sighand().handler(sig).unwrap(); - log::debug!( - "[DO_SIGNAL] PID {} signal {:?} sigaction: {:?}", - pcb.raw_pid(), - sig, - sa.action() - ); - match sa.action() { SigactionType::SaHandler(action_type) => match action_type { SaHandlerType::Error => { @@ -838,17 +731,11 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { } let oldset = *siginfo_mut_guard.sig_blocked(); - //避免死锁 drop(siginfo_mut_guard); - // no sig_struct guard to drop drop(pcb); - // 做完上面的检查后,开中断 - CurrentIrqArch::interrupt_enable(); - log::debug!("[DO_SIGNAL] No signal action to handle, returning without setting up frame"); - if sigaction.is_none() { - return; - } + // 开中断(如果有 ptrace,已经在中断开启状态下从 ptrace_stop 返回) + CurrentIrqArch::interrupt_enable(); let mut sigaction = sigaction.unwrap(); @@ -870,7 +757,6 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { } _ => { // Default 或 Ignore 动作不设置用户信号帧,got_signal 保持 false - log::debug!("[DO_SIGNAL] Default/Ignore action, got_signal remains false"); } } } @@ -894,39 +780,16 @@ fn try_restart_syscall(frame: &mut TrapFrame) { restore_saved_sigmask(); }); - let pcb = ProcessManager::current_pcb(); - let pid = pcb.raw_pid(); - // 关键修复:如果进程已经退出(例如处理了 SIGKILL 等致命信号),不重启系统调用 - let is_exited = pcb.sched_info().inner_lock_read_irqsave().state().is_exited(); - drop(pcb); - - if is_exited { - log::debug!("[TRY_RESTART] PID {}: already exited, not restarting syscall", pid); - return; - } - if unsafe { frame.syscall_nr() }.is_none() { - log::debug!("[TRY_RESTART] PID {}: no syscall, returning", pid); return; } - let syscall_nr = unsafe { frame.syscall_nr() }; - let rax_value = frame.rax; let syscall_err = unsafe { frame.syscall_error() }; if syscall_err.is_none() { - log::debug!("[TRY_RESTART] PID {}: no error, rax={:#x}, returning", pid, rax_value); return; } let syscall_err = syscall_err.unwrap(); - log::debug!( - "[TRY_RESTART] PID {}: syscall_nr={:?}, rax={:#x}, syscall_err={:?}", - pid, - syscall_nr, - rax_value, - syscall_err - ); - let mut restart = false; match syscall_err { SystemError::ERESTARTSYS | SystemError::ERESTARTNOHAND | SystemError::ERESTARTNOINTR => { @@ -941,13 +804,6 @@ fn try_restart_syscall(frame: &mut TrapFrame) { } _ => {} } - log::debug!( - "[TRY_RESTART] PID {}: restart={}, rip={:#x}, rax={:#x}", - pid, - restart, - frame.rip, - frame.rax - ); } pub struct X86_64SignalArch; @@ -957,27 +813,12 @@ impl SignalArch for X86_64SignalArch { /// /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/arch/x86/kernel/signal.c#865 unsafe fn do_signal_or_restart(frame: &mut TrapFrame) { - let pcb = ProcessManager::current_pcb(); - log::debug!("[DO_SIGNAL_OR_RESTART] PID {} entry, rip={:#x}, rsp={:#x}, state={:?}", - pcb.raw_pid(), frame.rip, frame.rsp, - pcb.sched_info().inner_lock_read_irqsave().state()); - drop(pcb); - let mut got_signal = false; do_signal(frame, &mut got_signal); - let pcb = ProcessManager::current_pcb(); - log::debug!("[DO_SIGNAL_OR_RESTART] PID {} after do_signal, got_signal={}, will_return_to_user={}", - pcb.raw_pid(), got_signal, frame.is_from_user()); - drop(pcb); - if got_signal { - log::debug!("[DO_SIGNAL_OR_RESTART] PID {} got_signal=true, NOT calling try_restart_syscall", - ProcessManager::current_pcb().raw_pid()); return; } - log::debug!("[DO_SIGNAL_OR_RESTART] PID {} got_signal=false, calling try_restart_syscall", - ProcessManager::current_pcb().raw_pid()); try_restart_syscall(frame); } @@ -1040,18 +881,7 @@ fn handle_signal( oldset: &SigSet, frame: &mut TrapFrame, ) -> Result { - log::debug!("handle_signal {:?}", sig); - - // 只在真正设置信号帧时(即自定义处理器)才修改系统调用错误码 - // 对于 Default 动作的信号,setup_frame 不会设置信号帧,而是调用 handle_default() 直接返回 - // 此时应该保留原始错误码,让 try_restart_syscan 正确处理系统调用重启 - let is_custom_handler = matches!( - sigaction.action(), - SigactionType::SaHandler(SaHandlerType::Customized(_)) - | SigactionType::SaSigaction(_) - ); - - if is_custom_handler && unsafe { frame.syscall_nr() }.is_some() { + if unsafe { frame.syscall_nr() }.is_some() { if let Some(syscall_err) = unsafe { frame.syscall_error() } { match syscall_err { SystemError::ERESTARTNOHAND => { diff --git a/kernel/src/arch/x86_64/syscall/mod.rs b/kernel/src/arch/x86_64/syscall/mod.rs index 246bb4ed6..e08a484c4 100644 --- a/kernel/src/arch/x86_64/syscall/mod.rs +++ b/kernel/src/arch/x86_64/syscall/mod.rs @@ -5,7 +5,9 @@ use crate::{ CurrentIrqArch, }, exception::InterruptArch, - ipc::signal_types::{OriginCode, SigCode, SigInfo, SigType, SignalArch}, + ipc::signal_types::{ + OriginCode, SigCode, SigFaultInfo, SigInfo, SigType, SignalArch, TrapCode, + }, libs::align::SafeForZero, mm::VirtAddr, process::{ProcessFlags, ProcessManager}, @@ -141,7 +143,7 @@ pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) { pcb.on_syscall_entry(syscall_num, &args); // 设置重启条件:使用 ERESTARTNOHAND 让 try_restart_syscall 稍后重启 - frame.rax = system_error::SystemError::ERESTARTNOHAND.to_posix_errno() as u64; + frame.rax = SystemError::ERESTARTNOHAND.to_posix_errno() as u64; // errcode 已经保存了原始系统调用号(line 69) // 标记已经完成入口停止,下次通过时将执行系统调用 @@ -151,13 +153,20 @@ pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) { pcb.flags().insert(ProcessFlags::HAS_PENDING_SIGNAL); // 发送 SIGTRAP 给自己,触发 ptrace 停止 (syscall entry) + // 使用 TRAP_TRACE (2) 表示系统调用跟踪 let mut info = SigInfo::new( Signal::SIGTRAP, - 0, // PTRACE_EVENTMSG_SYSCALL_ENTRY - SigCode::Origin(OriginCode::Kernel), - SigType::SigFault(crate::ipc::signal_types::SigFaultInfo { addr: 0, trapno: 0 }), + TrapCode::TrapTrace as i32, + SigCode::SigFault(SigFaultInfo { + addr: 0, + trapno: crate::ipc::signal_types::TrapCode::TrapTrace as i32, + }), + SigType::SigFault(SigFaultInfo { + addr: 0, + trapno: crate::ipc::signal_types::TrapCode::TrapTrace as i32, + }), ); - Signal::SIGTRAP.send_signal_info_to_pcb( + let _ = Signal::SIGTRAP.send_signal_info_to_pcb( Some(&mut info), pcb.clone(), crate::process::pid::PidType::PID, @@ -215,7 +224,7 @@ pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) { SigCode::Origin(OriginCode::Kernel), SigType::SigFault(crate::ipc::signal_types::SigFaultInfo { addr: 0, trapno: 0 }), ); - Signal::SIGTRAP.send_signal_info_to_pcb( + let _ = Signal::SIGTRAP.send_signal_info_to_pcb( Some(&mut info), pcb.clone(), crate::process::pid::PidType::PID, diff --git a/kernel/src/exception/entry.rs b/kernel/src/exception/entry.rs index e65b6b814..a790d5330 100644 --- a/kernel/src/exception/entry.rs +++ b/kernel/src/exception/entry.rs @@ -1,7 +1,7 @@ use crate::{ - arch::{CurrentSignalArch, interrupt::TrapFrame, ipc::signal::Signal}, + arch::{interrupt::TrapFrame, ipc::signal::Signal, CurrentSignalArch}, ipc::signal_types::SignalArch, - process::{ProcessFlags, ProcessManager, rseq::Rseq}, + process::{rseq::Rseq, ProcessFlags, ProcessManager}, }; #[no_mangle] @@ -60,10 +60,6 @@ unsafe fn exit_to_user_mode_loop(frame: &mut TrapFrame, mut process_flags_work: } if process_flags_work.contains(ProcessFlags::HAS_PENDING_SIGNAL) { - log::debug!( - "[EXIT_TO_USERMODE] PID {} calling do_signal_or_restart", - pcb.raw_pid() - ); unsafe { CurrentSignalArch::do_signal_or_restart(frame) }; } process_flags_work = *ProcessManager::current_pcb().flags(); diff --git a/kernel/src/ipc/generic_signal.rs b/kernel/src/ipc/generic_signal.rs index f2791fe0c..ad28739d4 100644 --- a/kernel/src/ipc/generic_signal.rs +++ b/kernel/src/ipc/generic_signal.rs @@ -137,13 +137,6 @@ impl GenericSignal { /// 调用信号的默认处理函数 pub fn handle_default(&self) { - let current_pcb = ProcessManager::current_pcb(); - log::debug!( - "[HANDLE_DEFAULT] PID {} handling signal {:?} with default action", - current_pcb.raw_pid(), - self - ); - match self { Self::INVALID => { log::error!("attempting to handler an Invalid"); @@ -431,37 +424,29 @@ fn sig_terminate_dump(sig: Signal) { } /// 信号默认处理函数——暂停进程 +/// +/// 按照 Linux 6.6.21 kernel/signal.c::get_signal -> do_signal_stop 的语义: +/// - 对于 ptrace 进程:ptrace 拦截发生在 signal 分发之前(ptrace_signal) +/// - 如果执行到这里,说明 tracer 已经允许信号传递给 tracee +/// - 但对于 ptrace 进程,"停止"不进入 TASK_STOPPED,而是由 tracer 控制状态 +/// - 因此这里绝不能再调用 ptrace_stop,否则会造成无限循环 fn sig_stop(sig: Signal) { - // 在接收者上下文设置停止标志,并让当前任务进入 Stopped let pcb = ProcessManager::current_pcb(); - // 标记停止事件,供 waitid(WSTOPPED) 可见 - pcb.sighand().flags_insert(SignalFlags::CLD_STOPPED); - pcb.sighand().flags_insert(SignalFlags::STOP_STOPPED); - - // 按照 Linux 6.6.21 的实现: - // 如果进程被 ptrace,需要调用 ptrace_stop 来停止进程并通知 tracer - // ptrace_stop 会让进程进入停止状态并等待 tracer 的恢复 + // ===== Ptrace 进程的特殊处理 ===== + // 按照 Linux 6.6.21:被 ptrace 的进程不会进入标准的 TASK_STOPPED 状态 + // 如果执行到这里,说明 ptrace_signal 已经在 do_signal 中处理过该信号 + // tracer 决定将信号注入给 tracee,但这不意味着 tracee 要再次停止 + // 直接返回,不做任何操作 if pcb.flags().contains(ProcessFlags::PTRACED) { - log::debug!("sig_stop: process is ptraced, calling ptrace_stop"); - // 对于 ptrace 进程,SIGSTOP 的默认处理需要真正停止进程 - // 调用 ptrace_stop 使进程停止并等待 tracer - use crate::ipc::signal_types::ChldCode; - let mut info = crate::ipc::signal_types::SigInfo::new( - sig, - 0, - crate::ipc::signal_types::SigCode::Origin(crate::ipc::signal_types::OriginCode::User), - crate::ipc::signal_types::SigType::SigFault(crate::ipc::signal_types::SigFaultInfo { - addr: 0, - trapno: 0, - }), - ); - pcb.ptrace_stop(sig as usize, ChldCode::Stopped, Some(&mut info)); - log::debug!("sig_stop: ptrace_stop returned, process resumed"); return; } - // 非 ptrace 进程的停止逻辑 + // ===== 非 ptrace 进程的 Group Stop 逻辑 ===== + // 标记停止事件,供 waitid(WSTOPPED) 可见 + pcb.sighand().flags_insert(SignalFlags::CLD_STOPPED); + pcb.sighand().flags_insert(SignalFlags::STOP_STOPPED); + let guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; ProcessManager::mark_stop(sig).unwrap_or_else(|e| { log::error!( @@ -472,10 +457,7 @@ fn sig_stop(sig: Signal) { ); }); drop(guard); - log::debug!( - "sig_stop: pid={:?} entered Stopped; notifying parent and scheduler", - ProcessManager::current_pcb().raw_pid() - ); + // 向父进程报告 SIGCHLD 并唤醒父进程可能阻塞的 wait let pcb = ProcessManager::current_pcb(); if let Some(parent) = pcb.parent_pcb() { diff --git a/kernel/src/ipc/kill.rs b/kernel/src/ipc/kill.rs index 1cd628eec..0adeef72a 100644 --- a/kernel/src/ipc/kill.rs +++ b/kernel/src/ipc/kill.rs @@ -1,10 +1,11 @@ -use crate::ipc::signal_types::{SigInfo, SigType}; -use crate::ipc::syscall::sys_kill::check_signal_permission_pcb_with_sig; use crate::process::pid::{Pid, PidType}; use crate::process::{ProcessControlBlock, ProcessManager, RawPid}; use crate::{ arch::ipc::signal::Signal, - ipc::signal_types::{OriginCode, SigCode}, + ipc::{ + signal_types::{OriginCode, SigCode, SigInfo, SigType}, + syscall::sys_kill::check_signal_permission_pcb_with_sig, + }, }; use alloc::sync::Arc; use alloc::vec::Vec; @@ -14,27 +15,15 @@ use system_error::SystemError; /// ### 向一个进程发送信号 /// kill() 系统调用发送进程级信号,使用 PidType::TGID pub fn send_signal_to_pid(pid: RawPid, sig: Signal) -> Result { - log::debug!( - "[SEND_SIGNAL_TO_PID] ===== ENTRY: Sending signal {:?} to PID {}", - sig, - pid - ); - // 查找目标进程 let target = ProcessManager::find_task_by_vpid(pid); if target.is_none() { - log::debug!("[SEND_SIGNAL_TO_PID] ===== ERROR: Target PID {} not found!", pid); return Err(SystemError::ESRCH); } let target = target.unwrap(); - log::debug!( - "[SEND_SIGNAL_TO_PID] Found target PID {}, calling send_signal_info_to_pcb", - pid - ); - // 检查权限(传入信号以处理 SIGCONT 特殊情况) check_signal_permission_pcb_with_sig(&target, Some(sig))?; @@ -54,18 +43,11 @@ pub fn send_signal_to_pid(pid: RawPid, sig: Signal) -> Result, pt: PidType) { - log::debug!( - "[COMPLETE_SIGNAL] Sending signal {:?} to PID {}, pt={:?}", - self, - pcb.raw_pid(), - pt - ); - compiler_fence(core::sync::atomic::Ordering::SeqCst); // ===== 寻找需要wakeup的目标进程 ===== // 备注:由于当前没有进程组的概念,每个进程只有1个对应的线程,因此不需要通知进程组内的每个进程。 @@ -270,22 +264,12 @@ impl Signal { // 根据信号类型选择添加到线程级 pending 还是进程级 shared_pending let is_thread_target = matches!(pt, PidType::PID); if is_thread_target { - log::debug!( - "[COMPLETE_SIGNAL] Adding signal {:?} to PID {} thread pending", - self, - pcb.raw_pid() - ); // 线程级信号:添加到线程的 sig_pending pcb.sig_info_mut() .sig_pending_mut() .signal_mut() .insert((*self).into()); } else { - log::debug!( - "[COMPLETE_SIGNAL] Adding signal {:?} to PID {} shared pending", - self, - pcb.raw_pid() - ); // 进程级信号:添加到 shared_pending // 注意:正常路径下(send_signal/enqueue_signal_locked)进程级信号会通过 // shared_pending_push() 同时完成“入队 + 位图置位”。这里仍然保留位图置位, @@ -299,23 +283,13 @@ impl Signal { // 若目标进程存在 signalfd 监听该信号,需要唤醒其等待者/epoll。 crate::ipc::signalfd::notify_signalfd_for_pcb(&pcb, *self); // 判断目标进程是否应该被唤醒以立即处理该信号 - log::debug!( - "[COMPLETE_SIGNAL] Checking if PID {} wants signal {:?}", - pcb.raw_pid(), - self - ); let wants_signal = self.wants_signal(pcb.clone()); - // 按照 Linux 6.6.21 语义: - // 对于被 ptrace 的进程,如果收到 SIGSTOP 信号,需要特殊处理: - // 1. 如果进程处于 Blocked 状态(如在 pause(), sleep() 等),需要唤醒它来处理信号 - // 2. 如果进程处于 Runnable 状态,不需要唤醒(它会自动处理) - // 3. 这样可以避免竞态条件:tracer 在 waitpid 之前 tracee 就被唤醒并继续执行 + // 按照 Linux 6.6.21 语义:对于被 ptrace 的进程,如果收到 SIGSTOP 信号,需要特殊处理 let is_ptrace_sigstop = pcb.flags().contains(ProcessFlags::PTRACED) && *self == Signal::SIGSTOP; let should_wake = if is_ptrace_sigstop { - // 对于 ptrace SIGSTOP,只有进程处于 Blocked 状态时才唤醒 matches!( pcb.sched_info().inner_lock_read_irqsave().state(), ProcessState::Blocked(_) @@ -325,28 +299,13 @@ impl Signal { }; if should_wake { - log::debug!( - "[COMPLETE_SIGNAL] PID {} wants signal {:?} (or blocked+ptrace SIGSTOP), will call signal_wake_up", - pcb.raw_pid(), - self - ); target_pcb = Some(pcb.clone()); } else if pt == PidType::PID { - log::debug!( - "[COMPLETE_SIGNAL] PID {} doesn't want signal {:?} (or runnable+ptrace SIGSTOP), pt=PID, returning without wake_up", - pcb.raw_pid(), - self - ); /* * 单线程场景且不需要唤醒:信号已入队,等待合适时机被取走 */ return; } else { - log::debug!( - "[COMPLETE_SIGNAL] PID {} doesn't want signal {:?} (or runnable+ptrace SIGSTOP), returning without wake_up", - pcb.raw_pid(), - self - ); /* * Otherwise try to find a suitable thread. * 由于目前每个进程只有1个线程,因此当前情况可以返回。信号队列的dequeue操作不需要考虑同步阻塞的问题。 @@ -359,11 +318,6 @@ impl Signal { // 统一按既有规则唤醒:STOP 信号需要把阻塞的系统调用唤醒到信号处理路径, // 由目标进程在自身上下文中执行默认处理(sig_stop),从而原地进入 Stopped,避免返回到用户态。 if let Some(target_pcb) = target_pcb { - log::debug!( - "[COMPLETE_SIGNAL] Calling signal_wake_up for PID {} with signal {:?}", - target_pcb.raw_pid(), - self - ); signal_wake_up(target_pcb.clone(), *self == Signal::SIGKILL); } } @@ -374,27 +328,13 @@ impl Signal { /// 这么做是为了防止我们把信号发送给了一个正在或已经退出的进程,或者是不响应该信号的进程。 #[inline] fn wants_signal(&self, pcb: Arc) -> bool { - log::debug!( - "[WANTS_SIGNAL] Checking if PID {} wants signal {:?}", - pcb.raw_pid(), - self - ); - // 若进程正在退出,则不能接收 if pcb.flags().contains(ProcessFlags::EXITING) { - log::debug!( - "[WANTS_SIGNAL] PID {} is exiting, returning false", - pcb.raw_pid() - ); return false; } // SIGKILL 总是唤醒 if *self == Signal::SIGKILL { - log::debug!( - "[WANTS_SIGNAL] SIGKILL for PID {}, returning true", - pcb.raw_pid() - ); return true; } @@ -402,31 +342,14 @@ impl Signal { // 则无论该信号是否在常规 blocked 集内,都应唤醒,由具体系统调用在返回路径上判定。 let state = pcb.sched_info().inner_lock_read_irqsave().state(); - log::debug!("[WANTS_SIGNAL] PID {} state: {:?}", pcb.raw_pid(), state); - // SIGCONT:即便被屏蔽或默认忽略,也应唤醒处于 Stopped 的任务,让其继续运行。 if *self == Signal::SIGCONT && state.is_stopped() { - log::debug!( - "[WANTS_SIGNAL] SIGCONT for stopped PID {}, returning true", - pcb.raw_pid() - ); return true; } let is_blocked_interruptable = state.is_blocked_interruptable(); let has_restore_sig_mask = pcb.flags().contains(ProcessFlags::RESTORE_SIG_MASK); - log::debug!( - "[WANTS_SIGNAL] PID {} is_blocked_interruptable={}, has_restore_sig_mask={}", - pcb.raw_pid(), - is_blocked_interruptable, - has_restore_sig_mask - ); - if is_blocked_interruptable && has_restore_sig_mask { - log::debug!( - "[WANTS_SIGNAL] PID {} blocked_interruptable + RESTORE_SIG_MASK, returning true", - pcb.raw_pid() - ); return true; } @@ -434,45 +357,17 @@ impl Signal { let blocked = *pcb.sig_info_irqsave().sig_blocked(); let is_blocked = blocked.contains((*self).into()); - log::debug!( - "[WANTS_SIGNAL] PID {} signal {:?} blocked={}, sig_blocked_set={:?}", - pcb.raw_pid(), - self, - is_blocked, - blocked - ); - if is_blocked { - log::debug!( - "[WANTS_SIGNAL] PID {} signal {:?} is blocked, returning false", - pcb.raw_pid(), - self - ); return false; } let is_blocked_non_interruptable = state.is_blocked() && (!state.is_blocked_interruptable()); - log::debug!( - "[WANTS_SIGNAL] PID {} is_blocked_non_interruptable={}", - pcb.raw_pid(), - is_blocked_non_interruptable - ); - if is_blocked_non_interruptable { - log::debug!( - "[WANTS_SIGNAL] PID {} is in non-interruptible blocked state, returning false", - pcb.raw_pid() - ); return false; } - log::debug!( - "[WANTS_SIGNAL] PID {} wants signal {:?}, returning true", - pcb.raw_pid(), - self - ); return true; } @@ -587,14 +482,8 @@ impl Signal { flush = Signal::SIGCONT.into_sigset(); // 对于 ptrace 进程,SIGSTOP 应该在 do_signal 中由 ptrace_signal 处理 - // 但是,我们仍然需要清理 SIGCONT,保持信号状态的一致性 if pcb.flags().contains(ProcessFlags::PTRACED) { - log::debug!( - "[PREPARE_SIGNAL] PID {} is ptraced, flushing SIGCONT but skipping stop handling", - pcb.raw_pid() - ); // 只清理 SIGCONT,不执行停止操作 - // 让信号正常入队,由 ptrace_signal 在 do_signal 中处理 thread_group_leader .sighand() .shared_pending_flush_by_mask(&flush); @@ -627,28 +516,11 @@ impl Signal { }); if let Some(parent) = pcb.parent_pcb() { - log::debug!( - "[SIGSTOP] PID {} sending SIGCHLD to parent={} via parent_pcb", - pcb.raw_pid(), - parent.raw_pid() - ); - let _ = crate::ipc::kill::send_signal_to_pcb(parent.clone(), Signal::SIGCHLD); + let _ = send_signal_to_pcb(parent.clone(), Signal::SIGCHLD); parent.wake_all_waiters(); - } else { - log::debug!( - "[SIGSTOP] PID {} has no parent_pcb, trying real_parent", - pcb.raw_pid() - ); - if let Some(real_parent) = pcb.real_parent_pcb() { - log::debug!( - "[SIGSTOP] PID {} sending SIGCHLD to real_parent={}", - pcb.raw_pid(), - real_parent.raw_pid() - ); - let _ = - crate::ipc::kill::send_signal_to_pcb(real_parent.clone(), Signal::SIGCHLD); - real_parent.wake_all_waiters(); - } + } else if let Some(real_parent) = pcb.real_parent_pcb() { + let _ = send_signal_to_pcb(real_parent.clone(), Signal::SIGCHLD); + real_parent.wake_all_waiters(); } // 唤醒等待在该子进程/线程上的等待者 thread_group_leader.wake_all_waiters(); @@ -657,7 +529,7 @@ impl Signal { }); // SIGSTOP 是 kernel-only stop 信号:其效果是把线程组置为 stopped 并通知父进程, - // 不应作为“可传递到用户态”的 pending 信号继续入队。 + // 不应作为"可传递到用户态"的 pending 信号继续入队。 // 否则在 SIGCONT 后可能错误地以 EINTR/ERESTART* 形式打断正在执行的系统调用(gVisor sigstop_test 即依赖这一点)。 if *self == Signal::SIGSTOP { return false; @@ -701,18 +573,11 @@ impl Signal { .sighand() .flags_remove(SignalFlags::STOP_STOPPED); if let Some(parent) = pcb.parent_pcb() { - log::debug!( - "[SIGCONT] PID {} sending SIGCHLD to parent={} via parent_pcb", - pcb.raw_pid(), - parent.raw_pid() - ); - let _ = crate::ipc::kill::send_signal_to_pcb(parent.clone(), Signal::SIGCHLD); + let _ = send_signal_to_pcb(parent.clone(), Signal::SIGCHLD); parent.wake_all_waiters(); - } else { - log::debug!( - "[SIGCONT] PID {} has no parent_pcb, trying real_parent", - pcb.raw_pid() - ); + } else if let Some(real_parent) = pcb.real_parent_pcb() { + let _ = send_signal_to_pcb(real_parent.clone(), Signal::SIGCHLD); + real_parent.wake_all_waiters(); } // 唤醒等待在该子进程上的等待者 thread_group_leader.wake_all_waiters(); @@ -742,12 +607,7 @@ impl Signal { pub fn signal_wake_up(pcb: Arc, fatal: bool) { // 如果是 fatal 的话就唤醒 stop 和 block 的进程来响应,因为唤醒后就会终止 // 如果不是 fatal 的就只唤醒 stop 的进程来响应 - log::debug!( - "[signal_wake_up] PID {} state={:?}, fatal={}", - pcb.raw_pid(), - pcb.sched_info().inner_lock_read_irqsave().state(), - fatal - ); + // debug!("signal_wake_up"); // 如果目标进程已经在运行,则发起一个ipi,使得它陷入内核 let state = pcb.sched_info().inner_lock_read_irqsave().state(); let mut wakeup_ok = true; @@ -771,14 +631,21 @@ pub fn signal_wake_up(pcb: Arc, fatal: bool) { // 强制让目标CPU陷入内核,尽快处理 pending 的信号(包括作业控制停止/继续) // 即使目标任务当前处于 Runnable,也需要 kick 以触发内核路径的 do_signal。 - // 对于非致命信号(如 SIGSTOP),如果进程在 Runnable 状态,仍然需要 kick - // 以便它在返回用户空间前处理信号 - if !wakeup_ok && !fatal { - // 当Runnable状态的进程从系统调用返回时,会看到 pending 信号并处理它 - ProcessManager::kick(&pcb); - } else if wakeup_ok { + if wakeup_ok { + // log::debug!( + // "signal_wake_up: target pid={:?}, state={:?}, fatal={} -> kick", + // pcb.raw_pid(), + // state, + // fatal + // ); ProcessManager::kick(&pcb); } else if fatal { + // log::debug!( + // "signal_wake_up: target pid={:?}, state={:?}, fatal={} -> wakeup+kick", + // pcb.raw_pid(), + // state, + // fatal + // ); let _r = ProcessManager::wakeup(&pcb).map(|_| { ProcessManager::kick(&pcb); }); diff --git a/kernel/src/ipc/signal_types.rs b/kernel/src/ipc/signal_types.rs index 47ec3c773..d4ba13dc9 100644 --- a/kernel/src/ipc/signal_types.rs +++ b/kernel/src/ipc/signal_types.rs @@ -23,6 +23,10 @@ pub enum SigCode { Origin(OriginCode), /// 描述 SIGCHLD 的具体原因 SigChld(ChldCode), + /// 描述 SIGTRAP 的具体原因 (TRAP_*) + SigFault(SigFaultInfo), + /// 描述 SIGILL/SIGFPE/SIGSEGV/SIGBUS 的原因 + Ill(IllCode), } impl From for i32 { @@ -30,6 +34,8 @@ impl From for i32 { match code { SigCode::Origin(origin) => origin as i32, SigCode::SigChld(chld) => chld as i32, + SigCode::SigFault(fault) => fault.trapno, + SigCode::Ill(ill) => ill as i32, } } } @@ -68,6 +74,52 @@ pub enum ChldCode { Continued = 6, } +/// SIGTRAP si_codes (TRAP_*) +/// 用于区分不同类型的陷阱/断点 +#[derive(Copy, Debug, Clone, PartialEq, Eq)] +#[repr(i32)] +#[allow(dead_code)] +pub enum TrapCode { + /// process breakpoint - 断点触发 + TrapBrkpt = 1, + /// process trace trap - ptrace 单步执行 + TrapTrace = 2, + /// process taken branch trap - 分支跟踪 + TrapBranch = 3, + /// hardware breakpoint/watchpoint - 硬件断点 + TrapHwbkpt = 4, + /// undiagnosed trap - 未诊断的陷阱 + TrapUnk = 5, + /// perf event with sigtrap=1 - 性能事件 + TrapPerf = 6, +} + +/// SIGILL/SIGFPE/SIGSEGV/SIGBUS 的原因码 (ILL_*, FPE_*, SEGV_*, BUS_*) +#[derive(Copy, Debug, Clone, PartialEq, Eq)] +#[repr(i32)] +pub enum IllCode { + /// 求编代码错误 + IllIll = 1, + /// 汇编指令的 operand 不存在 + IllIlladr = 2, +} + +/// SIGFPE si_codes +#[derive(Copy, Debug, Clone, PartialEq, Eq)] +#[repr(i32)] +#[allow(dead_code)] +pub enum FpeCode { + IntDiv = 1, /* integer divide by zero */ + IntoOvf = 2, /* integer overflow */ + FltDiv = 3, /* floating point divide by zero */ + FltOvf = 4, /* floating point overflow */ + FltUnd = 5, /* floating point underflow */ + FltInv = 6, /* floating point invalid operation */ + FltSub = 7, /* subscript out of range */ + FltDive = 8, /* floating point division by zero */ + Isock = 9, /* Invalid socket operation */ +} + impl SigCode { pub fn try_from_i32(x: i32) -> Option { match x { @@ -638,7 +690,7 @@ pub enum SigType { // SigSys, } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct SigFaultInfo { pub addr: usize, pub trapno: i32, diff --git a/kernel/src/ipc/syscall/sys_kill.rs b/kernel/src/ipc/syscall/sys_kill.rs index bc65fb60d..8fe5d40b4 100644 --- a/kernel/src/ipc/syscall/sys_kill.rs +++ b/kernel/src/ipc/syscall/sys_kill.rs @@ -207,13 +207,6 @@ impl Syscall for SysKillHandle { let current_pcb = ProcessManager::current_pcb(); - log::debug!( - "[SYS_KILL] PID {} sending signal {} to PID {}", - current_pcb.raw_pid(), - sig_c_int, - id - ); - let converter = PidConverter::from_id(id).ok_or(SystemError::ESRCH)?; // Handle null signal (signal 0) - used for existence and permission checks @@ -230,13 +223,6 @@ impl Syscall for SysKillHandle { return Err(SystemError::EINVAL); } - log::debug!( - "[SYS_KILL] Signal {:?} to PID {}, converter={:?}", - sig, - id, - converter - ); - match converter { PidConverter::Pid(pid) => send_signal_to_pid(pid.pid_vnr(), sig), PidConverter::Pgid(pgid) => send_signal_to_pgid(&pgid.ok_or(SystemError::ESRCH)?, sig), diff --git a/kernel/src/process/execve.rs b/kernel/src/process/execve.rs index 7733c9eb6..bb31bdf8d 100644 --- a/kernel/src/process/execve.rs +++ b/kernel/src/process/execve.rs @@ -1,16 +1,11 @@ -use crate::arch::ipc::signal::Signal; use crate::arch::CurrentIrqArch; use crate::exception::InterruptArch; use crate::filesystem::vfs::IndexNode; -use crate::ipc::signal_types::{ - ChldCode, SigChldInfo, SigCode, SigFaultInfo, SigInfo, SigType, SignalFlags, -}; use crate::libs::rwsem::RwSem; use crate::process::exec::{ load_binary_file_with_context, ExecContext, ExecParam, ExecParamFlags, LoadBinaryResult, }; -use crate::process::PtraceEvent; -use crate::process::{ProcessFlags, ProcessManager}; +use crate::process::ProcessManager; use crate::syscall::Syscall; use crate::{libs::rand::rand_bytes, mm::ucontext::AddressSpace}; diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs index 64dc0c6a6..ecc9066dd 100644 --- a/kernel/src/process/exit.rs +++ b/kernel/src/process/exit.rs @@ -204,42 +204,20 @@ fn is_eligible_child(child_pcb: &Arc, options: WaitOption) None => match child_pcb.real_parent_pcb() { Some(p) => p, None => { - log::debug!( - "[ELIGIBLE_CHILD] child {} has no parent, returning false", - child_pcb.raw_pid() - ); return false; } }, }; - log::debug!( - "[ELIGIBLE_CHILD] child={}, child_parent={}, current={}, current_tgid={}", - child_pcb.raw_pid(), - child_parent.raw_pid(), - current.raw_pid(), - current_tgid - ); - if options.contains(WaitOption::WNOTHREAD) { // 带 __WNOTHREAD:只能等待当前线程自己创建的子进程 // 检查子进程的 parent 是否就是当前线程 let result = Arc::ptr_eq(&child_parent, ¤t); - log::debug!( - "[ELIGIBLE_CHILD] WNOTHREAD check: parent_eq_current={}", - result - ); result } else { // 默认情况:线程组中的任何线程都可以等待同一线程组中任何线程创建的子进程 // 检查子进程的 parent 的 tgid 是否与当前线程的 tgid 相同 let result = child_parent.tgid == current_tgid; - log::debug!( - "[ELIGIBLE_CHILD] tgid check: parent_tgid={}, current_tgid={}, equal={}", - child_parent.tgid, - current_tgid, - result - ); result } } @@ -354,13 +332,6 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { let wait_res = parent.wait_queue.wait_event_interruptible( || { let rd_childen = parent.children.read(); - let children_pids: alloc::vec::Vec = rd_childen.iter().map(|p| p.data()).collect(); - log::debug!( - "[DO_WAIT] PID {} scanning children list, count={}, children={:?}", - parent.raw_pid(), - rd_childen.len(), - children_pids - ); if rd_childen.is_empty() { echild = true; return true; @@ -387,16 +358,6 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { all_children_exited = false; } - log::debug!( - "[DO_WAIT] checking child={}, state={:?}, is_exited={}, WSTOPPED={}, WEXITED={}, CLD_STOPPED={}", - pcb.raw_pid(), - state, - state.is_exited(), - kwo.options.contains(WaitOption::WSTOPPED), - kwo.options.contains(WaitOption::WEXITED), - pcb.sighand().flags_contains(SignalFlags::CLD_STOPPED) - ); - if matches!(state, ProcessState::Stopped(_)) && kwo.options.contains(WaitOption::WSTOPPED) && pcb.sighand().flags_contains(SignalFlags::CLD_STOPPED) @@ -681,15 +642,6 @@ fn do_waitpid( child_pcb: Arc, kwo: &mut KernelWaitOption, ) -> Option> { - log::debug!( - "[DO_WAITPID] child={}, WEXITED={}, WSTOPPED={}, WUNTRACED={}, WCONTINUED={}", - child_pcb.raw_pid(), - kwo.options.contains(WaitOption::WEXITED), - kwo.options.contains(WaitOption::WSTOPPED), - kwo.options.contains(WaitOption::WUNTRACED), - kwo.options.contains(WaitOption::WCONTINUED) - ); - // 优先处理继续事件:与 Linux 语义一致,只要标志存在即可报告 if kwo.options.contains(WaitOption::WCONTINUED) && child_pcb @@ -717,11 +669,6 @@ fn do_waitpid( } let state = child_pcb.sched_info().inner_lock_read_irqsave().state(); - log::debug!( - "[DO_WAITPID] child={} got state={:?}", - child_pcb.raw_pid(), - state - ); // 获取退出码 match state { ProcessState::Runnable => { @@ -741,7 +688,7 @@ fn do_waitpid( // - ((signal << 8) | 0x80) - ptrace 陷阱停止 // 我们需要提取实际的信号编号 (低 8 位 & 0x7f) let actual_sig = stopsig & 0x7f; - if actual_sig <= 0 || actual_sig >= Signal::SIGRTMAX.into() { + if actual_sig >= Signal::SIGRTMAX.into() { return Some(Err(SystemError::EINVAL)); } let ptrace = child_pcb.is_traced(); @@ -785,11 +732,6 @@ fn do_waitpid( // 这是 ptrace 专用的停止状态,总是报告给 tracer // 提取实际的信号编号 (低 8 位 & 0x7f) let actual_sig = stopsig & 0x7f; - log::debug!( - "[DO_WAITPID] child={} is TracedStopped with sig={}, returning Some", - child_pcb.raw_pid(), - actual_sig - ); if actual_sig <= 0 || actual_sig >= Signal::SIGRTMAX.into() { return Some(Err(SystemError::EINVAL)); } diff --git a/kernel/src/process/fork.rs b/kernel/src/process/fork.rs index 0ae03e1b7..e51e89bb9 100644 --- a/kernel/src/process/fork.rs +++ b/kernel/src/process/fork.rs @@ -696,17 +696,7 @@ impl ProcessManager { // 验证设置 let verify_parent = pcb.parent_pcb.read_irqsave(); - let verify_pid = verify_parent - .upgrade() - .map(|p| p.raw_pid()); - - log::debug!( - "[FORK] Set parent: child={}, parent={}, verified parent={:?}", - child_pid, - current_pid, - verify_pid - ); - + let verify_pid = verify_parent.upgrade().map(|p| p.raw_pid()); pcb.exit_signal .store(clone_args.exit_signal, Ordering::SeqCst); } diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 3d18d21d5..201a4fff8 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -430,13 +430,6 @@ impl ProcessManager { fn exit_notify() { let current = ProcessManager::current_pcb(); - log::debug!( - "[EXIT_NOTIFY] PID {} exiting, parent_pcb={:?}, real_parent_pcb={:?}", - current.raw_pid(), - current.parent_pcb().map(|p| p.raw_pid()), - current.real_parent_pcb().map(|p| p.raw_pid()) - ); - // 让INIT进程收养所有子进程 if current.raw_pid() != RawPid(1) { unsafe { @@ -445,43 +438,16 @@ impl ProcessManager { .unwrap_or_else(|e| panic!("adopte_childen failed: error: {e:?}")) }; - // 重新读取parent_pcb,因为adopt_children可能修改了它 - log::debug!( - "[EXIT_NOTIFY] After adopt_children, PID {} parent_pcb={:?}", - current.raw_pid(), - current.parent_pcb().map(|p| p.raw_pid()) - ); - let r = current.parent_pcb.read_irqsave().upgrade(); if r.is_none() { - log::debug!( - "[EXIT_NOTIFY] PID {} parent_pcb is None, cannot send SIGCHLD", - current.raw_pid() - ); return; } let parent_pcb = r.unwrap(); - log::debug!( - "[EXIT_NOTIFY] PID {} sending exit_signal={:?} to parent={}", - current.raw_pid(), - current.exit_signal.load(Ordering::SeqCst), - parent_pcb.raw_pid() - ); - // 按照 Linux 6.6.21 的语义: - // 1. 对于被 ptrace 的进程,应该发送 SIGCHLD 给父进程(tracer) - // 即使 exit_signal 被 ptrace 注入覆盖了 - // 2. 对于普通进程,使用 exit_signal 字段决定发送什么信号 - // - // 参考 Linux kernel/exit.c:do_notify_parent() // 如果进程被 ptrace,忽略 exit_signal,总是发送 SIGCHLD let is_ptraced = current.flags().contains(ProcessFlags::PTRACED); let signal_to_send = if is_ptraced { - log::debug!( - "[EXIT_NOTIFY] PID {} is ptraced, sending SIGCHLD regardless of exit_signal", - current.raw_pid() - ); Signal::SIGCHLD } else { let exit_signal = current.exit_signal.load(Ordering::SeqCst); @@ -503,19 +469,15 @@ impl ProcessManager { ); } - // 无论exit_signal是什么值,都要唤醒父进程的wait_queue - // 因为父进程可能使用__WALL选项等待任何类型的子进程(包括exit_signal=0的clone子进程) - // 根据Linux语义,exit_signal只决定发送什么信号,不决定是否唤醒父进程 + // 要唤醒父进程的wait_queue,因为父进程可能使用__WALL选项等待任何类型的子进程 parent_pcb .wait_queue .wakeup_all(Some(ProcessState::Blocked(true))); - // 当子进程退出时,需要唤醒父进程,即使父进程不在 wait() 中睡眠 + // 唤醒父进程 parent_pcb.wake_up_process(); - // 根据 Linux wait 语义,线程组中的任何线程都可以等待同一线程组中任何线程创建的子进程。 - // 由于子进程被添加到线程组 leader 的 children 列表中, - // 因此还需要唤醒线程组 leader 的 wait_queue(如果 leader 不是 parent_pcb 本身)。 + // 唤醒线程组 leader 的 wait_queue let parent_group_leader = { let ti = parent_pcb.thread.read_irqsave(); ti.group_leader() @@ -736,32 +698,15 @@ impl ProcessManager { /// /// 调用此函数前,调用者**不能持有**父进程的 children 锁,否则会死锁。 pub(super) unsafe fn release(pid: RawPid) { - log::debug!("[RELEASE] Releasing PID {}", pid); let pcb = ProcessManager::find(pid); if let Some(ref pcb) = pcb { // 从父进程的 children 列表中移除 if let Some(parent) = pcb.real_parent_pcb() { - log::debug!( - "[RELEASE] Removing PID {} from parent {}'s children list", - pid, - parent.raw_pid() - ); let mut children = parent.children.write(); - let before_count = children.len(); children.retain(|&p| p != pid); - let after_count = children.len(); - log::debug!( - "[RELEASE] Parent {} children count: {} -> {}", - parent.raw_pid(), - before_count, - after_count - ); } ALL_PROCESS.lock_irqsave().as_mut().unwrap().remove(&pid); - log::debug!("[RELEASE] PID {} removed from ALL_PROCESS", pid); - } else { - log::warn!("[RELEASE] PID {} not found in ALL_PROCESS", pid); } } @@ -926,18 +871,19 @@ impl ProcessState { #[repr(i32)] pub enum PtraceRequest { PtraceTraceme = 0, - PtraceAttach = 16, - PtraceDetach = 17, - PtraceSyscall = 24, - PtraceSinglestep = 9, + PtracePeekdata = 2, + PtracePeekuser = 3, + PtracePokedata = 5, PtraceCont = 7, + PtraceSinglestep = 9, PtraceGetregs = 12, PtraceSetregs = 13, - PtracePeekuser = 3, - PtracePeekdata = 2, - PtracePokedata = 5, - PtraceGetsiginfo = 0x4202, + PtraceAttach = 16, + PtraceDetach = 17, + PtraceSyscall = 24, PtraceSetoptions = 0x4200, + PtraceGetsiginfo = 0x4202, + PtraceSeize = 0x4206, // 现代 API,不发送 SIGSTOP } bitflags! { @@ -990,6 +936,9 @@ bitflags! { const TRACE_EXEC = 1 << 21; /// 系统调用正在中断点(入口或出口) const SYSCALL_INTERRUPT = 1 << 22; + /// 进程通过 PTRACE_SEIZE 被附加(而非 PTRACE_ATTACH) + /// 按照 Linux 6.6.21 语义:SEIZED 进程不会收到 Legacy SIGTRAP + const PT_SEIZED = 1 << 23; } } @@ -1113,8 +1062,6 @@ struct PtraceState { tracer: Option, /// 挂起的信号(等待调试器处理) pending_signals: Vec, - /// 系统调用信息 (用于 PTRACE_SYSCALL) - syscall_info: Option, stop_reason: PtraceStopReason, /// ptrace选项位 options: PtraceOptions, @@ -1135,7 +1082,6 @@ impl Default for PtraceState { Self { tracer: None, pending_signals: Vec::new(), - syscall_info: None, stop_reason: PtraceStopReason::None, options: PtraceOptions::empty(), exit_code: 0, @@ -1150,7 +1096,6 @@ impl PtraceState { Self { tracer: None, pending_signals: Vec::new(), - syscall_info: None, stop_reason: PtraceStopReason::None, options: PtraceOptions::empty(), exit_code: 0, @@ -1878,16 +1823,10 @@ impl ProcessControlBlock { for pid in all_child_pids.iter().copied() { if let Some(child) = ProcessManager::find_task_by_vpid(pid) { // 检查子进程是否被当前进程 ptrace - // 通过检查子进程的 parent_pcb 是否指向当前进程 if let Some(child_parent) = child.parent_pcb() { if Arc::ptr_eq(&child_parent, &self.self_ref.upgrade().unwrap()) { // 子进程的 parent_pcb 指向当前进程,说明是被 ptrace 的 // 不转移这个子进程 - log::debug!( - "[ADOPT_CHILDREN] PID {} is being traced by current process {}, keeping in children list", - child.raw_pid(), - self.raw_pid() - ); ptraced_children.push(pid); continue; } @@ -1898,15 +1837,9 @@ impl ProcessControlBlock { // 只清空并转移非 ptraced 的子进程 if !children_to_adopt.is_empty() { - // 从当前进程的 children 列表中移除被收养的子进程 - // 保留 ptraced children(不在 children_to_adopt 中) let mut children_guard = self.children.write(); children_guard.retain(|pid| !children_to_adopt.contains(pid)); } else { - log::debug!( - "[ADOPT_CHILDREN] PID {} all children are ptraced, nothing to adopt", - self.raw_pid() - ); // 所有子进程都是 ptraced 的,不需要转移任何子进程 return Ok(()); } diff --git a/kernel/src/process/ptrace.rs b/kernel/src/process/ptrace.rs index 00793775d..0f077304f 100644 --- a/kernel/src/process/ptrace.rs +++ b/kernel/src/process/ptrace.rs @@ -3,14 +3,14 @@ use crate::arch::ipc::signal::{SigFlags, Signal}; use crate::arch::kprobe; use crate::ipc::signal_types::{ ChldCode, OriginCode, SigChldInfo, SigCode, SigFaultInfo, SigInfo, SigType, Sigaction, - SigactionType, SignalFlags, + SigactionType, SignalFlags, TrapCode, }; use crate::process::{ pid::PidType, ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState, PtraceEvent, PtraceOptions, PtraceRequest, PtraceStopReason, PtraceSyscallInfo, PtraceSyscallInfoData, PtraceSyscallInfoEntry, PtraceSyscallInfoExit, PtraceSyscallInfoOp, RawPid, }; -use crate::sched::{schedule, DequeueFlag, EnqueueFlag, SchedMode, WakeupFlags}; +use crate::sched::{schedule, EnqueueFlag, SchedMode, WakeupFlags}; use alloc::{sync::Arc, vec::Vec}; use core::{intrinsics::unlikely, mem::MaybeUninit}; use system_error::SystemError; @@ -25,57 +25,21 @@ pub fn ptrace_signal( original_signal: Signal, info: &mut Option, ) -> Option { - log::debug!( - "[PTRACE_SIGNAL] PID {} processing signal {:?}", - pcb.raw_pid(), - original_signal - ); - // todo pcb.jobctl_set(JobControlFlags::STOP_DEQUEUED); - // 核心:调用 ptrace_stop 使进程停止并等待追踪者。 - // ptrace_stop 会返回追踪者注入的信号。 // 注意:ptrace_stop 内部会处理锁的释放和重新获取。 let mut signr = pcb.ptrace_stop(original_signal as usize, ChldCode::Trapped, info.as_mut()); - log::debug!( - "[PTRACE_SIGNAL] PID {} tracer returned signal {}", - pcb.raw_pid(), - signr - ); - - // 按照 Linux 6.6.21 的 get_signal 语义: - // 如果 signr == 0,表示没有注入信号,应该丢弃原始信号,继续执行 - // 如果 signr != 0,表示注入了新信号,应该处理该信号 if signr == 0 { - log::debug!( - "[PTRACE_SIGNAL] PID {} no injected signal, discarding original signal {:?}", - pcb.raw_pid(), - original_signal - ); return None; // 丢弃原始信号,继续处理下一个信号(如果没有,则继续执行) } // 将注入的信号转换为 Signal 类型 let mut injected_signal = Signal::from(signr); if injected_signal == Signal::INVALID { - // 这不应该发生,因为 signr != 0 - log::error!( - "[PTRACE_SIGNAL] PID {} invalid signal {}", - pcb.raw_pid(), - signr - ); return None; } - // 如果追踪者注入了不同于原始信号的新信号,更新 siginfo。 - // 注意:按照 Linux 6.6.21 的 ptrace 语义,注入的信号应该使用 SI_USER 代码 - // 而不是 SigChld 类型,因为这不是真正的子进程状态变化 + // 如果追踪者注入了不同于原始信号的新信号,更新 siginfo if injected_signal != original_signal { - log::debug!( - "[PTRACE_SIGNAL] PID {} tracer injected new signal {:?} (was {:?})", - pcb.raw_pid(), - injected_signal, - original_signal - ); if let Some(info_ref) = info { let tracer = pcb.parent_pcb().unwrap(); // 使用 Kill 类型(SI_USER)而不是 SigChld @@ -92,17 +56,11 @@ pub fn ptrace_signal( } } - // 特殊处理 SIGCONT:需要清除挂起的停止信号,但仍然要传递给用户 - // 按照 Linux 6.6.21 的语义,SIGCONT 应该唤醒进程并传递给用户空间处理 + // 特殊处理 SIGCONT:需要清除挂起的停止信号,但仍然要唤醒进程并传递给用户空间处理 if injected_signal == Signal::SIGCONT { - log::debug!( - "[PTRACE_SIGNAL] PID {} injected SIGCONT, clearing any pending stop signals", - pcb.raw_pid() - ); // 清除任何挂起的停止信号(如 SIGSTOP, SIGTSTP 等) let mut sig_info = pcb.sig_info.write(); let pending = sig_info.sig_pending_mut().signal_mut(); - // 清除停止信号 for stop_sig in [ Signal::SIGSTOP, Signal::SIGTSTP, @@ -112,8 +70,6 @@ pub fn ptrace_signal( pending.remove(stop_sig.into()); } drop(sig_info); - // 返回 Some(injected_signal) 让 SIGCONT 被正常处理 - // 这样用户的信号处理函数(如 sigcont_handler)会被调用 return Some(injected_signal); } @@ -123,23 +79,12 @@ pub fn ptrace_signal( .sig_blocked() .contains(injected_signal.into()) { - log::debug!( - "[PTRACE_SIGNAL] PID {} signal {:?} is blocked, requeuing", - pcb.raw_pid(), - injected_signal - ); // 如果被阻塞了,则将信号重新排队,让它在未来被处理。 let _ = injected_signal.send_signal_info_to_pcb(info.as_mut(), Arc::clone(pcb), PidType::PID); - // 告诉 get_signal,当前没有需要立即处理的信号。 return None; } // 如果没有被阻塞,则返回这个新信号,让 get_signal 继续分发和处理它。 - log::debug!( - "[PTRACE_SIGNAL] PID {} returning signal {:?} to handle", - pcb.raw_pid(), - injected_signal - ); Some(injected_signal) } @@ -200,15 +145,8 @@ pub fn handle_ptrace_signal_stop(current_pcb: &Arc, sig: Si let mut ptrace_state = current_pcb.ptrace_state.lock(); ptrace_state.stop_reason = PtraceStopReason::Signal(sig); ptrace_state.exit_code = sig as usize; - log::debug!( - "PID {} stopping due to ptrace on signal {:?}", - current_pcb.raw_pid(), - sig - ); drop(ptrace_state); - // 调用 ptrace_stop 让进程真正停止并等待跟踪器 - // 这会设置状态、通知跟踪器、并调用 schedule() 让出 CPU let mut info = SigInfo::new( sig, 0, @@ -242,7 +180,7 @@ impl ProcessControlBlock { /// 获取ptrace跟踪器 pub fn tracer(&self) -> Option { - self.ptrace_state.lock().tracer.clone() + self.ptrace_state.lock().tracer } pub fn is_traced(&self) -> bool { @@ -287,30 +225,13 @@ impl ProcessControlBlock { pub fn set_parent(&self, new_parent: &Arc) -> Result<(), SystemError> { if new_parent.raw_pid() == self.raw_pid() { - return Err(SystemError::EINVAL); // 不能将自己设为父进程 + return Err(SystemError::EINVAL); } if new_parent.is_exited() { - return Err(SystemError::ESRCH); // 父进程不能是退出状态或僵尸状态 + return Err(SystemError::ESRCH); } - let old_parent = self.parent_pcb().map(|p| p.raw_pid()); - log::debug!( - "[SET_PARENT] PID {} changing parent from {:?} to {}", - self.raw_pid(), - old_parent, - new_parent.raw_pid() - ); - *(self.parent_pcb.write()) = Arc::downgrade(new_parent); - - // 验证设置是否成功 - let verify_parent = self.parent_pcb().map(|p| p.raw_pid()); - log::debug!( - "[SET_PARENT] PID {} verified parent_pcb={:?}", - self.raw_pid(), - verify_parent - ); - Ok(()) } @@ -324,11 +245,6 @@ impl ProcessControlBlock { let mut info = self.sig_info.write(); info.sig_pending.signal_mut().insert(signal.into()); } - /// 从队列获取信号 - // pub fn dequeue_signal(&self) -> Option { - // let mut info = self.sig_info.write(); - // info.dequeue_signal(signal, self) - // } /// 唤醒父进程的等待队列 fn wake_up_parent(&self, state: Option) { @@ -374,196 +290,130 @@ impl ProcessControlBlock { Ok(()) } - pub fn ptrace_event_enabled(&self, event: PtraceEvent) -> bool { - let event_flag = 1 << (event as u32 + 3); - self.ptrace_state.lock().event_message == event_flag && event_flag != 0; - true - } - + /// ptrace 事件通知 + /// + /// 按照 Linux 6.6.21 的 ptrace_event 实现: + /// - 如果事件被启用(通过 PTRACE_O_TRACEEXEC 等选项),调用 ptrace_stop 阻塞进程 + /// - 进程保持 TracedStopped 状态,直到 tracer 唤醒它 + /// - 不应该手动设置 Runnable 状态,这由 ptrace_resume 处理 + /// + /// Legacy Exec 行为(PTRACE_SEIZE): + /// - 如果进程是通过 PTRACE_SEIZE 附加的(PT_SEIZED 标志已设置), + /// 且没有设置 PTRACE_O_TRACEEXEC,则不发送 Legacy SIGTRAP + /// - 这避免了现代调试器(如 rr、新版 GDB)收到意料之外的信号 pub fn ptrace_event(&self, event: PtraceEvent, message: usize) { + // 检查是否启用了该事件的追踪 if unlikely(self.ptrace_event_enabled(event)) { self.ptrace_state.lock().event_message = message; - let _ = Self::ptrace_notify((event as usize) << 8 | Signal::SIGTRAP as usize); + // ptrace_notify 会调用 ptrace_stop,阻塞进程直到 tracer 唤醒 + let exit_code = (event as usize) << 8 | Signal::SIGTRAP as usize; + let _ = Self::ptrace_notify(exit_code); + // 注意:这里不设置 Runnable! + // ptrace_stop 内部会调用 schedule() 阻塞 + // 当 tracer 调用 PTRACE_CONT 时,ptrace_resume 会设置 Runnable } else if event == PtraceEvent::Exec { - // if (ptrace_flags & (PT_PTRACED | PT_SEIZED)) == PT_PTRACED { - log::debug!("ProcessFlags::PTRACED"); - let sig = Signal::SIGTRAP; - let mut info = SigInfo::new( - sig, - 0, - SigCode::Origin(OriginCode::Kernel), - SigType::SigFault(SigFaultInfo { addr: 0, trapno: 0 }), - ); - let _ = sig.send_signal_info_to_pcb( - Some(&mut info), - self.self_ref.upgrade().unwrap(), - PidType::PID, - ); - // } + // Legacy Exec 行为:只有在非 PTRACE_SEIZE 时才发送自动 SIGTRAP + // 这符合 Linux 6.6.21 的逻辑: + // - PTRACE_ATTACH:发送 Legacy SIGTRAP + // - PTRACE_SEIZE:不发送 Legacy SIGTRAP(除非显式设置 PTRACE_O_TRACEEXEC) + let is_seized = self.flags().contains(ProcessFlags::PT_SEIZED); + + if !is_seized { + // 非 PTRACE_SEIZE:发送 Legacy SIGTRAP + let sig = Signal::SIGTRAP; + let mut info = SigInfo::new( + sig, + 0, + SigCode::Origin(OriginCode::Kernel), + SigType::SigFault(SigFaultInfo { addr: 0, trapno: 0 }), + ); + let _ = sig.send_signal_info_to_pcb( + Some(&mut info), + self.self_ref.upgrade().unwrap(), + PidType::PID, + ); + } + // PTRACE_SEIZE:不发送信号,静默返回 } - let wait_status = ((event as usize) << 8) | (Signal::SIGTRAP as usize); - self.set_state(ProcessState::Runnable); + // 移除了错误的 set_state(Runnable) 调用 + // ptrace_stop 已经正确处理了状态管理 + } + + /// 检查是否启用了指定的 ptrace 事件选项 + /// + /// 按照 Linux 6.6.21 的 ptrace_event_enabled 实现: + /// - 检查 PTRACE_O_TRACEEXEC 等选项是否被设置 + /// - 返回 true 表示 tracer 想要接收该事件的通知 + pub fn ptrace_event_enabled(&self, event: PtraceEvent) -> bool { + // 将 PtraceEvent 转换为对应的 PtraceOptions 标志 + let event_flag = match event { + PtraceEvent::Fork => PtraceOptions::TRACEFORK, + PtraceEvent::VFork => PtraceOptions::TRACEVFORK, + PtraceEvent::Clone => PtraceOptions::TRACECLONE, + PtraceEvent::Exec => PtraceOptions::TRACEEXEC, + PtraceEvent::VForkDone => PtraceOptions::TRACEVFORKDONE, + PtraceEvent::Exit => PtraceOptions::TRACEEXIT, + PtraceEvent::Seccomp => PtraceOptions::TRACESECCOMP, + _ => return false, + }; + + // 检查该选项是否在 ptrace_state.options 中被设置 + self.ptrace_state.lock().options.contains(event_flag) } + /// 设置进程为停止状态 + /// + /// 按照 Linux 6.6.21 的 ptrace_stop 实现: + /// - 设置状态为 TracedStopped (类似 TASK_TRACED) + /// - 调用 schedule() 让出 CPU,调度器会自动将任务从运行队列移除 + /// - 不需要手动 deactivate_task,这会引入竞态条件 pub fn ptrace_stop( &self, exit_code: usize, why: ChldCode, - info: Option<&mut SigInfo>, + _info: Option<&mut SigInfo>, ) -> usize { - log::debug!( - "[PTRACE_STOP] PID {} stopping: exit_code={}, why={:?}", - self.raw_pid(), - exit_code, - why - ); - - // 按照 Linux 6.6.21 的 ptrace_stop 语义: - // 1. 设置 TRAPPING 标志,表示 tracee 正在停止 - // 2. 设置进程状态为 Stopped - // 3. 唤醒 tracer 的等待队列 - // 4. 进入 schedule() 让出 CPU - // 5. 当 tracer 唤醒 tracee 后,schedule() 返回 - // 6. 清除 TRAPPING 标志 - // 设置 TRAPPING 标志,表示正在停止 self.flags().insert(ProcessFlags::TRAPPING); - // self.last_siginfo = info.cloned(); - // 按照 Linux 6.6.21 的 ptrace_stop 语义: // 使用 TracedStopped 状态(类似于 Linux 的 TASK_TRACED) - // 而不是 Stopped 状态(类似于 Linux 的 TASK_STOPPED) - // 这确保 tracee 只能被 tracer 通过 ptrace_resume 唤醒 - - // 获取 sched_info 锁并设置状态 let mut sched_info = self.sched_info.inner_lock_write_irqsave(); sched_info.set_state(ProcessState::TracedStopped(exit_code)); - // 关键:必须设置 sleep 标志,否则调度器不会把进程从运行队列移除 sched_info.set_sleep(); drop(sched_info); - self.flags().insert(ProcessFlags::PTRACED); - - log::debug!( - "[PTRACE_STOP] PID {} state set to TracedStopped({}), will call schedule", - self.raw_pid(), - exit_code - ); + // 注意:不再设置 PTRACED 标志,因为: + // 1. PTRACE_TRACEME/ATTACH 时已经设置 + // 2. 在 ptrace_stop 中设置会导致语义偏差 - // 为下次stop恢复 + // 清除 ptrace_state 中的 event_message self.ptrace_state.lock().event_message = 0; - // 按照 Linux 6.6.21 的 ptrace_stop 语义: - // 1. 先通知 tracer (do_notify_parent_cldstop) - 在 schedule() 之前 - // 2. 清除 TRAPPING 标志 - // 3. 确保任务从运行队列移除 - // 4. 调用 schedule() 让出 CPU - // - // 这样 tracer 会被唤醒并可以 wait(),tracee 会进入睡眠状态 - // 通知跟踪器 - 必须在 schedule() 之前调用! if let Some(tracer) = self.parent_pcb() { - log::debug!( - "[PTRACE_STOP] PID {} notifying tracer={}", - self.raw_pid(), - tracer.raw_pid() - ); self.notify_tracer(&tracer, why); - } else { - log::error!("PID {} is traced but has no parent tracer!", self.raw_pid()); } // 清除 TRAPPING 标志,表示已经完成停止准备工作 self.flags().remove(ProcessFlags::TRAPPING); - // 关键修复:确保任务从运行队列中移除 - // 由于任务可能之前被 signal_wake_up 唤醒并加入运行队列 - // 我们需要确保它现在被移除,否则 schedule() 会立即返回 - { - let rq = crate::sched::cpu_rq(crate::smp::core::smp_get_processor_id().data() as usize); - let (rq, _guard) = rq.self_lock(); - rq.deactivate_task( - self.self_ref.upgrade().unwrap(), - DequeueFlag::DEQUEUE_SLEEP | DequeueFlag::DEQUEUE_NOCLOCK, - ); - log::debug!( - "[PTRACE_STOP] PID {} manually deactivated from run queue", - self.raw_pid() - ); - } - - let preempt_count_before = ProcessManager::current_pcb().preempt_count(); - log::debug!( - "[PTRACE_STOP] PID {} before schedule: preempt_count={}", - self.raw_pid(), - preempt_count_before - ); - - log::debug!( - "[PTRACE_STOP] PID {} scheduling out, waiting for tracer", - self.raw_pid() - ); - - // 调度出去,让出CPU等待跟踪器恢复 - // set_state 已经释放了 sched_info 锁,现在可以安全调用 schedule - let state_before = self.sched_info().inner_lock_read_irqsave().state(); - log::debug!( - "[PTRACE_STOP] PID {} before schedule: state={:?}", - self.raw_pid(), - state_before - ); - drop(state_before); + // 按照 Linux 6.6.21 语义: + // 不需要手动从运行队列中移除任务 + // schedule() 内部会检查 state,如果不是 Runnable,调度器会自动处理 + // 手动 deactivate_task 会引入竞态条件(如果在 deactivate 后、schedule 前有唤醒请求) schedule(SchedMode::SM_NONE); // 从 schedule() 返回后,tracer 已经通过 ptrace_resume 唤醒了我们 - // 状态已经被 ptrace_resume 设置为 Runnable - // 不要在这里手动修改状态!否则会导致竞态条件 - let state_after = self.sched_info().inner_lock_read_irqsave().state(); - log::debug!( - "[PTRACE_STOP] PID {} after schedule: state={:?}", - self.raw_pid(), - state_after - ); - drop(state_after); - - log::debug!( - "[PTRACE_STOP] PID {} resumed by tracer, checking ptrace flag", - self.raw_pid() - ); - - // 按照 Linux 6.6.21 的 ptrace_stop 语义: // 进程恢复后,应该返回 tracer 注入的信号(data 参数) - // 而不是原始的 exit_code - // 从 ptrace_state.injected_signal 读取 tracer 注入的信号 let mut ptrace_state = self.ptrace_state.lock(); let injected_signal = ptrace_state.injected_signal; - log::debug!( - "[PTRACE_STOP] PID {} injected_signal={:?} (original exit_code={})", - self.raw_pid(), - injected_signal, - exit_code - ); - // 按照 Linux 6.6.21 的 get_signal/ptrace_stop 语义: - // 1. 如果注入的信号是 INVALID,返回 0,表示没有注入信号 - // 2. get_signal 会检查该信号,如果是 0,会丢弃原始信号并继续执行 - // 如果是非 0 信号,会处理该信号 + // 如果注入的信号是 INVALID,返回 0,表示没有注入信号 let result = if injected_signal == Signal::INVALID { - log::debug!( - "[PTRACE_STOP] PID {} no injected signal, continuing execution", - self.raw_pid() - ); - // 返回 0 表示没有注入信号,get_signal 会继续处理 0 } else { - log::debug!( - "[PTRACE_STOP] PID {} returning injected signal {:?}", - self.raw_pid(), - injected_signal - ); - // 清除注入的信号,因为已经被处理了 ptrace_state.injected_signal = Signal::INVALID; injected_signal as usize }; @@ -573,18 +423,31 @@ impl ProcessControlBlock { } fn notify_tracer(&self, tracer: &Arc, why: ChldCode) { - log::debug!( - "[NOTIFY_TRACER] Notifying tracer={} about tracee={}, why={:?}", - tracer.raw_pid(), - self.raw_pid(), - why - ); let status = match why { ChldCode::Stopped => self.exit_code().unwrap_or(0) as i32 & 0x7f, ChldCode::Trapped => self.exit_code().unwrap_or(0) as i32 & 0x7f, _ => Signal::SIGCONT as i32, }; - let mut info = SigInfo::new( + + // 按照 Linux 6.6.21 语义: + // 对于 ptrace_stop,构建的 SigInfo 应该是 SIGTRAP 类型 + // 使用 TRAP_BRKPT (1) 作为默认 trapno,表示 ptrace 触发的停止 + let _sigtrap_info = SigFaultInfo { + addr: 0, + trapno: TrapCode::TrapBrkpt as i32, + }; + + // 构造 SIGTRAP siginfo 供调试器通过 PTRACE_GETSIGINFO 读取 + let _info = SigInfo::new( + Signal::SIGTRAP, + TrapCode::TrapBrkpt as i32, + SigCode::SigFault(_sigtrap_info), + SigType::SigFault(_sigtrap_info), + ); + + // 发送 SIGCHLD 通知父进程(tracer) + // 这与 tracee 内部的 SIGTRAP siginfo 是分离的 + let mut chld_info = SigInfo::new( Signal::SIGCHLD, 0, SigCode::SigChld(why), @@ -592,32 +455,28 @@ impl ProcessControlBlock { pid: self.raw_pid(), uid: self.cred().uid.data(), status, - utime: 0, // todo: 填充时间 + utime: 0, stime: 0, }), ); + let should_send = { let tracer_sighand = tracer.sighand(); let sa = tracer_sighand.handler(Signal::SIGCHLD); if let Some(sa) = sa { !sa.action().is_ignore() && !sa.flags().contains(SigFlags::SA_NOCLDSTOP) } else { - // 当 sa 为 None 时,使用默认行为忽略 false } }; if should_send { - Signal::SIGCHLD.send_signal_info_to_pcb( - Some(&mut info), + let _ = Signal::SIGCHLD.send_signal_info_to_pcb( + Some(&mut chld_info), Arc::clone(tracer), PidType::TGID, ); } - // 按照 Linux 6.6.21 的 do_notify_parent_cldstop 语义: - // __wake_up_parent 唤醒的是 parent 的 wait_chldexit 队列 - // 而不是 child 的队列 - // 这样 do_wait 中的 wait_event_interruptible 才能被唤醒 - log::debug!("[NOTIFY_TRACER] Waking up tracer's wait_queue"); + // 唤醒 tracer 的 wait_queue tracer .wait_queue .wakeup(Some(ProcessState::TracedStopped(status as usize))); @@ -642,50 +501,14 @@ impl ProcessControlBlock { } pub fn ptrace_link(&self, tracer: &Arc) -> Result<(), SystemError> { - log::debug!( - "[PTRACE_LINK] Linking tracer={} to tracee={}", - tracer.raw_pid(), - self.raw_pid() - ); - if !tracer.has_permission_to_trace(self) { - log::debug!( - "[PTRACE_LINK] Permission denied: tracer={} cannot trace tracee={}", - tracer.raw_pid(), - self.raw_pid() - ); return Err(SystemError::EPERM); } - log::debug!("[PTRACE_LINK] Setting tracer for tracee={}", self.raw_pid()); - // 将子进程添加到父进程的跟踪列表 - // let mut ptrace_list = tracer.ptraced_list.write(); - // let child_pid = self.raw_pid(); - // if ptrace_list.iter().any(|&pid| pid == child_pid) { - // return Err(SystemError::EALREADY); - // } - // ptrace_list.push(child_pid); self.set_tracer(tracer.raw_pid())?; - - log::debug!( - "[PTRACE_LINK] Reparenting tracee={} to tracer={}", - self.raw_pid(), - tracer.raw_pid() - ); self.set_parent(tracer)?; - - log::debug!( - "[PTRACE_LINK] Updating credentials for tracee={}", - self.raw_pid() - ); *self.cred.lock() = tracer.cred().clone(); - log::debug!( - "[PTRACE_LINK] Link completed: tracer={} -> tracee={}", - tracer.raw_pid(), - self.raw_pid() - ); - Ok(()) } @@ -754,62 +577,21 @@ impl ProcessControlBlock { /// 处理PTRACE_ATTACH请求 pub fn attach(&self, tracer: &Arc) -> Result { - log::debug!( - "[PTRACE_ATTACH] Starting attach: tracer={}, target={}", - tracer.raw_pid(), - self.raw_pid() - ); - - // 验证权限(简化版) - // 按照 Linux 6.6.21 的 ptrace_attach 语义: - // 1. 不能 attach 自己 - // 2. 不能 attach 同一个线程组的其他线程 - let is_same_process = tracer.raw_pid() == self.raw_pid(); + // 验证权限 + let _is_same_process = tracer.raw_pid() == self.raw_pid(); let is_same_thread_group = tracer.raw_tgid() == self.raw_tgid(); - log::debug!( - "[PTRACE_ATTACH] Permission check: tracer_pid={}, tracer_tgid={}, target_pid={}, target_tgid={}, same_process={}, same_thread_group={}", - tracer.raw_pid(), - tracer.raw_tgid(), - self.raw_pid(), - self.raw_tgid(), - is_same_process, - is_same_thread_group - ); - if !tracer.has_permission_to_trace(self) || self.flags().contains(ProcessFlags::KTHREAD) || is_same_thread_group { - log::debug!( - "[PTRACE_ATTACH] Permission check failed for target={}", - self.raw_pid() - ); return Err(SystemError::EPERM); } - log::debug!( - "[PTRACE_ATTACH] Setting PTRACED flag for target={}", - self.raw_pid() - ); self.flags().insert(ProcessFlags::PTRACED); - - log::debug!( - "[PTRACE_ATTACH] Calling ptrace_link: tracer={}, target={}", - tracer.raw_pid(), - self.raw_pid() - ); self.ptrace_link(tracer)?; - // 注意:不要修改 exit_signal! - // exit_signal 是用来表示进程退出时发送给父进程的信号(通常是 SIGCHLD) - // ptrace 注入的信号应该存储在 ptrace_state.injected_signal 中 - let sig = Signal::SIGSTOP; - log::debug!( - "[PTRACE_ATTACH] Sending SIGSTOP to target={}", - self.raw_pid() - ); let mut info = SigInfo::new( sig, 0, @@ -821,71 +603,69 @@ impl ProcessControlBlock { self.self_ref.upgrade().unwrap(), PidType::PID, ) { - log::debug!( - "[PTRACE_ATTACH] Failed to send SIGSTOP to target={}, error={:?}", - self.raw_pid(), - e - ); // 回滚ptrace设置 self.flags().remove(ProcessFlags::PTRACED); - let _ = self.ptrace_unlink()?; + self.ptrace_unlink()?; return Err(e); } - // 按照 Linux 6.6.21 的 ptrace_attach 语义: - // 发送 SIGSTOP 信号后,不需要手动 kick tracee - // tracee 会在下一次返回用户态时自动调用 do_signal 处理 - // 然后调用 ptrace_stop 并进入 TracedStopped 状态 - // - // 关键:不要调用 kick()!如果调用 kick(),会导致 tracee 被 wake up - // 然后 tracee 调用 schedule() 后可能立即被调度,无法正确进入 TracedStopped 状态 - log::debug!( - "[PTRACE_ATTACH] Sent SIGSTOP to target={}, waiting for it to process signal", - self.raw_pid() - ); - // 等待 tracee 进入 TracedStopped 状态 - // 按照 Linux 6.6.21 语义:notify_tracer 调用 __wake_up_parent 唤醒 tracer 的 wait_queue - // 所以这里应该等待在 tracer 的 wait_queue 上,而不是 tracee 的 wait_queue let tracee_ref = self.self_ref.upgrade().unwrap(); let tracer_clone = tracer.clone(); - log::debug!( - "[PTRACE_ATTACH] Tracer {} entering wait_event_interruptible for tracee {}", - tracer.raw_pid(), - tracee_ref.raw_pid() - ); let _wait_result = tracer_clone.wait_queue.wait_event_interruptible( || { let state = tracee_ref.sched_info().inner_lock_read_irqsave().state(); - let is_stopped = matches!(state, ProcessState::TracedStopped(_)); - log::debug!( - "[PTRACE_ATTACH] Wait check: tracee {} state={:?}, is_stopped={}", - tracee_ref.raw_pid(), - state, - is_stopped - ); - is_stopped + matches!(state, ProcessState::TracedStopped(_)) }, None::, ); - log::debug!( - "[PTRACE_ATTACH] Attach completed: tracer={}, target={}", - tracer.raw_pid(), - self.raw_pid() - ); + Ok(0) + } + + /// 处理PTRACE_SEIZE请求 + /// + /// 按照 Linux 6.6.21 的实现: + /// - PTRACE_SEIZE 是 PTRACE_ATTACH 的现代替代品 + /// - 不会发送 SIGSTOP 给 tracee + /// - 设置 PT_SEIZED 标志,影响后续行为(如 Legacy Exec SIGTRAP) + /// - 如果指定了 PTRACE_O_TRACEEXEC 等选项,这些选项会生效 + pub fn seize( + &self, + tracer: &Arc, + options: PtraceOptions, + ) -> Result { + // 验证权限 + let _is_same_process = tracer.raw_pid() == self.raw_pid(); + let is_same_thread_group = tracer.raw_tgid() == self.raw_tgid(); + + if !tracer.has_permission_to_trace(self) + || self.flags().contains(ProcessFlags::KTHREAD) + || is_same_thread_group + { + return Err(SystemError::EPERM); + } + + // 设置 PTRACED 标志 + self.flags().insert(ProcessFlags::PTRACED); + + // 设置 PT_SEIZED 标志,表示使用现代 API 附加 + self.flags().insert(ProcessFlags::PT_SEIZED); + // 建立 ptrace 关系 + self.ptrace_link(tracer)?; + + // 设置 ptrace 选项 + let mut ptrace_state = self.ptrace_state.lock(); + ptrace_state.options = options; + drop(ptrace_state); + + // PTRACE_SEIZE 不发送 SIGSTOP,直接返回 Ok(0) } /// 处理PTRACE_DETACH请求 pub fn detach(&self, signal: Option) -> Result { - log::debug!( - "[PTRACE_DETACH] Detaching from PID {}, signal={:?}", - self.raw_pid(), - signal - ); - // 验证调用者是跟踪器 let current_pcb = ProcessManager::current_pcb(); if !self.is_traced_by(¤t_pcb) { @@ -893,63 +673,54 @@ impl ProcessControlBlock { } // 按照 Linux 6.6.21 的 ptrace_detach 实现: - // 1. 将 data 参数存储到 ptrace_state.injected_signal - // 2. 调用 __ptrace_detach (ptrace_unlink) - // 3. 恢复进程执行(使用与 ptrace_resume 相同的唤醒逻辑) - // - // 关键:data 参数会被传递给 ptrace_stop,作为恢复后要处理的信号 - // 如果 data 是 0,表示不发送任何信号,继续执行 + // 1. 先解除 ptrace 关系,这样后续的信号不会被 ptrace 拦截 + self.ptrace_unlink()?; + + // 2. 如果指定了信号,发送该信号到 tracee + // 此时 tracee 已不再被 ptrace,信号会正常入队并被处理 let data_signal = signal.unwrap_or(Signal::SIGCONT); + if let Some(sig) = signal { + // 将信号入队到 tracee 的 pending 队列 + let mut info = SigInfo::new( + sig, + 0, + SigCode::Origin(OriginCode::User), + SigType::Kill { + pid: current_pcb.raw_pid(), + uid: current_pcb.cred().uid.data() as u32, + }, + ); + // 发送信号(此时已经 ptrace_unlink,所以信号会正常处理) + let _ = sig.send_signal_info_to_pcb( + Some(&mut info), + self.self_ref.upgrade().unwrap(), + crate::process::pid::PidType::PID, + ); + } - // 将注入的信号存储到 ptrace_state.injected_signal - // 而不是 exit_signal!exit_signal 是用来表示进程退出时发送给父进程的信号 + // 3. 同时将信号存储到 ptrace_state.injected_signal + // 这样如果 tracee 正在 ptrace_stop 中,它也能获取到这个信号 let mut ptrace_state = self.ptrace_state.lock(); ptrace_state.injected_signal = data_signal; drop(ptrace_state); - log::debug!( - "[PTRACE_DETACH] Set ptrace_state.injected_signal={:?} for PID {}", - data_signal, - self.raw_pid() - ); - - // 解除跟踪关系 - // ptrace_unlink 会自动恢复父进程为 real_parent - // 并清除 ProcessFlags::PTRACED 和 TRACE_SYSCALL - self.ptrace_unlink()?; - - // 按照 Linux 6.6.21 的 ptrace_detach 实现: - // 使用与 ptrace_resume/wakeup_stop 相同的唤醒逻辑 - // Linux: child->jobctl &= ~JOBCTL_TRACED; wake_up_state(child, __TASK_TRACED); - // - // 关键:需要手动将 TracedStopped 状态改为 Runnable 并加入运行队列 - // signal_wake_up 不会唤醒 TracedStopped 状态的任务(它只唤醒 Blocked 状态) + // 4. 恢复进程执行 let mut sched_info = self.sched_info.inner_lock_write_irqsave(); - // 检查当前状态 match sched_info.state() { ProcessState::TracedStopped(_) | ProcessState::Stopped(_) => { // 将状态设置为 Runnable,让进程可以被调度 sched_info.set_state(ProcessState::Runnable); sched_info.set_wakeup(); - log::debug!( - "[PTRACE_DETACH] Set PID {} to Runnable and wakeup", - self.raw_pid() - ); } _ => { // 进程可能已经由于其他原因被唤醒,仍然需要确保 sleep 标志被清除 sched_info.set_wakeup(); - log::debug!( - "[PTRACE_DETACH] PID {} already runnable, just wakeup", - self.raw_pid() - ); } } drop(sched_info); - // 按照 wakeup_stop 的模式,使用 activate_task + check_preempt_currnet - // 确保 on_rq 被正确设置为 Queued + // 加入调度队列 let rq = crate::sched::cpu_rq( self.sched_info() .on_cpu() @@ -967,12 +738,6 @@ impl ProcessControlBlock { rq.check_preempt_currnet(&strong_ref, WakeupFlags::empty()); - log::debug!( - "[PTRACE_DETACH] Detached from PID {}, injected {:?}, activated and preempt-checked", - self.raw_pid(), - data_signal - ); - Ok(0) } @@ -987,63 +752,36 @@ impl ProcessControlBlock { PtraceRequest::PtraceSyscall => self.flags().insert(ProcessFlags::TRACE_SYSCALL), PtraceRequest::PtraceSinglestep => { self.flags().insert(ProcessFlags::TRACE_SINGLESTEP); - kprobe::setup_single_step(frame, frame.rip as usize); // 架构相关的操作,设置 TF 标志 + kprobe::setup_single_step(frame, frame.rip as usize); // 设置 TF 标志 } _ => {} // PTRACE_CONT 不需要特殊标志 } - // 按照 Linux 6.6.21 的 ptrace_resume 语义: - // data 参数应该存储到 ptrace_state.injected_signal - // 如果 data=0(signal 为 None),表示不注入任何信号,tracee 继续执行 - // 如果 data != 0,表示注入指定的信号 let resume_signal = signal.unwrap_or(Signal::INVALID); - log::info!("signal: {:?} to process {}", resume_signal, self.raw_pid()); // 清除停止/阻塞标志 self.flags().remove(ProcessFlags::STOPPED); // 将注入的信号存储到 ptrace_state.injected_signal - // 而不是 exit_signal!exit_signal 是用来表示进程退出时发送给父进程的信号 let mut ptrace_state = self.ptrace_state.lock(); ptrace_state.injected_signal = resume_signal; drop(ptrace_state); - log::debug!( - "[PTRACE_RESUME] Set ptrace_state.injected_signal={:?} for PID {}", - resume_signal, - self.raw_pid() - ); - - // 按照 Linux 6.6.21 的 ptrace_resume 语义: - // 需要将 TracedStopped 状态的进程设置为 Runnable 并加入运行队列 - // - // 注意:必须在唤醒之前设置状态,否则 tracee 可能继续睡眠 + // 将 TracedStopped 状态的进程设置为 Runnable 并加入运行队列 let mut sched_info = self.sched_info.inner_lock_write_irqsave(); - // 检查当前状态 match sched_info.state() { ProcessState::TracedStopped(_) | ProcessState::Stopped(_) => { - // 将状态设置为 Runnable,让进程可以被调度 sched_info.set_state(ProcessState::Runnable); sched_info.set_wakeup(); - log::debug!( - "[PTRACE_RESUME] Set PID {} to Runnable and wakeup", - self.raw_pid() - ); } _ => { - // 进程可能已经由于其他原因被唤醒,仍然需要确保 sleep 标志被清除 sched_info.set_wakeup(); - log::debug!( - "[PTRACE_RESUME] PID {} already runnable, just wakeup", - self.raw_pid() - ); } } drop(sched_info); // 加入调度队列(如果不在队列中的话) - // enqueue_task 会检查是否已在队列中,避免重复加入 if let Some(strong_ref) = self.self_ref.upgrade() { let rq = self.sched_info.sched_entity().cfs_rq().rq(); let (rq, _guard) = rq.self_lock(); @@ -1051,8 +789,6 @@ impl ProcessControlBlock { strong_ref.clone(), EnqueueFlag::ENQUEUE_RESTORE | EnqueueFlag::ENQUEUE_WAKEUP, ); - } else { - log::warn!("ptrace_resume: pid={} self_ref is dead", self.raw_pid()); } Ok(0) @@ -1063,6 +799,10 @@ impl ProcessControlBlock { // 设置系统调用跟踪标志 self.flags().insert(ProcessFlags::TRACE_SYSCALL); self.flags().remove(ProcessFlags::TRACE_SINGLESTEP); + + // 重置入口停止标志,确保下一个系统调用会在入口停止 + self.set_needs_syscall_entry_stop(true); + // 恢复进程运行 let mut sched_info = self.sched_info.inner_lock_write_irqsave(); match sched_info.state() { diff --git a/kernel/src/process/syscall/sys_exit_group.rs b/kernel/src/process/syscall/sys_exit_group.rs index 2058013bb..f0246fc77 100644 --- a/kernel/src/process/syscall/sys_exit_group.rs +++ b/kernel/src/process/syscall/sys_exit_group.rs @@ -23,13 +23,6 @@ impl Syscall for SysExitGroup { let pcb = ProcessManager::current_pcb(); let has_pending = pcb.flags().contains(ProcessFlags::HAS_PENDING_SIGNAL); let ptraced = pcb.flags().contains(ProcessFlags::PTRACED); - log::debug!( - "[EXIT_GROUP] PID {} exiting with code {}, has_pending={}, ptraced={}", - pcb.raw_pid(), - exit_code, - has_pending, - ptraced - ); // 仿照 Linux sys_exit_group:只取低 8 位并左移 8 位,形成 wstatus 编码, // 然后触发线程组整体退出。 ProcessManager::group_exit((exit_code & 0xff) << 8); diff --git a/kernel/src/process/syscall/sys_getpid.rs b/kernel/src/process/syscall/sys_getpid.rs index d7d44ca5f..f73dc8bde 100644 --- a/kernel/src/process/syscall/sys_getpid.rs +++ b/kernel/src/process/syscall/sys_getpid.rs @@ -15,16 +15,7 @@ impl Syscall for SysGetPid { /// 获取当前进程的tpid fn handle(&self, _args: &[usize], _frame: &mut TrapFrame) -> Result { let current_pcb = ProcessManager::current_pcb(); - log::debug!( - "[SYS_GETPID] PID {} calling getpid", - current_pcb.raw_pid() - ); let tgid = current_pcb.task_tgid_vnr().ok_or(SystemError::ESRCH)?; - log::debug!( - "[SYS_GETPID] PID {} getpid returning {}", - current_pcb.raw_pid(), - tgid.data() - ); Ok(tgid.into()) } diff --git a/kernel/src/process/syscall/sys_ptrace.rs b/kernel/src/process/syscall/sys_ptrace.rs index bff065db2..326a32f76 100644 --- a/kernel/src/process/syscall/sys_ptrace.rs +++ b/kernel/src/process/syscall/sys_ptrace.rs @@ -97,17 +97,18 @@ impl TryFrom for PtraceRequest { fn try_from(value: usize) -> Result { match value { 0 => Ok(PtraceRequest::PtraceTraceme), - 16 => Ok(PtraceRequest::PtraceAttach), - 17 => Ok(PtraceRequest::PtraceDetach), - 24 => Ok(PtraceRequest::PtraceSyscall), - 9 => Ok(PtraceRequest::PtraceSinglestep), + 2 => Ok(PtraceRequest::PtracePeekdata), + 5 => Ok(PtraceRequest::PtracePokedata), 7 => Ok(PtraceRequest::PtraceCont), + 9 => Ok(PtraceRequest::PtraceSinglestep), 12 => Ok(PtraceRequest::PtraceGetregs), 13 => Ok(PtraceRequest::PtraceSetregs), - 2 => Ok(PtraceRequest::PtracePeekdata), - 5 => Ok(PtraceRequest::PtracePokedata), - 0x4202 => Ok(PtraceRequest::PtraceGetsiginfo), + 16 => Ok(PtraceRequest::PtraceAttach), + 17 => Ok(PtraceRequest::PtraceDetach), + 24 => Ok(PtraceRequest::PtraceSyscall), 0x4200 => Ok(PtraceRequest::PtraceSetoptions), + 0x4202 => Ok(PtraceRequest::PtraceGetsiginfo), + 0x4206 => Ok(PtraceRequest::PtraceSeize), _ => Err(SystemError::EINVAL), } } @@ -147,6 +148,23 @@ impl SysPtrace { tracee.attach(tracer) } + /// 处理 PTRACE_SEIZE 请求(现代附加 API) + /// + /// 按照 Linux 6.6.21 实现: + /// - 不发送 SIGSTOP 给 tracee + /// - addr 参数包含 ptrace 选项 + /// - data 参数通常为 0 + fn handle_seize( + tracer: &Arc, + tracee_pid: RawPid, + addr: usize, + ) -> Result { + let tracee = ProcessManager::find(tracee_pid).ok_or(SystemError::ESRCH)?; + // addr 参数包含 ptrace 选项 + let options = PtraceOptions::from_bits_truncate(addr); + tracee.seize(tracer, options) + } + /// 处理 PTRACE_DETACH 请求(分离目标进程) fn handle_detach( tracee: &Arc, @@ -196,7 +214,7 @@ impl SysPtrace { addr: usize, ) -> Result { let value = tracee.peek_user(addr)?; - Ok(value as isize) + Ok(value) } /// 处理 PTRACE_PEEKDATA 请求(读取进程内存) @@ -337,13 +355,11 @@ impl SysPtrace { // 获取 tracee 的 TrapFrame // TrapFrame 位于内核栈顶部:kernel_stack.max_address - size_of::() let kstack = tracee.kernel_stack(); - let trap_frame_vaddr = VirtAddr::new( - kstack.stack_max_address().data() - core::mem::size_of::(), - ); + let trap_frame_vaddr = + VirtAddr::new(kstack.stack_max_address().data() - core::mem::size_of::()); // 从 tracee 的内核栈读取 TrapFrame - let trap_frame = - unsafe { &*(trap_frame_vaddr.data() as *const TrapFrame) }; + let trap_frame = unsafe { &*(trap_frame_vaddr.data() as *const TrapFrame) }; // 获取 fs_base 和 gs_base let arch_info = tracee.arch_info_irqsave(); @@ -462,15 +478,9 @@ impl SysPtrace { if !tracee.is_traced_by(¤t) { return Err(SystemError::EPERM); } - // 对于 KILL 请求,不需要目标处于停止状态 (Linux 逻辑) - // 这里我们简化逻辑,要求必须 Stopped match tracee.sched_info().inner_lock_read_irqsave().state() { ProcessState::Stopped(_) | ProcessState::TracedStopped(_) => Ok(()), - _ => { - // 如果请求是 KILL,Linux 允许不停止,但这里我们先严格要求 - log::debug!("ptrace_check_attach: process not stopped"); - Err(SystemError::ESRCH) - } + _ => Err(SystemError::ESRCH), } } } @@ -499,12 +509,14 @@ impl Syscall for SysPtrace { let signal: Option = if data == 0 { None // 表示无信号 } else { - Some(Signal::try_from(data as i32).map_err(|_| SystemError::EINVAL)?) + Some(Signal::from(data as i32)) }; let result: isize = match request { // 附加到目标进程 PtraceRequest::PtraceAttach => Self::handle_attach(&tracer, pid)?, + // PTRACE_SEIZE:现代 API,不发送 SIGSTOP + PtraceRequest::PtraceSeize => Self::handle_seize(&tracer, pid, addr)?, // 分离目标进程 PtraceRequest::PtraceDetach => Self::handle_detach(&tracee, signal)?, // 继续执行目标进程 diff --git a/kernel/src/process/syscall/sys_tkill.rs b/kernel/src/process/syscall/sys_tkill.rs index a4413bd29..4a1210626 100644 --- a/kernel/src/process/syscall/sys_tkill.rs +++ b/kernel/src/process/syscall/sys_tkill.rs @@ -14,7 +14,7 @@ impl SysTkill { } fn signal(args: &[usize]) -> usize { - args[1] as usize + args[1] } } diff --git a/user/apps/tests/syscall/gvisor/blocklists/ptrace_test b/user/apps/tests/syscall/gvisor/blocklists/ptrace_test new file mode 100644 index 000000000..fb172f3ce --- /dev/null +++ b/user/apps/tests/syscall/gvisor/blocklists/ptrace_test @@ -0,0 +1,16 @@ +PtraceTest.AttachParent_PeekData_PokeData_SignalSuppression +PtraceTest.GetSigMask +PtraceTest.GetSiginfo_SetSiginfo_SignalInjection +PtraceTest.SIGKILLDoesNotCauseSignalDeliveryStop +PtraceTest.PtraceKill +PtraceTest.GetRegSet +PtraceTest.ChangeRegSetInOptSyscall +PtraceTest.AttachingConvertsGroupStopToPtraceStop +PtraceTest.ExitWhenParentIsNotTracer_Syscall_TraceVfork_TraceVforkDone +PtraceTest.Int3 +PtraceTest.Sysemu_PokeUser +PtraceTest.85 +PtraceTest.Seize_Interrupt_Listen +PtraceTest.Interrupt_Listen_RequireSeize +PtraceTest.SingleStep +*PtraceExecveTest.Execve_GetRegs_PeekUser_SIGKILL_TraceClone_TraceExit* \ No newline at end of file From 90a99863f2be9477e5c45d00debdd7a9fb5c61df Mon Sep 17 00:00:00 2001 From: aLinChe <1129332011@qq.com> Date: Sun, 11 Jan 2026 23:27:53 +0800 Subject: [PATCH 08/15] pr review Signed-off-by: aLinChe <1129332011@qq.com> --- kernel/src/arch/x86_64/ipc/signal.rs | 41 +-- kernel/src/arch/x86_64/mm/fault.rs | 6 +- kernel/src/arch/x86_64/syscall/mod.rs | 215 ++++++--------- kernel/src/exception/entry.rs | 110 ++++---- kernel/src/ipc/generic_signal.rs | 16 +- kernel/src/ipc/kill.rs | 8 +- kernel/src/ipc/signal.rs | 11 +- kernel/src/ipc/signal_types.rs | 41 ++- kernel/src/ipc/syscall/sys_kill.rs | 2 - kernel/src/process/exit.rs | 2 +- kernel/src/process/fork.rs | 29 +- kernel/src/process/mod.rs | 68 ++--- kernel/src/process/ptrace.rs | 125 +++++---- kernel/src/process/rseq.rs | 67 +++-- kernel/src/process/syscall/sys_ptrace.rs | 323 +++++++++++++---------- 15 files changed, 556 insertions(+), 508 deletions(-) diff --git a/kernel/src/arch/x86_64/ipc/signal.rs b/kernel/src/arch/x86_64/ipc/signal.rs index 9983f392b..e0256f480 100644 --- a/kernel/src/arch/x86_64/ipc/signal.rs +++ b/kernel/src/arch/x86_64/ipc/signal.rs @@ -592,7 +592,6 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { let pcb = ProcessManager::current_pcb(); let siginfo = pcb.try_siginfo_irqsave(5); - if unlikely(siginfo.is_none()) { return; } @@ -621,14 +620,7 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { let mut siginfo_mut_guard = siginfo_mut.unwrap(); - // 按照 Linux 6.6.21 kernel/signal.c::get_signal 的语义: - // - // 1. 先检查 ptrace 拦截(所有信号,包括 kernel_only) - // 2. ptrace_signal 可以修改、取消或注入信号 - // 3. 处理 ptrace 返回的信号(可能已被修改) - // 4. 最后查找 sigaction 并根据 disposition 处理 - // - // 关键:ptrace 处理必须在 sigaction 查找之前完成! + // 循环直到取出一个有效的、需要处理的信号,或者队列为空 loop { (sig, info) = siginfo_mut_guard.dequeue_signal(&sig_block, &pcb); @@ -637,21 +629,14 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { return; } - // ===== 第一步:ptrace 拦截(所有信号统一处理) ===== - // 按照 Linux 6.6.21:不管是 kernel_only 还是普通信号, - // 都先通过 ptrace_signal 让 tracer 决定如何处理 + // 只要进程处于 PTRACED 状态,都必须先通知 Tracer let is_ptraced = pcb.flags().contains(ProcessFlags::PTRACED); if is_ptraced { - // 保存 oldset,因为需要释放锁 + // 保存 oldset,因为需要释放锁, ptrace_signal 内部会调用 schedule() let _oldset = *siginfo_mut_guard.sig_blocked(); - // 释放锁,因为 ptrace_stop 内部会调用 schedule() drop(siginfo_mut_guard); CurrentIrqArch::interrupt_enable(); - // ptrace_signal 会: - // 1. 调用 ptrace_stop 停止进程 - // 2. 等待 tracer 的指令 - // 3. 返回 Some(新信号) 或 None(取消) let result = ptrace_signal(&pcb, sig, &mut info); // 重新获取锁以继续处理 @@ -665,30 +650,29 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { Some(new_sig) => { // tracer 注入了新信号,继续处理 sig = new_sig; - // 注意:不 continue,需要对新信号查找 sigaction } None => { - // tracer 取消了信号,继续下一个信号 + // tracer 忽略了信号,继续下一个信号 continue; } } } - // ===== 第二步:处理 kernel_only 信号(SIGKILL/SIGSTOP) ===== - // 只有在非 ptrace 或 ptrace 返回了信号时才到这里 + // 只有在非 ptrace 状态,或 ptrace 返回了信号且该信号是 kernel_only 时才进入。 if sig.kernel_only() { - // kernel_only 信号使用默认处理 let _oldset = *siginfo_mut_guard.sig_blocked(); drop(siginfo_mut_guard); drop(pcb); CurrentIrqArch::interrupt_enable(); + // kernel_only 信号使用默认处理 sig.handle_default(); + // 注意:如果是 SIGSTOP,进程被唤醒后在 Linux 中通常会跳转回循环开头重新检查 pending 信号。 + // 这里直接 return,依靠下一次中断返回路径再次进入 do_signal 来处理后续信号。 return; } - // ===== 第三步:查找 sigaction(普通信号) ===== + // 查找普通信号的 sigaction let sa = pcb.sighand().handler(sig).unwrap(); - match sa.action() { SigactionType::SaHandler(action_type) => match action_type { SaHandlerType::Error => { @@ -706,6 +690,7 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { SigactionType::SaSigaction(_) => todo!(), } + // Init 进程保护机制 /* * Global init gets no signals it doesn't want. * Container-init gets no signals it doesn't want from same @@ -744,9 +729,8 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { let res: Result = handle_signal(sig, &mut sigaction, &info.unwrap(), &oldset, frame); - // 只有当信号帧真正被设置时(即自定义处理器),才设置 got_signal = true - // 对于默认动作的信号(如 SIGCONT),handle_signal 会调用 handle_default() 并返回 Ok(0), - // 不会设置信号帧。在这种情况下,应该允许系统调用重启。 + // 更新 got_signal 状态 + // 只有当信号帧真正被设置时(即自定义处理器),才设置 got_signal = true ,系统调用被中断且被处理,不自动重启 if res.is_ok() { match sigaction.action() { SigactionType::SaHandler(SaHandlerType::Customized(_)) => { @@ -804,6 +788,7 @@ fn try_restart_syscall(frame: &mut TrapFrame) { } _ => {} } + log::debug!("try restart syscall: {:?}", restart); } pub struct X86_64SignalArch; diff --git a/kernel/src/arch/x86_64/mm/fault.rs b/kernel/src/arch/x86_64/mm/fault.rs index 948d3ac57..d12ac4c57 100644 --- a/kernel/src/arch/x86_64/mm/fault.rs +++ b/kernel/src/arch/x86_64/mm/fault.rs @@ -278,14 +278,12 @@ impl X86_64MMArch { let send_segv = || { let pid = ProcessManager::current_pid(); + let uid = ProcessManager::current_pcb().cred().uid.data() as u32; let mut info = SigInfo::new( Signal::SIGSEGV, 0, SigCode::Origin(OriginCode::User), - SigType::Kill { - pid: ProcessManager::current_pid(), - uid: ProcessManager::current_pcb().cred().uid.data() as u32, - }, + SigType::Kill { pid, uid }, ); Signal::SIGSEGV .send_signal_info(Some(&mut info), pid) diff --git a/kernel/src/arch/x86_64/syscall/mod.rs b/kernel/src/arch/x86_64/syscall/mod.rs index e08a484c4..130744b7a 100644 --- a/kernel/src/arch/x86_64/syscall/mod.rs +++ b/kernel/src/arch/x86_64/syscall/mod.rs @@ -5,13 +5,11 @@ use crate::{ CurrentIrqArch, }, exception::InterruptArch, - ipc::signal_types::{ - OriginCode, SigCode, SigFaultInfo, SigInfo, SigType, SignalArch, TrapCode, - }, + ipc::signal_types::{ChldCode, SignalArch}, libs::align::SafeForZero, mm::VirtAddr, - process::{ProcessFlags, ProcessManager}, - syscall::{Syscall, SYS_SCHED}, + process::{ProcessFlags, ProcessManager, PtraceStopReason}, + syscall::Syscall, }; use log::debug; use system_error::SystemError; @@ -58,127 +56,87 @@ macro_rules! syscall_return { debug!("syscall return:pid={:?},ret= {:?}\n", pid, ret as isize); } - // 系统调用返回前检查并处理信号 - // 这是 ptrace 和普通信号处理的关键入口 - // 如果 HAS_PENDING_SIGNAL 标志被设置,需要调用 do_signal_or_restart - let pcb = ProcessManager::current_pcb(); - if pcb.flags().contains(ProcessFlags::HAS_PENDING_SIGNAL) { - drop(pcb); - // 调用退出到用户态的处理流程,会检查并处理信号 - // irqentry_exit 会检查 is_from_user() 并调用 exit_to_user_mode_prepare - unsafe { crate::exception::entry::irqentry_exit($regs) }; - // irqentry_exit 已经处理了退出流程,直接返回 - return; - } - drop(pcb); + // 无条件调用统一的退出处理函数,由它来检查和处理所有工作 + unsafe { crate::exception::entry::syscall_exit_to_user_mode($regs) }; - unsafe { - CurrentIrqArch::interrupt_disable(); - } + // 返回到汇编层,汇编代码将执行 iret/sysret 返回用户态 return; }}; } #[no_mangle] pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) { - // 系统调用进入时,把系统调用号存入errcode字段,以便在syscall_handler退出后,仍能获取到系统调用号 - frame.errcode = frame.rax; - let syscall_num = frame.rax as usize; - // 防止sys_sched由于超时无法退出导致的死锁 - if syscall_num == SYS_SCHED { - unsafe { - CurrentIrqArch::interrupt_disable(); - } - } else { - unsafe { - CurrentIrqArch::interrupt_enable(); - } - } + // 系统调用进入时,把系统调用号存入 orig_rax 字段 + // 对应 Linux 6.6.21 的 pt_regs.orig_rax 字段 + // 用于恢复被 ptrace 修改的系统调用号 + // frame.orig_rax = frame.rax; + // 系统调用进入时,始终开中断 + unsafe { + CurrentIrqArch::interrupt_enable(); + }; - let args = [ - frame.rdi as usize, - frame.rsi as usize, - frame.rdx as usize, - frame.r10 as usize, - frame.r8 as usize, - frame.r9 as usize, - ]; mfence(); let pid = ProcessManager::current_pcb().raw_pid(); let show = false; - // let show = if syscall_num != SYS_SCHED && pid.data() >= 9{ - // true - // } else { - // false - // }; if show { - debug!("syscall: pid: {:?}, num={:?}\n", pid, syscall_num); + debug!("syscall: pid: {:?}, num={:?}\n", pid, frame.rax as usize); } - // 检查是否需要 ptrace syscall trace (系统调用入口) let pcb = ProcessManager::current_pcb(); + + // 按照 Linux 6.6.21 的同步 ptrace 模型处理系统调用入口 + // 在 syscall_trace_enter() 中调用 ptrace_report_syscall_entry() + // ptrace_report_syscall() -> ptrace_notify() -> ptrace_stop() [同步阻塞] + // + // 参考 Linux 6.6.21 kernel/entry/common.c: + // - 第 50 行:ptrace_report_syscall_entry(regs) -> 同步阻塞 + // - 第 78 行:/* Either of the above might have changed the syscall number */ + // syscall = syscall_get_nr(current, regs); // 重新读取! + // + // 注意:必须同时检查 PTRACED 和 TRACE_SYSCALL 标志 + // - PTRACED: 进程正在被跟踪 + // - TRACE_SYSCALL: tracer 已调用 PTRACE_SYSCALL 请求系统调用跟踪 let needs_syscall_trace = pcb .flags() - .contains(ProcessFlags::PTRACED | ProcessFlags::TRACE_SYSCALL); + .contains(ProcessFlags::TRACE_SYSCALL); if needs_syscall_trace { - // 按照 Linux 6.6.21 的 ptrace_report_syscall_entry 语义: - // 在系统调用入口停止,而不是在系统调用执行后停止 - // - // 实现方式: - // 1. 设置 ERESTARTNOHAND 错误码,让 try_restart_syscall 稍后重启 - // 2. 发送 SIGTRAP 给自己,触发 ptrace 停止 - // 3. 直接返回,不执行系统调用 - // 4. 当 ptrace_stop 返回后,try_restart_syscall 会将 rip -= 2 重新执行系统调用 - // 5. 第二次执行时,由于 needs_syscall_entry_stop 已被设置为 false,执行系统调用并在出口停止 - - let needs_entry_stop = pcb.needs_syscall_entry_stop(); - drop(pcb); - - if needs_entry_stop { - let pcb = ProcessManager::current_pcb(); - // 第一次进入:需要在系统调用入口停止 - // 保存系统调用信息 - pcb.on_syscall_entry(syscall_num, &args); - - // 设置重启条件:使用 ERESTARTNOHAND 让 try_restart_syscall 稍后重启 - frame.rax = SystemError::ERESTARTNOHAND.to_posix_errno() as u64; - // errcode 已经保存了原始系统调用号(line 69) - - // 标记已经完成入口停止,下次通过时将执行系统调用 - pcb.set_needs_syscall_entry_stop(false); - - // 设置 HAS_PENDING_SIGNAL 标志,确保在返回用户态前处理信号 - pcb.flags().insert(ProcessFlags::HAS_PENDING_SIGNAL); - - // 发送 SIGTRAP 给自己,触发 ptrace 停止 (syscall entry) - // 使用 TRAP_TRACE (2) 表示系统调用跟踪 - let mut info = SigInfo::new( - Signal::SIGTRAP, - TrapCode::TrapTrace as i32, - SigCode::SigFault(SigFaultInfo { - addr: 0, - trapno: crate::ipc::signal_types::TrapCode::TrapTrace as i32, - }), - SigType::SigFault(SigFaultInfo { - addr: 0, - trapno: crate::ipc::signal_types::TrapCode::TrapTrace as i32, - }), - ); - let _ = Signal::SIGTRAP.send_signal_info_to_pcb( - Some(&mut info), - pcb.clone(), - crate::process::pid::PidType::PID, - ); + // 设置停止原因 + pcb.ptrace_state_mut().stop_reason = PtraceStopReason::SyscallEntry; - // 直接返回,不执行系统调用 - // try_restart_syscall 稍后会在信号处理后重启系统调用 - syscall_return!(frame.rax, frame, show); - } - // needs_entry_stop == false 表示已经完成入口停止,这次应该执行系统调用 + // 构造 syscall entry 的 exit_code: 0x80 | SIGTRAP + // 0x80 表示 PTRACE_SYSCALL_TRACE (PT_TRACESYSGOOD) + let exit_code = 0x80 | Signal::SIGTRAP as usize; + + // 同步调用 ptrace_stop,阻塞直到 tracer 唤醒 + // 这与 Linux 6.6.21 的 ptrace_report_syscall_entry() 行为一致 + let _signr = pcb.ptrace_stop(exit_code, ChldCode::Trapped, None); + + // ptrace_stop 返回后,检查 tracer 是否注入了信号 + // 如果有致命信号,需要立即处理 + // TODO: 处理注入信号 } + // 按照 Linux 6.6.21 kernel/entry/common.c:78 的模式: + // /* Either of the above might have changed the syscall number */ + // syscall = syscall_get_nr(current, regs); + // + // 关键:必须在 ptrace_stop 返回**之后**重新读取系统调用号和参数! + // 因为 tracer 可能在我们睡眠时修改了寄存器。 + let syscall_num = frame.rax as usize; + let args = [ + frame.rdi as usize, + frame.rsi as usize, + frame.rdx as usize, + frame.r10 as usize, + frame.r8 as usize, + frame.r9 as usize, + ]; + + // 保存系统调用入口信息(用于 PTRACE_GETSIGINFO) + pcb.on_syscall_entry(syscall_num, &args); + // Arch specific syscall match syscall_num { SYS_RT_SIGRETURN => { @@ -199,39 +157,34 @@ pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) { _ => {} } let mut syscall_handle = || -> u64 { + let pcb = ProcessManager::current_pcb(); let result = Syscall::catch_handle(syscall_num, &args, frame) .unwrap_or_else(|e| e.to_posix_errno() as usize) as u64; - // 系统调用出口 ptrace trace - let pcb = ProcessManager::current_pcb(); - if pcb - .flags() - .contains(ProcessFlags::PTRACED | ProcessFlags::TRACE_SYSCALL) - { - // 保存系统调用结果 - pcb.on_syscall_exit(result as isize); - - // 重置入口停止标志,以便下一个系统调用也在入口停止 - pcb.set_needs_syscall_entry_stop(true); - - // 设置 HAS_PENDING_SIGNAL 标志,确保在返回用户态前处理信号 - pcb.flags().insert(ProcessFlags::HAS_PENDING_SIGNAL); - - // 发送 SIGTRAP 给自己,触发 ptrace 停止 (syscall exit) - let mut info = SigInfo::new( - Signal::SIGTRAP, - 1, // PTRACE_EVENTMSG_SYSCALL_EXIT - SigCode::Origin(OriginCode::Kernel), - SigType::SigFault(crate::ipc::signal_types::SigFaultInfo { addr: 0, trapno: 0 }), - ); - let _ = Signal::SIGTRAP.send_signal_info_to_pcb( - Some(&mut info), - pcb.clone(), - crate::process::pid::PidType::PID, - ); + // 先将结果写入 frame.rax,这样 tracer 可以通过 PTRACE_POKEUSER 修改返回值 + frame.rax = result; + + // 按照 Linux 6.6.21 的同步 ptrace 模型处理系统调用出口 + // 在 syscall_exit_work() 中调用 ptrace_report_syscall_exit() + if pcb.flags().contains(ProcessFlags::TRACE_SYSCALL) { + // 设置停止原因 + pcb.ptrace_state_mut().stop_reason = crate::process::PtraceStopReason::SyscallExit; + + // 构造 syscall exit 的 exit_code: 0x80 | SIGTRAP + let exit_code = 0x80 | Signal::SIGTRAP as usize; + + // 同步调用 ptrace_stop,阻塞直到 tracer 唤醒 + // 这与 Linux 6.6.21 的 ptrace_report_syscall_exit() 行为一致 + let _signr = + pcb.ptrace_stop(exit_code, crate::ipc::signal_types::ChldCode::Trapped, None); + + // ptrace_stop 返回后,tracer 可能修改了 frame.rax + // 必须返回 frame.rax 而不是原始 result + // TODO: 处理注入信号 } - result + // 返回 frame.rax,包含 tracer 可能的修改 + frame.rax }; syscall_return!(syscall_handle(), frame, show); } diff --git a/kernel/src/exception/entry.rs b/kernel/src/exception/entry.rs index a790d5330..5d78b57c8 100644 --- a/kernel/src/exception/entry.rs +++ b/kernel/src/exception/entry.rs @@ -1,67 +1,83 @@ use crate::{ - arch::{interrupt::TrapFrame, ipc::signal::Signal, CurrentSignalArch}, + arch::{interrupt::TrapFrame, ipc::signal::Signal, CurrentIrqArch, CurrentSignalArch}, + exception::InterruptArch, ipc::signal_types::SignalArch, process::{rseq::Rseq, ProcessFlags, ProcessManager}, + sched::{schedule, SchedMode}, }; -#[no_mangle] -pub unsafe extern "C" fn irqentry_exit(frame: &mut TrapFrame) { - if frame.is_from_user() { - irqentry_exit_to_user_mode(frame); - } -} - /// 退出到用户态之前,在这个函数内做最后的处理 /// /// # Safety /// -/// 由于这个函数内可能会直接退出进程,因此,在进入函数之前, -/// 必须保证所有的栈上的Arc/Box指针等,都已经被释放。否则,可能会导致内存泄漏。 -unsafe fn irqentry_exit_to_user_mode(frame: &mut TrapFrame) { - exit_to_user_mode_prepare(frame); -} +/// 由于此函数内可能会直接退出进程,在进入之前必须保证所有栈上的 Arc/Box 指针已被释,否则可能导致内存泄漏。 +unsafe fn exit_to_user_mode_loop(frame: &mut TrapFrame) { + loop { + // 必须在关中断下读取标志,防止竞态 + CurrentIrqArch::interrupt_disable(); -/// # Safety -/// -/// 由于这个函数内可能会直接退出进程,因此,在进入函数之前, -/// 必须保证所有的栈上的Arc/Box指针等,都已经被释放。否则,可能会导致内存泄漏。 -unsafe fn exit_to_user_mode_prepare(frame: &mut TrapFrame) { - let process_flags_work = *ProcessManager::current_pcb().flags(); - if !process_flags_work.exit_to_user_mode_work().is_empty() { - exit_to_user_mode_loop(frame, process_flags_work); - } -} + let pcb = ProcessManager::current_pcb(); + let flags = *pcb.flags(); -/// # Safety -/// -/// 由于这个函数内可能会直接退出进程,因此,在进入函数之前, -/// 必须保证所有的栈上的Arc/Box指针等,都已经被释放。否则,可能会导致内存泄漏。 -unsafe fn exit_to_user_mode_loop(frame: &mut TrapFrame, mut process_flags_work: ProcessFlags) { - let pcb = ProcessManager::current_pcb(); - // if pcb.raw_pid() > RawPid::from(11) { - // log::debug!( - // "[EXIT_TO_USERMODE] PID {} flags={:?}, HAS_PENDING_SIGNAL={}, NEED_RSEQ={}", - // pcb.raw_pid(), - // process_flags_work, - // process_flags_work.contains(ProcessFlags::HAS_PENDING_SIGNAL), - // process_flags_work.contains(ProcessFlags::NEED_RSEQ) - // ); - // } + // 筛选出需要处理的标志位(信号、调度、RSEQ 等) + let work = flags.exit_to_user_mode_work(); + if work.is_empty() { + // 无工作,保持关中断返回 + break; + } + + // 有工作,必须开中断处理 + // 释放 PCB 引用,避免持有自旋锁或导致引用计数问题 + drop(pcb); + CurrentIrqArch::interrupt_enable(); + + // 处理调度 (Linux: _TIF_NEED_RESCHED),无论是 syscall 还是 irq 返回,都必须检查抢占! + if flags.contains(ProcessFlags::NEED_SCHEDULE) { + schedule(SchedMode::SM_NONE); + } - while !process_flags_work.exit_to_user_mode_work().is_empty() { - // 优先处理 rseq,因为信号递送会保存 trapframe 到 sigframe - // rseq 的 IP fixup 必须在信号递送之前完成 - if process_flags_work.contains(ProcessFlags::NEED_RSEQ) + // 处理信号 (Linux: _TIF_SIGPENDING) + // Linux 通常先处理信号。如果信号导致了栈帧改变(跳去 Handler),RSEQ 的处理将推迟到 Handler 返回时。 + if flags.contains(ProcessFlags::HAS_PENDING_SIGNAL) { + CurrentSignalArch::do_signal_or_restart(frame); + } + + // 处理 RSEQ / Notify Resume (Linux: _TIF_NOTIFY_RESUME) + if flags.contains(ProcessFlags::NEED_RSEQ) && Rseq::handle_notify_resume(Some(frame)).is_err() { - // rseq 处理失败,发送 SIGSEGV let pcb = ProcessManager::current_pcb(); let _ = crate::ipc::kill::send_signal_to_pcb(pcb, Signal::SIGSEGV); } - if process_flags_work.contains(ProcessFlags::HAS_PENDING_SIGNAL) { - unsafe { CurrentSignalArch::do_signal_or_restart(frame) }; - } - process_flags_work = *ProcessManager::current_pcb().flags(); + // 循环继续,再次关中断检查是否有新工作产生 + } + + // 循环结束,所有工作已完成,保持关中断状态返回到汇编层 + // 汇编代码将执行 iret/sysret 返回用户态 +} + +/// 从系统调用返回到用户态的统一退出路径 +/// 对应 Linux 6.6.21 arch/x86/entry/common.c::syscall_return_to_user_mode +/// +/// # Safety +/// +/// 由于此函数内可能会直接退出进程,在进入之前必须保证所有栈上的 Arc/Box 指针已被释放 +#[no_mangle] +pub unsafe extern "C" fn syscall_exit_to_user_mode(frame: &mut TrapFrame) { + // 这一步必须在 flags 检查之外进行,因为它是一个独立的安全检查 + Rseq::rseq_syscall_check(frame); + // 系统调用直接调用统一循环 + exit_to_user_mode_loop(frame); +} + +/// 从中断/异常返回到用户态的退出路径 +/// 对应 Linux 6.6.21 kernel/entry/common.c::irqentry_exit_to_user_mode +/// 用于处理非系统调用的返回路径(如中断返回) +#[no_mangle] +pub unsafe extern "C" fn irqentry_exit(frame: &mut TrapFrame) { + // 只有返回用户态时才处理 + if frame.is_from_user() { + exit_to_user_mode_loop(frame); } } diff --git a/kernel/src/ipc/generic_signal.rs b/kernel/src/ipc/generic_signal.rs index ad28739d4..351cfbb4b 100644 --- a/kernel/src/ipc/generic_signal.rs +++ b/kernel/src/ipc/generic_signal.rs @@ -5,7 +5,7 @@ use num_traits::FromPrimitive; use crate::ipc::signal_types::SignalFlags; use crate::{ arch::{ - ipc::signal::{SigSet, Signal, MAX_SIG_NUM}, + ipc::signal::{SigFlags, SigSet, Signal, MAX_SIG_NUM}, CurrentIrqArch, }, exception::InterruptArch, @@ -461,13 +461,25 @@ fn sig_stop(sig: Signal) { // 向父进程报告 SIGCHLD 并唤醒父进程可能阻塞的 wait let pcb = ProcessManager::current_pcb(); if let Some(parent) = pcb.parent_pcb() { - let _ = crate::ipc::kill::send_signal_to_pcb(parent.clone(), Signal::SIGCHLD); + let should_notify = { + let sighand = parent.sighand(); + sighand + .handler(Signal::SIGCHLD) + .map(|sa| !sa.flags().contains(SigFlags::SA_NOCLDSTOP)) + .unwrap_or(false) + }; + + if should_notify { + let _ = crate::ipc::kill::send_signal_to_pcb(parent.clone(), Signal::SIGCHLD); + } + // 无论是否发送 SIGCHLD,都需要唤醒父进程的 wait 队列,因为 waitpid(WUNTRACED) 可能需要返回 parent.wake_all_waiters(); } // 唤醒等待在该子进程等待队列上的等待者 pcb.wake_all_waiters(); schedule(SchedMode::SM_NONE); } + /// 信号默认处理函数——继续进程 fn sig_continue(_sig: Signal) { // 默认处理改为最小化:仅在已处于 Stopped 时唤醒停止,让进程继续运行。 diff --git a/kernel/src/ipc/kill.rs b/kernel/src/ipc/kill.rs index 0adeef72a..000040321 100644 --- a/kernel/src/ipc/kill.rs +++ b/kernel/src/ipc/kill.rs @@ -16,13 +16,7 @@ use system_error::SystemError; /// kill() 系统调用发送进程级信号,使用 PidType::TGID pub fn send_signal_to_pid(pid: RawPid, sig: Signal) -> Result { // 查找目标进程 - let target = ProcessManager::find_task_by_vpid(pid); - - if target.is_none() { - return Err(SystemError::ESRCH); - } - - let target = target.unwrap(); + let target = ProcessManager::find_task_by_vpid(pid).ok_or(SystemError::ESRCH)?; // 检查权限(传入信号以处理 SIGCONT 特殊情况) check_signal_permission_pcb_with_sig(&target, Some(sig))?; diff --git a/kernel/src/ipc/signal.rs b/kernel/src/ipc/signal.rs index 1b5ac0f8e..c26c7bb09 100644 --- a/kernel/src/ipc/signal.rs +++ b/kernel/src/ipc/signal.rs @@ -18,8 +18,7 @@ use crate::{ libs::rwlock::RwLockWriteGuard, mm::VirtAddr, process::{ - pid::PidType, ProcessControlBlock, ProcessFlags, ProcessManager, ProcessSignalInfo, - ProcessState, RawPid, + pid::PidType, ProcessControlBlock, ProcessFlags, ProcessManager, ProcessSignalInfo, RawPid, }, time::{syscall::PosixClockID, timekeeping::getnstimeofday, Instant, PosixTimeSpec}, }; @@ -285,15 +284,13 @@ impl Signal { // 判断目标进程是否应该被唤醒以立即处理该信号 let wants_signal = self.wants_signal(pcb.clone()); - // 按照 Linux 6.6.21 语义:对于被 ptrace 的进程,如果收到 SIGSTOP 信号,需要特殊处理 + // 对于被 ptrace 的进程,如果收到 SIGSTOP 信号,需要特殊处理 let is_ptrace_sigstop = pcb.flags().contains(ProcessFlags::PTRACED) && *self == Signal::SIGSTOP; let should_wake = if is_ptrace_sigstop { - matches!( - pcb.sched_info().inner_lock_read_irqsave().state(), - ProcessState::Blocked(_) - ) + // 对于 ptrace 进程的 SIGSTOP,总是需要唤醒 + true } else { wants_signal }; diff --git a/kernel/src/ipc/signal_types.rs b/kernel/src/ipc/signal_types.rs index d4ba13dc9..84b41043a 100644 --- a/kernel/src/ipc/signal_types.rs +++ b/kernel/src/ipc/signal_types.rs @@ -81,17 +81,17 @@ pub enum ChldCode { #[allow(dead_code)] pub enum TrapCode { /// process breakpoint - 断点触发 - TrapBrkpt = 1, + Brkpt = 1, /// process trace trap - ptrace 单步执行 - TrapTrace = 2, + Trace = 2, /// process taken branch trap - 分支跟踪 - TrapBranch = 3, + Branch = 3, /// hardware breakpoint/watchpoint - 硬件断点 - TrapHwbkpt = 4, + Hwbkpt = 4, /// undiagnosed trap - 未诊断的陷阱 - TrapUnk = 5, + Unk = 5, /// perf event with sigtrap=1 - 性能事件 - TrapPerf = 6, + Perf = 6, } /// SIGILL/SIGFPE/SIGSEGV/SIGBUS 的原因码 (ILL_*, FPE_*, SEGV_*, BUS_*) @@ -630,8 +630,33 @@ impl SigInfo { }, }, }, - SigType::SigFault(sig_fault_info) => todo!(), - SigType::SigChld(sig_chld_info) => todo!(), + SigType::SigFault(sig_fault_info) => PosixSigInfo { + si_signo: self.sig_no, + si_errno: self.errno, + si_code: i32::from(self.sig_code), + _sifields: PosixSiginfoFields { + _sigfault: PosixSiginfoSigfault { + si_addr: sig_fault_info.addr as u64, + si_addr_lsb: 0, + si_band: 0, + si_fd: 0, + }, + }, + }, + SigType::SigChld(sig_chld_info) => PosixSigInfo { + si_signo: self.sig_no, + si_errno: self.errno, + si_code: i32::from(self.sig_code), + _sifields: PosixSiginfoFields { + _sigchld: PosixSiginfoSigchld { + si_pid: sig_chld_info.pid.data() as i32, + si_uid: sig_chld_info.uid as u32, + si_status: sig_chld_info.status, + si_utime: sig_chld_info.utime as i64, + si_stime: sig_chld_info.stime as i64, + }, + }, + }, } } diff --git a/kernel/src/ipc/syscall/sys_kill.rs b/kernel/src/ipc/syscall/sys_kill.rs index 8fe5d40b4..afdeadbef 100644 --- a/kernel/src/ipc/syscall/sys_kill.rs +++ b/kernel/src/ipc/syscall/sys_kill.rs @@ -205,8 +205,6 @@ impl Syscall for SysKillHandle { let id = Self::pid(args); let sig_c_int = Self::sig(args); - let current_pcb = ProcessManager::current_pcb(); - let converter = PidConverter::from_id(id).ok_or(SystemError::ESRCH)?; // Handle null signal (signal 0) - used for existence and permission checks diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs index ecc9066dd..4b30ac153 100644 --- a/kernel/src/process/exit.rs +++ b/kernel/src/process/exit.rs @@ -732,7 +732,7 @@ fn do_waitpid( // 这是 ptrace 专用的停止状态,总是报告给 tracer // 提取实际的信号编号 (低 8 位 & 0x7f) let actual_sig = stopsig & 0x7f; - if actual_sig <= 0 || actual_sig >= Signal::SIGRTMAX.into() { + if actual_sig >= Signal::SIGRTMAX.into() { return Some(Err(SystemError::EINVAL)); } // TracedStopped 状态总是被 ptrace,所以总是报告停止状态 diff --git a/kernel/src/process/fork.rs b/kernel/src/process/fork.rs index e51e89bb9..6a9081752 100644 --- a/kernel/src/process/fork.rs +++ b/kernel/src/process/fork.rs @@ -1,25 +1,18 @@ -use alloc::vec::Vec; +use alloc::{string::ToString, sync::Arc, vec::Vec}; use core::{intrinsics::unlikely, sync::atomic::Ordering}; - -use crate::arch::MMArch; -use crate::filesystem::vfs::file::File; -use crate::filesystem::vfs::file::FileFlags; -use crate::filesystem::vfs::file::FilePrivateData; -use crate::filesystem::vfs::FileType; -use crate::filesystem::vfs::InodeMode; -use crate::mm::access_ok; -use crate::mm::MemoryManagementArch; -use crate::process::pid::PidPrivateData; -use alloc::{string::ToString, sync::Arc}; use log::error; use system_error::SystemError; use crate::{ - arch::{interrupt::TrapFrame, ipc::signal::Signal}, + arch::{interrupt::TrapFrame, ipc::signal::Signal, MMArch}, + filesystem::vfs::{ + file::{File, FileFlags, FilePrivateData}, + FileType, InodeMode, + }, ipc::signal_types::SignalFlags, libs::rwsem::RwSem, - mm::VirtAddr, - process::ProcessFlags, + mm::{access_ok, MemoryManagementArch, VirtAddr}, + process::{pid::PidPrivateData, ProcessFlags}, sched::{sched_cgroup_fork, sched_fork}, smp::core::smp_get_processor_id, syscall::user_access::UserBufferWriter, @@ -686,17 +679,11 @@ impl ProcessManager { } } else { // 新创建的进程,设置其父进程为当前进程 - let current_pid = current_pcb.raw_pid(); - let child_pid = pcb.raw_pid(); - *pcb.real_parent_pcb.write_irqsave() = Arc::downgrade(current_pcb); // 同时设置parent_pcb(按照Linux语义,默认parent=real_parent) *pcb.parent_pcb.write_irqsave() = Arc::downgrade(current_pcb); - // 验证设置 - let verify_parent = pcb.parent_pcb.read_irqsave(); - let verify_pid = verify_parent.upgrade().map(|p| p.raw_pid()); pcb.exit_signal .store(clone_args.exit_signal, Ordering::SeqCst); } diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 201a4fff8..55f7d12ef 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -870,20 +870,20 @@ impl ProcessState { #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(i32)] pub enum PtraceRequest { - PtraceTraceme = 0, - PtracePeekdata = 2, - PtracePeekuser = 3, - PtracePokedata = 5, - PtraceCont = 7, - PtraceSinglestep = 9, - PtraceGetregs = 12, - PtraceSetregs = 13, - PtraceAttach = 16, - PtraceDetach = 17, - PtraceSyscall = 24, - PtraceSetoptions = 0x4200, - PtraceGetsiginfo = 0x4202, - PtraceSeize = 0x4206, // 现代 API,不发送 SIGSTOP + Traceme = 0, + Peekdata = 2, + Peekuser = 3, + Pokedata = 5, + Cont = 7, + Singlestep = 9, + Getregs = 12, + Setregs = 13, + Attach = 16, + Detach = 17, + Syscall = 24, + Setoptions = 0x4200, + Getsiginfo = 0x4202, + Seize = 0x4206, // 现代 API,不发送 SIGSTOP } bitflags! { @@ -943,7 +943,24 @@ bitflags! { } impl ProcessFlags { + /// 获取需要在系统调用返回到用户态前处理的工作标志 + /// + /// 按照 Linux 6.6.21 的 _TIF_WORK_MASK 语义: + /// - TIF_SIGPENDING (HAS_PENDING_SIGNAL): 有待处理的信号 + /// - TIF_NEED_RESCHED (NEED_SCHEDULE): 需要调度 + /// - TIF_NOTIFY_RESUME (NEED_RSEQ): 需要处理 rseq pub const fn exit_to_user_mode_work(&self) -> Self { + Self::from_bits_truncate( + self.bits + & (Self::HAS_PENDING_SIGNAL.bits | Self::NEED_SCHEDULE.bits | Self::NEED_RSEQ.bits), + ) + } + + /// 获取需要在中断返回到用户态前处理的工作标志 + /// + /// 中断返回路径不需要检查 NEED_SCHEDULE,因为调度在其他地方处理 + #[allow(dead_code)] + pub const fn exit_to_user_mode_work_irq(&self) -> Self { Self::from_bits_truncate(self.bits & (Self::HAS_PENDING_SIGNAL.bits | Self::NEED_RSEQ.bits)) } @@ -1057,12 +1074,13 @@ pub enum PtraceEvent { /// 进程被跟踪的状态信息 #[derive(Debug)] -struct PtraceState { +pub struct PtraceState { /// 跟踪此进程的进程PID tracer: Option, /// 挂起的信号(等待调试器处理) pending_signals: Vec, - stop_reason: PtraceStopReason, + /// 停止原因(公开,以便在 syscall_handler 中设置) + pub stop_reason: PtraceStopReason, /// ptrace选项位 options: PtraceOptions, /// 停止状态的状态字 @@ -1071,10 +1089,6 @@ struct PtraceState { event_message: usize, /// tracer 注入的信号(在 ptrace_stop 返回后要处理的信号) injected_signal: Signal, - /// 是否需要在系统调用入口停止(用于 PTRACE_SYSCALL) - /// true: 需要在系统调用入口停止 - /// false: 已经完成入口停止,应该执行系统调用 - needs_syscall_entry_stop: bool, } impl Default for PtraceState { @@ -1087,7 +1101,6 @@ impl Default for PtraceState { exit_code: 0, event_message: 0, injected_signal: Signal::INVALID, - needs_syscall_entry_stop: true, // 默认需要在入口停止 } } } @@ -1101,7 +1114,6 @@ impl PtraceState { exit_code: 0, event_message: 0, injected_signal: Signal::INVALID, - needs_syscall_entry_stop: true, // 默认需要在入口停止 } } @@ -1974,12 +1986,6 @@ impl ProcessControlBlock { self.ptrace_state.lock() } - /// 设置是否需要在系统调用入口停止 - #[inline] - pub fn set_needs_syscall_entry_stop(&self, value: bool) { - self.ptrace_state.lock().needs_syscall_entry_stop = value; - } - /// 唤醒进程(用于子进程退出时唤醒父进程) /// /// 当子进程退出时,需要唤醒父进程,即使父进程不在 wait() 中睡眠 @@ -1989,12 +1995,6 @@ impl ProcessControlBlock { signal_wake_up(self.self_ref.upgrade().unwrap(), false); } - /// 获取是否需要在系统调用入口停止 - #[inline] - pub fn needs_syscall_entry_stop(&self) -> bool { - self.ptrace_state.lock().needs_syscall_entry_stop - } - pub fn try_siginfo_mut(&self, times: u8) -> Option> { for _ in 0..times { if let Some(r) = self.sig_info.try_write_irqsave() { diff --git a/kernel/src/process/ptrace.rs b/kernel/src/process/ptrace.rs index 0f077304f..86bd2a26e 100644 --- a/kernel/src/process/ptrace.rs +++ b/kernel/src/process/ptrace.rs @@ -2,8 +2,7 @@ use crate::arch::interrupt::TrapFrame; use crate::arch::ipc::signal::{SigFlags, Signal}; use crate::arch::kprobe; use crate::ipc::signal_types::{ - ChldCode, OriginCode, SigChldInfo, SigCode, SigFaultInfo, SigInfo, SigType, Sigaction, - SigactionType, SignalFlags, TrapCode, + ChldCode, OriginCode, SigChldInfo, SigCode, SigFaultInfo, SigInfo, SigType, TrapCode, }; use crate::process::{ pid::PidType, ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState, PtraceEvent, @@ -27,13 +26,13 @@ pub fn ptrace_signal( ) -> Option { // todo pcb.jobctl_set(JobControlFlags::STOP_DEQUEUED); // 注意:ptrace_stop 内部会处理锁的释放和重新获取。 - let mut signr = pcb.ptrace_stop(original_signal as usize, ChldCode::Trapped, info.as_mut()); + let signr = pcb.ptrace_stop(original_signal as usize, ChldCode::Trapped, info.as_mut()); if signr == 0 { return None; // 丢弃原始信号,继续处理下一个信号(如果没有,则继续执行) } // 将注入的信号转换为 Signal 类型 - let mut injected_signal = Signal::from(signr); + let injected_signal = Signal::from(signr); if injected_signal == Signal::INVALID { return None; } @@ -41,18 +40,19 @@ pub fn ptrace_signal( // 如果追踪者注入了不同于原始信号的新信号,更新 siginfo if injected_signal != original_signal { if let Some(info_ref) = info { - let tracer = pcb.parent_pcb().unwrap(); - // 使用 Kill 类型(SI_USER)而不是 SigChld - // 这样更符合 ptrace 注入信号的语义 - *info_ref = SigInfo::new( - injected_signal, - 0, - SigCode::Origin(OriginCode::User), - SigType::Kill { - pid: tracer.raw_pid(), - uid: tracer.cred().uid.data() as u32, - }, - ); + // 如果获取失败,保持原有的 siginfo + if let Some(tracer) = pcb.tracer().and_then(ProcessManager::find) { + *info_ref = SigInfo::new( + injected_signal, + 0, + SigCode::Origin(OriginCode::User), + SigType::Kill { + pid: tracer.raw_pid(), + uid: tracer.cred().uid.data() as u32, + }, + ); + } + // 如果获取 tracer 失败,info 保持原样,这不是致命错误 } } @@ -88,6 +88,7 @@ pub fn ptrace_signal( Some(injected_signal) } +#[allow(dead_code)] pub fn do_notify_parent(child: &ProcessControlBlock, signal: Signal) -> Result { let parent = match child.parent_pcb() { Some(p) => p, @@ -141,6 +142,7 @@ pub fn do_notify_parent(child: &ProcessControlBlock, signal: Signal) -> Result, sig: Signal) { let mut ptrace_state = current_pcb.ptrace_state.lock(); ptrace_state.stop_reason = PtraceStopReason::Signal(sig); @@ -247,6 +249,7 @@ impl ProcessControlBlock { } /// 唤醒父进程的等待队列 + #[allow(dead_code)] fn wake_up_parent(&self, state: Option) { if let Some(parent) = self.parent_pcb() { parent.wait_queue.wakeup(state); @@ -327,11 +330,11 @@ impl ProcessControlBlock { SigCode::Origin(OriginCode::Kernel), SigType::SigFault(SigFaultInfo { addr: 0, trapno: 0 }), ); - let _ = sig.send_signal_info_to_pcb( - Some(&mut info), - self.self_ref.upgrade().unwrap(), - PidType::PID, - ); + // 按照 Linux 6.6:如果 self_ref 升级失败,说明进程正在销毁 + // 此时发送信号没有意义,安全地跳过 + if let Some(strong_ref) = self.self_ref.upgrade() { + let _ = sig.send_signal_info_to_pcb(Some(&mut info), strong_ref, PidType::PID); + } } // PTRACE_SEIZE:不发送信号,静默返回 } @@ -434,13 +437,13 @@ impl ProcessControlBlock { // 使用 TRAP_BRKPT (1) 作为默认 trapno,表示 ptrace 触发的停止 let _sigtrap_info = SigFaultInfo { addr: 0, - trapno: TrapCode::TrapBrkpt as i32, + trapno: TrapCode::Brkpt as i32, }; // 构造 SIGTRAP siginfo 供调试器通过 PTRACE_GETSIGINFO 读取 let _info = SigInfo::new( Signal::SIGTRAP, - TrapCode::TrapBrkpt as i32, + TrapCode::Brkpt as i32, SigCode::SigFault(_sigtrap_info), SigType::SigFault(_sigtrap_info), ); @@ -529,7 +532,7 @@ impl ProcessControlBlock { // } // 清理凭证信息 { - let mut cred = self.cred.lock(); + let _cred = self.cred.lock(); // todo *cred = self.original_cred().clone(); } // 获取信号锁保护信号相关操作 @@ -592,27 +595,37 @@ impl ProcessControlBlock { self.ptrace_link(tracer)?; let sig = Signal::SIGSTOP; + // 按照 Linux 6.6 ptrace_attach:发送 SIGSTOP 作为内核信号 + // 使用 Kill 类型表示来自内核的信号 let mut info = SigInfo::new( sig, 0, SigCode::Origin(OriginCode::Kernel), - SigType::SigFault(SigFaultInfo { addr: 0, trapno: 0 }), + SigType::Kill { + pid: RawPid(0), // 内核发送 + uid: 0, + }, ); - if let Err(e) = sig.send_signal_info_to_pcb( - Some(&mut info), - self.self_ref.upgrade().unwrap(), - PidType::PID, - ) { - // 回滚ptrace设置 + // 按照 Linux 6.6:如果 self_ref 升级失败,说明进程正在销毁 + if let Some(strong_ref) = self.self_ref.upgrade() { + if let Err(e) = sig.send_signal_info_to_pcb(Some(&mut info), strong_ref, PidType::PID) { + // 回滚ptrace设置 + self.flags().remove(ProcessFlags::PTRACED); + self.ptrace_unlink()?; + return Err(e); + } + } else { + // 进程正在销毁,回滚 ptrace 设置 self.flags().remove(ProcessFlags::PTRACED); self.ptrace_unlink()?; - return Err(e); + return Err(SystemError::ESRCH); } // 等待 tracee 进入 TracedStopped 状态 - let tracee_ref = self.self_ref.upgrade().unwrap(); + // 按照 Linux 6.6:检查 wait 结果,如果被中断则回滚 + let tracee_ref = self.self_ref.upgrade().ok_or(SystemError::ESRCH)?; let tracer_clone = tracer.clone(); - let _wait_result = tracer_clone.wait_queue.wait_event_interruptible( + let wait_result = tracer_clone.wait_queue.wait_event_interruptible( || { let state = tracee_ref.sched_info().inner_lock_read_irqsave().state(); matches!(state, ProcessState::TracedStopped(_)) @@ -620,6 +633,13 @@ impl ProcessControlBlock { None::, ); + // 检查等待结果,如果被中断则回滚 + if wait_result.is_err() { + self.flags().remove(ProcessFlags::PTRACED); + self.ptrace_unlink()?; + return Err(SystemError::ERESTARTSYS); + } + Ok(0) } @@ -691,11 +711,15 @@ impl ProcessControlBlock { }, ); // 发送信号(此时已经 ptrace_unlink,所以信号会正常处理) - let _ = sig.send_signal_info_to_pcb( - Some(&mut info), - self.self_ref.upgrade().unwrap(), - crate::process::pid::PidType::PID, - ); + // 按照 Linux 6.6:如果 self_ref 升级失败,说明进程正在销毁 + if let Some(strong_ref) = self.self_ref.upgrade() { + let _ = sig.send_signal_info_to_pcb( + Some(&mut info), + strong_ref, + crate::process::pid::PidType::PID, + ); + } + // 如果进程正在销毁,信号发送失败不是致命错误 } // 3. 同时将信号存储到 ptrace_state.injected_signal @@ -730,7 +754,8 @@ impl ProcessControlBlock { let (rq, _guard) = rq.self_lock(); rq.update_rq_clock(); - let strong_ref = self.self_ref.upgrade().unwrap(); + // 按照 Linux 6.6:如果 self_ref 升级失败,说明进程正在销毁 + let strong_ref = self.self_ref.upgrade().ok_or(SystemError::ESRCH)?; rq.activate_task( &strong_ref, EnqueueFlag::ENQUEUE_WAKEUP | EnqueueFlag::ENQUEUE_NOCLOCK, @@ -749,8 +774,8 @@ impl ProcessControlBlock { frame: &mut TrapFrame, ) -> Result { match request { - PtraceRequest::PtraceSyscall => self.flags().insert(ProcessFlags::TRACE_SYSCALL), - PtraceRequest::PtraceSinglestep => { + PtraceRequest::Syscall => self.flags().insert(ProcessFlags::TRACE_SYSCALL), + PtraceRequest::Singlestep => { self.flags().insert(ProcessFlags::TRACE_SINGLESTEP); kprobe::setup_single_step(frame, frame.rip as usize); // 设置 TF 标志 } @@ -800,10 +825,9 @@ impl ProcessControlBlock { self.flags().insert(ProcessFlags::TRACE_SYSCALL); self.flags().remove(ProcessFlags::TRACE_SINGLESTEP); - // 重置入口停止标志,确保下一个系统调用会在入口停止 - self.set_needs_syscall_entry_stop(true); - // 恢复进程运行 + // 进程将在下次系统调用的入口和出口自动停止 + // (在 syscall_handler 中同步调用 ptrace_stop) let mut sched_info = self.sched_info.inner_lock_write_irqsave(); match sched_info.state() { ProcessState::TracedStopped(_) | ProcessState::Stopped(_) => { @@ -832,7 +856,7 @@ impl ProcessControlBlock { pub fn ptrace_get_syscall_info( &self, user_size: usize, - datavp: usize, // Use a raw byte pointer for flexibility + _datavp: usize, // Use a raw byte pointer for flexibility ) -> Result { // todo let trap_frame = self.task_context(); let trap_frame = TrapFrame::new(); @@ -881,7 +905,7 @@ impl ProcessControlBlock { let write_size = core::cmp::min(actual_size, user_size); if write_size > 0 { // 将结构体视为字节切片进行拷贝 - let info_bytes = + let _info_bytes = unsafe { core::slice::from_raw_parts(&info as *const _ as *const u8, write_size) }; // datavp.write_bytes(info_bytes)?; } @@ -938,17 +962,17 @@ impl ProcessControlBlock { } /// 在系统调用入口处理 - pub fn on_syscall_entry(&self, num: usize, args: &[usize]) { + pub fn on_syscall_entry(&self, _num: usize, _args: &[usize]) { // 实际实现中需要记录系统调用信息 } /// 在系统调用出口处理 - pub fn on_syscall_exit(&self, result: isize) { + pub fn on_syscall_exit(&self, _result: isize) { // 实际实现中需要记录系统调用结果 } /// 处理 PTRACE_PEEKUSER 请求 - pub fn peek_user(&self, addr: usize) -> Result { + pub fn peek_user(&self, _addr: usize) -> Result { // // 验证地址是否在用户空间范围内 // if !self.memory.is_user_address(addr) { // return Err(SystemError::EFAULT); @@ -991,6 +1015,7 @@ impl ProcessControlBlock { ); } + #[allow(dead_code)] fn decode_exit_code_for_siginfo(exit_code: i32) -> (SigCode, i32) { if (exit_code & 0x7f) == 0 { // 正常退出: exit() diff --git a/kernel/src/process/rseq.rs b/kernel/src/process/rseq.rs index b1b8285bb..46ec673fd 100644 --- a/kernel/src/process/rseq.rs +++ b/kernel/src/process/rseq.rs @@ -17,9 +17,11 @@ use core::sync::atomic::{AtomicU32, Ordering}; use system_error::SystemError; use crate::{ - arch::cpu::current_cpu_id, - mm::VirtAddr, + arch::{cpu::current_cpu_id, ipc::signal::Signal, MMArch}, + ipc::kill::send_signal_to_pcb, + mm::{MemoryManagementArch, VirtAddr}, process::{ProcessControlBlock, ProcessFlags, ProcessManager}, + syscall::user_access::{copy_from_user_protected, copy_to_user_protected}, }; // ============================================================================ @@ -205,7 +207,7 @@ impl UserRseqAccess { /// 读取 u32 值 unsafe fn read_u32(&self, offset: usize) -> Result { let mut bytes = [0u8; 4]; - crate::syscall::user_access::copy_from_user_protected(&mut bytes, self.base + offset) + copy_from_user_protected(&mut bytes, self.base + offset) .map_err(|_| RseqError::UserAccessFault)?; Ok(u32::from_ne_bytes(bytes)) } @@ -213,28 +215,22 @@ impl UserRseqAccess { /// 读取 u64 值 unsafe fn read_u64(&self, offset: usize) -> Result { let mut bytes = [0u8; 8]; - crate::syscall::user_access::copy_from_user_protected(&mut bytes, self.base + offset) + copy_from_user_protected(&mut bytes, self.base + offset) .map_err(|_| RseqError::UserAccessFault)?; Ok(u64::from_ne_bytes(bytes)) } /// 写入 u32 值 unsafe fn write_u32(&self, offset: usize, value: u32) -> Result<(), RseqError> { - crate::syscall::user_access::copy_to_user_protected( - self.base + offset, - &value.to_ne_bytes(), - ) - .map_err(|_| RseqError::UserAccessFault)?; + copy_to_user_protected(self.base + offset, &value.to_ne_bytes()) + .map_err(|_| RseqError::UserAccessFault)?; Ok(()) } /// 写入 u64 值 unsafe fn write_u64(&self, offset: usize, value: u64) -> Result<(), RseqError> { - crate::syscall::user_access::copy_to_user_protected( - self.base + offset, - &value.to_ne_bytes(), - ) - .map_err(|_| RseqError::UserAccessFault)?; + copy_to_user_protected(self.base + offset, &value.to_ne_bytes()) + .map_err(|_| RseqError::UserAccessFault)?; Ok(()) } @@ -271,7 +267,7 @@ impl UserRseqAccess { } let sig_addr = VirtAddr::new((rseq_cs.abort_ip - 4) as usize); let mut sig_bytes = [0u8; 4]; - crate::syscall::user_access::copy_from_user_protected(&mut sig_bytes, sig_addr) + copy_from_user_protected(&mut sig_bytes, sig_addr) .map_err(|_| RseqError::UserAccessFault)?; let read_sig = u32::from_ne_bytes(sig_bytes); @@ -385,6 +381,24 @@ impl RseqState { self.registration.as_ref() } + /// 获取当前 rseq_cs(从用户内存读取) + /// 用于 rseq_syscall_check:检查是否在 rseq 临界区内发起了系统调用 + /// + /// # Safety + /// + /// 调用者必须确保用户内存有效 + pub unsafe fn get_rseq_cs(&self) -> Option<(RseqCs, u32)> { + let reg = self.registration.as_ref()?; + let access = UserRseqAccess::new(reg.ptr); + let user_end = MMArch::USER_END_VADDR.data(); + + // 读取 rseq_cs,忽略签名验证(因为在 syscall 路径中我们已经注册过) + match access.read_rseq_cs(reg.sig, user_end) { + Ok(Some(cs)) => Some((cs, reg.sig)), + _ => None, + } + } + /// 设置事件掩码(原子操作) #[inline] pub fn set_event(&self, event: RseqEventMask) { @@ -451,8 +465,6 @@ impl Rseq { rseq_len: u32, sig: u32, ) -> Result { - use crate::{arch::MMArch, mm::MemoryManagementArch}; - let mut rseq_state = pcb.rseq_state_mut(); // 检查是否已注册 @@ -546,8 +558,6 @@ impl Rseq { /// /// 在返回用户态前调用,执行 IP 修正和 cpu_id 更新 pub fn handle_notify_resume(frame: Option<&mut F>) -> Result<(), ()> { - use crate::{arch::MMArch, mm::MemoryManagementArch}; - let pcb = ProcessManager::current_pcb(); // 如果进程正在退出,直接返回 @@ -685,12 +695,11 @@ impl Rseq { /// 在信号递送时调用 pub fn on_signal(frame: &mut F) { - use crate::arch::ipc::signal::Signal; let pcb = ProcessManager::current_pcb(); if pcb.rseq_state().is_registered() { pcb.rseq_state().set_event(RseqEventMask::SIGNAL); if Self::handle_notify_resume(Some(frame)).is_err() { - let _ = crate::ipc::kill::send_signal_to_pcb(pcb.clone(), Signal::SIGSEGV); + let _ = send_signal_to_pcb(pcb.clone(), Signal::SIGSEGV); } } } @@ -704,6 +713,22 @@ impl Rseq { pcb.flags().insert(ProcessFlags::NEED_RSEQ); } } + + /// 系统调用退出时的 rseq 检查 + /// **注意**: Linux 的 rseq_syscall 仅在 CONFIG_DEBUG_RSEQ 启用时编译, + /// 用于调试目的,检测在 rseq 临界区内发起系统调用的违规行为。 + /// + /// 在生产环境中,此函数应为空操作。rseq 的正确性依赖于: + /// 此函数目前为空操作,与 Linux 生产内核行为一致。 + /// + /// # Safety + /// + /// 调用者必须保证 frame 指向有效的 TrapFrame + #[inline] + pub unsafe fn rseq_syscall_check(_frame: &F) { + // 生产环境:空操作,与 Linux 生产内核一致 + // 若需启用调试检查,应编译时启用 DEBUG_RSEQ 特性标志 + } } // ============================================================================ diff --git a/kernel/src/process/syscall/sys_ptrace.rs b/kernel/src/process/syscall/sys_ptrace.rs index 326a32f76..2b0b0f831 100644 --- a/kernel/src/process/syscall/sys_ptrace.rs +++ b/kernel/src/process/syscall/sys_ptrace.rs @@ -1,14 +1,21 @@ -use crate::arch::interrupt::TrapFrame; -use crate::arch::ipc::signal::Signal; -use crate::arch::syscall::nr::{SYS_EXIT, SYS_PTRACE}; -use crate::mm::{MemoryManagementArch, PageTableKind, VirtAddr}; -use crate::process::syscall::sys_exit::SysExit; -use crate::process::{ - ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState, PtraceOptions, PtraceRequest, - RawPid, +use crate::{ + arch::{ + interrupt::TrapFrame, + ipc::signal::Signal, + syscall::nr::{SYS_EXIT, SYS_PTRACE}, + CurrentIrqArch, MMArch, + }, + exception::{InterruptArch, IrqFlagsGuard}, + mm::{MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr}, + process::{ + syscall::sys_exit::SysExit, ProcessControlBlock, ProcessFlags, ProcessManager, + ProcessState, PtraceOptions, PtraceRequest, RawPid, + }, + syscall::{ + table::{FormattedSyscallParam, Syscall}, + user_access::{copy_from_user_protected, copy_to_user_protected, UserBufferWriter}, + }, }; -use crate::syscall::table::{FormattedSyscallParam, Syscall}; -use crate::syscall::user_access::UserBufferWriter; use alloc::sync::Arc; use alloc::vec::Vec; use system_error::SystemError; @@ -96,24 +103,110 @@ impl TryFrom for PtraceRequest { fn try_from(value: usize) -> Result { match value { - 0 => Ok(PtraceRequest::PtraceTraceme), - 2 => Ok(PtraceRequest::PtracePeekdata), - 5 => Ok(PtraceRequest::PtracePokedata), - 7 => Ok(PtraceRequest::PtraceCont), - 9 => Ok(PtraceRequest::PtraceSinglestep), - 12 => Ok(PtraceRequest::PtraceGetregs), - 13 => Ok(PtraceRequest::PtraceSetregs), - 16 => Ok(PtraceRequest::PtraceAttach), - 17 => Ok(PtraceRequest::PtraceDetach), - 24 => Ok(PtraceRequest::PtraceSyscall), - 0x4200 => Ok(PtraceRequest::PtraceSetoptions), - 0x4202 => Ok(PtraceRequest::PtraceGetsiginfo), - 0x4206 => Ok(PtraceRequest::PtraceSeize), + 0 => Ok(PtraceRequest::Traceme), + 2 => Ok(PtraceRequest::Peekdata), + 5 => Ok(PtraceRequest::Pokedata), + 7 => Ok(PtraceRequest::Cont), + 9 => Ok(PtraceRequest::Singlestep), + 12 => Ok(PtraceRequest::Getregs), + 13 => Ok(PtraceRequest::Setregs), + 16 => Ok(PtraceRequest::Attach), + 17 => Ok(PtraceRequest::Detach), + 24 => Ok(PtraceRequest::Syscall), + 0x4200 => Ok(PtraceRequest::Setoptions), + 0x4202 => Ok(PtraceRequest::Getsiginfo), + 0x4206 => Ok(PtraceRequest::Seize), _ => Err(SystemError::EINVAL), } } } +/// 页表切换守卫,用于在作用域结束时自动恢复页表 +/// +/// 按照 Linux 6.6 ptrace_access_vm 的模式: +/// 1. 禁用中断,防止在切换期间发生中断处理 +/// 2. 切换到目标进程的页表 +/// 3. 在作用域结束时恢复原始页表并重新启用中断 +struct PageTableGuard { + original_paddr: PhysAddr, + kind: PageTableKind, + _irq_guard: IrqFlagsGuard, +} + +impl PageTableGuard { + /// 切换到目标进程的页表 + /// + /// # Safety + /// 调用者必须确保: + /// 1. target_paddr 是有效的页表物理地址 + /// 2. 在此守卫存在期间不会发生调度 + fn new(target_paddr: PhysAddr, kind: PageTableKind) -> Self { + // 1. 首先禁用中断(关键!) + let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; + + // 2. 获取当前页表物理地址用于恢复 + let current_pcb = ProcessManager::current_pcb(); + let original_paddr = current_pcb + .basic() + .user_vm() + .map(|vm| { + let inner = vm.read_irqsave(); + inner.user_mapper.utable.table().phys() + }) + .expect("current process must have user VM"); + + // 3. 切换到目标进程的页表 + unsafe { + ::set_table(kind, target_paddr); + } + + Self { + original_paddr, + kind, + _irq_guard: irq_guard, + } + } +} + +impl Drop for PageTableGuard { + fn drop(&mut self) { + // 恢复原始页表 + unsafe { + ::set_table(self.kind, self.original_paddr); + } + // 中断会在 _irq_guard drop 时自动恢复 + } +} + +/// ptrace 内存访问辅助函数 +/// +/// 按照 Linux 6.6 的 ptrace_access_vm 模式实现: +/// - 使用临时页表切换访问目标进程的地址空间 +/// - 在中断禁用状态下进行页表切换 +/// - 使用守卫模式确保页表一定会被恢复 +/// +/// # Safety +/// 调用者必须确保 tracee 在访问期间不会被销毁 +fn ptrace_access_vm(tracee: &Arc, f: F) -> Result +where + F: FnOnce() -> Result, +{ + // 获取目标进程的地址空间 + let tracee_vm = tracee.basic().user_vm().ok_or(SystemError::ESRCH)?; + + // 获取目标进程的用户页表物理地址 + let tracee_mapper_paddr = { + let inner = tracee_vm.read_irqsave(); + inner.user_mapper.utable.table().phys() + }; + + // 使用守卫切换页表,确保一定会恢复 + let _guard = PageTableGuard::new(tracee_mapper_paddr, PageTableKind::User); + + // 在目标进程的地址空间中执行操作 + f() +} + /// ptrace 系统调用实现 pub struct SysPtrace; @@ -171,7 +264,9 @@ impl SysPtrace { signal: Option, ) -> Result { // 验证调用者是跟踪器 - if ProcessManager::current_pcb().raw_pid() != tracee.tracer().unwrap() { + let tracer_pid = ProcessManager::current_pcb().raw_pid(); + let tracee_tracer = tracee.tracer().ok_or(SystemError::ESRCH)?; + if tracer_pid != tracee_tracer { return Err(SystemError::EPERM); } tracee.detach(signal) @@ -180,8 +275,9 @@ impl SysPtrace { /// 处理 PTRACE_SYSCALL 请求(在系统调用入口和出口暂停) fn handle_syscall(tracee: &Arc) -> Result { // 检查调用者是否是该进程的跟踪器 - if ProcessManager::current_pcb().raw_pid() != tracee.tracer().unwrap() { - // TODO + let tracer_pid = ProcessManager::current_pcb().raw_pid(); + let tracee_tracer = tracee.tracer().ok_or(SystemError::ESRCH)?; + if tracer_pid != tracee_tracer { return Err(SystemError::ESRCH); } // 设置系统调用跟踪标志 @@ -219,122 +315,59 @@ impl SysPtrace { /// 处理 PTRACE_PEEKDATA 请求(读取进程内存) /// - /// 按照 Linux 6.6.21 的 ptrace 语义,PTRACE_PEEKDATA 需要从目标进程的地址空间读取数据 + /// 按照 Linux 6.6.21 的 ptrace 语义: + /// - 使用 ptrace_access_vm 模式访问目标进程地址空间 + /// - 在中断禁用状态下进行页表切换 + /// - 使用守卫模式确保页表恢复 fn handle_peek_data( tracee: &Arc, addr: usize, ) -> Result { - // 获取目标进程的地址空间 - let tracee_vm = tracee.basic().user_vm().ok_or(SystemError::ESRCH)?; - - // 获取目标进程的用户页表物理地址 - let tracee_mapper_paddr = { - let inner = tracee_vm.read_irqsave(); - inner.user_mapper.utable.table().phys() - }; - - // 获取当前进程的用户页表物理地址(用于恢复) - let current_pcb = ProcessManager::current_pcb(); - let current_vm = current_pcb.basic().user_vm().ok_or(SystemError::ESRCH)?; - let current_mapper_paddr = { - let inner = current_vm.read_irqsave(); - inner.user_mapper.utable.table().phys() - }; - - // 切换到目标进程的页表 - unsafe { - ::set_table( - PageTableKind::User, - tracee_mapper_paddr, - ); - } - - // 读取数据 - let mut value: u64 = 0; - let result = unsafe { - crate::syscall::user_access::copy_from_user_protected( - core::slice::from_raw_parts_mut(&mut value as *mut u64 as *mut u8, 8), - VirtAddr::new(addr), - ) - }; - - // 恢复当前进程的页表 - unsafe { - ::set_table( - PageTableKind::User, - current_mapper_paddr, - ); - } - - if result.is_err() { - return Err(SystemError::EIO); - } - - Ok(value as isize) + // 使用安全的 ptrace_access_vm 辅助函数 + ptrace_access_vm(tracee, || { + let mut value: u64 = 0; + unsafe { + copy_from_user_protected( + core::slice::from_raw_parts_mut(&mut value as *mut u64 as *mut u8, 8), + VirtAddr::new(addr), + ) + }?; + Ok(value as isize) + }) + .map_err(|_| SystemError::EIO) } /// 处理 PTRACE_POKEDATA 请求(写入进程内存) /// - /// 按照 Linux 6.6.21 的 ptrace 语义,PTRACE_POKEDATA 需要向目标进程的地址空间写入数据 + /// 按照 Linux 6.6.21 的 ptrace 语义: + /// - 使用 ptrace_access_vm 模式访问目标进程地址空间 + /// - 在中断禁用状态下进行页表切换 + /// - 使用守卫模式确保页表恢复 fn handle_poke_data( tracee: &Arc, addr: usize, data: usize, ) -> Result { - // 获取目标进程的地址空间 - let tracee_vm = tracee.basic().user_vm().ok_or(SystemError::ESRCH)?; - - // 获取目标进程的用户页表物理地址 - let tracee_mapper_paddr = { - let inner = tracee_vm.read_irqsave(); - inner.user_mapper.utable.table().phys() - }; - - // 获取当前进程的用户页表物理地址(用于恢复) - let current_pcb = ProcessManager::current_pcb(); - let current_vm = current_pcb.basic().user_vm().ok_or(SystemError::ESRCH)?; - let current_mapper_paddr = { - let inner = current_vm.read_irqsave(); - inner.user_mapper.utable.table().phys() - }; - - // 切换到目标进程的页表 - unsafe { - ::set_table( - PageTableKind::User, - tracee_mapper_paddr, - ); - } - - // 写入数据 - let value: u64 = data as u64; - let result = unsafe { - crate::syscall::user_access::copy_to_user_protected( - VirtAddr::new(addr), - core::slice::from_raw_parts(&value as *const u64 as *const u8, 8), - ) - }; - - // 恢复当前进程的页表 - unsafe { - ::set_table( - PageTableKind::User, - current_mapper_paddr, - ); - } - - if result.is_err() { - return Err(SystemError::EIO); - } - - Ok(0) + // 使用安全的 ptrace_access_vm 辅助函数 + ptrace_access_vm(tracee, || { + let value: u64 = data as u64; + unsafe { + copy_to_user_protected( + VirtAddr::new(addr), + core::slice::from_raw_parts(&value as *const u64 as *const u8, 8), + ) + }?; + Ok(0) + }) + .map_err(|_| SystemError::EIO) } /// 处理 PTRACE_SINGLESTEP 请求 (单步执行) fn handle_single_step(tracee: &Arc) -> Result { // 检查调用者是否是该进程的跟踪器 - if ProcessManager::current_pcb().raw_pid() != tracee.tracer().unwrap() { - // TODO + let tracer_pid = ProcessManager::current_pcb().raw_pid(); + let tracee_tracer = tracee.tracer().ok_or(SystemError::ESRCH)?; + if tracer_pid != tracee_tracer { return Err(SystemError::ESRCH); } // 设置 EFLAGS 的 TF 标志 @@ -501,7 +534,7 @@ impl Syscall for SysPtrace { let data = Self::data(args); let tracer = ProcessManager::current_pcb(); - if request == PtraceRequest::PtraceTraceme { + if request == PtraceRequest::Traceme { return Self::handle_traceme(&tracer).map(|r| r as usize); } let tracee: Arc = @@ -513,30 +546,30 @@ impl Syscall for SysPtrace { }; let result: isize = match request { + // 读取进程内存 + PtraceRequest::Peekdata => Self::handle_peek_data(&tracee, addr)?, + // 读取用户寄存器 + PtraceRequest::Peekuser => Self::handle_peek_user(&tracee, addr)?, + // 写入进程内存 + PtraceRequest::Pokedata => Self::handle_poke_data(&tracee, addr, data)?, + // 继续执行目标进程 + PtraceRequest::Cont | PtraceRequest::Singlestep | PtraceRequest::Syscall => { + tracee.ptrace_resume(request, signal, frame)? + } + // 获取寄存器值 + PtraceRequest::Getregs => Self::handle_get_regs(&tracee, data)?, + // 设置寄存器值 + PtraceRequest::Setregs => Self::handle_set_regs(&tracee, data)?, // 附加到目标进程 - PtraceRequest::PtraceAttach => Self::handle_attach(&tracer, pid)?, - // PTRACE_SEIZE:现代 API,不发送 SIGSTOP - PtraceRequest::PtraceSeize => Self::handle_seize(&tracer, pid, addr)?, + PtraceRequest::Attach => Self::handle_attach(&tracer, pid)?, // 分离目标进程 - PtraceRequest::PtraceDetach => Self::handle_detach(&tracee, signal)?, - // 继续执行目标进程 - PtraceRequest::PtraceCont - | PtraceRequest::PtraceSinglestep - | PtraceRequest::PtraceSyscall => tracee.ptrace_resume(request, signal, frame)?, + PtraceRequest::Detach => Self::handle_detach(&tracee, signal)?, // 设置跟踪选项 - PtraceRequest::PtraceSetoptions => Self::handle_set_options(&tracee, data)?, + PtraceRequest::Setoptions => Self::handle_set_options(&tracee, data)?, // 获取信号信息 - PtraceRequest::PtraceGetsiginfo => Self::handle_get_siginfo(&tracee)?, - // 获取寄存器值 - PtraceRequest::PtraceGetregs => Self::handle_get_regs(&tracee, data)?, - // 设置寄存器值 - PtraceRequest::PtraceSetregs => Self::handle_set_regs(&tracee, data)?, - // 读取用户寄存器 - PtraceRequest::PtracePeekuser => Self::handle_peek_user(&tracee, addr)?, - // 读取进程内存 - PtraceRequest::PtracePeekdata => Self::handle_peek_data(&tracee, addr)?, - // 写入进程内存 - PtraceRequest::PtracePokedata => Self::handle_poke_data(&tracee, addr, data)?, + PtraceRequest::Getsiginfo => Self::handle_get_siginfo(&tracee)?, + // PTRACE_SEIZE:现代 API,不发送 SIGSTOP + PtraceRequest::Seize => Self::handle_seize(&tracer, pid, addr)?, // 其他请求类型 _ => { log::warn!("Unimplemented ptrace request: {:?}", request); From 6e98bf8f40e82cd77959d37836d2b9e78fc39a8d Mon Sep 17 00:00:00 2001 From: aLinChe <1129332011@qq.com> Date: Sun, 11 Jan 2026 23:29:46 +0800 Subject: [PATCH 09/15] pop strace Signed-off-by: aLinChe <1129332011@qq.com> --- user/apps/strace/.gitignore | 1 - user/apps/strace/Makefile | 20 -- user/apps/strace/main.cpp | 106 ------ user/apps/strace/strace_format.h | 504 ----------------------------- user/dadk/config/strace-0.1.0.toml | 40 --- 5 files changed, 671 deletions(-) delete mode 100644 user/apps/strace/.gitignore delete mode 100644 user/apps/strace/Makefile delete mode 100644 user/apps/strace/main.cpp delete mode 100644 user/apps/strace/strace_format.h delete mode 100644 user/dadk/config/strace-0.1.0.toml diff --git a/user/apps/strace/.gitignore b/user/apps/strace/.gitignore deleted file mode 100644 index 9d89263c5..000000000 --- a/user/apps/strace/.gitignore +++ /dev/null @@ -1 +0,0 @@ -strace diff --git a/user/apps/strace/Makefile b/user/apps/strace/Makefile deleted file mode 100644 index 168b35d0a..000000000 --- a/user/apps/strace/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -ifeq ($(ARCH), x86_64) - CROSS_COMPILE=x86_64-linux-musl- -else ifeq ($(ARCH), riscv64) - CROSS_COMPILE=riscv64-linux-musl- -endif - -CC=$(CROSS_COMPILE)g++ - -.PHONY: all -all: main.cpp - $(CC) -static -o strace main.cpp - -.PHONY: install clean -install: all - mv strace $(DADK_CURRENT_BUILD_DIR)/strace - -clean: - rm strace *.o - -fmt: diff --git a/user/apps/strace/main.cpp b/user/apps/strace/main.cpp deleted file mode 100644 index 29c6eeb9a..000000000 --- a/user/apps/strace/main.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "strace_format.h" - -#include -#include -#include -#include - -using namespace std; - -// 追踪子进程 -int trace_child(pid_t child_pid) { - int status; - bool first_stop = true; - int last_syscall = -1; - - while (true) { - // 等待子进程状态变化 - if (waitpid(child_pid, &status, 0) == -1) { - cerr << "waitpid error: " << strerror(errno) << '\n'; - return 1; - } - // 检查子进程是否退出 - if (WIFEXITED(status)) { - cout << "\n+++ exited with " << WEXITSTATUS(status) << " +++" << '\n'; - return 0; - } - // 检查是否收到信号 - if (WIFSIGNALED(status)) { - cout << "\n+++ killed by " << strsignal(WTERMSIG(status)) << " +++" << '\n'; - return 0; - } - // 首次跟踪需要忽略SIGTRAP - if (first_stop && WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) { - first_stop = false; - ptrace(PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACESYSGOOD); - if (ptrace(PTRACE_SYSCALL, child_pid, 0, 0) == -1) { - cerr << "ptrace(SYSCALL) failed: " << strerror(errno) << '\n'; - return 1; - } - continue; - } - - // 处理系统调用入口事件 - if (WIFSTOPPED(status) && WSTOPSIG(status) == (SIGTRAP | 0x80)) { - user_regs_struct regs; - if (ptrace(PTRACE_GETREGS, child_pid, 0, ®s) == -1) { - cerr << "ptrace(GETREGS) failed: " << strerror(errno) << '\n'; - return 1; - } - if (last_syscall == -1) { - // 获取系统调用号 - int syscall_num = static_cast(SYSCALL_REG(regs)); - last_syscall = syscall_num; - cout << format_arguments( - child_pid, syscall_num, ARG1(regs), ARG2(regs), ARG3(regs), ARG4(regs), ARG5(regs), ARG6(regs)); - } else { - long return_value = RETURN_REG(regs); - cout << format_return_value(return_value) << '\n'; - last_syscall = -1; - } - // 继续执行等待系统调用完成 - if (ptrace(PTRACE_SYSCALL, child_pid, 0, 0) == -1) { - cerr << "ptrace(SYSCALL) failed: " << strerror(errno) << '\n'; - return 1; - } - } else if (WIFSTOPPED(status)) { // 处理其他事件 - // 继续执行子进程 - if (ptrace(PTRACE_SYSCALL, child_pid, 0, WSTOPSIG(status)) == -1) { - cerr << "ptrace(SYSCALL) failed: " << strerror(errno) << '\n'; - return 1; - } - } - } - return 0; -} - -int main(int argc, char* argv[]) { - if (argc < 2) { - cerr << "Usage: " << argv[0] << " must have PROG [ARGS] or -p PID" << '\n'; - return 1; - } - - pid_t pid = fork(); - if (pid == -1) { - cerr << "fork failed: " << strerror(errno) << '\n'; - return 1; - } - // 子进程执行目标程序 - if (pid == 0) { - // 启用跟踪 - ptrace(PTRACE_TRACEME, 0, 0, 0); - // 设置execve参数 - vector args; - for (int i = 1; i < argc; ++i) { - args.push_back(argv[i]); - } - args.push_back(nullptr); - // 执行目标程序 - execvp(args[0], args.data()); - // 若exec失败 - cerr << "execvp failed: " << strerror(errno) << '\n'; - return 1; - } else { // 父进程执行跟踪 - return trace_child(pid); - } -} \ No newline at end of file diff --git a/user/apps/strace/strace_format.h b/user/apps/strace/strace_format.h deleted file mode 100644 index 025c776fa..000000000 --- a/user/apps/strace/strace_format.h +++ /dev/null @@ -1,504 +0,0 @@ -#ifndef _STRACE_FORMAT_H_ -#define _STRACE_FORMAT_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// 根据不同架构定义寄存器访问宏 -#if defined(__x86_64__) -#define SYSCALL_REG(regs) (regs.orig_rax) -#define RETURN_REG(regs) (regs.rax) -#define ARG1(regs) (regs.rdi) -#define ARG2(regs) (regs.rsi) -#define ARG3(regs) (regs.rdx) -#define ARG4(regs) (regs.r10) -#define ARG5(regs) (regs.r8) -#define ARG6(regs) (regs.r9) -#elif defined(__i386__) -#define SYSCALL_REG(regs) (regs.orig_eax) -#define RETURN_REG(regs) (regs.eax) -#define ARG1(regs) (regs.ebx) -#define ARG2(regs) (regs.ecx) -#define ARG3(regs) (regs.edx) -#define ARG4(regs) (regs.esi) -#define ARG5(regs) (regs.edi) -#define ARG6(regs) (regs.ebp) -#elif defined(__aarch64__) -#define SYSCALL_REG(regs) (regs.regs[8]) -#define RETURN_REG(regs) (regs.regs[0]) -#define ARG1(regs) (regs.regs[0]) -#define ARG2(regs) (regs.regs[1]) -#define ARG3(regs) (regs.regs[2]) -#define ARG4(regs) (regs.regs[3]) -#define ARG5(regs) (regs.regs[4]) -#define ARG6(regs) (regs.regs[5]) -#else -#error "Unsupported architecture" -#endif - -// 错误码映射 -const std::unordered_map error_names = { - {EPERM, "EPERM"}, {ENOENT, "ENOENT"}, {ESRCH, "ESRCH"}, {EINTR, "EINTR"}, {EIO, "EIO"}, - {ENXIO, "ENXIO"}, {E2BIG, "E2BIG"}, {ENOEXEC, "ENOEXEC"}, {EBADF, "EBADF"}, {ECHILD, "ECHILD"}, - {EAGAIN, "EAGAIN"}, {ENOMEM, "ENOMEM"}, {EACCES, "EACCES"}, {EFAULT, "EFAULT"}, {ENOTBLK, "ENOTBLK"}, - {EBUSY, "EBUSY"}, {EEXIST, "EEXIST"}, {EXDEV, "EXDEV"}, {ENODEV, "ENODEV"}, {ENOTDIR, "ENOTDIR"}, - {EISDIR, "EISDIR"}, {EINVAL, "EINVAL"}, {ENFILE, "ENFILE"}, {EMFILE, "EMFILE"}, {ENOTTY, "ENOTTY"}, - {ETXTBSY, "ETXTBSY"}, {EFBIG, "EFBIG"}, {ENOSPC, "ENOSPC"}, {ESPIPE, "ESPIPE"}, {EROFS, "EROFS"}, - {EMLINK, "EMLINK"}, {EPIPE, "EPIPE"}, {EDOM, "EDOM"}, {ERANGE, "ERANGE"}, -}; - -// 系统调用名称映射 -const std::unordered_map syscall_names = { - {SYS_read, "read"}, - {SYS_write, "write"}, - {SYS_open, "open"}, - {SYS_close, "close"}, - {SYS_stat, "stat"}, - {SYS_fstat, "fstat"}, - {SYS_lstat, "lstat"}, - {SYS_poll, "poll"}, - {SYS_lseek, "lseek"}, - {SYS_mmap, "mmap"}, - {SYS_mprotect, "mprotect"}, - {SYS_munmap, "munmap"}, - {SYS_brk, "brk"}, - {SYS_rt_sigaction, "rt_sigaction"}, - {SYS_ioctl, "ioctl"}, - {SYS_access, "access"}, - {SYS_pipe, "pipe"}, - {SYS_select, "select"}, - {SYS_dup, "dup"}, - {SYS_dup2, "dup2"}, - {SYS_getpid, "getpid"}, - {SYS_socket, "socket"}, - {SYS_connect, "connect"}, - {SYS_bind, "bind"}, - {SYS_listen, "listen"}, - {SYS_accept, "accept"}, - {SYS_execve, "execve"}, - {SYS_exit, "exit"}, - {SYS_wait4, "wait4"}, - {SYS_kill, "kill"}, - {SYS_uname, "uname"}, - {SYS_fcntl, "fcntl"}, - {SYS_fsync, "fsync"}, - {SYS_truncate, "truncate"}, - {SYS_getcwd, "getcwd"}, - {SYS_chdir, "chdir"}, - {SYS_rename, "rename"}, - {SYS_mkdir, "mkdir"}, - {SYS_rmdir, "rmdir"}, - {SYS_creat, "creat"}, - {SYS_link, "link"}, - {SYS_unlink, "unlink"}, - {SYS_readlink, "readlink"}, - {SYS_chmod, "chmod"}, - {SYS_gettimeofday, "gettimeofday"}, - {SYS_getrusage, "getrusage"}, - {SYS_sysinfo, "sysinfo"}, - {SYS_getuid, "getuid"}, - {SYS_getgid, "getgid"}, - {SYS_setuid, "setuid"}, - {SYS_setgid, "setgid"}, - {SYS_geteuid, "geteuid"}, - {SYS_getegid, "getegid"}, - {SYS_setpgid, "setpgid"}, - {SYS_getppid, "getppid"}, - {SYS_arch_prctl, "arch_prctl"}, - {SYS_exit_group, "exit_group"}, - {SYS_openat, "openat"}, - {SYS_newfstatat, "newfstatat"}, - {SYS_unshare, "unshare"}, - {SYS_getrandom, "getrandom"}, -}; - -const std::unordered_map fcntl_flags = { - {FD_CLOEXEC, "FD_CLOEXEC"}, {O_RDONLY, "O_RDONLY"}, {O_WRONLY, "O_WRONLY"}, {O_RDWR, "O_RDWR"}, - {O_CREAT, "O_CREAT"}, {O_EXCL, "O_EXCL"}, {O_NOCTTY, "O_NOCTTY"}, {O_TRUNC, "O_TRUNC"}, - {O_APPEND, "O_APPEND"}, {O_NONBLOCK, "O_NONBLOCK"}, {O_DSYNC, "O_DSYNC"}, {O_ASYNC, "O_ASYNC"}, - {O_DIRECT, "O_DIRECT"}, {O_LARGEFILE, "O_LARGEFILE"}, {O_DIRECTORY, "O_DIRECTORY"}, {O_NOFOLLOW, "O_NOFOLLOW"}, - {O_NOATIME, "O_NOATIME"}, {O_CLOEXEC, "O_CLOEXEC"}, {O_SYNC, "O_SYNC"}, {O_PATH, "O_PATH"}, - {O_TMPFILE, "O_TMPFILE"}, -}; -const std::unordered_map at_flags = { - {AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW"}, - {AT_REMOVEDIR, "AT_REMOVEDIR"}, - {AT_SYMLINK_FOLLOW, "AT_SYMLINK_FOLLOW"}, - {AT_NO_AUTOMOUNT, "AT_NO_AUTOMOUNT"}, - {AT_EMPTY_PATH, "AT_EMPTY_PATH"}, - {AT_STATX_SYNC_TYPE, "AT_STATX_SYNC_TYPE"}, - {AT_STATX_FORCE_SYNC, "AT_STATX_FORCE_SYNC"}, - {AT_STATX_DONT_SYNC, "AT_STATX_DONT_SYNC"}, - {AT_RECURSIVE, "AT_RECURSIVE"}, -}; -const std::unordered_map open_flags = { - {O_RDONLY, "O_RDONLY"}, - {O_WRONLY, "O_WRONLY"}, - {O_RDWR, "O_RDWR"}, - {O_CREAT, "O_CREAT"}, - {O_EXCL, "O_EXCL"}, - {O_TRUNC, "O_TRUNC"}, - {O_APPEND, "O_APPEND"}, - {O_NONBLOCK, "O_NONBLOCK"}, - {O_DIRECTORY, "O_DIRECTORY"}, - {O_NOFOLLOW, "O_NOFOLLOW"}, - {O_CLOEXEC, "O_CLOEXEC"}, - {AT_FDCWD, "AT_FDCWD"}, - {AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW"}, -}; -const std::unordered_map mmap_flags = { - {MAP_SHARED, "MAP_SHARED"}, - {MAP_PRIVATE, "MAP_PRIVATE"}, - {MAP_FIXED, "MAP_FIXED"}, - {MAP_ANONYMOUS, "MAP_ANONYMOUS"}, - {MAP_GROWSDOWN, "MAP_GROWSDOWN"}, - {MAP_DENYWRITE, "MAP_DENYWRITE"}, - {MAP_EXECUTABLE, "MAP_EXECUTABLE"}, - {MAP_LOCKED, "MAP_LOCKED"}, - {MAP_NORESERVE, "MAP_NORESERVE"}, - {MAP_POPULATE, "MAP_POPULATE"}, - {MAP_NONBLOCK, "MAP_NONBLOCK"}, - {MAP_STACK, "MAP_STACK"}, - {MAP_HUGETLB, "MAP_HUGETLB"}, -}; -const std::unordered_map grnd_flags = { - {GRND_NONBLOCK, "GRND_NONBLOCK"}, - {GRND_RANDOM, "GRND_RANDOM"}, -}; - -// 长整型转十六进制字符串 -std::string to_hex_string(unsigned long value) { - std::ostringstream oss; - oss << "0x" << std::hex << value; - return oss.str(); -} -// 从子进程读取字符串 -std::string read_child_string(pid_t pid, unsigned long addr) { - if (addr == 0) - return "NULL"; - std::string str; - long ret; - unsigned long tmp = 0; - - while (true) { - // 使用PTRACE_PEEKDATA读取内存 - errno = 0; - ret = ptrace(PTRACE_PEEKDATA, pid, addr + tmp, nullptr); - if (ret == -1 && errno != 0) { - return ""; - } - - // 逐字节读取,直到遇到空字符 - for (int i = 0; i < sizeof(long); ++i) { - char ch = static_cast((ret >> (i * 8)) & 0xFF); - if (ch == '\0') { - return str; - } - str += ch; - } - tmp += sizeof(long); - } -} -std::string read_child_buffer(pid_t pid, unsigned long addr, size_t len) { - if (addr == 0 || len == 0) - return ""; - - std::string buffer; - long ret; - unsigned long tmp = 0; - const size_t max_length = 256; // 最大读取长度 - - len = std::min(len, max_length); - - for (size_t i = 0; i < len; i += sizeof(long)) { - // 使用PTRACE_PEEKDATA读取内存 - errno = 0; - ret = ptrace(PTRACE_PEEKDATA, pid, addr + tmp, nullptr); - if (ret == -1 && errno != 0) { - return ""; - } - - // 逐字节读取 - for (int j = 0; j < sizeof(long) && (i + j) < len; ++j) { - char ch = static_cast((ret >> (j * 8)) & 0xFF); - buffer += ch; - } - tmp += sizeof(long); - } - return buffer; -} -std::string format_printable_string(const std::string& str) { - std::ostringstream oss; - oss << "\""; - for (char c : str) { - if (c == '\n') - oss << "\\n"; - else if (c == '\t') - oss << "\\t"; - else if (c == '\r') - oss << "\\r"; - else if (c == '\"') - oss << "\\\""; - else if (c == '\\') - oss << "\\\\"; - else if (std::isprint(static_cast(c))) - oss << c; - else - oss << "\\x" << std::hex << std::setw(2) << std::setfill('0') - << static_cast(static_cast(c)); - } - oss << "\""; - return oss.str(); -} -// 从子进程读取字符串数组 -std::vector read_child_string_array(pid_t pid, unsigned long addr) { - std::vector result; - if (addr == 0) - return result; - - unsigned long ptr; - unsigned long tmp = 0; - - while (true) { - // 读取指针值 - errno = 0; - long ret = ptrace(PTRACE_PEEKDATA, pid, addr + tmp, nullptr); - if (ret == -1 && errno != 0) { - break; - } - - ptr = static_cast(ret); - tmp += sizeof(long); - - if (ptr == 0) { - break; // NULL结尾 - } - - result.push_back(read_child_string(pid, ptr)); - } - - return result; -} -// 解析标志位 -std::string parse_flags(const std::unordered_map& flag_map, long flags) { - if (flags == 0) - return "0"; - std::vector flag_list; - for (const auto& flag : flag_map) { - if (flags & flag.first) { - flag_list.push_back(flag.second); - } - } - if (flag_list.empty()) { - return "0x" + to_hex_string(flags); - } - std::ostringstream oss; - for (size_t i = 0; i < flag_list.size(); ++i) { - if (i > 0) - oss << "|"; - oss << flag_list[i]; - } - return oss.str(); -} - -// 格式化参数列表 -std::string -format_arguments(pid_t child_pid, int sys_num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { - // 获取系统调用名称 - std::string syscall_name = "syscall_"; - if (syscall_names.find(sys_num) != syscall_names.end()) { - syscall_name = syscall_names.at(sys_num); - } else { - syscall_name += std::to_string(sys_num); - } - - std::ostringstream oss; - if (sys_num == SYS_execve) { - // 处理execve的特殊格式 - std::string path = read_child_string(child_pid, arg1); - std::vector argv = read_child_string_array(child_pid, arg2); - std::vector envp = read_child_string_array(child_pid, arg3); - - oss << syscall_name << "(\"" << path << "\", ["; - // 格式化argv - for (size_t i = 0; i < argv.size(); ++i) { - if (i > 0) - oss << ", "; - oss << "\"" << argv[i] << "\""; - } - oss << "], "; - // 格式化envp - if (envp.empty()) { - oss << "0x" << std::hex << arg3 << " /* 0 vars */)"; - } else { - oss << "0x" << std::hex << arg3 << " /* " << std::dec << envp.size() << " vars */"; - } - return oss.str(); - } else if (sys_num == SYS_brk) { - oss << syscall_name << "("; - if (arg1 == 0) { - oss << "NULL"; - } else { - oss << to_hex_string(arg1); - } - oss << ")"; - return oss.str(); - } else if (sys_num == SYS_open || sys_num == SYS_openat) { - oss << syscall_name << "("; - if (sys_num == SYS_openat) { - oss << "AT_FDCWD, "; - } - // 读取路径 - oss << "\"" << read_child_string(child_pid, (sys_num == SYS_openat) ? arg2 : arg1) << "\", "; - // 解析标志位 - long flags = (sys_num == SYS_openat) ? arg3 : arg2; - oss << parse_flags(open_flags, flags); - // 文件权限 - if (arg4 != 0) - oss << ", 0" << std::oct << arg4; - return oss.str(); - } else if (sys_num == SYS_write) { - oss << syscall_name << "(" << arg1 << ", "; - std::string buffer = read_child_buffer(child_pid, arg2, arg3); - oss << format_printable_string(buffer) << ", " << arg3 << ")"; - return oss.str(); - } else if (sys_num == SYS_read) { - oss << syscall_name << "(" << arg1 << ", "; - std::string buffer = read_child_buffer(child_pid, arg2, arg3); - oss << format_printable_string(buffer) << ", " << arg3 << ")"; - return oss.str(); - } else if (sys_num == SYS_dup || sys_num == SYS_dup2 || sys_num == SYS_dup3) { - oss << syscall_name << "(" << arg1; - if (sys_num == SYS_dup2 || sys_num == SYS_dup3) - oss << ", " << arg2; - if (sys_num == SYS_dup3) - oss << ", " << parse_flags(fcntl_flags, arg3); - oss << ")"; - return oss.str(); - } else if (sys_num == SYS_newfstatat) { - oss << syscall_name << "("; - // 文件描述符 - if (arg1 == AT_FDCWD) { - oss << "AT_FDCWD"; - } else { - oss << arg1; - } - oss << ", \"" << read_child_string(child_pid, arg2) << "\""; - // stat结构体指针 - oss << ", " << to_hex_string(arg3); - oss << ", " << parse_flags(at_flags, arg4); - oss << ")"; - return oss.str(); - } else if (sys_num == SYS_mmap) { - oss << syscall_name << "(" << to_hex_string(arg1) << ", " << std::dec << arg2 << ", " - << parse_flags(mmap_flags, arg3) << ", " << parse_flags(mmap_flags, arg4) << ", " << arg5 << ", " - << to_hex_string(arg6) << ")"; - return oss.str(); - } else if (sys_num == SYS_arch_prctl) { - oss << syscall_name << "(" << to_hex_string(arg1) << ", " << to_hex_string(arg2) << ")"; - return oss.str(); - } else if (sys_num == SYS_fcntl) { - std::ostringstream oss; - oss << syscall_name << "(" << arg1 << ", "; - if (fcntl_flags.count(static_cast(arg2))) { - oss << fcntl_flags.at(static_cast(arg2)); - } else { - oss << to_hex_string(arg2); - } - // 如果有第三个参数 - if (arg3 != 0) { - oss << ", "; - switch (static_cast(arg2)) { - case F_SETFL: - case F_GETFL: - oss << parse_flags(fcntl_flags, arg3); - break; - default: - oss << to_hex_string(arg3); - } - } - - oss << ")"; - return oss.str(); - } else if (sys_num == SYS_uname) { - // const size_t utsname_size = sizeof(struct utsname); - // const size_t words = (utsname_size + sizeof(long) - 1) / sizeof(long); - // // 分配缓冲区 - // char* buf = new char[words * sizeof(long)](); - // unsigned long addr = arg1; - // // 逐字读取子进程内存 - // for (size_t i = 0; i < words; ++i) { - // errno = 0; - // long ret = ptrace(PTRACE_PEEKDATA, child_pid, addr + i * sizeof(long), nullptr); - // if (ret == -1 && errno != 0) { - // delete[] buf; - // return syscall_name + "(" + to_hex_string(arg1) + ")"; - // } - // memcpy(buf + i * sizeof(long), &ret, sizeof(long)); - // } - // struct utsname* uname_buf = reinterpret_cast(buf); - struct utsname parent_uname; - uname(&parent_uname); - oss << syscall_name << "({"; - oss << "sysname=\"" << parent_uname.sysname << "\", "; - oss << "nodename=\"" << parent_uname.nodename << "\", "; - oss << "release=\"" << parent_uname.release << "\", "; - oss << "version=\"" << parent_uname.version << "\", "; - oss << "machine=\"" << parent_uname.machine << "\""; - oss << "})"; - // delete[] buf; - return oss.str(); - } else if (sys_num == SYS_getrandom) { - oss << syscall_name << "(" << to_hex_string(arg1) << ", " << arg2 << ", " << parse_flags(grnd_flags, arg3) - << ")"; - return oss.str(); - } else if (sys_num == SYS_access) { - return syscall_name + "(\"" + read_child_string(child_pid, arg1) + "\", " + to_hex_string(arg2) + ")"; - } else if (sys_num == SYS_exit || sys_num == SYS_exit_group || sys_num == SYS_close) { - return syscall_name + "(" + std::to_string(arg1) + ")"; - } else { - // 其他系统调用通用处理 - oss << syscall_name << "(" << to_hex_string(arg1); - if (arg2 != 0) - oss << ", " << to_hex_string(arg2); - if (arg3 != 0) - oss << ", " << to_hex_string(arg3); - if (arg4 != 0) - oss << ", " << to_hex_string(arg4); - if (arg5 != 0) - oss << ", " << to_hex_string(arg5); - if (arg6 != 0) - oss << ", " << to_hex_string(arg6); - oss << ")"; - return oss.str(); - } -} -// 格式化返回值 -std::string format_return_value(long ret_val) { - if (ret_val < 0) { - int err = static_cast(-ret_val); - if (error_names.find(err) != error_names.end()) { - return " = -1 " + error_names.at(err) + " (" + strerror(err) + ")"; - } else { - return " = -1 (unknown error)"; - } - } - - return " = " + to_hex_string(ret_val); -} - -#endif // _STRACE_FORMAT_H_ \ No newline at end of file diff --git a/user/dadk/config/strace-0.1.0.toml b/user/dadk/config/strace-0.1.0.toml deleted file mode 100644 index adaf03cdd..000000000 --- a/user/dadk/config/strace-0.1.0.toml +++ /dev/null @@ -1,40 +0,0 @@ -# 用户程序名称 -name = "strace" -# 版本号 -version = "0.1.0" -# 用户程序描述信息 -description = "一个简单的strace" -# (可选)默认: false 是否只构建一次,如果为true,DADK会在构建成功后,将构建结果缓存起来,下次构建时,直接使用缓存的构建结果 -build-once = false -# (可选) 默认: false 是否只安装一次,如果为true,DADK会在安装成功后,不再重复安装 -install-once = false -# 目标架构 -# 可选值:"x86_64", "aarch64", "riscv64" -target-arch = ["x86_64"] -# 任务源 -[task-source] -# 构建类型 -# 可选值:"build-from-source", "install-from-prebuilt" -type = "build-from-source" -# 构建来源 -# "build_from_source" 可选值:"git", "local", "archive" -# "install_from_prebuilt" 可选值:"local", "archive" -source = "local" -# 路径或URL -source-path = "user/apps/strace" -# 构建相关信息 -[build] -# (可选)构建命令 -build-command = "make install" -# 安装相关信息 -[install] -# (可选)安装到DragonOS的路径 -in-dragonos-path = "/bin" -# 清除相关信息 -[clean] -# (可选)清除命令 -clean-command = "make clean" -# (可选)依赖项 -# 注意:如果没有依赖项,忽略此项,不允许只留一个[[depends]] -# 环境变量 -# 注意:如果没有环境变量,忽略此项,不允许只留一个[[envs]] From 2cdf54eda3ffc3e5cf29f7a34caef9313fc58982 Mon Sep 17 00:00:00 2001 From: aLinChe <1129332011@qq.com> Date: Tue, 13 Jan 2026 00:00:23 +0800 Subject: [PATCH 10/15] pr review Signed-off-by: aLinChe <1129332011@qq.com> --- kernel/src/arch/x86_64/process/mod.rs | 10 + kernel/src/arch/x86_64/syscall/mod.rs | 20 +- kernel/src/ipc/generic_signal.rs | 12 +- kernel/src/ipc/kill.rs | 6 +- kernel/src/ipc/syscall/sys_tkill.rs | 104 ++-- kernel/src/process/exit.rs | 149 +++++- kernel/src/process/mod.rs | 19 + kernel/src/process/ptrace.rs | 447 ++++++------------ kernel/src/process/syscall/mod.rs | 1 - kernel/src/process/syscall/sys_ptrace.rs | 248 +++++----- kernel/src/process/syscall/sys_tkill.rs | 50 -- .../syscall/gvisor/blocklists/ptrace_test | 3 +- user/apps/tests/syscall/gvisor/whitelist.txt | 1 + 13 files changed, 513 insertions(+), 557 deletions(-) delete mode 100644 kernel/src/process/syscall/sys_tkill.rs diff --git a/kernel/src/arch/x86_64/process/mod.rs b/kernel/src/arch/x86_64/process/mod.rs index 1163e9b75..46e37ecfc 100644 --- a/kernel/src/arch/x86_64/process/mod.rs +++ b/kernel/src/arch/x86_64/process/mod.rs @@ -232,6 +232,16 @@ impl ArchPCBInfo { self.gsbase } + /// 获取 FS 段选择器的值 + pub fn fs(&self) -> u16 { + self.fs.bits() + } + + /// 获取 GS 段选择器的值 + pub fn gs(&self) -> u16 { + self.gs.bits() + } + pub fn cr2_mut(&mut self) -> &mut usize { &mut self.cr2 } diff --git a/kernel/src/arch/x86_64/syscall/mod.rs b/kernel/src/arch/x86_64/syscall/mod.rs index 130744b7a..1ee499551 100644 --- a/kernel/src/arch/x86_64/syscall/mod.rs +++ b/kernel/src/arch/x86_64/syscall/mod.rs @@ -67,9 +67,9 @@ macro_rules! syscall_return { #[no_mangle] pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) { // 系统调用进入时,把系统调用号存入 orig_rax 字段 - // 对应 Linux 6.6.21 的 pt_regs.orig_rax 字段 // 用于恢复被 ptrace 修改的系统调用号 // frame.orig_rax = frame.rax; + // 系统调用进入时,始终开中断 unsafe { CurrentIrqArch::interrupt_enable(); @@ -78,33 +78,17 @@ pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) { mfence(); let pid = ProcessManager::current_pcb().raw_pid(); let show = false; - if show { debug!("syscall: pid: {:?}, num={:?}\n", pid, frame.rax as usize); } let pcb = ProcessManager::current_pcb(); - // 按照 Linux 6.6.21 的同步 ptrace 模型处理系统调用入口 - // 在 syscall_trace_enter() 中调用 ptrace_report_syscall_entry() - // ptrace_report_syscall() -> ptrace_notify() -> ptrace_stop() [同步阻塞] - // - // 参考 Linux 6.6.21 kernel/entry/common.c: - // - 第 50 行:ptrace_report_syscall_entry(regs) -> 同步阻塞 - // - 第 78 行:/* Either of the above might have changed the syscall number */ - // syscall = syscall_get_nr(current, regs); // 重新读取! - // // 注意:必须同时检查 PTRACED 和 TRACE_SYSCALL 标志 - // - PTRACED: 进程正在被跟踪 - // - TRACE_SYSCALL: tracer 已调用 PTRACE_SYSCALL 请求系统调用跟踪 - let needs_syscall_trace = pcb - .flags() - .contains(ProcessFlags::TRACE_SYSCALL); - + let needs_syscall_trace = pcb.flags().contains(ProcessFlags::TRACE_SYSCALL); if needs_syscall_trace { // 设置停止原因 pcb.ptrace_state_mut().stop_reason = PtraceStopReason::SyscallEntry; - // 构造 syscall entry 的 exit_code: 0x80 | SIGTRAP // 0x80 表示 PTRACE_SYSCALL_TRACE (PT_TRACESYSGOOD) let exit_code = 0x80 | Signal::SIGTRAP as usize; diff --git a/kernel/src/ipc/generic_signal.rs b/kernel/src/ipc/generic_signal.rs index 351cfbb4b..c2b20fe78 100644 --- a/kernel/src/ipc/generic_signal.rs +++ b/kernel/src/ipc/generic_signal.rs @@ -423,18 +423,13 @@ fn sig_terminate_dump(sig: Signal) { // TODO 生成 coredump 文件 } -/// 信号默认处理函数——暂停进程 +/// 信号默认处理函数——暂停进程 (SIGSTOP/SIGTSTP/SIGTTIN/SIGTTOU) /// -/// 按照 Linux 6.6.21 kernel/signal.c::get_signal -> do_signal_stop 的语义: -/// - 对于 ptrace 进程:ptrace 拦截发生在 signal 分发之前(ptrace_signal) -/// - 如果执行到这里,说明 tracer 已经允许信号传递给 tracee -/// - 但对于 ptrace 进程,"停止"不进入 TASK_STOPPED,而是由 tracer 控制状态 -/// - 因此这里绝不能再调用 ptrace_stop,否则会造成无限循环 fn sig_stop(sig: Signal) { let pcb = ProcessManager::current_pcb(); // ===== Ptrace 进程的特殊处理 ===== - // 按照 Linux 6.6.21:被 ptrace 的进程不会进入标准的 TASK_STOPPED 状态 + // 被 ptrace 的进程由 tracer 控制其状态(TASK_TRACED),不进入标准的 TASK_STOPPED // 如果执行到这里,说明 ptrace_signal 已经在 do_signal 中处理过该信号 // tracer 决定将信号注入给 tracee,但这不意味着 tracee 要再次停止 // 直接返回,不做任何操作 @@ -447,6 +442,7 @@ fn sig_stop(sig: Signal) { pcb.sighand().flags_insert(SignalFlags::CLD_STOPPED); pcb.sighand().flags_insert(SignalFlags::STOP_STOPPED); + // 切换进程状态为 Stopped 并调度 let guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; ProcessManager::mark_stop(sig).unwrap_or_else(|e| { log::error!( @@ -461,6 +457,7 @@ fn sig_stop(sig: Signal) { // 向父进程报告 SIGCHLD 并唤醒父进程可能阻塞的 wait let pcb = ProcessManager::current_pcb(); if let Some(parent) = pcb.parent_pcb() { + // 检查父进程是否设置了 SA_NOCLDSTOP let should_notify = { let sighand = parent.sighand(); sighand @@ -477,6 +474,7 @@ fn sig_stop(sig: Signal) { } // 唤醒等待在该子进程等待队列上的等待者 pcb.wake_all_waiters(); + // 让出 CPU 进入睡眠 schedule(SchedMode::SM_NONE); } diff --git a/kernel/src/ipc/kill.rs b/kernel/src/ipc/kill.rs index 000040321..0cd3adb55 100644 --- a/kernel/src/ipc/kill.rs +++ b/kernel/src/ipc/kill.rs @@ -1,11 +1,13 @@ -use crate::process::pid::{Pid, PidType}; -use crate::process::{ProcessControlBlock, ProcessManager, RawPid}; use crate::{ arch::ipc::signal::Signal, ipc::{ signal_types::{OriginCode, SigCode, SigInfo, SigType}, syscall::sys_kill::check_signal_permission_pcb_with_sig, }, + process::{ + pid::{Pid, PidType}, + ProcessControlBlock, ProcessManager, RawPid, + }, }; use alloc::sync::Arc; use alloc::vec::Vec; diff --git a/kernel/src/ipc/syscall/sys_tkill.rs b/kernel/src/ipc/syscall/sys_tkill.rs index 4332f5950..3cdb2cafb 100644 --- a/kernel/src/ipc/syscall/sys_tkill.rs +++ b/kernel/src/ipc/syscall/sys_tkill.rs @@ -3,20 +3,14 @@ use alloc::sync::Arc; use alloc::vec::Vec; use core::ffi::c_int; -use crate::arch::interrupt::TrapFrame; -use crate::process::pid::PidType; -use crate::syscall::table::FormattedSyscallParam; -use crate::syscall::table::Syscall; use crate::{ - arch::{ipc::signal::Signal, syscall::nr::SYS_TKILL}, - ipc::signal_types::{OriginCode, SigCode}, - process::{ProcessControlBlock, ProcessManager, RawPid}, + arch::{interrupt::TrapFrame, ipc::signal::Signal, syscall::nr::SYS_TKILL}, + ipc::signal_types::{OriginCode, SigCode, SigInfo, SigType}, + process::{cred::CAPFlags, pid::PidType, ProcessControlBlock, ProcessManager, RawPid}, + syscall::table::{FormattedSyscallParam, Syscall}, }; use system_error::SystemError; -use crate::ipc::signal_types::{SigInfo, SigType}; -use crate::process::cred::CAPFlags; - /// tkill系统调用处理器 pub struct SysTkillHandle; @@ -46,7 +40,7 @@ impl Syscall for SysTkillHandle { return Err(SystemError::EINVAL); } - // 调用通用实现,tgid=0表示不验证线程组 + // 调用通用实现,tgid=0表示不验证线程组 (tkill行为) do_tkill(0, tid, sig) } @@ -79,39 +73,43 @@ pub fn do_tkill(tgid: i32, tid: i32, sig: c_int) -> Result { let target_pcb = ProcessManager::find_task_by_vpid(RawPid::from(tid as usize)).ok_or(SystemError::ESRCH)?; - // 2. 验证线程组归属 (仅当tgid > 0时) + // 2. 验证线程组归属 (tgkill 逻辑) if tgid > 0 { let target_tgid = target_pcb.task_tgid_vnr().ok_or(SystemError::ESRCH)?; - if target_tgid != RawPid::from(tgid as usize) { return Err(SystemError::ESRCH); } } - // 3. 探测模式处理 (sig == 0) + // 3. 信号预处理 + // sig=0 用于探测,不产生实际 Signal 对象 + let signal = if sig == 0 { + Signal::INVALID + } else { + let s = Signal::from(sig); + if s == Signal::INVALID { + return Err(SystemError::EINVAL); + } + s + }; + + // 4. 权限检查 (sig=0 时也必须检查权限) + check_kill_permission(signal, &target_pcb)?; + + // 5. 如果是探测模式,权限检查通过后直接返回 if sig == 0 { return Ok(0); } - // 4. 信号有效性检查 - let signal = Signal::from(sig); - if signal == Signal::INVALID { - return Err(SystemError::EINVAL); - } - - // 5. 权限检查 - check_kill_permission(signal, &target_pcb)?; - // 6. 发送信号 - send_signal_to_thread(signal, target_pcb) + send_signal_tkill(signal, target_pcb) } /// 检查发送信号的权限 /// /// 根据Linux的权限检查规则: -/// 1. 发送者和接收者同用户,或者 -/// 2. 发送者具有CAP_KILL权限 -/// 3. 对于SIGKILL和SIGSTOP,需要更严格的权限检查 +/// 1. 发送者和接收者同用户,或者发送者具有 CAP_KILL 权限 +/// 2. 对于 SIGCONT,规则更宽松:只要是同一 session 即可 /// /// # 参数 /// - `sig`: 要发送的信号 @@ -128,63 +126,57 @@ fn check_kill_permission( let current_cred = current_pcb.cred(); let target_cred = target_pcb.cred(); - // 检查是否具有CAP_KILL权限 + // 检查 CAP_KILL 权限 if current_cred.has_capability(CAPFlags::CAP_KILL) { return Ok(()); } - // 检查是否为同一用户 - if current_cred.euid == target_cred.euid { + // 凭证检查 (kill_ok_by_cred) + // 规则:发送者的 euid/uid 必须匹配目标线程的 suid/uid + if current_cred.euid == target_cred.suid + || current_cred.euid == target_cred.uid + || current_cred.uid == target_cred.suid + || current_cred.uid == target_cred.uid + { return Ok(()); } - // 对于SIGKILL和SIGSTOP,需要更严格的权限检查 - if matches!(sig, Signal::SIGKILL | Signal::SIGSTOP) { - if current_cred.has_capability(CAPFlags::CAP_KILL) { + // 3. SIGCONT 的特殊规则:同一 Session 即可 + if sig == Signal::SIGCONT { + let current_session = current_pcb.task_session(); + let target_session = target_pcb.task_session(); + // 确保双方都在 session 中且 session ID 相同 + if current_session.is_some() && current_session == target_session { return Ok(()); } - return Err(SystemError::EPERM); } - // 其他信号,如果不同用户且没有CAP_KILL权限,则拒绝 Err(SystemError::EPERM) } -/// 向指定线程发送信号 -/// -/// # 参数 -/// - `sig`: 要发送的信号 -/// - `target_pcb`: 目标进程控制块 -/// -/// # 返回值 -/// - `Ok(0)`: 成功 -/// - `Err(SystemError::ESRCH)`: 目标线程在投递过程中退出(竞态容忍) -fn send_signal_to_thread( +/// 发送 tkill 语义的信号 +fn send_signal_tkill( sig: Signal, target_pcb: Arc, ) -> Result { - // 构造SigInfo,使用SI_TKILL语义 let current_pcb = ProcessManager::current_pcb(); let current_tgid = current_pcb.task_tgid_vnr().unwrap_or(RawPid::from(0)); let sender_uid = current_pcb.cred().uid.data() as u32; let mut info = SigInfo::new( sig, - 0, - SigCode::Origin(OriginCode::Tkill), // 使用SI_TKILL语义 + 0, // errno + SigCode::Origin(OriginCode::Tkill), SigType::Kill { - pid: current_tgid, + pid: current_tgid, // 发送者的 TGID uid: sender_uid, }, ); - // 发送信号(tgkill 发送线程级信号,使用 PidType::PID) - let result = sig.send_signal_info_to_pcb(Some(&mut info), target_pcb, PidType::PID); - - // 处理竞态条件:如果目标线程在投递过程中退出,视为成功 - match result { - Err(SystemError::ESRCH) => Ok(0), // 竞态容忍 - other => other.map(|_| 0), + match sig.send_signal_info_to_pcb(Some(&mut info), target_pcb, PidType::PID) { + // 如果目标线程在投递过程中退出,Linux 视为成功(竞态容忍) + Err(SystemError::ESRCH) => Ok(0), + result => result.map(|_| 0), } } diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs index 4b30ac153..deea2dcd6 100644 --- a/kernel/src/process/exit.rs +++ b/kernel/src/process/exit.rs @@ -22,9 +22,13 @@ fn wstatus_to_waitid_status(raw_wstatus: i32) -> i32 { (raw_wstatus >> 8) & 0xff } +/// 获取子进程的 uid,用于填充 siginfo_t +fn get_child_uid(child_pcb: &Arc) -> u32 { + child_pcb.cred().uid.data() as u32 +} + /// 检查子进程的 exit_signal 是否与等待选项匹配 /// -/// 根据 Linux wait 语义(kernel/exit.c:eligible_child): /// - __WALL: 等待所有子进程,忽略 exit_signal /// - 如果子进程被 ptrace:总是可以等待,忽略 exit_signal /// - __WCLONE: 只等待"克隆"子进程(exit_signal != SIGCHLD) @@ -59,11 +63,11 @@ pub struct KernelWaitOption<'a> { } #[derive(Debug, Clone)] -#[allow(dead_code)] pub struct WaitIdInfo { pub pid: RawPid, pub status: i32, pub cause: i32, + pub uid: u32, // 子进程的 uid,用于填充 siginfo_t } impl KernelWaitOption<'_> { @@ -90,14 +94,14 @@ pub fn kernel_wait4( // 构造参数 let mut kwo = KernelWaitOption::new(converter, options); - // 如果调用者没有指定 __WALL 或 __WCLONE,我们自动添加 WEXITED 和 WUNTRACED - // 这样 waitpid() 能够同时等待子进程退出和停止 - if !options.contains(WaitOption::WALL) && !options.contains(WaitOption::WCLONE) { - kwo.options.insert(WaitOption::WEXITED); - kwo.options.insert(WaitOption::WSTOPPED); - } else { - kwo.options.insert(WaitOption::WEXITED); - } + // 根据 Linux 6.6.21 语义: + // - wait4/waitpid 默认只等待 WEXITED(退出的子进程) + // - 只有显式传入 WUNTRACED (WSTOPPED) 时才报告停止的子进程 + // - __WALL 和 __WCLONE 是内部标志,不影响 WEXITED 的默认行为 + // + // 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/exit.c#1744 + kwo.options.insert(WaitOption::WEXITED); + // 注意:绝不在这里默认添加 WSTOPPED! kwo.ret_rusage = rusage_buf; @@ -155,7 +159,7 @@ pub fn kernel_waitid( si._sifields = PosixSiginfoFields { _sigchld: PosixSiginfoSigchld { si_pid: info.pid.data() as i32, - si_uid: 0, + si_uid: info.uid, // 从 WaitIdInfo 获取 uid si_status: info.status, si_utime: 0, si_stime: 0, @@ -332,13 +336,16 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { let wait_res = parent.wait_queue.wait_event_interruptible( || { let rd_childen = parent.children.read(); - if rd_childen.is_empty() { + let rd_ptraced = parent.ptraced_list.read(); + + if rd_childen.is_empty() && rd_ptraced.is_empty() { echild = true; return true; } let mut all_children_exited = true; let mut pid_to_release: Option = None; + // 首先遍历 children 列表(类似 Linux 的 do_wait_thread) for pid in rd_childen.iter() { let pcb = match ProcessManager::find_task_by_vpid(*pid) { Some(p) => p, @@ -368,6 +375,7 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { pid: pcb.task_pid_vnr(), status: stopsig, cause: SigChildCode::Stopped.into(), + uid: get_child_uid(&pcb), }); kwo.ret_status = (stopsig << 8) | 0x7f; if !kwo.options.contains(WaitOption::WNOWAIT) { @@ -389,6 +397,7 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { pid: pcb.task_pid_vnr(), status: stopsig, cause: SigChildCode::Trapped.into(), + uid: get_child_uid(&pcb), }); kwo.ret_status = (stopsig << 8) | 0x7f; scan_result = Some(Ok((*pid).into())); @@ -402,6 +411,7 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { pid: pcb.task_pid_vnr(), status: Signal::SIGCONT as i32, cause: SigChildCode::Continued.into(), + uid: get_child_uid(&pcb), }); kwo.ret_status = 0xffff; if !kwo.options.contains(WaitOption::WNOWAIT) { @@ -420,6 +430,7 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { pid: pcb.task_pid_vnr(), status: status8, cause: SigChildCode::Exited.into(), + uid: get_child_uid(&pcb), }); tmp_child_pcb = Some(pcb.clone()); if !kwo.options.contains(WaitOption::WNOWAIT) { @@ -432,6 +443,73 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { drop(sched_guard); } drop(rd_childen); + + // 然后遍历 ptraced_list(类似 Linux 的 ptrace_do_wait) + // 被 ptrace 的进程不在 children 列表中,但可以被 tracer wait + if scan_result.is_none() { + for pid in rd_ptraced.iter() { + if scan_result.is_some() { + break; + } + let pcb = match ProcessManager::find_task_by_vpid(*pid) { + Some(p) => p, + None => continue, + }; + + // ptrace 的子进程总是可以被 wait,不需要检查 is_eligible_child + if !child_matches_wait_options(&pcb, kwo.options) { + continue; + } + + let sched_guard = pcb.sched_info().inner_lock_read_irqsave(); + let state = sched_guard.state(); + if !state.is_exited() { + all_children_exited = false; + } + + if matches!(state, ProcessState::TracedStopped(_)) { + // TracedStopped 状态总是报告给 tracer + let stopsig = if let ProcessState::TracedStopped(sig) = state { + (sig & 0x7f) as i32 + } else { + Signal::SIGSTOP as i32 + }; + kwo.no_task_error = None; + kwo.ret_info = Some(WaitIdInfo { + pid: pcb.task_pid_vnr(), + status: stopsig, + cause: SigChildCode::Trapped.into(), + uid: get_child_uid(&pcb), + }); + kwo.ret_status = (stopsig << 8) | 0x7f; + scan_result = Some(Ok((*pid).into())); + drop(sched_guard); + break; + } else if state.is_exited() + && kwo.options.contains(WaitOption::WEXITED) + { + let raw = state.exit_code().unwrap() as i32; + kwo.ret_status = raw; + let status8 = wstatus_to_waitid_status(raw); + kwo.no_task_error = None; + kwo.ret_info = Some(WaitIdInfo { + pid: pcb.task_pid_vnr(), + status: status8, + cause: SigChildCode::Exited.into(), + uid: get_child_uid(&pcb), + }); + tmp_child_pcb = Some(pcb.clone()); + if !kwo.options.contains(WaitOption::WNOWAIT) { + pid_to_release = Some(pcb.raw_pid()); + } + scan_result = Some(Ok((*pid).into())); + drop(sched_guard); + break; + } + drop(sched_guard); + } + } + if let Some(pid) = pid_to_release { unsafe { ProcessManager::release(pid) }; } @@ -531,6 +609,7 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { pid: pcb.task_pid_vnr(), status: stopsig, cause: SigChildCode::Stopped.into(), + uid: get_child_uid(&pcb), }); kwo.ret_status = (stopsig << 8) | 0x7f; if !kwo.options.contains(WaitOption::WNOWAIT) { @@ -547,6 +626,7 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { pid: pcb.task_pid_vnr(), status: Signal::SIGCONT as i32, cause: SigChildCode::Continued.into(), + uid: get_child_uid(&pcb), }); kwo.ret_status = 0xffff; if !kwo.options.contains(WaitOption::WNOWAIT) { @@ -565,6 +645,7 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { pid: pcb.task_pid_vnr(), status: status8, cause: SigChildCode::Exited.into(), + uid: get_child_uid(&pcb), }); tmp_child_pcb = Some(pcb.clone()); if !kwo.options.contains(WaitOption::WNOWAIT) { @@ -656,12 +737,22 @@ fn do_waitpid( pid: child_pcb.task_pid_vnr(), status: Signal::SIGCONT as i32, cause: SigChildCode::Continued.into(), + uid: get_child_uid(&child_pcb), }); // 设置 ret_status 供 wait4 使用 // Linux wait(2) 语义:continued 进程的 wstatus = 0xffff kwo.ret_status = 0xffff; + // 获取 rusage(如果提供了 rusage 缓冲区) + // 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/exit.c#1358 + if let Some(rusage) = kwo.ret_rusage.as_mut() { + if let Some(child_rusage) = child_pcb.get_rusage(super::resource::RUsageWho::RUsageSelf) + { + **rusage = child_rusage; + } + } + if !kwo.options.contains(WaitOption::WNOWAIT) { child_pcb.sighand().flags_remove(SignalFlags::CLD_CONTINUED); } @@ -722,8 +813,19 @@ fn do_waitpid( pid: child_pcb.task_pid_vnr(), status: actual_sig as i32, cause: SigChildCode::Stopped.into(), + uid: get_child_uid(&child_pcb), }); + // 获取 rusage(如果提供了 rusage 缓冲区) + // 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/exit.c#1308 + if let Some(rusage) = kwo.ret_rusage.as_mut() { + if let Some(child_rusage) = + child_pcb.get_rusage(super::resource::RUsageWho::RUsageSelf) + { + **rusage = child_rusage; + } + } + return Some(Ok(child_pcb.raw_pid().data())); } ProcessState::TracedStopped(stopsig) => { @@ -745,8 +847,19 @@ fn do_waitpid( pid: child_pcb.task_pid_vnr(), status: actual_sig as i32, cause: SigChildCode::Trapped.into(), + uid: get_child_uid(&child_pcb), }); + // 获取 rusage(如果提供了 rusage 缓冲区) + // 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/exit.c#1308 + if let Some(rusage) = kwo.ret_rusage.as_mut() { + if let Some(child_rusage) = + child_pcb.get_rusage(super::resource::RUsageWho::RUsageSelf) + { + **rusage = child_rusage; + } + } + return Some(Ok(child_pcb.raw_pid().data())); } ProcessState::Exited(status) => { @@ -762,10 +875,22 @@ fn do_waitpid( pid, status: wstatus_to_waitid_status(status as i32), cause: SigChildCode::Exited.into(), + uid: get_child_uid(&child_pcb), }); kwo.ret_status = status as i32; + // 获取 rusage(如果提供了 rusage 缓冲区) + // 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/exit.c#1191 + // 注意:需要在释放进程前获取 rusage + if let Some(rusage) = kwo.ret_rusage.as_mut() { + if let Some(child_rusage) = + child_pcb.get_rusage(super::resource::RUsageWho::RUsageSelf) + { + **rusage = child_rusage; + } + } + // 若指定 WNOWAIT,则只观测不回收 if !kwo.options.contains(WaitOption::WNOWAIT) { unsafe { ProcessManager::release(child_pcb.raw_pid()) }; diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 55f7d12ef..09db7efc0 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -1089,6 +1089,8 @@ pub struct PtraceState { event_message: usize, /// tracer 注入的信号(在 ptrace_stop 返回后要处理的信号) injected_signal: Signal, + /// 最后一次 ptrace 停止时的 siginfo(供 PTRACE_GETSIGINFO 读取) + last_siginfo: Option, } impl Default for PtraceState { @@ -1101,6 +1103,7 @@ impl Default for PtraceState { exit_code: 0, event_message: 0, injected_signal: Signal::INVALID, + last_siginfo: None, } } } @@ -1114,6 +1117,7 @@ impl PtraceState { exit_code: 0, event_message: 0, injected_signal: Signal::INVALID, + last_siginfo: None, } } @@ -1142,6 +1146,21 @@ impl PtraceState { Some(self.pending_signals.remove(0)) } } + + /// 获取 last_siginfo(供 PTRACE_GETSIGINFO 使用) + pub fn last_siginfo(&self) -> Option { + self.last_siginfo + } + + /// 设置 last_siginfo + pub fn set_last_siginfo(&mut self, info: crate::ipc::signal_types::SigInfo) { + self.last_siginfo = Some(info); + } + + /// 清除 last_siginfo + pub fn clear_last_siginfo(&mut self) { + self.last_siginfo = None; + } } #[derive(Debug, Default)] diff --git a/kernel/src/process/ptrace.rs b/kernel/src/process/ptrace.rs index 86bd2a26e..815831c73 100644 --- a/kernel/src/process/ptrace.rs +++ b/kernel/src/process/ptrace.rs @@ -4,6 +4,7 @@ use crate::arch::kprobe; use crate::ipc::signal_types::{ ChldCode, OriginCode, SigChldInfo, SigCode, SigFaultInfo, SigInfo, SigType, TrapCode, }; +use crate::process::cred; use crate::process::{ pid::PidType, ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState, PtraceEvent, PtraceOptions, PtraceRequest, PtraceStopReason, PtraceSyscallInfo, PtraceSyscallInfoData, @@ -31,6 +32,7 @@ pub fn ptrace_signal( if signr == 0 { return None; // 丢弃原始信号,继续处理下一个信号(如果没有,则继续执行) } + // 将注入的信号转换为 Signal 类型 let injected_signal = Signal::from(signr); if injected_signal == Signal::INVALID { @@ -88,76 +90,6 @@ pub fn ptrace_signal( Some(injected_signal) } -#[allow(dead_code)] -pub fn do_notify_parent(child: &ProcessControlBlock, signal: Signal) -> Result { - let parent = match child.parent_pcb() { - Some(p) => p, - None => { - // 父进程已经退出,子进程已被 `init` 收养 - return Err(SystemError::ESRCH); - } - }; - // debug_assert!(!child.is_stopped_or_traced()); - // todo WARN_ON_ONCE(!tsk->ptrace && (tsk->group_leader != tsk || !thread_group_empty(tsk))); - let mut autoreap = false; - let mut effective_signal = Some(signal); - // 检查父进程的信号处理方式以确定是否自动回收 - { - let sighand_lock = parent.sighand(); - let sa = sighand_lock.handler(Signal::SIGCHLD); - // 这里简化了 !ptrace 的检查 - if signal == Signal::SIGCHLD { - if sa.map(|s| s.action().is_ignore()).unwrap_or(true) { - // 父进程忽略 SIGCHLD,子进程应被自动回收 - autoreap = true; - // 并且不发送信号 - effective_signal = None; - } else if sa - .map(|s| s.flags().contains(SigFlags::SA_NOCLDWAIT)) - .unwrap_or(true) - { - // 父进程不等待子进程,子进程应被自动回收 - autoreap = true; - // 但根据POSIX,信号仍然可以发送 - } - } - } - if let Some(sig) = effective_signal { - let mut info = SigInfo::new( - sig, - 0, - SigCode::Origin(OriginCode::Kernel), - SigType::SigChld(SigChldInfo { - pid: child.task_pid_vnr(), - uid: child.cred().uid.data(), - status: 0, // todo - utime: 0, // 可以根据需要填充实际值 - stime: 0, // 可以根据需要填充实际值 - }), - ); - sig.send_signal_info_to_pcb(Some(&mut info), parent, PidType::TGID)?; - } - // 因为即使父进程忽略信号,也可能在 wait() 中阻塞,需要被唤醒以返回 -ECHILD - child.wake_up_parent(None); - Ok(autoreap) -} - -#[allow(dead_code)] -pub fn handle_ptrace_signal_stop(current_pcb: &Arc, sig: Signal) { - let mut ptrace_state = current_pcb.ptrace_state.lock(); - ptrace_state.stop_reason = PtraceStopReason::Signal(sig); - ptrace_state.exit_code = sig as usize; - drop(ptrace_state); - - let mut info = SigInfo::new( - sig, - 0, - SigCode::Origin(OriginCode::Kernel), - SigType::SigFault(SigFaultInfo { addr: 0, trapno: 0 }), - ); - current_pcb.ptrace_stop(sig as usize, ChldCode::Stopped, Some(&mut info)); -} - impl ProcessControlBlock { /// 设置ptrace跟踪器 pub fn set_tracer(&self, tracer: RawPid) -> Result<(), SystemError> { @@ -201,30 +133,7 @@ impl ProcessControlBlock { sched_info.set_state(state); } - /// 获取原始父进程 PID(非跟踪器) - pub fn real_parent_pid(&self) -> Option { - // 这里需要根据您的实际实现返回原始父进程 PID - // 假设有一个字段存储原始父进程 - self.parent_pcb().map(|p| p.raw_pid()) - } - - /// 获取父进程 PID(确保总是返回有效值) - pub fn parent_pid(&self) -> RawPid { - // 1. 尝试从直接父进程引用获取 - if let Some(tracer) = self.tracer() { - return tracer; - } - if let Some(parent) = self.parent_pcb() { - return parent.raw_pid(); - } - // // 2. 尝试从进程基本信息中的 ppid 字段获取 - // if self.basic().ppid != Pid(0) { - // return Pid::new(self.basic().ppid.data() as u32); - // } - // // 3. 如果都没有,则返回 init 进程的 PID (1) - self.raw_pid() - } - + /// 设置父进程(用于 ptrace_link 和 ptrace_unlink) pub fn set_parent(&self, new_parent: &Arc) -> Result<(), SystemError> { if new_parent.raw_pid() == self.raw_pid() { return Err(SystemError::EINVAL); @@ -248,14 +157,6 @@ impl ProcessControlBlock { info.sig_pending.signal_mut().insert(signal.into()); } - /// 唤醒父进程的等待队列 - #[allow(dead_code)] - fn wake_up_parent(&self, state: Option) { - if let Some(parent) = self.parent_pcb() { - parent.wait_queue.wakeup(state); - } - } - /// 通知父进程(调试器)发送 SIGTRAP 信号并设置适当的退出代码。 pub fn ptrace_notify(exit_code: usize) -> Result<(), SystemError> { let current_pcb = ProcessManager::current_pcb(); @@ -269,25 +170,26 @@ impl ProcessControlBlock { result } - /// 发送信号并通知父进程 fn ptrace_do_notify( signal: Signal, exit_code: usize, - _reason: Option, // todo + _reason: Option, ) -> Result<(), SystemError> { - let current_pcb: Arc = ProcessManager::current_pcb(); - // current_pcb.set_exit_code(exit_code); + let current_pcb = ProcessManager::current_pcb(); + + let fault_info = SigFaultInfo { + addr: 0, + trapno: exit_code as i32, // si_code = exit_code (通过 trapno) + }; + let mut info = SigInfo::new( - signal, - 0, - SigCode::Origin(OriginCode::Kernel), - SigType::SigChld(SigChldInfo { + signal, // si_signo = SIGTRAP + 0, // si_errno = 0 + SigCode::SigFault(fault_info), + SigType::Kill { pid: current_pcb.raw_pid(), - uid: current_pcb.cred().uid.data(), - status: exit_code as i32, - utime: 0, // 可以根据需要填充实际值 - stime: 0, // 可以根据需要填充实际值 - }), + uid: current_pcb.cred().uid.data() as u32, + }, ); current_pcb.ptrace_stop(exit_code, ChldCode::Trapped, Some(&mut info)); Ok(()) @@ -295,15 +197,13 @@ impl ProcessControlBlock { /// ptrace 事件通知 /// - /// 按照 Linux 6.6.21 的 ptrace_event 实现: - /// - 如果事件被启用(通过 PTRACE_O_TRACEEXEC 等选项),调用 ptrace_stop 阻塞进程 + /// - 如果事件被启用(通过 PTRACE_O_TRACEEXEC 等选项),调用 ptrace_event 阻塞进程 /// - 进程保持 TracedStopped 状态,直到 tracer 唤醒它 /// - 不应该手动设置 Runnable 状态,这由 ptrace_resume 处理 /// /// Legacy Exec 行为(PTRACE_SEIZE): /// - 如果进程是通过 PTRACE_SEIZE 附加的(PT_SEIZED 标志已设置), /// 且没有设置 PTRACE_O_TRACEEXEC,则不发送 Legacy SIGTRAP - /// - 这避免了现代调试器(如 rr、新版 GDB)收到意料之外的信号 pub fn ptrace_event(&self, event: PtraceEvent, message: usize) { // 检查是否启用了该事件的追踪 if unlikely(self.ptrace_event_enabled(event)) { @@ -311,17 +211,14 @@ impl ProcessControlBlock { // ptrace_notify 会调用 ptrace_stop,阻塞进程直到 tracer 唤醒 let exit_code = (event as usize) << 8 | Signal::SIGTRAP as usize; let _ = Self::ptrace_notify(exit_code); - // 注意:这里不设置 Runnable! // ptrace_stop 内部会调用 schedule() 阻塞 // 当 tracer 调用 PTRACE_CONT 时,ptrace_resume 会设置 Runnable } else if event == PtraceEvent::Exec { // Legacy Exec 行为:只有在非 PTRACE_SEIZE 时才发送自动 SIGTRAP - // 这符合 Linux 6.6.21 的逻辑: // - PTRACE_ATTACH:发送 Legacy SIGTRAP // - PTRACE_SEIZE:不发送 Legacy SIGTRAP(除非显式设置 PTRACE_O_TRACEEXEC) - let is_seized = self.flags().contains(ProcessFlags::PT_SEIZED); - - if !is_seized { + let flags = self.flags(); + if flags.contains(ProcessFlags::PTRACED) && !flags.contains(ProcessFlags::PT_SEIZED) { // 非 PTRACE_SEIZE:发送 Legacy SIGTRAP let sig = Signal::SIGTRAP; let mut info = SigInfo::new( @@ -330,21 +227,17 @@ impl ProcessControlBlock { SigCode::Origin(OriginCode::Kernel), SigType::SigFault(SigFaultInfo { addr: 0, trapno: 0 }), ); - // 按照 Linux 6.6:如果 self_ref 升级失败,说明进程正在销毁 - // 此时发送信号没有意义,安全地跳过 + // 如果 self_ref 升级失败,说明进程正在销毁,此时发送信号没有意义,安全地跳过 if let Some(strong_ref) = self.self_ref.upgrade() { let _ = sig.send_signal_info_to_pcb(Some(&mut info), strong_ref, PidType::PID); } } - // PTRACE_SEIZE:不发送信号,静默返回 + // 未PTRACED或PTRACE_SEIZE:不发送信号,静默返回 } - // 移除了错误的 set_state(Runnable) 调用 - // ptrace_stop 已经正确处理了状态管理 } /// 检查是否启用了指定的 ptrace 事件选项 /// - /// 按照 Linux 6.6.21 的 ptrace_event_enabled 实现: /// - 检查 PTRACE_O_TRACEEXEC 等选项是否被设置 /// - 返回 true 表示 tracer 想要接收该事件的通知 pub fn ptrace_event_enabled(&self, event: PtraceEvent) -> bool { @@ -366,33 +259,31 @@ impl ProcessControlBlock { /// 设置进程为停止状态 /// - /// 按照 Linux 6.6.21 的 ptrace_stop 实现: /// - 设置状态为 TracedStopped (类似 TASK_TRACED) + /// - 存储 last_siginfo(供 PTRACE_GETSIGINFO 读取) /// - 调用 schedule() 让出 CPU,调度器会自动将任务从运行队列移除 - /// - 不需要手动 deactivate_task,这会引入竞态条件 pub fn ptrace_stop( &self, exit_code: usize, why: ChldCode, - _info: Option<&mut SigInfo>, + info: Option<&mut SigInfo>, ) -> usize { // 设置 TRAPPING 标志,表示正在停止 self.flags().insert(ProcessFlags::TRAPPING); - - // 使用 TracedStopped 状态(类似于 Linux 的 TASK_TRACED) let mut sched_info = self.sched_info.inner_lock_write_irqsave(); sched_info.set_state(ProcessState::TracedStopped(exit_code)); sched_info.set_sleep(); drop(sched_info); - // 注意:不再设置 PTRACED 标志,因为: - // 1. PTRACE_TRACEME/ATTACH 时已经设置 - // 2. 在 ptrace_stop 中设置会导致语义偏差 - // 清除 ptrace_state 中的 event_message self.ptrace_state.lock().event_message = 0; - // 通知跟踪器 - 必须在 schedule() 之前调用! + // 存储 last_siginfo + if let Some(info) = info { + self.ptrace_state.lock().set_last_siginfo(*info); + } + + // 通知跟踪器 if let Some(tracer) = self.parent_pcb() { self.notify_tracer(&tracer, why); } @@ -400,11 +291,6 @@ impl ProcessControlBlock { // 清除 TRAPPING 标志,表示已经完成停止准备工作 self.flags().remove(ProcessFlags::TRAPPING); - // 按照 Linux 6.6.21 语义: - // 不需要手动从运行队列中移除任务 - // schedule() 内部会检查 state,如果不是 Runnable,调度器会自动处理 - // 手动 deactivate_task 会引入竞态条件(如果在 deactivate 后、schedule 前有唤醒请求) - schedule(SchedMode::SM_NONE); // 从 schedule() 返回后,tracer 已经通过 ptrace_resume 唤醒了我们 @@ -412,7 +298,6 @@ impl ProcessControlBlock { let mut ptrace_state = self.ptrace_state.lock(); let injected_signal = ptrace_state.injected_signal; - // 按照 Linux 6.6.21 的 get_signal/ptrace_stop 语义: // 如果注入的信号是 INVALID,返回 0,表示没有注入信号 let result = if injected_signal == Signal::INVALID { 0 @@ -432,22 +317,6 @@ impl ProcessControlBlock { _ => Signal::SIGCONT as i32, }; - // 按照 Linux 6.6.21 语义: - // 对于 ptrace_stop,构建的 SigInfo 应该是 SIGTRAP 类型 - // 使用 TRAP_BRKPT (1) 作为默认 trapno,表示 ptrace 触发的停止 - let _sigtrap_info = SigFaultInfo { - addr: 0, - trapno: TrapCode::Brkpt as i32, - }; - - // 构造 SIGTRAP siginfo 供调试器通过 PTRACE_GETSIGINFO 读取 - let _info = SigInfo::new( - Signal::SIGTRAP, - TrapCode::Brkpt as i32, - SigCode::SigFault(_sigtrap_info), - SigType::SigFault(_sigtrap_info), - ); - // 发送 SIGCHLD 通知父进程(tracer) // 这与 tracee 内部的 SIGTRAP siginfo 是分离的 let mut chld_info = SigInfo::new( @@ -466,8 +335,10 @@ impl ProcessControlBlock { let should_send = { let tracer_sighand = tracer.sighand(); let sa = tracer_sighand.handler(Signal::SIGCHLD); + let force_send = why == ChldCode::Trapped; if let Some(sa) = sa { - !sa.action().is_ignore() && !sa.flags().contains(SigFlags::SA_NOCLDSTOP) + !sa.action().is_ignore() + && (force_send || !sa.flags().contains(SigFlags::SA_NOCLDSTOP)) } else { false } @@ -485,22 +356,33 @@ impl ProcessControlBlock { .wakeup(Some(ProcessState::TracedStopped(status as usize))); } - /// 检查进程是否可以被指定进程跟踪 - pub fn has_permission_to_trace(&self, _tracee: &Self) -> bool { - // // 1. 超级用户可以跟踪任何进程 + /// 检查当前进程是否有权限跟踪目标进程 + pub fn has_permission_to_trace(&self, tracee: &Self) -> bool { + // 1. 超级用户可以跟踪任何进程 // if self.is_superuser() { // return true; // } - // // 2. 检查是否拥有CAP_SYS_PTRACE权限 - // if self.cred().has_cap(Capability::CAP_SYS_PTRACE) { - // return true; - // } - // // 3. 检查用户ID是否相同 - // if self.basic().uid() == tracee.basic().uid() { - // return true; - // } - // false - true + + // 2. 同一线程组允许访问(自省) + if self.raw_tgid() == tracee.raw_tgid() { + return true; + } + + // 3. 检查UID、GID是否完全匹配 (euid/suid/uid、gid 都要相同) + let caller_cred = self.cred(); + let tracee_cred = tracee.cred(); + let uid_match = caller_cred.uid == tracee_cred.euid + && caller_cred.uid == tracee_cred.suid + && caller_cred.uid == tracee_cred.uid; + let gid_match = caller_cred.gid == tracee_cred.egid + && caller_cred.gid == tracee_cred.sgid + && caller_cred.gid == tracee_cred.gid; + if uid_match && gid_match && tracee.dumpable() != 0 { + return true; + } + + // 4. 检查CAP_SYS_PTRACE权限 + caller_cred.has_capability(cred::CAPFlags::CAP_SYS_PTRACE) } pub fn ptrace_link(&self, tracer: &Arc) -> Result<(), SystemError> { @@ -510,55 +392,84 @@ impl ProcessControlBlock { self.set_tracer(tracer.raw_pid())?; self.set_parent(tracer)?; - *self.cred.lock() = tracer.cred().clone(); + + // 如果 root 进程 attach 一个普通用户进程,该进程必须保持原有权限。 + tracer.ptraced_list.write_irqsave().push(self.raw_pid()); Ok(()) } + /// 解除 ptrace 跟踪关系 pub fn ptrace_unlink(&self) -> Result<(), SystemError> { // 确保当前进程确实被跟踪 if !self.is_traced() { return Err(SystemError::EINVAL); } - // 清除系统调用跟踪相关工作 - // self.clear_syscall_trace_work(); - // 恢复父进程为真实父进程 - let real_parent = self.real_parent_pcb().ok_or(SystemError::ESRCH)?; - self.set_parent(&real_parent)?; - // 从跟踪器的跟踪列表中移除当前进程 - // let mut ptrace_list = tracer.ptraced_list.write(); - // if let Some(pos) = ptrace_list.iter().position(|&pid| pid == self.raw_pid()) { - // ptrace_list.remove(pos); - // } - // 清理凭证信息 - { - let _cred = self.cred.lock(); - // todo *cred = self.original_cred().clone(); - } - // 获取信号锁保护信号相关操作 - let sighand_lock = self.sighand(); + + // 1. 从跟踪器的跟踪列表中移除当前进程 + if let Some(tracer) = self.parent_pcb() { + tracer + .ptraced_list + .write_irqsave() + .retain(|&pid| pid != self.raw_pid()); + } + + // 2. 恢复父进程为真实父进程 + // 如果 real_parent 已退出,则过继给 init 进程(pid=1) + let new_parent = self + .real_parent_pcb() + .or_else(|| ProcessManager::find_task_by_vpid(RawPid(1))) + .ok_or(SystemError::ESRCH)?; + self.set_parent(&new_parent)?; + + // 获取信号锁 + let _sighand_lock = self.sighand(); + // 3. 清除 ptrace 标志和 tracer self.clear_tracer(); - self.flags() - .remove(ProcessFlags::PTRACED | ProcessFlags::TRACE_SYSCALL); - // 清除所有挂起的陷阱和TRAPPING状态 - // self.clear_jobctl_pending(JobCtl::TRAP_MASK); // 假设有JobCtl枚举和clear_jobctl_pending方法 - // self.clear_jobctl_trapping(); // 假设有clear_jobctl_trapping方法 - // 如果进程没有退出且有停止信号或组停止计数,重新设置停止挂起标志 - // if !self.is_exiting() - // && (self.signal_flags().contains(SignalFlags::STOP_STOPPED) - // || self.group_stop_count() > 0) - // { - // self.set_jobctl_pending(JobCtl::STOP_PENDING); - // // 如果没有设置停止信号掩码,默认使用SIGSTOP - // if !self.jobctl().contains(JobCtl::STOP_SIGMASK) { - // self.set_jobctl_pending(JobCtl::from_signal(Signal::SIGSTOP)); // 假设有from_signal方法 - // } - // } - // 如果有停止挂起或任务处于被跟踪状态,唤醒进程 - // if self.jobctl().contains(JobCtl::STOP_PENDING) || self.is_traced() { - // self.ptrace_signal_wake_up(true); // 假设有ptrace_signal_wake_up方法 - // } - drop(sighand_lock); + + // 4. 清除 TRAPPING 标志:表示正在停止的同步标志 + self.flags().remove(ProcessFlags::TRAPPING); + + // 5. 检查进程是否需要进入停止状态 + // Linux: 如果组停止有效且子进程未退出,则重新设置 JOBCTL_STOP_PENDING + let is_exiting = self.flags().contains(ProcessFlags::EXITING); + if !is_exiting { + // 获取当前调度状态 + let mut sched_info = self.sched_info.inner_lock_write_irqsave(); + let current_state = sched_info.state(); + + match current_state { + // 如果进程处于 TracedStopped 状态 + ProcessState::TracedStopped(_exit_code) => { + // Linux 逻辑:如果 detach 时进程处于 TRACED 状态 + // 需要唤醒它,让它从 ptrace_stop 中返回 + // 唤醒后,进程会根据 injected_signal 决定后续行为 + sched_info.set_state(ProcessState::Runnable); + sched_info.set_wakeup(); + drop(sched_info); + + // 加入运行队列,确保进程能被调度 + if let Some(strong_ref) = self.self_ref.upgrade() { + let rq = crate::sched::cpu_rq( + self.sched_info() + .on_cpu() + .unwrap_or(crate::smp::core::smp_get_processor_id()) + .data() as usize, + ); + let (rq, _guard) = rq.self_lock(); + rq.update_rq_clock(); + rq.activate_task( + &strong_ref, + EnqueueFlag::ENQUEUE_WAKEUP | EnqueueFlag::ENQUEUE_NOCLOCK, + ); + } + } + _ => { + // 其他状态,清除 TRAPPING 标志即可 + drop(sched_info); + } + } + } Ok(()) } @@ -570,11 +481,6 @@ impl ProcessControlBlock { let parent = self.real_parent_pcb().ok_or(SystemError::ESRCH)?; self.flags().insert(ProcessFlags::PTRACED); self.ptrace_link(&parent)?; - - // 注意:不要修改 exit_signal! - // exit_signal 是用来表示进程退出时发送给父进程的信号(通常是 SIGCHLD) - // ptrace 注入的信号应该存储在 ptrace_state.injected_signal 中 - Ok(0) } @@ -594,9 +500,8 @@ impl ProcessControlBlock { self.flags().insert(ProcessFlags::PTRACED); self.ptrace_link(tracer)?; + // ptrace_attach 发送 SIGSTOP 作为内核信号 let sig = Signal::SIGSTOP; - // 按照 Linux 6.6 ptrace_attach:发送 SIGSTOP 作为内核信号 - // 使用 Kill 类型表示来自内核的信号 let mut info = SigInfo::new( sig, 0, @@ -606,7 +511,6 @@ impl ProcessControlBlock { uid: 0, }, ); - // 按照 Linux 6.6:如果 self_ref 升级失败,说明进程正在销毁 if let Some(strong_ref) = self.self_ref.upgrade() { if let Err(e) = sig.send_signal_info_to_pcb(Some(&mut info), strong_ref, PidType::PID) { // 回滚ptrace设置 @@ -615,31 +519,12 @@ impl ProcessControlBlock { return Err(e); } } else { - // 进程正在销毁,回滚 ptrace 设置 + // 如果 self_ref 升级失败,说明进程正在销毁,回滚 ptrace 设置 self.flags().remove(ProcessFlags::PTRACED); self.ptrace_unlink()?; return Err(SystemError::ESRCH); } - - // 等待 tracee 进入 TracedStopped 状态 - // 按照 Linux 6.6:检查 wait 结果,如果被中断则回滚 - let tracee_ref = self.self_ref.upgrade().ok_or(SystemError::ESRCH)?; - let tracer_clone = tracer.clone(); - let wait_result = tracer_clone.wait_queue.wait_event_interruptible( - || { - let state = tracee_ref.sched_info().inner_lock_read_irqsave().state(); - matches!(state, ProcessState::TracedStopped(_)) - }, - None::, - ); - - // 检查等待结果,如果被中断则回滚 - if wait_result.is_err() { - self.flags().remove(ProcessFlags::PTRACED); - self.ptrace_unlink()?; - return Err(SystemError::ERESTARTSYS); - } - + // PTRACE_ATTACH 发送信号后立即返回 Ok(0) } @@ -685,52 +570,42 @@ impl ProcessControlBlock { } /// 处理PTRACE_DETACH请求 + /// + /// 注意:Linux 不重新发送信号到 pending 队列,只设置 exit_code。 + /// 如果 tracee 在 ptrace_stop 中睡眠,醒来后会读取 exit_code 作为返回值。 + /// 如果 tracee 不在 ptrace_stop 中,设置 exit_code 无效(预期行为)。 + /// + /// 信号处理语义: + /// - signal = None (data=0): 表示不注入信号,子进程继续运行 + /// - signal = Some(sig): 注入指定信号给子进程处理 pub fn detach(&self, signal: Option) -> Result { // 验证调用者是跟踪器 let current_pcb = ProcessManager::current_pcb(); + if !self.is_traced_by(¤t_pcb) { return Err(SystemError::EPERM); } - // 按照 Linux 6.6.21 的 ptrace_detach 实现: - // 1. 先解除 ptrace 关系,这样后续的信号不会被 ptrace 拦截 - self.ptrace_unlink()?; - - // 2. 如果指定了信号,发送该信号到 tracee - // 此时 tracee 已不再被 ptrace,信号会正常入队并被处理 - let data_signal = signal.unwrap_or(Signal::SIGCONT); - if let Some(sig) = signal { - // 将信号入队到 tracee 的 pending 队列 - let mut info = SigInfo::new( - sig, - 0, - SigCode::Origin(OriginCode::User), - SigType::Kill { - pid: current_pcb.raw_pid(), - uid: current_pcb.cred().uid.data() as u32, - }, - ); - // 发送信号(此时已经 ptrace_unlink,所以信号会正常处理) - // 按照 Linux 6.6:如果 self_ref 升级失败,说明进程正在销毁 - if let Some(strong_ref) = self.self_ref.upgrade() { - let _ = sig.send_signal_info_to_pcb( - Some(&mut info), - strong_ref, - crate::process::pid::PidType::PID, - ); + let data_signal = match signal { + None => Signal::INVALID, // data=0 表示不注入信号 + Some(sig) => { + if sig == Signal::INVALID { + // 显式指定了无效信号(这种情况在 syscall 层已被过滤) + return Err(SystemError::EIO); + } + sig } - // 如果进程正在销毁,信号发送失败不是致命错误 - } + }; - // 3. 同时将信号存储到 ptrace_state.injected_signal - // 这样如果 tracee 正在 ptrace_stop 中,它也能获取到这个信号 let mut ptrace_state = self.ptrace_state.lock(); ptrace_state.injected_signal = data_signal; drop(ptrace_state); - // 4. 恢复进程执行 - let mut sched_info = self.sched_info.inner_lock_write_irqsave(); + // 解除 ptrace 关系,恢复 real_parent + self.ptrace_unlink()?; + // 唤醒处于停止状态的进程 + let mut sched_info = self.sched_info.inner_lock_write_irqsave(); match sched_info.state() { ProcessState::TracedStopped(_) | ProcessState::Stopped(_) => { // 将状态设置为 Runnable,让进程可以被调度 @@ -751,16 +626,13 @@ impl ProcessControlBlock { .unwrap_or(crate::smp::core::smp_get_processor_id()) .data() as usize, ); - let (rq, _guard) = rq.self_lock(); rq.update_rq_clock(); - // 按照 Linux 6.6:如果 self_ref 升级失败,说明进程正在销毁 let strong_ref = self.self_ref.upgrade().ok_or(SystemError::ESRCH)?; rq.activate_task( &strong_ref, EnqueueFlag::ENQUEUE_WAKEUP | EnqueueFlag::ENQUEUE_NOCLOCK, ); - rq.check_preempt_currnet(&strong_ref, WakeupFlags::empty()); Ok(0) @@ -1014,23 +886,4 @@ impl ProcessControlBlock { ProcessFlags::PTRACED | ProcessFlags::TRACE_SYSCALL | ProcessFlags::TRACE_SINGLESTEP, ); } - - #[allow(dead_code)] - fn decode_exit_code_for_siginfo(exit_code: i32) -> (SigCode, i32) { - if (exit_code & 0x7f) == 0 { - // 正常退出: exit() - let status = (exit_code >> 8) & 0xff; - (SigCode::SigChld(ChldCode::Exited), status) - } else { - // 因信号终止 - let signal_num = exit_code & 0x7f; - if (exit_code & 0x80) != 0 { - // 生成了 core dump - (SigCode::SigChld(ChldCode::Dumped), signal_num) - } else { - // 未生成 core dump - (SigCode::SigChld(ChldCode::Killed), signal_num) - } - } - } } diff --git a/kernel/src/process/syscall/mod.rs b/kernel/src/process/syscall/mod.rs index 2089f6d3f..43182e86b 100644 --- a/kernel/src/process/syscall/mod.rs +++ b/kernel/src/process/syscall/mod.rs @@ -40,7 +40,6 @@ mod sys_setresuid; mod sys_setreuid; mod sys_setsid; mod sys_setuid; -mod sys_tkill; mod sys_umask; mod sys_uname; mod sys_unshare; diff --git a/kernel/src/process/syscall/sys_ptrace.rs b/kernel/src/process/syscall/sys_ptrace.rs index 2b0b0f831..a01ee6822 100644 --- a/kernel/src/process/syscall/sys_ptrace.rs +++ b/kernel/src/process/syscall/sys_ptrace.rs @@ -3,17 +3,16 @@ use crate::{ interrupt::TrapFrame, ipc::signal::Signal, syscall::nr::{SYS_EXIT, SYS_PTRACE}, - CurrentIrqArch, MMArch, + MMArch, }, - exception::{InterruptArch, IrqFlagsGuard}, - mm::{MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr}, + mm::{MemoryManagementArch, PhysAddr, VirtAddr}, process::{ syscall::sys_exit::SysExit, ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState, PtraceOptions, PtraceRequest, RawPid, }, syscall::{ table::{FormattedSyscallParam, Syscall}, - user_access::{copy_from_user_protected, copy_to_user_protected, UserBufferWriter}, + user_access::UserBufferWriter, }, }; use alloc::sync::Arc; @@ -121,69 +120,13 @@ impl TryFrom for PtraceRequest { } } -/// 页表切换守卫,用于在作用域结束时自动恢复页表 -/// -/// 按照 Linux 6.6 ptrace_access_vm 的模式: -/// 1. 禁用中断,防止在切换期间发生中断处理 -/// 2. 切换到目标进程的页表 -/// 3. 在作用域结束时恢复原始页表并重新启用中断 -struct PageTableGuard { - original_paddr: PhysAddr, - kind: PageTableKind, - _irq_guard: IrqFlagsGuard, -} - -impl PageTableGuard { - /// 切换到目标进程的页表 - /// - /// # Safety - /// 调用者必须确保: - /// 1. target_paddr 是有效的页表物理地址 - /// 2. 在此守卫存在期间不会发生调度 - fn new(target_paddr: PhysAddr, kind: PageTableKind) -> Self { - // 1. 首先禁用中断(关键!) - let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; - - // 2. 获取当前页表物理地址用于恢复 - let current_pcb = ProcessManager::current_pcb(); - let original_paddr = current_pcb - .basic() - .user_vm() - .map(|vm| { - let inner = vm.read_irqsave(); - inner.user_mapper.utable.table().phys() - }) - .expect("current process must have user VM"); - - // 3. 切换到目标进程的页表 - unsafe { - ::set_table(kind, target_paddr); - } - - Self { - original_paddr, - kind, - _irq_guard: irq_guard, - } - } -} - -impl Drop for PageTableGuard { - fn drop(&mut self) { - // 恢复原始页表 - unsafe { - ::set_table(self.kind, self.original_paddr); - } - // 中断会在 _irq_guard drop 时自动恢复 - } -} - /// ptrace 内存访问辅助函数 /// -/// 按照 Linux 6.6 的 ptrace_access_vm 模式实现: -/// - 使用临时页表切换访问目标进程的地址空间 -/// - 在中断禁用状态下进行页表切换 -/// - 使用守卫模式确保页表一定会被恢复 +/// 按照 Linux 6.6 的 ptrace_access_vm 模式实现,但不使用页表切换: +/// - 直接将 tracee 的虚拟地址翻译为物理地址 +/// - 通过 phys_2_virt 映射到内核虚拟地址空间 +/// - 使用异常表保护的拷贝函数,安全处理缺页异常 +/// - **不关闭中断**,避免中断禁用期间缺页导致的死锁 /// /// # Safety /// 调用者必须确保 tracee 在访问期间不会被销毁 @@ -194,17 +137,100 @@ where // 获取目标进程的地址空间 let tracee_vm = tracee.basic().user_vm().ok_or(SystemError::ESRCH)?; - // 获取目标进程的用户页表物理地址 - let tracee_mapper_paddr = { - let inner = tracee_vm.read_irqsave(); - inner.user_mapper.utable.table().phys() + // 获取目标进程的地址空间锁,但不切换页表 + // 只需要在地址空间读锁保护下执行操作 + let _tracee_vm_guard = tracee_vm.read_irqsave(); + + // 在目标进程的地址空间读锁保护中执行操作 + f() +} + +/// 从 tracee 的用户空间读取数据(安全版本) +/// +/// 使用物理地址翻译避免页表切换,不关闭中断。 +/// 参考 process_vm_readv 的实现方式。 +fn ptrace_peek_data(tracee: &Arc, addr: usize) -> Result { + let tracee_vm = tracee.basic().user_vm().ok_or(SystemError::ESRCH)?; + let tracee_vm_guard = tracee_vm.read_irqsave(); + + let tracee_addr = VirtAddr::new(addr); + + // 检查地址是否在 tracee 的地址空间中 + if tracee_vm_guard.mappings.contains(tracee_addr).is_none() { + return Err(SystemError::EIO); + } + + // 计算页内偏移 + let page_offset = addr & (MMArch::PAGE_SIZE - 1); + + // 翻译 tracee 的虚拟地址为物理地址 + let tracee_phys = match tracee_vm_guard.user_mapper.utable.translate(tracee_addr) { + Some((phys_frame, _)) => PhysAddr::new(phys_frame.data() + page_offset), + None => return Err(SystemError::EIO), }; + drop(tracee_vm_guard); + + // 使用异常表保护的拷贝 + let mut value: u64 = 0; + unsafe { + // 将物理地址映射为内核虚拟地址 + let kernel_virt = MMArch::phys_2_virt(tracee_phys).ok_or(SystemError::EIO)?; + + let src_ptr = kernel_virt.data() as *const u8; + let dst_ptr = &mut value as *mut u64 as *mut u8; + let result = MMArch::copy_with_exception_table(dst_ptr, src_ptr, 8); + if result != 0 { + return Err(SystemError::EIO); + } + } + + Ok(value as isize) +} + +/// 向 tracee 的用户空间写入数据(安全版本) +/// +/// 使用物理地址翻译避免页表切换,不关闭中断。 +/// 参考 process_vm_writev 的实现方式。 +fn ptrace_poke_data( + tracee: &Arc, + addr: usize, + data: usize, +) -> Result { + let tracee_vm = tracee.basic().user_vm().ok_or(SystemError::ESRCH)?; + let tracee_vm_guard = tracee_vm.read_irqsave(); - // 使用守卫切换页表,确保一定会恢复 - let _guard = PageTableGuard::new(tracee_mapper_paddr, PageTableKind::User); + let tracee_addr = VirtAddr::new(addr); - // 在目标进程的地址空间中执行操作 - f() + // 检查地址是否在 tracee 的地址空间中 + if tracee_vm_guard.mappings.contains(tracee_addr).is_none() { + return Err(SystemError::EIO); + } + + // 计算页内偏移 + let page_offset = addr & (MMArch::PAGE_SIZE - 1); + + // 翻译 tracee 的虚拟地址为物理地址 + let tracee_phys = match tracee_vm_guard.user_mapper.utable.translate(tracee_addr) { + Some((phys_frame, _)) => PhysAddr::new(phys_frame.data() + page_offset), + None => return Err(SystemError::EIO), + }; + drop(tracee_vm_guard); + + // 使用异常表保护的拷贝 + let value: u64 = data as u64; + unsafe { + // 将物理地址映射为内核虚拟地址 + let kernel_virt = MMArch::phys_2_virt(tracee_phys).ok_or(SystemError::EIO)?; + + let src_ptr = &value as *const u64 as *const u8; + let dst_ptr = kernel_virt.data() as *mut u8; + let result = MMArch::copy_with_exception_table(dst_ptr, src_ptr, 8); + if result != 0 { + return Err(SystemError::EIO); + } + } + + Ok(0) } /// ptrace 系统调用实现 @@ -298,9 +324,18 @@ impl SysPtrace { } /// 处理 PTRACE_GETSIGINFO 请求(获取信号信息) - fn handle_get_siginfo(_tracee: &Arc) -> Result { - // 在实际实现中,你需要获取并返回信号信息 - // 这里仅返回占位值 + fn handle_get_siginfo(tracee: &Arc) -> Result { + // 读取 last_siginfo 并拷贝到用户空间 + let siginfo = tracee + .ptrace_state + .lock() + .last_siginfo() + .ok_or(SystemError::EINVAL)?; + + // TODO: 将 siginfo 拷贝到用户空间的 data 参数指向的地址 + // 目前返回成功,表示 siginfo 存在 + // 完整实现需要:将 siginfo 转换为 PosixSigInfo 格式并拷贝到用户空间 + log::debug!("PTRACE_GETSIGINFO: siginfo={:?}", siginfo); Ok(0) } @@ -315,51 +350,29 @@ impl SysPtrace { /// 处理 PTRACE_PEEKDATA 请求(读取进程内存) /// - /// 按照 Linux 6.6.21 的 ptrace 语义: - /// - 使用 ptrace_access_vm 模式访问目标进程地址空间 - /// - 在中断禁用状态下进行页表切换 - /// - 使用守卫模式确保页表恢复 + /// 使用安全的物理地址翻译方式访问目标进程地址空间: + /// - 不进行页表切换 + /// - 不关闭中断 + /// - 使用异常表保护安全处理缺页 fn handle_peek_data( tracee: &Arc, addr: usize, ) -> Result { - // 使用安全的 ptrace_access_vm 辅助函数 - ptrace_access_vm(tracee, || { - let mut value: u64 = 0; - unsafe { - copy_from_user_protected( - core::slice::from_raw_parts_mut(&mut value as *mut u64 as *mut u8, 8), - VirtAddr::new(addr), - ) - }?; - Ok(value as isize) - }) - .map_err(|_| SystemError::EIO) + ptrace_peek_data(tracee, addr) } /// 处理 PTRACE_POKEDATA 请求(写入进程内存) /// - /// 按照 Linux 6.6.21 的 ptrace 语义: - /// - 使用 ptrace_access_vm 模式访问目标进程地址空间 - /// - 在中断禁用状态下进行页表切换 - /// - 使用守卫模式确保页表恢复 + /// 使用安全的物理地址翻译方式访问目标进程地址空间: + /// - 不进行页表切换 + /// - 不关闭中断 + /// - 使用异常表保护安全处理缺页 fn handle_poke_data( tracee: &Arc, addr: usize, data: usize, ) -> Result { - // 使用安全的 ptrace_access_vm 辅助函数 - ptrace_access_vm(tracee, || { - let value: u64 = data as u64; - unsafe { - copy_to_user_protected( - VirtAddr::new(addr), - core::slice::from_raw_parts(&value as *const u64 as *const u8, 8), - ) - }?; - Ok(0) - }) - .map_err(|_| SystemError::EIO) + ptrace_poke_data(tracee, addr, data) } /// 处理 PTRACE_SINGLESTEP 请求 (单步执行) @@ -394,12 +407,21 @@ impl SysPtrace { // 从 tracee 的内核栈读取 TrapFrame let trap_frame = unsafe { &*(trap_frame_vaddr.data() as *const TrapFrame) }; - // 获取 fs_base 和 gs_base + // 获取 fs_base、gs_base 和段选择器 + // - fs_base/gs_base: task->thread.fsbase/gsbase + // - fs/gs: task->thread.fsindex/gsindex + // - ds/es: task->thread.ds/es 或 pt_regs->ds/es let arch_info = tracee.arch_info_irqsave(); let fs_base = arch_info.fsbase() as u64; let gs_base = arch_info.gsbase() as u64; + let fs = arch_info.fs() as u64; + let gs = arch_info.gs() as u64; drop(arch_info); + // TrapFrame 包含 ds 和 es(对应 pt_regs->ds/es) + let ds = trap_frame.ds as u64; + let es = trap_frame.es as u64; + // 构造用户态寄存器结构体 let user_regs = user_regs_struct { r15: trap_frame.r15, @@ -425,10 +447,10 @@ impl SysPtrace { ss: trap_frame.ss, fs_base, gs_base, - ds: 0, - es: 0, - fs: 0, - gs: 0, + ds, + es, + fs, + gs, }; // 拷贝到用户空间 diff --git a/kernel/src/process/syscall/sys_tkill.rs b/kernel/src/process/syscall/sys_tkill.rs deleted file mode 100644 index 4a1210626..000000000 --- a/kernel/src/process/syscall/sys_tkill.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::arch::interrupt::TrapFrame; -use crate::arch::ipc::signal::Signal; -use crate::arch::syscall::nr::SYS_TKILL; -use crate::process::ProcessManager; -use crate::syscall::table::{FormattedSyscallParam, Syscall}; -use alloc::vec::Vec; -use system_error::SystemError; - -pub struct SysTkill; - -impl SysTkill { - fn thread_id(args: &[usize]) -> usize { - args[0] - } - - fn signal(args: &[usize]) -> usize { - args[1] - } -} - -impl Syscall for SysTkill { - fn num_args(&self) -> usize { - 2 - } - - fn handle(&self, args: &[usize], _tf: &mut TrapFrame) -> Result { - let tid = Self::thread_id(args); - let sig = Self::signal(args); - // 当前只支持向当前进程的线程发送信号 - let current = ProcessManager::current_pcb(); - // 检查线程ID是否有效(目前简化处理) - if tid != 0 && tid != current.raw_pid().data() { - return Err(SystemError::ESRCH); - } - if sig > Signal::SIGRTMAX as usize { - return Err(SystemError::EINVAL); - } - // current.stop_process(sig.into()); - Ok(0) - } - - fn entry_format(&self, args: &[usize]) -> Vec { - vec![ - FormattedSyscallParam::new("tid", format!("{}", Self::thread_id(args))), - FormattedSyscallParam::new("sig", format!("{}", Self::signal(args))), - ] - } -} - -syscall_table_macros::declare_syscall!(SYS_TKILL, SysTkill); diff --git a/user/apps/tests/syscall/gvisor/blocklists/ptrace_test b/user/apps/tests/syscall/gvisor/blocklists/ptrace_test index fb172f3ce..8c8f5a57a 100644 --- a/user/apps/tests/syscall/gvisor/blocklists/ptrace_test +++ b/user/apps/tests/syscall/gvisor/blocklists/ptrace_test @@ -12,5 +12,6 @@ PtraceTest.Sysemu_PokeUser PtraceTest.85 PtraceTest.Seize_Interrupt_Listen PtraceTest.Interrupt_Listen_RequireSeize +PtraceTest.SeizeSetOptions PtraceTest.SingleStep -*PtraceExecveTest.Execve_GetRegs_PeekUser_SIGKILL_TraceClone_TraceExit* \ No newline at end of file +*PtraceExecveTest.Execve_GetRegs_PeekUser_SIGKILL_TraceClone_TraceExit* diff --git a/user/apps/tests/syscall/gvisor/whitelist.txt b/user/apps/tests/syscall/gvisor/whitelist.txt index 42b1d34f0..d7f5bc573 100644 --- a/user/apps/tests/syscall/gvisor/whitelist.txt +++ b/user/apps/tests/syscall/gvisor/whitelist.txt @@ -62,6 +62,7 @@ setns_test eventfd_test poll_test rseq_test +ptrace_test # 内存管理测试 From 5377b90485f48b1f884daa82cf19392196930674 Mon Sep 17 00:00:00 2001 From: aLinChe <1129332011@qq.com> Date: Wed, 14 Jan 2026 22:19:31 +0800 Subject: [PATCH 11/15] =?UTF-8?q?feat(ptrace):=20=E5=AE=8C=E5=96=84ptrace?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=92=8C=E4=BF=A1=E5=8F=B7=E5=A4=84=E7=90=86?= =?UTF-8?q?=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主要改进: - 重构信号权限检查,统一使用check_kill_permission函数 - 修复wait系统调用对ptrace子进程的支持,包括TracedStopped状态处理 - 完善ptrace_signal函数,修复潜在的use-after-free问题 - 改进exit_signal时序,确保waitid后进程资源立即释放 - 修复ProcessState::Stopped状态存储实际停止信号号 - 增强错误处理,避免panic风险 --- kernel/src/ipc/kill.rs | 6 +- kernel/src/ipc/signal.rs | 8 +- kernel/src/ipc/signal_types.rs | 2 +- kernel/src/ipc/syscall/sys_kill.rs | 50 ++++++-- kernel/src/ipc/syscall/sys_rt_sigqueueinfo.rs | 6 +- kernel/src/ipc/syscall/sys_tkill.rs | 58 +-------- kernel/src/process/exit.rs | 99 ++++++++++++++- kernel/src/process/mod.rs | 24 ++-- kernel/src/process/ptrace.rs | 114 +++++++++++++----- kernel/src/process/syscall/sys_exit_group.rs | 5 +- kernel/src/process/syscall/sys_ptrace.rs | 26 +++- .../tests/syscall/gvisor/blocklists/wait_test | 2 - 12 files changed, 271 insertions(+), 129 deletions(-) diff --git a/kernel/src/ipc/kill.rs b/kernel/src/ipc/kill.rs index 0cd3adb55..91bab43b9 100644 --- a/kernel/src/ipc/kill.rs +++ b/kernel/src/ipc/kill.rs @@ -2,7 +2,7 @@ use crate::{ arch::ipc::signal::Signal, ipc::{ signal_types::{OriginCode, SigCode, SigInfo, SigType}, - syscall::sys_kill::check_signal_permission_pcb_with_sig, + syscall::sys_kill::check_kill_permission, }, process::{ pid::{Pid, PidType}, @@ -21,7 +21,7 @@ pub fn send_signal_to_pid(pid: RawPid, sig: Signal) -> Result, sig: Signal) -> Result Result<(), SystemError> { let mut info = SigInfo::new( sig, 0, - SigCode::Kernel, + SigCode::Origin(OriginCode::Kernel), SigType::Kill { pid: RawPid::new(0), uid: 0, @@ -166,7 +166,7 @@ impl Signal { //详见 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/signal.c?r=&mo=32170&fi=1220#1226 } - let prepare_result = self.prepare_sianal(pcb.clone(), force_send); + let prepare_result = self.prepare_signal(pcb.clone(), force_send); if !prepare_result { return Ok(0); } @@ -472,7 +472,7 @@ impl Signal { /// - `true` 能够发送信号 /// /// - `false` 不能发送信号 - fn prepare_sianal(&self, pcb: Arc, _force: bool) -> bool { + fn prepare_signal(&self, pcb: Arc, _force: bool) -> bool { // 统一从线程组组长的 ThreadInfo 中获取完整线程列表。 // 注意:当前 sighand 共享在 CLONE_THREAD 线程组内,因此标志位操作仍然只需要对共享 sighand 做一次。 let thread_group_leader = { @@ -534,7 +534,7 @@ impl Signal { // 线程组 stop:对组内所有线程置为 Stopped,保证 SIGSTOP 对整个线程组生效。 for_each_thread_in_group(&mut |t| { - let _ = ProcessManager::stop_task(t); + let _ = ProcessManager::stop_task(t, *self); }); if let Some(parent) = pcb.parent_pcb() { diff --git a/kernel/src/ipc/signal_types.rs b/kernel/src/ipc/signal_types.rs index 84b41043a..c5e8e6436 100644 --- a/kernel/src/ipc/signal_types.rs +++ b/kernel/src/ipc/signal_types.rs @@ -98,7 +98,7 @@ pub enum TrapCode { #[derive(Copy, Debug, Clone, PartialEq, Eq)] #[repr(i32)] pub enum IllCode { - /// 求编代码错误 + /// 非法代码错误 IllIll = 1, /// 汇编指令的 operand 不存在 IllIlladr = 2, diff --git a/kernel/src/ipc/syscall/sys_kill.rs b/kernel/src/ipc/syscall/sys_kill.rs index afdeadbef..ff726adf3 100644 --- a/kernel/src/ipc/syscall/sys_kill.rs +++ b/kernel/src/ipc/syscall/sys_kill.rs @@ -6,6 +6,7 @@ use core::ffi::c_int; use crate::arch::interrupt::TrapFrame; use crate::process::cred::CAPFlags; use crate::process::pid::Pid; +use crate::process::pid::PidType; use crate::process::ProcessControlBlock; use crate::syscall::table::FormattedSyscallParam; use crate::syscall::table::Syscall; @@ -93,7 +94,7 @@ impl PidConverter { /// - SIGCONT can be sent to any process in the same session /// /// 参考: https://man7.org/linux/man-pages/man2/kill.2.html -pub fn check_signal_permission_pcb_with_sig( +pub fn check_kill_permission( target: &Arc, sig: Option, ) -> Result<(), SystemError> { @@ -111,11 +112,12 @@ pub fn check_signal_permission_pcb_with_sig( return Ok(()); } + // 凭证检查 (kill_ok_by_cred) // Check if sender's UID matches target's UID or saved UID - if current_cred.euid == target_cred.uid - || current_cred.euid == target_cred.suid - || current_cred.uid == target_cred.uid + if current_cred.euid == target_cred.suid + || current_cred.euid == target_cred.uid || current_cred.uid == target_cred.suid + || current_cred.uid == target_cred.uid { return Ok(()); } @@ -141,7 +143,7 @@ pub fn check_signal_permission_pcb_with_sig( /// Check if the current process has permission to send a signal to the target process. /// (不带信号参数的兼容版本) pub fn check_signal_permission_pcb(target: &Arc) -> Result<(), SystemError> { - check_signal_permission_pcb_with_sig(target, None) + check_kill_permission(target, None) } /// Check if the current process has permission to send a signal to the target process. @@ -170,10 +172,40 @@ fn handle_null_signal(converter: &PidConverter) -> Result { Ok(0) } PidConverter::Pgid(pgid) => { - // For process groups, verify the group exists - // A more complete implementation could check all processes in the group - pgid.as_ref().ok_or(SystemError::ESRCH)?; - Ok(0) + // For process groups, verify the group exists and has at least one living process + let pg = pgid.as_ref().ok_or(SystemError::ESRCH)?; + // 检查进程组中是否有存活的进程 + let tasks: Vec> = pg.tasks_iter(PidType::PGID).collect(); + if tasks.is_empty() { + return Err(SystemError::ESRCH); + } + + let mut any_success = false; + let mut last_err = SystemError::ESRCH; // 默认为 ESRCH,处理全员退出的情况 + for pcb in tasks { + // 如果进程已退出(僵尸),在 kill(0) 语义下通常视为不存在,跳过 + if pcb.is_exited() { + continue; + } + // 检查权限! + match check_signal_permission_pcb(&pcb) { + Ok(_) => { + // 只要有一个进程通过检查,整体就算成功 + any_success = true; + } + Err(e) => { + last_err = e; + } + } + } + if any_success { + Ok(0) + } else { + // 如果没有一个成功: + // 1. 可能是因为所有进程都是僵尸 (last_err 初始值 ESRCH) + // 2. 可能是因为所有活进程都无权发送 (last_err 被更新为 EPERM) + Err(last_err) + } } PidConverter::All => { // Signal 0 to all processes: just verify the syscall is valid diff --git a/kernel/src/ipc/syscall/sys_rt_sigqueueinfo.rs b/kernel/src/ipc/syscall/sys_rt_sigqueueinfo.rs index a108c58b4..e651a8465 100644 --- a/kernel/src/ipc/syscall/sys_rt_sigqueueinfo.rs +++ b/kernel/src/ipc/syscall/sys_rt_sigqueueinfo.rs @@ -6,7 +6,7 @@ use core::mem::size_of; use crate::arch::interrupt::TrapFrame; use crate::arch::syscall::nr::SYS_RT_SIGQUEUEINFO; use crate::ipc::signal_types::{OriginCode, PosixSigInfo, SigCode, SigInfo, SigType}; -use crate::ipc::syscall::sys_kill::check_signal_permission_pcb_with_sig; +use crate::ipc::syscall::sys_kill::check_kill_permission; use crate::process::pid::PidType; use crate::syscall::table::{FormattedSyscallParam, Syscall}; use crate::syscall::user_access::UserBufferReader; @@ -63,7 +63,7 @@ impl Syscall for SysRtSigqueueinfoHandle { let target_pid = RawPid::from(pid as usize); let target = ProcessManager::find_task_by_vpid(target_pid).ok_or(SystemError::ESRCH)?; // 传入 Signal::INVALID/0 在权限检查里无特殊含义,这里用 None 即可 - check_signal_permission_pcb_with_sig(&target, None)?; + check_kill_permission(&target, None)?; return Ok(0); } @@ -129,7 +129,7 @@ impl Syscall for SysRtSigqueueinfoHandle { // 查找目标进程并检查权限 let target = ProcessManager::find_task_by_vpid(target_pid).ok_or(SystemError::ESRCH)?; - check_signal_permission_pcb_with_sig(&target, Some(signal))?; + check_kill_permission(&target, Some(signal))?; // rt_sigqueueinfo 发送进程级信号,使用 PidType::TGID signal diff --git a/kernel/src/ipc/syscall/sys_tkill.rs b/kernel/src/ipc/syscall/sys_tkill.rs index 3cdb2cafb..2d41764b3 100644 --- a/kernel/src/ipc/syscall/sys_tkill.rs +++ b/kernel/src/ipc/syscall/sys_tkill.rs @@ -5,8 +5,11 @@ use core::ffi::c_int; use crate::{ arch::{interrupt::TrapFrame, ipc::signal::Signal, syscall::nr::SYS_TKILL}, - ipc::signal_types::{OriginCode, SigCode, SigInfo, SigType}, - process::{cred::CAPFlags, pid::PidType, ProcessControlBlock, ProcessManager, RawPid}, + ipc::{ + signal_types::{OriginCode, SigCode, SigInfo, SigType}, + syscall::sys_kill::check_kill_permission, + }, + process::{pid::PidType, ProcessControlBlock, ProcessManager, RawPid}, syscall::table::{FormattedSyscallParam, Syscall}, }; use system_error::SystemError; @@ -94,7 +97,7 @@ pub fn do_tkill(tgid: i32, tid: i32, sig: c_int) -> Result { }; // 4. 权限检查 (sig=0 时也必须检查权限) - check_kill_permission(signal, &target_pcb)?; + check_kill_permission(&target_pcb, Some(signal))?; // 5. 如果是探测模式,权限检查通过后直接返回 if sig == 0 { @@ -105,55 +108,6 @@ pub fn do_tkill(tgid: i32, tid: i32, sig: c_int) -> Result { send_signal_tkill(signal, target_pcb) } -/// 检查发送信号的权限 -/// -/// 根据Linux的权限检查规则: -/// 1. 发送者和接收者同用户,或者发送者具有 CAP_KILL 权限 -/// 2. 对于 SIGCONT,规则更宽松:只要是同一 session 即可 -/// -/// # 参数 -/// - `sig`: 要发送的信号 -/// - `target_pcb`: 目标进程控制块 -/// -/// # 返回值 -/// - `Ok(())`: 权限检查通过 -/// - `Err(SystemError::EPERM)`: 权限不足 -fn check_kill_permission( - sig: Signal, - target_pcb: &Arc, -) -> Result<(), SystemError> { - let current_pcb = ProcessManager::current_pcb(); - let current_cred = current_pcb.cred(); - let target_cred = target_pcb.cred(); - - // 检查 CAP_KILL 权限 - if current_cred.has_capability(CAPFlags::CAP_KILL) { - return Ok(()); - } - - // 凭证检查 (kill_ok_by_cred) - // 规则:发送者的 euid/uid 必须匹配目标线程的 suid/uid - if current_cred.euid == target_cred.suid - || current_cred.euid == target_cred.uid - || current_cred.uid == target_cred.suid - || current_cred.uid == target_cred.uid - { - return Ok(()); - } - - // 3. SIGCONT 的特殊规则:同一 Session 即可 - if sig == Signal::SIGCONT { - let current_session = current_pcb.task_session(); - let target_session = target_pcb.task_session(); - // 确保双方都在 session 中且 session ID 相同 - if current_session.is_some() && current_session == target_session { - return Ok(()); - } - } - - Err(SystemError::EPERM) -} - /// 发送 tkill 语义的信号 fn send_signal_tkill( sig: Signal, diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs index deea2dcd6..aa16f54d9 100644 --- a/kernel/src/process/exit.rs +++ b/kernel/src/process/exit.rs @@ -369,7 +369,12 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { && kwo.options.contains(WaitOption::WSTOPPED) && pcb.sighand().flags_contains(SignalFlags::CLD_STOPPED) { - let stopsig = Signal::SIGSTOP as i32; + // 从 ProcessState::Stopped 中提取实际的停止信号号 + let stopsig = if let ProcessState::Stopped(sig) = state { + (sig & 0x7f) as i32 + } else { + Signal::SIGSTOP as i32 + }; kwo.no_task_error = None; kwo.ret_info = Some(WaitIdInfo { pid: pcb.task_pid_vnr(), @@ -558,7 +563,9 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { let wait_res = parent.wait_queue.wait_event_interruptible( || { let rd_children = parent.children.read(); - if rd_children.is_empty() { + let rd_ptraced = parent.ptraced_list.read(); + + if rd_children.is_empty() && rd_ptraced.is_empty() { echild = true; return true; } @@ -603,7 +610,12 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { && kwo.options.contains(WaitOption::WSTOPPED) && pcb.sighand().flags_contains(SignalFlags::CLD_STOPPED) { - let stopsig = Signal::SIGSTOP as i32; + // 从 ProcessState::Stopped 中提取实际的停止信号号 + let stopsig = if let ProcessState::Stopped(sig) = state { + (sig & 0x7f) as i32 + } else { + Signal::SIGSTOP as i32 + }; kwo.no_task_error = None; kwo.ret_info = Some(WaitIdInfo { pid: pcb.task_pid_vnr(), @@ -658,6 +670,85 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { drop(sched_guard); } drop(rd_children); + + if scan_result.is_none() { + for ptraced_pid in rd_ptraced.iter() { + if scan_result.is_some() { + break; + } + + let pcb = match ProcessManager::find_task_by_vpid(*ptraced_pid) { + Some(p) => p, + None => continue, + }; + + // 检查 PGID 是否匹配 + let child_pgrp = pcb.task_pgrp(); + let in_target_pgrp = match &child_pgrp { + Some(cp) => Arc::ptr_eq(cp, pgid), + None => false, + }; + if !in_target_pgrp { + continue; + } + + has_matching_child = true; + + // ptrace 的子进程总是可以被 wait,不需要检查 is_eligible_child + if !child_matches_wait_options(&pcb, kwo.options) { + continue; + } + + let sched_guard = pcb.sched_info().inner_lock_read_irqsave(); + let state = sched_guard.state(); + if !state.is_exited() { + all_matching_children_exited = false; + } + + if matches!(state, ProcessState::TracedStopped(_)) { + // TracedStopped 状态总是报告给 tracer + let stopsig = if let ProcessState::TracedStopped(sig) = state { + (sig & 0x7f) as i32 + } else { + Signal::SIGSTOP as i32 + }; + kwo.no_task_error = None; + kwo.ret_info = Some(WaitIdInfo { + pid: pcb.task_pid_vnr(), + status: stopsig, + cause: SigChildCode::Trapped.into(), + uid: get_child_uid(&pcb), + }); + kwo.ret_status = (stopsig << 8) | 0x7f; + scan_result = Some(Ok((*ptraced_pid).into())); + drop(sched_guard); + break; + } else if state.is_exited() + && kwo.options.contains(WaitOption::WEXITED) + { + let raw = state.exit_code().unwrap() as i32; + kwo.ret_status = raw; + let status8 = wstatus_to_waitid_status(raw); + kwo.no_task_error = None; + kwo.ret_info = Some(WaitIdInfo { + pid: pcb.task_pid_vnr(), + status: status8, + cause: SigChildCode::Exited.into(), + uid: get_child_uid(&pcb), + }); + tmp_child_pcb = Some(pcb.clone()); + if !kwo.options.contains(WaitOption::WNOWAIT) { + pid_to_release = Some(pcb.raw_pid()); + } + scan_result = Some(Ok((*ptraced_pid).into())); + drop(sched_guard); + break; + } + drop(sched_guard); + } + } + drop(rd_ptraced); + if let Some(pid) = pid_to_release { unsafe { ProcessManager::release(pid) }; } @@ -908,7 +999,7 @@ fn do_waitpid( impl ProcessControlBlock { /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/exit.c#143 - pub(super) fn __exit_signal(&mut self) { + pub(super) fn __exit_signal(&self) { let group_dead = self.is_thread_group_leader(); let mut sig_guard = self.sig_info_mut(); let mut tty: Option> = None; diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 6ca54b93f..7d0f12a3d 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -400,7 +400,7 @@ impl ProcessManager { /// /// 注意:该函数用于对“目标进程”进行停止标记,不要求在目标进程上下文调用。 /// 与 `mark_stop`(仅当前进程)相对应。 - pub fn stop_task(pcb: &Arc) -> Result<(), SystemError> { + pub fn stop_task(pcb: &Arc, sig: Signal) -> Result<(), SystemError> { let _guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; let mut writer = pcb.sched_info().inner_lock_write_irqsave(); let state = writer.state(); @@ -410,7 +410,7 @@ impl ProcessManager { // Stopped 的任务不应继续留在 runqueue 中,否则仍可能被选中运行。 let on_rq = *pcb.sched_info().on_rq.lock_irqsave(); - writer.set_state(ProcessState::Stopped(0)); + writer.set_state(ProcessState::Stopped(sig.into())); // stop 后不应再被视为“睡眠任务”,避免后续调度错误地做 DEQUEUE_SLEEP。 writer.set_wakeup(); pcb.flags().insert(ProcessFlags::NEED_SCHEDULE); @@ -490,9 +490,11 @@ impl ProcessManager { // 让INIT进程收养所有子进程 if current.raw_pid() != RawPid(1) { unsafe { - current - .adopt_childen() - .unwrap_or_else(|e| panic!("adopte_childen failed: error: {e:?}")) + if let Err(e) = current.adopt_childen() { + // Log error but don't panic - allow exit to continue + // Init will inherit orphaned children + log::error!("adopt_children failed during exit: {:?}. Children will be inherited by init.", e); + } }; let r = current.parent_pcb.read_irqsave().upgrade(); @@ -757,6 +759,10 @@ impl ProcessManager { pub(super) unsafe fn release(pid: RawPid) { let pcb = ProcessManager::find(pid); if let Some(ref pcb) = pcb { + // 立即执行 exit_signal,清理 PID 等资源 + // 确保 waitid 之后的调用能立即感知到进程已彻底消失(特别是 PID namespace 清理) + pcb.__exit_signal(); + // 从父进程的 children 列表中移除 if let Some(parent) = pcb.real_parent_pcb() { let mut children = parent.children.write(); @@ -800,7 +806,6 @@ impl ProcessManager { /// ## 参数 /// /// - `pcb` : 进程的pcb - #[allow(dead_code)] pub fn kick(pcb: &Arc) { ProcessManager::current_pcb().preempt_disable(); let cpu_id = pcb.sched_info().on_cpu(); @@ -877,7 +882,6 @@ pub enum ProcessState { Exited(usize), } -#[allow(dead_code)] impl ProcessState { #[inline(always)] pub fn is_runnable(&self) -> bool { @@ -1063,6 +1067,7 @@ pub enum PtraceSyscallInfoOp { None = 0, Entry = 1, Exit = 2, + #[allow(dead_code)] Seccomp = 3, } @@ -1140,8 +1145,6 @@ pub struct PtraceState { pub stop_reason: PtraceStopReason, /// ptrace选项位 options: PtraceOptions, - /// 停止状态的状态字 - exit_code: usize, /// 用于存储事件消息 event_message: usize, /// tracer 注入的信号(在 ptrace_stop 返回后要处理的信号) @@ -1157,7 +1160,6 @@ impl Default for PtraceState { pending_signals: Vec::new(), stop_reason: PtraceStopReason::None, options: PtraceOptions::empty(), - exit_code: 0, event_message: 0, injected_signal: Signal::INVALID, last_siginfo: None, @@ -1171,7 +1173,6 @@ impl PtraceState { pending_signals: Vec::new(), stop_reason: PtraceStopReason::None, options: PtraceOptions::empty(), - exit_code: 0, event_message: 0, injected_signal: Signal::INVALID, last_siginfo: None, @@ -1221,6 +1222,7 @@ impl PtraceState { } #[derive(Debug, Default)] +#[allow(dead_code)] pub struct SyscallInfo { /// 系统调用入口信息(系统调用号、参数、返回值) syscall_num: usize, diff --git a/kernel/src/process/ptrace.rs b/kernel/src/process/ptrace.rs index 815831c73..1b2bbfc2f 100644 --- a/kernel/src/process/ptrace.rs +++ b/kernel/src/process/ptrace.rs @@ -2,7 +2,7 @@ use crate::arch::interrupt::TrapFrame; use crate::arch::ipc::signal::{SigFlags, Signal}; use crate::arch::kprobe; use crate::ipc::signal_types::{ - ChldCode, OriginCode, SigChldInfo, SigCode, SigFaultInfo, SigInfo, SigType, TrapCode, + ChldCode, OriginCode, SigChldInfo, SigCode, SigFaultInfo, SigInfo, SigType, }; use crate::process::cred; use crate::process::{ @@ -25,9 +25,11 @@ pub fn ptrace_signal( original_signal: Signal, info: &mut Option, ) -> Option { + // Clone the Arc before calling ptrace_stop to prevent use-after-free. + let pcb_clone = Arc::clone(pcb); // todo pcb.jobctl_set(JobControlFlags::STOP_DEQUEUED); // 注意:ptrace_stop 内部会处理锁的释放和重新获取。 - let signr = pcb.ptrace_stop(original_signal as usize, ChldCode::Trapped, info.as_mut()); + let signr = pcb_clone.ptrace_stop(original_signal as usize, ChldCode::Trapped, info.as_mut()); if signr == 0 { return None; // 丢弃原始信号,继续处理下一个信号(如果没有,则继续执行) @@ -43,7 +45,7 @@ pub fn ptrace_signal( if injected_signal != original_signal { if let Some(info_ref) = info { // 如果获取失败,保持原有的 siginfo - if let Some(tracer) = pcb.tracer().and_then(ProcessManager::find) { + if let Some(tracer) = pcb_clone.tracer().and_then(ProcessManager::find) { *info_ref = SigInfo::new( injected_signal, 0, @@ -61,7 +63,7 @@ pub fn ptrace_signal( // 特殊处理 SIGCONT:需要清除挂起的停止信号,但仍然要唤醒进程并传递给用户空间处理 if injected_signal == Signal::SIGCONT { // 清除任何挂起的停止信号(如 SIGSTOP, SIGTSTP 等) - let mut sig_info = pcb.sig_info.write(); + let mut sig_info = pcb_clone.sig_info.write(); let pending = sig_info.sig_pending_mut().signal_mut(); for stop_sig in [ Signal::SIGSTOP, @@ -76,15 +78,25 @@ pub fn ptrace_signal( } // 检查新信号是否被当前进程的信号掩码阻塞 - let sig_info_guard = pcb.sig_info_irqsave(); - if sig_info_guard - .sig_blocked() - .contains(injected_signal.into()) - { - // 如果被阻塞了,则将信号重新排队,让它在未来被处理。 - let _ = - injected_signal.send_signal_info_to_pcb(info.as_mut(), Arc::clone(pcb), PidType::PID); - return None; + let sig_set = { + let guard = pcb_clone.sig_info_irqsave(); + *guard.sig_blocked() + }; + + if sig_set.contains(injected_signal.into()) { + // 如果信号被阻塞了,则尝试重新入队 + match injected_signal.send_signal_info_to_pcb(info.as_mut(), pcb_clone, PidType::PID) { + Ok(_) => return None, // 成功入队 + Err(e) => { + // 严重错误:无法保留被阻塞的信号。 + log::error!( + "ptrace_signal lost signal {:?} due to re-queue failure: {:?}", + injected_signal, + e + ); + return None; + } + } } // 如果没有被阻塞,则返回这个新信号,让 get_signal 继续分发和处理它。 Some(injected_signal) @@ -122,8 +134,9 @@ impl ProcessControlBlock { } pub fn is_traced_by(&self, tracer: &Arc) -> bool { - match self.tracer() { - Some(tracer_pid) => tracer_pid == tracer.raw_pid(), + let state = self.ptrace_state.lock(); + match state.tracer { + Some(pid) => pid == tracer.raw_pid(), None => false, } } @@ -210,7 +223,13 @@ impl ProcessControlBlock { self.ptrace_state.lock().event_message = message; // ptrace_notify 会调用 ptrace_stop,阻塞进程直到 tracer 唤醒 let exit_code = (event as usize) << 8 | Signal::SIGTRAP as usize; - let _ = Self::ptrace_notify(exit_code); + if let Err(e) = Self::ptrace_notify(exit_code) { + log::error!( + "ptrace_event: failed to notify tracer of event {:?}: {:?}", + event, + e + ); + } // ptrace_stop 内部会调用 schedule() 阻塞 // 当 tracer 调用 PTRACE_CONT 时,ptrace_resume 会设置 Runnable } else if event == PtraceEvent::Exec { @@ -229,7 +248,14 @@ impl ProcessControlBlock { ); // 如果 self_ref 升级失败,说明进程正在销毁,此时发送信号没有意义,安全地跳过 if let Some(strong_ref) = self.self_ref.upgrade() { - let _ = sig.send_signal_info_to_pcb(Some(&mut info), strong_ref, PidType::PID); + if let Err(e) = + sig.send_signal_info_to_pcb(Some(&mut info), strong_ref, PidType::PID) + { + log::error!( + "ptrace_event: failed to send legacy SIGTRAP for exec: {:?}", + e + ); + } } } // 未PTRACED或PTRACE_SEIZE:不发送信号,静默返回 @@ -368,7 +394,7 @@ impl ProcessControlBlock { return true; } - // 3. 检查UID、GID是否完全匹配 (euid/suid/uid、gid 都要相同) + // 3. 检查UID、GID是否完全匹配 (euid/suid/uid、gid 都要相同) let caller_cred = self.cred(); let tracee_cred = tracee.cred(); let uid_match = caller_cred.uid == tracee_cred.euid @@ -422,8 +448,6 @@ impl ProcessControlBlock { .ok_or(SystemError::ESRCH)?; self.set_parent(&new_parent)?; - // 获取信号锁 - let _sighand_lock = self.sighand(); // 3. 清除 ptrace 标志和 tracer self.clear_tracer(); @@ -513,7 +537,7 @@ impl ProcessControlBlock { ); if let Some(strong_ref) = self.self_ref.upgrade() { if let Err(e) = sig.send_signal_info_to_pcb(Some(&mut info), strong_ref, PidType::PID) { - // 回滚ptrace设置 + // 回滚 ptrace 设置 self.flags().remove(ProcessFlags::PTRACED); self.ptrace_unlink()?; return Err(e); @@ -725,12 +749,18 @@ impl ProcessControlBlock { Ok(0) } + /// 处理 PTRACE_GETSIGINFO 请求,获取系统调用信息 + /// + /// # 注意 + /// **此函数当前未完全实现** - 返回的数据可能不正确 + #[allow(dead_code)] pub fn ptrace_get_syscall_info( &self, user_size: usize, _datavp: usize, // Use a raw byte pointer for flexibility ) -> Result { - // todo let trap_frame = self.task_context(); + // TODO: 获取实际的trapframe,而不是创建空的 + // let trap_frame = self.task_context(); let trap_frame = TrapFrame::new(); let ctx = kprobe::KProbeContext::from(&trap_frame); let mut info = PtraceSyscallInfo { @@ -776,23 +806,30 @@ impl ProcessControlBlock { // 将数据拷贝到用户空间 let write_size = core::cmp::min(actual_size, user_size); if write_size > 0 { - // 将结构体视为字节切片进行拷贝 + // TODO: 实现用户空间数据拷贝 + // 需要使用 UserBufferWriter 将 info 结构体拷贝到 _datavp let _info_bytes = unsafe { core::slice::from_raw_parts(&info as *const _ as *const u8, write_size) }; // datavp.write_bytes(info_bytes)?; } // 无论拷贝多少,都返回内核准备好的完整数据大小 + // 注意:当前返回的大小是正确的,但数据内容是空的(因为使用TrapFrame::new()) Ok(actual_size as isize) } /// 处理PTRACE_SINGLESTEP请求 + /// # 未实现 + /// - CPU层面的单步执行标志设置(x86_64的EFLAGS.TF位) + #[allow(dead_code)] pub fn single_step(&self) -> Result { // 设置单步执行标志 self.flags().insert(ProcessFlags::TRACE_SINGLESTEP); self.flags().remove(ProcessFlags::TRACE_SYSCALL); - // 在CPU层面启用单步执行 + // TODO: 在CPU层面启用单步执行 + // 需要设置x86_64的EFLAGS.TF (Trap Flag) 位 + // 参考: Linux arch/x86/kernel/ptrace.c::user_enable_single_step() // if let Some(context) = self.context_mut() { // context.enable_single_step(); // } @@ -823,9 +860,18 @@ impl ProcessControlBlock { Ok(0) } - /// 启用单步执行 + /// 启用单步执行功能 + /// # TODO + /// 需要实现架构特定的CPU标志设置: + /// - **x86_64**: 设置 EFLAGS.TF (Trap Flag, bit 8) + /// - **RISC-V**: 设置 sstatus.SSTEP + /// - **ARM64**: 设置 MDSCR_EL1.SS + /// + /// 参考: + /// - https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/kernel/step.c#217 + #[allow(dead_code)] pub fn enable_single_step(&self) { - // 实际实现中需要设置CPU标志 + unimplemented!() } /// 启用系统调用跟踪 @@ -833,18 +879,25 @@ impl ProcessControlBlock { self.flags().insert(ProcessFlags::TRACE_SYSCALL); } - /// 在系统调用入口处理 + /// 在系统调用入口处调用 + #[allow(dead_code)] pub fn on_syscall_entry(&self, _num: usize, _args: &[usize]) { - // 实际实现中需要记录系统调用信息 + // TODO: 记录系统调用入口信息 } - /// 在系统调用出口处理 + /// 在系统调用出口处调用 + #[allow(dead_code)] pub fn on_syscall_exit(&self, _result: isize) { - // 实际实现中需要记录系统调用结果 + // TODO: 记录系统调用出口信息 } /// 处理 PTRACE_PEEKUSER 请求 + /// 在Linux中,此函数读取 tracee 的 "USER" 区域数据,主要包含: + /// - 寄存器值(通过偏移量访问) + /// - 特殊值如调试寄存器 + #[allow(dead_code)] pub fn peek_user(&self, _addr: usize) -> Result { + // 未实现注释掉的代码: // // 验证地址是否在用户空间范围内 // if !self.memory.is_user_address(addr) { // return Err(SystemError::EFAULT); @@ -872,6 +925,7 @@ impl ProcessControlBlock { } /// 清空待处理信号 + #[allow(dead_code)] pub fn clear_ptrace(&self) { let mut ptrace_state = self.ptrace_state.lock(); diff --git a/kernel/src/process/syscall/sys_exit_group.rs b/kernel/src/process/syscall/sys_exit_group.rs index f0246fc77..cc25a7b95 100644 --- a/kernel/src/process/syscall/sys_exit_group.rs +++ b/kernel/src/process/syscall/sys_exit_group.rs @@ -1,6 +1,6 @@ use crate::arch::interrupt::TrapFrame; use crate::arch::syscall::nr::SYS_EXIT_GROUP; -use crate::process::{ProcessFlags, ProcessManager}; +use crate::process::ProcessManager; use crate::syscall::table::{FormattedSyscallParam, Syscall}; use alloc::vec::Vec; use system_error::SystemError; @@ -20,9 +20,6 @@ impl Syscall for SysExitGroup { fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { let exit_code = Self::exit_code(args); - let pcb = ProcessManager::current_pcb(); - let has_pending = pcb.flags().contains(ProcessFlags::HAS_PENDING_SIGNAL); - let ptraced = pcb.flags().contains(ProcessFlags::PTRACED); // 仿照 Linux sys_exit_group:只取低 8 位并左移 8 位,形成 wstatus 编码, // 然后触发线程组整体退出。 ProcessManager::group_exit((exit_code & 0xff) << 8); diff --git a/kernel/src/process/syscall/sys_ptrace.rs b/kernel/src/process/syscall/sys_ptrace.rs index a01ee6822..867d9619e 100644 --- a/kernel/src/process/syscall/sys_ptrace.rs +++ b/kernel/src/process/syscall/sys_ptrace.rs @@ -5,6 +5,7 @@ use crate::{ syscall::nr::{SYS_EXIT, SYS_PTRACE}, MMArch, }, + ipc::signal_types::PosixSigInfo, mm::{MemoryManagementArch, PhysAddr, VirtAddr}, process::{ syscall::sys_exit::SysExit, ProcessControlBlock, ProcessFlags, ProcessManager, @@ -60,6 +61,7 @@ impl user_regs_struct { /// # Safety /// /// 调用者必须确保 trap_frame 指向的内存有效 + #[allow(dead_code)] pub unsafe fn from_trap_frame_extra( trap_frame: &TrapFrame, fs_base: u64, @@ -130,6 +132,7 @@ impl TryFrom for PtraceRequest { /// /// # Safety /// 调用者必须确保 tracee 在访问期间不会被销毁 +#[allow(dead_code)] fn ptrace_access_vm(tracee: &Arc, f: F) -> Result where F: FnOnce() -> Result, @@ -299,6 +302,7 @@ impl SysPtrace { } /// 处理 PTRACE_SYSCALL 请求(在系统调用入口和出口暂停) + #[allow(dead_code)] fn handle_syscall(tracee: &Arc) -> Result { // 检查调用者是否是该进程的跟踪器 let tracer_pid = ProcessManager::current_pcb().raw_pid(); @@ -312,6 +316,7 @@ impl SysPtrace { } /// 处理 PTRACE_SETOPTIONS 请求(设置跟踪选项) + #[allow(dead_code)] fn handle_set_options( tracee: &Arc, data: usize, @@ -324,7 +329,11 @@ impl SysPtrace { } /// 处理 PTRACE_GETSIGINFO 请求(获取信号信息) - fn handle_get_siginfo(tracee: &Arc) -> Result { + #[allow(dead_code)] + fn handle_get_siginfo( + tracee: &Arc, + data: usize, + ) -> Result { // 读取 last_siginfo 并拷贝到用户空间 let siginfo = tracee .ptrace_state @@ -332,9 +341,9 @@ impl SysPtrace { .last_siginfo() .ok_or(SystemError::EINVAL)?; - // TODO: 将 siginfo 拷贝到用户空间的 data 参数指向的地址 - // 目前返回成功,表示 siginfo 存在 - // 完整实现需要:将 siginfo 转换为 PosixSigInfo 格式并拷贝到用户空间 + // 将 siginfo 转换为 PosixSigInfo 格式并拷贝到用户空间 + let uinfo = data as *mut PosixSigInfo; + siginfo.copy_posix_siginfo_to_user(uinfo)?; log::debug!("PTRACE_GETSIGINFO: siginfo={:?}", siginfo); Ok(0) } @@ -376,6 +385,7 @@ impl SysPtrace { } /// 处理 PTRACE_SINGLESTEP 请求 (单步执行) + #[allow(dead_code)] fn handle_single_step(tracee: &Arc) -> Result { // 检查调用者是否是该进程的跟踪器 let tracer_pid = ProcessManager::current_pcb().raw_pid(); @@ -474,6 +484,7 @@ impl SysPtrace { } // 在系统调用处理之前 + #[allow(dead_code)] fn before_handle_syscall(num: usize, args: &[usize]) { let current = ProcessManager::current_pcb(); // 检查进程是否被跟踪并且启用了系统调用跟踪 @@ -490,7 +501,8 @@ impl SysPtrace { } // 在系统调用处理之后 - fn after_handle_syscall(num: usize, result: isize) { + #[allow(dead_code)] + fn after_handle_syscall(_num: usize, result: isize) { let current = ProcessManager::current_pcb(); // 检查进程是否被跟踪并且启用了系统调用跟踪 if current @@ -506,6 +518,7 @@ impl SysPtrace { } // 在系统调用分发函数中 + #[allow(dead_code)] fn dispatch_syscall( num: usize, args: &[usize], @@ -524,6 +537,7 @@ impl SysPtrace { Ok(result) } + #[allow(dead_code)] fn ptrace_check_attach( tracee: &Arc, _request: PtraceRequest, @@ -589,7 +603,7 @@ impl Syscall for SysPtrace { // 设置跟踪选项 PtraceRequest::Setoptions => Self::handle_set_options(&tracee, data)?, // 获取信号信息 - PtraceRequest::Getsiginfo => Self::handle_get_siginfo(&tracee)?, + PtraceRequest::Getsiginfo => Self::handle_get_siginfo(&tracee, data)?, // PTRACE_SEIZE:现代 API,不发送 SIGSTOP PtraceRequest::Seize => Self::handle_seize(&tracer, pid, addr)?, // 其他请求类型 diff --git a/user/apps/tests/syscall/gvisor/blocklists/wait_test b/user/apps/tests/syscall/gvisor/blocklists/wait_test index b953b1bcb..ed8934816 100644 --- a/user/apps/tests/syscall/gvisor/blocklists/wait_test +++ b/user/apps/tests/syscall/gvisor/blocklists/wait_test @@ -1,7 +1,5 @@ WaitTest.Wait4Rusage WaitTest.WaitidRusage -# 缺少 SYS_PTRACE -WaitTest.TraceeWALL # 卡死 Waiters/WaitAnyChildTest.WaitedChildRusage/* Waiters/WaitAnyChildTest.IgnoredChildRusage/* From 0c969d7aa6a31796f8282a859f8ce995e2b89e67 Mon Sep 17 00:00:00 2001 From: aLinChe <1129332011@qq.com> Date: Wed, 14 Jan 2026 22:56:01 +0800 Subject: [PATCH 12/15] update SigCode Signed-off-by: aLinChe <1129332011@qq.com> --- kernel/src/arch/x86_64/mm/fault.rs | 26 +++++----- kernel/src/ipc/signal_types.rs | 79 ++++++++++++++++++++++++------ kernel/src/process/ptrace.rs | 29 +++++++---- 3 files changed, 97 insertions(+), 37 deletions(-) diff --git a/kernel/src/arch/x86_64/mm/fault.rs b/kernel/src/arch/x86_64/mm/fault.rs index d12ac4c57..f50f0a560 100644 --- a/kernel/src/arch/x86_64/mm/fault.rs +++ b/kernel/src/arch/x86_64/mm/fault.rs @@ -11,7 +11,7 @@ use crate::{ CurrentIrqArch, MMArch, }, exception::{extable::ExceptionTableManager, InterruptArch}, - ipc::signal_types::{OriginCode, SigCode, SigInfo, SigType}, + ipc::signal_types::{BusCode, SegvCode, SigCode, SigFaultInfo, SigInfo, SigType}, mm::{ fault::{FaultFlags, PageFaultHandler, PageFaultMessage}, ucontext::{AddressSpace, LockedVMA}, @@ -278,12 +278,14 @@ impl X86_64MMArch { let send_segv = || { let pid = ProcessManager::current_pid(); - let uid = ProcessManager::current_pcb().cred().uid.data() as u32; let mut info = SigInfo::new( Signal::SIGSEGV, 0, - SigCode::Origin(OriginCode::User), - SigType::Kill { pid, uid }, + SigCode::Segv(SegvCode::MapErr), + SigType::SigFault(SigFaultInfo { + addr: address.data(), + trapno: 14, // X86_TRAP_PF + }), ); Signal::SIGSEGV .send_signal_info(Some(&mut info), pid) @@ -463,21 +465,21 @@ impl X86_64MMArch { } // 用户态 fault:发送对应信号 - let sig = if fault.contains(VmFaultReason::VM_FAULT_SIGSEGV) { - Signal::SIGSEGV + let (sig, code) = if fault.contains(VmFaultReason::VM_FAULT_SIGSEGV) { + (Signal::SIGSEGV, SigCode::Segv(SegvCode::MapErr)) } else { // 包括 SIGBUS / OOM / HWPOISON 等:目前统一 SIGBUS(后续可按 Linux 进一步细分) - Signal::SIGBUS + (Signal::SIGBUS, SigCode::Bus(BusCode::AdrErr)) }; let mut info = SigInfo::new( sig, 0, - SigCode::Origin(OriginCode::User), - SigType::Kill { - pid: ProcessManager::current_pid(), - uid: ProcessManager::current_pcb().cred().uid.data() as u32, - }, + code, + SigType::SigFault(SigFaultInfo { + addr: address.data(), + trapno: 14, // X86_TRAP_PF + }), ); let _ = sig.send_signal_info(Some(&mut info), ProcessManager::current_pid()); return; diff --git a/kernel/src/ipc/signal_types.rs b/kernel/src/ipc/signal_types.rs index c5e8e6436..44602ef16 100644 --- a/kernel/src/ipc/signal_types.rs +++ b/kernel/src/ipc/signal_types.rs @@ -24,9 +24,17 @@ pub enum SigCode { /// 描述 SIGCHLD 的具体原因 SigChld(ChldCode), /// 描述 SIGTRAP 的具体原因 (TRAP_*) - SigFault(SigFaultInfo), - /// 描述 SIGILL/SIGFPE/SIGSEGV/SIGBUS 的原因 + Trap(TrapCode), + /// 描述 SIGILL 的原因 Ill(IllCode), + /// 描述 SIGFPE 的原因 + Fpe(FpeCode), + /// 描述 SIGSEGV 的原因 + Segv(SegvCode), + /// 描述 SIGBUS 的原因 + Bus(BusCode), + /// 其他未分类的 si_code (如 ptrace event 生成的 (event<<8)|SIGTRAP) + Raw(i32), } impl From for i32 { @@ -34,8 +42,12 @@ impl From for i32 { match code { SigCode::Origin(origin) => origin as i32, SigCode::SigChld(chld) => chld as i32, - SigCode::SigFault(fault) => fault.trapno, + SigCode::Trap(trap) => trap as i32, SigCode::Ill(ill) => ill as i32, + SigCode::Fpe(fpe) => fpe as i32, + SigCode::Segv(segv) => segv as i32, + SigCode::Bus(bus) => bus as i32, + SigCode::Raw(raw) => raw, } } } @@ -98,10 +110,22 @@ pub enum TrapCode { #[derive(Copy, Debug, Clone, PartialEq, Eq)] #[repr(i32)] pub enum IllCode { - /// 非法代码错误 - IllIll = 1, - /// 汇编指令的 operand 不存在 - IllIlladr = 2, + /// 非法操作码 (Illegal Opcode) + IllOpC = 1, + /// 非法操作数 (Illegal Operand) + IllOpN = 2, + /// 非法寻址模式 (Illegal Addressing Mode) + IllAdr = 3, + /// 非法陷阱 (Illegal Trap) + IllTrp = 4, + /// 特权操作码 (Privileged Opcode) + PrvOpC = 5, + /// 特权寄存器 (Privileged Register) + PrvReg = 6, + /// 协处理器错误 (Coprocessor Error) + CoProc = 7, + /// 内部堆栈错误 (Internal Stack Error) + BadStk = 8, } /// SIGFPE si_codes @@ -109,15 +133,38 @@ pub enum IllCode { #[repr(i32)] #[allow(dead_code)] pub enum FpeCode { - IntDiv = 1, /* integer divide by zero */ - IntoOvf = 2, /* integer overflow */ - FltDiv = 3, /* floating point divide by zero */ - FltOvf = 4, /* floating point overflow */ - FltUnd = 5, /* floating point underflow */ - FltInv = 6, /* floating point invalid operation */ - FltSub = 7, /* subscript out of range */ - FltDive = 8, /* floating point division by zero */ - Isock = 9, /* Invalid socket operation */ + IntDiv = 1, /* integer divide by zero */ + IntOvf = 2, /* integer overflow */ + FltDiv = 3, /* floating point divide by zero */ + FltOvf = 4, /* floating point overflow */ + FltUnd = 5, /* floating point underflow */ + FltRes = 6, /* floating point inexact result */ + FltInv = 7, /* floating point invalid operation */ + FltSub = 8, /* subscript out of range */ +} + +/// SIGSEGV si_codes +#[derive(Copy, Debug, Clone, PartialEq, Eq)] +#[repr(i32)] +#[allow(clippy::enum_variant_names)] +#[allow(dead_code)] +pub enum SegvCode { + MapErr = 1, /* address not mapped to object */ + AccErr = 2, /* invalid permissions for mapped object */ + BndErr = 3, /* failed address bound checks */ + PkuErr = 4, /* access was denied by memory protection keys */ +} + +/// SIGBUS si_codes +#[derive(Copy, Debug, Clone, PartialEq, Eq)] +#[repr(i32)] +#[allow(dead_code)] +pub enum BusCode { + AdrAln = 1, /* invalid address alignment */ + AdrErr = 2, /* non-existent physical address */ + ObjErr = 3, /* object specific hardware error */ + MceErrAr = 4, /* hardware memory error consumed on a machine check: action required */ + MceErrAo = 5, /* hardware memory error detected in process but not consumed: action optional */ } impl SigCode { diff --git a/kernel/src/process/ptrace.rs b/kernel/src/process/ptrace.rs index 1b2bbfc2f..102b27c7c 100644 --- a/kernel/src/process/ptrace.rs +++ b/kernel/src/process/ptrace.rs @@ -2,7 +2,7 @@ use crate::arch::interrupt::TrapFrame; use crate::arch::ipc::signal::{SigFlags, Signal}; use crate::arch::kprobe; use crate::ipc::signal_types::{ - ChldCode, OriginCode, SigChldInfo, SigCode, SigFaultInfo, SigInfo, SigType, + ChldCode, OriginCode, SigChldInfo, SigCode, SigFaultInfo, SigInfo, SigType, TrapCode, }; use crate::process::cred; use crate::process::{ @@ -190,19 +190,30 @@ impl ProcessControlBlock { ) -> Result<(), SystemError> { let current_pcb = ProcessManager::current_pcb(); - let fault_info = SigFaultInfo { - addr: 0, - trapno: exit_code as i32, // si_code = exit_code (通过 trapno) + // 构造 Raw code (si_code = exit_code & 0xff) + // Linux 中 ptrace_notify 使用 (exit_code & 0xff) 作为 si_code + // 通常是 SIGTRAP | (PTRACE_EVENT_xxx << 8) + let si_code = (exit_code >> 8) as i32; + + // 如果是标准的 TRAP_* 代码,使用 TrapCode + let code = match si_code { + 1 => SigCode::Trap(TrapCode::Brkpt), + 2 => SigCode::Trap(TrapCode::Trace), + 3 => SigCode::Trap(TrapCode::Branch), + 4 => SigCode::Trap(TrapCode::Hwbkpt), + 5 => SigCode::Trap(TrapCode::Unk), + 6 => SigCode::Trap(TrapCode::Perf), + _ => SigCode::Raw(si_code), }; let mut info = SigInfo::new( signal, // si_signo = SIGTRAP 0, // si_errno = 0 - SigCode::SigFault(fault_info), - SigType::Kill { - pid: current_pcb.raw_pid(), - uid: current_pcb.cred().uid.data() as u32, - }, + code, + SigType::SigFault(SigFaultInfo { + addr: 0, + trapno: exit_code as i32, // trapno 暂时用来存完整 exit_code + }), ); current_pcb.ptrace_stop(exit_code, ChldCode::Trapped, Some(&mut info)); Ok(()) From e82c603ac9c7632ca35f9506a989398dc68910b6 Mon Sep 17 00:00:00 2001 From: aLinChe <1129332011@qq.com> Date: Wed, 14 Jan 2026 23:41:40 +0800 Subject: [PATCH 13/15] update Signed-off-by: aLinChe <1129332011@qq.com> --- kernel/src/process/mod.rs | 2 -- kernel/src/process/syscall/sys_ptrace.rs | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index d0c655ab4..b61c29b86 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -504,7 +504,6 @@ impl ProcessManager { } let parent_pcb = r.unwrap(); - // 按照 Linux 6.6.21 的语义: // 如果进程被 ptrace,忽略 exit_signal,总是发送 SIGCHLD let is_ptraced = current.flags().contains(ProcessFlags::PTRACED); let signal_to_send = if is_ptraced { @@ -1307,7 +1306,6 @@ pub struct ProcessControlBlock { sig_altstack: RwLock, /// 退出状态(Running/Zombie/Dead) exit_state: AtomicU8, - /// 退出信号S exit_signal: AtomicSignal, /// 父进程退出时要发送给当前进程的信号(PR_SET_PDEATHSIG) diff --git a/kernel/src/process/syscall/sys_ptrace.rs b/kernel/src/process/syscall/sys_ptrace.rs index 867d9619e..efcfb1684 100644 --- a/kernel/src/process/syscall/sys_ptrace.rs +++ b/kernel/src/process/syscall/sys_ptrace.rs @@ -142,7 +142,7 @@ where // 获取目标进程的地址空间锁,但不切换页表 // 只需要在地址空间读锁保护下执行操作 - let _tracee_vm_guard = tracee_vm.read_irqsave(); + let _tracee_vm_guard = tracee_vm.read(); // 在目标进程的地址空间读锁保护中执行操作 f() @@ -154,7 +154,7 @@ where /// 参考 process_vm_readv 的实现方式。 fn ptrace_peek_data(tracee: &Arc, addr: usize) -> Result { let tracee_vm = tracee.basic().user_vm().ok_or(SystemError::ESRCH)?; - let tracee_vm_guard = tracee_vm.read_irqsave(); + let tracee_vm_guard = tracee_vm.read(); let tracee_addr = VirtAddr::new(addr); @@ -200,7 +200,7 @@ fn ptrace_poke_data( data: usize, ) -> Result { let tracee_vm = tracee.basic().user_vm().ok_or(SystemError::ESRCH)?; - let tracee_vm_guard = tracee_vm.read_irqsave(); + let tracee_vm_guard = tracee_vm.read(); let tracee_addr = VirtAddr::new(addr); From c199abee37e31a425c6b76c89d47c9ed8d4e6705 Mon Sep 17 00:00:00 2001 From: aLinChe <1129332011@qq.com> Date: Thu, 15 Jan 2026 13:26:25 +0800 Subject: [PATCH 14/15] fix gvisor bug and fix arch bug Signed-off-by: aLinChe <1129332011@qq.com> --- kernel/src/arch/loongarch64/interrupt/mod.rs | 113 +++++++++++++++ kernel/src/arch/loongarch64/kprobe.rs | 133 +++++++++++++++++- kernel/src/arch/riscv64/interrupt/mod.rs | 123 ++++++++++++++++ kernel/src/arch/riscv64/kprobe.rs | 40 ++++++ kernel/src/arch/x86_64/interrupt/mod.rs | 133 ++++++++++++++++++ kernel/src/process/exit.rs | 26 ++-- kernel/src/process/ptrace.rs | 5 +- kernel/src/process/syscall/sys_ptrace.rs | 120 +--------------- .../tests/syscall/gvisor/blocklists/fork_test | 2 + 9 files changed, 565 insertions(+), 130 deletions(-) diff --git a/kernel/src/arch/loongarch64/interrupt/mod.rs b/kernel/src/arch/loongarch64/interrupt/mod.rs index bf9ba32c0..950312043 100644 --- a/kernel/src/arch/loongarch64/interrupt/mod.rs +++ b/kernel/src/arch/loongarch64/interrupt/mod.rs @@ -141,3 +141,116 @@ impl crate::process::rseq::RseqTrapFrame for TrapFrame { self.csr_era = ip; } } + +/// Linux 兼容的用户寄存器结构体 (LoongArch64) +/// +/// 严格按照 Linux 6.6.21 的 `arch/loongarch/include/uapi/asm/ptrace.h` 中的 +/// +/// 该结构体用于 ptrace 系统调用向用户空间暴露寄存器信息。 +/// +/// 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/include/uapi/asm/ptrace.h#30 +#[repr(C, align(8))] +#[derive(Debug, Clone, Copy, Default)] +pub struct UserRegsStruct { + /// 主处理器寄存器 (r0-r31) + pub regs: [u64; 32], + /// 原始系统调用参数 a0 + pub orig_a0: u64, + /// CSR ERA (Exception Return Address) + pub csr_era: u64, + /// CSR BADV (Bad Virtual Address) + pub csr_badv: u64, + /// 保留字段 + pub reserved: [u64; 10], +} + +impl UserRegsStruct { + /// 从 TrapFrame 创建 UserRegsStruct + /// + /// 这对应 Linux 中从 pt_regs 构建 user_pt_regs 的过程。 + pub fn from_trap_frame(trap_frame: &TrapFrame) -> Self { + let mut regs = [0u64; 32]; + // 按照 LoongArch 寄存器编号映射 + regs[0] = trap_frame.r0 as u64; + regs[1] = trap_frame.ra as u64; + regs[2] = trap_frame.tp as u64; + regs[3] = trap_frame.usp as u64; + regs[4] = trap_frame.a0 as u64; + regs[5] = trap_frame.a1 as u64; + regs[6] = trap_frame.a2 as u64; + regs[7] = trap_frame.a3 as u64; + regs[8] = trap_frame.a4 as u64; + regs[9] = trap_frame.a5 as u64; + regs[10] = trap_frame.a6 as u64; + regs[11] = trap_frame.a7 as u64; + regs[12] = trap_frame.t0 as u64; + regs[13] = trap_frame.t1 as u64; + regs[14] = trap_frame.t2 as u64; + regs[15] = trap_frame.t3 as u64; + regs[16] = trap_frame.t4 as u64; + regs[17] = trap_frame.t5 as u64; + regs[18] = trap_frame.t6 as u64; + regs[19] = trap_frame.t7 as u64; + regs[20] = trap_frame.t8 as u64; + regs[21] = trap_frame.r21 as u64; + regs[22] = trap_frame.fp as u64; + regs[23] = trap_frame.s0 as u64; + regs[24] = trap_frame.s1 as u64; + regs[25] = trap_frame.s2 as u64; + regs[26] = trap_frame.s3 as u64; + regs[27] = trap_frame.s4 as u64; + regs[28] = trap_frame.s5 as u64; + regs[29] = trap_frame.s6 as u64; + regs[30] = trap_frame.s7 as u64; + regs[31] = trap_frame.s8 as u64; + + Self { + regs, + orig_a0: trap_frame.orig_a0 as u64, + csr_era: trap_frame.csr_era as u64, + csr_badv: trap_frame.csr_badvaddr as u64, + reserved: [0; 10], + } + } + + /// 将 UserRegsStruct 的值写回 TrapFrame + /// + /// 用于 PTRACE_SETREGS 操作,允许调试器修改被跟踪进程的寄存器。 + pub fn write_to_trap_frame(&self, trap_frame: &mut TrapFrame) { + trap_frame.r0 = self.regs[0] as usize; + trap_frame.ra = self.regs[1] as usize; + trap_frame.tp = self.regs[2] as usize; + trap_frame.usp = self.regs[3] as usize; + trap_frame.a0 = self.regs[4] as usize; + trap_frame.a1 = self.regs[5] as usize; + trap_frame.a2 = self.regs[6] as usize; + trap_frame.a3 = self.regs[7] as usize; + trap_frame.a4 = self.regs[8] as usize; + trap_frame.a5 = self.regs[9] as usize; + trap_frame.a6 = self.regs[10] as usize; + trap_frame.a7 = self.regs[11] as usize; + trap_frame.t0 = self.regs[12] as usize; + trap_frame.t1 = self.regs[13] as usize; + trap_frame.t2 = self.regs[14] as usize; + trap_frame.t3 = self.regs[15] as usize; + trap_frame.t4 = self.regs[16] as usize; + trap_frame.t5 = self.regs[17] as usize; + trap_frame.t6 = self.regs[18] as usize; + trap_frame.t7 = self.regs[19] as usize; + trap_frame.t8 = self.regs[20] as usize; + trap_frame.r21 = self.regs[21] as usize; + trap_frame.fp = self.regs[22] as usize; + trap_frame.s0 = self.regs[23] as usize; + trap_frame.s1 = self.regs[24] as usize; + trap_frame.s2 = self.regs[25] as usize; + trap_frame.s3 = self.regs[26] as usize; + trap_frame.s4 = self.regs[27] as usize; + trap_frame.s5 = self.regs[28] as usize; + trap_frame.s6 = self.regs[29] as usize; + trap_frame.s7 = self.regs[30] as usize; + trap_frame.s8 = self.regs[31] as usize; + trap_frame.orig_a0 = self.orig_a0 as usize; + trap_frame.csr_era = self.csr_era as usize; + trap_frame.csr_badvaddr = self.csr_badv as usize; + } +} diff --git a/kernel/src/arch/loongarch64/kprobe.rs b/kernel/src/arch/loongarch64/kprobe.rs index 1d85e6d9d..04173e4d4 100644 --- a/kernel/src/arch/loongarch64/kprobe.rs +++ b/kernel/src/arch/loongarch64/kprobe.rs @@ -1,19 +1,144 @@ use crate::arch::interrupt::TrapFrame; pub fn setup_single_step(frame: &mut TrapFrame, step_addr: usize) { - todo!("la64: setup_single_step") + // LoongArch64 单步调试需要设置 CSR.FWPS 寄存器 + // 目前先设置 PC 到目标地址 + frame.csr_era = step_addr; } pub fn clear_single_step(frame: &mut TrapFrame, return_addr: usize) { - todo!("la64: clear_single_step") + // 清除单步调试状态并设置返回地址 + frame.csr_era = return_addr; } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct KProbeContext {} +pub struct KProbeContext { + pub r0: usize, + pub ra: usize, + pub tp: usize, + pub sp: usize, + pub a0: usize, + pub a1: usize, + pub a2: usize, + pub a3: usize, + pub a4: usize, + pub a5: usize, + pub a6: usize, + pub a7: usize, + pub t0: usize, + pub t1: usize, + pub t2: usize, + pub t3: usize, + pub t4: usize, + pub t5: usize, + pub t6: usize, + pub t7: usize, + pub t8: usize, + pub r21: usize, + pub fp: usize, + pub s0: usize, + pub s1: usize, + pub s2: usize, + pub s3: usize, + pub s4: usize, + pub s5: usize, + pub s6: usize, + pub s7: usize, + pub s8: usize, + pub orig_a0: usize, + pub csr_era: usize, + pub csr_badvaddr: usize, + pub csr_crmd: usize, + pub csr_prmd: usize, + pub csr_euen: usize, + pub csr_ecfg: usize, + pub csr_estat: usize, +} impl From<&TrapFrame> for KProbeContext { fn from(trap_frame: &TrapFrame) -> Self { - todo!("from trap frame to kprobe context"); + Self { + r0: trap_frame.r0, + ra: trap_frame.ra, + tp: trap_frame.tp, + sp: trap_frame.usp, + a0: trap_frame.a0, + a1: trap_frame.a1, + a2: trap_frame.a2, + a3: trap_frame.a3, + a4: trap_frame.a4, + a5: trap_frame.a5, + a6: trap_frame.a6, + a7: trap_frame.a7, + t0: trap_frame.t0, + t1: trap_frame.t1, + t2: trap_frame.t2, + t3: trap_frame.t3, + t4: trap_frame.t4, + t5: trap_frame.t5, + t6: trap_frame.t6, + t7: trap_frame.t7, + t8: trap_frame.t8, + r21: trap_frame.r21, + fp: trap_frame.fp, + s0: trap_frame.s0, + s1: trap_frame.s1, + s2: trap_frame.s2, + s3: trap_frame.s3, + s4: trap_frame.s4, + s5: trap_frame.s5, + s6: trap_frame.s6, + s7: trap_frame.s7, + s8: trap_frame.s8, + orig_a0: trap_frame.orig_a0, + csr_era: trap_frame.csr_era, + csr_badvaddr: trap_frame.csr_badvaddr, + csr_crmd: trap_frame.csr_crmd, + csr_prmd: trap_frame.csr_prmd, + csr_euen: trap_frame.csr_euen, + csr_ecfg: trap_frame.csr_ecfg, + csr_estat: trap_frame.csr_estat, + } } } + +// LoongArch 64-bit 架构标识 (EM_LOONGARCH = 258, 64-bit) +const AUDIT_ARCH_LOONGARCH64: u32 = 0xC000_0102; + +/// 获取当前架构标识 +pub fn syscall_get_arch() -> u32 { + AUDIT_ARCH_LOONGARCH64 +} + +/// 从 KProbeContext 获取指令指针 (csr_era) +pub fn instruction_pointer(ctx: &KProbeContext) -> u64 { + ctx.csr_era as u64 +} + +/// 从 KProbeContext 获取用户栈指针 (sp) +pub fn user_stack_pointer(ctx: &KProbeContext) -> u64 { + ctx.sp as u64 +} + +/// 从 KProbeContext 获取系统调用号 (a7) +/// LoongArch64 使用 a7 寄存器传递系统调用号 +pub fn syscall_get_nr(ctx: &KProbeContext) -> u64 { + ctx.a7 as u64 +} + +/// 从 KProbeContext 获取系统调用返回值 (a0) +pub fn syscall_get_return_value(ctx: &KProbeContext) -> i64 { + ctx.a0 as i64 +} + +/// 从 KProbeContext 获取系统调用的前 6 个参数 +/// LoongArch64 使用 a0-a5 寄存器传递系统调用参数 +pub fn syscall_get_arguments(ctx: &KProbeContext, args: &mut [u64; 6]) { + args[0] = ctx.a0 as u64; + args[1] = ctx.a1 as u64; + args[2] = ctx.a2 as u64; + args[3] = ctx.a3 as u64; + args[4] = ctx.a4 as u64; + args[5] = ctx.a5 as u64; +} diff --git a/kernel/src/arch/riscv64/interrupt/mod.rs b/kernel/src/arch/riscv64/interrupt/mod.rs index ff5bb5e05..595d309a9 100644 --- a/kernel/src/arch/riscv64/interrupt/mod.rs +++ b/kernel/src/arch/riscv64/interrupt/mod.rs @@ -198,3 +198,126 @@ impl crate::process::rseq::RseqTrapFrame for TrapFrame { self.epc = ip; } } + +/// Linux 兼容的用户寄存器结构体 (RISC-V 64) +/// +/// 该结构体用于 ptrace 系统调用向用户空间暴露寄存器信息。 +/// +/// 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/arch/riscv/include/uapi/asm/ptrace.h#24 +#[repr(C)] +#[derive(Debug, Clone, Copy, Default)] +pub struct UserRegsStruct { + pub pc: u64, + pub ra: u64, + pub sp: u64, + pub gp: u64, + pub tp: u64, + pub t0: u64, + pub t1: u64, + pub t2: u64, + pub s0: u64, + pub s1: u64, + pub a0: u64, + pub a1: u64, + pub a2: u64, + pub a3: u64, + pub a4: u64, + pub a5: u64, + pub a6: u64, + pub a7: u64, + pub s2: u64, + pub s3: u64, + pub s4: u64, + pub s5: u64, + pub s6: u64, + pub s7: u64, + pub s8: u64, + pub s9: u64, + pub s10: u64, + pub s11: u64, + pub t3: u64, + pub t4: u64, + pub t5: u64, + pub t6: u64, +} + +impl UserRegsStruct { + /// 从 TrapFrame 创建 UserRegsStruct + /// + /// 这对应 Linux 中从 pt_regs 构建 user_regs_struct 的过程。 + /// RISC-V 的 user_regs_struct 是 pt_regs 的前缀。 + pub fn from_trap_frame(trap_frame: &TrapFrame) -> Self { + Self { + pc: trap_frame.epc as u64, + ra: trap_frame.ra as u64, + sp: trap_frame.sp as u64, + gp: trap_frame.gp as u64, + tp: trap_frame.tp as u64, + t0: trap_frame.t0 as u64, + t1: trap_frame.t1 as u64, + t2: trap_frame.t2 as u64, + s0: trap_frame.s0 as u64, + s1: trap_frame.s1 as u64, + a0: trap_frame.a0 as u64, + a1: trap_frame.a1 as u64, + a2: trap_frame.a2 as u64, + a3: trap_frame.a3 as u64, + a4: trap_frame.a4 as u64, + a5: trap_frame.a5 as u64, + a6: trap_frame.a6 as u64, + a7: trap_frame.a7 as u64, + s2: trap_frame.s2 as u64, + s3: trap_frame.s3 as u64, + s4: trap_frame.s4 as u64, + s5: trap_frame.s5 as u64, + s6: trap_frame.s6 as u64, + s7: trap_frame.s7 as u64, + s8: trap_frame.s8 as u64, + s9: trap_frame.s9 as u64, + s10: trap_frame.s10 as u64, + s11: trap_frame.s11 as u64, + t3: trap_frame.t3 as u64, + t4: trap_frame.t4 as u64, + t5: trap_frame.t5 as u64, + t6: trap_frame.t6 as u64, + } + } + + /// 将 UserRegsStruct 的值写回 TrapFrame + /// + /// 用于 PTRACE_SETREGS 操作,允许调试器修改被跟踪进程的寄存器。 + pub fn write_to_trap_frame(&self, trap_frame: &mut TrapFrame) { + trap_frame.epc = self.pc as usize; + trap_frame.ra = self.ra as usize; + trap_frame.sp = self.sp as usize; + trap_frame.gp = self.gp as usize; + trap_frame.tp = self.tp as usize; + trap_frame.t0 = self.t0 as usize; + trap_frame.t1 = self.t1 as usize; + trap_frame.t2 = self.t2 as usize; + trap_frame.s0 = self.s0 as usize; + trap_frame.s1 = self.s1 as usize; + trap_frame.a0 = self.a0 as usize; + trap_frame.a1 = self.a1 as usize; + trap_frame.a2 = self.a2 as usize; + trap_frame.a3 = self.a3 as usize; + trap_frame.a4 = self.a4 as usize; + trap_frame.a5 = self.a5 as usize; + trap_frame.a6 = self.a6 as usize; + trap_frame.a7 = self.a7 as usize; + trap_frame.s2 = self.s2 as usize; + trap_frame.s3 = self.s3 as usize; + trap_frame.s4 = self.s4 as usize; + trap_frame.s5 = self.s5 as usize; + trap_frame.s6 = self.s6 as usize; + trap_frame.s7 = self.s7 as usize; + trap_frame.s8 = self.s8 as usize; + trap_frame.s9 = self.s9 as usize; + trap_frame.s10 = self.s10 as usize; + trap_frame.s11 = self.s11 as usize; + trap_frame.t3 = self.t3 as usize; + trap_frame.t4 = self.t4 as usize; + trap_frame.t5 = self.t5 as usize; + trap_frame.t6 = self.t6 as usize; + } +} diff --git a/kernel/src/arch/riscv64/kprobe.rs b/kernel/src/arch/riscv64/kprobe.rs index 960b06cd6..2c7397afc 100644 --- a/kernel/src/arch/riscv64/kprobe.rs +++ b/kernel/src/arch/riscv64/kprobe.rs @@ -83,3 +83,43 @@ impl From<&TrapFrame> for KProbeContext { } } } + +// RISC-V 64-bit 架构标识 (EM_RISCV = 243, 64-bit) +const AUDIT_ARCH_RISCV64: u32 = 0xC000_00F3; + +/// 获取当前架构标识 +pub fn syscall_get_arch() -> u32 { + AUDIT_ARCH_RISCV64 +} + +/// 从 KProbeContext 获取指令指针 (pc) +pub fn instruction_pointer(ctx: &KProbeContext) -> u64 { + ctx.pc as u64 +} + +/// 从 KProbeContext 获取用户栈指针 (sp) +pub fn user_stack_pointer(ctx: &KProbeContext) -> u64 { + ctx.sp as u64 +} + +/// 从 KProbeContext 获取系统调用号 (a7) +/// RISC-V 使用 a7 寄存器传递系统调用号 +pub fn syscall_get_nr(ctx: &KProbeContext) -> u64 { + ctx.a7 as u64 +} + +/// 从 KProbeContext 获取系统调用返回值 (a0) +pub fn syscall_get_return_value(ctx: &KProbeContext) -> i64 { + ctx.a0 as i64 +} + +/// 从 KProbeContext 获取系统调用的前 6 个参数 +/// RISC-V 使用 a0-a5 寄存器传递系统调用参数 +pub fn syscall_get_arguments(ctx: &KProbeContext, args: &mut [u64; 6]) { + args[0] = ctx.a0 as u64; + args[1] = ctx.a1 as u64; + args[2] = ctx.a2 as u64; + args[3] = ctx.a3 as u64; + args[4] = ctx.a4 as u64; + args[5] = ctx.a5 as u64; +} diff --git a/kernel/src/arch/x86_64/interrupt/mod.rs b/kernel/src/arch/x86_64/interrupt/mod.rs index 21335665f..b69b099a0 100644 --- a/kernel/src/arch/x86_64/interrupt/mod.rs +++ b/kernel/src/arch/x86_64/interrupt/mod.rs @@ -253,3 +253,136 @@ impl crate::process::rseq::RseqTrapFrame for TrapFrame { self.rip = ip as u64; } } + +/// Linux 兼容的用户寄存器结构体 (x86_64) +/// +/// 该结构体用于 ptrace 系统调用向用户空间暴露寄存器信息。 +/// +/// 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/include/asm/user_64.h#69 +#[repr(C)] +#[derive(Debug, Clone, Copy, Default)] +pub struct UserRegsStruct { + pub r15: u64, + pub r14: u64, + pub r13: u64, + pub r12: u64, + pub bp: u64, + pub bx: u64, + pub r11: u64, + pub r10: u64, + pub r9: u64, + pub r8: u64, + pub ax: u64, + pub cx: u64, + pub dx: u64, + pub si: u64, + pub di: u64, + /// 在系统调用入口时保存原始的 rax(系统调用号) + pub orig_ax: u64, + pub ip: u64, + pub cs: u64, + pub flags: u64, + pub sp: u64, + pub ss: u64, + /// FS 段基址,来自 task->thread.fsbase + pub fs_base: u64, + /// GS 段基址,来自 task->thread.gsbase + pub gs_base: u64, + /// DS 段选择器 + pub ds: u64, + /// ES 段选择器 + pub es: u64, + /// FS 段选择器 + pub fs: u64, + /// GS 段选择器 + pub gs: u64, +} + +impl UserRegsStruct { + /// 从 TrapFrame 创建 UserRegsStruct + /// + /// 这对应 Linux 中从 pt_regs 构建 user_regs_struct 的过程。 + /// TrapFrame 包含了 pt_regs 的核心字段,额外的段寄存器信息 + /// 需要从进程的 arch_info 中获取。 + /// + /// # 参数 + /// - `trap_frame`: 中断/异常时保存的寄存器状态 + /// - `fs_base`: FS 段基址(来自 task->thread.fsbase) + /// - `gs_base`: GS 段基址(来自 task->thread.gsbase) + /// - `fs`: FS 段选择器(来自 task->thread.fsindex) + /// - `gs`: GS 段选择器(来自 task->thread.gsindex) + pub fn from_trap_frame( + trap_frame: &TrapFrame, + fs_base: u64, + gs_base: u64, + fs: u64, + gs: u64, + ) -> Self { + Self { + r15: trap_frame.r15, + r14: trap_frame.r14, + r13: trap_frame.r13, + r12: trap_frame.r12, + bp: trap_frame.rbp, + bx: trap_frame.rbx, + r11: trap_frame.r11, + r10: trap_frame.r10, + r9: trap_frame.r9, + r8: trap_frame.r8, + ax: trap_frame.rax, + cx: trap_frame.rcx, + dx: trap_frame.rdx, + si: trap_frame.rsi, + di: trap_frame.rdi, + // errcode 在系统调用上下文中存储系统调用号 + orig_ax: trap_frame.errcode, + ip: trap_frame.rip, + cs: trap_frame.cs, + flags: trap_frame.rflags, + sp: trap_frame.rsp, + ss: trap_frame.ss, + fs_base, + gs_base, + // TrapFrame 中的 ds/es 是完整的段选择器值 + ds: trap_frame.ds, + es: trap_frame.es, + fs, + gs, + } + } + + /// 将 UserRegsStruct 的值写回 TrapFrame + /// + /// 用于 PTRACE_SETREGS 操作,允许调试器修改被跟踪进程的寄存器。 + /// + /// # 注意 + /// - fs_base, gs_base, fs, gs 需要单独写回到进程的 arch_info + /// - 某些字段(如 cs, ss)的修改可能受到安全限制 + #[allow(dead_code)] + pub fn write_to_trap_frame(&self, trap_frame: &mut TrapFrame) { + trap_frame.r15 = self.r15; + trap_frame.r14 = self.r14; + trap_frame.r13 = self.r13; + trap_frame.r12 = self.r12; + trap_frame.rbp = self.bp; + trap_frame.rbx = self.bx; + trap_frame.r11 = self.r11; + trap_frame.r10 = self.r10; + trap_frame.r9 = self.r9; + trap_frame.r8 = self.r8; + trap_frame.rax = self.ax; + trap_frame.rcx = self.cx; + trap_frame.rdx = self.dx; + trap_frame.rsi = self.si; + trap_frame.rdi = self.di; + trap_frame.errcode = self.orig_ax; + trap_frame.rip = self.ip; + // cs 和 ss 的修改需要谨慎,这里暂时允许 + trap_frame.cs = self.cs; + trap_frame.rflags = self.flags; + trap_frame.rsp = self.sp; + trap_frame.ss = self.ss; + trap_frame.ds = self.ds; + trap_frame.es = self.es; + } +} diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs index 1cee5aacd..cbf7c385c 100644 --- a/kernel/src/process/exit.rs +++ b/kernel/src/process/exit.rs @@ -321,17 +321,9 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { get_thread_group_leader(¤t) }; loop { - if kwo.options.contains(WaitOption::WNOHANG) { - let rd_children = parent.children.read(); - if rd_children.is_empty() { - break Err(SystemError::ECHILD); - } else { - break Ok(0); - } - } - let mut scan_result: Option> = None; let mut echild = false; + let mut has_eligible_child = false; let wait_res = parent.wait_queue.wait_event_interruptible( || { @@ -359,6 +351,9 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { continue; } + // 找到了符合条件的子进程,标记为有可等待的子进程 + has_eligible_child = true; + let sched_guard = pcb.sched_info().inner_lock_read_irqsave(); let state = sched_guard.state(); if !pcb.is_zombie() { @@ -473,6 +468,9 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { continue; } + // 找到了符合条件的ptrace子进程,标记为有可等待的子进程 + has_eligible_child = true; + let sched_guard = pcb.sched_info().inner_lock_read_irqsave(); let state = sched_guard.state(); if !state.is_exited() { @@ -532,6 +530,11 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { echild = true; return true; } + // 如果没有找到任何符合条件的子进程,返回ECHILD + if !has_eligible_child { + echild = true; + return true; + } false }, None::, @@ -545,6 +548,11 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { if echild { break Err(SystemError::ECHILD); } + // 如果设置了WNOHANG,且没有符合条件的子进程准备好, + // 返回0表示"没有子进程准备好但存在可等待的子进程" + if kwo.options.contains(WaitOption::WNOHANG) { + break Ok(0); + } if ProcessManager::current_pcb().has_pending_signal_fast() { break Err(SystemError::ERESTARTSYS); } diff --git a/kernel/src/process/ptrace.rs b/kernel/src/process/ptrace.rs index 102b27c7c..ace62ae8a 100644 --- a/kernel/src/process/ptrace.rs +++ b/kernel/src/process/ptrace.rs @@ -11,6 +11,7 @@ use crate::process::{ PtraceSyscallInfoEntry, PtraceSyscallInfoExit, PtraceSyscallInfoOp, RawPid, }; use crate::sched::{schedule, EnqueueFlag, SchedMode, WakeupFlags}; +use ::kprobe::ProbeArgs; use alloc::{sync::Arc, vec::Vec}; use core::{intrinsics::unlikely, mem::MaybeUninit}; use system_error::SystemError; @@ -684,7 +685,9 @@ impl ProcessControlBlock { PtraceRequest::Syscall => self.flags().insert(ProcessFlags::TRACE_SYSCALL), PtraceRequest::Singlestep => { self.flags().insert(ProcessFlags::TRACE_SINGLESTEP); - kprobe::setup_single_step(frame, frame.rip as usize); // 设置 TF 标志 + // 使用架构无关的方式获取指令指针 + let step_addr = frame.break_address(); + kprobe::setup_single_step(frame, step_addr); } _ => {} // PTRACE_CONT 不需要特殊标志 } diff --git a/kernel/src/process/syscall/sys_ptrace.rs b/kernel/src/process/syscall/sys_ptrace.rs index efcfb1684..0a5bb1192 100644 --- a/kernel/src/process/syscall/sys_ptrace.rs +++ b/kernel/src/process/syscall/sys_ptrace.rs @@ -1,6 +1,6 @@ use crate::{ arch::{ - interrupt::TrapFrame, + interrupt::{TrapFrame, UserRegsStruct}, ipc::signal::Signal, syscall::nr::{SYS_EXIT, SYS_PTRACE}, MMArch, @@ -20,85 +20,6 @@ use alloc::sync::Arc; use alloc::vec::Vec; use system_error::SystemError; -/// Linux 兼容的用户寄存器结构体 (x86_64) -/// 参考 /usr/include/x86_64-linux-gnu/sys/user.h -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct user_regs_struct { - pub r15: u64, - pub r14: u64, - pub r13: u64, - pub r12: u64, - pub rbp: u64, - pub rbx: u64, - pub r11: u64, - pub r10: u64, - pub r9: u64, - pub r8: u64, - pub rax: u64, - pub rcx: u64, - pub rdx: u64, - pub rsi: u64, - pub rdi: u64, - pub orig_rax: u64, - pub rip: u64, - pub cs: u64, - pub eflags: u64, - pub rsp: u64, - pub ss: u64, - pub fs_base: u64, - pub gs_base: u64, - pub ds: u64, - pub es: u64, - pub fs: u64, - pub gs: u64, -} - -/// 从 TrapFrame 和额外的寄存器信息构建 user_regs_struct -impl user_regs_struct { - /// 从 TrapFrame 转换,需要提供 fs_base 和 gs_base - /// - /// # Safety - /// - /// 调用者必须确保 trap_frame 指向的内存有效 - #[allow(dead_code)] - pub unsafe fn from_trap_frame_extra( - trap_frame: &TrapFrame, - fs_base: u64, - gs_base: u64, - ) -> Self { - Self { - r15: trap_frame.r15, - r14: trap_frame.r14, - r13: trap_frame.r13, - r12: trap_frame.r12, - rbp: trap_frame.rbp, - rbx: trap_frame.rbx, - r11: trap_frame.r11, - r10: trap_frame.r10, - r9: trap_frame.r9, - r8: trap_frame.r8, - rax: trap_frame.rax, - rcx: trap_frame.rcx, - rdx: trap_frame.rdx, - rsi: trap_frame.rsi, - rdi: trap_frame.rdi, - orig_rax: trap_frame.errcode, // syscall number - rip: trap_frame.rip, - cs: trap_frame.cs, - eflags: trap_frame.rflags, - rsp: trap_frame.rsp, - ss: trap_frame.ss, - fs_base, - gs_base, - ds: 0, - es: 0, - fs: 0, - gs: 0, - } - } -} - impl TryFrom for PtraceRequest { type Error = SystemError; @@ -420,7 +341,6 @@ impl SysPtrace { // 获取 fs_base、gs_base 和段选择器 // - fs_base/gs_base: task->thread.fsbase/gsbase // - fs/gs: task->thread.fsindex/gsindex - // - ds/es: task->thread.ds/es 或 pt_regs->ds/es let arch_info = tracee.arch_info_irqsave(); let fs_base = arch_info.fsbase() as u64; let gs_base = arch_info.gsbase() as u64; @@ -428,45 +348,13 @@ impl SysPtrace { let gs = arch_info.gs() as u64; drop(arch_info); - // TrapFrame 包含 ds 和 es(对应 pt_regs->ds/es) - let ds = trap_frame.ds as u64; - let es = trap_frame.es as u64; - - // 构造用户态寄存器结构体 - let user_regs = user_regs_struct { - r15: trap_frame.r15, - r14: trap_frame.r14, - r13: trap_frame.r13, - r12: trap_frame.r12, - rbp: trap_frame.rbp, - rbx: trap_frame.rbx, - r11: trap_frame.r11, - r10: trap_frame.r10, - r9: trap_frame.r9, - r8: trap_frame.r8, - rax: trap_frame.rax, - rcx: trap_frame.rcx, - rdx: trap_frame.rdx, - rsi: trap_frame.rsi, - rdi: trap_frame.rdi, - orig_rax: trap_frame.errcode, // syscall number - rip: trap_frame.rip, - cs: trap_frame.cs, - eflags: trap_frame.rflags, - rsp: trap_frame.rsp, - ss: trap_frame.ss, - fs_base, - gs_base, - ds, - es, - fs, - gs, - }; + // 使用 UserRegsStruct::from_trap_frame 构造用户态寄存器结构体 + let user_regs = UserRegsStruct::from_trap_frame(trap_frame, fs_base, gs_base, fs, gs); // 拷贝到用户空间 let mut writer = UserBufferWriter::new( data as *mut u8, - core::mem::size_of::(), + core::mem::size_of::(), true, )?; writer.copy_one_to_user(&user_regs, 0)?; diff --git a/user/apps/tests/syscall/gvisor/blocklists/fork_test b/user/apps/tests/syscall/gvisor/blocklists/fork_test index 6c86ead40..adec90902 100644 --- a/user/apps/tests/syscall/gvisor/blocklists/fork_test +++ b/user/apps/tests/syscall/gvisor/blocklists/fork_test @@ -1 +1,3 @@ +# 未实现 SYS_SCHED_SETAFFINITY ForkTest.Affinity + From 5a8d3e60a05653216b3c98c9a624595ed8720f57 Mon Sep 17 00:00:00 2001 From: aLinChe <1129332011@qq.com> Date: Thu, 15 Jan 2026 13:49:00 +0800 Subject: [PATCH 15/15] use conditional compile Signed-off-by: aLinChe <1129332011@qq.com> --- kernel/src/process/syscall/sys_ptrace.rs | 26 +++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/kernel/src/process/syscall/sys_ptrace.rs b/kernel/src/process/syscall/sys_ptrace.rs index 0a5bb1192..aa70f3a0f 100644 --- a/kernel/src/process/syscall/sys_ptrace.rs +++ b/kernel/src/process/syscall/sys_ptrace.rs @@ -338,18 +338,20 @@ impl SysPtrace { // 从 tracee 的内核栈读取 TrapFrame let trap_frame = unsafe { &*(trap_frame_vaddr.data() as *const TrapFrame) }; - // 获取 fs_base、gs_base 和段选择器 - // - fs_base/gs_base: task->thread.fsbase/gsbase - // - fs/gs: task->thread.fsindex/gsindex - let arch_info = tracee.arch_info_irqsave(); - let fs_base = arch_info.fsbase() as u64; - let gs_base = arch_info.gsbase() as u64; - let fs = arch_info.fs() as u64; - let gs = arch_info.gs() as u64; - drop(arch_info); - - // 使用 UserRegsStruct::from_trap_frame 构造用户态寄存器结构体 - let user_regs = UserRegsStruct::from_trap_frame(trap_frame, fs_base, gs_base, fs, gs); + #[cfg(target_arch = "x86_64")] + let user_regs = { + // 获取 fs_base、gs_base 和段选择器 + let arch_info = tracee.arch_info_irqsave(); + let fs_base = arch_info.fsbase() as u64; + let gs_base = arch_info.gsbase() as u64; + let fs = arch_info.fs() as u64; + let gs = arch_info.gs() as u64; + drop(arch_info); + // 使用 UserRegsStruct::from_trap_frame 构造用户态寄存器结构体 + UserRegsStruct::from_trap_frame(trap_frame, fs_base, gs_base, fs, gs) + }; + #[cfg(not(target_arch = "x86_64"))] + let user_regs = { UserRegsStruct::from_trap_frame(trap_frame) }; // 拷贝到用户空间 let mut writer = UserBufferWriter::new(