1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 use std::sync::Arc;
15 use std::{io, mem};
16
17 use libc::{c_int, c_void, sigaction, siginfo_t, SIGFPE, SIGILL, SIGKILL, SIGSEGV, SIGSTOP};
18
19 use crate::linux::signal_manager::{SigAction, SignalManager};
20
21 // These signals should not be handled at all due to POSIX settings or their
22 // specialness
23 const SIGNAL_BLOCK_LIST: &[c_int] = &[SIGSEGV, SIGKILL, SIGSTOP, SIGILL, SIGFPE];
24
25 type SigHandler = dyn Fn(&siginfo_t) + Send + Sync;
26
27 #[derive(Clone)]
28 pub struct Signal {
29 sig_num: c_int,
30 old_act: sigaction,
31 new_act: Option<Arc<SigHandler>>,
32 }
33
34 impl Signal {
register_action<F>(sig_num: c_int, handler: F) -> io::Result<()> where F: Fn(&siginfo_t) + Sync + Send + 'static,35 pub(crate) unsafe fn register_action<F>(sig_num: c_int, handler: F) -> io::Result<()>
36 where
37 F: Fn(&siginfo_t) + Sync + Send + 'static,
38 {
39 if SIGNAL_BLOCK_LIST.contains(&sig_num) {
40 return Err(io::ErrorKind::InvalidInput.into());
41 }
42
43 let global = SignalManager::get_instance();
44 let act = Arc::new(handler);
45 let mut write_guard = global.data.write();
46 let mut signal_map = write_guard.clone();
47
48 if let Some(signal) = signal_map.get_mut(&sig_num) {
49 if signal.new_act.is_some() {
50 return Err(io::ErrorKind::AlreadyExists.into());
51 } else {
52 signal.new_act = Some(act);
53 }
54 } else {
55 let old_act = SigAction::get_old_action(sig_num)?;
56 global.race_old.write().store(Some(old_act));
57
58 let signal = Signal::new(sig_num, act)?;
59 signal_map.insert(sig_num, signal);
60 }
61 write_guard.store(signal_map);
62 Ok(())
63 }
64
deregister_action(sig_num: c_int)65 pub(crate) fn deregister_action(sig_num: c_int) {
66 let global = SignalManager::get_instance();
67 let mut write_guard = global.data.write();
68 let mut signal_map = write_guard.clone();
69 if let Some(signal) = signal_map.get_mut(&sig_num) {
70 signal.new_act = None;
71 }
72 write_guard.store(signal_map);
73 }
74
deregister_hook(sig_num: c_int) -> io::Result<()>75 pub(crate) fn deregister_hook(sig_num: c_int) -> io::Result<()> {
76 let mut new_act: libc::sigaction = unsafe { mem::zeroed() };
77 let mut old_act: libc::sigaction = unsafe { mem::zeroed() };
78 new_act.sa_sigaction = libc::SIG_DFL;
79
80 let global = SignalManager::get_instance();
81 let mut write_guard = global.data.write();
82 let mut signal_map = write_guard.clone();
83
84 unsafe {
85 if libc::sigaction(sig_num, &new_act, &mut old_act) != 0 {
86 return Err(io::Error::last_os_error());
87 }
88 }
89 signal_map.remove(&sig_num);
90 write_guard.store(signal_map);
91 Ok(())
92 }
93
new(sig_num: c_int, new_act: Arc<SigHandler>) -> io::Result<Signal>94 fn new(sig_num: c_int, new_act: Arc<SigHandler>) -> io::Result<Signal> {
95 // c structure, initialized it to all zeros
96 let mut handler: libc::sigaction = unsafe { mem::zeroed() };
97 let mut old_act: libc::sigaction = unsafe { mem::zeroed() };
98
99 handler.sa_sigaction = sig_handler as usize;
100 handler.sa_flags = libc::SA_RESTART | libc::SA_SIGINFO;
101
102 unsafe {
103 if libc::sigaction(sig_num, &handler, &mut old_act) != 0 {
104 return Err(io::Error::last_os_error());
105 }
106 }
107 Ok(Signal {
108 sig_num,
109 old_act,
110 new_act: Some(new_act),
111 })
112 }
113 }
114
sig_handler(sig_num: c_int, sig_info: *mut siginfo_t, data: *mut c_void)115 extern "C" fn sig_handler(sig_num: c_int, sig_info: *mut siginfo_t, data: *mut c_void) {
116 let global = SignalManager::get_instance();
117 let race_fallback = global.race_old.read();
118 let signal_map = global.data.read();
119
120 if let Some(signal) = signal_map.get(&sig_num) {
121 execute_act(&signal.old_act, signal.sig_num, sig_info, data);
122
123 // sig_info should not be null, but in a sig handler we cannot panic directly,
124 // therefore we abort instead
125 if sig_info.is_null() {
126 unsafe { libc::abort() };
127 }
128
129 let info = unsafe { &*sig_info };
130 if let Some(act) = &signal.new_act {
131 act(info);
132 }
133 } else if let Some(old_act) = race_fallback.as_ref() {
134 // There could be a race condition between swapping the old handler with the new
135 // handler and storing the change back to the global during the register
136 // procedure. Because of the race condition, the old handler and the new
137 // action could both not get executed. In order to prevent this, we
138 // store the old handler into global before swapping the handler in
139 // register. And during the handler execution, if the the action
140 // of the signal cannot be found, we execute this old handler instead if the
141 // sig_num matches.
142 if old_act.sig_num == sig_num {
143 execute_act(&old_act.act, sig_num, sig_info, data);
144 }
145 }
146 }
147
execute_act(act: &sigaction, sig_num: c_int, sig_info: *mut siginfo_t, data: *mut c_void)148 fn execute_act(act: &sigaction, sig_num: c_int, sig_info: *mut siginfo_t, data: *mut c_void) {
149 let handler = act.sa_sigaction;
150
151 // SIG_DFL for the default action.
152 // SIG_IGN to ignore this signal.
153 if handler == libc::SIG_DFL || handler == libc::SIG_IGN {
154 return;
155 }
156
157 // If SA_SIGINFO flag is set, then the signal handler takes three arguments, not
158 // one. In this case, sa_sigaction should be set instead of sa_handler.
159 // We transmute the handler from ptr to actual function type according to
160 // definition.
161 if act.sa_flags & libc::SA_SIGINFO == 0 {
162 let action = unsafe { mem::transmute::<usize, extern "C" fn(c_int)>(handler) };
163 action(sig_num);
164 } else {
165 type Action = extern "C" fn(c_int, *mut siginfo_t, *mut c_void);
166 let action = unsafe { mem::transmute::<usize, Action>(handler) };
167 action(sig_num, sig_info, data);
168 }
169 }
170