18e7579b2SChao Peng // Copyright 2017 The Chromium OS Authors. All rights reserved. 28e7579b2SChao Peng // Use of this source code is governed by a BSD-style license that can be 38e7579b2SChao Peng // found in the LICENSE file. 45e9886bbSRuslan Mstoi // 55e9886bbSRuslan Mstoi // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause 68e7579b2SChao Peng 788a9f799SRob Bradford use std::fs::File; 888a9f799SRob Bradford use std::os::unix::io::AsRawFd; 988a9f799SRob Bradford use std::sync::atomic::AtomicBool; 1088a9f799SRob Bradford use std::sync::{Arc, Barrier}; 1161e57e1cSRuoqing He use std::{io, result}; 1288a9f799SRob Bradford 1388a9f799SRob Bradford use anyhow::anyhow; 1488a9f799SRob Bradford use seccompiler::SeccompAction; 1588a9f799SRob Bradford use serde::{Deserialize, Serialize}; 1688a9f799SRob Bradford use thiserror::Error; 1788a9f799SRob Bradford use virtio_queue::{Queue, QueueT}; 1888a9f799SRob Bradford use vm_memory::{GuestAddressSpace, GuestMemory, GuestMemoryAtomic}; 1988a9f799SRob Bradford use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable}; 2088a9f799SRob Bradford use vm_virtio::{AccessPlatform, Translatable}; 2188a9f799SRob Bradford use vmm_sys_util::eventfd::EventFd; 2288a9f799SRob Bradford 23b2589d4fSRob Bradford use super::{ 2461e57e1cSRuoqing He ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, 2561e57e1cSRuoqing He Error as DeviceError, VirtioCommon, VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, 2661e57e1cSRuoqing He VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1, 27b2589d4fSRob Bradford }; 2854e523c3SRob Bradford use crate::seccomp_filters::Thread; 2954e523c3SRob Bradford use crate::thread_helper::spawn_virtio_thread; 3061e57e1cSRuoqing He use crate::{GuestMemoryMmap, VirtioInterrupt, VirtioInterruptType}; 318e7579b2SChao Peng 328e7579b2SChao Peng const QUEUE_SIZE: u16 = 256; 338e7579b2SChao Peng const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE]; 348e7579b2SChao Peng 358e7579b2SChao Peng // New descriptors are pending on the virtio queue. 36e093f0e8SRob Bradford const QUEUE_AVAIL_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 1; 378e7579b2SChao Peng 381c1bff93SBo Chen #[derive(Error, Debug)] 391c1bff93SBo Chen enum Error { 401c1bff93SBo Chen #[error("Descriptor chain too short")] 411c1bff93SBo Chen DescriptorChainTooShort, 42f0c55f52SBo Chen #[error("Invalid descriptor")] 43f0c55f52SBo Chen InvalidDescriptor, 44*8e2973feSPhilipp Schuster #[error("Failed to write to guest memory")] 4528e0a954SPhilipp Schuster GuestMemoryWrite(#[source] vm_memory::guest_memory::Error), 46*8e2973feSPhilipp Schuster #[error("Failed adding used index")] 4728e0a954SPhilipp Schuster QueueAddUsed(#[source] virtio_queue::Error), 481c1bff93SBo Chen } 491c1bff93SBo Chen 508e7579b2SChao Peng struct RngEpollHandler { 51a423bf13SSebastien Boeuf mem: GuestMemoryAtomic<GuestMemoryMmap>, 52a423bf13SSebastien Boeuf queue: Queue, 538e7579b2SChao Peng random_file: File, 54c396bacaSSebastien Boeuf interrupt_cb: Arc<dyn VirtioInterrupt>, 558e7579b2SChao Peng queue_evt: EventFd, 568e7579b2SChao Peng kill_evt: EventFd, 57dae0b2efSSamuel Ortiz pause_evt: EventFd, 5809f5b82fSSebastien Boeuf access_platform: Option<Arc<dyn AccessPlatform>>, 598e7579b2SChao Peng } 608e7579b2SChao Peng 618e7579b2SChao Peng impl RngEpollHandler { process_queue(&mut self) -> result::Result<bool, Error>621c1bff93SBo Chen fn process_queue(&mut self) -> result::Result<bool, Error> { 633f62a172SSebastien Boeuf let queue = &mut self.queue; 648e7579b2SChao Peng 65a4859ffeSSebastien Boeuf let mut used_descs = false; 6687f57f7cSSebastien Boeuf while let Some(mut desc_chain) = queue.pop_descriptor_chain(self.mem.memory()) { 671c1bff93SBo Chen let desc = desc_chain.next().ok_or(Error::DescriptorChainTooShort)?; 688e7579b2SChao Peng 69f0c55f52SBo Chen // The descriptor must be write-only and non-zero length 70f0c55f52SBo Chen if !(desc.is_write_only() && desc.len() > 0) { 71f0c55f52SBo Chen return Err(Error::InvalidDescriptor); 72f0c55f52SBo Chen } 73f0c55f52SBo Chen 748e7579b2SChao Peng // Fill the read with data from the random device on the host. 75f0c55f52SBo Chen let len = desc_chain 76f0c55f52SBo Chen .memory() 77d4892f41SBo Chen .read_volatile_from( 7877df4e67SSebastien Boeuf desc.addr() 79059e787cSSebastien Boeuf .translate_gva(self.access_platform.as_ref(), desc.len() as usize), 8077df4e67SSebastien Boeuf &mut self.random_file, 8177df4e67SSebastien Boeuf desc.len() as usize, 82f0c55f52SBo Chen ) 8331ca22d4SRob Bradford .map_err(Error::GuestMemoryWrite)?; 848e7579b2SChao Peng 85a4859ffeSSebastien Boeuf queue 86f0c55f52SBo Chen .add_used(desc_chain.memory(), desc_chain.head_index(), len as u32) 871c1bff93SBo Chen .map_err(Error::QueueAddUsed)?; 88a4859ffeSSebastien Boeuf used_descs = true; 898e7579b2SChao Peng } 908e7579b2SChao Peng 911c1bff93SBo Chen Ok(used_descs) 928e7579b2SChao Peng } 938e7579b2SChao Peng signal_used_queue(&self) -> result::Result<(), DeviceError>948e7579b2SChao Peng fn signal_used_queue(&self) -> result::Result<(), DeviceError> { 95c396bacaSSebastien Boeuf self.interrupt_cb 96de3e003eSSebastien Boeuf .trigger(VirtioInterruptType::Queue(0)) 97c396bacaSSebastien Boeuf .map_err(|e| { 988e7579b2SChao Peng error!("Failed to signal used queue: {:?}", e); 998e7579b2SChao Peng DeviceError::FailedSignalingUsedQueue(e) 1008e7579b2SChao Peng }) 1018e7579b2SChao Peng } 1028e7579b2SChao Peng run( &mut self, paused: Arc<AtomicBool>, paused_sync: Arc<Barrier>, ) -> result::Result<(), EpollHelperError>103aa57762cSSebastien Boeuf fn run( 104aa57762cSSebastien Boeuf &mut self, 105aa57762cSSebastien Boeuf paused: Arc<AtomicBool>, 106aa57762cSSebastien Boeuf paused_sync: Arc<Barrier>, 107aa57762cSSebastien Boeuf ) -> result::Result<(), EpollHelperError> { 108e093f0e8SRob Bradford let mut helper = EpollHelper::new(&self.kill_evt, &self.pause_evt)?; 109e093f0e8SRob Bradford helper.add_event(self.queue_evt.as_raw_fd(), QUEUE_AVAIL_EVENT)?; 110aa57762cSSebastien Boeuf helper.run(paused, paused_sync, self)?; 1118e7579b2SChao Peng 112e093f0e8SRob Bradford Ok(()) 113e093f0e8SRob Bradford } 114e382dc66SSebastien Boeuf } 115e382dc66SSebastien Boeuf 116e093f0e8SRob Bradford impl EpollHelperHandler for RngEpollHandler { handle_event( &mut self, _helper: &mut EpollHelper, event: &epoll::Event, ) -> result::Result<(), EpollHelperError>117b1752994SBo Chen fn handle_event( 118b1752994SBo Chen &mut self, 119b1752994SBo Chen _helper: &mut EpollHelper, 120b1752994SBo Chen event: &epoll::Event, 121b1752994SBo Chen ) -> result::Result<(), EpollHelperError> { 12201e7bd72SSebastien Boeuf let ev_type = event.data as u16; 12301e7bd72SSebastien Boeuf match ev_type { 1248e7579b2SChao Peng QUEUE_AVAIL_EVENT => { 125b1752994SBo Chen self.queue_evt.read().map_err(|e| { 126b1752994SBo Chen EpollHelperError::HandleEvent(anyhow!("Failed to get queue event: {:?}", e)) 127b1752994SBo Chen })?; 1281c1bff93SBo Chen let needs_notification = self.process_queue().map_err(|e| { 1291c1bff93SBo Chen EpollHelperError::HandleEvent(anyhow!("Failed to process queue : {:?}", e)) 1301c1bff93SBo Chen })?; 1311c1bff93SBo Chen if needs_notification { 132b1752994SBo Chen self.signal_used_queue().map_err(|e| { 133b1752994SBo Chen EpollHelperError::HandleEvent(anyhow!( 134b1752994SBo Chen "Failed to signal used queue: {:?}", 135b1752994SBo Chen e 136b1752994SBo Chen )) 137b1752994SBo Chen })?; 1388e7579b2SChao Peng } 1398e7579b2SChao Peng } 1408e7579b2SChao Peng _ => { 141b1752994SBo Chen return Err(EpollHelperError::HandleEvent(anyhow!( 142b1752994SBo Chen "Unexpected event: {}", 143b1752994SBo Chen ev_type 144b1752994SBo Chen ))); 1458e7579b2SChao Peng } 1468e7579b2SChao Peng } 147b1752994SBo Chen Ok(()) 1488e7579b2SChao Peng } 1498e7579b2SChao Peng } 1508e7579b2SChao Peng 1518e7579b2SChao Peng /// Virtio device for exposing entropy to the guest OS through virtio. 1528e7579b2SChao Peng pub struct Rng { 15337e99bbbSRob Bradford common: VirtioCommon, 1542e91b738SSebastien Boeuf id: String, 1558e7579b2SChao Peng random_file: Option<File>, 156a4262211SBo Chen seccomp_action: SeccompAction, 157687d646cSRob Bradford exit_evt: EventFd, 1588e7579b2SChao Peng } 1598e7579b2SChao Peng 16010ab87d6SRob Bradford #[derive(Deserialize, Serialize)] 161a484aa7bSSamuel Ortiz pub struct RngState { 162a484aa7bSSamuel Ortiz pub avail_features: u64, 163a484aa7bSSamuel Ortiz pub acked_features: u64, 164a484aa7bSSamuel Ortiz } 165a484aa7bSSamuel Ortiz 1668e7579b2SChao Peng impl Rng { 1678e7579b2SChao Peng /// Create a new virtio rng device that gets random data from /dev/urandom. new( id: String, path: &str, iommu: bool, seccomp_action: SeccompAction, exit_evt: EventFd, state: Option<RngState>, ) -> io::Result<Rng>168a4262211SBo Chen pub fn new( 169a4262211SBo Chen id: String, 170a4262211SBo Chen path: &str, 171a4262211SBo Chen iommu: bool, 172a4262211SBo Chen seccomp_action: SeccompAction, 173687d646cSRob Bradford exit_evt: EventFd, 1741f0e5eb6SSebastien Boeuf state: Option<RngState>, 175a4262211SBo Chen ) -> io::Result<Rng> { 1768e7579b2SChao Peng let random_file = File::open(path)?; 1771f0e5eb6SSebastien Boeuf 178b62a40efSSebastien Boeuf let (avail_features, acked_features, paused) = if let Some(state) = state { 1791f0e5eb6SSebastien Boeuf info!("Restoring virtio-rng {}", id); 180b62a40efSSebastien Boeuf (state.avail_features, state.acked_features, true) 1811f0e5eb6SSebastien Boeuf } else { 1829ab00dcbSSebastien Boeuf let mut avail_features = 1u64 << VIRTIO_F_VERSION_1; 1839ab00dcbSSebastien Boeuf 1849ab00dcbSSebastien Boeuf if iommu { 1859ab00dcbSSebastien Boeuf avail_features |= 1u64 << VIRTIO_F_IOMMU_PLATFORM; 1869ab00dcbSSebastien Boeuf } 1878e7579b2SChao Peng 188b62a40efSSebastien Boeuf (avail_features, 0, false) 1891f0e5eb6SSebastien Boeuf }; 1901f0e5eb6SSebastien Boeuf 1918e7579b2SChao Peng Ok(Rng { 19237e99bbbSRob Bradford common: VirtioCommon { 193aa34d545SRob Bradford device_type: VirtioDeviceType::Rng as u32, 194c37fb5b6SRob Bradford queue_sizes: QUEUE_SIZES.to_vec(), 195c37fb5b6SRob Bradford paused_sync: Some(Arc::new(Barrier::new(2))), 19637e99bbbSRob Bradford avail_features, 1971f0e5eb6SSebastien Boeuf acked_features, 198c90f77e3SRob Bradford min_queues: 1, 199b62a40efSSebastien Boeuf paused: Arc::new(AtomicBool::new(paused)), 200a9a13846SRob Bradford ..Default::default() 20137e99bbbSRob Bradford }, 2022e91b738SSebastien Boeuf id, 2038e7579b2SChao Peng random_file: Some(random_file), 204a4262211SBo Chen seccomp_action, 205687d646cSRob Bradford exit_evt, 2068e7579b2SChao Peng }) 2078e7579b2SChao Peng } 208a484aa7bSSamuel Ortiz state(&self) -> RngState209a484aa7bSSamuel Ortiz fn state(&self) -> RngState { 210a484aa7bSSamuel Ortiz RngState { 21137e99bbbSRob Bradford avail_features: self.common.avail_features, 21237e99bbbSRob Bradford acked_features: self.common.acked_features, 213a484aa7bSSamuel Ortiz } 214a484aa7bSSamuel Ortiz } 215a484aa7bSSamuel Ortiz 216194b59f4SRob Bradford #[cfg(fuzzing)] wait_for_epoll_threads(&mut self)217194b59f4SRob Bradford pub fn wait_for_epoll_threads(&mut self) { 218194b59f4SRob Bradford self.common.wait_for_epoll_threads(); 219194b59f4SRob Bradford } 2208e7579b2SChao Peng } 2218e7579b2SChao Peng 2228e7579b2SChao Peng impl Drop for Rng { drop(&mut self)2238e7579b2SChao Peng fn drop(&mut self) { 224c37fb5b6SRob Bradford if let Some(kill_evt) = self.common.kill_evt.take() { 2258e7579b2SChao Peng // Ignore the result because there is nothing we can do about it. 2268e7579b2SChao Peng let _ = kill_evt.write(1); 2278e7579b2SChao Peng } 228ad6c0ee5SPhilipp Schuster self.common.wait_for_epoll_threads(); 2298e7579b2SChao Peng } 2308e7579b2SChao Peng } 2318e7579b2SChao Peng 2328e7579b2SChao Peng impl VirtioDevice for Rng { device_type(&self) -> u322338e7579b2SChao Peng fn device_type(&self) -> u32 { 234c37fb5b6SRob Bradford self.common.device_type 2358e7579b2SChao Peng } 2368e7579b2SChao Peng queue_max_sizes(&self) -> &[u16]2378e7579b2SChao Peng fn queue_max_sizes(&self) -> &[u16] { 238c37fb5b6SRob Bradford &self.common.queue_sizes 2398e7579b2SChao Peng } 2408e7579b2SChao Peng features(&self) -> u6424114eddf72SCathy Zhang fn features(&self) -> u64 { 24237e99bbbSRob Bradford self.common.avail_features 2438e7579b2SChao Peng } 2448e7579b2SChao Peng ack_features(&mut self, value: u64)24514eddf72SCathy Zhang fn ack_features(&mut self, value: u64) { 24637e99bbbSRob Bradford self.common.ack_features(value) 2478e7579b2SChao Peng } 2488e7579b2SChao Peng activate( &mut self, mem: GuestMemoryAtomic<GuestMemoryMmap>, interrupt_cb: Arc<dyn VirtioInterrupt>, mut queues: Vec<(usize, Queue, EventFd)>, ) -> ActivateResult2498e7579b2SChao Peng fn activate( 2508e7579b2SChao Peng &mut self, 251a423bf13SSebastien Boeuf mem: GuestMemoryAtomic<GuestMemoryMmap>, 252c396bacaSSebastien Boeuf interrupt_cb: Arc<dyn VirtioInterrupt>, 253a423bf13SSebastien Boeuf mut queues: Vec<(usize, Queue, EventFd)>, 2548e7579b2SChao Peng ) -> ActivateResult { 2553f62a172SSebastien Boeuf self.common.activate(&queues, &interrupt_cb)?; 256280bef83SRob Bradford let (kill_evt, pause_evt) = self.common.dup_eventfds(); 257eb91bc81SSebastien Boeuf 258eb91bc81SSebastien Boeuf if let Some(file) = self.random_file.as_ref() { 259eb91bc81SSebastien Boeuf let random_file = file.try_clone().map_err(|e| { 260eb91bc81SSebastien Boeuf error!("failed cloning rng source: {}", e); 261eb91bc81SSebastien Boeuf ActivateError::BadActivate 262eb91bc81SSebastien Boeuf })?; 2633f62a172SSebastien Boeuf 2643f62a172SSebastien Boeuf let (_, queue, queue_evt) = queues.remove(0); 2653f62a172SSebastien Boeuf 2668e7579b2SChao Peng let mut handler = RngEpollHandler { 267a423bf13SSebastien Boeuf mem, 2683f62a172SSebastien Boeuf queue, 2698e7579b2SChao Peng random_file, 270d3c7b455SSebastien Boeuf interrupt_cb, 2713f62a172SSebastien Boeuf queue_evt, 2728e7579b2SChao Peng kill_evt, 273dae0b2efSSamuel Ortiz pause_evt, 27409f5b82fSSebastien Boeuf access_platform: self.common.access_platform.clone(), 2758e7579b2SChao Peng }; 2768e7579b2SChao Peng 277c37fb5b6SRob Bradford let paused = self.common.paused.clone(); 278c37fb5b6SRob Bradford let paused_sync = self.common.paused_sync.clone(); 279f648f285SSamuel Ortiz let mut epoll_threads = Vec::new(); 28054e523c3SRob Bradford spawn_virtio_thread( 28154e523c3SRob Bradford &self.id, 28254e523c3SRob Bradford &self.seccomp_action, 28354e523c3SRob Bradford Thread::VirtioRng, 28454e523c3SRob Bradford &mut epoll_threads, 285687d646cSRob Bradford &self.exit_evt, 286df5b803aSBo Chen move || handler.run(paused, paused_sync.unwrap()), 28754e523c3SRob Bradford )?; 2888e7579b2SChao Peng 289c37fb5b6SRob Bradford self.common.epoll_threads = Some(epoll_threads); 290f648f285SSamuel Ortiz 291c89095abSRob Bradford event!("virtio-device", "activated", "id", &self.id); 2928e7579b2SChao Peng return Ok(()); 2938e7579b2SChao Peng } 2948e7579b2SChao Peng Err(ActivateError::BadActivate) 2958e7579b2SChao Peng } 296eb91bc81SSebastien Boeuf reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>>29723f9ec50SRob Bradford fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> { 298c89095abSRob Bradford let result = self.common.reset(); 299c89095abSRob Bradford event!("virtio-device", "reset", "id", &self.id); 300c89095abSRob Bradford result 301eb91bc81SSebastien Boeuf } 30209f5b82fSSebastien Boeuf set_access_platform(&mut self, access_platform: Arc<dyn AccessPlatform>)30309f5b82fSSebastien Boeuf fn set_access_platform(&mut self, access_platform: Arc<dyn AccessPlatform>) { 30409f5b82fSSebastien Boeuf self.common.set_access_platform(access_platform) 30509f5b82fSSebastien Boeuf } 3068e7579b2SChao Peng } 307dae0b2efSSamuel Ortiz 308c37fb5b6SRob Bradford impl Pausable for Rng { pause(&mut self) -> result::Result<(), MigratableError>309c37fb5b6SRob Bradford fn pause(&mut self) -> result::Result<(), MigratableError> { 310c37fb5b6SRob Bradford self.common.pause() 311c37fb5b6SRob Bradford } 312c37fb5b6SRob Bradford resume(&mut self) -> result::Result<(), MigratableError>313c37fb5b6SRob Bradford fn resume(&mut self) -> result::Result<(), MigratableError> { 314c37fb5b6SRob Bradford self.common.resume() 315c37fb5b6SRob Bradford } 316c37fb5b6SRob Bradford } 317c37fb5b6SRob Bradford 318a484aa7bSSamuel Ortiz impl Snapshottable for Rng { id(&self) -> String319a484aa7bSSamuel Ortiz fn id(&self) -> String { 3202e91b738SSebastien Boeuf self.id.clone() 321a484aa7bSSamuel Ortiz } 322a484aa7bSSamuel Ortiz snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError>323871138d5SSebastien Boeuf fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 32410ab87d6SRob Bradford Snapshot::new_from_state(&self.state()) 325a484aa7bSSamuel Ortiz } 326a484aa7bSSamuel Ortiz } 327a484aa7bSSamuel Ortiz 3281b1a2175SSamuel Ortiz impl Transportable for Rng {} 329dae0b2efSSamuel Ortiz impl Migratable for Rng {} 330