Skip to content

Commit

Permalink
tests: Add tests for Rust bindings
Browse files Browse the repository at this point in the history
Add the regression tests (1-60) for the libseccomp crate that is
Rust language bindings for the libseccomp library.

You can run the tests as follows:

```sh
$ sed -i "/^AC_INIT/ s/0.0.0/9.9.9/" configure.ac
$ ./autogen.sh
$ ./configure --prefix=$(pwd)/src/.libs --enable-rust
$ make && make install
$ make check-build
$ cd tests && ./regression -m rust
```

Based on: #323

Signed-off-by: Manabu Sugimoto <[email protected]>
Signed-off-by: mayank <[email protected]>
  • Loading branch information
ManaSugi committed Feb 19, 2024
1 parent 47ca644 commit 86f5b73
Show file tree
Hide file tree
Showing 70 changed files with 3,914 additions and 6 deletions.
4 changes: 4 additions & 0 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,8 @@ runs:
shell: bash
- run: |
./autogen.sh
# Specify the tentative version of the libseccomp test library because some
# functions of the Rust bindings are restricted based on the version.
TEST_VERSION=9.9.9
sed -i "/^AC_INIT/ s/0.0.0/$TEST_VERSION/" configure.ac
shell: bash
15 changes: 12 additions & 3 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ jobs:
uses: ./.github/actions/setup
- name: Build libseccomp
run: |
./configure --enable-python
./configure --prefix=$(pwd)/src/.libs --enable-python --enable-rust
# make and make install are required to create a pkconfig because
# the Rust bindings need it for the compilation.
make
make install
make check-build
- name: Run tests
run: |
Expand All @@ -52,13 +56,18 @@ jobs:
uses: ./.github/actions/setup
- name: Build libseccomp
run: |
./configure --enable-python
./configure --prefix=$(pwd)/src/.libs --enable-python --enable-rust
# make and make install are required to create a pkconfig because
# the Rust bindings need it for the compilation.
# This can be removed when the Rust bindings drop the version check by pkgconfig.
make
make install
make check-build
- name: Run live tests
run: |
LIBSECCOMP_TSTCFG_JOBS=0 \
LIBSECCOMP_TSTCFG_TYPE=live \
LIBSECCOMP_TSTCFG_MODE_LIST=c make -C tests check
LIBSECCOMP_TSTCFG_MODE_LIST="c rust" make -C tests check
scanbuild:
name: Scan Build
Expand Down
4 changes: 2 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ AM_MAKEFLAGS_1 =
AM_MAKEFLAGS_ = ${AM_MAKEFLAGS_0}
AM_MAKEFLAGS = ${AM_MAKEFLAGS_@AM_V@}

# enable python during distcheck
AM_DISTCHECK_CONFIGURE_FLAGS = --enable-python
# enable python and rust during distcheck
AM_DISTCHECK_CONFIGURE_FLAGS = --enable-python --enable-rust

check-build: all
${MAKE} ${AM_MAKEFLAGS} -C src check-build
Expand Down
30 changes: 30 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,36 @@ AC_DEFINE_UNQUOTED([ENABLE_PYTHON],
[$(test "$enable_python" = "yes" && echo 1 || echo 0)],
[Python bindings build flag.])

dnl ####
dnl rustc checks
dnl ####
AC_CHECK_PROGS(rustc, rustc, "no")
AS_IF([test "$rustc" != no], [
AS_ECHO("checking rustc version... $($rustc -V 2>&1 | cut -d' ' -f 2)")
RUSTC_VER_MAJ=$($rustc -V 2>&1 | cut -d' ' -f 2 | cut -d'.' -f 1);
RUSTC_VER_MIN=$($rustc -V 2>&1 | cut -d' ' -f 2 | cut -d'.' -f 2);
],[
RUSTC_VER_MAJ=0
RUSTC_VER_MIN=0
])

