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