shadow_rs/host/syscall/handler/
signal.rs1use linux_api::errno::Errno;
2use linux_api::signal::{
3 LinuxDefaultAction, SigAltStackFlags, SigProcMaskAction, Signal, SignalHandler, defaultaction,
4 siginfo_t,
5};
6use shadow_shim_helper_rs::explicit_drop::{ExplicitDrop, ExplicitDropper};
7use shadow_shim_helper_rs::syscall_types::ForeignPtr;
8
9use crate::host::process::Process;
10use crate::host::syscall::handler::{SyscallContext, SyscallHandler, ThreadContext};
11use crate::host::thread::Thread;
12
13impl SyscallHandler {
14 log_syscall!(
15 kill,
16 std::ffi::c_int,
17 linux_api::posix_types::kernel_pid_t,
18 std::ffi::c_int,
19 );
20 pub fn kill(
21 ctx: &mut SyscallContext,
22 pid: linux_api::posix_types::kernel_pid_t,
23 sig: std::ffi::c_int,
24 ) -> Result<(), Errno> {
25 log::trace!("kill called on pid {pid} with signal {sig}");
26
27 let pid = if pid == -1 {
28 log::warn!("kill with pid=-1 unimplemented");
34 return Err(Errno::ENOTSUP);
35 } else if pid == 0 {
36 ctx.objs.process.id()
44 } else if pid < -1 {
45 (-pid).try_into().or(Err(Errno::ESRCH))?
53 } else {
54 pid.try_into().or(Err(Errno::ESRCH))?
55 };
56
57 let Some(target_process) = ctx.objs.host.process_borrow(pid) else {
58 log::debug!("Process {pid} not found");
59 return Err(Errno::ESRCH);
60 };
61 let target_process = &*target_process.borrow(ctx.objs.host.root());
62
63 Self::signal_process(ctx.objs, target_process, sig)
64 }
65
66 fn signal_process(
69 objs: &ThreadContext,
70 target_process: &Process,
71 signal: std::ffi::c_int,
72 ) -> Result<(), Errno> {
73 if signal == 0 {
74 return Ok(());
75 }
76
77 let Ok(signal) = Signal::try_from(signal) else {
78 return Err(Errno::EINVAL);
79 };
80
81 if signal.is_realtime() {
82 log::warn!("Unimplemented signal {signal:?}");
83 return Err(Errno::ENOTSUP);
84 }
85
86 let sender_pid = objs.process.id().into();
87 let siginfo = siginfo_t::new_for_kill(signal, sender_pid, 0);
88
89 target_process.signal(objs.host, Some(objs.thread), &siginfo);
90
91 Ok(())
92 }
93
94 log_syscall!(
95 tkill,
96 std::ffi::c_int,
97 linux_api::posix_types::kernel_pid_t,
98 std::ffi::c_int,
99 );
100 pub fn tkill(
101 ctx: &mut SyscallContext,
102 tid: linux_api::posix_types::kernel_pid_t,
103 sig: std::ffi::c_int,
104 ) -> Result<(), Errno> {
105 log::trace!("tkill called on tid {tid} with signal {sig}");
106
107 let tid = tid.try_into().or(Err(Errno::ESRCH))?;
108
109 let Some(target_thread) = ctx.objs.host.thread_cloned_rc(tid) else {
110 return Err(Errno::ESRCH);
111 };
112 let target_thread = ExplicitDropper::new(target_thread, |value| {
113 value.explicit_drop(ctx.objs.host.root())
114 });
115 let target_thread = &*target_thread.borrow(ctx.objs.host.root());
116
117 Self::signal_thread(ctx.objs, target_thread, sig)
118 }
119
120 log_syscall!(
121 tgkill,
122 std::ffi::c_int,
123 linux_api::posix_types::kernel_pid_t,
124 linux_api::posix_types::kernel_pid_t,
125 std::ffi::c_int,
126 );
127 pub fn tgkill(
128 ctx: &mut SyscallContext,
129 tgid: linux_api::posix_types::kernel_pid_t,
130 tid: linux_api::posix_types::kernel_pid_t,
131 sig: std::ffi::c_int,
132 ) -> Result<(), Errno> {
133 log::trace!("tgkill called on tgid {tgid} and tid {tid} with signal {sig}");
134
135 let tgid = tgid.try_into().or(Err(Errno::ESRCH))?;
136 let tid = tid.try_into().or(Err(Errno::ESRCH))?;
137
138 let Some(target_thread) = ctx.objs.host.thread_cloned_rc(tid) else {
139 return Err(Errno::ESRCH);
140 };
141 let target_thread = ExplicitDropper::new(target_thread, |value| {
142 value.explicit_drop(ctx.objs.host.root())
143 });
144 let target_thread = &*target_thread.borrow(ctx.objs.host.root());
145
146 if target_thread.process_id() != tgid {
147 return Err(Errno::ESRCH);
148 }
149
150 Self::signal_thread(ctx.objs, target_thread, sig)
151 }
152
153 fn signal_thread(
156 objs: &ThreadContext,
157 target_thread: &Thread,
158 signal: std::ffi::c_int,
159 ) -> Result<(), Errno> {
160 if signal == 0 {
161 return Ok(());
162 }
163
164 let Ok(signal) = Signal::try_from(signal) else {
165 return Err(Errno::EINVAL);
166 };
167
168 if signal.is_realtime() {
169 log::warn!("Unimplemented signal {signal:?}");
170 return Err(Errno::ENOTSUP);
171 }
172
173 let mut cond = {
175 let shmem_lock = &*objs.host.shim_shmem_lock_borrow().unwrap();
176
177 let target_process = objs
178 .host
179 .process_borrow(target_thread.process_id())
180 .unwrap();
181 let target_process = &*target_process.borrow(objs.host.root());
182
183 let process_shmem = target_process.borrow_as_runnable().unwrap();
184 let process_shmem = &*process_shmem.shmem();
185 let process_protected = process_shmem.protected.borrow(&shmem_lock.root);
186
187 let thread_shmem = target_thread.shmem();
188 let mut thread_protected = thread_shmem.protected.borrow_mut(&shmem_lock.root);
189
190 let action = unsafe { process_protected.signal_action(signal) };
191 let action_handler = unsafe { action.handler() };
192
193 let signal_is_ignored = match action_handler {
194 SignalHandler::SigIgn => true,
195 SignalHandler::SigDfl => defaultaction(signal) == LinuxDefaultAction::IGN,
196 _ => false,
197 };
198
199 if signal_is_ignored {
200 return Ok(());
202 }
203
204 if thread_protected.pending_signals.has(signal) {
205 return Ok(());
209 }
210
211 thread_protected.pending_signals.add(signal);
212
213 let sender_pid = objs.process.id();
214 let sender_tid = objs.thread.id();
215
216 let siginfo = siginfo_t::new_for_tkill(signal, sender_pid.into(), 0);
217
218 thread_protected.set_pending_standard_siginfo(signal, &siginfo);
219
220 if sender_tid == target_thread.id() {
221 return Ok(());
224 }
225
226 if thread_protected.blocked_signals.has(signal) {
227 return Ok(());
231 }
232
233 let Some(cond) = target_thread.syscall_condition_mut() else {
234 return Ok(());
237 };
238
239 cond
240 };
241
242 let was_scheduled = cond.wakeup_for_signal(objs.host, signal);
243
244 assert!(was_scheduled);
247
248 Ok(())
249 }
250
251 log_syscall!(
252 rt_sigaction,
253 std::ffi::c_int,
254 std::ffi::c_int,
255 *const std::ffi::c_void,
256 *const std::ffi::c_void,
257 libc::size_t,
258 );
259 pub fn rt_sigaction(
260 ctx: &mut SyscallContext,
261 sig: std::ffi::c_int,
262 act: ForeignPtr<linux_api::signal::sigaction>,
263 oact: ForeignPtr<linux_api::signal::sigaction>,
264 sigsetsize: libc::size_t,
265 ) -> Result<(), Errno> {
266 if sigsetsize != size_of::<linux_api::signal::sigset_t>() {
275 return Err(Errno::EINVAL);
276 }
277
278 let Ok(sig) = Signal::try_from(sig) else {
279 return Err(Errno::EINVAL);
280 };
281
282 let shmem_lock = ctx.objs.host.shim_shmem_lock_borrow().unwrap();
283 let process_shmem = ctx.objs.process.shmem();
284 let mut process_protected = process_shmem.protected.borrow_mut(&shmem_lock.root);
285
286 if !oact.is_null() {
287 let old_action = unsafe { process_protected.signal_action(sig) };
288 ctx.objs
289 .process
290 .memory_borrow_mut()
291 .write(oact, old_action)?;
292 }
293
294 if act.is_null() {
295 return Ok(());
297 }
298
299 if sig == Signal::SIGKILL || sig == Signal::SIGSTOP {
300 return Err(Errno::EINVAL);
301 }
302
303 let new_action = ctx.objs.process.memory_borrow().read(act)?;
304 unsafe { *process_protected.signal_action_mut(sig) = new_action };
305
306 Ok(())
307 }
308
309 log_syscall!(
310 rt_sigprocmask,
311 std::ffi::c_int,
312 std::ffi::c_int,
313 *const std::ffi::c_void,
314 *const std::ffi::c_void,
315 libc::size_t,
316 );
317 pub fn rt_sigprocmask(
318 ctx: &mut SyscallContext,
319 how: std::ffi::c_int,
320 nset: ForeignPtr<linux_api::signal::sigset_t>,
321 oset: ForeignPtr<linux_api::signal::sigset_t>,
322 sigsetsize: libc::size_t,
323 ) -> Result<(), Errno> {
324 if sigsetsize != size_of::<linux_api::signal::sigset_t>() {
329 warn_once_then_debug!("Bad sigsetsize {sigsetsize}");
330 return Err(Errno::EINVAL);
331 }
332
333 let shmem_lock = ctx.objs.host.shim_shmem_lock_borrow().unwrap();
334 let thread_shmem = ctx.objs.thread.shmem();
335 let mut thread_protected = thread_shmem.protected.borrow_mut(&shmem_lock.root);
336
337 let current_set = thread_protected.blocked_signals;
338
339 if !oset.is_null() {
340 ctx.objs
341 .process
342 .memory_borrow_mut()
343 .write(oset, ¤t_set)?;
344 }
345
346 if nset.is_null() {
347 return Ok(());
349 }
350
351 let set = ctx.objs.process.memory_borrow().read(nset)?;
352
353 let set = match SigProcMaskAction::try_from(how) {
354 Ok(SigProcMaskAction::SIG_BLOCK) => set | current_set,
355 Ok(SigProcMaskAction::SIG_UNBLOCK) => !set & current_set,
356 Ok(SigProcMaskAction::SIG_SETMASK) => set,
357 Err(_) => return Err(Errno::EINVAL),
358 };
359
360 thread_protected.blocked_signals = set;
361
362 Ok(())
363 }
364
365 log_syscall!(
366 sigaltstack,
367 std::ffi::c_int,
368 *const std::ffi::c_void,
369 *const std::ffi::c_void,
370 );
371 pub fn sigaltstack(
372 ctx: &mut SyscallContext,
373 uss: ForeignPtr<linux_api::signal::stack_t>,
374 uoss: ForeignPtr<linux_api::signal::stack_t>,
375 ) -> Result<(), Errno> {
376 let shmem_lock = ctx.objs.host.shim_shmem_lock_borrow().unwrap();
377 let thread_shmem = ctx.objs.thread.shmem();
378 let mut thread_protected = thread_shmem.protected.borrow_mut(&shmem_lock.root);
379
380 let old_ss = unsafe { *thread_protected.sigaltstack() };
381
382 if !uss.is_null() {
383 if old_ss.flags_retain().contains(SigAltStackFlags::SS_ONSTACK) {
384 return Err(Errno::EPERM);
387 }
388
389 let mut new_ss = ctx.objs.process.memory_borrow().read(uss)?;
390 if new_ss.flags_retain().contains(SigAltStackFlags::SS_DISABLE) {
391 new_ss = shadow_pod::zeroed();
395 new_ss.ss_flags = SigAltStackFlags::SS_DISABLE.bits();
396 }
397
398 let unrecognized_flags = new_ss
399 .flags_retain()
400 .difference(SigAltStackFlags::SS_DISABLE | SigAltStackFlags::SS_AUTODISARM);
401
402 if !unrecognized_flags.is_empty() {
403 warn_once_then_debug!(
404 "Unrecognized signal stack flags {unrecognized_flags:?} in {:?}",
405 new_ss.flags_retain(),
406 );
407 return Err(Errno::EINVAL);
409 }
410
411 *unsafe { thread_protected.sigaltstack_mut() } = new_ss;
412 }
413
414 if !uoss.is_null() {
417 ctx.objs.process.memory_borrow_mut().write(uoss, &old_ss)?;
418 }
419
420 Ok(())
421 }
422}
423
424#[cfg(test)]
425mod test {
426 use super::*;
427
428 #[test]
431 fn unrecognized_flags_difference() {
432 let foo = 1 << 28;
433 assert_eq!(SigAltStackFlags::from_bits(foo), None);
435 let foo = SigAltStackFlags::from_bits_retain(foo);
436 assert_eq!(
437 foo.difference(SigAltStackFlags::SS_DISABLE).bits(),
438 (1 << 28) & !SigAltStackFlags::SS_DISABLE.bits(),
439 );
440 assert_eq!(
441 (foo - SigAltStackFlags::SS_DISABLE).bits(),
442 (1 << 28) & !SigAltStackFlags::SS_DISABLE.bits(),
443 );
444 }
445
446 #[test]
447 fn unrecognized_flags_empty() {
448 let foo = 1 << 28;
449 assert_ne!(foo, 0);
450 assert_eq!(SigAltStackFlags::from_bits(foo), None);
452 let foo = SigAltStackFlags::from_bits_retain(foo);
453 assert_ne!(foo.bits(), 0);
454 assert!(!foo.is_empty());
455 }
456}