Add prng_seeder utility

This binary seeds a FIPS-approved DRBG from /dev/hw_random and then
serves seeds to other processes on the system using a socket
(/dev/socket/prng_seeder) that is passed in by init.

This cherry-pick for tm-qpr-dev omits the command line support
to avoid a dependency problem.

Bug: 243933553
Test: Started under init and verified correct operation using strace
Merged-In: Id4461a402d1ac92180a54cc4b241a2720b94d8de
Change-Id: Id4461a402d1ac92180a54cc4b241a2720b94d8de
(cherry picked from commit d21b00001d40f735105c01cd794c62a353aed6f5)
(cherry picked from commit a8579bf648774abe63aefb53c057acd9e4aa8e22)
Merged-In: Id4461a402d1ac92180a54cc4b241a2720b94d8de
diff --git a/prng_seeder/Android.bp b/prng_seeder/Android.bp
new file mode 100644
index 0000000..ea4f00f
--- /dev/null
+++ b/prng_seeder/Android.bp
@@ -0,0 +1,50 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "external_boringssl_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["system_security_license"],
+}
+
+rust_bindgen {
+    name: "libcutils_socket_bindgen",
+    crate_name: "cutils_socket_bindgen",
+    wrapper_src: "cutils_wrapper.h",
+    source_stem: "bindings",
+    bindgen_flags: [
+        "--allowlist-function=android_get_control_socket",
+    ],
+    shared_libs: [
+        "libcutils",
+    ],
+}
+
+rust_binary {
+    name: "prng_seeder",
+    edition: "2021",
+    srcs: ["src/main.rs"],
+    rustlibs: [
+        "libanyhow",
+        "libbssl_ffi",
+        "libcutils_socket_bindgen",
+        "liblogger",
+        "liblog_rust",
+        "libnix",
+        "libtokio",
+    ],
+}
diff --git a/prng_seeder/cutils_wrapper.h b/prng_seeder/cutils_wrapper.h
new file mode 100644
index 0000000..9c1fe56
--- /dev/null
+++ b/prng_seeder/cutils_wrapper.h
@@ -0,0 +1,15 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cutils/sockets.h>
diff --git a/prng_seeder/src/conditioner.rs b/prng_seeder/src/conditioner.rs
new file mode 100644
index 0000000..66b29a4
--- /dev/null
+++ b/prng_seeder/src/conditioner.rs
@@ -0,0 +1,58 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use std::{fs::File, io::Read};
+
+use anyhow::{ensure, Result};
+use log::debug;
+use tokio::io::AsyncReadExt;
+
+use crate::drbg;
+
+const SEED_FOR_CLIENT_LEN: usize = 496;
+const NUM_REQUESTS_PER_RESEED: u32 = 256;
+
+pub struct Conditioner {
+    hwrng: tokio::fs::File,
+    rg: drbg::Drbg,
+    requests_since_reseed: u32,
+}
+
+impl Conditioner {
+    pub fn new(mut hwrng: File) -> Result<Conditioner> {
+        let mut et: drbg::Entropy = [0; drbg::ENTROPY_LEN];
+        hwrng.read_exact(&mut et)?;
+        let rg = drbg::Drbg::new(&et)?;
+        Ok(Conditioner { hwrng: tokio::fs::File::from_std(hwrng), rg, requests_since_reseed: 0 })
+    }
+
+    pub async fn reseed_if_necessary(&mut self) -> Result<()> {
+        if self.requests_since_reseed >= NUM_REQUESTS_PER_RESEED {
+            debug!("Reseeding DRBG");
+            let mut et: drbg::Entropy = [0; drbg::ENTROPY_LEN];
+            self.hwrng.read_exact(&mut et).await?;
+            self.rg.reseed(&et)?;
+            self.requests_since_reseed = 0;
+        }
+        Ok(())
+    }
+
+    pub fn request(&mut self) -> Result<[u8; SEED_FOR_CLIENT_LEN]> {
+        ensure!(self.requests_since_reseed < NUM_REQUESTS_PER_RESEED, "Not enough reseeds");
+        let mut seed_for_client = [0u8; SEED_FOR_CLIENT_LEN];
+        self.rg.generate(&mut seed_for_client)?;
+        self.requests_since_reseed += 1;
+        Ok(seed_for_client)
+    }
+}
diff --git a/prng_seeder/src/cutils_socket.rs b/prng_seeder/src/cutils_socket.rs
new file mode 100644
index 0000000..ab2c869
--- /dev/null
+++ b/prng_seeder/src/cutils_socket.rs
@@ -0,0 +1,25 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use std::ffi::CString;
+use std::os::unix::{net::UnixListener, prelude::FromRawFd};
+
+use anyhow::{ensure, Result};
+
+pub fn android_get_control_socket(name: &str) -> Result<UnixListener> {
+    let name = CString::new(name)?;
+    let fd = unsafe { cutils_socket_bindgen::android_get_control_socket(name.as_ptr()) };
+    ensure!(fd >= 0, "android_get_control_socket failed");
+    Ok(unsafe { UnixListener::from_raw_fd(fd) })
+}
diff --git a/prng_seeder/src/drbg.rs b/prng_seeder/src/drbg.rs
new file mode 100644
index 0000000..89c5a88
--- /dev/null
+++ b/prng_seeder/src/drbg.rs
@@ -0,0 +1,65 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use anyhow::{ensure, Result};
+use bssl_ffi as bssl_sys;
+
+pub const ENTROPY_LEN: usize = bssl_sys::CTR_DRBG_ENTROPY_LEN as usize;
+
+pub type Entropy = [u8; ENTROPY_LEN];
+
+pub struct Drbg(*mut bssl_sys::CTR_DRBG_STATE);
+
+impl Drbg {
+    pub fn new(entropy: &Entropy) -> Result<Drbg> {
+        let p = unsafe { bssl_sys::CTR_DRBG_new(entropy.as_ptr(), std::ptr::null(), 0) };
+        ensure!(!p.is_null(), "CTR_DRBG_new failed");
+        Ok(Drbg(p))
+    }
+
+    pub fn reseed(&mut self, entropy: &Entropy) -> Result<()> {
+        ensure!(
+            unsafe { bssl_sys::CTR_DRBG_reseed(self.0, entropy.as_ptr(), std::ptr::null(), 0) }
+                == 1,
+            "CTR_DRBG_reseed failed"
+        );
+        Ok(())
+    }
+
+    pub fn generate(&mut self, buf: &mut [u8]) -> Result<()> {
+        ensure!(
+            unsafe {
+                bssl_sys::CTR_DRBG_generate(
+                    self.0,
+                    buf.as_mut_ptr(),
+                    buf.len(),
+                    std::ptr::null(),
+                    0,
+                )
+            } == 1,
+            "CTR_DRBG_generate failed"
+        );
+        Ok(())
+    }
+}
+
+impl Drop for Drbg {
+    fn drop(&mut self) {
+        unsafe {
+            bssl_sys::CTR_DRBG_free(self.0);
+        }
+    }
+}
+
+unsafe impl Send for Drbg {}
diff --git a/prng_seeder/src/main.rs b/prng_seeder/src/main.rs
new file mode 100644
index 0000000..8062d9a
--- /dev/null
+++ b/prng_seeder/src/main.rs
@@ -0,0 +1,111 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! FIPS compliant random number conditioner. Reads from /dev/hw_random
+//! and applies the NIST SP 800-90A CTR DRBG strategy to provide
+//! pseudorandom bytes to clients which connect to a socket provided
+//! by init.
+
+mod conditioner;
+mod cutils_socket;
+mod drbg;
+
+use std::{
+    convert::Infallible,
+    fs::{remove_file, File},
+    io::ErrorKind,
+    os::unix::{net::UnixListener, prelude::AsRawFd},
+    path::{Path, PathBuf},
+};
+
+use anyhow::Result;
+use log::{error, info};
+use nix::{
+    fcntl::{fcntl, FcntlArg::F_SETFL, OFlag},
+    sys::signal,
+};
+use tokio::{io::AsyncWriteExt, net::UnixListener as TokioUnixListener};
+
+use crate::conditioner::Conditioner;
+
+//#[derive(Debug, clap::Parser)]
+struct Cli {
+    //#[clap(long, default_value = "/dev/hw_random")]
+    source: PathBuf,
+    //#[clap(long)]
+    socket: Option<PathBuf>,
+}
+
+fn configure_logging() {
+    logger::init(Default::default());
+}
+
+fn get_socket(path: &Path) -> Result<UnixListener> {
+    if let Err(e) = remove_file(path) {
+        if e.kind() != ErrorKind::NotFound {
+            return Err(e.into());
+        }
+    } else {
+        info!("Deleted old {}", path.to_string_lossy());
+    }
+    Ok(UnixListener::bind(path)?)
+}
+
+async fn listen_loop(hwrng: File, listener: UnixListener) -> Result<Infallible> {
+    let mut conditioner = Conditioner::new(hwrng)?;
+    let listener = TokioUnixListener::from_std(listener)?;
+    loop {
+        match listener.accept().await {
+            Ok((mut stream, _)) => {
+                let new_bytes = conditioner.request()?;
+                tokio::spawn(async move {
+                    if let Err(e) = stream.write_all(&new_bytes).await {
+                        error!("Request failed: {}", e);
+                    }
+                });
+                conditioner.reseed_if_necessary().await?;
+            }
+            Err(e) if e.kind() == ErrorKind::Interrupted => {}
+            Err(e) => return Err(e.into()),
+        }
+    }
+}
+
+fn run(cli: Cli) -> Result<Infallible> {
+    let hwrng = std::fs::File::open(&cli.source)?;
+    fcntl(hwrng.as_raw_fd(), F_SETFL(OFlag::O_NONBLOCK))?;
+    let listener = match cli.socket {
+        Some(path) => get_socket(path.as_path())?,
+        None => cutils_socket::android_get_control_socket("prng_seeder")?,
+    };
+    listener.set_nonblocking(true)?;
+
+    unsafe { signal::signal(signal::Signal::SIGPIPE, signal::SigHandler::SigIgn) }?;
+
+    tokio::runtime::Builder::new_current_thread()
+        .enable_all()
+        .build()?
+        .block_on(async { listen_loop(hwrng, listener).await })
+}
+
+fn main() {
+    let cli = Cli { source: PathBuf::from("/dev/hw_random"), socket: None };
+    configure_logging();
+    if let Err(e) = run(cli) {
+        error!("Launch failed: {}", e);
+    } else {
+        error!("Loop terminated without an error")
+    }
+    std::process::exit(-1);
+}