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 16use std::{io, mem, ptr}; 17 18use libc::{c_int, c_void, sigaction, siginfo_t}; 19 20use crate::common::{SigAction, Signal}; 21use crate::sig_map::SigMap; 22 23impl SigAction { 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 38impl Signal { 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 56pub(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 87fn 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