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

Add full arm64/aarch64 support #7

Open
wants to merge 26 commits into
base: master
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
17 changes: 10 additions & 7 deletions .github/workflows/build-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,20 @@ jobs:
strategy:
fail-fast: false
matrix:
target-triple: [x86_64-unknown-linux-gnu, x86_64-unknown-linux-musl]
target-triple:
- x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl
- aarch64-unknown-linux-gnu
- aarch64-unknown-linux-musl
steps:
- name: Install musl lib
if: ${{ contains(matrix.target-triple, 'musl') }}
run: sudo apt-get install musl-tools
- name: Install target triple
run: rustup target install ${{ matrix.target-triple }}
- name: Install cross tools
run: cargo install cross --git https://github.com/cross-rs/cross
- name: Checkout
uses: actions/checkout@v4
- name: Run tests
run: make test-ci TARGET_TRIPLE=${{ matrix.target-triple }}
run: |
cross test --target ${{ matrix.target-triple }} --tests --examples --all-features
cross test --target ${{ matrix.target-triple }} --tests --examples --no-default-features

doc:
name: Documentation Check
Expand Down
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,8 @@ rusqlite = "^0.26"
[target.'cfg(target_env = "musl")'.dev-dependencies]
reqwest = { version = "^0.11", default-features = false, features = ["rustls-tls"] }

[target.'cfg(not(target_env = "musl"))'.dev-dependencies]
[target.'cfg(all(not(target_env = "musl"), target_arch = "aarch64"))'.dev-dependencies]
reqwest = { version = "^0.11", features = ["native-tls-vendored"] }

[target.'cfg(not(any(target_env = "musl", target_arch = "aarch64")))'.dev-dependencies]
reqwest = { version = "^0.11" }
23 changes: 23 additions & 0 deletions Cross.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[target.aarch64-unknown-linux-gnu]
pre-build = [
"dpkg --add-architecture $CROSS_DEB_ARCH",
"apt-get update && apt-get install --assume-yes libssl-dev:$CROSS_DEB_ARCH libsqlite3-dev:$CROSS_DEB_ARCH"
]

[target.x86_64-unknown-linux-gnu]
pre-build = [
"dpkg --add-architecture $CROSS_DEB_ARCH",
"apt-get update && apt-get install --assume-yes libssl-dev:$CROSS_DEB_ARCH libsqlite3-dev:$CROSS_DEB_ARCH"
]

[target.x86_64-unknown-linux-musl]
pre-build = [
"dpkg --add-architecture $CROSS_DEB_ARCH",
"apt-get update && apt-get install --assume-yes libsqlite3-dev:$CROSS_DEB_ARCH"
]