dnl ####
dnl rust binding checks
dnl ####
AC_ARG_ENABLE([rust],
[AS_HELP_STRING([--enable-rust],
[build the rust bindings, requires rustc])])
AS_IF([test "$enable_rust" = yes], [
# rustc version check
AS_IF([test "$RUSTC_VER_MAJ" -eq 1 -a "$RUSTC_VER_MIN" -lt 63], [
AC_MSG_ERROR([rust bindings require rustc 1.63 or higher])
])
])
AM_CONDITIONAL([ENABLE_RUST], [test "$enable_rust" = yes])
AC_DEFINE_UNQUOTED([ENABLE_RUST],
[$(test "$enable_rust" = yes && echo 1 || echo 0)],
[Rust bindings build flag.])

AC_CHECK_TOOL(GPERF, gperf)
if test -z "$GPERF"; then
AC_MSG_ERROR([please install gperf])
Expand Down
4 changes: 4 additions & 0 deletions tests/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,7 @@ util.pyc
58-live-tsync_notify
59-basic-empty_binary_tree
60-sim-precompute
/rust/target
/rust/utils/target
.crates.toml
.crates2.json
34 changes: 34 additions & 0 deletions tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,32 @@ miniseq_LDADD =

TESTS = regression

if ENABLE_RUST
rust_BINDINGS_TEST = yes
else
rust_BINDINGS_TEST = no
endif

rust_TESTS_DIR = ./rust
rust_CARGO_TOML = Cargo.toml
rust_LINK_TYPE = static
rust_LIBSECCOMP_LIBRARY_DIR = ../src/.libs/lib
export LIBSECCOMP_LINK_TYPE =$(rust_LINK_TYPE)
export LIBSECCOMP_LIB_PATH =$(shell realpath $(rust_LIBSECCOMP_LIBRARY_DIR))

define check_rust_bindings
echo "Check format and lint for rust bindings"; \
cargo fmt --manifest-path $(rust_TESTS_DIR)/$(rust_CARGO_TOML) -- --check || exit 1; \
cargo clippy --manifest-path $(rust_TESTS_DIR)/$(rust_CARGO_TOML) \
--all-targets --all-features -- -D warnings || exit 1;
endef

define build_rust_bindings
echo "Build test programs for rust bindings"; \
cargo build --manifest-path $(rust_TESTS_DIR)/$(rust_CARGO_TOML) || exit 1; \
cargo install --quiet --root $(rust_TESTS_DIR) --path $(rust_TESTS_DIR) || exit 1;
endef

check_PROGRAMS = \
miniseq \
01-sim-allow \
Expand Down Expand Up @@ -240,6 +266,14 @@ EXTRA_PROGRAMS = 00-test

check-build:
${MAKE} ${AM_MAKEFLAGS} ${check_PROGRAMS}
@if [ "$(rust_BINDINGS_TEST)" = "yes" ]; then \
$(call check_rust_bindings) \
$(call build_rust_bindings) \
fi

clean-local:
${RM} -f 00-test *.pyc
if [ "$(rust_BINDINGS_TEST)" = "yes" ]; then \
cargo clean --manifest-path $(rust_TESTS_DIR)/$(rust_CARGO_TOML); \
${RM} -rf $(rust_TESTS_DIR)/bin; \
fi
24 changes: 23 additions & 1 deletion tests/regression
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ GLBL_SYS_RESOLVER="../tools/scmp_sys_resolver"
GLBL_SYS_SIM="../tools/scmp_bpf_sim"
GLBL_SYS_API="../tools/scmp_api_level"

RUST_TESTS_DIR="./rust"
RUST_TESTS_BIN_DIR="${RUST_TESTS_DIR}/bin"

####
# functions

