From 1369454858f894e6ead91300ee02d6fe706eab4c Mon Sep 17 00:00:00 2001 From: noproto Date: Sun, 8 Mar 2020 21:06:03 -0400 Subject: [PATCH] Template hooks (2/2), Relicense --- LICENSE | 21 ----- LICENSE.md | 7 ++ src/application/Cargo.toml | 2 +- src/library/Cargo.toml | 2 +- src/library/platforms/linux/hooks/execv.rs | 33 +------- src/library/platforms/linux/hooks/execve.rs | 59 ++++--------- src/library/platforms/linux/hooks/execvp.rs | 48 +++-------- src/library/platforms/linux/hooks/execvpe.rs | 46 +++-------- src/library/platforms/linux/hooks/template.rs | 82 +++++++++++++++++-- 9 files changed, 130 insertions(+), 170 deletions(-) delete mode 100644 LICENSE create mode 100644 LICENSE.md diff --git a/LICENSE b/LICENSE deleted file mode 100644 index e4bf354..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 WhiteBeam Security, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..e4babf9 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,7 @@ +## License + +Copyright (c) 2020 WhiteBeam Security, Inc. + +This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. + +Creative Commons License diff --git a/src/application/Cargo.toml b/src/application/Cargo.toml index 6511c4c..f7ecb7c 100644 --- a/src/application/Cargo.toml +++ b/src/application/Cargo.toml @@ -1,7 +1,7 @@ # General info [package] name = "whitebeam" -version = "0.1.1" +version = "0.1.2" authors = ["WhiteBeam Security, Inc."] edition = "2018" diff --git a/src/library/Cargo.toml b/src/library/Cargo.toml index 2abb7e4..693e61c 100644 --- a/src/library/Cargo.toml +++ b/src/library/Cargo.toml @@ -1,7 +1,7 @@ # General info [package] name = "libwhitebeam" -version = "0.1.1" +version = "0.1.2" authors = ["WhiteBeam Security, Inc."] edition = "2018" diff --git a/src/library/platforms/linux/hooks/execv.rs b/src/library/platforms/linux/hooks/execv.rs index 9015db6..2094b1a 100644 --- a/src/library/platforms/linux/hooks/execv.rs +++ b/src/library/platforms/linux/hooks/execv.rs @@ -1,34 +1,9 @@ -use libc::{c_char, c_int}; -use std::ptr; -use crate::platforms::linux; -use crate::common::whitelist; -use crate::common::event; -use crate::common::hash; - +#[macro_use] /* int execv(const char *path, char *const argv[]); */ -#[no_mangle] -pub unsafe extern "C" fn execv(path: *const c_char, argv: *const *const c_char) -> c_int { - let envp: *const *const c_char = ptr::null(); - let program = linux::c_char_to_osstring(path); - let env = linux::parse_env_collection(envp); - let hexdigest = hash::common_hash_file(&program); - let uid = linux::get_current_uid(); - // Permit/deny execution - if whitelist::is_whitelisted(&program, &env, &hexdigest) { - event::send_exec_event(uid, &program, &hexdigest, true); - // Pass through - static mut REAL: *const u8 = 0 as *const u8; - static mut ONCE: ::std::sync::Once = ::std::sync::Once::new(); - ONCE.call_once(|| { - REAL = crate::platforms::linux::dlsym_next("execv\u{0}"); - }); - let execv_real: unsafe extern "C" fn(path: *const c_char, argv: *const *const c_char) -> c_int = std::mem::transmute(REAL); - execv_real(path, argv) - } else { - event::send_exec_event(uid, &program, &hexdigest, false); - *linux::errno_location() = libc::EACCES; - return -1 +build_exec_hook! { + hook execv (program) { + // execv custom routines } } diff --git a/src/library/platforms/linux/hooks/execve.rs b/src/library/platforms/linux/hooks/execve.rs index c9405fd..9aef924 100644 --- a/src/library/platforms/linux/hooks/execve.rs +++ b/src/library/platforms/linux/hooks/execve.rs @@ -1,49 +1,26 @@ -use libc::{c_char, c_int}; -use std::ffi::OsString; -use crate::platforms::linux; -use crate::common::whitelist; -use crate::common::event; -use crate::common::hash; - +#[macro_use] /* int execve(const char *path, char *const argv[], char *const envp[]); */ -#[no_mangle] -pub unsafe extern "C" fn execve(path: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> c_int { - let program = linux::c_char_to_osstring(path); - let env = linux::parse_env_collection(envp); - let hexdigest = hash::common_hash_file(&program); - let uid = linux::get_current_uid(); - // Warn that legacy versions of man-db must disable seccomp - // TODO: Hook proper function - if program == "/usr/bin/man" { - let needle = OsString::from("MAN_DISABLE_SECCOMP"); - let mut disable_defined = false; - for env_var in &env { - if env_var.0 == needle { - disable_defined = true; - break; +build_exec_hook! { + hook execve (program, envp) { + // execve custom routines + // Warn that legacy versions of man-db must disable seccomp + // TODO: Hook proper function + if program == "/usr/bin/man" { + let needle = std::ffi::OsString::from("MAN_DISABLE_SECCOMP"); + let mut disable_defined = false; + let man_env = crate::platforms::linux::parse_env_collection(envp); + for env_var in man_env { + if env_var.0 == needle { + disable_defined = true; + break; + } + } + if !(disable_defined) { + eprintln!("WhiteBeam: Legacy man-db versions require MAN_DISABLE_SECCOMP=1") } } - if !(disable_defined) { - eprintln!("WhiteBeam: Legacy man-db versions require MAN_DISABLE_SECCOMP=1") - } - } - // Permit/deny execution - if whitelist::is_whitelisted(&program, &env, &hexdigest) { - event::send_exec_event(uid, &program, &hexdigest, true); - // Pass through - static mut REAL: *const u8 = 0 as *const u8; - static mut ONCE: ::std::sync::Once = ::std::sync::Once::new(); - ONCE.call_once(|| { - REAL = crate::platforms::linux::dlsym_next("execve\u{0}"); - }); - let execve_real: unsafe extern "C" fn(path: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> c_int = std::mem::transmute(REAL); - execve_real(path, argv, envp) - } else { - event::send_exec_event(uid, &program, &hexdigest, false); - *linux::errno_location() = libc::EACCES; - return -1 } } diff --git a/src/library/platforms/linux/hooks/execvp.rs b/src/library/platforms/linux/hooks/execvp.rs index 0c120e0..338a5a9 100644 --- a/src/library/platforms/linux/hooks/execvp.rs +++ b/src/library/platforms/linux/hooks/execvp.rs @@ -1,41 +1,17 @@ -use libc::{c_char, c_int}; -use std::ptr; -use crate::platforms::linux; -use crate::common::whitelist; -use crate::common::event; -use crate::common::hash; - +#[macro_use] /* int execvp(const char *file, char *const argv[]); */ -#[no_mangle] -pub unsafe extern "C" fn execvp(path: *const c_char, argv: *const *const c_char) -> c_int { - let envp: *const *const c_char = ptr::null(); - let program = linux::c_char_to_osstring(path); - let env = linux::parse_env_collection(envp); - let which_abs_pathbuf = match linux::search_path(&program) { - Some(prog_path) => prog_path, - None => { - *linux::errno_location() = libc::ENOENT; - return -1 } - }; - let abs_prog_str = which_abs_pathbuf.as_os_str(); - let hexdigest = hash::common_hash_file(abs_prog_str); - let uid = linux::get_current_uid(); - // Permit/deny execution - if whitelist::is_whitelisted(abs_prog_str, &env, &hexdigest) { - event::send_exec_event(uid, abs_prog_str, &hexdigest, true); - // Pass through - static mut REAL: *const u8 = 0 as *const u8; - static mut ONCE: ::std::sync::Once = ::std::sync::Once::new(); - ONCE.call_once(|| { - REAL = crate::platforms::linux::dlsym_next("execvp\u{0}"); - }); - let execvp_real: unsafe extern "C" fn(path: *const c_char, argv: *const *const c_char) -> c_int = std::mem::transmute(REAL); - execvp_real(path, argv) - } else { - event::send_exec_event(uid, abs_prog_str, &hexdigest, false); - *linux::errno_location() = libc::EACCES; - return -1 +build_exec_hook! { + hook execvp (program) { + // execvp custom routines + // Repopulate program + let absolute_path = match crate::platforms::linux::search_path(&program) { + Some(abspath) => abspath, + None => { + *crate::platforms::linux::errno_location() = libc::ENOENT; + return -1 } + }; + program = absolute_path.as_os_str().to_owned(); } } diff --git a/src/library/platforms/linux/hooks/execvpe.rs b/src/library/platforms/linux/hooks/execvpe.rs index 79037da..651bfa3 100644 --- a/src/library/platforms/linux/hooks/execvpe.rs +++ b/src/library/platforms/linux/hooks/execvpe.rs @@ -1,40 +1,18 @@ -use libc::{c_char, c_int}; -use crate::platforms::linux; -use crate::common::whitelist; -use crate::common::event; -use crate::common::hash; - +#[macro_use] /* int execvpe(const char *path, char *const argv[], char *const envp[]); */ -#[no_mangle] -pub unsafe extern "C" fn execvpe(path: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> c_int { - let program = linux::c_char_to_osstring(path); - let env = linux::parse_env_collection(envp); - let which_abs_pathbuf = match linux::search_path(&program) { - Some(prog_path) => prog_path, - None => { - *linux::errno_location() = libc::ENOENT; - return -1 } - }; - let abs_prog_str = which_abs_pathbuf.as_os_str(); - let hexdigest = hash::common_hash_file(abs_prog_str); - let uid = linux::get_current_uid(); - // Permit/deny execution - if whitelist::is_whitelisted(abs_prog_str, &env, &hexdigest) { - event::send_exec_event(uid, abs_prog_str, &hexdigest, true); - // Pass through - static mut REAL: *const u8 = 0 as *const u8; - static mut ONCE: ::std::sync::Once = ::std::sync::Once::new(); - ONCE.call_once(|| { - REAL = crate::platforms::linux::dlsym_next("execvpe\u{0}"); - }); - let execvpe_real: unsafe extern "C" fn(path: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> c_int = std::mem::transmute(REAL); - execvpe_real(path, argv, envp) - } else { - event::send_exec_event(uid, abs_prog_str, &hexdigest, false); - *linux::errno_location() = libc::EACCES; - return -1 +build_exec_hook! { + hook execvpe (program, envp) { + // execvpe custom routines + // Repopulate program + let absolute_path = match crate::platforms::linux::search_path(&program) { + Some(abspath) => abspath, + None => { + *crate::platforms::linux::errno_location() = libc::ENOENT; + return -1 } + }; + program = absolute_path.as_os_str().to_owned(); } } diff --git a/src/library/platforms/linux/hooks/template.rs b/src/library/platforms/linux/hooks/template.rs index 33754ad..0dfc154 100644 --- a/src/library/platforms/linux/hooks/template.rs +++ b/src/library/platforms/linux/hooks/template.rs @@ -1,21 +1,89 @@ #[macro_export] +// TODO: Reduce duplication of code +// TODO: Add generic hook, fexecve -// TODO: Exec hook template -/* +// Exec hook template macro_rules! build_exec_hook { // Parameters for the hook template - (hook fn $func_name:ident ( $($v:ident : $t:ty),* ) -> $return_type:ty $body:block) => { + (hook $func_name:ident ($program: ident) $body:block) => { // ===================================================================== // Generated code for the hook template #[no_mangle] - pub unsafe extern "C" fn $func_name ( $($v : $t),* ) -> $return_type { + #[allow(unused_mut)] + pub unsafe extern "C" fn $func_name (mut path: *const libc::c_char, argv: *const *const libc::c_char) -> libc::c_int { // Common hook code + let envp: *const *const libc::c_char = std::ptr::null(); + let mut $program = crate::platforms::linux::c_char_to_osstring(path); $body + let program_c_str = match crate::platforms::linux::osstr_to_cstring(&$program) { + Err(_why) => { + *crate::platforms::linux::errno_location() = libc::ENOENT; + return -1 }, + Ok(res) => res + }; + path = program_c_str.as_ptr() as *const libc::c_char; + let hexdigest = crate::common::hash::common_hash_file(&$program); + let env = crate::platforms::linux::parse_env_collection(envp); + let uid = crate::platforms::linux::get_current_uid(); + // Permit/deny execution + if crate::common::whitelist::is_whitelisted(&$program, &env, &hexdigest) { + crate::common::event::send_exec_event(uid, &$program, &hexdigest, true); + // Call execve + static mut REAL: *const u8 = 0 as *const u8; + static mut ONCE: ::std::sync::Once = ::std::sync::Once::new(); + ONCE.call_once(|| { + REAL = crate::platforms::linux::dlsym_next(concat!(stringify!($func_name), "\0")); + }); + let func_real: unsafe extern "C" fn(path: *const libc::c_char, argv: *const *const libc::c_char) -> libc::c_int = std::mem::transmute(REAL); + func_real(path, argv) + } else { + crate::common::event::send_exec_event(uid, &$program, &hexdigest, false); + *crate::platforms::linux::errno_location() = libc::EACCES; + return -1 + } + } + // ===================================================================== + }; + (hook $func_name:ident ($program: ident, $envp:ident) $body:block) => { + // ===================================================================== + // Generated code for the hook template + #[no_mangle] + #[allow(unused_assignments)] + #[allow(unused_mut)] + pub unsafe extern "C" fn $func_name (mut path: *const libc::c_char, argv: *const *const libc::c_char, $envp: *const *const libc::c_char) -> libc::c_int { + // Common hook code + let mut $program = crate::platforms::linux::c_char_to_osstring(path); + $body + let program_c_str = match crate::platforms::linux::osstr_to_cstring(&$program) { + Err(_why) => { + *crate::platforms::linux::errno_location() = libc::ENOENT; + return -1 }, + Ok(res) => res + }; + path = program_c_str.as_ptr() as *const libc::c_char; + let hexdigest = crate::common::hash::common_hash_file(&$program); + let env = crate::platforms::linux::parse_env_collection($envp); + let uid = crate::platforms::linux::get_current_uid(); + // Permit/deny execution + if crate::common::whitelist::is_whitelisted(&$program, &env, &hexdigest) { + crate::common::event::send_exec_event(uid, &$program, &hexdigest, true); + // Call execve + static mut REAL: *const u8 = 0 as *const u8; + static mut ONCE: ::std::sync::Once = ::std::sync::Once::new(); + ONCE.call_once(|| { + REAL = crate::platforms::linux::dlsym_next(concat!(stringify!($func_name), "\0")); + }); + let func_real: unsafe extern "C" fn(path: *const libc::c_char, argv: *const *const libc::c_char, envp: *const *const libc::c_char) -> libc::c_int = std::mem::transmute(REAL); + func_real(path, argv, $envp) + } else { + crate::common::event::send_exec_event(uid, &$program, &hexdigest, false); + *crate::platforms::linux::errno_location() = libc::EACCES; + return -1 + } } // ===================================================================== - } + }; } -*/ // Variadic exec hook template macro_rules! build_variadic_exec_hook { @@ -70,5 +138,5 @@ macro_rules! build_variadic_exec_hook { } } // ===================================================================== - } + }; }