[target.aarch64-unknown-linux-musl]
pre-build = [
"dpkg --add-architecture $CROSS_DEB_ARCH",
"apt-get update && apt-get install --assume-yes libsqlite3-dev:$CROSS_DEB_ARCH"
]
2 changes: 2 additions & 0 deletions src/builtins/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ impl RuleSet for BasicCapabilities {

// Readlink isn't dangerous because you still need to be able to open the file to do
// anything with the resolved name.
#[cfg(target_arch = "x86_64")]
Sysno::readlink,
Sysno::readlinkat,

// Getpid/tid is fine.
Sysno::getpid,
Expand Down
17 changes: 12 additions & 5 deletions src/builtins/danger_zone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,23 @@ pub struct ForkAndExec;
impl RuleSet for ForkAndExec {
fn simple_rules(&self) -> Vec<Sysno> {
let mut rules = vec![
Sysno::fork, Sysno::vfork,
Sysno::execve, Sysno::execveat,
Sysno::wait4, Sysno::waitid,
Sysno::clone, Sysno::clone3,
#[cfg(target_arch = "x86_64")]
Sysno::fork,
#[cfg(target_arch = "x86_64")]
Sysno::vfork,
Sysno::execve, Sysno::execveat,
Sysno::wait4, Sysno::waitid,
Sysno::clone, Sysno::clone3,
];

// musl creates a pipe when it starts a new process, and fails the operation if it can't
// create the pipe
if cfg!(target_env = "musl") {
rules.extend([Sysno::pipe, Sysno::pipe2]);
rules.extend([
#[cfg(target_arch = "x86_64")]
Sysno::pipe,
Sysno::pipe2,
]);
}

rules
Expand Down
24 changes: 15 additions & 9 deletions src/builtins/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,22 @@ use crate::{SeccompRule, RuleSet};

// TODO: add io_uring
const NET_IO_SYSCALLS: &[Sysno] = &[
Sysno::epoll_create, Sysno::epoll_create1,
Sysno::epoll_ctl, Sysno::epoll_wait, Sysno::epoll_pwait, Sysno::epoll_pwait2,
Sysno::select, Sysno::pselect6,
Sysno::poll, Sysno::ppoll,

Sysno::accept, Sysno::accept4,

#[cfg(target_arch = "x86_64")]
Sysno::epoll_create,
Sysno::epoll_create1, Sysno::epoll_ctl,
#[cfg(target_arch = "x86_64")]
Sysno::epoll_wait,
Sysno::epoll_pwait, Sysno::epoll_pwait2,
#[cfg(target_arch = "x86_64")]
Sysno::select,
Sysno::pselect6,
#[cfg(target_arch = "x86_64")]
Sysno::poll,
Sysno::ppoll, Sysno::accept, Sysno::accept4,
// used in reqwest::blocking I guess to notify when blocking reads finish?
Sysno::eventfd, Sysno::eventfd2,

#[cfg(target_arch = "x86_64")]
Sysno::eventfd,
Sysno::eventfd2,
// Used to set tcp_nodelay
Sysno::fcntl, Sysno::ioctl,
Sysno::getsockopt,
Expand Down
6 changes: 5 additions & 1 deletion src/builtins/pipes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ use crate::RuleSet;
pub struct Pipes;
impl RuleSet for Pipes {
fn simple_rules(&self) -> Vec<Sysno> {
vec![Sysno::pipe, Sysno::pipe2]
vec![
#[cfg(target_arch = "x86_64")]
Sysno::pipe,
Sysno::pipe2
]
}

fn name(&self) -> &'static str {
Expand Down
87 changes: 70 additions & 17 deletions src/builtins/systemio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,54 @@ use crate::landlock::{access, AccessFs, BitFlags};
use crate::{RuleSet, SeccompRule};
use super::YesReally;

pub(crate) const IO_READ_SYSCALLS: &[Sysno] = &[Sysno::read, Sysno::readv, Sysno::preadv, Sysno::preadv2, Sysno::pread64, Sysno::lseek];
pub(crate) const IO_WRITE_SYSCALLS: &[Sysno] = &[Sysno::write, Sysno::writev, Sysno::pwritev, Sysno::pwritev2, Sysno::pwrite64,
Sysno::fsync, Sysno::fdatasync, Sysno::lseek];
pub(crate) const IO_OPEN_SYSCALLS: &[Sysno] = &[Sysno::open, Sysno::openat, Sysno::openat2];
pub(crate) const IO_READ_SYSCALLS: &[Sysno] = &[
Sysno::read,
Sysno::readv,
Sysno::preadv,
Sysno::preadv2,
Sysno::pread64,
Sysno::lseek,
];
pub(crate) const IO_WRITE_SYSCALLS: &[Sysno] = &[
Sysno::write,
Sysno::writev,
Sysno::pwritev,
Sysno::pwritev2,
Sysno::pwrite64,
Sysno::fsync,
Sysno::fdatasync,
Sysno::lseek,
];
pub(crate) const IO_OPEN_SYSCALLS: &[Sysno] = &[
#[cfg(target_arch = "x86_64")]
Sysno::open,
Sysno::openat,
Sysno::openat2
];
pub(crate) const IO_IOCTL_SYSCALLS: &[Sysno] = &[Sysno::ioctl, Sysno::fcntl];
// TODO: may want to separate fd-based and filename-based?
pub(crate) const IO_METADATA_SYSCALLS: &[Sysno] = &[Sysno::stat, Sysno::fstat, Sysno::newfstatat,
Sysno::lstat, Sysno::statx,
Sysno::getdents, Sysno::getdents64,
Sysno::getcwd];
pub(crate) const IO_METADATA_SYSCALLS: &[Sysno] = &[
#[cfg(target_arch = "x86_64")]
Sysno::stat,
Sysno::fstat,
#[cfg(target_arch = "x86_64")]
Sysno::newfstatat,
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
Sysno::fstatat,
#[cfg(target_arch = "x86_64")]
Sysno::lstat,
Sysno::statx,
#[cfg(target_arch = "x86_64")]
Sysno::getdents,
Sysno::getdents64,
Sysno::getcwd,
];
pub(crate) const IO_CLOSE_SYSCALLS: &[Sysno] = &[Sysno::close, Sysno::close_range];
pub(crate) const IO_UNLINK_SYSCALLS: &[Sysno] = &[Sysno::unlink, Sysno::unlinkat];
pub(crate) const IO_UNLINK_SYSCALLS: &[Sysno] = &[
#[cfg(target_arch = "x86_64")]
Sysno::unlink,
Sysno::unlinkat
];

// TODO: split into SystemIO, SystemIOLandlock, SystemIOSeccompRestricted so that you can't call a
// landlock function after using a seccomp argument filter function (or vice versa). You can still
Expand Down Expand Up @@ -125,11 +161,14 @@ impl SystemIO {
const WRITECREATE: u64 = O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_EXCL;// | O_TMPFILE;

// flags are the second argument for open but the third for openat
let rule = SeccompRule::new(Sysno::open)
.and_condition(seccomp_arg_filter!(arg1 & WRITECREATE == 0));
self.custom.entry(Sysno::open)
.or_insert_with(Vec::new)
.push(rule);
#[cfg(target_arch = "x86_64")]
{
let rule = SeccompRule::new(Sysno::open)
.and_condition(seccomp_arg_filter!(arg1 & WRITECREATE == 0));
self.custom.entry(Sysno::open)
.or_insert_with(Vec::new)
.push(rule);
}

let rule = SeccompRule::new(Sysno::openat)
.and_condition(seccomp_arg_filter!(arg2 & WRITECREATE == 0));
Expand Down Expand Up @@ -317,6 +356,8 @@ impl SystemIO {
self.insert_flags(path, new_flags);

// allow relevant syscalls as well
// creat only exists on x86-64, aarch64 uses O_CREAT with open
#[cfg(target_arch = "x86_64")]
self.allowed.extend(&[Sysno::creat]);
self.allow_open().yes_really()
}
Expand All @@ -341,7 +382,11 @@ impl SystemIO {
self.insert_flags(path, new_flags);

// allow relevant syscalls as well
self.allowed.extend(&[Sysno::mkdir, Sysno::mkdirat]);
self.allowed.extend(&[
#[cfg(target_arch = "x86_64")]
Sysno::mkdir,
Sysno::mkdirat
]);
self
}

Expand All @@ -352,7 +397,11 @@ impl SystemIO {
self.insert_flags(path, new_flags);

// allow relevant syscalls as well
self.allowed.extend(&[Sysno::unlink, Sysno::unlinkat]);
self.allowed.extend(&[
#[cfg(target_arch = "x86_64")]
Sysno::unlink,
Sysno::unlinkat
]);
self
}

Expand All @@ -371,7 +420,11 @@ impl SystemIO {
// allow relevant syscalls as well
// unlinkat may be be used to remove directories as well so we include it here, since files
// will be protected by landlock anyway.
self.allowed.extend(&[Sysno::rmdir, Sysno::unlinkat]);
self.allowed.extend(&[
#[cfg(target_arch = "x86_64")]
Sysno::rmdir,
Sysno::unlinkat
]);
self
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/isolate/isolate_sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use std::ffi::CString;
use super::IsolateError;
use std::io::Write;
use std::os::fd::FromRawFd;
use std::os::raw::c_char;

use std::collections::HashMap;

Expand Down Expand Up @@ -142,7 +143,7 @@ pub fn make_tempdir(isolate_name: &str) -> PathBuf {
let template_str = format!("/tmp/{}.XXXXXX\0", isolate_name);
let mut dir_buf: Vec<u8> = template_str.clone().into_bytes();

let dir_ptr: *mut i8 = dir_buf.as_mut_ptr().cast::<i8>();
let dir_ptr: *mut c_char = dir_buf.as_mut_ptr().cast::<c_char>();
let ret = unsafe { libc::mkdtemp(dir_ptr) };
fail_null!(ret, "failed to create temporary directory after clone");

Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,8 +530,8 @@ impl SafetyContext {
assert!(result.is_none(), "extrasafe logic error: somehow inserted the same syscall's rules twice");
}

#[cfg(not(all(target_arch = "x86_64", target_os = "linux")))]
compile_error!("extrasafe is currently only supported on linux x86_64");
#[cfg(not(all(target_os = "linux", any(target_arch = "aarch64", target_arch = "x86_64"))))]
compile_error!("extrasafe is currently only supported on arm64 and amd64 linux");

let seccompiler_filter = SeccompilerFilter::new(
rules_map,
Expand Down