mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-21 08:26:30 +00:00
Support alternate signal stack
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
3734306398
commit
a91a35ebce
@ -265,6 +265,7 @@ int test_sigchld() {
|
|||||||
// child process
|
// child process
|
||||||
printf("create a new proces successfully (pid = %d)\n", getpid());
|
printf("create a new proces successfully (pid = %d)\n", getpid());
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
exit(0);
|
||||||
} else {
|
} else {
|
||||||
// parent process
|
// parent process
|
||||||
wait(NULL);
|
wait(NULL);
|
||||||
@ -274,11 +275,82 @@ int test_sigchld() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Test handle signal on alternate signal stack
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#define MAX_ALTSTACK_RECURSION_LEVEL 2
|
||||||
|
|
||||||
|
stack_t g_old_ss;
|
||||||
|
|
||||||
|
static void handle_sigpipe(int num, siginfo_t *info, void *context) {
|
||||||
|
static volatile int recursion_level = 0;
|
||||||
|
printf("Hello from SIGPIPE signal handler on the alternate signal stack (recursion_level = %d)\n",
|
||||||
|
recursion_level);
|
||||||
|
|
||||||
|
// save old_ss to check if we are on stack
|
||||||
|
stack_t old_ss;
|
||||||
|
sigaltstack(NULL, &old_ss);
|
||||||
|
g_old_ss = old_ss;
|
||||||
|
|
||||||
|
recursion_level++;
|
||||||
|
if (recursion_level <= MAX_ALTSTACK_RECURSION_LEVEL) {
|
||||||
|
raise(SIGPIPE);
|
||||||
|
}
|
||||||
|
recursion_level--;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SIGSTACKSIZE (4*4096)
|
||||||
|
|
||||||
|
int test_sigaltstack() {
|
||||||
|
static char stack[SIGSTACKSIZE];
|
||||||
|
stack_t expected_ss = {
|
||||||
|
.ss_size = SIGSTACKSIZE,
|
||||||
|
.ss_sp = stack,
|
||||||
|
.ss_flags = 0,
|
||||||
|
};
|
||||||
|
if (sigaltstack(&expected_ss, NULL) < 0) {
|
||||||
|
THROW_ERROR("failed to call sigaltstack");
|
||||||
|
}
|
||||||
|
stack_t actual_ss;
|
||||||
|
if (sigaltstack(NULL, &actual_ss) < 0) {
|
||||||
|
THROW_ERROR("failed to call sigaltstack");
|
||||||
|
}
|
||||||
|
if (actual_ss.ss_size != expected_ss.ss_size
|
||||||
|
|| actual_ss.ss_sp != expected_ss.ss_sp
|
||||||
|
|| actual_ss.ss_flags != expected_ss.ss_flags) {
|
||||||
|
THROW_ERROR("failed to check the signal stack after set");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sigaction new_action, old_action;
|
||||||
|
memset(&new_action, 0, sizeof(struct sigaction));
|
||||||
|
memset(&old_action, 0, sizeof(struct sigaction));
|
||||||
|
new_action.sa_sigaction = handle_sigpipe;
|
||||||
|
new_action.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
|
||||||
|
if (sigaction(SIGPIPE, &new_action, &old_action) < 0) {
|
||||||
|
THROW_ERROR("registering new signal handler failed");
|
||||||
|
}
|
||||||
|
if (old_action.sa_handler != SIG_DFL) {
|
||||||
|
THROW_ERROR("unexpected old sig handler");
|
||||||
|
}
|
||||||
|
|
||||||
|
raise(SIGPIPE);
|
||||||
|
if (g_old_ss.ss_flags != SS_ONSTACK) {
|
||||||
|
THROW_ERROR("check stack flags failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sigaction(SIGPIPE, &old_action, NULL) < 0) {
|
||||||
|
THROW_ERROR("restoring old signal handler failed");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
test_sigprocmask();
|
test_sigprocmask();
|
||||||
test_raise();
|
test_raise();
|
||||||
test_handle_sigfpe();
|
test_handle_sigfpe();
|
||||||
test_handle_sigsegv();
|
test_handle_sigsegv();
|
||||||
test_sigchld();
|
test_sigchld();
|
||||||
|
test_sigaltstack();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -92,7 +92,6 @@ impl PosixThreadBuilder {
|
|||||||
let thread = Arc::new_cyclic(|thread_ref| {
|
let thread = Arc::new_cyclic(|thread_ref| {
|
||||||
let task = create_new_user_task(user_space, thread_ref.clone());
|
let task = create_new_user_task(user_space, thread_ref.clone());
|
||||||
let status = ThreadStatus::Init;
|
let status = ThreadStatus::Init;
|
||||||
let sig_context = Mutex::new(None);
|
|
||||||
let posix_thread = PosixThread {
|
let posix_thread = PosixThread {
|
||||||
process,
|
process,
|
||||||
is_main_thread,
|
is_main_thread,
|
||||||
@ -102,7 +101,8 @@ impl PosixThreadBuilder {
|
|||||||
credentials,
|
credentials,
|
||||||
sig_mask: Mutex::new(sig_mask),
|
sig_mask: Mutex::new(sig_mask),
|
||||||
sig_queues: Mutex::new(sig_queues),
|
sig_queues: Mutex::new(sig_queues),
|
||||||
sig_context,
|
sig_context: Mutex::new(None),
|
||||||
|
sig_stack: Mutex::new(None),
|
||||||
robust_list: Mutex::new(None),
|
robust_list: Mutex::new(None),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ use super::signal::sig_mask::SigMask;
|
|||||||
use super::signal::sig_num::SigNum;
|
use super::signal::sig_num::SigNum;
|
||||||
use super::signal::sig_queues::SigQueues;
|
use super::signal::sig_queues::SigQueues;
|
||||||
use super::signal::signals::Signal;
|
use super::signal::signals::Signal;
|
||||||
use super::signal::{SigEvents, SigEventsFilter};
|
use super::signal::{SigEvents, SigEventsFilter, SigStack};
|
||||||
use super::{do_exit_group, Credentials, Process, TermStatus};
|
use super::{do_exit_group, Credentials, Process, TermStatus};
|
||||||
use crate::events::Observer;
|
use crate::events::Observer;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
@ -51,6 +51,7 @@ pub struct PosixThread {
|
|||||||
/// Signal handler ucontext address
|
/// Signal handler ucontext address
|
||||||
/// FIXME: This field may be removed. For glibc applications with RESTORER flag set, the sig_context is always equals with rsp.
|
/// FIXME: This field may be removed. For glibc applications with RESTORER flag set, the sig_context is always equals with rsp.
|
||||||
sig_context: Mutex<Option<Vaddr>>,
|
sig_context: Mutex<Option<Vaddr>>,
|
||||||
|
sig_stack: Mutex<Option<SigStack>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PosixThread {
|
impl PosixThread {
|
||||||
@ -152,6 +153,10 @@ impl PosixThread {
|
|||||||
&self.sig_context
|
&self.sig_context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sig_stack(&self) -> &Mutex<Option<SigStack>> {
|
||||||
|
&self.sig_stack
|
||||||
|
}
|
||||||
|
|
||||||
pub fn robust_list(&self) -> &Mutex<Option<RobustListHead>> {
|
pub fn robust_list(&self) -> &Mutex<Option<RobustListHead>> {
|
||||||
&self.robust_list
|
&self.robust_list
|
||||||
}
|
}
|
||||||
|
@ -8,30 +8,27 @@ pub mod sig_disposition;
|
|||||||
pub mod sig_mask;
|
pub mod sig_mask;
|
||||||
pub mod sig_num;
|
pub mod sig_num;
|
||||||
pub mod sig_queues;
|
pub mod sig_queues;
|
||||||
|
mod sig_stack;
|
||||||
pub mod signals;
|
pub mod signals;
|
||||||
|
|
||||||
pub use events::{SigEvents, SigEventsFilter};
|
pub use events::{SigEvents, SigEventsFilter};
|
||||||
pub use pauser::Pauser;
|
pub use pauser::Pauser;
|
||||||
pub use poll::{Pollee, Poller};
|
pub use poll::{Pollee, Poller};
|
||||||
|
pub use sig_stack::{SigStack, SigStackFlags, SigStackStatus};
|
||||||
use core::mem;
|
|
||||||
|
|
||||||
use align_ext::AlignExt;
|
use align_ext::AlignExt;
|
||||||
use jinux_frame::{cpu::UserContext, task::Task};
|
use core::mem;
|
||||||
|
use jinux_frame::cpu::UserContext;
|
||||||
|
use jinux_frame::task::Task;
|
||||||
|
|
||||||
use self::c_types::siginfo_t;
|
use super::posix_thread::{PosixThread, PosixThreadExt};
|
||||||
use self::sig_mask::SigMask;
|
use crate::prelude::*;
|
||||||
use self::sig_num::SigNum;
|
|
||||||
use crate::current_thread;
|
|
||||||
use crate::process::posix_thread::PosixThreadExt;
|
|
||||||
use crate::process::signal::c_types::ucontext_t;
|
|
||||||
use crate::process::signal::sig_action::SigActionFlags;
|
|
||||||
use crate::process::{do_exit_group, TermStatus};
|
use crate::process::{do_exit_group, TermStatus};
|
||||||
use crate::util::{write_bytes_to_user, write_val_to_user};
|
use crate::util::{write_bytes_to_user, write_val_to_user};
|
||||||
use crate::{
|
use c_types::{siginfo_t, ucontext_t};
|
||||||
prelude::*,
|
use sig_action::{SigAction, SigActionFlags, SigDefaultAction};
|
||||||
process::signal::sig_action::{SigAction, SigDefaultAction},
|
use sig_mask::SigMask;
|
||||||
};
|
use sig_num::SigNum;
|
||||||
|
|
||||||
/// Handle pending signal for current process
|
/// Handle pending signal for current process
|
||||||
pub fn handle_pending_signal(context: &mut UserContext) -> Result<()> {
|
pub fn handle_pending_signal(context: &mut UserContext) -> Result<()> {
|
||||||
@ -134,19 +131,24 @@ pub fn handle_user_signal(
|
|||||||
// block signals in sigmask when running signal handler
|
// block signals in sigmask when running signal handler
|
||||||
posix_thread.sig_mask().lock().block(mask.as_u64());
|
posix_thread.sig_mask().lock().block(mask.as_u64());
|
||||||
|
|
||||||
// Set up signal stack in user stack,
|
// Set up signal stack.
|
||||||
// to avoid corrupting user stack, we minus 128 first.
|
let mut stack_pointer = if let Some(sp) = use_alternate_signal_stack(posix_thread) {
|
||||||
let mut user_rsp = context.rsp() as u64;
|
sp as u64
|
||||||
user_rsp -= 128;
|
} else {
|
||||||
|
// just use user stack
|
||||||
|
context.rsp() as u64
|
||||||
|
};
|
||||||
|
|
||||||
|
// To avoid corrupting signal stack, we minus 128 first.
|
||||||
|
stack_pointer -= 128;
|
||||||
|
|
||||||
// 1. write siginfo_t
|
// 1. write siginfo_t
|
||||||
user_rsp -= mem::size_of::<siginfo_t>() as u64;
|
stack_pointer -= mem::size_of::<siginfo_t>() as u64;
|
||||||
write_val_to_user(user_rsp as _, &sig_info)?;
|
write_val_to_user(stack_pointer as _, &sig_info)?;
|
||||||
let siginfo_addr = user_rsp;
|
let siginfo_addr = stack_pointer;
|
||||||
// debug!("siginfo_addr = 0x{:x}", siginfo_addr);
|
|
||||||
|
|
||||||
// 2. write ucontext_t.
|
// 2. write ucontext_t.
|
||||||
user_rsp = alloc_aligned_in_user_stack(user_rsp, 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.as_u64(),
|
uc_sigmask: mask.as_u64(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -159,18 +161,17 @@ pub fn handle_user_signal(
|
|||||||
ucontext.uc_link = 0;
|
ucontext.uc_link = 0;
|
||||||
}
|
}
|
||||||
// TODO: store fp regs in ucontext
|
// TODO: store fp regs in ucontext
|
||||||
write_val_to_user(user_rsp as _, &ucontext)?;
|
write_val_to_user(stack_pointer as _, &ucontext)?;
|
||||||
let ucontext_addr = user_rsp;
|
let ucontext_addr = stack_pointer;
|
||||||
// Store the ucontext addr in sig context of current process.
|
// Store the ucontext addr in sig context of current thread.
|
||||||
*sig_context = Some(ucontext_addr as Vaddr);
|
*sig_context = Some(ucontext_addr as Vaddr);
|
||||||
// current.sig_context().lock().push_back(ucontext_addr as _);
|
|
||||||
|
|
||||||
// 3. Set the address of the trampoline code.
|
// 3. Set the address of the trampoline 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 contains SA_RESTORER flag, trampoline code is provided by libc in restorer_addr.
|
||||||
// We just store restorer_addr on user stack to allow user code just to trampoline code.
|
// We just store restorer_addr on user stack to allow user code just to trampoline code.
|
||||||
user_rsp = write_u64_to_user_stack(user_rsp, 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}", user_rsp);
|
trace!("After set restorer addr: user_rsp = 0x{:x}", stack_pointer);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise we create a trampoline.
|
// Otherwise we create a trampoline.
|
||||||
// FIXME: This may cause problems if we read old_context from rsp.
|
// FIXME: This may cause problems if we read old_context from rsp.
|
||||||
@ -179,14 +180,14 @@ pub fn handle_user_signal(
|
|||||||
0x0f, 0x05, // syscall (call rt_sigreturn)
|
0x0f, 0x05, // syscall (call rt_sigreturn)
|
||||||
0x90, // nop (for alignment)
|
0x90, // nop (for alignment)
|
||||||
];
|
];
|
||||||
user_rsp -= TRAMPOLINE.len() as u64;
|
stack_pointer -= TRAMPOLINE.len() as u64;
|
||||||
let trampoline_rip = user_rsp;
|
let trampoline_rip = stack_pointer;
|
||||||
write_bytes_to_user(user_rsp as Vaddr, TRAMPOLINE)?;
|
write_bytes_to_user(stack_pointer as Vaddr, TRAMPOLINE)?;
|
||||||
user_rsp = write_u64_to_user_stack(user_rsp, trampoline_rip)?;
|
stack_pointer = write_u64_to_user_stack(stack_pointer, trampoline_rip)?;
|
||||||
}
|
}
|
||||||
// 4. Set correct register values
|
// 4. Set correct register values
|
||||||
context.set_rip(handler_addr as _);
|
context.set_rip(handler_addr as _);
|
||||||
context.set_rsp(user_rsp as usize);
|
context.set_rsp(stack_pointer as usize);
|
||||||
// parameters of signal handler
|
// parameters of signal handler
|
||||||
context.set_rdi(sig_num.as_u8() as usize); // signal number
|
context.set_rdi(sig_num.as_u8() as usize); // signal number
|
||||||
if flags.contains(SigActionFlags::SA_SIGINFO) {
|
if flags.contains(SigActionFlags::SA_SIGINFO) {
|
||||||
@ -200,6 +201,34 @@ pub fn handle_user_signal(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Use an alternate signal stack, which was installed by sigaltstack.
|
||||||
|
/// It the stack is already active, we just increase the handler counter and return None, since
|
||||||
|
/// the stack pointer can be read from context.
|
||||||
|
/// It the stack is not used by any handler, we will return the new sp in alternate signal stack.
|
||||||
|
fn use_alternate_signal_stack(posix_thread: &PosixThread) -> Option<usize> {
|
||||||
|
let mut sig_stack = posix_thread.sig_stack().lock();
|
||||||
|
|
||||||
|
let Some(sig_stack) = &mut *sig_stack else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
if sig_stack.is_disabled() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if sig_stack.is_active() {
|
||||||
|
// The stack is already active, so we just use sp in context.
|
||||||
|
sig_stack.increase_handler_counter();
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
sig_stack.increase_handler_counter();
|
||||||
|
|
||||||
|
// Make sp align at 16. FIXME: is this required?
|
||||||
|
let stack_pointer = (sig_stack.base() + sig_stack.size()).align_down(16);
|
||||||
|
Some(stack_pointer)
|
||||||
|
}
|
||||||
|
|
||||||
fn write_u64_to_user_stack(rsp: u64, value: u64) -> Result<u64> {
|
fn write_u64_to_user_stack(rsp: u64, value: u64) -> Result<u64> {
|
||||||
let rsp = rsp - 8;
|
let rsp = rsp - 8;
|
||||||
write_val_to_user(rsp as Vaddr, &value)?;
|
write_val_to_user(rsp as Vaddr, &value)?;
|
||||||
|
@ -103,7 +103,6 @@ impl SigActionFlags {
|
|||||||
self.intersects(
|
self.intersects(
|
||||||
SigActionFlags::SA_NOCLDSTOP
|
SigActionFlags::SA_NOCLDSTOP
|
||||||
| SigActionFlags::SA_NOCLDWAIT
|
| SigActionFlags::SA_NOCLDWAIT
|
||||||
| SigActionFlags::SA_ONSTACK
|
|
||||||
| SigActionFlags::SA_RESETHAND,
|
| SigActionFlags::SA_RESETHAND,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
93
services/libs/jinux-std/src/process/signal/sig_stack.rs
Normal file
93
services/libs/jinux-std/src/process/signal/sig_stack.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// User-provided signal stack. `SigStack` is per-thread, and each thread can have
|
||||||
|
/// at most one `SigStack`. If one signal handler specifying the `SA_ONSTACK` flag,
|
||||||
|
/// the handler should be executed on the `SigStack`, instead of on the default stack.
|
||||||
|
///
|
||||||
|
/// SigStack can be registered and unregistered by syscall `sigaltstack`.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct SigStack {
|
||||||
|
base: Vaddr,
|
||||||
|
flags: SigStackFlags,
|
||||||
|
size: usize,
|
||||||
|
/// The number of handlers that are currently using the stack
|
||||||
|
handler_counter: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct SigStackFlags: u32 {
|
||||||
|
const SS_AUTODISARM = 1 << 31;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||||||
|
pub enum SigStackStatus {
|
||||||
|
#[default]
|
||||||
|
SS_INACTIVE = 0,
|
||||||
|
// The thread is currently executing on the alternate signal stack
|
||||||
|
SS_ONSTACK = 1,
|
||||||
|
// The stack is currently disabled.
|
||||||
|
SS_DISABLE = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SigStack {
|
||||||
|
pub fn new(base: Vaddr, flags: SigStackFlags, size: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
base,
|
||||||
|
flags,
|
||||||
|
size,
|
||||||
|
handler_counter: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn base(&self) -> Vaddr {
|
||||||
|
self.base
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flags(&self) -> SigStackFlags {
|
||||||
|
self.flags
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> usize {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn status(&self) -> SigStackStatus {
|
||||||
|
if self.handler_counter == 0 {
|
||||||
|
return SigStackStatus::SS_INACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Learning From [sigaltstack doc](https://man7.org/linux/man-pages/man2/sigaltstack.2.html):
|
||||||
|
// If the stack is currently executed on,
|
||||||
|
// 1. If the stack was established with flag SS_AUTODISARM, the stack status is DISABLE,
|
||||||
|
// 2. otherwise, the stack status is ONSTACK
|
||||||
|
if self.flags.contains(SigStackFlags::SS_AUTODISARM) {
|
||||||
|
SigStackStatus::SS_DISABLE
|
||||||
|
} else {
|
||||||
|
SigStackStatus::SS_ONSTACK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark the stack is currently used by a signal handler.
|
||||||
|
pub fn increase_handler_counter(&mut self) {
|
||||||
|
self.handler_counter += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the stack is freed by current handler.
|
||||||
|
pub fn decrease_handler_counter(&mut self) {
|
||||||
|
// FIXME: deal with SS_AUTODISARM flag
|
||||||
|
self.handler_counter -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determins whether the stack is executed on by any signal handler
|
||||||
|
pub fn is_active(&self) -> bool {
|
||||||
|
// FIXME: can DISABLE stack be used?
|
||||||
|
self.handler_counter != 0 && !self.flags.contains(SigStackFlags::SS_AUTODISARM)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_disabled(&self) -> bool {
|
||||||
|
self.handler_counter != 0 && self.flags.contains(SigStackFlags::SS_AUTODISARM)
|
||||||
|
}
|
||||||
|
}
|
@ -99,6 +99,7 @@ use self::setsid::sys_setsid;
|
|||||||
use self::setsockopt::sys_setsockopt;
|
use self::setsockopt::sys_setsockopt;
|
||||||
use self::setuid::sys_setuid;
|
use self::setuid::sys_setuid;
|
||||||
use self::shutdown::sys_shutdown;
|
use self::shutdown::sys_shutdown;
|
||||||
|
use self::sigaltstack::sys_sigaltstack;
|
||||||
use self::socket::sys_socket;
|
use self::socket::sys_socket;
|
||||||
use self::socketpair::sys_socketpair;
|
use self::socketpair::sys_socketpair;
|
||||||
|
|
||||||
@ -185,6 +186,7 @@ mod setsid;
|
|||||||
mod setsockopt;
|
mod setsockopt;
|
||||||
mod setuid;
|
mod setuid;
|
||||||
mod shutdown;
|
mod shutdown;
|
||||||
|
mod sigaltstack;
|
||||||
mod socket;
|
mod socket;
|
||||||
mod socketpair;
|
mod socketpair;
|
||||||
mod stat;
|
mod stat;
|
||||||
@ -316,6 +318,7 @@ define_syscall_nums!(
|
|||||||
SYS_SETFSUID = 122,
|
SYS_SETFSUID = 122,
|
||||||
SYS_SETFSGID = 123,
|
SYS_SETFSGID = 123,
|
||||||
SYS_GETSID = 124,
|
SYS_GETSID = 124,
|
||||||
|
SYS_SIGALTSTACK = 131,
|
||||||
SYS_STATFS = 137,
|
SYS_STATFS = 137,
|
||||||
SYS_FSTATFS = 138,
|
SYS_FSTATFS = 138,
|
||||||
SYS_PRCTL = 157,
|
SYS_PRCTL = 157,
|
||||||
@ -491,6 +494,7 @@ pub fn syscall_dispatch(
|
|||||||
SYS_SETFSUID => syscall_handler!(1, sys_setfsuid, args),
|
SYS_SETFSUID => syscall_handler!(1, sys_setfsuid, args),
|
||||||
SYS_SETFSGID => syscall_handler!(1, sys_setfsgid, args),
|
SYS_SETFSGID => syscall_handler!(1, sys_setfsgid, args),
|
||||||
SYS_GETSID => syscall_handler!(1, sys_getsid, args),
|
SYS_GETSID => syscall_handler!(1, sys_getsid, args),
|
||||||
|
SYS_SIGALTSTACK => syscall_handler!(2, sys_sigaltstack, args),
|
||||||
SYS_STATFS => syscall_handler!(2, sys_statfs, args),
|
SYS_STATFS => syscall_handler!(2, sys_statfs, args),
|
||||||
SYS_FSTATFS => syscall_handler!(2, sys_fstatfs, args),
|
SYS_FSTATFS => syscall_handler!(2, sys_fstatfs, args),
|
||||||
SYS_PRCTL => syscall_handler!(5, sys_prctl, args),
|
SYS_PRCTL => syscall_handler!(5, sys_prctl, args),
|
||||||
|
@ -23,6 +23,15 @@ pub fn sys_rt_sigreturn(context: &mut UserContext) -> Result<SyscallReturn> {
|
|||||||
debug_assert!(sig_context_addr == context.rsp() as Vaddr);
|
debug_assert!(sig_context_addr == context.rsp() as Vaddr);
|
||||||
|
|
||||||
let ucontext = read_val_from_user::<ucontext_t>(sig_context_addr)?;
|
let ucontext = read_val_from_user::<ucontext_t>(sig_context_addr)?;
|
||||||
|
|
||||||
|
// If the sig stack is active and used by current handler, decrease handler counter.
|
||||||
|
if let Some(sig_stack) = posix_thread.sig_stack().lock().as_mut() {
|
||||||
|
let rsp = context.rsp();
|
||||||
|
if rsp >= sig_stack.base() && rsp <= sig_stack.base() + sig_stack.size() {
|
||||||
|
sig_stack.decrease_handler_counter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Set previous ucontext address
|
// Set previous ucontext address
|
||||||
if ucontext.uc_link == 0 {
|
if ucontext.uc_link == 0 {
|
||||||
*sig_context = None;
|
*sig_context = None;
|
||||||
@ -33,5 +42,6 @@ pub fn sys_rt_sigreturn(context: &mut UserContext) -> Result<SyscallReturn> {
|
|||||||
// unblock sig mask
|
// unblock sig mask
|
||||||
let sig_mask = ucontext.uc_sigmask;
|
let sig_mask = ucontext.uc_sigmask;
|
||||||
posix_thread.sig_mask().lock().unblock(sig_mask);
|
posix_thread.sig_mask().lock().unblock(sig_mask);
|
||||||
|
|
||||||
Ok(SyscallReturn::NoReturn)
|
Ok(SyscallReturn::NoReturn)
|
||||||
}
|
}
|
||||||
|
112
services/libs/jinux-std/src/syscall/sigaltstack.rs
Normal file
112
services/libs/jinux-std/src/syscall/sigaltstack.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
use crate::log_syscall_entry;
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::process::posix_thread::PosixThreadExt;
|
||||||
|
use crate::process::signal::SigStack;
|
||||||
|
use crate::process::signal::SigStackFlags;
|
||||||
|
use crate::util::read_val_from_user;
|
||||||
|
use crate::util::write_val_to_user;
|
||||||
|
|
||||||
|
use super::{SyscallReturn, SYS_SIGALTSTACK};
|
||||||
|
|
||||||
|
pub fn sys_sigaltstack(sig_stack_addr: Vaddr, old_sig_stack_addr: Vaddr) -> Result<SyscallReturn> {
|
||||||
|
log_syscall_entry!(SYS_SIGALTSTACK);
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"sig_stack_addr = 0x{:x}, old_sig_stack_addr: 0x{:x}",
|
||||||
|
sig_stack_addr, old_sig_stack_addr
|
||||||
|
);
|
||||||
|
|
||||||
|
let old_stack = {
|
||||||
|
let current_thread = current_thread!();
|
||||||
|
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||||
|
let sig_stack = posix_thread.sig_stack().lock();
|
||||||
|
sig_stack.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
get_old_stack(old_sig_stack_addr, old_stack.as_ref())?;
|
||||||
|
set_new_stack(sig_stack_addr, old_stack.as_ref())?;
|
||||||
|
|
||||||
|
Ok(SyscallReturn::Return(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_old_stack(old_sig_stack_addr: Vaddr, old_stack: Option<&SigStack>) -> Result<()> {
|
||||||
|
if old_sig_stack_addr == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(old_stack) = old_stack else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("old stack = {:?}", old_stack);
|
||||||
|
|
||||||
|
let stack = stack_t::from(old_stack.clone());
|
||||||
|
write_val_to_user(old_sig_stack_addr, &stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_new_stack(sig_stack_addr: Vaddr, old_stack: Option<&SigStack>) -> Result<()> {
|
||||||
|
if sig_stack_addr == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(old_stack) = old_stack && old_stack.is_active() {
|
||||||
|
return_errno_with_message!(Errno::EPERM, "the old stack is active now");
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_stack = {
|
||||||
|
let stack = read_val_from_user::<stack_t>(sig_stack_addr)?;
|
||||||
|
SigStack::try_from(stack)?
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("new_stack = {:?}", new_stack);
|
||||||
|
|
||||||
|
let current_thread = current_thread!();
|
||||||
|
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||||
|
*posix_thread.sig_stack().lock() = Some(new_stack);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Debug, Clone, Copy, Pod)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct stack_t {
|
||||||
|
// Base address of stack
|
||||||
|
sp: Vaddr,
|
||||||
|
flags: i32,
|
||||||
|
// Number of bytes in stack
|
||||||
|
size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<stack_t> for SigStack {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_from(stack: stack_t) -> Result<Self> {
|
||||||
|
if stack.flags < 0 {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "negative flags");
|
||||||
|
}
|
||||||
|
|
||||||
|
let flags = SigStackFlags::from_bits(stack.flags as u32)
|
||||||
|
.ok_or_else(|| Error::with_message(Errno::EINVAL, "invalid flags"))?;
|
||||||
|
|
||||||
|
if stack.size < MINSTKSZ {
|
||||||
|
return_errno_with_message!(Errno::ENOMEM, "stack size is less than MINSTKSZ");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self::new(stack.sp, flags, stack.size))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SigStack> for stack_t {
|
||||||
|
fn from(stack: SigStack) -> Self {
|
||||||
|
let flags = stack.flags().bits() as i32 | stack.status() as i32;
|
||||||
|
Self {
|
||||||
|
sp: stack.base(),
|
||||||
|
flags,
|
||||||
|
size: stack.size(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SIGSTKSZ: usize = 8192;
|
||||||
|
const MINSTKSZ: usize = 2048;
|
Reference in New Issue
Block a user