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

RFE: add tests for Rust bindings #411

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
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
Loading