diff --git a/CHANGELOG.md b/CHANGELOG.md index ec69969..53a2d26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - N/A +## [0.2.1] - 2021-05-01 + +### Added + +- VerifyCanTerminate action + +### Changed + +- Updated to latest dependencies + +### Security +- A privileged user (such as root) with local access to a server running WhiteBeam can kill the WhiteBeam logging service + Fixed in 0.2.1: https://github.com/WhiteBeamSec/WhiteBeam/security/advisories/GHSA-h543-6328-8f64 + ## [0.2.0] - 2021-04-20 ### Added diff --git a/src/application/Cargo.toml b/src/application/Cargo.toml index a079468..5291626 100644 --- a/src/application/Cargo.toml +++ b/src/application/Cargo.toml @@ -1,7 +1,7 @@ # General info [package] name = "whitebeam" -version = "0.2.0" +version = "0.2.1" authors = ["WhiteBeam Security, Inc."] edition = "2018" @@ -25,14 +25,14 @@ rpassword = { version = "5.0" } cli-table = { version = "0.4" } linkme = { version = "0.2" } automod = { version = "1.0" } -rand = { version = "0.7" } +rand = { version = "0.8" } glob = { version = "0.3" } goblin = { version = "0.4" } # Cryptographic dependencies sha3 = { version = "0.9" } blake3 = { version = "0.3" } -argon2 = { version = "0.1" } -crypto_box = { version = "0.5" } +argon2 = { version = "0.2" } +crypto_box = { version = "0.6" } [features] whitelist_test = [] diff --git a/src/application/common/crypto.rs b/src/application/common/crypto.rs index bf35fa4..4460763 100644 --- a/src/application/common/crypto.rs +++ b/src/application/common/crypto.rs @@ -17,7 +17,7 @@ use std::{error::Error, path::Path, fmt::Write as FmtWrite, num::ParseIntError}; -use crypto_box::{ChaChaBox, PublicKey, SecretKey, aead::{Aead, Nonce}, KEY_SIZE}; +use crypto_box::{ChaChaBox, PublicKey, SecretKey, aead::{Aead, generic_array::GenericArray}, KEY_SIZE}; pub const NONCE_SIZE: usize = 24; // TODO: Test, probably doesn't work as-is. Especially the ChaChaBox without the postfix tag: https://stackoverflow.com/a/62140062 @@ -135,7 +135,7 @@ fn generate_ciphertext(plaintext: &[u8], nonce: &[u8]) -> Result, Box Ok(ciphertext), Err(_e) => return Err("Could not generate ciphertext".into()) @@ -146,7 +146,7 @@ fn decrypt_server_ciphertext(ciphertext: &[u8], nonce: &[u8]) -> Result, let (_client_public_key, client_private_key) = get_client_public_private_key()?; let server_public_key = get_server_public_key()?; let client_box = ChaChaBox::new(&server_public_key, &client_private_key); - let nonce_obj = Nonce::from_slice(nonce); + let nonce_obj = GenericArray::from_slice(nonce); // Verification and decryption match client_box.decrypt(&nonce_obj, ciphertext) { Ok(plaintext) => Ok(plaintext), diff --git a/src/application/common/hash/hashes/argon2id.rs b/src/application/common/hash/hashes/argon2id.rs index d2d4fcc..1de16a6 100644 --- a/src/application/common/hash/hashes/argon2id.rs +++ b/src/application/common/hash/hashes/argon2id.rs @@ -8,7 +8,7 @@ build_hash! { ARGON2ID (reader, salt_opt) { Some(val) => val, None => { let mut rng = rand::thread_rng(); - let mut bytes = [0u8; argon2::password_hash::Salt::recommended_len()]; + let mut bytes = [0u8; argon2::password_hash::Salt::RECOMMENDED_LENGTH]; rng.fill_bytes(&mut bytes); String::from(argon2::password_hash::SaltString::b64_encode(&bytes).expect("WhiteBeam: Salt string invariant violated").as_str()) } @@ -16,5 +16,5 @@ build_hash! { ARGON2ID (reader, salt_opt) { // Argon2 with default params (Argon2id v19) let argon2 = argon2::Argon2::default(); // Hash password to PHC string ($argon2id$v=19$...) - argon2.hash_password_simple(password.as_bytes(), salt.as_ref()).unwrap().to_string() + argon2.hash_password_simple::(password.as_bytes(), &salt).unwrap().to_string() }} diff --git a/src/installer/Cargo.toml b/src/installer/Cargo.toml index 7a7abc8..04fd62b 100644 --- a/src/installer/Cargo.toml +++ b/src/installer/Cargo.toml @@ -1,7 +1,7 @@ # General info [package] name = "whitebeam-installer" -version = "0.2.0" +version = "0.2.1" authors = ["WhiteBeam Security, Inc."] edition = "2018" diff --git a/src/library/Cargo.toml b/src/library/Cargo.toml index 1261ef6..f96ee96 100644 --- a/src/library/Cargo.toml +++ b/src/library/Cargo.toml @@ -1,7 +1,7 @@ # General info [package] name = "libwhitebeam" -version = "0.2.0" +version = "0.2.1" authors = ["WhiteBeam Security, Inc."] edition = "2018" @@ -23,7 +23,7 @@ glob = { version = "0.3" } # Cryptographic dependencies sha3 = { version = "0.9" } blake3 = { version = "0.3" } -argon2 = { version = "0.1" } +argon2 = { version = "0.2" } [features] whitelist_test = [] diff --git a/src/library/common/action/actions/verify_can_terminate.rs b/src/library/common/action/actions/verify_can_terminate.rs new file mode 100644 index 0000000..8cfa1c7 --- /dev/null +++ b/src/library/common/action/actions/verify_can_terminate.rs @@ -0,0 +1,24 @@ +#[macro_use] +build_action! { VerifyCanTerminate (src_prog, hook, arg_id, args, do_return, return_value) { + // Permit termination if not running in prevention mode + if !(crate::common::db::get_prevention()) { + return (hook, args, do_return, return_value); + } + // Permit authorized termination + if crate::common::db::get_valid_auth_env() { + return (hook, args, do_return, return_value); + } + let pid_index = args.iter().position(|arg| arg.id == arg_id).expect("WhiteBeam: Lost track of environment"); + let pid: i32 = args[pid_index].clone().real as i32; + let service_pid_string: String = std::fs::read_to_string(platform::get_data_file_path_string("whitebeam.pid")).expect("WhiteBeam: Lost track of environment"); + let service_pid: i32 = service_pid_string.strip_suffix("\n").unwrap_or(&service_pid_string).parse().expect("WhiteBeam: Unexpected null reference"); + let service_pgid: i32 = unsafe { libc::getpgid(service_pid) }; + if (pid == service_pid) || + (pid == -service_pgid) || + ((pid == -1) && (platform::get_current_uid() == 0)) { + event::send_log_event(event::LogClass::Warn as i64, format!("Blocked {} from killing WhiteBeam service (VerifyCanTerminate)", &src_prog)); + eprintln!("WhiteBeam: kill ({}): Operation not permitted", pid); + do_return = true; + return_value = -1; + } +}} diff --git a/src/library/common/action/actions/verify_can_write.rs b/src/library/common/action/actions/verify_can_write.rs index 1ef13e5..74535fc 100644 --- a/src/library/common/action/actions/verify_can_write.rs +++ b/src/library/common/action/actions/verify_can_write.rs @@ -7,7 +7,7 @@ build_action! { VerifyCanWrite (src_prog, hook, arg_id, args, do_return, return_ if !(crate::common::db::get_prevention()) { return (hook, args, do_return, return_value); } - // Permit authorized execution + // Permit authorized writes if crate::common::db::get_valid_auth_env() { return (hook, args, do_return, return_value); } diff --git a/src/library/common/convert.rs b/src/library/common/convert.rs index dec8d8b..fa69ec5 100644 --- a/src/library/common/convert.rs +++ b/src/library/common/convert.rs @@ -7,7 +7,7 @@ use std::{ffi::CStr, os::unix::ffi::OsStrExt, os::unix::ffi::OsStringExt}; -// TODO: impl/trait? Extend types? .into()? 0.2.1 +// TODO: impl/trait? Extend types? .into()? 0.2.2 pub unsafe fn c_char_to_osstring(char_ptr: *const c_char) -> OsString { match char_ptr.is_null() { diff --git a/src/library/common/hash/hashes/argon2id.rs b/src/library/common/hash/hashes/argon2id.rs index 33f5380..241235c 100644 --- a/src/library/common/hash/hashes/argon2id.rs +++ b/src/library/common/hash/hashes/argon2id.rs @@ -8,5 +8,5 @@ build_hash! { ARGON2ID (reader, salt_opt) { // Argon2 with default params (Argon2id v19) let argon2 = argon2::Argon2::default(); // Hash password to PHC string ($argon2id$v=19$...) - argon2.hash_password_simple(password.as_bytes(), salt.as_ref()).unwrap().to_string() + argon2.hash_password_simple::(password.as_bytes(), &salt).unwrap().to_string() }} diff --git a/src/library/platforms/linux/mod.rs b/src/library/platforms/linux/mod.rs index 3329832..c1ab015 100644 --- a/src/library/platforms/linux/mod.rs +++ b/src/library/platforms/linux/mod.rs @@ -303,7 +303,7 @@ unsafe extern "C" fn generic_hook (mut arg1: usize, mut args: ...) -> isize { // Unsupported _ => panic!("WhiteBeam: Unsupported operation"), }; - // TODO: Replace below with post action framework (0.2.1 - 0.2.2) + // TODO: Replace below with post action framework (0.2.2 - 0.2.3) // TODO: May need fopen/fopen64 => fdopen match (hook_orig.symbol.as_ref(), hook.symbol.as_ref()) { ("symlink", "symlinkat") => { @@ -500,13 +500,17 @@ pub unsafe fn dlsym_next_relative(symbol: &str, real_addr: usize) -> *const u8 { calculated_addr } -pub fn get_data_file_path(data_file: &str) -> PathBuf { +pub fn get_data_file_path_string(data_file: &str) -> String { #[cfg(feature = "whitelist_test")] let data_path: String = format!("{}/target/release/examples/", env!("PWD")); #[cfg(not(feature = "whitelist_test"))] let data_path: String = String::from("/opt/WhiteBeam/data/"); let data_file_path = data_path + data_file; - PathBuf::from(data_file_path) + data_file_path +} + +pub fn get_data_file_path(data_file: &str) -> PathBuf { + PathBuf::from(get_data_file_path_string(data_file)) } pub fn get_rtld_audit_lib_path() -> PathBuf { diff --git a/src/library/tests/Cargo.toml b/src/library/tests/Cargo.toml index 07fdb6a..5b4ae21 100644 --- a/src/library/tests/Cargo.toml +++ b/src/library/tests/Cargo.toml @@ -1,7 +1,7 @@ # General info [package] name = "libwhitebeam-tests" -version = "0.2.0" +version = "0.2.1" authors = ["WhiteBeam Security, Inc."] edition = "2018"