Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
5 changes: 5 additions & 0 deletions docs/changelog/3080.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
area: Machine Learning
issues: []
pr: 3080
summary: Reject non-native ABIs in ML seccomp filter (socketcall/getuid collision)
type: bug
3 changes: 3 additions & 0 deletions include/seccomp/CSystemCallFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ namespace seccomp {
//!
//! Linux:
//! Seccomp BPF is used to restrict system calls on kernels since 3.5.
//! The filter first requires seccomp_data.arch to match the native ABI
//! (rejecting compat ABIs such as i386 int 0x80 on x86_64, which would
//! otherwise collide with allowlisted syscall numbers).
//!
//! macOs:
//! The sandbox facility is used to restict access to system resources.
Comment thread
edsavage marked this conversation as resolved.
Outdated
Expand Down
17 changes: 16 additions & 1 deletion lib/seccomp/CSystemCallFilter_Linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,25 @@ namespace {
// The x64 ABI should fail these calls
const std::uint32_t UPPER_NR_LIMIT = 0x3FFFFFFF;

// Offset to the nr field in struct seccomp_data
// Offsets into struct seccomp_data (linux/seccomp.h).
const std::uint32_t SECCOMP_DATA_NR_OFFSET = 0x00;
const std::uint32_t SECCOMP_DATA_ARCH_OFFSET = 0x04;
Comment thread
edsavage marked this conversation as resolved.
Outdated

const struct sock_filter FILTER[] = {
// Reject non-native ABIs before matching syscall numbers. Without this,
// an x86_64 process can issue int 0x80 (i386) and hit number collisions —
// e.g. i386 socketcall (102) matches the allowlisted x86_64 getuid (102).
// See elastic/security#12621 / HackerOne report on ML seccomp bypass.
// This prefix is self-contained (immediate RET on mismatch) so the relative
// jump offsets in the nr allowlist below are unchanged.
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, SECCOMP_DATA_ARCH_OFFSET),
#ifdef __x86_64__
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0),
#elif defined(__aarch64__)
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_AARCH64, 1, 0),
#endif
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | (EACCES & SECCOMP_RET_DATA)),

// Load the system call number into accumulator
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, SECCOMP_DATA_NR_OFFSET),

Expand Down
6 changes: 6 additions & 0 deletions lib/seccomp/unittest/CSystemCallFilterTest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@ BOOST_AUTO_TEST_CASE(testSystemCallFilter) {
// Install the filter
ml::seccomp::CSystemCallFilter::installSystemCallFilter();

// Native allowlisted calls must still work. Compat-ABI collisions
// (e.g. i386 socketcall via int 0x80 matching x86_64 getuid=102) are
// rejected by the seccomp_data.arch check at the start of the filter;
// that path is not exercised here because it requires issuing a foreign
// ABI syscall from the test process.
Comment thread
edsavage marked this conversation as resolved.
Outdated

BOOST_REQUIRE_MESSAGE(systemCall() == false, "Calling std::system should fail");

// Operations that must function after seccomp is initialised
Expand Down