Skip to content
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
3 changes: 2 additions & 1 deletion .buildkite/custom-tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"platform": [
"x86_64",
"aarch64",
"riscv64"
"riscv64",
"s390x"
]
},
{
Expand Down
2 changes: 1 addition & 1 deletion .platform
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
x86_64
aarch64
riscv64

s390x
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Upcoming Release

# v0.5.0
## Added
- [[#97]](https://github.com/rust-vmm/seccompiler/pull/97): Added big-endian
support and S390X as first big-endian system.

## Added
- [[#72]](https://github.com/rust-vmm/seccompiler/pull/72): Introduce RISC-V
Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ json = ["serde", "serde_json"]
libc = "^0.2.153"
serde = { version = "^1.0.27", features = ["derive"], optional = true}
serde_json = {version = "^1.0.9", optional = true}

[dev-dependencies]
errno = "0.3.14"
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Supported host architectures:
- Little-endian x86_64
- Little-endian aarch64
- Little-endian riscv64
- Big-endian s390x (*Experimental*)

## Short seccomp tutorial

Expand Down
2 changes: 1 addition & 1 deletion coverage_config_x86_64.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"coverage_score": 96.7,
"coverage_score": 97.50,
"exclude_path": "tests/integration_tests.rs,tests/json.rs",
"crate_features": "json"
}
5 changes: 5 additions & 0 deletions src/backend/bpf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ pub const AUDIT_ARCH_AARCH64: u32 = 183 | 0x8000_0000 | 0x4000_0000;
// `#define AUDIT_ARCH_RISCV64 (EM_RISCV|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)`
pub const AUDIT_ARCH_RISCV64: u32 = 243 | 0x8000_0000 | 0x4000_0000;

// Architecture identifier for s390x BE.
// Defined as:
// #define AUDIT_ARCH_S390X (EM_S390|__AUDIT_ARCH_64BIT)
pub const AUDIT_ARCH_S390X: u32 = 22 | 0x8000_0000;

/// BPF instruction structure definition.
// See /usr/include/linux/filter.h .
// We cannot use the `libc::sock_filter` definition since it doesn't implement `Debug` and
Expand Down
18 changes: 17 additions & 1 deletion src/backend/condition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,17 @@ impl SeccompCondition {

// Extracts offsets of most significant and least significant halves of argument.
// Addition cannot overflow because it's at most `arg_offset` + 4 = 68.
(arg_offset + SECCOMP_DATA_ARG_SIZE / 2, arg_offset)
#[cfg(target_endian = "little")]
return (arg_offset + SECCOMP_DATA_ARG_SIZE / 2, arg_offset);

#[cfg(target_endian = "big")]
return (arg_offset, arg_offset + SECCOMP_DATA_ARG_SIZE / 2);
}

/// Splits the `value` field into 32 bit chunks
///
/// Returns the most significant and least significant halves of the `value`.
/// shifts are endianness independent
fn split_value(&self) -> (u32, u32) {
((self.value >> 32) as u32, self.value as u32)
}
Expand Down Expand Up @@ -315,6 +320,8 @@ mod tests {
fn test_get_data_offsets() {
let cond = SeccompCondition::new(1, SeccompCmpArgLen::Qword, SeccompCmpOp::Eq, 60).unwrap();
let (msb_offset, lsb_offset) = cond.get_data_offsets();

#[cfg(target_endian = "little")]
assert_eq!(
(msb_offset, lsb_offset),
(
Expand All @@ -323,6 +330,15 @@ mod tests {
)
);

#[cfg(target_endian = "big")]
assert_eq!(
(msb_offset, lsb_offset),
(
SECCOMP_DATA_ARGS_OFFSET + SECCOMP_DATA_ARG_SIZE,
SECCOMP_DATA_ARGS_OFFSET + SECCOMP_DATA_ARG_SIZE + 4
)
);

let data = libc::seccomp_data {
nr: 0,
arch: 0,
Expand Down
48 changes: 29 additions & 19 deletions src/backend/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,35 +346,40 @@ mod tests {
// Compares translated filter with hardcoded BPF program.
let filter = create_test_bpf_filter(ArgLen::Dword);

#[cfg(target_endian = "little")]
let offset = 0;
#[cfg(target_endian = "big")]
let offset = 4;

let mut instructions = Vec::new();
instructions.extend(build_arch_validation_sequence(ARCH.try_into().unwrap()));
instructions.extend(vec![
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 0),
bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 1, 0, 1),
bpf_stmt(BPF_JMP | BPF_JA, 1),
bpf_stmt(BPF_JMP | BPF_JA, 6),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32 + offset),
bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 10, 3, 0),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32 + offset),
bpf_jump(BPF_JMP | BPF_JGT | BPF_K, 14, 1, 0),
bpf_stmt(BPF_RET, 0x7fff_0000),
bpf_stmt(BPF_JMP | BPF_JA, 1),
bpf_stmt(BPF_JMP | BPF_JA, 6),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32 + offset),
bpf_jump(BPF_JMP | BPF_JGE | BPF_K, 30, 3, 0),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32 + offset),
bpf_jump(BPF_JMP | BPF_JGT | BPF_K, 20, 0, 1),
bpf_stmt(BPF_RET, 0x7fff_0000),
bpf_stmt(BPF_JMP | BPF_JA, 1),
bpf_stmt(BPF_JMP | BPF_JA, 4),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32 + offset),
bpf_jump(BPF_JMP | BPF_JGE | BPF_K, 42, 0, 1),
bpf_stmt(BPF_RET, 0x7fff_0000),
bpf_stmt(BPF_RET, 0x0003_0000),
bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 9, 0, 1),
bpf_stmt(BPF_JMP | BPF_JA, 1),
bpf_stmt(BPF_JMP | BPF_JA, 5),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 24),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 24 + offset),
bpf_stmt(BPF_ALU | BPF_AND | BPF_K, 0b100),
bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 36 & 0b100, 0, 1),
bpf_stmt(BPF_RET, 0x7fff_0000),
Expand All @@ -394,7 +399,12 @@ mod tests {

#[test]
fn test_filter_bpf_output_qword() {
let filter = create_test_bpf_filter(ArgLen::Qword);
let filter: SeccompFilter = create_test_bpf_filter(ArgLen::Qword);

#[cfg(target_endian = "little")]
let (msb_offset, lsb_offset) = (4, 0);
#[cfg(target_endian = "big")]
let (msb_offset, lsb_offset) = (0, 4);

let mut instructions = Vec::new();
instructions.extend(build_arch_validation_sequence(ARCH.try_into().unwrap()));
Expand All @@ -403,45 +413,45 @@ mod tests {
bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 1, 0, 1),
bpf_stmt(BPF_JMP | BPF_JA, 1),
bpf_stmt(BPF_JMP | BPF_JA, 11),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 36),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32 + msb_offset),
bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, 2),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32 + lsb_offset),
bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 10, 6, 0),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 36),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32 + msb_offset),
bpf_jump(BPF_JMP | BPF_JGT | BPF_K, 0, 4, 0),
bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, 2),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32 + lsb_offset),
bpf_jump(BPF_JMP | BPF_JGT | BPF_K, 14, 1, 0),
bpf_stmt(BPF_RET, 0x7fff_0000),
bpf_stmt(BPF_JMP | BPF_JA, 1),
bpf_stmt(BPF_JMP | BPF_JA, 12),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 36),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32 + msb_offset),
bpf_jump(BPF_JMP | BPF_JGT | BPF_K, 0, 9, 0),
bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, 2),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32 + lsb_offset),
bpf_jump(BPF_JMP | BPF_JGE | BPF_K, 30, 6, 0),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 36),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32 + msb_offset),
bpf_jump(BPF_JMP | BPF_JGT | BPF_K, 0, 3, 0),
bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, 3),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32 + lsb_offset),
bpf_jump(BPF_JMP | BPF_JGT | BPF_K, 20, 0, 1),
bpf_stmt(BPF_RET, 0x7fff_0000),
bpf_stmt(BPF_JMP | BPF_JA, 1),
bpf_stmt(BPF_JMP | BPF_JA, 7),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 36),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32 + msb_offset),
bpf_jump(BPF_JMP | BPF_JGT | BPF_K, 0, 3, 0),
bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, 3),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 32 + lsb_offset),
bpf_jump(BPF_JMP | BPF_JGE | BPF_K, 42, 0, 1),
bpf_stmt(BPF_RET, 0x7fff_0000),
bpf_stmt(BPF_RET, 0x0003_0000),
bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 9, 0, 1),
bpf_stmt(BPF_JMP | BPF_JA, 1),
bpf_stmt(BPF_JMP | BPF_JA, 8),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 28),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 24 + msb_offset),
bpf_stmt(BPF_ALU | BPF_AND | BPF_K, 0),
bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, 4),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 24),
bpf_stmt(BPF_LD | BPF_W | BPF_ABS, 24 + lsb_offset),
bpf_stmt(BPF_ALU | BPF_AND | BPF_K, 0b100),
bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 36 & 0b100, 0, 1),
bpf_stmt(BPF_RET, 0x7fff_0000),
Expand Down
9 changes: 8 additions & 1 deletion src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ use libc::{
SECCOMP_RET_KILL_THREAD, SECCOMP_RET_LOG, SECCOMP_RET_TRACE, SECCOMP_RET_TRAP,
};

