crosvm/crosvm/sys/linux/
jail_warden.rs1#![deny(missing_docs)]
8
9use std::path::Path;
10use std::sync::Arc;
11
12use anyhow::anyhow;
13use anyhow::Context;
14use anyhow::Result;
15use base::error;
16use base::info;
17use base::syslog;
18use base::AsRawDescriptor;
19#[cfg(feature = "swap")]
20use base::AsRawDescriptors;
21use base::Pid;
22use base::Tube;
23use devices::virtio::VirtioDeviceType;
24use devices::BusDevice;
25use devices::ChildProcIntf;
26use devices::PciDevice;
27use devices::ProxyDevice;
28use devices::ResourceCarrier;
29use jail::create_base_minijail;
30use jail::create_sandbox_minijail;
31use jail::fork::fork_process;
32use jail::fork::Child;
33use jail::RunAsUser;
34use jail::SandboxConfig;
35use jail::MAX_OPEN_FILES_FOR_JAIL_WARDEN;
36use serde::Deserialize;
37use serde::Serialize;
38#[cfg(feature = "swap")]
39use swap::SwapDeviceHelper;
40use sync::Mutex;
41use vm_memory::GuestMemory;
42
43use crate::crosvm::sys::linux::pci_hotplug_helpers::build_hotplug_net_device;
44use crate::crosvm::sys::linux::pci_hotplug_helpers::NetLocalParameters;
45use crate::crosvm::sys::linux::VirtioDeviceBuilder;
46use crate::Config;
47
48#[derive(Serialize, Deserialize)]
50pub enum JailCommand {
51 Exit,
53 ForkDevice(ResourceCarrier),
55}
56
57#[derive(Serialize, Deserialize)]
59pub enum JailResponse {
60 ForkDeviceError(String),
62 ForkDeviceOk(ChildProcIntf),
64}
65
66pub trait JailWarden {
68 fn make_proxy_device(
70 &self,
71 resource_carrier: ResourceCarrier,
72 ) -> Result<(Arc<Mutex<dyn BusDevice>>, Pid)>;
73}
74
75pub struct JailWardenImpl {
77 worker_process: Option<Child>,
78 main_tube: Tube,
79}
80
81impl JailWardenImpl {
82 pub fn new(
84 guest_memory: GuestMemory,
85 config: &Config,
86 #[cfg(feature = "swap")] swap_device_helper: Option<SwapDeviceHelper>,
87 ) -> Result<Self> {
88 let mut keep_rds = Vec::new();
89 syslog::push_descriptors(&mut keep_rds);
90 cros_tracing::push_descriptors!(&mut keep_rds);
91 metrics::push_descriptors(&mut keep_rds);
92 let (main_tube, worker_tube) = Tube::pair()?;
93 keep_rds.push(worker_tube.as_raw_descriptor());
94 #[cfg(feature = "swap")]
95 if let Some(swap_device_helper) = &swap_device_helper {
96 keep_rds.extend(swap_device_helper.as_raw_descriptors());
97 }
98
99 let jail = match &config.jail_config {
100 Some(jail_config) => {
101 base::info!("Using sandboxed jailwarden");
102 let mut sandbox_config = SandboxConfig::new(jail_config, "jail_warden");
103 sandbox_config.run_as = RunAsUser::CurrentUser;
105 sandbox_config.limit_caps = false;
107 sandbox_config.namespace_net = false;
109 create_sandbox_minijail(
110 Path::new("/"),
111 MAX_OPEN_FILES_FOR_JAIL_WARDEN,
112 &sandbox_config,
113 )
114 }
115 None => {
116 base::info!("Using base jailwarden");
117 create_base_minijail(Path::new("/"), MAX_OPEN_FILES_FOR_JAIL_WARDEN)
118 }
119 }?;
120
121 let worker_process =
122 fork_process(jail, keep_rds, Some(String::from("jail warden")), || {
123 if let Err(e) = jail_worker_process(
124 guest_memory,
125 worker_tube,
126 config,
127 #[cfg(feature = "swap")]
128 swap_device_helper,
129 ) {
130 error!("jail_worker_process exited with error: {:#}", e);
131 }
132 })?;
133 Ok(Self {
134 worker_process: Some(worker_process),
135 main_tube,
136 })
137 }
138}
139
140impl JailWarden for JailWardenImpl {
141 fn make_proxy_device(
142 &self,
143 resource_carrier: ResourceCarrier,
144 ) -> Result<(Arc<Mutex<dyn BusDevice>>, Pid)> {
145 self.main_tube
146 .send(&JailCommand::ForkDevice(resource_carrier))?;
147 match self.main_tube.recv::<JailResponse>()? {
148 JailResponse::ForkDeviceOk(proxy_device_primitive) => {
149 let proxy_device: ProxyDevice = proxy_device_primitive.try_into()?;
150 let pid = proxy_device.pid();
151 Ok((Arc::new(Mutex::new(proxy_device)), pid))
152 }
153 JailResponse::ForkDeviceError(e) => Err(anyhow!(e)),
154 }
155 }
156}
157
158impl Drop for JailWardenImpl {
159 fn drop(&mut self) {
160 if let Err(e) = self.main_tube.send(&JailCommand::Exit) {
161 error!("Failed to send jail warden exit command: {:?}", &e);
162 }
163 if let Some(worker_process) = self.worker_process.take() {
164 if let Err(e) = worker_process.wait() {
165 error!(
166 "Failed to wait for jail warden worker process shutdown: {:?}",
167 &e
168 );
169 }
170 }
171 }
172}
173
174fn jail_worker_process(
176 guest_memory: GuestMemory,
177 worker_tube: Tube,
178 config: &Config,
179 #[cfg(feature = "swap")] mut swap_device_helper: Option<SwapDeviceHelper>,
180) -> Result<()> {
181 info!("JailWarden worker process started");
182
183 'worker_loop: loop {
184 match worker_tube.recv::<JailCommand>()? {
185 JailCommand::Exit => {
186 break 'worker_loop;
187 }
188 JailCommand::ForkDevice(hot_plug_device_builder) => {
189 let (pci_device, jail) = match hot_plug_device_builder {
190 ResourceCarrier::VirtioNet(net_resource_carrier) => {
191 let net_param = &net_resource_carrier.net_param;
192 let jail = net_param
193 .create_jail(config.jail_config.as_ref(), VirtioDeviceType::Regular)?
194 .ok_or(anyhow!("no jail created"))?;
195 let net_local_parameters =
196 NetLocalParameters::new(guest_memory.clone(), config.protection_type);
197 let pci_device =
198 build_hotplug_net_device(net_resource_carrier, net_local_parameters)?;
199 (pci_device, jail)
200 }
201 };
202 let mut keep_rds = vec![];
203 syslog::push_descriptors(&mut keep_rds);
204 cros_tracing::push_descriptors!(&mut keep_rds);
205 metrics::push_descriptors(&mut keep_rds);
206 keep_rds.extend(pci_device.keep_rds());
207 let proxy_device_primitive = ChildProcIntf::new(
208 pci_device,
209 jail,
210 keep_rds,
211 #[cfg(feature = "swap")]
212 &mut swap_device_helper,
213 )?;
214 worker_tube
215 .send(&JailResponse::ForkDeviceOk(proxy_device_primitive))
216 .context("send ChildProcIntf failed.")?;
217 }
218 }
219 }
220 Ok(())
221}
222
223pub struct PermissiveJailWarden {
227 protection_type: hypervisor::ProtectionType,
228 guest_memory: GuestMemory,
229}
230
231impl PermissiveJailWarden {
232 pub fn new(
234 guest_memory: GuestMemory,
235 config: &Config,
236 #[cfg(feature = "swap")] _swap_device_helper: Option<SwapDeviceHelper>,
237 ) -> Result<Self> {
238 Ok(Self {
239 protection_type: config.protection_type,
240 guest_memory,
241 })
242 }
243}
244
245impl JailWarden for PermissiveJailWarden {
246 fn make_proxy_device(
247 &self,
248 resource_carrier: ResourceCarrier,
249 ) -> Result<(Arc<Mutex<dyn BusDevice>>, Pid)> {
250 let pci_device = match resource_carrier {
251 ResourceCarrier::VirtioNet(net_resource_carrier) => {
252 let net_local_parameters =
253 NetLocalParameters::new(self.guest_memory.clone(), self.protection_type);
254 build_hotplug_net_device(net_resource_carrier, net_local_parameters)?
255 }
256 };
257 Ok((Arc::new(Mutex::new(pci_device)), 0))
258 }
259}