mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-05 10:10:41 +00:00
devices: Update rng devices to be platform agnostic
On Unix, instead of getting random data from `/dev/urandom`, it will get it from the `rand` platform agnostic crate instead. OsRng.fill_bytes on unix will make a syscall to getrandom(2) if available, otherwise it will read from `dev/urandom` after a succesful poll to `dev/random`. Regardless of which way a random data is retrieved, if the entropy pool is not intialized, `fill_bytes` will block until it is intialized. This shouldn't be a problem because it is a one time cost. This CL will also upstream the Windows implementation of the rng device. BUG=b:213149162 TEST=built and presubmits Change-Id: Ic017f11795f8006e0bf2a04eb0478b3a3d336507 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3657812 Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Richard Zhang <rizhang@google.com>
This commit is contained in:
parent
69a55d5540
commit
a19d6ce89c
5 changed files with 52 additions and 55 deletions
|
@ -53,6 +53,7 @@ p9 = "*"
|
|||
power_monitor = { path = "../power_monitor" }
|
||||
protobuf = { version = "2.3", optional = true }
|
||||
protos = { path = "../protos", optional = true }
|
||||
rand = "0.7.2"
|
||||
remain = "*"
|
||||
resources = { path = "../resources" }
|
||||
serde = { version = "1", features = [ "derive" ] }
|
||||
|
|
|
@ -2,34 +2,32 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::{self, Write};
|
||||
use std::thread;
|
||||
|
||||
use base::{error, warn, AsRawDescriptor, Event, PollToken, RawDescriptor, WaitContext};
|
||||
use base::{error, warn, Event, PollToken, RawDescriptor, WaitContext};
|
||||
use rand::rngs::OsRng;
|
||||
use rand::RngCore;
|
||||
use remain::sorted;
|
||||
use thiserror::Error;
|
||||
use vm_memory::GuestMemory;
|
||||
|
||||
use super::{DeviceType, Interrupt, Queue, SignalableInterrupt, VirtioDevice, Writer};
|
||||
use super::{DeviceType, Interrupt, Queue, SignalableInterrupt, VirtioDevice};
|
||||
|
||||
use crate::virtio::Writer;
|
||||
|
||||
const QUEUE_SIZE: u16 = 256;
|
||||
const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE];
|
||||
|
||||
#[sorted]
|
||||
#[derive(Error, Debug)]
|
||||
pub enum RngError {
|
||||
/// Can't access /dev/urandom
|
||||
#[error("failed to access /dev/urandom: {0}")]
|
||||
AccessingRandomDev(io::Error),
|
||||
}
|
||||
pub enum RngError {}
|
||||
pub type Result<T> = std::result::Result<T, RngError>;
|
||||
|
||||
struct Worker {
|
||||
interrupt: Interrupt,
|
||||
queue: Queue,
|
||||
mem: GuestMemory,
|
||||
random_file: File,
|
||||
}
|
||||
|
||||
impl Worker {
|
||||
|
@ -39,19 +37,30 @@ impl Worker {
|
|||
let mut needs_interrupt = false;
|
||||
while let Some(avail_desc) = queue.pop(&self.mem) {
|
||||
let index = avail_desc.index;
|
||||
let random_file = &mut self.random_file;
|
||||
let written = match Writer::new(self.mem.clone(), avail_desc)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))
|
||||
.and_then(|mut writer| writer.write_from(random_file, std::usize::MAX))
|
||||
{
|
||||
Ok(n) => n,
|
||||
|
||||
let writer_or_err = Writer::new(self.mem.clone(), avail_desc)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e));
|
||||
let written_size = match writer_or_err {
|
||||
Ok(mut writer) => {
|
||||
let avail_bytes = writer.available_bytes();
|
||||
|
||||
let mut rand_bytes = vec![0u8; avail_bytes];
|
||||
OsRng.fill_bytes(&mut rand_bytes);
|
||||
|
||||
match writer.write_all(&rand_bytes) {
|
||||
Ok(_) => rand_bytes.len(),
|
||||
Err(e) => {
|
||||
warn!("Failed to write random data to the guest: {}", e);
|
||||
0usize
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to write random data to the guest: {}", e);
|
||||
0
|
||||
0usize
|
||||
}
|
||||
};
|
||||
|
||||
queue.add_used(&self.mem, index, written as u32);
|
||||
queue.add_used(&self.mem, index, written_size as u32);
|
||||
needs_interrupt = true;
|
||||
}
|
||||
|
||||
|
@ -122,18 +131,15 @@ impl Worker {
|
|||
pub struct Rng {
|
||||
kill_evt: Option<Event>,
|
||||
worker_thread: Option<thread::JoinHandle<Worker>>,
|
||||
random_file: Option<File>,
|
||||
virtio_features: u64,
|
||||
}
|
||||
|
||||
impl Rng {
|
||||
/// Create a new virtio rng device that gets random data from /dev/urandom.
|
||||
pub fn new(virtio_features: u64) -> Result<Rng> {
|
||||
let random_file = File::open("/dev/urandom").map_err(RngError::AccessingRandomDev)?;
|
||||
Ok(Rng {
|
||||
kill_evt: None,
|
||||
worker_thread: None,
|
||||
random_file: Some(random_file),
|
||||
virtio_features,
|
||||
})
|
||||
}
|
||||
|
@ -154,13 +160,7 @@ impl Drop for Rng {
|
|||
|
||||
impl VirtioDevice for Rng {
|
||||
fn keep_rds(&self) -> Vec<RawDescriptor> {
|
||||
let mut keep_rds = Vec::new();
|
||||
|
||||
if let Some(random_file) = &self.random_file {
|
||||
keep_rds.push(random_file.as_raw_descriptor());
|
||||
}
|
||||
|
||||
keep_rds
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn device_type(&self) -> DeviceType {
|
||||
|
@ -197,29 +197,25 @@ impl VirtioDevice for Rng {
|
|||
|
||||
let queue = queues.remove(0);
|
||||
|
||||
if let Some(random_file) = self.random_file.take() {
|
||||
let worker_result =
|
||||
thread::Builder::new()
|
||||
.name("virtio_rng".to_string())
|
||||
.spawn(move || {
|
||||
let mut worker = Worker {
|
||||
interrupt,
|
||||
queue,
|
||||
mem,
|
||||
random_file,
|
||||
};
|
||||
worker.run(queue_evts.remove(0), kill_evt);
|
||||
worker
|
||||
});
|
||||
let worker_result =
|
||||
thread::Builder::new()
|
||||
.name("virtio_rng".to_string())
|
||||
.spawn(move || {
|
||||
let mut worker = Worker {
|
||||
interrupt,
|
||||
queue,
|
||||
mem,
|
||||
};
|
||||
worker.run(queue_evts.remove(0), kill_evt);
|
||||
worker
|
||||
});
|
||||
|
||||
match worker_result {
|
||||
Err(e) => {
|
||||
error!("failed to spawn virtio_rng worker: {}", e);
|
||||
return;
|
||||
}
|
||||
Ok(join_handle) => {
|
||||
self.worker_thread = Some(join_handle);
|
||||
}
|
||||
match worker_result {
|
||||
Err(e) => {
|
||||
error!("failed to spawn virtio_rng worker: {}", e);
|
||||
}
|
||||
Ok(join_handle) => {
|
||||
self.worker_thread = Some(join_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -238,10 +234,7 @@ impl VirtioDevice for Rng {
|
|||
error!("{}: failed to get back resources", self.debug_label());
|
||||
return false;
|
||||
}
|
||||
Ok(worker) => {
|
||||
self.random_file = Some(worker.random_file);
|
||||
return true;
|
||||
}
|
||||
Ok(_) => return true,
|
||||
}
|
||||
}
|
||||
false
|
||||
|
|
|
@ -4,5 +4,6 @@
|
|||
|
||||
@include /usr/share/policy/crosvm/common_device.policy
|
||||
|
||||
getrandom: 1
|
||||
openat: return ENOENT
|
||||
prctl: arg0 == PR_SET_NAME
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
@include /usr/share/policy/crosvm/common_device.policy
|
||||
|
||||
getrandom: 1
|
||||
open: return ENOENT
|
||||
openat: return ENOENT
|
||||
prctl: arg0 == PR_SET_NAME
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
@include /usr/share/policy/crosvm/common_device.policy
|
||||
|
||||
getrandom: 1
|
||||
open: return ENOENT
|
||||
openat: return ENOENT
|
||||
prctl: arg0 == PR_SET_NAME
|
||||
|
|
Loading…
Reference in a new issue