From 8117119d8efb58bf11288f134cc6d6d8e1f5eaa2 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 11 Jun 2020 16:05:00 +0200 Subject: [PATCH 1/4] Wrap borrows of page table entries in unsafe. This is safe because `Entry` is `#[repr(8)]` which is the minimum alignment for qwords. Since the size of a qword is equal to that alignment (8), they can also be borrowed from the array. --- src/arch/x86_64/paging/entry.rs | 8 ++++++++ src/arch/x86_64/paging/table.rs | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/arch/x86_64/paging/entry.rs b/src/arch/x86_64/paging/entry.rs index 56f9755..c8a0f96 100644 --- a/src/arch/x86_64/paging/entry.rs +++ b/src/arch/x86_64/paging/entry.rs @@ -77,3 +77,11 @@ impl Entry { self.0 = (self.0 & !COUNTER_MASK) | (count << 52); } } + +#[cfg(test)] +mod tests { + #[test] + fn entry_has_required_arch_alignment() { + assert_eq!(core::mem::align_of::(), core::mem::align_of::()); + } +} diff --git a/src/arch/x86_64/paging/table.rs b/src/arch/x86_64/paging/table.rs index 9ebfcef..a6f45c5 100644 --- a/src/arch/x86_64/paging/table.rs +++ b/src/arch/x86_64/paging/table.rs @@ -55,7 +55,7 @@ impl Table where L: TableLevel { } pub fn zero(&mut self) { - for entry in self.entries.iter_mut() { + for entry in unsafe { &mut self.entries }.iter_mut() { entry.set_zero(); } } @@ -63,12 +63,12 @@ impl Table where L: TableLevel { /// Set number of entries in first table entry fn set_entry_count(&mut self, count: u64) { debug_assert!(count <= ENTRY_COUNT as u64, "count can't be greater than ENTRY_COUNT"); - self.entries[0].set_counter_bits(count); + unsafe { &mut self.entries[0] }.set_counter_bits(count) } /// Get number of entries in first table entry fn entry_count(&self) -> u64 { - self.entries[0].counter_bits() + unsafe { &self.entries[0] }.counter_bits() } pub fn increment_entry_count(&mut self) { @@ -118,12 +118,12 @@ impl Index for Table where L: TableLevel { type Output = Entry; fn index(&self, index: usize) -> &Entry { - &self.entries[index] + unsafe { &self.entries[index] } } } impl IndexMut for Table where L: TableLevel { fn index_mut(&mut self, index: usize) -> &mut Entry { - &mut self.entries[index] + unsafe { &mut self.entries[index] } } } From 1c0e6c253fac14d7c4f61622ba10cc619616ff04 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 11 Jun 2020 16:11:46 +0200 Subject: [PATCH 2/4] Fix test. --- src/arch/x86_64/paging/entry.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/arch/x86_64/paging/entry.rs b/src/arch/x86_64/paging/entry.rs index c8a0f96..ba6f941 100644 --- a/src/arch/x86_64/paging/entry.rs +++ b/src/arch/x86_64/paging/entry.rs @@ -82,6 +82,7 @@ impl Entry { mod tests { #[test] fn entry_has_required_arch_alignment() { - assert_eq!(core::mem::align_of::(), core::mem::align_of::()); + use super::Entry; + assert!(core::mem::align_of::() >= core::mem::align_of::(), "alignment of Entry is less than the required alignment of u64 ({} < {})", core::mem::align_of::(), core::mem::align_of::()); } } From 103ed1b17f30cf798b8c2411f962c3a4104ab8db Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Wed, 8 Jul 2020 10:54:34 +0200 Subject: [PATCH 3/4] Make interrupt stack readable on kernel signals --- src/arch/x86_64/macros.rs | 42 +++++++++++++++++++++++---------------- src/lib.rs | 8 +++++++- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/arch/x86_64/macros.rs b/src/arch/x86_64/macros.rs index 6271229..29d0d10 100644 --- a/src/arch/x86_64/macros.rs +++ b/src/arch/x86_64/macros.rs @@ -48,9 +48,8 @@ impl ScratchRegisters { } macro_rules! scratch_push { - () => (asm!( - "push rax - push rcx + (without rax) => (asm!( + "push rcx push rdx push rdi push rsi @@ -60,6 +59,10 @@ macro_rules! scratch_push { push r11" : : : : "intel", "volatile" )); + () => ({ + asm!("push rax" : : : : "intel", "volatile"); + scratch_push!(without rax); + }); } macro_rules! scratch_pop { @@ -362,20 +365,14 @@ macro_rules! interrupt_stack { #[derive(Default)] #[repr(packed)] pub struct InterruptErrorStack { - pub fs: usize, - pub preserved: PreservedRegisters, - pub scratch: ScratchRegisters, pub code: usize, - pub iret: IretRegisters, + pub inner: InterruptStack, } impl InterruptErrorStack { pub fn dump(&self) { - self.iret.dump(); + self.inner.dump(); println!("CODE: {:>016X}", { self.code }); - self.scratch.dump(); - self.preserved.dump(); - println!("FS: {:>016X}", { self.fs }); } } @@ -385,12 +382,23 @@ macro_rules! interrupt_error { #[naked] pub unsafe extern fn $name () { #[inline(never)] - unsafe fn inner($stack: &$crate::arch::x86_64::macros::InterruptErrorStack) { + unsafe fn inner($stack: &mut $crate::arch::x86_64::macros::InterruptErrorStack) { + let _guard = ptrace::set_process_regs(&mut $stack.inner); $func } - // Push scratch registers - interrupt_push!(); + // Swap RAX and error code, in order to push the code later and be + // compatible with InterruptStack. + asm!("xchg [rsp], rax" : : : : "intel", "volatile"); + + // Push all the registers (except for rax which is already pushed, + // in place of the error code) + scratch_push!(without rax); + preserved_push!(); + fs_push!(); + + // Finally, push rax (now containing error code) + asm!("push rax" : : : : "intel", "volatile"); // Get reference to stack variables let rsp: usize; @@ -400,14 +408,14 @@ macro_rules! interrupt_error { $crate::arch::x86_64::pti::map(); // Call inner rust function - inner(&*(rsp as *const $crate::arch::x86_64::macros::InterruptErrorStack)); + inner(&mut *(rsp as *mut $crate::arch::x86_64::macros::InterruptErrorStack)); // Unmap kernel $crate::arch::x86_64::pti::unmap(); - // Pop scratch registers, error code, and return - interrupt_pop!(); + // Pop error code, registers, and return asm!("add rsp, 8" : : : : "intel", "volatile"); // pop error code + interrupt_pop!(); iret!(); } }; diff --git a/src/lib.rs b/src/lib.rs index 8627940..82004e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -274,5 +274,11 @@ pub extern fn ksignal(signal: usize) { println!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) }); } } - syscall::exit(signal & 0x7F); + + // Try running kill(getpid(), signal), but fallback to exiting + syscall::getpid() + .and_then(|pid| syscall::kill(pid, signal).map(|_| ())) + .unwrap_or_else(|_| { + syscall::exit(signal & 0x7F); + }); } From 56f55a3b97c9d51317500b776e45583a8cc72c71 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Wed, 8 Jul 2020 11:47:12 +0200 Subject: [PATCH 4/4] Always save proccess registers Not sure if this is going to be required, and I'm not sure if this will hurt performance, y'know, *always* doing this. --- src/arch/x86_64/interrupt/exception.rs | 8 -------- src/arch/x86_64/interrupt/irq.rs | 1 - src/arch/x86_64/macros.rs | 1 + 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/arch/x86_64/interrupt/exception.rs b/src/arch/x86_64/interrupt/exception.rs index b55a13e..5c0e8ea 100644 --- a/src/arch/x86_64/interrupt/exception.rs +++ b/src/arch/x86_64/interrupt/exception.rs @@ -18,8 +18,6 @@ interrupt_stack!(divide_by_zero, stack, { interrupt_stack!(debug, stack, { let mut handled = false; - let guard = ptrace::set_process_regs(stack); - // Disable singlestep before there is a breakpoint, since the breakpoint // handler might end up setting it again but unless it does we want the // default to be false. @@ -33,8 +31,6 @@ interrupt_stack!(debug, stack, { stack.set_singlestep(had_singlestep); } - drop(guard); - if !handled { println!("Debug trap"); stack.dump(); @@ -61,11 +57,7 @@ interrupt_stack!(breakpoint, stack, { // int3 instruction. After all, it's the sanest thing to do. stack.iret.rip -= 1; - let guard = ptrace::set_process_regs(stack); - if ptrace::breakpoint_callback(PTRACE_STOP_BREAKPOINT, None).is_none() { - drop(guard); - println!("Breakpoint trap"); stack.dump(); ksignal(SIGTRAP); diff --git a/src/arch/x86_64/interrupt/irq.rs b/src/arch/x86_64/interrupt/irq.rs index a01196f..291879c 100644 --- a/src/arch/x86_64/interrupt/irq.rs +++ b/src/arch/x86_64/interrupt/irq.rs @@ -189,7 +189,6 @@ interrupt_stack!(pit, stack, { timeout::trigger(); if PIT_TICKS.fetch_add(1, Ordering::SeqCst) >= 10 { - let _guard = ptrace::set_process_regs(stack); let _ = context::switch(); } }); diff --git a/src/arch/x86_64/macros.rs b/src/arch/x86_64/macros.rs index 29d0d10..f3d54d9 100644 --- a/src/arch/x86_64/macros.rs +++ b/src/arch/x86_64/macros.rs @@ -335,6 +335,7 @@ macro_rules! interrupt_stack { pub unsafe extern fn $name () { #[inline(never)] unsafe fn inner($stack: &mut $crate::arch::x86_64::macros::InterruptStack) { + let _guard = ptrace::set_process_regs($stack); $func }