Add new API occlum_pal_kill
This API enables sending signals to one or multiple LibOS processes from outside the enclave.
This commit is contained in:
parent
6e140a0d38
commit
1d1330772c
@ -61,6 +61,23 @@ enclave {
|
||||
* ESRCH - Cannot find the LibOS thread.
|
||||
*/
|
||||
public int occlum_ecall_exec_thread(int libos_tid, int host_tid);
|
||||
|
||||
/*
|
||||
* Send a signal to one or multiple LibOS processes.
|
||||
*
|
||||
* If pid == -1, send the signal to all processes. If pid > 0, send
|
||||
* the signal to the specific process. For the purpose of security,
|
||||
* the only allowed signals for now are SIGKILL and SIGTERM.
|
||||
*
|
||||
* @retval On success, return 0. On error, return -errno.
|
||||
*
|
||||
* The possible values of errno are
|
||||
* EAGAIN - The LibOS is not initialized.
|
||||
* EINVAL - The value of an argument are invalid.
|
||||
* ESRCH - Cannot find the process specified by pid.
|
||||
* EPERM - No permission to send the signal or to the process.
|
||||
*/
|
||||
public int occlum_ecall_kill(int pid, int sig);
|
||||
};
|
||||
|
||||
untrusted {
|
||||
|
@ -1,14 +1,16 @@
|
||||
use super::*;
|
||||
use exception::*;
|
||||
use fs::HostStdioFds;
|
||||
use process::pid_t;
|
||||
use std::ffi::{CStr, CString, OsString};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Once;
|
||||
use util::log::LevelFilter;
|
||||
use util::mem_util::from_untrusted::*;
|
||||
use util::sgx::allow_debug as sgx_allow_debug;
|
||||
|
||||
use super::*;
|
||||
use crate::exception::*;
|
||||
use crate::fs::HostStdioFds;
|
||||
use crate::process::ProcessFilter;
|
||||
use crate::signal::SigNum;
|
||||
use crate::util::log::LevelFilter;
|
||||
use crate::util::mem_util::from_untrusted::*;
|
||||
use crate::util::sgx::allow_debug as sgx_allow_debug;
|
||||
use sgx_tse::*;
|
||||
|
||||
pub static mut INSTANCE_DIR: String = String::new();
|
||||
@ -129,6 +131,25 @@ pub extern "C" fn occlum_ecall_exec_thread(libos_pid: i32, host_tid: i32) -> i32
|
||||
.unwrap_or(ecall_errno!(EFAULT))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn occlum_ecall_kill(pid: i32, sig: i32) -> i32 {
|
||||
if HAS_INIT.load(Ordering::SeqCst) == false {
|
||||
return ecall_errno!(EAGAIN);
|
||||
}
|
||||
|
||||
let _ = unsafe { backtrace::enable_backtrace(&ENCLAVE_PATH, PrintFormat::Short) };
|
||||
panic::catch_unwind(|| {
|
||||
backtrace::__rust_begin_short_backtrace(|| match do_kill(pid, sig) {
|
||||
Ok(()) => 0,
|
||||
Err(e) => {
|
||||
eprintln!("failed to kill: {}", e.backtrace());
|
||||
ecall_errno!(e.errno())
|
||||
}
|
||||
})
|
||||
})
|
||||
.unwrap_or(ecall_errno!(EFAULT))
|
||||
}
|
||||
|
||||
fn parse_log_level(level_chars: *const c_char) -> Result<LevelFilter> {
|
||||
const DEFAULT_LEVEL: LevelFilter = LevelFilter::Off;
|
||||
|
||||
@ -255,3 +276,23 @@ fn validate_program_path(target_path: &PathBuf) -> Result<()> {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn do_kill(pid: i32, sig: i32) -> Result<()> {
|
||||
let filter = if pid > 0 {
|
||||
ProcessFilter::WithPid(pid as pid_t)
|
||||
} else if pid == -1 {
|
||||
ProcessFilter::WithAnyPid
|
||||
} else if pid < 0 {
|
||||
return_errno!(EINVAL, "Invalid pid");
|
||||
} else {
|
||||
// pid == 0
|
||||
return_errno!(EPERM, "Process 0 cannot be killed");
|
||||
};
|
||||
let signum = {
|
||||
if sig < 0 {
|
||||
return_errno!(EINVAL, "invalid arguments");
|
||||
}
|
||||
SigNum::from_u8(sig as u8)?
|
||||
};
|
||||
crate::signal::do_kill_from_outside_enclave(filter, signum)
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use super::signals::{UserSignal, UserSignalKind};
|
||||
use super::constants::*;
|
||||
use super::signals::{KernelSignal, UserSignal, UserSignalKind};
|
||||
use super::{SigNum, Signal};
|
||||
use crate::prelude::*;
|
||||
use crate::process::{table, ProcessFilter, ProcessRef, ProcessStatus, ThreadRef, ThreadStatus};
|
||||
@ -21,6 +22,32 @@ pub fn do_kill(filter: ProcessFilter, signum: SigNum) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Send a signal from the outside the enclave.
|
||||
///
|
||||
/// Such a call must be performed very carefully. The obvious reason
|
||||
/// is that the call is not trusted. And there is a less obvious reason:
|
||||
/// the function is not executed during a normal syscall. Thus, current!() does
|
||||
/// not refer to a valid LibOS thread. So let's implement this function with
|
||||
/// these two insights in mind.
|
||||
pub fn do_kill_from_outside_enclave(filter: ProcessFilter, signum: SigNum) -> Result<()> {
|
||||
let signal = {
|
||||
if signum != SIGKILL && signum != SIGTERM {
|
||||
return_errno!(EPERM, "The signal is not allowed");
|
||||
}
|
||||
Box::new(KernelSignal::new(signum))
|
||||
};
|
||||
let processes = get_processes(&filter)?;
|
||||
for process in processes {
|
||||
if process.status() == ProcessStatus::Zombie {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut sig_queues = process.sig_queues().lock().unwrap();
|
||||
sig_queues.enqueue(signal.clone());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_processes(filter: &ProcessFilter) -> Result<Vec<ProcessRef>> {
|
||||
let processes = match filter {
|
||||
ProcessFilter::WithAnyPid => table::get_all_processes(),
|
||||
|
@ -6,6 +6,7 @@ use sig_action::{SigAction, SigActionFlags, SigDefaultAction};
|
||||
|
||||
pub use self::c_types::{sigaction_t, sigset_t};
|
||||
pub use self::constants::*;
|
||||
pub use self::do_kill::do_kill_from_outside_enclave;
|
||||
pub use self::do_sigreturn::{deliver_signal, force_signal};
|
||||
pub use self::sig_dispositions::SigDispositions;
|
||||
pub use self::sig_num::SigNum;
|
||||
|
@ -73,6 +73,18 @@ int occlum_pal_exec(const char* cmd_path,
|
||||
const struct occlum_stdio_fds* io_fds,
|
||||
int* exit_status);
|
||||
|
||||
/*
|
||||
* @brief Send a signal to one or multiple LibOS processes
|
||||
*
|
||||
* @param pid If pid > 0, send the signal to the process with the
|
||||
* pid; if pid == -1, send the signal to all processes.
|
||||
* @param sig The signal number. For the purpose of security, the
|
||||
* only allowed signals for now are SIGKILL and SIGTERM.
|
||||
*
|
||||
* @retval If 0, then success; otherwise, check errno for the exact error type.
|
||||
*/
|
||||
int occlum_pal_kill(int pid, int sig);
|
||||
|
||||
/*
|
||||
* @brief Destroy teh Occlum enclave
|
||||
*
|
||||
|
@ -94,6 +94,32 @@ int occlum_pal_exec(const char* cmd_path,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int occlum_pal_kill(int pid, int sig) {
|
||||
errno = 0;
|
||||
|
||||
sgx_enclave_id_t eid = pal_get_enclave_id();
|
||||
if (eid == SGX_INVALID_ENCLAVE_ID) {
|
||||
errno = ENOENT;
|
||||
PAL_ERROR("Enclave is not initialized yet.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ecall_ret = 0;
|
||||
sgx_status_t ecall_status = occlum_ecall_kill(eid, &ecall_ret, pid, sig);
|
||||
if (ecall_status != SGX_SUCCESS) {
|
||||
const char* sgx_err = pal_get_sgx_error_msg(ecall_status);
|
||||
PAL_ERROR("Failed to do ECall: %s", sgx_err);
|
||||
return -1;
|
||||
}
|
||||
if (ecall_ret < 0) {
|
||||
errno = -ecall_ret;
|
||||
PAL_ERROR("Failed to occlum_ecall_kill: %s", errno2str(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int occlum_pal_destroy(void) {
|
||||
errno = 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user