-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds a test exercising the agent functionality. This works by spawning the agent to monitor the test executable itself, where crypto-auditing probes are defined. Signed-off-by: Daiki Ueno <[email protected]>
- Loading branch information
Showing
12 changed files
with
431 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[target.x86_64-unknown-linux-gnu] | ||
runner = "sudo -E" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# library = ["/usr/lib64/libgnutls.so.30", "/usr/lib64/libssl.so.3"] | ||
# log_file = "/var/log/crypto-auditing/audit.cborseq" | ||
# user = "crypto-auditing:crypto-auditing" | ||
# coalesce_window = 100 | ||
# max_events = 1000000 | ||
|
||
coalesce_window = 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
[package] | ||
name = "agenttest" | ||
version = "0.1.0" | ||
edition = "2021" | ||
license = "GPL-3.0-or-later" | ||
authors = ["The crypto-auditing developers"] | ||
|
||
[dependencies] | ||
anyhow = "1.0" | ||
libbpf-rs = { version = "0.20", features = ["novendor"] } | ||
libc = "0.2" | ||
nix = "0.26" | ||
tempfile = "3" | ||
plain = "0.2" | ||
|
||
[build-dependencies] | ||
libbpf-cargo = { version = "0.20", features = ["novendor"] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
|
||
use libbpf_cargo::SkeletonBuilder; | ||
use std::{env, path::PathBuf}; | ||
|
||
const SRC: &str = "src/bpf/agent.bpf.c"; | ||
|
||
fn main() { | ||
let mut out = | ||
PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR must be set in build script")); | ||
out.push("agent.skel.rs"); | ||
SkeletonBuilder::new() | ||
.source(SRC) | ||
.build_and_generate(&out) | ||
.unwrap(); | ||
println!("cargo:rerun-if-changed={}", SRC); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* SPDX-License-Identifier: GPL-2.0 */ | ||
|
||
#include "vmlinux.h" | ||
#include <bpf/usdt.bpf.h> | ||
|
||
#define MAX_DATA_SIZE 512 | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_RINGBUF); | ||
__uint(max_entries, 4096 /* one page */); | ||
} ringbuf SEC(".maps"); | ||
|
||
SEC("usdt") | ||
int | ||
BPF_USDT(event_group, long count) | ||
{ | ||
long *value; | ||
long err; | ||
|
||
value = bpf_ringbuf_reserve (&ringbuf, sizeof(*value), 0); | ||
if (value) | ||
{ | ||
*value = count; | ||
bpf_ringbuf_submit (value, 0); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
char LICENSE[] SEC("license") = "GPL"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../../../src/bpf/vmlinux.h |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
// Copyright (C) 2023 The crypto-auditing developers. | ||
|
||
use anyhow::{bail, Result}; | ||
use libbpf_rs::{Link, Map, Object, RingBufferBuilder}; | ||
use std::env; | ||
use std::path::{Path, PathBuf}; | ||
use std::process::Child; | ||
use std::time::Duration; | ||
|
||
mod skel { | ||
include!(concat!(env!("OUT_DIR"), "/agent.skel.rs")); | ||
} | ||
use skel::*; | ||
|
||
pub fn target_dir() -> PathBuf { | ||
env::current_exe() | ||
.ok() | ||
.map(|mut path| { | ||
path.pop(); | ||
if path.ends_with("deps") { | ||
path.pop(); | ||
} | ||
path | ||
}) | ||
.unwrap() | ||
} | ||
|
||
pub fn agent_path() -> PathBuf { | ||
target_dir().join("crypto-auditing-agent") | ||
} | ||
|
||
pub fn bump_memlock_rlimit() -> Result<()> { | ||
let rlimit = libc::rlimit { | ||
rlim_cur: 128 << 20, | ||
rlim_max: 128 << 20, | ||
}; | ||
|
||
if unsafe { libc::setrlimit(libc::RLIMIT_MEMLOCK, &rlimit) } != 0 { | ||
bail!("Failed to increase rlimit"); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn attach_bpf(process: &Child, path: impl AsRef<Path>) -> Result<(Link, Object)> { | ||
let skel_builder = AgentSkelBuilder::default(); | ||
let open_skel = skel_builder.open()?; | ||
let mut skel = open_skel.load()?; | ||
|
||
let mut progs = skel.progs_mut(); | ||
let prog = progs.event_group(); | ||
|
||
let link = prog | ||
.attach_usdt( | ||
process.id() as i32, | ||
path.as_ref(), | ||
"crypto_auditing_internal_agent", | ||
"event_group", | ||
) | ||
.expect("unable to attach prog"); | ||
|
||
Ok((link, skel.obj)) | ||
} | ||
|
||
// Copied from libbpf-rs/libbpf-rs/tests/test.rs | ||
pub fn with_ringbuffer<F>(map: &Map, action: F, timeout: Duration) -> Result<i64> | ||
where | ||
F: FnOnce(), | ||
{ | ||
let mut value = 0i64; | ||
{ | ||
let callback = |data: &[u8]| { | ||
plain::copy_from_bytes(&mut value, data).expect("Wrong size"); | ||
0 | ||
}; | ||
|
||
let mut builder = RingBufferBuilder::new(); | ||
builder.add(map, callback)?; | ||
let mgr = builder.build()?; | ||
|
||
action(); | ||
mgr.poll(timeout)?; | ||
mgr.consume()?; | ||
} | ||
|
||
Ok(value) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
// Copyright (C) 2023 The crypto-auditing developers. | ||
|
||
extern crate agenttest; | ||
use agenttest::*; | ||
|
||
use crypto_auditing::types::EventGroup; | ||
use probe::probe; | ||
use serde_cbor::de::Deserializer; | ||
use std::env; | ||
use std::panic; | ||
use std::path::PathBuf; | ||
use std::process::Command; | ||
use std::thread; | ||
use std::time::Duration; | ||
use tempfile::tempdir; | ||
|
||
fn fixture_dir() -> PathBuf { | ||
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("fixtures") | ||
} | ||
|
||
#[test] | ||
fn test_probe_coalesce() { | ||
bump_memlock_rlimit().expect("unable to bump memlock rlimit"); | ||
|
||
let agent_path = agent_path(); | ||
let log_dir = tempdir().expect("unable to create temporary directory"); | ||
let log_path = log_dir.path().join("agent.log"); | ||
let mut process = Command::new(&agent_path) | ||
.arg("-c") | ||
.arg(fixture_dir().join("agent.conf")) | ||
.arg("--log-file") | ||
.arg(&log_path) | ||
.arg("--library") | ||
.arg(&env::current_exe().unwrap()) | ||
.arg("--coalesce-window") | ||
.arg("1000") | ||
.spawn() | ||
.expect("unable to spawn agent"); | ||
|
||
// Wait until the agent process starts up | ||
while !log_path.exists() { | ||
thread::sleep(Duration::from_millis(100)); | ||
} | ||
|
||
let result = panic::catch_unwind(|| { | ||
let foo = String::from("foo\0"); | ||
let bar = String::from("bar\0"); | ||
let baz = String::from("baz\0"); | ||
|
||
let (_link, object) = | ||
attach_bpf(&process, &agent_path).expect("unable to attach agent.bpf.o"); | ||
let map = object.map("ringbuf").expect("unable to get ringbuf map"); | ||
|
||
let timeout = Duration::from_secs(10); | ||
|
||
let result = with_ringbuffer( | ||
map, | ||
|| { | ||
probe!(crypto_auditing, new_context, 1, 2); | ||
probe!(crypto_auditing, word_data, 1, foo.as_ptr(), 3); | ||
probe!(crypto_auditing, string_data, 1, bar.as_ptr(), bar.as_ptr()); | ||
probe!( | ||
crypto_auditing, | ||
blob_data, | ||
1, | ||
baz.as_ptr(), | ||
baz.as_ptr(), | ||
baz.len() | ||
); | ||
}, | ||
timeout, | ||
) | ||
.expect("unable to exercise probe points"); | ||
assert_eq!(result, 4); | ||
let result = with_ringbuffer( | ||
map, | ||
|| { | ||
probe!(crypto_auditing, new_context, 4, 5); | ||
}, | ||
timeout, | ||
) | ||
.expect("unable to exercise probe points"); | ||
assert_eq!(result, 1); | ||
|
||
let log_file = std::fs::File::open(&log_path) | ||
.expect(&format!("unable to read file `{}`", log_path.display())); | ||
|
||
let groups: Result<Vec<_>, _> = Deserializer::from_reader(&log_file) | ||
.into_iter::<EventGroup>() | ||
.collect(); | ||
let groups = groups.expect("error deserializing"); | ||
assert_eq!(groups.len(), 2); | ||
assert_eq!(groups[0].events().len(), 4); | ||
assert_eq!(groups[1].events().len(), 1); | ||
}); | ||
|
||
process.kill().expect("unable to kill agent"); | ||
|
||
assert!(result.is_ok()); | ||
} |
Oops, something went wrong.