• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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