• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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