use bpf::{ARG_NUMBER_MAX, AUDIT_ARCH_AARCH64, AUDIT_ARCH_RISCV64, AUDIT_ARCH_X86_64, BPF_MAX_LEN};
use bpf::{
ARG_NUMBER_MAX, AUDIT_ARCH_AARCH64, AUDIT_ARCH_RISCV64, AUDIT_ARCH_S390X, AUDIT_ARCH_X86_64,
BPF_MAX_LEN,
};

pub use bpf::{sock_filter, BpfProgram, BpfProgramRef};

Expand Down Expand Up @@ -85,6 +88,8 @@ pub enum TargetArch {
aarch64,
/// riscv64 arch
riscv64,
/// s390x arch
s390x,
}

impl TargetArch {
Expand All @@ -94,6 +99,7 @@ impl TargetArch {
TargetArch::x86_64 => AUDIT_ARCH_X86_64,
TargetArch::aarch64 => AUDIT_ARCH_AARCH64,
TargetArch::riscv64 => AUDIT_ARCH_RISCV64,
TargetArch::s390x => AUDIT_ARCH_S390X,
}
}
}
Expand All @@ -105,6 +111,7 @@ impl TryFrom<&str> for TargetArch {
"x86_64" => Ok(TargetArch::x86_64),
"aarch64" => Ok(TargetArch::aarch64),
"riscv64" => Ok(TargetArch::riscv64),
"s390x" => Ok(TargetArch::s390x),
_ => Err(Error::InvalidTargetArch(input.to_string())),
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/backend/rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,12 @@ mod tests {
])
.unwrap();

