Skip to content

Commit

Permalink
feat: use seccomp_export_bpf instead of seccomp_export_bpf_mem
Browse files Browse the repository at this point in the history
The `seccomp_export_bpf_mem` is not available in usually disrtibuted
`libseccomp` libraries for some reason, so use `seccomp_export_bpf` +
`memfd` setup from before to simplify the compatibility.

Signed-off-by: Egor Lazarchuk <[email protected]>
  • Loading branch information
ShadowCurse committed Dec 10, 2024
1 parent 342ea0c commit 9d8e031
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 22 deletions.
1 change: 0 additions & 1 deletion src/seccompiler/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@
// SPDX-License-Identifier: Apache-2.0

fn main() {
println!("cargo::rustc-link-search=/usr/local/lib");
println!("cargo::rustc-link-lib=seccomp");
}
13 changes: 4 additions & 9 deletions src/seccompiler/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,19 +155,14 @@ extern "C" {
arg_array: *const scmp_arg_cmp,
) -> c_int;

/// Generate seccomp Berkeley Packet Filter (BPF) code and export it to a buffer
/// Generate seccomp Berkeley Packet Filter (BPF) code and export it to a file
///
/// - `ctx`: the filter context
/// - `buf`: the destination buffer
/// - `len`: on input the length of the buffer, on output the number of bytes in the program
/// - `fd`: the destination fd
///
/// This function generates seccomp Berkeley Packer Filter (BPF) code and writes
/// it to the given buffer. Returns zero on success, negative values on failure.
pub fn seccomp_export_bpf_mem(
ctx: const_scmp_filter_ctx,
buf: *mut c_void,
len: *mut usize,
) -> c_int;
/// it to the given fd. Returns zero on success, negative values on failure.
pub fn seccomp_export_bpf(ctx: const_scmp_filter_ctx, fd: c_int) -> c_int;
}

/// Negative pseudo syscall number returned by some functions in case of an error
Expand Down
46 changes: 34 additions & 12 deletions src/seccompiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@

use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::io::{Read, Seek};
use std::os::fd::{AsRawFd, FromRawFd};
use std::os::unix::fs::MetadataExt;

use bincode::Error as BincodeError;

mod bindings;
use bindings::*;

pub mod types;
use libc::c_void;
pub use types::*;

/// Binary filter compilation errors.
Expand All @@ -33,8 +34,12 @@ pub enum CompilationError {
LibSeccompSycall,
/// Cannot add libseccomp syscall rule
LibSeccompRule,
/// Cannot create memfd: {0}
MemfdCreate(i32),
/// Cannot export libseccomp bpf
LibSeccompExport,
/// Cannot read from memfd: {0}
MemfdRead(std::io::Error),
/// Cannot create output file: {0}
OutputCreate(std::io::Error),
/// Cannot serialize bfp: {0}
Expand All @@ -57,6 +62,18 @@ pub fn compile_bpf(

let arch: TargetArch = arch.try_into().map_err(CompilationError::ArchParse)?;

// SAFETY: Safe because the parameters are valid.
let memfd_fd = unsafe { libc::memfd_create("bpf\0".as_ptr().cast(), 0) };
if memfd_fd < 0 {
return Err(CompilationError::MemfdCreate(
// SAFETY: Safe because there are no parameters.
unsafe { *libc::__errno_location() },
));
}

// SAFETY: Safe because the parameters are valid.
let mut memfd = unsafe { File::from_raw_fd(memfd_fd) };

let mut bpf_map: HashMap<String, Vec<BpfInstruction>> = HashMap::new();
for (name, filter) in bpf_map_json.0.iter() {
let default_action = filter.default_action.to_scmp_type();
Expand Down Expand Up @@ -195,24 +212,29 @@ pub fn compile_bpf(
}
}

// First we need to get a number of bytes we need to store the bpf.
let mut len: usize = 0;
memfd.rewind().unwrap();
// SAFETY: Safe as all args are correect.
unsafe {
if seccomp_export_bpf_mem(bpf_filter, std::ptr::null_mut::<c_void>(), &mut len) != 0 {
if seccomp_export_bpf(bpf_filter, memfd.as_raw_fd()) != 0 {
return Err(CompilationError::LibSeccompExport);
}
}
memfd.rewind().unwrap();

// We can safely cast because usize == u64
#[allow(clippy::cast_possible_truncation)]
let size = memfd.metadata().unwrap().size() as usize;
// Bpf consists of instructions each 8 bytes long and 4 bytes aligned.
let instructions = size / std::mem::size_of::<BpfInstruction>();
// We will use Vec<u64> to store bpf program to safisfy all the needs.
let len_u64 = len / std::mem::size_of::<u64>();
let mut bpf = vec![0_u64; len_u64];
let mut bpf = vec![0_u64; instructions];
// SAFETY: Safe as u64 has bigger alignment and size is correct.
unsafe {
if seccomp_export_bpf_mem(bpf_filter, bpf.as_mut_ptr().cast(), &mut len) != 0 {
return Err(CompilationError::LibSeccompExport);
}
}
let bpf_u8: &mut [u8] =
unsafe { std::slice::from_raw_parts_mut(bpf.as_mut_ptr().cast(), size) };

_ = memfd
.read_exact(bpf_u8)
.map_err(CompilationError::MemfdRead);

bpf_map.insert(name.clone(), bpf);
}
Expand Down

0 comments on commit 9d8e031

Please sign in to comment.