Pass host-generated SIGPIPE to libos

Socket-related ocalls, e.g, sendto, sendmsg and write, may cause SIGPIPE
in host. Since the ocall is called by libos, this kind of signal should
be handled in libos. We ignore SIGPIPE in host and raise the same signal
in libos if the return value of the above ocalls is EPIPE. In this way
the signal is handled by libos.
This commit is contained in:
He Sun 2020-09-14 17:15:48 +08:00 committed by Tate, Hongliang Tian
parent 44583e15be
commit 5d5e8d44ec
6 changed files with 41 additions and 17 deletions

@ -51,3 +51,20 @@ macro_rules! try_libc {
ret ret
}}; }};
} }
// return Err(errno) if libc return -1
// raise SIGPIPE if errno == EPIPE
macro_rules! try_libc_may_epipe {
($ret: expr) => {{
let ret = unsafe { $ret };
if ret < 0 {
let errno = unsafe { libc::errno() };
if errno == Errno::EPIPE as i32 {
// SIGPIPE = 12
crate::signal::do_tkill(current!().tid(), 12);
}
return_errno!(Errno::from(errno as u32), "libc error");
}
ret
}};
}

@ -59,7 +59,7 @@ impl File for SocketFile {
fn write(&self, buf: &[u8]) -> Result<usize> { fn write(&self, buf: &[u8]) -> Result<usize> {
let (buf_ptr, buf_len) = buf.as_ptr_and_len(); let (buf_ptr, buf_len) = buf.as_ptr_and_len();
let ret = try_libc!(libc::ocall::write( let ret = try_libc_may_epipe!(libc::ocall::write(
self.host_fd, self.host_fd,
buf_ptr as *const c_void, buf_ptr as *const c_void,
buf_len buf_len

@ -56,10 +56,10 @@ impl SocketFile {
let (msg_control, msg_controllen) = control.as_ptr_and_len(); let (msg_control, msg_controllen) = control.as_ptr_and_len();
let msg_control = msg_control as *const c_void; let msg_control = msg_control as *const c_void;
// Flags // Flags
let flags = flags.bits(); let raw_flags = flags.bits();
let bytes_sent = try_libc!({ // Do OCall
// Do OCall unsafe {
let status = occlum_ocall_sendmsg( let status = occlum_ocall_sendmsg(
&mut retval as *mut isize, &mut retval as *mut isize,
host_fd, host_fd,
@ -69,12 +69,17 @@ impl SocketFile {
msg_iovlen, msg_iovlen,
msg_control, msg_control,
msg_controllen, msg_controllen,
flags, raw_flags,
); );
assert!(status == sgx_status_t::SGX_SUCCESS); assert!(status == sgx_status_t::SGX_SUCCESS);
}
let bytes_sent = if flags.contains(SendFlags::MSG_NOSIGNAL) {
try_libc!(retval)
} else {
try_libc_may_epipe!(retval)
};
retval
});
debug_assert!(bytes_sent >= 0); debug_assert!(bytes_sent >= 0);
Ok(bytes_sent as usize) Ok(bytes_sent as usize)
} }

@ -286,7 +286,7 @@ pub fn do_sendto(
let file_ref = current!().file(fd as FileDesc)?; let file_ref = current!().file(fd as FileDesc)?;
if let Ok(socket) = file_ref.as_socket() { if let Ok(socket) = file_ref.as_socket() {
// TODO: check addr and addr_len according to connection mode // TODO: check addr and addr_len according to connection mode
let ret = try_libc!(libc::ocall::sendto( let ret = try_libc_may_epipe!(libc::ocall::sendto(
socket.fd(), socket.fd(),
base, base,
len, len,

@ -36,12 +36,10 @@ int occlum_pal_init(const struct occlum_pal_attr *attr) {
errno = EEXIST; errno = EEXIST;
return -1; return -1;
} }
// FIXME
#ifndef SGX_MODE_SIM
if (pal_register_sig_handlers() < 0) { if (pal_register_sig_handlers() < 0) {
return -1; return -1;
} }
#endif
if (pal_init_enclave(resolved_path) < 0) { if (pal_init_enclave(resolved_path) < 0) {
return -1; return -1;

@ -7,12 +7,16 @@
#define SIGRT_INTERRUPT 64 #define SIGRT_INTERRUPT 64
int pal_register_sig_handlers(void) { int pal_register_sig_handlers(void) {
struct sigaction action; // FIXME: enable interruptable signal in SIM mode
action.sa_handler = SIG_IGN; #ifndef SGX_MODE_SIM
memset(&action.sa_mask, 0, sizeof(action.sa_mask)); if (signal(SIGRT_INTERRUPT, SIG_IGN) == SIG_ERR) {
action.sa_flags = 0; PAL_ERROR("Failed to regiter the SIG64 handler");
if (sigaction(SIGRT_INTERRUPT, &action, NULL) < 0) { return -1;
PAL_ERROR("Failed to regiter signal handlers"); }
#endif
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
PAL_ERROR("Failed to regiter the SIGPIPE handler");
return -1; return -1;
} }
return 0; return 0;