Repository: firecracker-microvm/firecracker
File: src/vmm/src/devices/virtio/rng/device.rs (Rust)

Code before:
            return Ok(0);
        }

        let mut rand_bytes = vec![0; iovec.len() as usize];
        rand::fill(&mut rand_bytes).map_err(|err| {
            METRICS.host_rng_fails.inc();
            err
        })?;

        // It is ok to unwrap here. We are writing `iovec.len()` bytes at offset 0.
        iovec.write_all_volatile_at(&rand_bytes, 0).unwrap();
        Ok(iovec.len())
    }

    fn process_entropy_queue(&mut self) {
        // This is safe since we checked in the event handler that the device is activated.
        let mem = self.device_state.mem().unwrap();

        let mut used_any = false;
        while let Some(desc) = self.queues[RNG_QUEUE].pop() {
            let index = desc.index;
            METRICS.entropy_event_count.inc();

            // SAFETY: This descriptor chain is only loaded once
            // virtio requests are handled sequentially so no two IoVecBuffers
            // are live at the same time, meaning this has exclusive ownership over the memory
            let bytes = match unsafe { self.buffer.load_descriptor_chain(mem, desc) } {
                Ok(()) => {
                    debug!(
                        "entropy: guest request for {} bytes of entropy",
                        self.buffer.len()
                    );

                    // Check for available rate limiting budget.
                    // If not enough budget is available, leave the request descriptor in the queue
                    // to handle once we do have budget.
                    if !Self::rate_limit_request(&mut self.rate_limiter, u64::from(self.buffer.len())) {
                        debug!("entropy: throttling entropy queue");
                        METRICS.entropy_rate_limiter_throttled.inc();
                        self.queues[RNG_QUEUE].undo_pop();
                        break;
                    }

                    Self::handle_one(&mut self.buffer).unwrap_or_else(|err| {
                        error!("entropy: {err}");
                        METRICS.entropy_event_fails.inc();
                        0
                    })
                }
                Err(err) => {
                    error!("entropy: Could not parse descriptor chain: {err}");

Review comment (suggestion):
```suggestion
            // SAFETY: This descriptor chain points to a single `DescriptorChain` memory buffer,
            // no other `IoVecBufferMut` object points to the same `DescriptorChain` at the same
            // time and we clear the `iovec` after we process the request.
```


Code after:
            return Ok(0);
        }

        let mut rand_bytes = vec![0; self.buffer.len() as usize];
        rand::fill(&mut rand_bytes).map_err(|err| {
            METRICS.host_rng_fails.inc();
            err
        })?;

        // It is ok to unwrap here. We are writing `iovec.len()` bytes at offset 0.
        self.buffer.write_all_volatile_at(&rand_bytes, 0).unwrap();
        Ok(self.buffer.len())
    }

    fn process_entropy_queue(&mut self) {
        let mut used_any = false;
        while let Some(desc) = self.queues[RNG_QUEUE].pop() {
            // This is safe since we checked in the event handler that the device is activated.
            let mem = self.device_state.mem().unwrap();
            let index = desc.index;
            METRICS.entropy_event_count.inc();

            // SAFETY: This descriptor chain points to a single `DescriptorChain` memory buffer,
            // no other `IoVecBufferMut` object points to the same `DescriptorChain` at the same
            // time and we clear the `iovec` after we process the request.
            let bytes = match unsafe { self.buffer.load_descriptor_chain(mem, desc) } {
                Ok(()) => {
                    debug!(
                        "entropy: guest request for {} bytes of entropy",
                        self.buffer.len()
                    );

                    // Check for available rate limiting budget.
                    // If not enough budget is available, leave the request descriptor in the queue
                    // to handle once we do have budget.
                    if !self.rate_limit_request(u64::from(self.buffer.len())) {
                        debug!("entropy: throttling entropy queue");
                        METRICS.entropy_rate_limiter_throttled.inc();
                        self.queues[RNG_QUEUE].undo_pop();
                        break;
                    }

                    self.handle_one().unwrap_or_else(|err| {
                        error!("entropy: {err}");
                        METRICS.entropy_event_fails.inc();
                        0
                    })
                }
                Err(err) => {
                    error!("entropy: Could not parse descriptor chain: {err}");
                    METRICS.entropy_event_fails.inc();