1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use std::collections::hash_map::{Entry, HashMap, VacantEntry};
6 use std::env::set_var;
7 use std::fs::File;
8 use std::io::{IoSlice, IoSliceMut, Write};
9 use std::mem::transmute;
10 use std::os::unix::net::UnixDatagram;
11 use std::path::Path;
12 use std::process::Command;
13 use std::result;
14 use std::sync::{Arc, RwLock};
15 use std::thread::JoinHandle;
16
17 use net_util::Error as NetError;
18
19 use libc::{
20 pid_t, waitpid, EINVAL, ENODATA, ENOTTY, STDERR_FILENO, WEXITSTATUS, WIFEXITED, WNOHANG,
21 WTERMSIG,
22 };
23
24 use protobuf::Message;
25
26 use base::{
27 error, AsRawDescriptor, Descriptor, Error as SysError, Event, IntoRawDescriptor, Killable,
28 MemoryMappingBuilder, Result as SysResult, ScmSocket, SharedMemory, SharedMemoryUnix, SIGRTMIN,
29 };
30 use kvm::{dirty_log_bitmap_size, Datamatch, IoeventAddress, IrqRoute, IrqSource, PicId, Vm};
31 use kvm_sys::{kvm_clock_data, kvm_ioapic_state, kvm_pic_state, kvm_pit_state2};
32 use minijail::Minijail;
33 use protos::plugin::*;
34 use sync::Mutex;
35 use vm_memory::GuestAddress;
36
37 use super::*;
38
39 // Wrapper types to make the kvm state structs DataInit
40 use data_model::DataInit;
41 #[derive(Copy, Clone)]
42 struct VmPicState(kvm_pic_state);
43 unsafe impl DataInit for VmPicState {}
44 #[derive(Copy, Clone)]
45 struct VmIoapicState(kvm_ioapic_state);
46 unsafe impl DataInit for VmIoapicState {}
47 #[derive(Copy, Clone)]
48 struct VmPitState(kvm_pit_state2);
49 unsafe impl DataInit for VmPitState {}
50 #[derive(Copy, Clone)]
51 struct VmClockState(kvm_clock_data);
52 unsafe impl DataInit for VmClockState {}
53
54 const CROSVM_SOCKET_ENV: &str = "CROSVM_SOCKET";
55
get_vm_state(vm: &Vm, state_set: MainRequest_StateSet) -> SysResult<Vec<u8>>56 fn get_vm_state(vm: &Vm, state_set: MainRequest_StateSet) -> SysResult<Vec<u8>> {
57 Ok(match state_set {
58 MainRequest_StateSet::PIC0 => VmPicState(vm.get_pic_state(PicId::Primary)?)
59 .as_slice()
60 .to_vec(),
61 MainRequest_StateSet::PIC1 => VmPicState(vm.get_pic_state(PicId::Secondary)?)
62 .as_slice()
63 .to_vec(),
64 MainRequest_StateSet::IOAPIC => VmIoapicState(vm.get_ioapic_state()?).as_slice().to_vec(),
65 MainRequest_StateSet::PIT => VmPitState(vm.get_pit_state()?).as_slice().to_vec(),
66 MainRequest_StateSet::CLOCK => VmClockState(vm.get_clock()?).as_slice().to_vec(),
67 })
68 }
69
set_vm_state(vm: &Vm, state_set: MainRequest_StateSet, state: &[u8]) -> SysResult<()>70 fn set_vm_state(vm: &Vm, state_set: MainRequest_StateSet, state: &[u8]) -> SysResult<()> {
71 match state_set {
72 MainRequest_StateSet::PIC0 => vm.set_pic_state(
73 PicId::Primary,
74 &VmPicState::from_slice(state)
75 .ok_or(SysError::new(EINVAL))?
76 .0,
77 ),
78 MainRequest_StateSet::PIC1 => vm.set_pic_state(
79 PicId::Secondary,
80 &VmPicState::from_slice(state)
81 .ok_or(SysError::new(EINVAL))?
82 .0,
83 ),
84 MainRequest_StateSet::IOAPIC => vm.set_ioapic_state(
85 &VmIoapicState::from_slice(state)
86 .ok_or(SysError::new(EINVAL))?
87 .0,
88 ),
89 MainRequest_StateSet::PIT => vm.set_pit_state(
90 &VmPitState::from_slice(state)
91 .ok_or(SysError::new(EINVAL))?
92 .0,
93 ),
94 MainRequest_StateSet::CLOCK => vm.set_clock(
95 &VmClockState::from_slice(state)
96 .ok_or(SysError::new(EINVAL))?
97 .0,
98 ),
99 }
100 }
101
102 /// The status of a process, either that it is running, or that it exited under some condition.
103 pub enum ProcessStatus {
104 /// The process is running and therefore has no information about its result.
105 Running,
106 /// The process has exited with a successful code.
107 Success,
108 /// The process failed with the given exit code.
109 Fail(i32),
110 /// The process was terminated with the given signal code.
111 Signal(i32),
112 }
113
114 /// Creates, owns, and handles messages from a plugin process.
115 ///
116 /// A plugin process has control over a single VM and a fixed number of VCPUs via a set of pipes & unix
117 /// domain socket connections and a protocol defined in `protos::plugin`. The plugin process is run
118 /// in an unprivileged manner as a child process spawned via a path to a arbitrary executable.
119 pub struct Process {
120 started: bool,
121 plugin_pid: pid_t,
122 request_sockets: Vec<UnixDatagram>,
123 objects: HashMap<u32, PluginObject>,
124 shared_vcpu_state: Arc<RwLock<SharedVcpuState>>,
125 per_vcpu_states: Vec<Arc<Mutex<PerVcpuState>>>,
126
127 // Resource to sent to plugin
128 kill_evt: Event,
129 vcpu_pipes: Vec<VcpuPipe>,
130
131 // Socket Transmission
132 request_buffer: Vec<u8>,
133 response_buffer: Vec<u8>,
134 }
135
136 impl Process {
137 /// Creates a new plugin process for the given number of vcpus and VM.
138 ///
139 /// This will immediately spawn the plugin process and wait for the child to signal that it is
140 /// ready to start. This call may block indefinitely.
141 ///
142 /// Set the `jail` argument to spawn the plugin process within the preconfigured jail.
143 /// Due to an API limitation in libminijail necessitating that this function set an environment
144 /// variable, this function is not thread-safe.
145 ///
146 /// Arguments:
147 ///
148 /// * `cpu_count`: number of vcpus
149 /// * `cmd`: path to plugin executable
150 /// * `args`: arguments to plugin executable
151 /// * `jail`: jail to launch plugin in. If None plugin will just be spawned as a child
152 /// * `stderr`: File to redirect stderr of plugin process to
153 /// * `env_fds`: collection of (Name, FD) where FD will be inherited by spawned process
154 /// and added to child's environment as a variable Name
new( cpu_count: u32, cmd: &Path, args: &[&str], jail: Option<Minijail>, stderr: File, env_fds: Vec<(String, Descriptor)>, ) -> Result<Process>155 pub fn new(
156 cpu_count: u32,
157 cmd: &Path,
158 args: &[&str],
159 jail: Option<Minijail>,
160 stderr: File,
161 env_fds: Vec<(String, Descriptor)>,
162 ) -> Result<Process> {
163 let (request_socket, child_socket) =
164 new_seqpacket_pair().context("error creating main request socket")?;
165
166 let mut vcpu_pipes: Vec<VcpuPipe> = Vec::with_capacity(cpu_count as usize);
167 for _ in 0..cpu_count {
168 vcpu_pipes.push(new_pipe_pair().context("error creating vcpu request socket")?);
169 }
170
171 let mut per_vcpu_states: Vec<Arc<Mutex<PerVcpuState>>> = Vec::new();
172 per_vcpu_states.resize_with(cpu_count as usize, Default::default);
173
174 let plugin_pid = match jail {
175 Some(jail) => {
176 set_var(
177 CROSVM_SOCKET_ENV,
178 child_socket.as_raw_descriptor().to_string(),
179 );
180 env_fds
181 .iter()
182 .for_each(|(k, fd)| set_var(k, fd.as_raw_descriptor().to_string()));
183 jail.run_remap(
184 cmd,
185 &env_fds
186 .into_iter()
187 .map(|(_, fd)| (fd.as_raw_descriptor(), fd.as_raw_descriptor()))
188 .chain(
189 [
190 (stderr.as_raw_descriptor(), STDERR_FILENO),
191 (
192 child_socket.as_raw_descriptor(),
193 child_socket.as_raw_descriptor(),
194 ),
195 ]
196 .into_iter(),
197 )
198 .collect::<Vec<_>>(),
199 args,
200 )
201 .context("failed to run plugin jail")?
202 }
203 None => {
204 for (_, fd) in env_fds.iter() {
205 base::clear_descriptor_cloexec(fd)?;
206 }
207 Command::new(cmd)
208 .args(args)
209 .envs(
210 env_fds
211 .into_iter()
212 .map(|(k, fd)| (k, { fd.as_raw_descriptor().to_string() })),
213 )
214 .env(
215 CROSVM_SOCKET_ENV,
216 child_socket.as_raw_descriptor().to_string(),
217 )
218 .stderr(stderr)
219 .spawn()
220 .context("failed to spawn plugin")?
221 .id() as pid_t
222 }
223 };
224
225 Ok(Process {
226 started: false,
227 plugin_pid,
228 request_sockets: vec![request_socket],
229 objects: Default::default(),
230 shared_vcpu_state: Default::default(),
231 per_vcpu_states,
232 kill_evt: Event::new().context("failed to create plugin kill event")?,
233 vcpu_pipes,
234 request_buffer: vec![0; MAX_DATAGRAM_SIZE],
235 response_buffer: Vec::new(),
236 })
237 }
238
239 /// Creates a VCPU plugin connection object, used by a VCPU run loop to communicate with the
240 /// plugin process.
241 ///
242 /// While each invocation of `create_vcpu` with the given `cpu_id` will return a unique
243 /// `PluginVcpu` object, the underlying resources are shared by each `PluginVcpu` resulting from
244 /// the same `cpu_id`.
create_vcpu(&self, cpu_id: u32) -> Result<PluginVcpu>245 pub fn create_vcpu(&self, cpu_id: u32) -> Result<PluginVcpu> {
246 let vcpu_pipe_read = self.vcpu_pipes[cpu_id as usize]
247 .crosvm_read
248 .try_clone()
249 .context("failed to clone vcpu read pipe")?;
250 let vcpu_pipe_write = self.vcpu_pipes[cpu_id as usize]
251 .crosvm_write
252 .try_clone()
253 .context("failed to clone vcpu write pipe")?;
254 Ok(PluginVcpu::new(
255 self.shared_vcpu_state.clone(),
256 self.per_vcpu_states[cpu_id as usize].clone(),
257 vcpu_pipe_read,
258 vcpu_pipe_write,
259 ))
260 }
261
262 /// Returns if the plugin process indicated the VM was ready to start.
is_started(&self) -> bool263 pub fn is_started(&self) -> bool {
264 self.started
265 }
266
267 /// Returns the process ID of the plugin process.
pid(&self) -> pid_t268 pub fn pid(&self) -> pid_t {
269 self.plugin_pid
270 }
271
272 /// Returns a slice of each socket that should be polled.
273 ///
274 /// If any socket in this slice becomes readable, `handle_socket` should be called with the
275 /// index of that socket. If any socket becomes closed, its index should be passed to
276 /// `drop_sockets`.
sockets(&self) -> &[UnixDatagram]277 pub fn sockets(&self) -> &[UnixDatagram] {
278 &self.request_sockets
279 }
280
281 /// Drops the each socket identified by its index in the slice returned by `sockets`.
282 ///
283 /// The given `socket_idxs` slice will be modified in an arbitrary way for efficient removal of
284 /// the sockets from internal data structures.
drop_sockets(&mut self, socket_idxs: &mut [usize])285 pub fn drop_sockets(&mut self, socket_idxs: &mut [usize]) {
286 // Takes a mutable slice so that the indices can be sorted for efficient removal in
287 // request_sockets..
288 socket_idxs.sort_unstable_by(|a, b| b.cmp(a));
289 let old_len = self.request_sockets.len();
290 for &socket_index in socket_idxs.iter() {
291 // swap_remove changes the index of the last element, but we already know that one
292 // doesn't need to be removed because we are removing sockets in descending order thanks
293 // to the above sort.
294 self.request_sockets.swap_remove(socket_index);
295 }
296 assert_eq!(old_len - socket_idxs.len(), self.request_sockets.len());
297 }
298
299 /// Gently requests that the plugin process exit cleanly, and ends handling of all VCPU
300 /// connections.
301 ///
302 /// The plugin process can ignore the given signal, and so some timeout should be used before
303 /// forcefully terminating the process.
304 ///
305 /// Any blocked VCPU connections will get interrupted so that the VCPU threads can exit cleanly.
306 /// Any subsequent attempt to use the VCPU connections will fail.
signal_kill(&mut self) -> SysResult<()>307 pub fn signal_kill(&mut self) -> SysResult<()> {
308 self.kill_evt.write(1)?;
309 // Normally we'd get any blocked recv() calls in the VCPU threads
310 // to unblock by calling shutdown(). However, we're using pipes
311 // (for improved performance), and pipes don't have shutdown so
312 // instead we'll write a shutdown message to ourselves using the
313 // the writable side of the pipe (normally used by the plugin).
314 for pipe in self.vcpu_pipes.iter_mut() {
315 let mut shutdown_request = VcpuRequest::new();
316 shutdown_request.set_shutdown(VcpuRequest_Shutdown::new());
317 let mut buffer = Vec::new();
318 shutdown_request
319 .write_to_vec(&mut buffer)
320 .map_err(proto_to_sys_err)?;
321 pipe.plugin_write
322 .write(&buffer[..])
323 .map_err(io_to_sys_err)?;
324 }
325 Ok(())
326 }
327
328 /// Waits without blocking for the plugin process to exit and returns the status.
try_wait(&mut self) -> SysResult<ProcessStatus>329 pub fn try_wait(&mut self) -> SysResult<ProcessStatus> {
330 let mut status = 0;
331 // Safe because waitpid is given a valid pointer of correct size and mutability, and the
332 // return value is checked.
333 let ret = unsafe { waitpid(self.plugin_pid, &mut status, WNOHANG) };
334 match ret {
335 -1 => Err(SysError::last()),
336 0 => Ok(ProcessStatus::Running),
337 _ => {
338 if WIFEXITED(status) {
339 match WEXITSTATUS(status) {
340 0 => Ok(ProcessStatus::Success),
341 code => Ok(ProcessStatus::Fail(code)),
342 }
343 } else {
344 // Plugin terminated but has no exit status, so it must have been signaled.
345 Ok(ProcessStatus::Signal(WTERMSIG(status)))
346 }
347 }
348 }
349 }
350
handle_io_event( entry: VacantEntry<u32, PluginObject>, vm: &mut Vm, io_event: &MainRequest_Create_IoEvent, ) -> SysResult<RawDescriptor>351 fn handle_io_event(
352 entry: VacantEntry<u32, PluginObject>,
353 vm: &mut Vm,
354 io_event: &MainRequest_Create_IoEvent,
355 ) -> SysResult<RawDescriptor> {
356 let evt = Event::new()?;
357 let addr = match io_event.space {
358 AddressSpace::IOPORT => IoeventAddress::Pio(io_event.address),
359 AddressSpace::MMIO => IoeventAddress::Mmio(io_event.address),
360 };
361 match io_event.length {
362 0 => vm.register_ioevent(&evt, addr, Datamatch::AnyLength)?,
363 1 => vm.register_ioevent(&evt, addr, Datamatch::U8(Some(io_event.datamatch as u8)))?,
364 2 => {
365 vm.register_ioevent(&evt, addr, Datamatch::U16(Some(io_event.datamatch as u16)))?
366 }
367 4 => {
368 vm.register_ioevent(&evt, addr, Datamatch::U32(Some(io_event.datamatch as u32)))?
369 }
370 8 => {
371 vm.register_ioevent(&evt, addr, Datamatch::U64(Some(io_event.datamatch as u64)))?
372 }
373 _ => return Err(SysError::new(EINVAL)),
374 };
375
376 let fd = evt.as_raw_descriptor();
377 entry.insert(PluginObject::IoEvent {
378 evt,
379 addr,
380 length: io_event.length,
381 datamatch: io_event.datamatch,
382 });
383 Ok(fd)
384 }
385
handle_memory( entry: VacantEntry<u32, PluginObject>, vm: &mut Vm, memfd: File, offset: u64, start: u64, length: u64, read_only: bool, dirty_log: bool, ) -> SysResult<()>386 fn handle_memory(
387 entry: VacantEntry<u32, PluginObject>,
388 vm: &mut Vm,
389 memfd: File,
390 offset: u64,
391 start: u64,
392 length: u64,
393 read_only: bool,
394 dirty_log: bool,
395 ) -> SysResult<()> {
396 let shm = SharedMemory::from_file(memfd)?;
397 // Checking the seals ensures the plugin process won't shrink the mmapped file, causing us
398 // to SIGBUS in the future.
399 let seals = shm.get_seals()?;
400 if !seals.shrink_seal() {
401 return Err(SysError::new(EPERM));
402 }
403 // Check to make sure we don't mmap areas beyond the end of the memfd.
404 match length.checked_add(offset) {
405 Some(end) if end > shm.size() => return Err(SysError::new(EINVAL)),
406 None => return Err(SysError::new(EOVERFLOW)),
407 _ => {}
408 }
409 let mem = MemoryMappingBuilder::new(length as usize)
410 .from_shared_memory(&shm)
411 .offset(offset)
412 .build()
413 .map_err(mmap_to_sys_err)?;
414 let slot =
415 vm.add_memory_region(GuestAddress(start), Box::new(mem), read_only, dirty_log)?;
416 entry.insert(PluginObject::Memory {
417 slot,
418 length: length as usize,
419 });
420 Ok(())
421 }
422
handle_reserve_range(&mut self, reserve_range: &MainRequest_ReserveRange) -> SysResult<()>423 fn handle_reserve_range(&mut self, reserve_range: &MainRequest_ReserveRange) -> SysResult<()> {
424 match self.shared_vcpu_state.write() {
425 Ok(mut lock) => {
426 let space = match reserve_range.space {
427 AddressSpace::IOPORT => IoSpace::Ioport,
428 AddressSpace::MMIO => IoSpace::Mmio,
429 };
430 match reserve_range.length {
431 0 => lock.unreserve_range(space, reserve_range.start),
432 _ => lock.reserve_range(
433 space,
434 reserve_range.start,
435 reserve_range.length,
436 reserve_range.async_write,
437 ),
438 }
439 }
440 Err(_) => Err(SysError::new(EDEADLK)),
441 }
442 }
443
handle_set_irq_routing( vm: &mut Vm, irq_routing: &MainRequest_SetIrqRouting, ) -> SysResult<()>444 fn handle_set_irq_routing(
445 vm: &mut Vm,
446 irq_routing: &MainRequest_SetIrqRouting,
447 ) -> SysResult<()> {
448 let mut routes = Vec::with_capacity(irq_routing.routes.len());
449 for route in &irq_routing.routes {
450 routes.push(IrqRoute {
451 gsi: route.irq_id,
452 source: if route.has_irqchip() {
453 let irqchip = route.get_irqchip();
454 IrqSource::Irqchip {
455 chip: irqchip.irqchip,
456 pin: irqchip.pin,
457 }
458 } else if route.has_msi() {
459 let msi = route.get_msi();
460 IrqSource::Msi {
461 address: msi.address,
462 data: msi.data,
463 }
464 } else {
465 // Because route is a oneof field in the proto definition, this should
466 // only happen if a new variant gets added without updating this chained
467 // if block.
468 return Err(SysError::new(EINVAL));
469 },
470 });
471 }
472 vm.set_gsi_routing(&routes[..])
473 }
474
handle_set_call_hint(&mut self, hints: &MainRequest_SetCallHint) -> SysResult<()>475 fn handle_set_call_hint(&mut self, hints: &MainRequest_SetCallHint) -> SysResult<()> {
476 let mut regs: Vec<CallHintDetails> = vec![];
477 for hint in &hints.hints {
478 regs.push(CallHintDetails {
479 match_rax: hint.match_rax,
480 match_rbx: hint.match_rbx,
481 match_rcx: hint.match_rcx,
482 match_rdx: hint.match_rdx,
483 rax: hint.rax,
484 rbx: hint.rbx,
485 rcx: hint.rcx,
486 rdx: hint.rdx,
487 send_sregs: hint.send_sregs,
488 send_debugregs: hint.send_debugregs,
489 });
490 }
491 match self.shared_vcpu_state.write() {
492 Ok(mut lock) => {
493 let space = match hints.space {
494 AddressSpace::IOPORT => IoSpace::Ioport,
495 AddressSpace::MMIO => IoSpace::Mmio,
496 };
497 lock.set_hint(space, hints.address, hints.on_write, regs);
498 Ok(())
499 }
500 Err(_) => Err(SysError::new(EDEADLK)),
501 }
502 }
503
handle_pause_vcpus(&self, vcpu_handles: &[JoinHandle<()>], cpu_mask: u64, user_data: u64)504 fn handle_pause_vcpus(&self, vcpu_handles: &[JoinHandle<()>], cpu_mask: u64, user_data: u64) {
505 for (cpu_id, (handle, per_cpu_state)) in
506 vcpu_handles.iter().zip(&self.per_vcpu_states).enumerate()
507 {
508 if cpu_mask & (1 << cpu_id) != 0 {
509 per_cpu_state.lock().request_pause(user_data);
510 if let Err(e) = handle.kill(SIGRTMIN() + 0) {
511 error!("failed to interrupt vcpu {}: {}", cpu_id, e);
512 }
513 }
514 }
515 }
516
handle_get_net_config( tap: &net_util::Tap, config: &mut MainResponse_GetNetConfig, ) -> SysResult<()>517 fn handle_get_net_config(
518 tap: &net_util::Tap,
519 config: &mut MainResponse_GetNetConfig,
520 ) -> SysResult<()> {
521 // Log any NetError so that the cause can be found later, but extract and return the
522 // underlying errno for the client as well.
523 fn map_net_error(s: &str, e: NetError) -> SysError {
524 error!("failed to get {}: {}", s, e);
525 e.sys_error()
526 }
527
528 let ip_addr = tap.ip_addr().map_err(|e| map_net_error("IP address", e))?;
529 config.set_host_ipv4_address(u32::from(ip_addr));
530
531 let netmask = tap.netmask().map_err(|e| map_net_error("netmask", e))?;
532 config.set_netmask(u32::from(netmask));
533
534 let result_mac_addr = config.mut_host_mac_address();
535 let mac_addr_octets = tap
536 .mac_address()
537 .map_err(|e| map_net_error("mac address", e))?
538 .octets();
539 result_mac_addr.resize(mac_addr_octets.len(), 0);
540 result_mac_addr.clone_from_slice(&mac_addr_octets);
541
542 Ok(())
543 }
544
545 /// Handles a request on a readable socket identified by its index in the slice returned by
546 /// `sockets`.
547 ///
548 /// The `vm` is used to service request that affect the VM. The `vcpu_handles` slice is used to
549 /// interrupt a VCPU thread currently running in the VM if the socket request it.
handle_socket( &mut self, index: usize, kvm: &Kvm, vm: &mut Vm, vcpu_handles: &[JoinHandle<()>], taps: &[Tap], ) -> result::Result<(), CommError>550 pub fn handle_socket(
551 &mut self,
552 index: usize,
553 kvm: &Kvm,
554 vm: &mut Vm,
555 vcpu_handles: &[JoinHandle<()>],
556 taps: &[Tap],
557 ) -> result::Result<(), CommError> {
558 let (msg_size, request_file) = self.request_sockets[index]
559 .recv_with_fd(IoSliceMut::new(&mut self.request_buffer))
560 .map_err(CommError::PluginSocketRecv)?;
561
562 if msg_size == 0 {
563 return Err(CommError::PluginSocketHup);
564 }
565
566 let request: MainRequest = Message::parse_from_bytes(&self.request_buffer[..msg_size])
567 .map_err(CommError::DecodeRequest)?;
568
569 /// Use this to make it easier to stuff various kinds of File-like objects into the
570 /// `boxed_fds` list.
571 fn box_owned_fd<F: IntoRawDescriptor + 'static>(f: F) -> Box<dyn IntoRawDescriptor> {
572 Box::new(f)
573 }
574
575 // This vec is used to extend ownership of certain FDs until the end of this function.
576 let mut boxed_fds = Vec::new();
577 let mut response_fds = Vec::new();
578 let mut response = MainResponse::new();
579 let res = if request.has_create() {
580 response.mut_create();
581 let create = request.get_create();
582 match self.objects.entry(create.id) {
583 Entry::Vacant(entry) => {
584 if create.has_io_event() {
585 match Self::handle_io_event(entry, vm, create.get_io_event()) {
586 Ok(fd) => {
587 response_fds.push(fd);
588 Ok(())
589 }
590 Err(e) => Err(e),
591 }
592 } else if create.has_memory() {
593 let memory = create.get_memory();
594 match request_file {
595 Some(memfd) => Self::handle_memory(
596 entry,
597 vm,
598 memfd,
599 memory.offset,
600 memory.start,
601 memory.length,
602 memory.read_only,
603 memory.dirty_log,
604 ),
605 None => Err(SysError::new(EBADF)),
606 }
607 } else if create.has_irq_event() {
608 let irq_event = create.get_irq_event();
609 match (Event::new(), Event::new()) {
610 (Ok(evt), Ok(resample_evt)) => match vm.register_irqfd_resample(
611 &evt,
612 &resample_evt,
613 irq_event.irq_id,
614 ) {
615 Ok(()) => {
616 response_fds.push(evt.as_raw_descriptor());
617 response_fds.push(resample_evt.as_raw_descriptor());
618 boxed_fds.push(box_owned_fd(resample_evt));
619 entry.insert(PluginObject::IrqEvent {
620 irq_id: irq_event.irq_id,
621 evt,
622 });
623 Ok(())
624 }
625 Err(e) => Err(e),
626 },
627 (Err(e), _) | (_, Err(e)) => Err(e),
628 }
629 } else {
630 Err(SysError::new(ENOTTY))
631 }
632 }
633 Entry::Occupied(_) => Err(SysError::new(EEXIST)),
634 }
635 } else if request.has_destroy() {
636 response.mut_destroy();
637 match self.objects.entry(request.get_destroy().id) {
638 Entry::Occupied(entry) => entry.remove().destroy(vm),
639 Entry::Vacant(_) => Err(SysError::new(ENOENT)),
640 }
641 } else if request.has_new_connection() {
642 response.mut_new_connection();
643 match new_seqpacket_pair() {
644 Ok((request_socket, child_socket)) => {
645 self.request_sockets.push(request_socket);
646 response_fds.push(child_socket.as_raw_descriptor());
647 boxed_fds.push(box_owned_fd(child_socket));
648 Ok(())
649 }
650 Err(e) => Err(e),
651 }
652 } else if request.has_get_shutdown_eventfd() {
653 response.mut_get_shutdown_eventfd();
654 response_fds.push(self.kill_evt.as_raw_descriptor());
655 Ok(())
656 } else if request.has_check_extension() {
657 // Safe because the Cap enum is not read by the check_extension method. In that method,
658 // cap is cast back to an integer and fed to an ioctl. If the extension name is actually
659 // invalid, the kernel will safely reject the extension under the assumption that the
660 // capability is legitimately unsupported.
661 let cap = unsafe { transmute(request.get_check_extension().extension) };
662 response.mut_check_extension().has_extension = vm.check_extension(cap);
663 Ok(())
664 } else if request.has_reserve_range() {
665 response.mut_reserve_range();
666 self.handle_reserve_range(request.get_reserve_range())
667 } else if request.has_set_irq() {
668 response.mut_set_irq();
669 let irq = request.get_set_irq();
670 vm.set_irq_line(irq.irq_id, irq.active)
671 } else if request.has_set_irq_routing() {
672 response.mut_set_irq_routing();
673 Self::handle_set_irq_routing(vm, request.get_set_irq_routing())
674 } else if request.has_get_state() {
675 let response_state = response.mut_get_state();
676 match get_vm_state(vm, request.get_get_state().set) {
677 Ok(state) => {
678 response_state.state = state;
679 Ok(())
680 }
681 Err(e) => Err(e),
682 }
683 } else if request.has_set_state() {
684 response.mut_set_state();
685 let set_state = request.get_set_state();
686 set_vm_state(vm, set_state.set, set_state.get_state())
687 } else if request.has_set_identity_map_addr() {
688 response.mut_set_identity_map_addr();
689 let addr = request.get_set_identity_map_addr().address;
690 vm.set_identity_map_addr(GuestAddress(addr as u64))
691 } else if request.has_pause_vcpus() {
692 response.mut_pause_vcpus();
693 let pause_vcpus = request.get_pause_vcpus();
694 self.handle_pause_vcpus(vcpu_handles, pause_vcpus.cpu_mask, pause_vcpus.user);
695 Ok(())
696 } else if request.has_get_vcpus() {
697 response.mut_get_vcpus();
698 for pipe in self.vcpu_pipes.iter() {
699 response_fds.push(pipe.plugin_write.as_raw_descriptor());
700 response_fds.push(pipe.plugin_read.as_raw_descriptor());
701 }
702 Ok(())
703 } else if request.has_start() {
704 response.mut_start();
705 if self.started {
706 Err(SysError::new(EINVAL))
707 } else {
708 self.started = true;
709 Ok(())
710 }
711 } else if request.has_get_net_config() {
712 match taps.first() {
713 Some(tap) => {
714 match Self::handle_get_net_config(tap, response.mut_get_net_config()) {
715 Ok(_) => {
716 response_fds.push(tap.as_raw_descriptor());
717 Ok(())
718 }
719 Err(e) => Err(e),
720 }
721 }
722 None => Err(SysError::new(ENODATA)),
723 }
724 } else if request.has_set_call_hint() {
725 response.mut_set_call_hint();
726 self.handle_set_call_hint(request.get_set_call_hint())
727 } else if request.has_dirty_log() {
728 let dirty_log_response = response.mut_dirty_log();
729 match self.objects.get(&request.get_dirty_log().id) {
730 Some(&PluginObject::Memory { slot, length }) => {
731 let dirty_log = dirty_log_response.mut_bitmap();
732 dirty_log.resize(dirty_log_bitmap_size(length), 0);
733 vm.get_dirty_log(slot, &mut dirty_log[..])
734 }
735 _ => Err(SysError::new(ENOENT)),
736 }
737 } else if request.has_get_supported_cpuid() {
738 let cpuid_response = &mut response.mut_get_supported_cpuid().entries;
739 match kvm.get_supported_cpuid() {
740 Ok(mut cpuid) => {
741 for entry in cpuid.mut_entries_slice() {
742 cpuid_response.push(cpuid_kvm_to_proto(entry));
743 }
744 Ok(())
745 }
746 Err(e) => Err(e),
747 }
748 } else if request.has_get_emulated_cpuid() {
749 let cpuid_response = &mut response.mut_get_emulated_cpuid().entries;
750 match kvm.get_emulated_cpuid() {
751 Ok(mut cpuid) => {
752 for entry in cpuid.mut_entries_slice() {
753 cpuid_response.push(cpuid_kvm_to_proto(entry));
754 }
755 Ok(())
756 }
757 Err(e) => Err(e),
758 }
759 } else if request.has_get_msr_index_list() {
760 let msr_list_response = &mut response.mut_get_msr_index_list().indices;
761 match kvm.get_msr_index_list() {
762 Ok(indices) => {
763 for entry in indices {
764 msr_list_response.push(entry);
765 }
766 Ok(())
767 }
768 Err(e) => Err(e),
769 }
770 } else {
771 Err(SysError::new(ENOTTY))
772 };
773
774 if let Err(e) = res {
775 response.errno = e.errno();
776 }
777
778 self.response_buffer.clear();
779 response
780 .write_to_vec(&mut self.response_buffer)
781 .map_err(CommError::EncodeResponse)?;
782 assert_ne!(self.response_buffer.len(), 0);
783 self.request_sockets[index]
784 .send_with_fds(&[IoSlice::new(&self.response_buffer[..])], &response_fds)
785 .map_err(CommError::PluginSocketSend)?;
786
787 Ok(())
788 }
789 }
790
791 impl Drop for Process {
drop(&mut self)792 fn drop(&mut self) {
793 // Ignore the result because there is nothing we can do about it.
794 if let Err(e) = self.signal_kill() {
795 error!("failed to signal kill event for plugin: {}", e);
796 }
797 }
798 }
799