Skip to content

Commit

Permalink
Tool enhancements (#1059)
Browse files Browse the repository at this point in the history
A handful of improvements to the tools consolidated from other branches.

- rulec exit code representative of clean or dirty rules
- profiler improved output modes to command line
- improved dpkg loading in tdb
- man pages for cli

Closes #1041
  • Loading branch information
jw3 authored Dec 31, 2024
1 parent 1baaf50 commit 6f8868e
Show file tree
Hide file tree
Showing 13 changed files with 307 additions and 98 deletions.
73 changes: 71 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 10 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ RED=\033[0;31m
NC=\033[0m # No Color

VERSION ?= $(shell sed -n 's/^Version: *//p' fapolicy-analyzer.spec)
FID ?= rawhide
fc ?= rawhide
el ?= 9

# List the common developer targets
list:
Expand Down Expand Up @@ -142,17 +143,17 @@ build-info:

# Generate Fedora rawhide rpms
fc-rpm:
@echo -e "${GRN}--- Fedora $(FID) RPM generation v${VERSION}...${NC}"
@echo -e "${GRN}--- Fedora $(fc) RPM generation v${VERSION}...${NC}"
make -f .copr/Makefile vendor OS_ID=fedora VERSION=${VERSION}
podman build -t fapolicy-analyzer:build --target fedorabuild --build-arg version=${VERSION} -f Containerfile .
podman run --privileged --rm -it -v /tmp:/v fapolicy-analyzer:build fedora-$(FID)-x86_64 /v
podman build -t fapolicy-analyzer:build-fc$(fc) --target fedorabuild --build-arg version=${VERSION} -f Containerfile .
podman run --privileged --rm -it -v /tmp:/v fapolicy-analyzer:build-fc$(fc) fedora-$(fc)-x86_64 /v

# Generate RHEL 9 rpms
el9-rpm:
@echo -e "${GRN}--- el9 RPM generation v${VERSION}...${NC}"
make -f .copr/Makefile vendor vendor-rs OS_ID=rhel VERSION=${VERSION} DIST=.el9 spec=scripts/srpm/fapolicy-analyzer.el9.spec
podman build -t fapolicy-analyzer:build --target elbuild --build-arg version=${VERSION} --build-arg spec=scripts/srpm/fapolicy-analyzer.el9.spec -f Containerfile .
podman run --privileged --rm -it -v /tmp:/v fapolicy-analyzer:build rocky+epel-9-x86_64 /v
el-rpm:
@echo -e "${GRN}--- el$(el) RPM generation v${VERSION}...${NC}"
make -f .copr/Makefile vendor vendor-rs OS_ID=rhel VERSION=${VERSION} DIST=.el$(el) spec=scripts/srpm/fapolicy-analyzer.el$(el).spec
podman build -t fapolicy-analyzer:build-el$(el) --target elbuild --build-arg version=${VERSION} --build-arg spec=scripts/srpm/fapolicy-analyzer.el$(el).spec -f Containerfile .
podman run --privileged --rm -it -v /tmp:/v fapolicy-analyzer:build-el$(el) rocky+epel-$(el)-x86_64 /v

# Update embedded help documentation
help-docs:
Expand Down
3 changes: 3 additions & 0 deletions crates/daemon/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,7 @@ pub enum Error {

#[error("failed to parse stat entry: {0}")]
ParseStatsError(String),

#[error("the profiler is already active")]
ProfilerAlreadyActive,
}
90 changes: 50 additions & 40 deletions crates/daemon/src/profiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ use fapolicy_rules::db::DB;
use fapolicy_rules::write;

use crate::error::Error;
use crate::error::Error::ProfilerAlreadyActive;
use crate::fapolicyd::{Daemon, COMPILED_RULES_PATH};
use crate::svc::State;
use crate::svc::{wait_for_service, State};
use crate::{fapolicyd, svc};

const PROFILER_NAME: &str = "fapolicyp";
Expand Down Expand Up @@ -48,49 +49,59 @@ impl Profiler {
self.fapolicyp.active()
}

pub fn activate(&mut self) -> Result<State, Error> {
pub fn activate(&mut self) -> Result<PathBuf, Error> {
self.activate_with_rules(None)
}

pub fn activate_with_rules(&mut self, db: Option<&DB>) -> Result<State, Error> {
pub fn activate_with_rules(&mut self, db: Option<&DB>) -> Result<PathBuf, Error> {
let fapolicyd = svc::Handle::default();
if !self.is_active() {
// 1. preserve fapolicyd daemon state
self.prev_state = Some(fapolicyd.state()?);
// 2. stop fapolicyd daemon if running
if let Some(State::Active) = self.prev_state {
// todo;; probably need to ensure its not in
// a state like restart, init or some such
fapolicyd.stop()?
}
// 3. swap the rules file if necessary
if let Some(db) = db {
// compiled.rules is always at the default location
let compiled = PathBuf::from(COMPILED_RULES_PATH);
// create a temp file as the backup location
let backup = NamedTempFile::new()?;
// move original compiled to backup location
fs::rename(&compiled, &backup).or_else(|x| {
log::debug!("rename fallback copy");
fs::copy(&compiled, &backup)
.and_then(|_| fs::remove_file(&compiled))
.or(Err(x))
})?;
// write compiled rules for the profiling run
write::compiled_rules(db, &compiled)?;
log::debug!("rules backed up to {:?}", backup.path());
self.prev_rules = Some(backup);
}
// 5. start the profiler daemon
self.fapolicyp.start(self.events_log.as_ref())?;
// 6. wait for the profiler daemon to become active
if let Some(log) = self.events_log.as_ref() {
if fapolicyd::wait_until_ready(log).is_err() {
log::warn!("wait_until_ready failed");
};
}
if self.is_active() {
return Err(ProfilerAlreadyActive);
}
fapolicyd.state()

// 1. preserve fapolicyd daemon state
self.prev_state = Some(fapolicyd.state()?);
// 2. stop fapolicyd daemon if running
if let Some(State::Active) = self.prev_state {
// todo;; probably need to ensure its not in
// a state like restart, init or some such
fapolicyd.stop()?;
wait_for_service(&fapolicyd, State::Inactive, 10)?;
}
// 3. swap the rules file if necessary
if let Some(db) = db {
// compiled.rules is always at the default location
let compiled = PathBuf::from(COMPILED_RULES_PATH);
// create a temp file as the backup location
let backup = NamedTempFile::new()?;
// move original compiled to backup location
fs::rename(&compiled, &backup).or_else(|x| {
log::debug!("rename fallback copy");
fs::copy(&compiled, &backup)
.and_then(|_| fs::remove_file(&compiled))
.or(Err(x))
})?;
// write compiled rules for the profiling run
write::compiled_rules(db, &compiled)?;
log::debug!("rules backed up to {:?}", backup.path());
self.prev_rules = Some(backup);
}
// 5. resolve the output file
let outfile = match &self.events_log {
Some(p) => p.clone(),
None => NamedTempFile::new()?.into_temp_path().to_path_buf(),
};
log::debug!("events-file: {}", outfile.display());

// 6. start the profiler daemon
self.fapolicyp.start(Some(&outfile))?;

// 7. wait for the profiler daemon to become active
if fapolicyd::wait_until_ready(&outfile).is_err() {
log::warn!("wait_until_ready failed");
};

Ok(outfile)
}

pub fn deactivate(&mut self) -> Result<State, Error> {
Expand All @@ -107,7 +118,6 @@ impl Profiler {
}
// 4. start fapolicyd daemon if it was previously active
if let Some(State::Active) = self.prev_state {
log::debug!("restarting daemon");
fapolicyd.start()?;
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/tools/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ path = "src/rule_check.rs"
clap = { version = "3.2.20", features = ["derive"] }
lmdb = "0.8"
nom = "7.1"
rayon = "1.5"
thiserror = "1.0"
log = "0.4"
ariadne = { version = "0.4", optional = true }
human-panic = "2.0"
env_logger = "0.11"
strip-ansi-escapes = "0.2"

fapolicy-analyzer = { path = "../analyzer" }
fapolicy-app = { path = "../app" }
fapolicy-daemon = { path = "../daemon" }
fapolicy-rules = { path = "../rules" }
Expand Down
Loading

0 comments on commit 6f8868e

Please sign in to comment.