Skip to main content

strat9_kernel/syscall/
signal.rs

1//! Signal-related syscall handlers for Strat9-OS.
2
3use super::error::SyscallError;
4use crate::{
5    memory::{UserSliceRead, UserSliceWrite},
6    process::{
7        current_pgid, current_task_clone, current_task_id, get_all_tasks, get_task_by_id,
8        get_task_id_by_pid, get_task_ids_in_pgid,
9        signal::{SigActionData, SigStack, Signal},
10        TaskId,
11    },
12};
13
14/// Performs the sys sigaction operation.
15pub fn sys_sigaction(signum: u64, act_ptr: u64, oact_ptr: u64) -> Result<u64, SyscallError> {
16    use core::mem;
17
18    let signal = Signal::from_u32(signum as u32).ok_or(SyscallError::InvalidArgument)?;
19    if signal.is_uncatchable() {
20        return Err(SyscallError::InvalidArgument);
21    }
22
23    let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
24
25    unsafe {
26        let actions = &mut *task.process.signal_actions.get();
27
28        if oact_ptr != 0 {
29            let old = actions[signum as usize];
30            let raw = SigActionRaw {
31                sa_handler: old.handler,
32                sa_flags: old.flags,
33                sa_restorer: old.restorer,
34                sa_mask: old.mask,
35            };
36            let user = UserSliceWrite::new(oact_ptr, mem::size_of::<SigActionRaw>())?;
37            user.copy_from(&raw.to_bytes());
38        }
39
40        if act_ptr != 0 {
41            let user = UserSliceRead::new(act_ptr, mem::size_of::<SigActionRaw>())?;
42            let bytes = user.read_to_vec();
43            if bytes.len() != mem::size_of::<SigActionRaw>() {
44                return Err(SyscallError::InvalidArgument);
45            }
46            let raw = SigActionRaw::from_bytes(&bytes);
47            actions[signum as usize] = SigActionData {
48                handler: raw.sa_handler,
49                flags: raw.sa_flags,
50                restorer: raw.sa_restorer,
51                mask: raw.sa_mask,
52            };
53        }
54    }
55
56    Ok(0)
57}
58
59/// Raw representation of struct sigaction for userspace
60#[repr(C)]
61struct SigActionRaw {
62    sa_handler: u64,
63    sa_flags: u64,
64    sa_restorer: u64,
65    sa_mask: u64,
66}
67
68impl SigActionRaw {
69    /// Converts this to bytes.
70    fn to_bytes(&self) -> [u8; 32] {
71        let mut bytes = [0u8; 32];
72        bytes[0..8].copy_from_slice(&self.sa_handler.to_ne_bytes());
73        bytes[8..16].copy_from_slice(&self.sa_flags.to_ne_bytes());
74        bytes[16..24].copy_from_slice(&self.sa_restorer.to_ne_bytes());
75        bytes[24..32].copy_from_slice(&self.sa_mask.to_ne_bytes());
76        bytes
77    }
78
79    /// Builds this from bytes.
80    fn from_bytes(bytes: &[u8]) -> Self {
81        Self {
82            sa_handler: u64::from_ne_bytes(bytes[0..8].try_into().unwrap()),
83            sa_flags: u64::from_ne_bytes(bytes[8..16].try_into().unwrap()),
84            sa_restorer: u64::from_ne_bytes(bytes[16..24].try_into().unwrap()),
85            sa_mask: u64::from_ne_bytes(bytes[24..32].try_into().unwrap()),
86        }
87    }
88}
89
90/// SYS_SIGALTSTACK (323): Set/get signal alternate stack.
91///
92/// arg1 = ss_ptr (new stack), arg2 = old_ss_ptr (old stack out)
93pub fn sys_sigaltstack(ss_ptr: u64, old_ss_ptr: u64) -> Result<u64, SyscallError> {
94    let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
95
96    // SAFETY: We have a reference to the task.
97    unsafe {
98        let stack = &mut *task.signal_stack.get();
99
100        // If old_ss_ptr is not null, write the old stack.
101        if old_ss_ptr != 0 {
102            let user = UserSliceWrite::new(old_ss_ptr, 24)?; // sizeof(SigStack)
103            let raw = match stack {
104                Some(s) => SigStackRaw {
105                    ss_sp: s.ss_sp,
106                    ss_flags: s.ss_flags,
107                    ss_size: s.ss_size,
108                },
109                None => SigStackRaw {
110                    ss_sp: 0,
111                    ss_flags: 1, // SS_DISABLE
112                    ss_size: 0,
113                },
114            };
115            user.copy_from(&raw.to_bytes());
116        }
117
118        // If ss_ptr is not null, update the stack.
119        if ss_ptr != 0 {
120            let user = UserSliceRead::new(ss_ptr, 24)?;
121            let bytes = user.read_to_vec();
122            if bytes.len() != 24 {
123                return Err(SyscallError::InvalidArgument);
124            }
125            let raw = SigStackRaw::from_bytes(&bytes);
126
127            if raw.ss_flags & 1 != 0 {
128                // SS_DISABLE
129                *stack = None;
130            } else {
131                *stack = Some(SigStack {
132                    ss_sp: raw.ss_sp,
133                    ss_flags: raw.ss_flags,
134                    ss_size: raw.ss_size,
135                });
136            }
137        }
138    }
139
140    Ok(0)
141}
142
143#[repr(C)]
144struct SigStackRaw {
145    ss_sp: u64,
146    ss_flags: i32,
147    ss_size: usize,
148}
149
150impl SigStackRaw {
151    /// Converts this to bytes.
152    fn to_bytes(&self) -> [u8; 24] {
153        let mut bytes = [0u8; 24];
154        bytes[0..8].copy_from_slice(&self.ss_sp.to_ne_bytes());
155        bytes[8..12].copy_from_slice(&self.ss_flags.to_ne_bytes());
156        bytes[12..16].copy_from_slice(&(self.ss_size as u32).to_ne_bytes());
157        bytes[16..20].copy_from_slice(&((self.ss_size >> 32) as u32).to_ne_bytes());
158        bytes
159    }
160
161    /// Builds this from bytes.
162    fn from_bytes(bytes: &[u8]) -> Self {
163        Self {
164            ss_sp: u64::from_ne_bytes(bytes[0..8].try_into().unwrap()),
165            ss_flags: i32::from_ne_bytes(bytes[8..12].try_into().unwrap()),
166            ss_size: (u32::from_ne_bytes(bytes[12..16].try_into().unwrap()) as usize)
167                | ((u32::from_ne_bytes(bytes[16..20].try_into().unwrap()) as usize) << 32),
168        }
169    }
170}
171
172/// SYS_SIGPENDING (324): Check for pending signals.
173///
174/// arg1 = set_ptr (output signal set)
175pub fn sys_sigpending(set_ptr: u64) -> Result<u64, SyscallError> {
176    let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
177
178    // We have a reference to the task.
179    let pending = &task.pending_signals;
180    let mask = pending.get_mask();
181
182    if set_ptr != 0 {
183        let user = UserSliceWrite::new(set_ptr, 8)?;
184        user.copy_from(&mask.to_ne_bytes());
185    }
186
187    Ok(0)
188}
189
190/// SYS_SIGSUSPEND (325): Wait for signals.
191///
192/// arg1 = mask_ptr (temporary signal mask)
193/// Returns EINTR if a signal was caught
194pub fn sys_sigsuspend(mask_ptr: u64) -> Result<u64, SyscallError> {
195    let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
196
197    // We have a reference to the task.
198    // Save the old mask
199    let blocked = &task.blocked_signals;
200    let old_mask = blocked.get_mask();
201
202    // Set the new mask
203    if mask_ptr != 0 {
204        let user = UserSliceRead::new(mask_ptr, 8)?;
205        let mut buf = [0u8; 8];
206        user.copy_to(&mut buf);
207        let new_mask = u64::from_ne_bytes(buf);
208        blocked.set_mask(new_mask);
209    }
210
211    // Block the task until a signal arrives
212    // The task will be woken by send_signal() if an unblocked signal is pending
213    crate::process::block_current_task();
214
215    // Restore the old mask
216    blocked.set_mask(old_mask);
217
218    // If we get here, we were woken by a signal
219    Err(SyscallError::Interrupted)
220}
221
222/// SYS_SIGTIMEDWAIT (326): Wait for signals with timeout.
223///
224/// arg1 = set_ptr (signal set to wait for), arg2 = siginfo_ptr (output), arg3 = timeout_ptr
225pub fn sys_sigtimedwait(
226    set_ptr: u64,
227    _siginfo_ptr: u64,
228    _timeout_ptr: u64,
229) -> Result<u64, SyscallError> {
230    // TODO: Implement proper timed wait
231    // For now, just check if any signal in the set is pending
232
233    let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
234
235    // We have a reference to the task.
236    let pending = &task.pending_signals;
237    let blocked = &task.blocked_signals;
238
239    // Read the signal set to wait for
240    if set_ptr != 0 {
241        let user = UserSliceRead::new(set_ptr, 8)?;
242        let mut buf = [0u8; 8];
243        user.copy_to(&mut buf);
244        let wait_mask = u64::from_ne_bytes(buf);
245
246        // Check if any signal in wait_mask is pending and not blocked
247        let pending_mask = pending.get_mask();
248        let blocked_mask = blocked.get_mask();
249        let deliverable = pending_mask & wait_mask & !blocked_mask;
250
251        if deliverable != 0 {
252            // Return the lowest signal number
253            let signal_num = deliverable.trailing_zeros() + 1;
254            pending.remove(Signal::from_u32(signal_num).unwrap());
255            return Ok(signal_num as u64);
256        }
257    }
258
259    // No signal pending - would need to implement timeout wait
260    Err(SyscallError::Interrupted)
261}
262
263/// SYS_SIGQUEUE (327): Send signal with value to a task.
264///
265/// arg1 = pid, arg2 = signum, arg3 = sigval_ptr
266pub fn sys_sigqueue(pid: i64, signum: u32, _sigval_ptr: u64) -> Result<u64, SyscallError> {
267    // TODO: store sigval with the pending signal record.
268    sys_kill(pid, signum)
269}
270
271/// SYS_KILLPG (328): Send signal to process group.
272///
273/// arg1 = pgrp, arg2 = signum
274pub fn sys_killpg(pgrp: u64, signum: u32) -> Result<u64, SyscallError> {
275    if pgrp == 0 {
276        return Err(SyscallError::InvalidArgument);
277    }
278    sys_kill(-(pgrp as i64), signum)
279}
280
281/// SYS_KILL (320): POSIX kill semantics by pid/group.
282pub fn sys_kill(pid: i64, signum: u32) -> Result<u64, SyscallError> {
283    let targets = resolve_kill_targets(pid)?;
284    let sender = current_task_clone().ok_or(SyscallError::Fault)?;
285    if signum == 0 {
286        // Existence + permission check only.
287        for target in &targets {
288            if !has_kill_permission(&sender, *target)? {
289                return Err(SyscallError::PermissionDenied);
290            }
291        }
292        return Ok(0);
293    }
294
295    let signal = Signal::from_u32(signum).ok_or(SyscallError::InvalidArgument)?;
296    let mut delivered = 0usize;
297    for target in targets {
298        if !has_kill_permission(&sender, target)? {
299            continue;
300        }
301        crate::process::send_signal(target, signal)?;
302        delivered += 1;
303    }
304    if delivered == 0 {
305        return Err(SyscallError::PermissionDenied);
306    }
307    Ok(0)
308}
309
310/// Returns whether kill permission is available.
311fn has_kill_permission(
312    sender: &alloc::sync::Arc<crate::process::Task>,
313    target_id: TaskId,
314) -> Result<bool, SyscallError> {
315    let target = get_task_by_id(target_id).ok_or(SyscallError::NotFound)?;
316
317    let sender_euid = sender.euid.load(core::sync::atomic::Ordering::Relaxed);
318    if sender_euid == 0 {
319        return Ok(true);
320    }
321
322    let sender_uid = sender.uid.load(core::sync::atomic::Ordering::Relaxed);
323    let target_uid = target.uid.load(core::sync::atomic::Ordering::Relaxed);
324    let target_euid = target.euid.load(core::sync::atomic::Ordering::Relaxed);
325    Ok(sender_uid == target_uid
326        || sender_uid == target_euid
327        || sender_euid == target_uid
328        || sender_euid == target_euid)
329}
330
331/// Performs the resolve kill targets operation.
332fn resolve_kill_targets(pid: i64) -> Result<alloc::vec::Vec<TaskId>, SyscallError> {
333    use alloc::vec::Vec;
334
335    let mut targets = Vec::new();
336    match pid {
337        p if p > 0 => {
338            let target = get_task_id_by_pid(p as u32).ok_or(SyscallError::NotFound)?;
339            targets.push(target);
340        }
341        0 => {
342            let pgid = current_pgid().ok_or(SyscallError::Fault)?;
343            targets = get_task_ids_in_pgid(pgid);
344        }
345        -1 => {
346            let me = current_task_id();
347            if let Some(tasks) = get_all_tasks() {
348                for task in tasks {
349                    if task.is_kernel() {
350                        continue;
351                    }
352                    if Some(task.id) == me {
353                        continue;
354                    }
355                    targets.push(task.id);
356                }
357            }
358        }
359        p => {
360            let pgid = (-p) as u32;
361            targets = get_task_ids_in_pgid(pgid);
362        }
363    }
364
365    if targets.is_empty() {
366        return Err(SyscallError::NotFound);
367    }
368    Ok(targets)
369}
370
371/// SYS_GETITIMER (329): Get interval timer value.
372///
373/// arg1 = which (ITIMER_REAL/VIRTUAL/PROF), arg2 = value_ptr (output)
374pub fn sys_getitimer(which: u32, value_ptr: u64) -> Result<u64, SyscallError> {
375    use crate::process::timer::{ITimerVal, ITimerWhich};
376    use core::mem;
377
378    let which = ITimerWhich::from_u32(which).ok_or(SyscallError::InvalidArgument)?;
379    let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
380
381    // Get current monotonic time (stub for now - returns 0)
382    // TODO: Implement proper time source
383    let current_time_ns = 0u64;
384
385    let timer = task.itimers.get(which);
386    let value = timer.get(current_time_ns);
387
388    if value_ptr != 0 {
389        let user = UserSliceWrite::new(value_ptr, mem::size_of::<ITimerVal>())?;
390        user.copy_from(&itimerval_to_bytes(&value));
391    }
392
393    Ok(0)
394}
395
396/// SYS_SETITIMER (330): Set interval timer value.
397///
398/// arg1 = which (ITIMER_REAL/VIRTUAL/PROF), arg2 = new_value_ptr, arg3 = old_value_ptr (output)
399pub fn sys_setitimer(
400    which: u32,
401    new_value_ptr: u64,
402    old_value_ptr: u64,
403) -> Result<u64, SyscallError> {
404    use crate::process::timer::{ITimerVal, ITimerWhich};
405    use core::mem;
406
407    let which = ITimerWhich::from_u32(which).ok_or(SyscallError::InvalidArgument)?;
408    let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
409
410    let current_time_ns = crate::syscall::time::current_time_ns();
411
412    let timer = task.itimers.get(which);
413
414    // Get old value if requested
415    if old_value_ptr != 0 {
416        let old_value = timer.get(current_time_ns);
417        let user = UserSliceWrite::new(old_value_ptr, mem::size_of::<ITimerVal>())?;
418        user.copy_from(&itimerval_to_bytes(&old_value));
419    }
420
421    // Set new value if provided
422    if new_value_ptr != 0 {
423        let user = UserSliceRead::new(new_value_ptr, mem::size_of::<ITimerVal>())?;
424        let bytes = user.read_to_vec();
425        if bytes.len() != mem::size_of::<ITimerVal>() {
426            return Err(SyscallError::InvalidArgument);
427        }
428        let new_value = itimerval_from_bytes(&bytes);
429        let valid = |sec: i64, usec: i64| sec >= 0 && (0..1_000_000).contains(&usec);
430        if !valid(new_value.it_interval.tv_sec, new_value.it_interval.tv_usec)
431            || !valid(new_value.it_value.tv_sec, new_value.it_value.tv_usec)
432        {
433            return Err(SyscallError::InvalidArgument);
434        }
435        timer.set(&new_value, current_time_ns);
436    }
437
438    Ok(0)
439}
440
441/// Convert ITimerVal to bytes
442fn itimerval_to_bytes(val: &crate::process::timer::ITimerVal) -> [u8; 32] {
443    let mut bytes = [0u8; 32];
444    // it_interval
445    bytes[0..8].copy_from_slice(&val.it_interval.tv_sec.to_ne_bytes());
446    bytes[8..16].copy_from_slice(&val.it_interval.tv_usec.to_ne_bytes());
447    // it_value
448    bytes[16..24].copy_from_slice(&val.it_value.tv_sec.to_ne_bytes());
449    bytes[24..32].copy_from_slice(&val.it_value.tv_usec.to_ne_bytes());
450    bytes
451}
452
453/// Convert bytes to ITimerVal
454fn itimerval_from_bytes(bytes: &[u8]) -> crate::process::timer::ITimerVal {
455    use crate::process::timer::{ITimerVal, TimeVal};
456    ITimerVal {
457        it_interval: TimeVal {
458            tv_sec: i64::from_ne_bytes(bytes[0..8].try_into().unwrap()),
459            tv_usec: i64::from_ne_bytes(bytes[8..16].try_into().unwrap()),
460        },
461        it_value: TimeVal {
462            tv_sec: i64::from_ne_bytes(bytes[16..24].try_into().unwrap()),
463            tv_usec: i64::from_ne_bytes(bytes[24..32].try_into().unwrap()),
464        },
465    }
466}
467
468/// Performs the sys rt sigreturn operation.
469pub fn sys_rt_sigreturn(frame: &mut super::SyscallFrame) -> Result<u64, SyscallError> {
470    use crate::process::signal::{SignalFrame, SIGNAL_FRAME_MAGIC};
471
472    let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
473    let user_rsp = frame.iret_rsp;
474
475    let frame_size = core::mem::size_of::<SignalFrame>();
476    let sig_frame_addr = user_rsp - 8; // RET popped the restorer, back up to frame start
477
478    let user = UserSliceRead::new(sig_frame_addr, frame_size)?;
479    let bytes = user.read_to_vec();
480    if bytes.len() != frame_size {
481        return Err(SyscallError::Fault);
482    }
483
484    // SAFETY: SignalFrame is repr(C) and matches the byte layout
485    let sig_frame: SignalFrame =
486        unsafe { core::ptr::read_unaligned(bytes.as_ptr() as *const SignalFrame) };
487
488    if sig_frame.magic != SIGNAL_FRAME_MAGIC {
489        log::warn!("[sigreturn] bad magic, killing");
490        crate::process::kill_task(task.id);
491        return Err(SyscallError::Fault);
492    }
493
494    task.blocked_signals.set_mask(sig_frame.saved_mask);
495
496    frame.iret_rip = sig_frame.rip;
497    frame.iret_rsp = sig_frame.rsp;
498    frame.iret_rflags = sig_frame.rflags;
499    frame.rax = sig_frame.rax;
500    frame.rcx = sig_frame.rcx;
501    frame.rdx = sig_frame.rdx;
502    frame.rbx = sig_frame.rbx;
503    frame.rbp = sig_frame.rbp;
504    frame.rsi = sig_frame.rsi;
505    frame.rdi = sig_frame.rdi;
506    frame.r8 = sig_frame.r8;
507    frame.r9 = sig_frame.r9;
508    frame.r10 = sig_frame.r10;
509    frame.r11 = sig_frame.r11;
510    frame.r12 = sig_frame.r12;
511    frame.r13 = sig_frame.r13;
512    frame.r14 = sig_frame.r14;
513    frame.r15 = sig_frame.r15;
514
515    Ok(frame.rax)
516}