blob: 88ab116a3af4506fd0b7ed248f367bbd611fa3b1 [file]
// Copyright 2026 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
use crate::user_copy::{UserInPtr, UserOutPtr};
use syscalls_macro::syscall;
use zx_status::Status;
use zx_types::{ZX_CPRNG_ADD_ENTROPY_MAX_LEN, ZX_CPRNG_DRAW_MAX_LEN};
const MAX_CPRNG_DRAW: usize = ZX_CPRNG_DRAW_MAX_LEN;
const MAX_CPRNG_SEED: usize = ZX_CPRNG_ADD_ENTROPY_MAX_LEN;
unsafe extern "C" {
fn mandatory_memset(dst: *mut u8, c: core::ffi::c_int, n: usize) -> *mut u8;
fn cpp_global_prng_draw(buffer: *mut u8, len: usize);
fn cpp_global_prng_add_entropy(buffer: *const u8, len: usize);
}
use core::ops::{Deref, DerefMut};
struct ZeroOnDrop<'a, T>(&'a mut [T]);
impl<'a, T> Deref for ZeroOnDrop<'a, T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<'a, T> DerefMut for ZeroOnDrop<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.0
}
}
impl<'a, T> Drop for ZeroOnDrop<'a, T> {
fn drop(&mut self) {
// SAFETY: `self.0` is a valid slice of `size_of_val(self.0)` bytes.
unsafe {
mandatory_memset(self.0.as_mut_ptr() as *mut u8, 0, core::mem::size_of_val(self.0));
}
}
}
#[syscall]
pub fn sys_cprng_draw_once(buffer: UserOutPtr<u8>, len: usize) -> Result<(), Status> {
if len > MAX_CPRNG_DRAW {
return Err(Status::INVALID_ARGS);
}
let mut storage = [0u8; MAX_CPRNG_DRAW];
// Ensure we get rid of the stack copy of the random data as this function returns.
let mut kernel_buf = ZeroOnDrop(&mut storage);
// SAFETY: `kernel_buf` points to valid stack memory with capacity of `MAX_CPRNG_DRAW` bytes.
unsafe {
cpp_global_prng_draw(kernel_buf.as_mut_ptr(), len);
}
buffer.copy_slice_to_user(&kernel_buf[..len]).map_err(|_| Status::INVALID_ARGS)?;
Ok(())
}
#[syscall]
pub fn sys_cprng_add_entropy(buffer: UserInPtr<u8>, buffer_size: usize) -> Result<(), Status> {
if buffer_size > MAX_CPRNG_SEED {
return Err(Status::INVALID_ARGS);
}
let mut storage = [core::mem::MaybeUninit::<u8>::uninit(); MAX_CPRNG_SEED];
// Ensure we get rid of the stack copy of the entropy as this function returns.
let mut kernel_buf = ZeroOnDrop(&mut storage);
let slice = buffer
.copy_slice_from_user(&mut kernel_buf[..buffer_size])
.map_err(|_| Status::INVALID_ARGS)?;
// SAFETY: `slice` has been initialized from userspace and has length `buffer_size`.
unsafe {
cpp_global_prng_add_entropy(slice.as_ptr(), buffer_size);
}
Ok(())
}