mod init; mod run; mod spec; use std::{io, process}; use ipc_channel::ipc; use nix::{sys::signal, unistd}; use serde::{Deserialize, Serialize}; use crate::types::*; use crate::unshare; use crate::util::ipc::CheckDisconnect; #[derive(Debug, Deserialize, Serialize)] struct Request( TaskRef, TaskDef, ipc::IpcSender>, ); fn runner( idmap_finished: ipc::IpcReceiver<()>, init_error_sender: ipc::IpcSender, channel: ipc::IpcReceiver, ) -> ! { if let Err(error) = init::runc_preinit() { init_error_sender.send(error).expect("IPC send() failed"); process::exit(1); } drop(init_error_sender); idmap_finished .recv() .check_disconnect() .expect("IPC recv() error") .expect("Unexpected IPC message"); unistd::setuid(unistd::Uid::from_raw(0)).expect("setuid()"); unistd::setgid(unistd::Gid::from_raw(0)).expect("setgid()"); unistd::setgroups(&[]).expect("setgroups()"); init::runc_init().unwrap(); unsafe { signal::signal(signal::Signal::SIGCHLD, signal::SigHandler::SigIgn) }.unwrap(); while let Ok(request) = channel.recv() { match unsafe { unistd::fork() }.expect("fork()") { unistd::ForkResult::Parent { .. } => {} unistd::ForkResult::Child => { unsafe { signal::signal(signal::Signal::SIGCHLD, signal::SigHandler::SigDfl) } .unwrap(); let Request(task, task_def, reply_sender) = request; let result = run::handle_task(task, task_def); reply_sender.send(result).expect("IPC send() failed"); } } } process::exit(0); } pub struct RuncRunner { channel: ipc::IpcSender, } impl RuncRunner { /// Creates a new Runc runner /// /// Unsafe: Do not call in multithreaded processes pub unsafe fn new() -> io::Result { let (tx, rx) = ipc::channel().expect("IPC channel creation failed"); let (idmap_finished_tx, idmap_finished_rx) = ipc::channel().expect("IPC channel creation failed"); let (init_error_tx, init_error_rx) = ipc::channel().expect("IPC channel creation failed"); let pid = match unistd::fork().expect("fork()") { unistd::ForkResult::Parent { child } => { drop(rx); drop(idmap_finished_rx); drop(init_error_tx); child } unistd::ForkResult::Child => { drop(tx); drop(idmap_finished_tx); drop(init_error_rx); runner(idmap_finished_rx, init_error_tx, rx); /* Not reached */ } }; init_error_rx .recv() .check_disconnect() .expect("IPC recv() error")?; unshare::idmap(pid)?; drop(idmap_finished_tx); Ok(RuncRunner { channel: tx }) } } impl super::Runner for RuncRunner { fn run(&self, tasks: &TaskMap, task: &TaskRef) -> super::Result { let task_def = tasks.get(task).expect("Invalid TaskRef"); let (reply_tx, reply_rx) = ipc::channel().expect("IPC channel creation failed"); self.channel .send(Request(task.clone(), task_def.clone(), reply_tx)) .expect("RuncRunner task submission failed"); Ok(reply_rx.recv().expect("IPC recv() error")?) } }