From 51e39b366659737d47f4bb6576fa3526bb5fc86b Mon Sep 17 00:00:00 2001 From: Ashwin Naren Date: Mon, 5 Jan 2026 15:07:38 -0800 Subject: [PATCH] initial ptrace --- etc/syscalls_linux_aarch64.md | 2 +- src/arch/arm64/exceptions/syscall.rs | 8 +++ src/process/clone.rs | 2 + src/process/mod.rs | 3 + src/process/owned.rs | 3 + src/process/ptrace.rs | 91 ++++++++++++++++++++++++++++ 6 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 src/process/ptrace.rs diff --git a/etc/syscalls_linux_aarch64.md b/etc/syscalls_linux_aarch64.md index 423c196..75e37a6 100644 --- a/etc/syscalls_linux_aarch64.md +++ b/etc/syscalls_linux_aarch64.md @@ -117,7 +117,7 @@ | 0x72 (114) | clock_getres | (const clockid_t which_clock, struct __kernel_timespec *tp) | __arm64_sys_clock_getres | false | | 0x73 (115) | clock_nanosleep | (const clockid_t which_clock, int flags, const struct __kernel_timespec *rqtp, struct __kernel_timespec *rmtp) | __arm64_sys_clock_nanosleep | false | | 0x74 (116) | syslog | (int type, char *buf, int len) | __arm64_sys_syslog | false | -| 0x75 (117) | ptrace | (long request, long pid, unsigned long addr, unsigned long data) | __arm64_sys_ptrace | false | +| 0x75 (117) | ptrace | (long request, long pid, unsigned long addr, unsigned long data) | __arm64_sys_ptrace | partially | | 0x76 (118) | sched_setparam | (pid_t pid, struct sched_param *param) | __arm64_sys_sched_setparam | false | | 0x77 (119) | sched_setscheduler | (pid_t pid, int policy, struct sched_param *param) | __arm64_sys_sched_setscheduler | false | | 0x78 (120) | sched_getscheduler | (pid_t pid) | __arm64_sys_sched_getscheduler | false | diff --git a/src/arch/arm64/exceptions/syscall.rs b/src/arch/arm64/exceptions/syscall.rs index 31612dd..569e311 100644 --- a/src/arch/arm64/exceptions/syscall.rs +++ b/src/arch/arm64/exceptions/syscall.rs @@ -53,6 +53,7 @@ use crate::{ fcntl::sys_fcntl, select::{sys_ppoll, sys_pselect6}, }, + ptrace::sys_ptrace, sleep::sys_nanosleep, thread_group::{ Pgid, @@ -290,6 +291,13 @@ pub async fn handle_syscall() { 0x63 => sys_set_robust_list(TUA::from_value(arg1 as _), arg2 as _).await, 0x65 => sys_nanosleep(TUA::from_value(arg1 as _), TUA::from_value(arg2 as _)).await, 0x71 => sys_clock_gettime(arg1 as _, TUA::from_value(arg2 as _)).await, + 0x75 => sys_ptrace( + arg1 as _, + arg2 as _, + TUA::from_value(arg3 as _), + TUA::from_value(arg4 as _), + ) + .await, 0x7b => Err(KernelError::NotSupported), 0x7c => sys_sched_yield(), 0x81 => sys_kill(arg1 as _, arg2.into()), diff --git a/src/process/clone.rs b/src/process/clone.rs index 77b46ae..cc97427 100644 --- a/src/process/clone.rs +++ b/src/process/clone.rs @@ -8,6 +8,7 @@ use crate::{ sync::SpinLock, }; use alloc::boxed::Box; +use core::sync::atomic::AtomicBool; use bitflags::bitflags; use libkernel::memory::address::TUA; use libkernel::{ @@ -153,6 +154,7 @@ pub async fn sys_clone( creds: SpinLock::new(creds), state: Arc::new(SpinLock::new(TaskState::Runnable)), last_cpu: SpinLock::new(CpuId::this()), + ptrace: AtomicBool::new(flags.contains(CloneFlags::CLONE_PTRACE) && current_task.ptrace.load(core::sync::atomic::Ordering::SeqCst)), }), } }; diff --git a/src/process/mod.rs b/src/process/mod.rs index 1770c41..0472a87 100644 --- a/src/process/mod.rs +++ b/src/process/mod.rs @@ -4,6 +4,7 @@ use alloc::{ sync::{Arc, Weak}, }; use core::fmt::Display; +use core::sync::atomic::AtomicBool; use creds::Credentials; use fd_table::FileDescriptorTable; use libkernel::{VirtualMemory, fs::Inode}; @@ -18,6 +19,7 @@ pub mod exec; pub mod exit; pub mod fd_table; pub mod owned; +pub mod ptrace; pub mod sleep; pub mod thread_group; pub mod threading; @@ -163,6 +165,7 @@ pub struct Task { pub fd_table: Arc>, pub state: Arc>, pub last_cpu: SpinLock, + pub ptrace: AtomicBool } impl Task { diff --git a/src/process/owned.rs b/src/process/owned.rs index e3782d0..3d4b336 100644 --- a/src/process/owned.rs +++ b/src/process/owned.rs @@ -19,6 +19,7 @@ use crate::{ sync::SpinLock, }; use alloc::sync::Arc; +use core::sync::atomic::AtomicBool; use libkernel::{ VirtualMemory, fs::pathbuf::PathBuf, @@ -75,6 +76,7 @@ impl OwnedTask { vm: Arc::new(SpinLock::new(vm)), fd_table: Arc::new(SpinLock::new(FileDescriptorTable::new())), last_cpu: SpinLock::new(CpuId::this()), + ptrace: AtomicBool::new(false), }; Self { @@ -102,6 +104,7 @@ impl OwnedTask { )), fd_table: Arc::new(SpinLock::new(FileDescriptorTable::new())), last_cpu: SpinLock::new(CpuId::this()), + ptrace: AtomicBool::new(false), }; Self { diff --git a/src/process/ptrace.rs b/src/process/ptrace.rs new file mode 100644 index 0000000..1e12074 --- /dev/null +++ b/src/process/ptrace.rs @@ -0,0 +1,91 @@ +use alloc::sync::Arc; +use core::sync::atomic::Ordering; +use libkernel::error::{KernelError, Result}; +use libkernel::memory::address::UA; +use crate::process::{find_task_by_descriptor, Task, Tid, TASK_LIST}; +use crate::process::thread_group::signal::SigId; +use crate::sched::current::current_task_shared; + +#[repr(i32)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum PtraceOperation { + TraceMe = 0, + PeekText = 1, + PeekData = 2, + PeekUser = 3, + PokeText = 4, + PokeData = 5, + PokeUser = 6, + Cont = 7, + Kill = 8, + SingleStep = 9, + GetRegs = 12, + SetRegs = 13, + GetFpRegs = 14, + SetFpRegs = 15, + Attach = 16, + Detach = 17, + Syscall = 24, +} + +impl TryFrom for PtraceOperation { + type Error = KernelError; + + fn try_from(value: i32) -> Result { + match value { + 0 => Ok(PtraceOperation::TraceMe), + 1 => Ok(PtraceOperation::PeekText), + 2 => Ok(PtraceOperation::PeekData), + // TODO: Should be EIO + _ => Err(KernelError::InvalidValue) + } + } +} + +pub async fn sys_ptrace(op: i32, pid: Tid, addr: UA, data: UA) -> Result { + let op = PtraceOperation::try_from(op)?; + if op == PtraceOperation::TraceMe { + // Change ptrace status + let current_task = current_task_shared(); + current_task.ptrace.store(true, Ordering::SeqCst); + return Ok(0); + } + let task_list = TASK_LIST.lock_save_irq(); + let id = task_list + .iter() + .find(|(desc, _)| desc.tid == pid) + .map(|(desc, _)| *desc); + drop(task_list); + let task_details = if let Some(desc) = id { + find_task_by_descriptor(&desc) + } else { + None + }; + // TODO: Wrong error? + let task = task_details.ok_or(KernelError::NoProcess)?; + // Check if the current task is allowed to ptrace the target task + let current_task = current_task_shared(); + // TODO: Check CAP_SYS_PTRACE & security + if !current_task.process.children.lock_save_irq().iter().any(|(ch_id, _)| &task.process.tgid == ch_id) { + // TODO: Wrong error + return Err(KernelError::NotSupported); + } + match op { + PtraceOperation::TraceMe => { + unreachable!(); + } + PtraceOperation::Attach => { + if !task.ptrace.load(Ordering::SeqCst) { + // TODO: Wrong error + return Err(KernelError::InvalidValue); + } + task.process + .signals + .lock_save_irq() + .set_pending(SigId::SIGSTOP); + Ok(0) + } + // TODO: Wrong error + _ => Err(KernelError::InvalidValue), + } +} \ No newline at end of file