From 039f7f5c8391f9638aeddecb1a8ca8db5e8d888c Mon Sep 17 00:00:00 2001 From: jD91mZM2 <me@krake.one> Date: Tue, 7 Jul 2020 14:16:42 +0200 Subject: [PATCH] Simplify EXEC catching Instead of having a separate flag, let's reuse STOP_SINGLESTEP :) I wasn't thinking enough when making this flag! --- src/arch/x86_64/macros.rs | 19 ------------------- src/arch/x86_64/start.rs | 40 ++++++++------------------------------- src/context/signal.rs | 11 ++++++++++- src/syscall/process.rs | 40 +++++++++++++++------------------------ syscall | 2 +- 5 files changed, 34 insertions(+), 78 deletions(-) diff --git a/src/arch/x86_64/macros.rs b/src/arch/x86_64/macros.rs index 5e9002f..6271229 100644 --- a/src/arch/x86_64/macros.rs +++ b/src/arch/x86_64/macros.rs @@ -1,6 +1,5 @@ use core::mem; use syscall::data::IntRegisters; -use super::gdt; /// Print to console #[macro_export] @@ -216,24 +215,6 @@ pub struct InterruptStack { } impl InterruptStack { - pub fn new_usermode(ip: usize, sp: usize, arg: usize) -> Self { - // See which registers are set in start.rs, function `usermode` - Self { - fs: gdt::GDT_USER_TLS << 3 | 3, - preserved: PreservedRegisters::default(), - scratch: ScratchRegisters { - rdi: arg, - ..ScratchRegisters::default() - }, - iret: IretRegisters { - rip: ip, - cs: gdt::GDT_USER_CODE << 3 | 3, - rflags: 1 << 9, - rsp: sp, - ss: gdt::GDT_USER_DATA << 3 | 3, - }, - } - } pub fn dump(&self) { self.iret.dump(); self.scratch.dump(); diff --git a/src/arch/x86_64/start.rs b/src/arch/x86_64/start.rs index b2bc4e5..30425f0 100644 --- a/src/arch/x86_64/start.rs +++ b/src/arch/x86_64/start.rs @@ -3,7 +3,7 @@ /// It must create the IDT with the correct entries, those entries are /// defined in other files inside of the `arch` module -use core::{slice, mem, ptr}; +use core::slice; use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use crate::allocator; @@ -17,7 +17,6 @@ use crate::gdt; use crate::idt; use crate::interrupt; use crate::log; -use crate::macros::InterruptStack; use crate::memory; use crate::paging; @@ -234,7 +233,12 @@ pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! { } #[naked] -pub unsafe fn usermode(ip: usize, sp: usize, arg: usize) -> ! { +pub unsafe fn usermode(ip: usize, sp: usize, arg: usize, singlestep: bool) -> ! { + let mut flags = 1 << 9; + if singlestep { + flags |= 1 << 8; + } + asm!("push r10 push r11 push r12 @@ -244,7 +248,7 @@ pub unsafe fn usermode(ip: usize, sp: usize, arg: usize) -> ! { : // No output : "{r10}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment "{r11}"(sp), // Stack pointer - "{r12}"(1 << 9), // Flags - Set interrupt enable flag + "{r12}"(flags), // Flags - Set interrupt enable flag "{r13}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment "{r14}"(ip), // IP "{r15}"(arg) // Argument @@ -284,31 +288,3 @@ pub unsafe fn usermode(ip: usize, sp: usize, arg: usize) -> ! { : "intel", "volatile"); unreachable!(); } - -#[naked] -pub unsafe fn usermode_interrupt_stack(stack: InterruptStack) -> ! { - // Push fake stack to the actual stack - let rsp: usize; - asm!("sub rsp, $1" : "={rsp}"(rsp) : "r"(mem::size_of::<InterruptStack>()) : : "intel", "volatile"); - ptr::write(rsp as *mut InterruptStack, stack); - - // Unmap kernel - pti::unmap(); - - // Set up floating point and TLS - asm!("mov ds, r14d - mov es, r14d - mov fs, r15d - mov gs, r14d - fninit" - : // No output because it never returns - : "{r14}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment - "{r15}"(gdt::GDT_USER_TLS << 3 | 3) // TLS segment - : "ds", "es", "fs", "gs" - : "intel", "volatile"); - - // Go to usermode - interrupt_pop!(); - iret!(); - unreachable!(); -} diff --git a/src/context/signal.rs b/src/context/signal.rs index 78e165a..05d3ff7 100644 --- a/src/context/signal.rs +++ b/src/context/signal.rs @@ -105,6 +105,15 @@ pub extern "C" fn signal_handler(sig: usize) { } else { // println!("Call {:X}", handler); + let singlestep = { + let contexts = contexts(); + let context = contexts.current().expect("context::signal_handler userspace not inside of context"); + let context = context.read(); + unsafe { + ptrace::regs_for(&context).map(|s| s.is_singlestep()).unwrap_or(false) + } + }; + unsafe { let mut sp = crate::USER_SIGSTACK_OFFSET + crate::USER_SIGSTACK_SIZE - 256; @@ -113,7 +122,7 @@ pub extern "C" fn signal_handler(sig: usize) { sp -= mem::size_of::<usize>(); *(sp as *mut usize) = restorer; - usermode(handler, sp, sig); + usermode(handler, sp, sig, singlestep); } } diff --git a/src/syscall/process.rs b/src/syscall/process.rs index e27576f..2da33bd 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -6,7 +6,6 @@ use core::{intrinsics, mem}; use core::ops::DerefMut; use spin::Mutex; -use crate::arch::macros::InterruptStack; use crate::context::file::FileDescriptor; use crate::context::{ContextId, WaitpidKey}; use crate::context; @@ -21,14 +20,14 @@ use crate::paging::temporary_page::TemporaryPage; use crate::paging::{ActivePageTable, InactivePageTable, Page, VirtualAddress, PAGE_SIZE}; use crate::{ptrace, syscall}; use crate::scheme::FileHandle; -use crate::start::{usermode, usermode_interrupt_stack}; +use crate::start::usermode; use crate::syscall::data::{SigAction, Stat}; use crate::syscall::error::*; -use crate::syscall::flag::{CloneFlags, CLONE_FILES, CLONE_FS, CLONE_SIGHAND, - CLONE_STACK, CLONE_VFORK, CLONE_VM, MapFlags, PtraceFlags, PROT_EXEC, - PROT_READ, PROT_WRITE, PTRACE_EVENT_CLONE, PTRACE_STOP_EXIT, SigActionFlags, - SIG_BLOCK, SIG_DFL, SIG_SETMASK, SIG_UNBLOCK, SIGCONT, SIGTERM, WaitFlags, - WCONTINUED, WNOHANG,WUNTRACED, wifcontinued, wifstopped}; +use crate::syscall::flag::{wifcontinued, wifstopped, CloneFlags, CLONE_FILES, + CLONE_FS, CLONE_SIGHAND, CLONE_STACK, CLONE_VFORK, CLONE_VM, MapFlags, + PROT_EXEC, PROT_READ, PROT_WRITE, PTRACE_EVENT_CLONE, PTRACE_STOP_EXIT, + SigActionFlags, SIG_BLOCK, SIG_DFL, SIG_SETMASK, SIG_UNBLOCK, SIGCONT, SIGTERM, + WaitFlags, WCONTINUED, WNOHANG,WUNTRACED}; use crate::syscall::ptrace_event; use crate::syscall::validate::{validate_slice, validate_slice_mut}; @@ -661,6 +660,7 @@ fn fexec_noreturn( vars: Box<[Box<[u8]>]> ) -> ! { let entry; + let singlestep; let mut sp = crate::USER_STACK_OFFSET + crate::USER_STACK_SIZE - 256; { @@ -669,6 +669,10 @@ fn fexec_noreturn( let context_lock = contexts.current().ok_or(Error::new(ESRCH)).expect("exec_noreturn pid not found"); let mut context = context_lock.write(); + singlestep = unsafe { + ptrace::regs_for(&context).map(|s| s.is_singlestep()).unwrap_or(false) + }; + context.name = Arc::new(Mutex::new(name)); empty(&mut context, false); @@ -712,8 +716,8 @@ fn fexec_noreturn( unsafe { // Copy file data intrinsics::copy((elf.data.as_ptr() as usize + segment.p_offset as usize) as *const u8, - segment.p_vaddr as *mut u8, - segment.p_filesz as usize); + segment.p_vaddr as *mut u8, + segment.p_filesz as usize); } let mut flags = EntryFlags::NO_EXECUTE | EntryFlags::USER_ACCESSIBLE; @@ -900,22 +904,8 @@ fn fexec_noreturn( } } - // Create dummy stack for ptrace to read from - let mut regs = InterruptStack::new_usermode(entry, sp, 0); - - // ptrace breakpoint - let was_traced = { - let _guard = ptrace::set_process_regs(&mut regs); - ptrace::breakpoint_callback(PtraceFlags::PTRACE_STOP_EXEC, None).is_some() - }; - - if !was_traced { - // Go to usermode, fast route - unsafe { usermode(entry, sp, 0) } - } else { - // Go to usermode, take ptrace-modified stack into account - unsafe { usermode_interrupt_stack(regs) } - } + // Go to usermode + unsafe { usermode(entry, sp, 0, singlestep) } } pub fn fexec_kernel(fd: FileHandle, args: Box<[Box<[u8]>]>, vars: Box<[Box<[u8]>]>, name_override_opt: Option<Box<[u8]>>) -> Result<usize> { diff --git a/syscall b/syscall index fcebe8f..a1af645 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit fcebe8f225142830fa5880a27d9faa6ed6b2aeb8 +Subproject commit a1af645cbf426c2ff66b3d06d04dd2aceb538128 -- GitLab