mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-09 13:26:48 +00:00
Remove trampoline code in handling user kernel
This commit is contained in:
parent
7afc3c88f9
commit
7e96810e1a
@ -17,7 +17,7 @@ use core::{mem, sync::atomic::Ordering};
|
|||||||
|
|
||||||
use align_ext::AlignExt;
|
use align_ext::AlignExt;
|
||||||
use c_types::{siginfo_t, ucontext_t};
|
use c_types::{siginfo_t, ucontext_t};
|
||||||
use constants::SIGKILL;
|
use constants::SIGSEGV;
|
||||||
pub use events::{SigEvents, SigEventsFilter};
|
pub use events::{SigEvents, SigEventsFilter};
|
||||||
use ostd::{cpu::UserContext, user::UserContextApi};
|
use ostd::{cpu::UserContext, user::UserContextApi};
|
||||||
pub use pause::{with_signal_blocked, Pause};
|
pub use pause::{with_signal_blocked, Pause};
|
||||||
@ -119,7 +119,9 @@ pub fn handle_pending_signal(
|
|||||||
signal.to_info(),
|
signal.to_info(),
|
||||||
) {
|
) {
|
||||||
debug!("Failed to handle user signal: {:?}", e);
|
debug!("Failed to handle user signal: {:?}", e);
|
||||||
do_exit_group(TermStatus::Killed(SIGKILL));
|
// If signal handling fails, the process should be terminated with SIGSEGV.
|
||||||
|
// Ref: <https://elixir.bootlin.com/linux/v6.13/source/kernel/signal.c#L3082>
|
||||||
|
do_exit_group(TermStatus::Killed(SIGSEGV));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SigAction::Dfl => {
|
SigAction::Dfl => {
|
||||||
@ -164,17 +166,17 @@ pub fn handle_user_signal(
|
|||||||
debug!("handler_addr = 0x{:x}", handler_addr);
|
debug!("handler_addr = 0x{:x}", handler_addr);
|
||||||
debug!("flags = {:?}", flags);
|
debug!("flags = {:?}", flags);
|
||||||
debug!("restorer_addr = 0x{:x}", restorer_addr);
|
debug!("restorer_addr = 0x{:x}", restorer_addr);
|
||||||
// FIXME: How to respect flags?
|
|
||||||
if flags.contains_unsupported_flag() {
|
if flags.contains_unsupported_flag() {
|
||||||
warn!("Unsupported Signal flags: {:?}", flags);
|
warn!("Unsupported Signal flags: {:?}", flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !flags.contains(SigActionFlags::SA_NODEFER) {
|
if !flags.contains(SigActionFlags::SA_NODEFER) {
|
||||||
// add current signal to mask
|
// Add current signal to mask
|
||||||
mask += sig_num;
|
mask += sig_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
// block signals in sigmask when running signal handler
|
// Block signals in sigmask when running signal handler
|
||||||
let old_mask = ctx.posix_thread.sig_mask().load(Ordering::Relaxed);
|
let old_mask = ctx.posix_thread.sig_mask().load(Ordering::Relaxed);
|
||||||
ctx.posix_thread
|
ctx.posix_thread
|
||||||
.sig_mask()
|
.sig_mask()
|
||||||
@ -184,7 +186,7 @@ pub fn handle_user_signal(
|
|||||||
let mut stack_pointer = if let Some(sp) = use_alternate_signal_stack(ctx.thread_local) {
|
let mut stack_pointer = if let Some(sp) = use_alternate_signal_stack(ctx.thread_local) {
|
||||||
sp as u64
|
sp as u64
|
||||||
} else {
|
} else {
|
||||||
// just use user stack
|
// Just use user stack
|
||||||
user_ctx.stack_pointer() as u64
|
user_ctx.stack_pointer() as u64
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -193,12 +195,12 @@ pub fn handle_user_signal(
|
|||||||
|
|
||||||
let user_space = ctx.user_space();
|
let user_space = ctx.user_space();
|
||||||
|
|
||||||
// 1. write siginfo_t
|
// 1. Write siginfo_t
|
||||||
stack_pointer -= mem::size_of::<siginfo_t>() as u64;
|
stack_pointer -= mem::size_of::<siginfo_t>() as u64;
|
||||||
user_space.write_val(stack_pointer as _, &sig_info)?;
|
user_space.write_val(stack_pointer as _, &sig_info)?;
|
||||||
let siginfo_addr = stack_pointer;
|
let siginfo_addr = stack_pointer;
|
||||||
|
|
||||||
// 2. write ucontext_t.
|
// 2. Write ucontext_t.
|
||||||
stack_pointer = alloc_aligned_in_user_stack(stack_pointer, mem::size_of::<ucontext_t>(), 16)?;
|
stack_pointer = alloc_aligned_in_user_stack(stack_pointer, mem::size_of::<ucontext_t>(), 16)?;
|
||||||
let mut ucontext = ucontext_t {
|
let mut ucontext = ucontext_t {
|
||||||
uc_sigmask: mask.into(),
|
uc_sigmask: mask.into(),
|
||||||
@ -223,30 +225,20 @@ pub fn handle_user_signal(
|
|||||||
.sig_context()
|
.sig_context()
|
||||||
.set(Some(ucontext_addr as Vaddr));
|
.set(Some(ucontext_addr as Vaddr));
|
||||||
|
|
||||||
// 3. Set the address of the trampoline code.
|
// 3. Write the address of the restorer code.
|
||||||
if flags.contains(SigActionFlags::SA_RESTORER) {
|
if flags.contains(SigActionFlags::SA_RESTORER) {
|
||||||
// If contains SA_RESTORER flag, trampoline code is provided by libc in restorer_addr.
|
// If the SA_RESTORER flag is present, the restorer code address is provided by the user.
|
||||||
// We just store restorer_addr on user stack to allow user code just to trampoline code.
|
|
||||||
stack_pointer = write_u64_to_user_stack(stack_pointer, restorer_addr as u64)?;
|
stack_pointer = write_u64_to_user_stack(stack_pointer, restorer_addr as u64)?;
|
||||||
trace!("After set restorer addr: user_rsp = 0x{:x}", stack_pointer);
|
trace!(
|
||||||
} else {
|
"After writing restorer addr: user_rsp = 0x{:x}",
|
||||||
// Otherwise we create a trampoline.
|
stack_pointer
|
||||||
// FIXME: This may cause problems if we read old_context from rsp.
|
);
|
||||||
const TRAMPOLINE: &[u8] = &[
|
|
||||||
0xb8, 0x0f, 0x00, 0x00, 0x00, // mov eax, 15(syscall number of rt_sigreturn)
|
|
||||||
0x0f, 0x05, // syscall (call rt_sigreturn)
|
|
||||||
0x90, // nop (for alignment)
|
|
||||||
];
|
|
||||||
stack_pointer -= TRAMPOLINE.len() as u64;
|
|
||||||
let trampoline_rip = stack_pointer;
|
|
||||||
user_space.write_bytes(stack_pointer as Vaddr, &mut VmReader::from(TRAMPOLINE))?;
|
|
||||||
stack_pointer = write_u64_to_user_stack(stack_pointer, trampoline_rip)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Set correct register values
|
// 4. Set correct register values
|
||||||
user_ctx.set_instruction_pointer(handler_addr as _);
|
user_ctx.set_instruction_pointer(handler_addr as _);
|
||||||
user_ctx.set_stack_pointer(stack_pointer as usize);
|
user_ctx.set_stack_pointer(stack_pointer as usize);
|
||||||
// parameters of signal handler
|
// Parameters of signal handler
|
||||||
if flags.contains(SigActionFlags::SA_SIGINFO) {
|
if flags.contains(SigActionFlags::SA_SIGINFO) {
|
||||||
user_ctx.set_arguments(sig_num, siginfo_addr as usize, ucontext_addr as usize);
|
user_ctx.set_arguments(sig_num, siginfo_addr as usize, ucontext_addr as usize);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use super::{constants::*, sig_action::SigAction, sig_num::SigNum};
|
use super::{constants::*, sig_action::SigAction, sig_num::SigNum};
|
||||||
|
use crate::{prelude::*, process::signal::sig_action::SigActionFlags};
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct SigDispositions {
|
pub struct SigDispositions {
|
||||||
@ -26,9 +27,10 @@ impl SigDispositions {
|
|||||||
self.map[idx]
|
self.map[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&mut self, num: SigNum, sa: SigAction) -> SigAction {
|
pub fn set(&mut self, num: SigNum, sa: SigAction) -> Result<SigAction> {
|
||||||
|
check_sigaction(&sa)?;
|
||||||
let idx = Self::num_to_idx(num);
|
let idx = Self::num_to_idx(num);
|
||||||
core::mem::replace(&mut self.map[idx], sa)
|
Ok(core::mem::replace(&mut self.map[idx], sa))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_default(&mut self, num: SigNum) {
|
pub fn set_default(&mut self, num: SigNum) {
|
||||||
@ -52,3 +54,36 @@ impl SigDispositions {
|
|||||||
(num.as_u8() - MIN_STD_SIG_NUM) as usize
|
(num.as_u8() - MIN_STD_SIG_NUM) as usize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_sigaction(sig_action: &SigAction) -> Result<()> {
|
||||||
|
// Here we only check if the SA_RESTORER flag is set and restorer_addr is not 0.
|
||||||
|
// Note: Linux checks the SA_RESTORER flag when initializing the signal stack,
|
||||||
|
// whereas we have moved this check forward to prevent this action from being set.
|
||||||
|
// This may result in some differences from the behavior of Linux.
|
||||||
|
|
||||||
|
let SigAction::User {
|
||||||
|
flags,
|
||||||
|
restorer_addr,
|
||||||
|
..
|
||||||
|
} = sig_action
|
||||||
|
else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
if flags.contains(SigActionFlags::SA_RESTORER) && *restorer_addr != 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(target_arch = "x86_64")] {
|
||||||
|
// On x86-64, `SA_RESTORER` is mandatory and cannot be omitted.
|
||||||
|
// Ref: <https://elixir.bootlin.com/linux/v6.13/source/arch/x86/kernel/signal_64.c#L172>
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "x86-64 should always use SA_RESTORER");
|
||||||
|
} else {
|
||||||
|
// FIXME: The support for user-provided signal handlers
|
||||||
|
// without `SA_RESTORER` is arch-dependent.
|
||||||
|
// Other archs may need to handle scenarios where `SA_RESTORER` is omitted.
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "TODO: properly deal with SA_RESTORER");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user