Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

integration-test: fix when host != target #796

Merged
merged 3 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 43 additions & 52 deletions test/integration-ebpf/src/bpf_probe_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,47 +10,47 @@ use aya_bpf::{

const RESULT_BUF_LEN: usize = 1024;

macro_rules! read_str_bytes {
($fun:ident, $ptr:expr, $len:expr $(,)?) => {
let Some(ptr) = RESULT.get_ptr_mut(0) else {
return;
};
let TestResult {
did_error,
len,
buf,
} = unsafe { &mut *ptr };

// $len comes from ctx.arg(1) so it's dynamic and the verifier
// doesn't see any bounds. We do $len.min(RESULT_BUF_LEN) here to
// ensure that the verifier can see the upper bound, or you get:
//
// 18: (79) r7 = *(u64 *)(r7 +8) ; R7_w=scalar()
// [snip]
// 27: (bf) r2 = r7 ;
// R2_w=scalar(id=2,umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff)) [snip]
// 28: (85) call bpf_probe_read_user_str#114
// R2 unbounded memory access, use 'var &= const' or 'if (var < const)'
let Some(buf) = buf.get_mut(..$len) else {
return;
};
fn read_str_bytes(
fun: unsafe fn(*const u8, &mut [u8]) -> Result<&[u8], i64>,
iptr: Option<*const u8>,
ilen: Option<usize>,
) {
let Some(iptr) = iptr else {
return;
};
let Some(ilen) = ilen else {
return;
};
let Some(ptr) = RESULT.get_ptr_mut(0) else {
return;
};
let dst = unsafe { ptr.as_mut() };
let Some(TestResult { buf, len }) = dst else {
return;
};
*len = None;

match unsafe { $fun($ptr, buf) } {
Ok(s) => {
*len = s.len();
}
Err(_) => {
*did_error = 1;
}
}
// len comes from ctx.arg(1) so it's dynamic and the verifier
// doesn't see any bounds. We do len.min(RESULT_BUF_LEN) here to
// ensure that the verifier can see the upper bound, or you get:
//
// 18: (79) r7 = *(u64 *)(r7 +8) ; R7_w=scalar()
// [snip]
// 27: (bf) r2 = r7 ;
// R2_w=scalar(id=2,umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff)) [snip]
// 28: (85) call bpf_probe_read_user_str#114
// R2 unbounded memory access, use 'var &= const' or 'if (var < const)'
let Some(buf) = buf.get_mut(..ilen) else {
return;
};

*len = Some(unsafe { fun(iptr, buf) }.map(<[_]>::len));
}

#[repr(C)]
struct TestResult {
did_error: u64,
len: usize,
buf: [u8; RESULT_BUF_LEN],
len: Option<Result<usize, i64>>,
}

#[map]
Expand All @@ -61,31 +61,22 @@ static KERNEL_BUFFER: Array<[u8; RESULT_BUF_LEN]> = Array::with_max_entries(1, 0

#[uprobe]
pub fn test_bpf_probe_read_user_str_bytes(ctx: ProbeContext) {
read_str_bytes!(
read_str_bytes(
bpf_probe_read_user_str_bytes,
match ctx.arg::<*const u8>(0) {
Some(p) => p,
_ => return,
},
match ctx.arg::<usize>(1) {
Some(p) => p,
_ => return,
},
ctx.arg::<*const u8>(0),
ctx.arg::<usize>(1),
);
}

#[uprobe]
pub fn test_bpf_probe_read_kernel_str_bytes(ctx: ProbeContext) {
read_str_bytes!(
read_str_bytes(
bpf_probe_read_kernel_str_bytes,
match KERNEL_BUFFER.get_ptr(0) {
Some(p) => p as *const u8,
_ => return,
},
match ctx.arg::<usize>(0) {
Some(p) => p,
_ => return,
},
KERNEL_BUFFER
.get_ptr(0)
.and_then(|ptr| unsafe { ptr.as_ref() })
.map(|buf| buf.as_ptr()),
ctx.arg::<usize>(0),
);
}

Expand Down
4 changes: 3 additions & 1 deletion test/integration-test/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ fn main() {
} else if arch == "aarch64" {
target_arch.push("arm64");
} else {
target_arch.push(arch);
target_arch.push(&arch);
};

// NB: libbpf's documentation suggests that vmlinux.h be generated by running `bpftool btf
Expand Down Expand Up @@ -198,6 +198,8 @@ fn main() {
&target,
]);

cmd.env("CARGO_CFG_BPF_TARGET_ARCH", arch);

// Workaround to make sure that the rust-toolchain.toml is respected.
for key in ["RUSTUP_TOOLCHAIN", "RUSTC"] {
cmd.env_remove(key);
Expand Down
12 changes: 6 additions & 6 deletions test/integration-test/src/tests/bpf_probe_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ const RESULT_BUF_LEN: usize = 1024;
#[derive(Copy, Clone)]
#[repr(C)]
struct TestResult {
did_error: u64,
len: usize,
buf: [u8; RESULT_BUF_LEN],
len: Option<Result<usize, i64>>,
}

unsafe impl aya::Pod for TestResult {}
Expand Down Expand Up @@ -96,11 +95,12 @@ fn set_kernel_buffer_element(bpf: &mut Bpf, bytes: &[u8]) {
#[track_caller]
fn result_bytes(bpf: &Bpf) -> Vec<u8> {
let m = Array::<_, TestResult>::try_from(bpf.map("RESULT").unwrap()).unwrap();
let result = m.get(&0, 0).unwrap();
assert_eq!(result.did_error, 0);
let TestResult { buf, len } = m.get(&0, 0).unwrap();
let len = len.unwrap();
let len = len.unwrap();
// assert that the buffer is always null terminated
assert_eq!(result.buf[result.len], 0);
result.buf[..result.len].to_vec()
assert_eq!(buf[len], 0);
buf[..len].to_vec()
}

fn load_and_attach_uprobe(prog_name: &str, func_name: &str, bytes: &[u8]) -> Bpf {
Expand Down