use linux_api::errno::Errno;
use linux_api::signal::{defaultaction, siginfo_t, LinuxDefaultAction, Signal, SignalHandler};
use shadow_shim_helper_rs::explicit_drop::{ExplicitDrop, ExplicitDropper};
use shadow_shim_helper_rs::syscall_types::ForeignPtr;
use crate::cshadow as c;
use crate::host::process::Process;
use crate::host::syscall::handler::{SyscallContext, SyscallHandler, ThreadContext};
use crate::host::syscall::types::SyscallError;
use crate::host::thread::Thread;
impl SyscallHandler {
log_syscall!(
kill,
std::ffi::c_int,
linux_api::posix_types::kernel_pid_t,
std::ffi::c_int,
);
pub fn kill(
ctx: &mut SyscallContext,
pid: linux_api::posix_types::kernel_pid_t,
sig: std::ffi::c_int,
) -> Result<(), Errno> {
log::trace!("kill called on pid {pid} with signal {sig}");
let pid = if pid == -1 {
log::warn!("kill with pid=-1 unimplemented");
return Err(Errno::ENOTSUP);
} else if pid == 0 {
ctx.objs.process.id()
} else if pid < -1 {
(-pid).try_into().or(Err(Errno::ESRCH))?
} else {
pid.try_into().or(Err(Errno::ESRCH))?
};
let Some(target_process) = ctx.objs.host.process_borrow(pid) else {
log::debug!("Process {pid} not found");
return Err(Errno::ESRCH);
};
let target_process = &*target_process.borrow(ctx.objs.host.root());
Self::signal_process(ctx.objs, target_process, sig)
}
fn signal_process(
objs: &ThreadContext,
target_process: &Process,
signal: std::ffi::c_int,
) -> Result<(), Errno> {
if signal == 0 {
return Ok(());
}
let Ok(signal) = Signal::try_from(signal) else {
return Err(Errno::EINVAL);
};
if signal.is_realtime() {
log::warn!("Unimplemented signal {signal:?}");
return Err(Errno::ENOTSUP);
}
let sender_pid = objs.process.id().into();
let siginfo = siginfo_t::new_for_kill(signal, sender_pid, 0);
target_process.signal(objs.host, Some(objs.thread), &siginfo);
Ok(())
}
log_syscall!(
tkill,
std::ffi::c_int,
linux_api::posix_types::kernel_pid_t,
std::ffi::c_int,
);
pub fn tkill(
ctx: &mut SyscallContext,
tid: linux_api::posix_types::kernel_pid_t,
sig: std::ffi::c_int,
) -> Result<(), Errno> {
log::trace!("tkill called on tid {tid} with signal {sig}");
let tid = tid.try_into().or(Err(Errno::ESRCH))?;
let Some(target_thread) = ctx.objs.host.thread_cloned_rc(tid) else {
return Err(Errno::ESRCH);
};
let target_thread = ExplicitDropper::new(target_thread, |value| {
value.explicit_drop(ctx.objs.host.root())
});
let target_thread = &*target_thread.borrow(ctx.objs.host.root());
Self::signal_thread(ctx.objs, target_thread, sig)
}
log_syscall!(
tgkill,
std::ffi::c_int,
linux_api::posix_types::kernel_pid_t,
linux_api::posix_types::kernel_pid_t,
std::ffi::c_int,
);
pub fn tgkill(
ctx: &mut SyscallContext,
tgid: linux_api::posix_types::kernel_pid_t,
tid: linux_api::posix_types::kernel_pid_t,
sig: std::ffi::c_int,
) -> Result<(), Errno> {
log::trace!("tgkill called on tgid {tgid} and tid {tid} with signal {sig}");
let tgid = tgid.try_into().or(Err(Errno::ESRCH))?;
let tid = tid.try_into().or(Err(Errno::ESRCH))?;
let Some(target_thread) = ctx.objs.host.thread_cloned_rc(tid) else {
return Err(Errno::ESRCH);
};
let target_thread = ExplicitDropper::new(target_thread, |value| {
value.explicit_drop(ctx.objs.host.root())
});
let target_thread = &*target_thread.borrow(ctx.objs.host.root());
if target_thread.process_id() != tgid {
return Err(Errno::ESRCH);
}
Self::signal_thread(ctx.objs, target_thread, sig)
}
fn signal_thread(
objs: &ThreadContext,
target_thread: &Thread,
signal: std::ffi::c_int,
) -> Result<(), Errno> {
if signal == 0 {
return Ok(());
}
let Ok(signal) = Signal::try_from(signal) else {
return Err(Errno::EINVAL);
};
if signal.is_realtime() {
log::warn!("Unimplemented signal {signal:?}");
return Err(Errno::ENOTSUP);
}
let mut cond = {
let shmem_lock = &*objs.host.shim_shmem_lock_borrow().unwrap();
let target_process = objs
.host
.process_borrow(target_thread.process_id())
.unwrap();
let target_process = &*target_process.borrow(objs.host.root());
let process_shmem = target_process.borrow_as_runnable().unwrap();
let process_shmem = &*process_shmem.shmem();
let process_protected = process_shmem.protected.borrow(&shmem_lock.root);
let thread_shmem = target_thread.shmem();
let mut thread_protected = thread_shmem.protected.borrow_mut(&shmem_lock.root);
let action = unsafe { process_protected.signal_action(signal) };
let action_handler = unsafe { action.handler() };
let signal_is_ignored = match action_handler {
SignalHandler::SigIgn => true,
SignalHandler::SigDfl => defaultaction(signal) == LinuxDefaultAction::IGN,
_ => false,
};
if signal_is_ignored {
return Ok(());
}
if thread_protected.pending_signals.has(signal) {
return Ok(());
}
thread_protected.pending_signals.add(signal);
let sender_pid = objs.process.id();
let sender_tid = objs.thread.id();
let siginfo = siginfo_t::new_for_tkill(signal, sender_pid.into(), 0);
thread_protected.set_pending_standard_siginfo(signal, &siginfo);
if sender_tid == target_thread.id() {
return Ok(());
}
if thread_protected.blocked_signals.has(signal) {
return Ok(());
}
let Some(cond) = target_thread.syscall_condition_mut() else {
return Ok(());
};
cond
};
let was_scheduled = cond.wakeup_for_signal(objs.host, signal);
assert!(was_scheduled);
Ok(())
}
log_syscall!(
rt_sigaction,
std::ffi::c_int,
std::ffi::c_int,
*const std::ffi::c_void,
*const std::ffi::c_void,
libc::size_t,
);
pub fn rt_sigaction(
ctx: &mut SyscallContext,
_sig: std::ffi::c_int,
_act: ForeignPtr<linux_api::signal::sigaction>,
_oact: ForeignPtr<linux_api::signal::sigaction>,
_sigsetsize: libc::size_t,
) -> Result<(), SyscallError> {
let rv: i32 = Self::legacy_syscall(c::syscallhandler_rt_sigaction, ctx)?;
assert_eq!(rv, 0);
Ok(())
}
log_syscall!(
rt_sigprocmask,
std::ffi::c_int,
std::ffi::c_int,
*const std::ffi::c_void,
*const std::ffi::c_void,
libc::size_t,
);
pub fn rt_sigprocmask(
ctx: &mut SyscallContext,
_how: std::ffi::c_int,
_nset: ForeignPtr<linux_api::signal::sigset_t>,
_oset: ForeignPtr<linux_api::signal::sigset_t>,
_sigsetsize: libc::size_t,
) -> Result<(), SyscallError> {
let rv: i32 = Self::legacy_syscall(c::syscallhandler_rt_sigprocmask, ctx)?;
assert_eq!(rv, 0);
Ok(())
}
log_syscall!(
sigaltstack,
std::ffi::c_int,
*const std::ffi::c_void,
*const std::ffi::c_void,
);
pub fn sigaltstack(
ctx: &mut SyscallContext,
_uss: ForeignPtr<linux_api::signal::stack_t>,
_uoss: ForeignPtr<linux_api::signal::stack_t>,
) -> Result<(), SyscallError> {
let rv: i32 = Self::legacy_syscall(c::syscallhandler_sigaltstack, ctx)?;
assert_eq!(rv, 0);
Ok(())
}
}