summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Crowley <paulcrowley@google.com>2022-09-28 18:37:43 +0000
committerPaul Crowley <paulcrowley@google.com>2022-10-03 17:29:41 +0000
commit4e6fe88753fddbb4da0ffd8574c389d1255baf65 (patch)
tree3dc74eac714d740041c9847f126ad69c49ade89d
parenta8579bf648774abe63aefb53c057acd9e4aa8e22 (diff)
downloadsecurity-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.bp3
-rw-r--r--prng_seeder/src/conditioner.rs38
-rw-r--r--prng_seeder/src/main.rs97
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);
}