Expand Down Expand Up @@ -104,7 +107,7 @@ optional arguments:
-h show this help message and exit
-j JOBS run up to JOBS test jobs in parallel
can also be set via LIBSECCOMP_TSTCFG_JOBS env variable
-m MODE specified the test mode [c (default), python]
-m MODE specified the test mode [c (default), python, rust]
can also be set via LIBSECCOMP_TSTCFG_MODE_LIST env variable
-a specifies all tests are to be run
-b BATCH_NAME specifies batch of tests to be run
Expand Down Expand Up @@ -266,6 +269,8 @@ function run_test_command() {
else
cmd="$cmd /usr/bin/env python ${srcdir}/$2.py $3"
fi
elif [[ $mode == "rust" ]]; then
cmd="${RUST_TESTS_BIN_DIR}/$2 $3"
else
cmd="$2 $3"
fi
Expand Down Expand Up @@ -871,6 +876,16 @@ function run_test() {
# generate the test number string for the line of batch test data
local testnumstr=$(generate_test_num "$1" $2 1)

# skip tests not yet supported for Rust bindings
if [[ "$mode" == "rust" ]]; then
if [[ ! -e "${RUST_TESTS_DIR}/${1}.rs" ]]; then
print_result $testnumstr "SKIPPED" \
"(test not yet supported)"
stats_skipped=$(($stats_skipped+1))
return
fi
fi

# ensure we only run tests which match the specified type
match_csv_word "$type" "$4"
local type_match=$?
Expand Down Expand Up @@ -1115,6 +1130,9 @@ while getopts "ab:gj:l:m:s:t:T:vh" opt; do
verify_deps python
mode_list="$mode_list python"
;;
rust)
mode_list="$mode_list rust"
;;
*)
usage
exit 1
Expand Down Expand Up @@ -1160,6 +1178,10 @@ if [[ -z $mode_list ]]; then
[[ "$(grep "ENABLE_PYTHON" ../configure.h | \
awk '{ print $3 }')" = "1" ]] && \
mode_list="$mode_list python"
# rust tests
[[ "$(grep "ENABLE_RUST" ../configure.h | \
awk '{ print $3 }')" = "1" ]] && \
mode_list="$mode_list rust"
fi
fi

Expand Down
17 changes: 17 additions & 0 deletions tests/rust/01-sim-allow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: LGPL-2.1-only
//
// Copyright 2024 Sony Group Corporation
//
// Seccomp Library test program
//

use anyhow::Result;
use libseccomp::*;
use utils::*;

fn main() -> Result<()> {
let opts = util_getopt();
let ctx = ScmpFilterContext::new(ScmpAction::Allow)?;

util_filter_output(&opts, &ctx)
}
22 changes: 22 additions & 0 deletions tests/rust/02-sim-basic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: LGPL-2.1-only
//
// Copyright 2024 Sony Group Corporation
//
// Seccomp Library test program
//

use anyhow::Result;
use libseccomp::*;
use utils::*;

fn main() -> Result<()> {
let opts = util_getopt();
let mut ctx = ScmpFilterContext::new(ScmpAction::KillThread)?;

ctx.add_rule_exact(ScmpAction::Allow, ScmpSyscall::from_name("read")?)?;
ctx.add_rule_exact(ScmpAction::Allow, ScmpSyscall::from_name("write")?)?;
ctx.add_rule_exact(ScmpAction::Allow, ScmpSyscall::from_name("close")?)?;
ctx.add_rule_exact(ScmpAction::Allow, ScmpSyscall::from_name("rt_sigreturn")?)?;

util_filter_output(&opts, &ctx)
}
37 changes: 37 additions & 0 deletions tests/rust/03-sim-basic_chains.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: LGPL-2.1-only
//
// Copyright 2024 Sony Group Corporation
//
// Seccomp Library test program
//

use anyhow::Result;
use libseccomp::*;
use std::io::{stderr, stdin, stdout};
use std::os::unix::io::AsRawFd;
use utils::*;

