Skip to content

Commit

Permalink
Enable build on other (non-Linux) Unix systems
Browse files Browse the repository at this point in the history
This is probably going to be useful mostly for development and
testing, not for production
  • Loading branch information
hillu committed Nov 29, 2023
1 parent 6558c6b commit 7e986e1
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 45 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ serde_json = { version = "1", features = ["preserve_order"] }
indexmap = { version = "2", features = ["serde"] }
toml = "0.5"
nix = "0.26"
caps = "0.5"
libc = "0.2"
exacl = ">= 0.6"
regex = "1"
Expand All @@ -35,6 +34,9 @@ log = "0.4"
simple_logger = ">= 1"
syslog = "6"

[target.'cfg(target_os = "linux")'.dependencies]
caps = "0.5"

[build-dependencies]
bindgen = ">= 0.60"

Expand Down
3 changes: 2 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {

fs::write(dest_path, buf)?;

// sockaddr
#[cfg(target_os = "linux")]
bindgen::Builder::default()
.header("src/sockaddr.h")
.rust_target(bindgen::RustTarget::Stable_1_47)
Expand All @@ -143,6 +143,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {

println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=const.rs.in");
#[cfg(target_os = "linux")]
println!("cargo:rerun-if-changed=src/sockaddr.h");
println!("cargo:rerun-if-changed={}", msg_file);
println!("cargo:rerun-if-changed={}", fields_file);
Expand Down
46 changes: 25 additions & 21 deletions src/bin/laurel/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
//! the Linux Audit daemon and reformats events as JSON lines.
use getopts::Options;
use std::collections::HashSet;
use std::env;
use std::error::Error;
use std::fs;
Expand All @@ -18,10 +17,12 @@ use std::sync::{
};
use std::time::{Duration, SystemTime};

use nix::unistd::{chown, execve, setresgid, setresuid, Uid, User};
use nix::unistd::{chown, execve, Uid, User};
#[cfg(target_os = "linux")]
use nix::unistd::{setresgid, setresuid};

use caps::securebits::set_keepcaps;
use caps::{CapSet, Capability};
#[cfg(target_os = "linux")]
use caps::{securebits::set_keepcaps, CapSet, Capability};

use serde::Serialize;

Expand Down Expand Up @@ -56,27 +57,26 @@ impl AddAssign for Stats {
/// - CAP_DAC_READ_SEARCH+CAP_SYS_PTRACE are required for accessing
/// environment variables from arbitrary processes
/// (/proc/$PID/environ).
#[cfg(target_os = "linux")]
fn drop_privileges(runas_user: &User) -> Result<(), Box<dyn Error>> {
set_keepcaps(true)?;

let uid = runas_user.uid;
let gid = runas_user.gid;

setresgid(gid, gid, gid).map_err(|e| format!("setresgid({}): {}", gid, e))?;
setresuid(uid, uid, uid).map_err(|e| format!("setresuid({}): {}", uid, e))?;

let mut capabilities = HashSet::new();
#[cfg(feature = "procfs")]
{
let mut capabilities = std::collections::HashSet::new();
capabilities.insert(Capability::CAP_SYS_PTRACE);
capabilities.insert(Capability::CAP_DAC_READ_SEARCH);
caps::set(None, CapSet::Permitted, &capabilities)
.map_err(|e| format!("set permitted capabilities: {}", e))?;
caps::set(None, CapSet::Effective, &capabilities)
.map_err(|e| format!("set effective capabilities: {}", e))?;
caps::set(None, CapSet::Inheritable, &capabilities)
.map_err(|e| format!("set inheritable capabilities: {}", e))?;
}
caps::set(None, CapSet::Permitted, &capabilities)
.map_err(|e| format!("set permitted capabilities: {}", e))?;
caps::set(None, CapSet::Effective, &capabilities)
.map_err(|e| format!("set effective capabilities: {}", e))?;
caps::set(None, CapSet::Inheritable, &capabilities)
.map_err(|e| format!("set inheritable capabilities: {}", e))?;

set_keepcaps(false)?;
Ok(())
Expand Down Expand Up @@ -270,10 +270,11 @@ fn run_app() -> Result<(), Box<dyn Error>> {
log::warn!("Not dropping privileges -- not running as root");
} else if runas_user.uid.is_root() {
log::warn!("Not dropping privileges -- no user configured");
} else if let Err(e) = drop_privileges(&runas_user) {
// Logged to syslog by caller
return Err(e);
} else {
#[cfg(target_os = "linux")]
drop_privileges(&runas_user)?;
}
#[cfg(target_os = "linux")]
if let Err(e) = caps::clear(None, CapSet::Ambient) {
log::warn!("could not set ambient capabilities: {}", e);
}
Expand Down Expand Up @@ -359,11 +360,14 @@ fn run_app() -> Result<(), Box<dyn Error>> {
.map(|(k, v)| CString::new(format!("{}={}", k, v)).unwrap())
.collect();

let mut capabilities = HashSet::new();
capabilities.insert(Capability::CAP_SYS_PTRACE);
capabilities.insert(Capability::CAP_DAC_READ_SEARCH);
if let Err(e) = caps::set(None, CapSet::Ambient, &capabilities) {
log::warn!("could not set ambient capabilities: {}", e);
#[cfg(target_os = "linux")]
{
let mut capabilities = std::collections::HashSet::new();
capabilities.insert(Capability::CAP_SYS_PTRACE);
capabilities.insert(Capability::CAP_DAC_READ_SEARCH);
if let Err(e) = caps::set(None, CapSet::Ambient, &capabilities) {
log::warn!("could not set ambient capabilities: {}", e);
}
}
execve(&argv[0], &argv, &env)?;
}
Expand Down
34 changes: 23 additions & 11 deletions src/coalesce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ use crate::constants::{msg_type::*, ARCH_NAMES, SYSCALL_NAMES};
use crate::label_matcher::LabelMatcher;
use crate::parser::parse;
use crate::proc::{ContainerInfo, ProcTable, Process, ProcessKey};
#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
use crate::procfs;
#[cfg(target_os = "linux")]
use crate::sockaddr::SocketAddr;
use crate::types::*;
use crate::userdb::UserDB;
Expand Down Expand Up @@ -97,6 +98,7 @@ const EXPIRE_DONE_TIMEOUT: u64 = 120_000;

/// generate translation of SocketAddr enum to a format similar to
/// what auditd log_format=ENRICHED produces
#[cfg(target_os = "linux")]
fn translate_socketaddr(rv: &mut Record, sa: SocketAddr) -> Value {
let f = SimpleKey::Literal("saddr_fam");
let m = match sa {
Expand Down Expand Up @@ -245,7 +247,7 @@ fn translate_socketaddr(rv: &mut Record, sa: SocketAddr) -> Value {
///
/// As an extra sanity check, exe is compared with normalized
/// PATH.name. If they are equal, no script is returned.
#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
fn path_script_name(path: &Record, pid: u32, cwd: &[u8], exe: &[u8]) -> Option<NVec> {
use std::{
ffi::OsStr,
Expand Down Expand Up @@ -587,7 +589,7 @@ impl<'a> Coalesce<'a> {
proc.key = pr.key;
proc.parent = pr.parent;
proc.labels = pr.labels.clone();
#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
{
proc.container_info = pr.container_info.clone();
}
Expand All @@ -606,7 +608,7 @@ impl<'a> Coalesce<'a> {
.cloned();
proc.labels.extend(propagated_labels);
}
#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
if self.settings.enrich_container {
if let Ok(Some(id)) = procfs::parse_proc_pid_cgroup(proc.pid) {
proc.container_info = Some(ContainerInfo { id });
Expand Down Expand Up @@ -725,7 +727,7 @@ impl<'a> Coalesce<'a> {
}

// ENV
#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
if let (Some(proc), false) = (&current_process, self.settings.execve_env.is_empty()) {
if let Ok(vars) =
procfs::get_environ(proc.pid, |k| self.settings.execve_env.contains(k))
Expand All @@ -742,7 +744,7 @@ impl<'a> Coalesce<'a> {
}

// Handle script enrichment
#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
let script: Option<NVec> = match (self.settings.enrich_script, self.settings.label_script) {
(false, None) => None,
_ => match (&current_process, ev.body.get(&PATH), syscall_is_exec) {
Expand All @@ -766,7 +768,7 @@ impl<'a> Coalesce<'a> {
},
};

#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
if let (Some(ref mut proc), Some(script)) = (&mut current_process, &script) {
if let Some(label_script) = self.settings.label_script {
for label in label_script.matches(script.as_ref()) {
Expand Down Expand Up @@ -803,6 +805,7 @@ impl<'a> Coalesce<'a> {
if let (Key::Name(name), Value::Str(vr, _)) = (k, v) {
match name.as_ref() {
b"saddr" if self.settings.translate_universal => {
#[cfg(target_os = "linux")]
if let Ok(sa) = SocketAddr::parse(&rv.raw[vr.clone()]) {
let kv = (
Key::Literal("SADDR"),
Expand Down Expand Up @@ -936,7 +939,7 @@ impl<'a> Coalesce<'a> {
sc.elems.push((Key::Literal("PPID"), Value::Map(m)));
}

#[cfg(featuree = "procfs")]
#[cfg(all(featuree = "procfs", target_os = "linux"))]
if let (true, Some(script)) = (self.settings.enrich_script, script) {
let (k, v) = (
Key::Literal("SCRIPT"),
Expand Down Expand Up @@ -970,7 +973,7 @@ impl<'a> Coalesce<'a> {
sc.elems.push((Key::Literal("LABELS"), Value::List(labels)));
}

#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
if let (true, Some(c)) = (self.settings.enrich_container, &proc.container_info) {
let mut ci = Record::default();
let r = ci.put(&c.id);
Expand Down Expand Up @@ -1219,14 +1222,18 @@ mod test {
&mut c,
strip_enriched(include_bytes!("testdata/record-execve.txt")),
)?;
let gid0name = nix::unistd::Group::from_gid(0.into())
.unwrap()
.unwrap()
.name;
let output = event_to_json(ec.borrow().last().unwrap());
println!("{}", output);
assert!(
output.contains(r#""UID":"root","#),
"output contains translated UID"
);
assert!(
output.contains(r#""EGID":"root","#),
output.contains(&format!(r#""EGID":"{gid0name}","#)),
"output contains translated EGID"
);
assert!(
Expand Down Expand Up @@ -1277,6 +1284,11 @@ mod test {
fn translate_uids() {
let ec = Rc::new(RefCell::new(None));

let gid0name = nix::unistd::Group::from_gid(0.into())
.unwrap()
.unwrap()
.name;

let mut c = Coalesce::new(|e: &Event| *ec.borrow_mut() = Some(e.clone()));
c.settings.translate_userdb = true;
c.settings.translate_universal = true;
Expand All @@ -1296,7 +1308,7 @@ mod test {
}
if k.to_string().ends_with("GID") {
gids += 1;
assert!(&v == "root", "Got {}={:?}, expected root", k, v);
assert!(&v == gid0name.as_str(), "Got {}={:?}, expected root", k, v);
}
}
assert!(
Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ pub mod label_matcher;
pub mod logger;
pub mod parser;
pub mod proc;
#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
pub mod procfs;
pub mod quoted_string;
pub mod rotate;
#[cfg(target_os = "linux")]
pub mod sockaddr;
pub mod types;
pub mod userdb;
18 changes: 9 additions & 9 deletions src/proc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use serde::{Serialize, Serializer};
use crate::label_matcher::LabelMatcher;
use crate::types::EventID;

#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
use crate::procfs;

#[derive(Clone, Debug, Default)]
Expand Down Expand Up @@ -104,11 +104,11 @@ pub struct Process {
pub comm: Option<Vec<u8>>,
/// Labels assigned to process
pub labels: HashSet<Vec<u8>>,
#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
pub container_info: Option<ContainerInfo>,
}

#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
impl From<procfs::ProcPidInfo> for Process {
fn from(p: procfs::ProcPidInfo) -> Self {
Self {
Expand All @@ -129,7 +129,7 @@ impl From<procfs::ProcPidInfo> for Process {

impl Process {
/// Generate a shadow process table entry from /proc/$PID for a given PID
#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
pub fn parse_proc(pid: u32) -> Result<Process, Box<dyn Error>> {
procfs::parse_proc_pid(pid).map(|p| p.into())
}
Expand Down Expand Up @@ -159,7 +159,7 @@ impl ProcTable {
current: BTreeMap::new(),
};

#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
{
for pid in procfs::get_pids()? {
// /proc/<pid> access is racy. Ignore errors here.
Expand Down Expand Up @@ -211,7 +211,7 @@ impl ProcTable {
/// shadow process table, an attempt is made to fetch the
/// information from another source, i.e. /proc.
pub fn get_or_retrieve(&mut self, pid: u32) -> Option<&Process> {
#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
if self.get_pid(pid).is_none() {
self.insert_from_procfs(pid);
}
Expand All @@ -220,7 +220,7 @@ impl ProcTable {

/// Fetch process information from procfs, insert into shadow
/// process table.
#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
pub fn insert_from_procfs(&mut self, pid: u32) -> Option<&Process> {
if let Ok(p) = Process::parse_proc(pid) {
let key = p.key;
Expand All @@ -236,7 +236,7 @@ impl ProcTable {
///
/// It should be possible to run this every few seconds without
/// incurring load.
#[cfg(feature = "procfs")]
#[cfg(all(feature = "procfs", target_os = "linux"))]
pub fn expire(&mut self) {
use std::collections::BTreeSet;

Expand Down Expand Up @@ -288,7 +288,7 @@ impl ProcTable {

/// No expire mechanism has been implemented for the case where
/// there's no procfs support.
#[cfg(not(feature = "procfs"))]
#[cfg(not(all(feature = "procfs", target_os = "linux")))]
pub fn expire(&self) {}

pub fn set_labels(&mut self, key: &ProcessKey, labels: &HashSet<Vec<u8>>) {
Expand Down
1 change: 1 addition & 0 deletions src/rotate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ impl FileRotate {
let mut acl = vec![
AclEntry::allow_user("", Perm::from_bits_truncate(6), None),
AclEntry::allow_group("", Perm::from_bits_truncate(4), None),
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
AclEntry::allow_other(Perm::empty(), None),
];
for uid in &self.uids {
Expand Down
2 changes: 1 addition & 1 deletion src/userdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub struct UserDB {
}

fn now() -> i64 {
unsafe { libc::time(std::ptr::null_mut()) }
unsafe { libc::time(std::ptr::null_mut()) }
}

impl UserDB {
Expand Down

0 comments on commit 7e986e1

Please sign in to comment.