Set siginfo_t.si_{pid,uid} from kill signals too.

This commit is contained in:
4lDO2
2024-08-02 16:01:46 +02:00
parent e5136e66c1
commit 30caf55429
7 changed files with 109 additions and 61 deletions
+2
View File
@@ -7,6 +7,8 @@
typedef struct siginfo siginfo_t;
typedef unsigned long long sigset_t;
typedef struct ucontext ucontext_t;
typedef struct mcontext mcontext_t;
struct sigaction {
union {
+12 -3
View File
@@ -29,7 +29,8 @@ pub struct SigArea {
pub tmp_rdx: usize,
pub tmp_rdi: usize,
pub tmp_rsi: usize,
pub tmp_inf: RtSigInfo,
pub tmp_rt_inf: RtSigInfo,
pub tmp_id_inf: u64,
pub altstack_top: usize,
pub altstack_bottom: usize,
@@ -192,7 +193,10 @@ asmfunction!(__relibc_internal_sigentry: ["
and eax, edx
bsf eax, eax
jz 8f
lea rdi, [rip + {pctl} + {pctl_off_sender_infos}]
mov rdi, [rdi + rax * 8]
lock btr [rip + {pctl} + {pctl_off_pending}], eax
mov fs:[{tcb_sa_off} + {sa_tmp_id_inf}], rdi
jc 9f
8:
// Read second signal word - both process and thread simultaneously.
@@ -211,7 +215,7 @@ asmfunction!(__relibc_internal_sigentry: ["
mov esi, eax
mov eax, {SYS_SIGDEQUEUE}
mov rdi, fs:[0]
add rdi, {tcb_sa_off} + {sa_tmp_inf} // out pointer of dequeued realtime sig
add rdi, {tcb_sa_off} + {sa_tmp_rt_inf} // out pointer of dequeued realtime sig
syscall
test eax, eax
jnz 1b // assumes error can only be EAGAIN
@@ -220,7 +224,9 @@ asmfunction!(__relibc_internal_sigentry: ["
2:
mov edx, eax
shr edx, 5
mov rdi, fs:[{tcb_sc_off} + {sc_sender_infos} + eax * 8]
lock btr fs:[{tcb_sc_off} + {sc_word} + edx * 4], eax
mov fs:[{tcb_sa_off} + {sa_tmp_id_inf}], rdi
add eax, 64 // indicate signal was targeted at thread
9:
sub rsp, {REDZONE_SIZE}
@@ -396,17 +402,20 @@ __relibc_internal_sigentry_crit_third:
sa_tmp_rdx = const offset_of!(SigArea, tmp_rdx),
sa_tmp_rdi = const offset_of!(SigArea, tmp_rdi),
sa_tmp_rsi = const offset_of!(SigArea, tmp_rsi),
sa_tmp_inf = const offset_of!(SigArea, tmp_inf),
sa_tmp_rt_inf = const offset_of!(SigArea, tmp_rt_inf),
sa_tmp_id_inf = const offset_of!(SigArea, tmp_id_inf),
sa_altstack_top = const offset_of!(SigArea, altstack_top),
sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom),
sc_saved_rflags = const offset_of!(Sigcontrol, saved_archdep_reg),
sc_saved_rip = const offset_of!(Sigcontrol, saved_ip),
sc_word = const offset_of!(Sigcontrol, word),
sc_sender_infos = const offset_of!(Sigcontrol, sender_infos),
sc_control = const offset_of!(Sigcontrol, control_flags),
tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch),
tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control),
pctl_off_actions = const offset_of!(SigProcControl, actions),
pctl_off_pending = const offset_of!(SigProcControl, pending),
pctl_off_sender_infos = const offset_of!(SigProcControl, sender_infos),
pctl = sym PROC_CONTROL_STRUCT,
supports_avx = sym SUPPORTS_AVX,
REDZONE_SIZE = const 128,
+27 -23
View File
@@ -6,10 +6,10 @@ use core::{
};
use syscall::{
data::AtomicU64, Error, NonatomicUsize, RawAction, Result, SetSighandlerData, SigProcControl,
Sigcontrol, SigcontrolFlags, EINVAL, ENOMEM, EPERM, SIGABRT, SIGBUS, SIGCHLD, SIGCONT, SIGFPE,
SIGILL, SIGKILL, SIGQUIT, SIGSEGV, SIGSTOP, SIGSYS, SIGTRAP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG,
SIGWINCH, SIGXCPU, SIGXFSZ,
data::AtomicU64, Error, NonatomicUsize, RawAction, Result, SenderInfo, SetSighandlerData,
SigProcControl, Sigcontrol, SigcontrolFlags, EINVAL, ENOMEM, EPERM, SIGABRT, SIGBUS, SIGCHLD,
SIGCONT, SIGFPE, SIGILL, SIGKILL, SIGQUIT, SIGSEGV, SIGSTOP, SIGSYS, SIGTRAP, SIGTSTP, SIGTTIN,
SIGTTOU, SIGURG, SIGWINCH, SIGXCPU, SIGXFSZ,
};
use crate::{arch::*, proc::FdGuard, sync::Mutex, RtTcb, Tcb};
@@ -85,16 +85,19 @@ unsafe fn inner(stack: &mut SigStack) {
let (sender_pid, sender_uid) = {
let area = &mut *os.arch.get();
stack.sival = area.tmp_inf.arg;
// Undefined if the signal was not realtime
stack.sival = area.tmp_rt_inf.arg;
stack.old_stack = arch_pre(stack, area);
if (stack.sig_num - 1) / 32 == 1 && !targeted_thread_not_process {
stack.sig_code = area.tmp_inf.code as u32;
(area.tmp_inf.pid, area.tmp_inf.uid)
stack.sig_code = area.tmp_rt_inf.code as u32;
(area.tmp_rt_inf.pid, area.tmp_rt_inf.uid)
} else {
// TODO: SIGCHLD information when applicable
stack.sig_code = 0;
(0, 0) // TODO
stack.sig_code = 0; // TODO: SI_USER constant?
// TODO: Handle SIGCHLD. Maybe that should always be queued though?
let inf = SenderInfo::from_raw(area.tmp_id_inf);
(inf.pid, inf.ruid)
}
};
@@ -140,7 +143,6 @@ unsafe fn inner(stack: &mut SigStack) {
let sigallow_inside_lo = sigallow_inside & 0xffff_ffff;
let sigallow_inside_hi = sigallow_inside >> 32;
//let _ = syscall::write(1, &alloc::format!("WORD0 {:x?}\n", os.control.word).as_bytes());
let prev_w0 = os.control.word[0].fetch_add(
(sigallow_inside_lo << 32).wrapping_sub(prev_sigallow_lo << 32),
Ordering::Relaxed,
@@ -149,7 +151,6 @@ unsafe fn inner(stack: &mut SigStack) {
(sigallow_inside_hi << 32).wrapping_sub(prev_sigallow_hi << 32),
Ordering::Relaxed,
);
//let _ = syscall::write(1, &alloc::format!("WORD1 {:x?}\n", os.control.word).as_bytes());
// TODO: If sa_mask caused signals to be unblocked, deliver one or all of those first?
@@ -161,13 +162,12 @@ unsafe fn inner(stack: &mut SigStack) {
);
core::sync::atomic::compiler_fence(Ordering::Acquire);
stack.old_mask = ((prev_w1 >> 32) << 32) | (prev_w0 >> 32);
// Call handler, either sa_handler or sa_siginfo depending on flag.
if sigaction.flags.contains(SigactionFlags::SIGINFO)
&& let Some(sigaction) = handler.sigaction
{
stack.old_mask = ((prev_w1 >> 32) << 32) | (prev_w0 >> 32);
//let _ = syscall::write(1, alloc::format!("SIGACTION {:p}\n", sigaction).as_bytes());
let info = SiginfoAbi {
si_signo: stack.sig_num as c_int,
si_addr: core::ptr::null_mut(),
@@ -184,10 +184,8 @@ unsafe fn inner(stack: &mut SigStack) {
stack as *mut SigStack as *mut (),
);
} else if let Some(handler) = handler.handler {
//let _ = syscall::write(1, alloc::format!("HANDLER {:p}\n", handler).as_bytes());
handler(stack.sig_num as c_int);
}
//let _ = syscall::write(1, alloc::format!("RETURNED HANDLER\n").as_bytes());
// Disable signals while we modify the sigmask again
control_flags.store(
@@ -197,25 +195,30 @@ unsafe fn inner(stack: &mut SigStack) {
core::sync::atomic::compiler_fence(Ordering::Acquire);
// Update allowset again.
//let _ = syscall::write(1, &alloc::format!("WORD2 {:x?}\n", os.control.word).as_bytes());
let new_mask = stack.old_mask;
let old_mask = (os.control.word[0].load(Ordering::Relaxed) >> 32)
| ((os.control.word[1].load(Ordering::Relaxed) >> 32) << 32);
let _prev_w0 = os.control.word[0].fetch_add(
(prev_sigallow_lo << 32).wrapping_sub(sigallow_inside_lo << 32),
((new_mask & 0xffff_ffff) << 32).wrapping_sub((old_mask & 0xffff_ffff) << 32),
Ordering::Relaxed,
);
let _prev_w1 = os.control.word[1].fetch_add(
(prev_sigallow_hi << 32).wrapping_sub(sigallow_inside_hi << 32),
((new_mask >> 32) << 32).wrapping_sub((old_mask >> 32) << 32),
Ordering::Relaxed,
);
//let _ = syscall::write(1, &alloc::format!("WORD3 {:x?}\n", os.control.word).as_bytes());
// TODO: If resetting the sigmask caused signals to be unblocked, then should they be delivered
// here? And would it be possible to tail-call-optimize that?
//let _ = syscall::write(1, alloc::format!("will return to {:x?}\n", stack.regs.eip).as_bytes());
(*os.arch.get()).last_sig_was_restart = shall_restart;
// TODO: Support setting uc_link to jump back to a different context?
(*os.arch.get()).last_sigstack = NonNull::new(stack.link);
// TODO: Support restoring uc_stack?
// And re-enable them again
if !signals_were_disabled {
core::sync::atomic::compiler_fence(Ordering::Release);
@@ -502,6 +505,7 @@ pub(crate) static PROC_CONTROL_STRUCT: SigProcControl = SigProcControl {
user_data: AtomicU64::new(0),
}
}; 64],
sender_infos: [const { AtomicU64::new(0) }; 32],
};
fn combine_allowset([lo, hi]: [u64; 2]) -> u64 {
+38
View File
@@ -1,5 +1,7 @@
use core::arch::global_asm;
use super::{sigset_t, stack_t};
pub const SIGHUP: usize = 1;
pub const SIGINT: usize = 2;
pub const SIGQUIT: usize = 3;
@@ -54,3 +56,39 @@ pub const SIGSTKSZ: usize = 8096;
pub const SI_QUEUE: i32 = -1;
pub const SI_USER: i32 = 0;
pub(crate) type ucontext_t = ucontext;
pub(crate) type mcontext_t = mcontext;
#[repr(C)]
pub struct ucontext {
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
_pad: [usize; 1], // pad from 7*8 to 64
#[cfg(target_arch = "x86")]
_pad: [usize; 3], // pad from 9*4 to 12*4
pub uc_link: *mut ucontext_t,
pub uc_stack: stack_t,
pub uc_sigmask: sigset_t,
_sival: usize,
_sigcode: u32,
_signum: u32,
pub uc_mcontext: mcontext_t,
}
#[repr(C)]
pub struct mcontext {
#[cfg(target_arch = "x86")]
_opaque: [u8; 512],
#[cfg(target_arch = "x86-64")]
_opaque: [u8; 864],
#[cfg(target_arch = "aarch64")]
_opaque: [u8; 272],
}
#[no_mangle]
pub extern "C" fn __completely_unused_cbindgen_workaround_fn_ucontext_mcontext(
a: *const ucontext_t,
b: *const mcontext_t,
) {
}
+2 -29
View File
@@ -13,8 +13,8 @@ use crate::{
header::{
errno::{EINVAL, ENOSYS},
signal::{
sigaction, siginfo_t, sigset_t, sigval, stack_t, SA_SIGINFO, SIG_BLOCK, SIG_DFL,
SIG_IGN, SIG_SETMASK, SIG_UNBLOCK, SS_DISABLE, SS_ONSTACK,
sigaction, siginfo_t, sigset_t, sigval, stack_t, ucontext_t, SA_SIGINFO, SIG_BLOCK,
SIG_DFL, SIG_IGN, SIG_SETMASK, SIG_UNBLOCK, SS_DISABLE, SS_ONSTACK,
},
sys_time::{itimerval, ITIMER_REAL},
time::timespec,
@@ -22,23 +22,6 @@ use crate::{
platform::ERRNO,
};
#[repr(C)]
pub struct ucontext_t {
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
_pad: [usize; 1], // pad from 7*8 to 64
#[cfg(target_arch = "x86")]
_pad: [usize; 3], // pad from 9*4 to 12*4
pub uc_link: *mut ucontext_t,
pub uc_stack: stack_t,
pub uc_sigmask: sigset_t,
_sival: usize,
_sigcode: u32,
_signum: u32,
pub uc_mcontext: mcontext_t,
}
const _: () = {
#[track_caller]
const fn assert_eq(a: usize, b: usize) {
@@ -61,16 +44,6 @@ const _: () = {
);
};
#[repr(C)]
pub struct mcontext_t {
#[cfg(target_arch = "x86")]
_opaque: [u8; 512],
#[cfg(target_arch = "x86-64")]
_opaque: [u8; 864],
#[cfg(target_arch = "aarch64")]
_opaque: [u8; 272],
}
impl PalSignal for Sys {
unsafe fn getitimer(which: c_int, out: *mut itimerval) -> c_int {
let path = match which {
+26 -6
View File
@@ -1,4 +1,6 @@
#include <assert.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -7,23 +9,41 @@
#include "test_helpers.h"
void handler1(int sig) {
ERROR_IF(handler, sig, != SIGUSR1);
puts("Signal handler1 called!");
assert(sig == SIGUSR1);
char *str = "Signal handler1 called!\n";
write(STDOUT_FILENO, str, strlen(str));
}
void handler2(int sig) {
ERROR_IF(handler, sig, != SIGUSR1);
puts("Signal handler2 called!");
sigset_t the_set = { 0 };
void handler2(int sig, siginfo_t *info, void *context_raw) {
assert(sig == SIGUSR1);
char *str = "Signal handler2 called!\n";
write(STDOUT_FILENO, str, strlen(str));
assert(info != NULL);
assert(info->si_signo == SIGUSR1);
assert(info->si_code == SI_USER);
assert(info->si_pid == getpid());
assert(info->si_uid == getuid());
ucontext_t *context = context_raw;
assert(context != NULL);
assert(memcmp(&context->uc_sigmask, &the_set, sizeof(sigset_t)));
assert(context->uc_link == NULL);
}
int main(void) {
struct sigaction sa1 = { .sa_handler = handler1 };
struct sigaction sa2 = { .sa_handler = handler2 };
struct sigaction sa2 = { .sa_sigaction = handler2, .sa_flags = SA_SIGINFO };
struct sigaction saold = {0};
sigemptyset(&sa1.sa_mask);
sigemptyset(&sa2.sa_mask);
int status = sigprocmask(SIG_SETMASK, NULL, &the_set);
ERROR_IF(sigprocmask, status, == -1);
int rcode = sigaction(SIGUSR1, &sa1, NULL);
ERROR_IF(signal, rcode, != 0);
+2
View File
@@ -17,6 +17,8 @@ int parent;
void action(int sig, siginfo_t *info, void *context) {
(void)context;
assert(sig == THE_SIG);
assert(info != NULL);
assert(context != NULL);
assert(info->si_signo == THE_SIG);
assert(info->si_value.sival_int == num);
assert(info->si_code == SI_QUEUE);