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