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