use crate::components;
use crate::error::Result;
pub struct Config {
anti_tracing: bool,
fs: Fs,
unstable: Unstable,
win_dacl: WinDacl,
}
impl Default for Config {
fn default() -> Self {
Self::DEFAULT
}
}
impl Config {
pub const DEFAULT: Self = Self {
anti_tracing: true,
fs: Fs::DEFAULT,
unstable: Unstable::DEFAULT,
win_dacl: WinDacl::DEFAULT,
};
#[must_use]
pub const fn new_with_anti_tracing(anti_tracing: bool) -> Self {
Self {
anti_tracing,
fs: Fs::DEFAULT,
unstable: Unstable::DEFAULT,
win_dacl: WinDacl::DEFAULT,
}
}
pub fn set_anti_tracing(&mut self, b: bool) {
self.anti_tracing = b;
}
pub fn set_fs(&mut self, b: bool) {
self.fs = match b {
true => Fs::TRUE,
false => Fs::FALSE,
};
}
pub fn fs_mut(&mut self) -> &mut Fs {
&mut self.fs
}
pub fn set_fs_procfs(&mut self, b: bool) {
self.fs.set_procfs(b);
}
pub fn set_unstable(&mut self, b: bool) {
self.unstable = match b {
true => Unstable::TRUE,
false => Unstable::FALSE,
};
}
pub fn unstable_mut(&mut self) -> &mut Unstable {
&mut self.unstable
}
pub fn set_unstable_win_ntapi(&mut self, b: bool) {
self.unstable.set_win_ntapi(b);
}
pub fn set_unstable_win_kernelmem(&mut self, b: bool) {
self.unstable.set_win_kernelmem(b);
}
pub fn set_win_dacl(&mut self, dacl: WinDacl) {
self.win_dacl = dacl;
}
pub fn set_win_dacl_default(&mut self) {
self.set_win_dacl(WinDacl::Default);
}
pub fn set_win_dacl_empty(&mut self) {
self.set_win_dacl(WinDacl::Empty);
}
pub fn set_win_dacl_custom_user_perm(&mut self, access: WinDaclProcessAccess) {
self.set_win_dacl(WinDacl::CustomUserPerm(access));
}
pub fn set_win_dacl_custom_fn(&mut self, fnptr: fn() -> Result) {
self.set_win_dacl(WinDacl::CustomFn(fnptr));
}
pub fn harden_process(self) -> Result {
{
if self.unstable.has_win_ntapi() {
#[cfg(all(windows, feature = "unstable"))]
components::hide_thread_from_debugger_ntapi()?;
}
}
{
#[cfg(windows)]
self.win_dacl.call()?;
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))]
components::disable_tracing_prctl()?;
#[cfg(unix)]
components::disable_core_dumps_rlimit()?;
}
if self.anti_tracing {
#[cfg(windows)]
components::check_tracer_winapi()?;
if self.unstable.has_win_kernelmem() {
#[cfg(all(windows, feature = "unstable"))]
components::check_tracer_unstable()?;
}
if self.fs.has_procfs() {
#[cfg(all(target_os = "linux", feature = "std"))]
components::check_tracer_procfs()?;
}
#[cfg(target_os = "freebsd")]
components::check_tracer_prctl()?;
}
Ok(())
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Fs {
procfs: bool,
}
impl Default for Fs {
fn default() -> Self {
Self::DEFAULT
}
}
impl Fs {
pub const DEFAULT: Self = Self::TRUE;
pub const FALSE: Self = Self { procfs: false };
pub const TRUE: Self = Self { procfs: true };
pub fn set_procfs(&mut self, b: bool) {
self.procfs = b;
}
const fn has_procfs(&self) -> bool {
self.procfs
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Unstable {
win_ntapi: bool,
win_kernelmem: bool,
}
impl Default for Unstable {
fn default() -> Self {
Self::DEFAULT
}
}
impl Unstable {
pub const DEFAULT: Self = Self::FALSE;
pub const FALSE: Self = Self {
win_ntapi: false,
win_kernelmem: false,
};
pub const TRUE: Self = Self {
win_ntapi: true,
win_kernelmem: true,
};
pub fn set_win_ntapi(&mut self, b: bool) {
self.win_ntapi = b;
}
pub fn set_win_kernelmem(&mut self, b: bool) {
self.win_kernelmem = b;
}
const fn has_win_ntapi(&self) -> bool {
self.win_ntapi
}
const fn has_win_kernelmem(&self) -> bool {
self.win_kernelmem
}
}
pub enum WinDacl {
Empty,
Default,
CustomUserPerm(WinDaclProcessAccess),
False,
CustomFn(fn() -> Result),
}
#[derive(Debug, Clone, Copy)]
pub struct WinDaclProcessAccess(u32);
impl core::ops::BitOr for WinDaclProcessAccess {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl core::ops::BitAnd for WinDaclProcessAccess {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
Self(self.0 & rhs.0)
}
}
impl core::ops::BitOrAssign for WinDaclProcessAccess {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
impl core::ops::BitAndAssign for WinDaclProcessAccess {
fn bitand_assign(&mut self, rhs: Self) {
self.0 &= rhs.0;
}
}
#[cfg(windows)]
impl From<WinDaclProcessAccess> for windows::Win32::System::Threading::PROCESS_ACCESS_RIGHTS {
fn from(access: WinDaclProcessAccess) -> Self {
Self(access.0)
}
}
#[cfg(windows)]
impl From<&WinDaclProcessAccess> for windows::Win32::System::Threading::PROCESS_ACCESS_RIGHTS {
fn from(access: &WinDaclProcessAccess) -> Self {
Self(access.0)
}
}
#[cfg(windows)]
impl WinDaclProcessAccess {
pub const ALL_ACCESS: Self = Self::new(windows::Win32::System::Threading::PROCESS_ALL_ACCESS);
pub const CREATE_PROCESS: Self =
Self::new(windows::Win32::System::Threading::PROCESS_CREATE_PROCESS);
pub const CREATE_THREAD: Self =
Self::new(windows::Win32::System::Threading::PROCESS_CREATE_THREAD);
pub const DELETE: Self = Self::new(windows::Win32::System::Threading::PROCESS_DELETE);
pub const DUP_HANDLE: Self = Self::new(windows::Win32::System::Threading::PROCESS_DUP_HANDLE);
pub const QUERY_INFORMATION: Self =
Self::new(windows::Win32::System::Threading::PROCESS_QUERY_INFORMATION);
pub const QUERY_LIMITED_INFORMATION: Self =
Self::new(windows::Win32::System::Threading::PROCESS_QUERY_LIMITED_INFORMATION);
pub const READ_CONTROL: Self =
Self::new(windows::Win32::System::Threading::PROCESS_READ_CONTROL);
pub const SET_INFORMATION: Self =
Self::new(windows::Win32::System::Threading::PROCESS_SET_INFORMATION);
pub const SET_QUOTA: Self = Self::new(windows::Win32::System::Threading::PROCESS_SET_QUOTA);
pub const SUSPEND_RESUME: Self =
Self::new(windows::Win32::System::Threading::PROCESS_SUSPEND_RESUME);
pub const SYNCHRONIZE: Self = Self::new(windows::Win32::System::Threading::PROCESS_SYNCHRONIZE);
pub const TERMINATE: Self = Self::new(windows::Win32::System::Threading::PROCESS_TERMINATE);
pub const VM_OPERATION: Self =
Self::new(windows::Win32::System::Threading::PROCESS_VM_OPERATION);
pub const VM_READ: Self = Self::new(windows::Win32::System::Threading::PROCESS_VM_READ);
pub const VM_WRITE: Self = Self::new(windows::Win32::System::Threading::PROCESS_VM_WRITE);
pub const WRITE_DAC: Self = Self::new(windows::Win32::System::Threading::PROCESS_WRITE_DAC);
pub const WRITE_OWNER: Self = Self::new(windows::Win32::System::Threading::PROCESS_WRITE_OWNER);
const fn new(access: windows::Win32::System::Threading::PROCESS_ACCESS_RIGHTS) -> Self {
Self(access.0)
}
}
#[cfg(not(windows))]
impl WinDaclProcessAccess {
pub const ALL_ACCESS: Self = Self(0);
pub const CREATE_PROCESS: Self = Self(0);
pub const CREATE_THREAD: Self = Self(0);
pub const DELETE: Self = Self(0);
pub const DUP_HANDLE: Self = Self(0);
pub const QUERY_INFORMATION: Self = Self(0);
pub const QUERY_LIMITED_INFORMATION: Self = Self(0);
pub const READ_CONTROL: Self = Self(0);
pub const SET_INFORMATION: Self = Self(0);
pub const SET_QUOTA: Self = Self(0);
pub const SUSPEND_RESUME: Self = Self(0);
pub const SYNCHRONIZE: Self = Self(0);
pub const TERMINATE: Self = Self(0);
pub const VM_OPERATION: Self = Self(0);
pub const VM_READ: Self = Self(0);
pub const VM_WRITE: Self = Self(0);
pub const WRITE_DAC: Self = Self(0);
pub const WRITE_OWNER: Self = Self(0);
}
impl Default for WinDacl {
fn default() -> Self {
Self::DEFAULT
}
}
impl WinDacl {
pub const DEFAULT: Self = Self::Default;
pub fn call(&self) -> Result {
#[cfg(windows)]
return match self {
Self::Empty => components::set_empty_dacl_winapi(),
Self::Default => components::set_default_dacl_winapi(),
Self::CustomUserPerm(access) => components::set_custom_dacl_winapi(access.into()),
Self::False => Ok(()),
Self::CustomFn(f) => f(),
};
#[cfg(not(windows))]
Ok(())
}
}