Skip to content

Commit 138c9f9

Browse files
committed
harden(rng): cap per-request entropy allocation to 64 KiB
Backports upstream firecracker PR firecracker-microvm#5762 (commit 7550869). Adds a MAX_ENTROPY_BYTES (64 KiB) cap on the per-request rand_bytes allocation in handle_one(). The pre-fix code did `vec![0; iovec.len()]` where `iovec.len()` is the *sum* of all descriptor lengths in a chain, not the distinct guest memory backing them. A guest can craft 255 overlapping descriptors each claiming 16 MiB but all pointing to the same guest physical memory, inflating iovec.len() to ~4 GiB and exhausting host RAM. No CVE was assigned upstream; AWS classifies this as a host DoS hardening rather than a security advisory. Operationally, SAFE microVMs do not attach an entropy device, so the unfixed code path is unreachable in our deployment. This is defence-in-depth for any future config that does attach one. Manual port — could not be cherry-picked cleanly because by v1.15.x the rng device holds an owned `self.buffer` field and process_entropy_queue has a different signature. Most importantly, IoVecBufferMut::len() returns u32 in v1.15.x but usize in v1.6.5, which forced a small change to the cap arithmetic and the function return path. The actual security-relevant change (the cap itself) is the same as upstream.
1 parent d3b81c2 commit 138c9f9

1 file changed

Lines changed: 12 additions & 3 deletions

File tree

src/vmm/src/devices/virtio/rng/device.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ use crate::vstate::memory::GuestMemoryMmap;
2323

2424
pub const ENTROPY_DEV_ID: &str = "rng";
2525

26+
// Cap the per-request entropy allocation. A guest can craft a virtio
27+
// descriptor chain whose total `iovec.len()` is the sum of many overlapping
28+
// descriptors, reaching multi-GiB sizes from a small guest memory and
29+
// exhausting host RAM. The guest still gets up to this many bytes of entropy
30+
// per request.
31+
const MAX_ENTROPY_BYTES: u32 = 64 * 1024;
32+
2633
#[derive(Debug, thiserror::Error, displaydoc::Display)]
2734
pub enum EntropyError {
2835
/// Error while handling an Event file descriptor: {0}
@@ -112,15 +119,17 @@ impl Entropy {
112119
return Ok(0);
113120
}
114121

115-
let mut rand_bytes = vec![0; iovec.len()];
122+
let len = std::cmp::min(iovec.len(), MAX_ENTROPY_BYTES as usize);
123+
let mut rand_bytes = vec![0; len];
116124
rand::fill(&mut rand_bytes).map_err(|err| {
117125
METRICS.host_rng_fails.inc();
118126
err
119127
})?;
120128

121-
// It is ok to unwrap here. We are writing `iovec.len()` bytes at offset 0.
129+
// We are writing at most `iovec.len()` bytes starting at offset 0.
122130
iovec.write_all_volatile_at(&rand_bytes, 0).unwrap();
123-
Ok(iovec.len().try_into().unwrap())
131+
// `len` fits in u32: bounded above by MAX_ENTROPY_BYTES (64 KiB).
132+
Ok(len.try_into().unwrap())
124133
}
125134

126135
fn process_entropy_queue(&mut self) {

0 commit comments

Comments
 (0)