#[cfg(target_endian = "little")]
let (msb_offset, lsb_offset) = { (4, 0) };

#[cfg(target_endian = "big")]
let (msb_offset, lsb_offset) = { (0, 4) };

// Builds hardcoded BPF instructions.
let instructions = vec![
bpf_stmt(BPF_JMP | BPF_JA, 1), // Start evaluating the rule.
Expand Down Expand Up @@ -203,8 +207,12 @@ mod tests {
conditions.push(Cond::new(0, ArgLen::Qword, Eq, 0).unwrap());
let rule = SeccompRule::new(conditions).unwrap();

#[cfg(target_endian = "little")]
let (msb_offset, lsb_offset) = { (4, 0) };

#[cfg(target_endian = "big")]
let (msb_offset, lsb_offset) = { (0, 4) };

// Builds hardcoded BPF instructions.
let mut instructions = vec![
bpf_stmt(BPF_JMP | BPF_JA, 1), // Start evaluating the rule.
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
#![deny(missing_docs)]
#![cfg(target_endian = "little")]
//! Provides easy-to-use Linux seccomp-bpf jailing.
//!
//! Seccomp is a Linux kernel security feature which enables a tight control over what kernel-level
Expand Down Expand Up @@ -35,6 +34,7 @@
//! - Little-endian x86_64
//! - Little-endian aarch64
//! - Little-endian riscv64
//! - Big-endian s390x
//!
//! # Terminology
//!
Expand Down
5 changes: 5 additions & 0 deletions src/syscall_table/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

mod aarch64;
mod riscv64;
mod s390x;
mod x86_64;

use crate::backend::TargetArch;
Expand All @@ -21,6 +22,7 @@ impl SyscallTable {
TargetArch::aarch64 => aarch64::make_syscall_table(),
TargetArch::x86_64 => x86_64::make_syscall_table(),
TargetArch::riscv64 => riscv64::make_syscall_table(),
TargetArch::s390x => s390x::make_syscall_table(),
},
}
}
Expand All @@ -42,14 +44,17 @@ mod tests {
let instance_x86_64 = SyscallTable::new(TargetArch::x86_64);
let instance_aarch64 = SyscallTable::new(TargetArch::aarch64);
let instance_riscv64 = SyscallTable::new(TargetArch::riscv64);
let instance_s390x = SyscallTable::new(TargetArch::s390x);

assert_eq!(instance_x86_64.get_syscall_nr("close").unwrap(), 3);
assert_eq!(instance_aarch64.get_syscall_nr("close").unwrap(), 57);
assert_eq!(instance_riscv64.get_syscall_nr("close").unwrap(), 57);
assert_eq!(instance_s390x.get_syscall_nr("close").unwrap(), 6);

// invalid syscall name
assert!(instance_x86_64.get_syscall_nr("nosyscall").is_none());
assert!(instance_aarch64.get_syscall_nr("nosyscall").is_none());
assert!(instance_riscv64.get_syscall_nr("nosyscall").is_none());
assert!(instance_s390x.get_syscall_nr("nosyscall").is_none());
}
}
Loading