fn main() -> Result<()> {
let opts = util_getopt();
let mut ctx = ScmpFilterContext::new(ScmpAction::KillThread)?;

ctx.add_rule_conditional_exact(
ScmpAction::Allow,
ScmpSyscall::from_name("read")?,
&[scmp_cmp!($arg0 == stdin().as_raw_fd() as u64)],
)?;
ctx.add_rule_conditional_exact(
ScmpAction::Allow,
ScmpSyscall::from_name("write")?,
&[scmp_cmp!($arg0 == stdout().as_raw_fd() as u64)],
)?;
ctx.add_rule_conditional_exact(
ScmpAction::Allow,
ScmpSyscall::from_name("write")?,
&[scmp_cmp!($arg0 == stderr().as_raw_fd() as u64)],
)?;
ctx.add_rule_exact(ScmpAction::Allow, ScmpSyscall::from_name("close")?)?;
ctx.add_rule_exact(ScmpAction::Allow, ScmpSyscall::from_name("rt_sigreturn")?)?;

util_filter_output(&opts, &ctx)
}
51 changes: 51 additions & 0 deletions tests/rust/04-sim-multilevel_chains.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: LGPL-2.1-only
//
// Copyright 2024 Sony Group Corporation
//
// Seccomp Library test program
//

use anyhow::Result;
use libseccomp::*;
use std::io::{stderr, stdin, stdout};
use std::os::unix::io::AsRawFd;
use utils::*;

fn main() -> Result<()> {
let opts = util_getopt();
let mut ctx = ScmpFilterContext::new(ScmpAction::KillThread)?;

ctx.add_rule(ScmpAction::Allow, ScmpSyscall::from_name("openat")?)?;
ctx.add_rule(ScmpAction::Allow, ScmpSyscall::from_name("close")?)?;
ctx.add_rule_conditional(
ScmpAction::Allow,
ScmpSyscall::from_name("read")?,
&[
scmp_cmp!($arg0 == stdin().as_raw_fd() as u64),
scmp_cmp!($arg1 != 0),
scmp_cmp!($arg2 < libc::ssize_t::MAX as u64),
],
)?;
ctx.add_rule_conditional(
ScmpAction::Allow,
ScmpSyscall::from_name("write")?,
&[
scmp_cmp!($arg0 == stdout().as_raw_fd() as u64),
scmp_cmp!($arg1 != 0),
scmp_cmp!($arg2 < libc::ssize_t::MAX as u64),
],
)?;
ctx.add_rule_conditional(
ScmpAction::Allow,
ScmpSyscall::from_name("write")?,
&[
scmp_cmp!($arg0 == stderr().as_raw_fd() as u64),
scmp_cmp!($arg1 != 0),
scmp_cmp!($arg2 < libc::ssize_t::MAX as u64),
],
)?;
ctx.add_rule(ScmpAction::Allow, ScmpSyscall::from_name("close")?)?;
ctx.add_rule(ScmpAction::Allow, ScmpSyscall::from_name("rt_sigreturn")?)?;

util_filter_output(&opts, &ctx)
}
52 changes: 52 additions & 0 deletions tests/rust/05-sim-long_jumps.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: LGPL-2.1-only
//
// Copyright 2024 Sony Group Corporation
//
// Seccomp Library test program
//

use anyhow::Result;
use libseccomp::*;
use utils::*;

fn main() -> Result<()> {
let opts = util_getopt();
let mut ctx = ScmpFilterContext::new(ScmpAction::KillThread)?;

ctx.add_rule(ScmpAction::Allow, ScmpSyscall::from_name("brk")?)?;

// same syscall, many chains
for iter in 0..100 {
ctx.add_rule_conditional(
ScmpAction::Allow,
ScmpSyscall::from_name("chdir")?,
&[
scmp_cmp!($arg0 == iter),
scmp_cmp!($arg1 != 0),
scmp_cmp!($arg2 < libc::ssize_t::MAX as u64),
],
)?;
}

// many syscalls, same chain
let mut ctr = 0;
for iter in 0..10000 {
if ctr >= 100 {
break;
}

let syscall = ScmpSyscall::from(iter);
if syscall == ScmpSyscall::from_name("chdir")? {
continue;
}

if syscall.get_name().is_ok() {
ctx.add_rule_conditional(ScmpAction::Allow, iter, &[scmp_cmp!($arg0 != 0)])?;
ctr += 1;
}
}

ctx.add_rule(ScmpAction::Allow, ScmpSyscall::from_name("close")?)?;

util_filter_output(&opts, &ctx)
}
Loading

0 comments on commit 86f5b73

Please sign in to comment.