1cac7dca0Sopenharmony_ci// Copyright (c) 2023 Huawei Device Co., Ltd. 2cac7dca0Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 3cac7dca0Sopenharmony_ci// you may not use this file except in compliance with the License. 4cac7dca0Sopenharmony_ci// You may obtain a copy of the License at 5cac7dca0Sopenharmony_ci// 6cac7dca0Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 7cac7dca0Sopenharmony_ci// 8cac7dca0Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 9cac7dca0Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 10cac7dca0Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11cac7dca0Sopenharmony_ci// See the License for the specific language governing permissions and 12cac7dca0Sopenharmony_ci// limitations under the License. 13cac7dca0Sopenharmony_ci 14cac7dca0Sopenharmony_ci//! Linux wrapping of signal syscall 15cac7dca0Sopenharmony_ci 16cac7dca0Sopenharmony_ciuse std::{io, mem, ptr}; 17cac7dca0Sopenharmony_ci 18cac7dca0Sopenharmony_ciuse libc::{c_int, c_void, sigaction, siginfo_t}; 19cac7dca0Sopenharmony_ci 20cac7dca0Sopenharmony_ciuse crate::common::{SigAction, Signal}; 21cac7dca0Sopenharmony_ciuse crate::sig_map::SigMap; 22cac7dca0Sopenharmony_ci 23cac7dca0Sopenharmony_ciimpl SigAction { 24cac7dca0Sopenharmony_ci pub(crate) fn get_old_action(sig_num: c_int) -> io::Result<Self> { 25cac7dca0Sopenharmony_ci let mut old_act: libc::sigaction = unsafe { mem::zeroed() }; 26cac7dca0Sopenharmony_ci unsafe { 27cac7dca0Sopenharmony_ci if libc::sigaction(sig_num, ptr::null(), &mut old_act) != 0 { 28cac7dca0Sopenharmony_ci return Err(io::Error::last_os_error()); 29cac7dca0Sopenharmony_ci } 30cac7dca0Sopenharmony_ci } 31cac7dca0Sopenharmony_ci Ok(SigAction { 32cac7dca0Sopenharmony_ci sig_num, 33cac7dca0Sopenharmony_ci act: old_act, 34cac7dca0Sopenharmony_ci }) 35cac7dca0Sopenharmony_ci } 36cac7dca0Sopenharmony_ci} 37cac7dca0Sopenharmony_ci 38cac7dca0Sopenharmony_ciimpl Signal { 39cac7dca0Sopenharmony_ci pub(crate) fn replace_sigaction(sig_num: c_int, new_action: usize) -> io::Result<sigaction> { 40cac7dca0Sopenharmony_ci let mut handler: libc::sigaction = unsafe { mem::zeroed() }; 41cac7dca0Sopenharmony_ci let mut old_act: libc::sigaction = unsafe { mem::zeroed() }; 42cac7dca0Sopenharmony_ci 43cac7dca0Sopenharmony_ci handler.sa_sigaction = new_action; 44cac7dca0Sopenharmony_ci handler.sa_flags = libc::SA_RESTART | libc::SA_SIGINFO; 45cac7dca0Sopenharmony_ci 46cac7dca0Sopenharmony_ci unsafe { 47cac7dca0Sopenharmony_ci if libc::sigaction(sig_num, &handler, &mut old_act) != 0 { 48cac7dca0Sopenharmony_ci return Err(io::Error::last_os_error()); 49cac7dca0Sopenharmony_ci } 50cac7dca0Sopenharmony_ci } 51cac7dca0Sopenharmony_ci 52cac7dca0Sopenharmony_ci Ok(old_act) 53cac7dca0Sopenharmony_ci } 54cac7dca0Sopenharmony_ci} 55cac7dca0Sopenharmony_ci 56cac7dca0Sopenharmony_cipub(crate) extern "C" fn sig_handler(sig_num: c_int, sig_info: *mut siginfo_t, data: *mut c_void) { 57cac7dca0Sopenharmony_ci let sig_map = SigMap::get_instance(); 58cac7dca0Sopenharmony_ci let race_fallback = sig_map.race_old.read(); 59cac7dca0Sopenharmony_ci let signals = sig_map.data.read(); 60cac7dca0Sopenharmony_ci 61cac7dca0Sopenharmony_ci if let Some(signal) = signals.get(&sig_num) { 62cac7dca0Sopenharmony_ci // sig_info should not be null, but in a sig handler we cannot panic directly, 63cac7dca0Sopenharmony_ci // therefore we abort instead 64cac7dca0Sopenharmony_ci if sig_info.is_null() { 65cac7dca0Sopenharmony_ci unsafe { libc::abort() }; 66cac7dca0Sopenharmony_ci } 67cac7dca0Sopenharmony_ci 68cac7dca0Sopenharmony_ci let info = unsafe { &*sig_info }; 69cac7dca0Sopenharmony_ci if let Some(act) = &signal.new_act { 70cac7dca0Sopenharmony_ci act(info); 71cac7dca0Sopenharmony_ci } 72cac7dca0Sopenharmony_ci } else if let Some(fallback) = race_fallback.as_ref() { 73cac7dca0Sopenharmony_ci // There could be a race condition between swapping the old handler with the new 74cac7dca0Sopenharmony_ci // handler and storing the change back to the global during the register 75cac7dca0Sopenharmony_ci // procedure. Because of the race condition, the old handler and the new 76cac7dca0Sopenharmony_ci // action could both not get executed. In order to prevent this, we 77cac7dca0Sopenharmony_ci // store the old handler into global before swapping the handler in 78cac7dca0Sopenharmony_ci // register. And during the handler execution, if the the action 79cac7dca0Sopenharmony_ci // of the signal cannot be found, we execute this old handler instead if the 80cac7dca0Sopenharmony_ci // sig_num matches. 81cac7dca0Sopenharmony_ci if fallback.sig_num == sig_num { 82cac7dca0Sopenharmony_ci execute_act(&fallback.act, sig_num, sig_info, data); 83cac7dca0Sopenharmony_ci } 84cac7dca0Sopenharmony_ci } 85cac7dca0Sopenharmony_ci} 86cac7dca0Sopenharmony_ci 87cac7dca0Sopenharmony_cifn execute_act(act: &sigaction, sig_num: c_int, sig_info: *mut siginfo_t, data: *mut c_void) { 88cac7dca0Sopenharmony_ci let handler = act.sa_sigaction; 89cac7dca0Sopenharmony_ci 90cac7dca0Sopenharmony_ci // SIG_DFL for the default action. 91cac7dca0Sopenharmony_ci // SIG_IGN to ignore this signal. 92cac7dca0Sopenharmony_ci if handler == libc::SIG_DFL || handler == libc::SIG_IGN { 93cac7dca0Sopenharmony_ci return; 94cac7dca0Sopenharmony_ci } 95cac7dca0Sopenharmony_ci 96cac7dca0Sopenharmony_ci // If SA_SIGINFO flag is set, then the signal handler takes three arguments, not 97cac7dca0Sopenharmony_ci // one. In this case, sa_sigaction should be set instead of sa_handler. 98cac7dca0Sopenharmony_ci // We transmute the handler from ptr to actual function type according to 99cac7dca0Sopenharmony_ci // definition. 100cac7dca0Sopenharmony_ci if act.sa_flags & libc::SA_SIGINFO == 0 { 101cac7dca0Sopenharmony_ci let action = unsafe { mem::transmute::<usize, extern "C" fn(c_int)>(handler) }; 102cac7dca0Sopenharmony_ci action(sig_num); 103cac7dca0Sopenharmony_ci } else { 104cac7dca0Sopenharmony_ci type Action = extern "C" fn(c_int, *mut siginfo_t, *mut c_void); 105cac7dca0Sopenharmony_ci let action = unsafe { mem::transmute::<usize, Action>(handler) }; 106cac7dca0Sopenharmony_ci action(sig_num, sig_info, data); 107cac7dca0Sopenharmony_ci } 108cac7dca0Sopenharmony_ci} 109