1 // Copyright 2017 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 super::Error as DeviceError; 6 use super::{ 7 ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, VirtioCommon, 8 VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_IOMMU_PLATFORM, 9 VIRTIO_F_VERSION_1, 10 }; 11 use crate::seccomp_filters::Thread; 12 use crate::thread_helper::spawn_virtio_thread; 13 use crate::GuestMemoryMmap; 14 use crate::{VirtioInterrupt, VirtioInterruptType}; 15 use seccompiler::SeccompAction; 16 use std::fs::File; 17 use std::io; 18 use std::os::unix::io::AsRawFd; 19 use std::result; 20 use std::sync::atomic::AtomicBool; 21 use std::sync::{Arc, Barrier}; 22 use versionize::{VersionMap, Versionize, VersionizeResult}; 23 use versionize_derive::Versionize; 24 use virtio_queue::Queue; 25 use vm_memory::{Bytes, GuestMemoryAtomic}; 26 use vm_migration::VersionMapped; 27 use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable}; 28 use vm_virtio::{AccessPlatform, Translatable}; 29 use vmm_sys_util::eventfd::EventFd; 30 31 const QUEUE_SIZE: u16 = 256; 32 const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE]; 33 34 // New descriptors are pending on the virtio queue. 35 const QUEUE_AVAIL_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 1; 36 37 struct RngEpollHandler { 38 queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, 39 random_file: File, 40 interrupt_cb: Arc<dyn VirtioInterrupt>, 41 queue_evt: EventFd, 42 kill_evt: EventFd, 43 pause_evt: EventFd, 44 access_platform: Option<Arc<dyn AccessPlatform>>, 45 } 46 47 impl RngEpollHandler { 48 fn process_queue(&mut self) -> bool { 49 let queue = &mut self.queues[0]; 50 51 let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize]; 52 let mut used_count = 0; 53 for mut desc_chain in queue.iter().unwrap() { 54 let desc = desc_chain.next().unwrap(); 55 let mut len = 0; 56 57 // Drivers can only read from the random device. 58 if desc.is_write_only() { 59 // Fill the read with data from the random device on the host. 60 if desc_chain 61 .memory() 62 .read_from( 63 desc.addr() 64 .translate_gva(self.access_platform.as_ref(), desc.len() as usize), 65 &mut self.random_file, 66 desc.len() as usize, 67 ) 68 .is_ok() 69 { 70 len = desc.len(); 71 } 72 } 73 74 used_desc_heads[used_count] = (desc_chain.head_index(), len); 75 used_count += 1; 76 } 77 78 for &(desc_index, len) in &used_desc_heads[..used_count] { 79 queue.add_used(desc_index, len).unwrap(); 80 } 81 used_count > 0 82 } 83 84 fn signal_used_queue(&self) -> result::Result<(), DeviceError> { 85 self.interrupt_cb 86 .trigger(VirtioInterruptType::Queue(0)) 87 .map_err(|e| { 88 error!("Failed to signal used queue: {:?}", e); 89 DeviceError::FailedSignalingUsedQueue(e) 90 }) 91 } 92 93 fn run( 94 &mut self, 95 paused: Arc<AtomicBool>, 96 paused_sync: Arc<Barrier>, 97 ) -> result::Result<(), EpollHelperError> { 98 let mut helper = EpollHelper::new(&self.kill_evt, &self.pause_evt)?; 99 helper.add_event(self.queue_evt.as_raw_fd(), QUEUE_AVAIL_EVENT)?; 100 helper.run(paused, paused_sync, self)?; 101 102 Ok(()) 103 } 104 } 105 106 impl EpollHelperHandler for RngEpollHandler { 107 fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool { 108 let ev_type = event.data as u16; 109 match ev_type { 110 QUEUE_AVAIL_EVENT => { 111 if let Err(e) = self.queue_evt.read() { 112 error!("Failed to get queue event: {:?}", e); 113 return true; 114 } else if self.process_queue() { 115 if let Err(e) = self.signal_used_queue() { 116 error!("Failed to signal used queue: {:?}", e); 117 return true; 118 } 119 } 120 } 121 _ => { 122 error!("Unexpected event: {}", ev_type); 123 return true; 124 } 125 } 126 false 127 } 128 } 129 130 /// Virtio device for exposing entropy to the guest OS through virtio. 131 pub struct Rng { 132 common: VirtioCommon, 133 id: String, 134 random_file: Option<File>, 135 seccomp_action: SeccompAction, 136 exit_evt: EventFd, 137 } 138 139 #[derive(Versionize)] 140 pub struct RngState { 141 pub avail_features: u64, 142 pub acked_features: u64, 143 } 144 145 impl VersionMapped for RngState {} 146 147 impl Rng { 148 /// Create a new virtio rng device that gets random data from /dev/urandom. 149 pub fn new( 150 id: String, 151 path: &str, 152 iommu: bool, 153 seccomp_action: SeccompAction, 154 exit_evt: EventFd, 155 ) -> io::Result<Rng> { 156 let random_file = File::open(path)?; 157 let mut avail_features = 1u64 << VIRTIO_F_VERSION_1; 158 159 if iommu { 160 avail_features |= 1u64 << VIRTIO_F_IOMMU_PLATFORM; 161 } 162 163 Ok(Rng { 164 common: VirtioCommon { 165 device_type: VirtioDeviceType::Rng as u32, 166 queue_sizes: QUEUE_SIZES.to_vec(), 167 paused_sync: Some(Arc::new(Barrier::new(2))), 168 avail_features, 169 min_queues: 1, 170 ..Default::default() 171 }, 172 id, 173 random_file: Some(random_file), 174 seccomp_action, 175 exit_evt, 176 }) 177 } 178 179 fn state(&self) -> RngState { 180 RngState { 181 avail_features: self.common.avail_features, 182 acked_features: self.common.acked_features, 183 } 184 } 185 186 fn set_state(&mut self, state: &RngState) { 187 self.common.avail_features = state.avail_features; 188 self.common.acked_features = state.acked_features; 189 } 190 } 191 192 impl Drop for Rng { 193 fn drop(&mut self) { 194 if let Some(kill_evt) = self.common.kill_evt.take() { 195 // Ignore the result because there is nothing we can do about it. 196 let _ = kill_evt.write(1); 197 } 198 } 199 } 200 201 impl VirtioDevice for Rng { 202 fn device_type(&self) -> u32 { 203 self.common.device_type 204 } 205 206 fn queue_max_sizes(&self) -> &[u16] { 207 &self.common.queue_sizes 208 } 209 210 fn features(&self) -> u64 { 211 self.common.avail_features 212 } 213 214 fn ack_features(&mut self, value: u64) { 215 self.common.ack_features(value) 216 } 217 218 fn activate( 219 &mut self, 220 _mem: GuestMemoryAtomic<GuestMemoryMmap>, 221 interrupt_cb: Arc<dyn VirtioInterrupt>, 222 queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, 223 mut queue_evts: Vec<EventFd>, 224 ) -> ActivateResult { 225 self.common.activate(&queues, &queue_evts, &interrupt_cb)?; 226 let (kill_evt, pause_evt) = self.common.dup_eventfds(); 227 228 if let Some(file) = self.random_file.as_ref() { 229 let random_file = file.try_clone().map_err(|e| { 230 error!("failed cloning rng source: {}", e); 231 ActivateError::BadActivate 232 })?; 233 let mut handler = RngEpollHandler { 234 queues, 235 random_file, 236 interrupt_cb, 237 queue_evt: queue_evts.remove(0), 238 kill_evt, 239 pause_evt, 240 access_platform: self.common.access_platform.clone(), 241 }; 242 243 let paused = self.common.paused.clone(); 244 let paused_sync = self.common.paused_sync.clone(); 245 let mut epoll_threads = Vec::new(); 246 spawn_virtio_thread( 247 &self.id, 248 &self.seccomp_action, 249 Thread::VirtioRng, 250 &mut epoll_threads, 251 &self.exit_evt, 252 move || { 253 if let Err(e) = handler.run(paused, paused_sync.unwrap()) { 254 error!("Error running worker: {:?}", e); 255 } 256 }, 257 )?; 258 259 self.common.epoll_threads = Some(epoll_threads); 260 261 event!("virtio-device", "activated", "id", &self.id); 262 return Ok(()); 263 } 264 Err(ActivateError::BadActivate) 265 } 266 267 fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> { 268 let result = self.common.reset(); 269 event!("virtio-device", "reset", "id", &self.id); 270 result 271 } 272 273 fn set_access_platform(&mut self, access_platform: Arc<dyn AccessPlatform>) { 274 self.common.set_access_platform(access_platform) 275 } 276 } 277 278 impl Pausable for Rng { 279 fn pause(&mut self) -> result::Result<(), MigratableError> { 280 self.common.pause() 281 } 282 283 fn resume(&mut self) -> result::Result<(), MigratableError> { 284 self.common.resume() 285 } 286 } 287 288 impl Snapshottable for Rng { 289 fn id(&self) -> String { 290 self.id.clone() 291 } 292 293 fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 294 Snapshot::new_from_versioned_state(&self.id, &self.state()) 295 } 296 297 fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { 298 self.set_state(&snapshot.to_versioned_state(&self.id)?); 299 Ok(()) 300 } 301 } 302 303 impl Transportable for Rng {} 304 impl Migratable for Rng {} 305