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 //! Linux wrapping of signal syscall
15
16 use std::{io, mem, ptr};
17
18 use libc::{c_int, c_void, sigaction, siginfo_t};
19
20 use crate::common::{SigAction, Signal};
21 use crate::sig_map::SigMap;
22
23 impl SigAction {
get_old_action(sig_num: c_int) -> io::Result<Self>24 pub(crate) fn get_old_action(sig_num: c_int) -> io::Result<Self> {
25 let mut old_act: libc::sigaction = unsafe { mem::zeroed() };
26 unsafe {
27 if libc::sigaction(sig_num, ptr::null(), &mut old_act) != 0 {
28 return Err(io::Error::last_os_error());
29 }
30 }
31 Ok(SigAction {
32 sig_num,
33 act: old_act,
34 })
35 }
36 }
37
38 impl Signal {
replace_sigaction(sig_num: c_int, new_action: usize) -> io::Result<sigaction>39 pub(crate) fn replace_sigaction(sig_num: c_int, new_action: usize) -> io::Result<sigaction> {
40 let mut handler: libc::sigaction = unsafe { mem::zeroed() };
41 let mut old_act: libc::sigaction = unsafe { mem::zeroed() };
42
43 handler.sa_sigaction = new_action;
44 handler.sa_flags = libc::SA_RESTART | libc::SA_SIGINFO;
45
46 unsafe {
47 if libc::sigaction(sig_num, &handler, &mut old_act) != 0 {
48 return Err(io::Error::last_os_error());
49 }
50 }
51
52 Ok(old_act)
53 }
54 }
55
sig_handler(sig_num: c_int, sig_info: *mut siginfo_t, data: *mut c_void)56 pub(crate) extern "C" fn sig_handler(sig_num: c_int, sig_info: *mut siginfo_t, data: *mut c_void) {
57 let sig_map = SigMap::get_instance();
58 let race_fallback = sig_map.race_old.read();
59 let signals = sig_map.data.read();
60
61 if let Some(signal) = signals.get(&sig_num) {
62 // sig_info should not be null, but in a sig handler we cannot panic directly,
63 // therefore we abort instead
64 if sig_info.is_null() {
65 unsafe { libc::abort() };
66 }
67
68 let info = unsafe { &*sig_info };
69 if let Some(act) = &signal.new_act {
70 act(info);
71 }
72 } else if let Some(fallback) = race_fallback.as_ref() {
73 // There could be a race condition between swapping the old handler with the new
74 // handler and storing the change back to the global during the register
75 // procedure. Because of the race condition, the old handler and the new
76 // action could both not get executed. In order to prevent this, we
77 // store the old handler into global before swapping the handler in
78 // register. And during the handler execution, if the the action
79 // of the signal cannot be found, we execute this old handler instead if the
80 // sig_num matches.
81 if fallback.sig_num == sig_num {
82 execute_act(&fallback.act, sig_num, sig_info, data);
83 }
84 }
85 }
86
execute_act(act: &sigaction, sig_num: c_int, sig_info: *mut siginfo_t, data: *mut c_void)87 fn execute_act(act: &sigaction, sig_num: c_int, sig_info: *mut siginfo_t, data: *mut c_void) {
88 let handler = act.sa_sigaction;
89
90 // SIG_DFL for the default action.
91 // SIG_IGN to ignore this signal.
92 if handler == libc::SIG_DFL || handler == libc::SIG_IGN {
93 return;
94 }
95
96 // If SA_SIGINFO flag is set, then the signal handler takes three arguments, not
97 // one. In this case, sa_sigaction should be set instead of sa_handler.
98 // We transmute the handler from ptr to actual function type according to
99 // definition.
100 if act.sa_flags & libc::SA_SIGINFO == 0 {
101 let action = unsafe { mem::transmute::<usize, extern "C" fn(c_int)>(handler) };
102 action(sig_num);
103 } else {
104 type Action = extern "C" fn(c_int, *mut siginfo_t, *mut c_void);
105 let action = unsafe { mem::transmute::<usize, Action>(handler) };
106 action(sig_num, sig_info, data);
107 }
108 }
109