diff options
author | Paul Crowley <paulcrowley@google.com> | 2022-09-28 18:37:43 +0000 |
---|---|---|
committer | Paul Crowley <paulcrowley@google.com> | 2022-10-03 17:29:41 +0000 |
commit | 4e6fe88753fddbb4da0ffd8574c389d1255baf65 (patch) | |
tree | 3dc74eac714d740041c9847f126ad69c49ade89d | |
parent | a8579bf648774abe63aefb53c057acd9e4aa8e22 (diff) | |
download | security-4e6fe88753fddbb4da0ffd8574c389d1255baf65.tar.gz |
If setup fails, hang forever
Without this init will repeatedly try to start this daemon,
causing logspam.
Also:
* wait until just before tokio conversion to set O_NONBLOCK
* ensure logging code reflects source example
* log at info and higher
* use contexts for better logging
* fall back to println to work around logging problems
* remove wrong copy-pasted comment in Android.bp
Bug: 249531229
Fixes: 249566340
Test: in permissive mode, rm /dev/hw_random before start
Change-Id: Ib70cbcb048f33dca789151622d98c6d56270fa37
Merged-In: Ib70cbcb048f33dca789151622d98c6d56270fa37
(cherry picked from commit 021cf557e6cdf1ff0779e87834532c0e0e893ef8)
-rw-r--r-- | prng_seeder/Android.bp | 3 | ||||
-rw-r--r-- | prng_seeder/src/conditioner.rs | 38 | ||||
-rw-r--r-- | prng_seeder/src/main.rs | 97 |
3 files changed, 89 insertions, 49 deletions
diff --git a/prng_seeder/Android.bp b/prng_seeder/Android.bp index ea4f00ff..2be20a97 100644 --- a/prng_seeder/Android.bp +++ b/prng_seeder/Android.bp @@ -14,9 +14,6 @@ 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"], } diff --git a/prng_seeder/src/conditioner.rs b/prng_seeder/src/conditioner.rs index 66b29a45..eca8af88 100644 --- a/prng_seeder/src/conditioner.rs +++ b/prng_seeder/src/conditioner.rs @@ -12,10 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{fs::File, io::Read}; +use std::{fs::File, io::Read, os::unix::io::AsRawFd}; -use anyhow::{ensure, Result}; +use anyhow::{ensure, Context, Result}; use log::debug; +use nix::fcntl::{fcntl, FcntlArg::F_SETFL, OFlag}; use tokio::io::AsyncReadExt; use crate::drbg; @@ -23,25 +24,42 @@ use crate::drbg; const SEED_FOR_CLIENT_LEN: usize = 496; const NUM_REQUESTS_PER_RESEED: u32 = 256; -pub struct Conditioner { - hwrng: tokio::fs::File, +pub struct ConditionerBuilder { + hwrng: File, rg: drbg::Drbg, - requests_since_reseed: u32, } -impl Conditioner { - pub fn new(mut hwrng: File) -> Result<Conditioner> { +impl ConditionerBuilder { + pub fn new(mut hwrng: File) -> Result<ConditionerBuilder> { let mut et: drbg::Entropy = [0; drbg::ENTROPY_LEN]; - hwrng.read_exact(&mut et)?; + hwrng.read_exact(&mut et).context("hwrng.read_exact in new")?; let rg = drbg::Drbg::new(&et)?; - Ok(Conditioner { hwrng: tokio::fs::File::from_std(hwrng), rg, requests_since_reseed: 0 }) + fcntl(hwrng.as_raw_fd(), F_SETFL(OFlag::O_NONBLOCK)) + .context("setting O_NONBLOCK on hwrng")?; + Ok(ConditionerBuilder { hwrng, rg }) } + pub fn build(self) -> Conditioner { + Conditioner { + hwrng: tokio::fs::File::from_std(self.hwrng), + rg: self.rg, + requests_since_reseed: 0, + } + } +} + +pub struct Conditioner { + hwrng: tokio::fs::File, + rg: drbg::Drbg, + requests_since_reseed: u32, +} + +impl Conditioner { 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.hwrng.read_exact(&mut et).await.context("hwrng.read_exact in reseed")?; self.rg.reseed(&et)?; self.requests_since_reseed = 0; } diff --git a/prng_seeder/src/main.rs b/prng_seeder/src/main.rs index 8062d9a4..10f853dd 100644 --- a/prng_seeder/src/main.rs +++ b/prng_seeder/src/main.rs @@ -23,21 +23,18 @@ mod drbg; use std::{ convert::Infallible, - fs::{remove_file, File}, + fs::remove_file, io::ErrorKind, - os::unix::{net::UnixListener, prelude::AsRawFd}, + os::unix::net::UnixListener, path::{Path, PathBuf}, }; -use anyhow::Result; -use log::{error, info}; -use nix::{ - fcntl::{fcntl, FcntlArg::F_SETFL, OFlag}, - sys::signal, -}; +use anyhow::{ensure, Context, Result}; +use log::{error, info, Level}; +use nix::sys::signal; use tokio::{io::AsyncWriteExt, net::UnixListener as TokioUnixListener}; -use crate::conditioner::Conditioner; +use crate::conditioner::ConditionerBuilder; //#[derive(Debug, clap::Parser)] struct Cli { @@ -47,24 +44,50 @@ struct Cli { socket: Option<PathBuf>, } -fn configure_logging() { - logger::init(Default::default()); +fn configure_logging() -> Result<()> { + ensure!( + logger::init( + logger::Config::default().with_tag_on_device("prng_seeder").with_min_level(Level::Info) + ), + "log configuration failed" + ); + Ok(()) } fn get_socket(path: &Path) -> Result<UnixListener> { if let Err(e) = remove_file(path) { if e.kind() != ErrorKind::NotFound { - return Err(e.into()); + return Err(e).context(format!("Removing old socket: {}", path.display())); } } else { - info!("Deleted old {}", path.to_string_lossy()); + info!("Deleted old {}", path.display()); } - Ok(UnixListener::bind(path)?) + UnixListener::bind(path) + .with_context(|| format!("In get_socket: binding socket to {}", path.display())) +} + +fn setup() -> Result<(ConditionerBuilder, UnixListener)> { + configure_logging()?; + let cli = Cli { source: PathBuf::from("/dev/hw_random"), socket: None }; + unsafe { signal::signal(signal::Signal::SIGPIPE, signal::SigHandler::SigIgn) } + .context("In setup, setting SIGPIPE to SIG_IGN")?; + + let listener = match cli.socket { + Some(path) => get_socket(path.as_path())?, + None => cutils_socket::android_get_control_socket("prng_seeder") + .context("In setup, calling android_get_control_socket")?, + }; + let hwrng = std::fs::File::open(&cli.source) + .with_context(|| format!("Unable to open hwrng {}", cli.source.display()))?; + let cb = ConditionerBuilder::new(hwrng)?; + Ok((cb, listener)) } -async fn listen_loop(hwrng: File, listener: UnixListener) -> Result<Infallible> { - let mut conditioner = Conditioner::new(hwrng)?; - let listener = TokioUnixListener::from_std(listener)?; +async fn listen_loop(cb: ConditionerBuilder, listener: UnixListener) -> Result<Infallible> { + let mut conditioner = cb.build(); + listener.set_nonblocking(true).context("In listen_loop, on set_nonblocking")?; + let listener = TokioUnixListener::from_std(listener).context("In listen_loop, on from_std")?; + info!("Starting listen loop"); loop { match listener.accept().await { Ok((mut stream, _)) => { @@ -77,35 +100,37 @@ async fn listen_loop(hwrng: File, listener: UnixListener) -> Result<Infallible> conditioner.reseed_if_necessary().await?; } Err(e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => return Err(e.into()), + Err(e) => return Err(e).context("accept on socket failed"), } } } -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")?, +fn run() -> Result<Infallible> { + let (cb, listener) = match setup() { + Ok(t) => t, + Err(e) => { + // If setup fails, just hang forever. That way init doesn't respawn us. + error!("Hanging forever because setup failed: {:?}", e); + // Logs are sometimes mysteriously not being logged, so print too + println!("prng_seeder: Hanging forever because setup failed: {:?}", e); + loop { + std::thread::park(); + error!("std::thread::park() finished unexpectedly, re-parking thread"); + } + } }; - 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 }) + .build() + .context("In run, building reactor")? + .block_on(async { listen_loop(cb, 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") - } + let e = run(); + error!("Launch terminated: {:?}", e); + // Logs are sometimes mysteriously not being logged, so print too + println!("prng_seeder: launch terminated: {:?}", e); std::process::exit(-1); } |