diff --git a/system/linux/syscalls/src/aarch64.rs b/system/linux/syscalls/src/aarch64.rs index f5e6875..522d9a5 100644 --- a/system/linux/syscalls/src/aarch64.rs +++ b/system/linux/syscalls/src/aarch64.rs @@ -5,20 +5,54 @@ use core::arch::asm; #[non_exhaustive] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Sysno { + /// + Dup = 23, + /// + Fcntl = 25, + /// + Fstatfs = 44, + /// + Ftruncate = 46, + /// + Chdir = 49, + /// + Fchdir = 50, + /// + Chroot = 51, + /// + Fchmod = 52, + /// + Fchown = 55, /// Openat = 56, /// Close = 57, /// Write = 64, + /// + Fstat = 80, + /// + Fsync = 82, + /// + Acct = 89, /// Exit = 93, + /// + DeleteModule = 106, /// Kill = 129, + /// + Adjtimex = 171, /// Getpid = 172, + /// + Brk = 214, /// Mremap = 216, + /// + Clone = 220, + /// + Execve = 221, /// Mmap = 222, } diff --git a/system/linux/syscalls/src/lib.rs b/system/linux/syscalls/src/lib.rs index d3311cb..1f668c3 100644 --- a/system/linux/syscalls/src/lib.rs +++ b/system/linux/syscalls/src/lib.rs @@ -15,13 +15,41 @@ pub mod arch { pub use super::x86_64::*; } -use libc::{c_char, c_int, c_void, mode_t, off_t, pid_t, size_t, ssize_t}; +use libc::{ + c_char, c_int, c_long, c_ulong, c_void, gid_t, mode_t, off_t, pid_t, + size_t, ssize_t, stat, statfs, timex, uid_t, +}; + +#[cfg(not(target_arch = "aarch64"))] +use libc::c_uint; #[cfg(not(miri))] use arch::{ Sysno, syscall0, syscall1, syscall2, syscall3, syscall4, syscall5, syscall6, }; +#[cfg(miri)] +use core::ptr; + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +/// On success, the child process receives 0 and the parent receives the child's +/// PID. +#[cfg(not(target_arch = "aarch64"))] +pub fn fork() -> pid_t { + // SAFETY: fork is safe to call. + #[cfg(not(miri))] + return unsafe { syscall0(Sysno::Fork) } as _; + + #[cfg(miri)] + { + // Syscall not supported by Miri + -libc::ENOSYS as pid_t + } +} + /// /// /// Returns the raw kernel return value. @@ -38,6 +66,131 @@ pub fn getpid() -> pid_t { } } +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +/// +/// # Safety +/// - `path` must a pointer to a null-terminated string, +/// that must be readable until the null terminator (see [`core::ptr::read`]), +/// or [`core::ptr::null()`] to disable accounting. +pub unsafe fn acct(path: *const c_char) -> c_int { + // SAFETY: guaranteed by caller. + #[cfg(not(miri))] + return unsafe { syscall1(Sysno::Acct, path.addr()) } as _; + + #[cfg(miri)] + { + _ = path; + // Syscall not supported by Miri + -libc::ENOSYS as c_int + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +/// +/// # Safety +/// - `buf` must be a valid pointer to a [`timex`] struct, +/// that must be readable/writable until the syscall completes +/// (see [`core::ptr::read`] and [`core::ptr::write`] for details). +pub unsafe fn adjtimex(buf: *mut timex) -> c_int { + // SAFETY: guaranteed by caller. + #[cfg(not(miri))] + return unsafe { syscall1(Sysno::Adjtimex, buf.addr()) } as _; + + #[cfg(miri)] + { + _ = buf; + // Syscall not supported by Miri + -libc::ENOSYS as c_int + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +#[cfg(not(target_arch = "aarch64"))] +pub fn alarm(seconds: c_uint) -> c_uint { + // SAFETY: alarm is safe to call. + #[cfg(not(miri))] + return unsafe { syscall1(Sysno::Alarm, seconds as _) } as _; + + // Syscall not supported by Miri + #[cfg(miri)] + { + _ = seconds; + 0 + } +} + +/// +/// +/// Returns the raw kernel return value. +/// +/// # Safety +/// On success, any pointers or references to memory with an address greater +/// than or equal to `addr` are no longer valid if `addr` is less than the +/// current program break value. +pub unsafe fn brk(addr: *mut c_void) -> *mut c_void { + // SAFETY: guaranteed by caller. + #[cfg(not(miri))] + return unsafe { syscall1(Sysno::Brk, addr.addr()) } as _; + + #[cfg(miri)] + { + _ = addr; + // Syscall not supported by Miri + ptr::null_mut() + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +/// +/// # Safety +/// - `path` must a pointer to a null-terminated string, +/// that must be readable until the null terminator (see [`core::ptr::read`]). +pub unsafe fn chdir(path: *const c_char) -> c_int { + // SAFETY: guaranteed by caller. + #[cfg(not(miri))] + return unsafe { syscall1(Sysno::Chdir, path.addr()) } as _; + + #[cfg(miri)] + { + _ = path; + // Syscall not supported by Miri (when isolation is enabled) + -libc::ENOSYS as c_int + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +/// +/// # Safety +/// - `path` must a pointer to a null-terminated string, +/// that must be readable until the null terminator (see [`core::ptr::read`]). +pub unsafe fn chroot(path: *const c_char) -> c_int { + // SAFETY: guaranteed by caller. + #[cfg(not(miri))] + return unsafe { syscall1(Sysno::Chroot, path.addr()) } as _; + + #[cfg(miri)] + { + _ = path; + // Syscall not supported by Miri + -libc::ENOSYS as c_int + } +} + /// /// /// Returns the raw kernel return value. @@ -54,6 +207,22 @@ pub fn close(fd: c_int) -> c_int { } } +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +pub fn dup(oldfd: c_int) -> c_int { + // SAFETY: dup is safe to call. + #[cfg(not(miri))] + return unsafe { syscall1(Sysno::Dup, oldfd as _) } as _; + + // SAFETY: dup is safe to call. + #[cfg(miri)] + unsafe { + libc::dup(oldfd) + } +} + /// /// /// Returns the raw kernel return value. @@ -77,6 +246,255 @@ pub fn exit(status: c_int) -> ! { } } +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +pub fn fchdir(fd: c_int) -> c_int { + // SAFETY: fchdir is safe to call. + #[cfg(not(miri))] + return unsafe { syscall1(Sysno::Fchdir, fd as _) } as _; + + #[cfg(miri)] + { + _ = fd; + // Syscall not supported by Miri + -libc::ENOSYS as c_int + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +/// +/// # Safety +/// - `path` must a pointer to a null-terminated string, +/// that must be readable until the null terminator (see [`core::ptr::read`]). +#[cfg(not(target_arch = "aarch64"))] +pub unsafe fn access(path: *const c_char, mode: c_int) -> c_int { + // SAFETY: access is safe to call. + #[cfg(not(miri))] + return unsafe { syscall2(Sysno::Access, path.addr(), mode as _) } as _; + + #[cfg(miri)] + { + _ = path; + _ = mode; + // Syscall not supported by Miri + -libc::ENOSYS as c_int + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +/// +/// # Safety +/// - `path` must a pointer to a null-terminated string, +/// that must be readable until the null terminator (see [`core::ptr::read`]). +#[cfg(not(target_arch = "aarch64"))] +pub unsafe fn chmod(path: *const c_char, mode: mode_t) -> c_int { + // SAFETY: guaranteed by caller. + #[cfg(not(miri))] + return unsafe { syscall2(Sysno::Chmod, path.addr(), mode as _) } as _; + + #[cfg(miri)] + { + _ = path; + _ = mode; + // Syscall not supported by Miri + -libc::ENOSYS as c_int + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +/// +/// # Safety +/// - `path` must a pointer to a null-terminated string, +/// that must be readable until the null terminator (see [`core::ptr::read`]). +#[cfg(not(target_arch = "aarch64"))] +pub unsafe fn creat(path: *const c_char, mode: mode_t) -> c_int { + // SAFETY: guaranteed by caller. + #[cfg(not(miri))] + return unsafe { syscall2(Sysno::Creat, path.addr(), mode as _) } as _; + + #[cfg(miri)] + { + _ = path; + _ = mode; + // Syscall not supported by Miri + -libc::ENOSYS as c_int + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +/// +/// # Safety +/// - `name` must a pointer to a null-terminated string, +/// that must be readable until the null terminator (see [`core::ptr::read`]). +#[cfg(not(target_arch = "aarch64"))] +pub unsafe fn create_module(name: *const c_char, size: size_t) -> c_long { + // SAFETY: guaranteed by caller. + #[cfg(not(miri))] + return unsafe { syscall2(Sysno::CreateModule, name.addr(), size as _) } + as _; + + #[cfg(miri)] + { + _ = name; + _ = size; + // Syscall not supported by Miri + -libc::ENOSYS as c_long + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +/// +/// # Safety +/// - `name` must a pointer to a null-terminated string, +/// that must be readable until the null terminator (see [`core::ptr::read`]). +pub unsafe fn delete_module(name: *const c_char, flags: c_int) -> c_int { + // SAFETY: guaranteed by caller. + #[cfg(not(miri))] + return unsafe { syscall2(Sysno::DeleteModule, name.addr(), flags as _) } + as _; + + #[cfg(miri)] + { + _ = name; + _ = flags; + // Syscall not supported by Miri + -libc::ENOSYS as c_int + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +pub fn fchmod(fd: c_int, mode: mode_t) -> c_int { + // SAFETY: fchmod is safe to call. + #[cfg(not(miri))] + return unsafe { syscall2(Sysno::Fchmod, fd as _, mode as _) } as _; + + #[cfg(miri)] + { + _ = fd; + _ = mode; + // Syscall not supported by Miri + -libc::ENOSYS as c_int + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +/// +/// # Safety +/// - `statbuf` must be a valid pointer to a [`stat`] struct, +/// that must be writable for the duration of the syscall +/// (see [`core::ptr::write`] for details). +pub unsafe fn fstat(fd: c_int, statbuf: *mut stat) -> c_int { + // SAFETY: guaranteed by caller. + #[cfg(not(miri))] + return unsafe { syscall2(Sysno::Fstat, fd as _, statbuf.addr()) } as _; + + #[cfg(miri)] + { + _ = fd; + _ = statbuf; + // Syscall not supported by Miri (when isolation is enabled) + -libc::ENOSYS as c_int + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +/// +/// # Safety +/// - `buf` must be a valid pointer to a [`statfs`] struct, +/// that must be writable for the duration of the syscall +/// (see [`core::ptr::write`] for details). +pub unsafe fn fstatfs(fd: c_int, buf: *mut statfs) -> c_int { + // SAFETY: guaranteed by caller. + #[cfg(not(miri))] + return unsafe { syscall2(Sysno::Fstatfs, fd as _, buf.addr()) } as _; + + #[cfg(miri)] + { + _ = fd; + _ = buf; + // Syscall not supported by Miri + -libc::ENOSYS as c_int + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +pub fn ftruncate(fd: c_int, length: off_t) -> c_int { + // SAFETY: ftruncate is safe to call. + #[cfg(not(miri))] + return unsafe { syscall2(Sysno::Ftruncate, fd as _, length as _) } as _; + + #[cfg(miri)] + { + _ = fd; + _ = length; + // Syscall not supported by Miri (when isolation is enabled) + -libc::ENOSYS as c_int + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +pub fn fsync(fd: c_int) -> c_int { + // SAFETY: fsync is safe to call. + #[cfg(not(miri))] + return unsafe { syscall1(Sysno::Fsync, fd as _) } as _; + + #[cfg(miri)] + { + _ = fd; + // Syscall not supported by Miri (when isolation is enabled) + -libc::ENOSYS as c_int + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +#[cfg(not(target_arch = "aarch64"))] +pub fn dup2(oldfd: c_int, newfd: c_int) -> c_int { + // SAFETY: dup2 is safe to call. + #[cfg(not(miri))] + return unsafe { syscall2(Sysno::Dup2, oldfd as _, newfd as _) } as _; + + // SAFETY: dup2 is safe to call. + #[cfg(miri)] + unsafe { + libc::dup2(oldfd, newfd) + } +} + /// /// /// Returns the raw kernel return value. @@ -95,6 +513,79 @@ pub fn kill(pid: pid_t, sig: c_int) -> c_int { } } +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +/// On success, this function does not return (the process image is replaced). +/// +/// # Safety +/// - `path` must be a pointer to a null-terminated string, +/// that must be readable until the null terminator (see [`core::ptr::read`]). +/// - `argv` must be a pointer to an array of pointers to null-terminated +/// strings, terminated by a null pointer. Each string must be readable +/// until the null terminator. +/// - `envp` must be a pointer to an array of pointers to null-terminated +/// strings (or [`core::ptr::null()`] for an empty environment), terminated +/// by a null pointer. Each string must be readable until the null +/// terminator. +pub unsafe fn execve( + path: *const c_char, + argv: *const *const c_char, + envp: *const *const c_char, +) -> c_int { + // SAFETY: guaranteed by caller. + #[cfg(not(miri))] + return unsafe { + syscall3(Sysno::Execve, path.addr(), argv.addr(), envp.addr()) + } as _; + + #[cfg(miri)] + { + _ = path; + _ = argv; + _ = envp; + // Syscall not supported by Miri + -libc::ENOSYS as c_int + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +pub fn fchown(fd: c_int, owner: uid_t, group: gid_t) -> c_int { + // SAFETY: fchown is safe to call. + #[cfg(not(miri))] + return unsafe { syscall3(Sysno::Fchown, fd as _, owner as _, group as _) } + as _; + + #[cfg(miri)] + { + _ = fd; + _ = owner; + _ = group; + // Syscall not supported by Miri + -libc::ENOSYS as c_int + } +} + +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +pub fn fcntl(fd: c_int, cmd: c_int, arg: c_int) -> c_int { + // SAFETY: fcntl is safe to call. + #[cfg(not(miri))] + return unsafe { syscall3(Sysno::Fcntl, fd as _, cmd as _, arg as _) } as _; + + // SAFETY: fcntl is safe to call. + #[cfg(miri)] + unsafe { + libc::fcntl(fd, cmd, arg) + } +} + /// /// /// Returns the raw kernel return value. @@ -152,6 +643,74 @@ pub unsafe fn openat( } } +/// +/// +/// Returns the raw kernel return value. +/// Negative values in `[-4095, -1]` represent `errno`. +/// +/// # Safety +/// - If this call succeeds, execution continues in both the parent and the +/// child. The caller must ensure that running the child with the provided +/// `flags` is sound. +/// - If the child will run on `stack`, `stack` must point to writable memory +/// that is valid for use as the child stack. +/// - If `flags` contains [`libc::CLONE_PARENT_SETTID`], `parent_tid` must be a +/// valid writable pointer to a [`c_int`] until the syscall completes. +/// - If `flags` contains [`libc::CLONE_CHILD_SETTID`], `child_tid` must point +/// to writable memory where the kernel may store the child TID in the child. +/// - If `flags` contains [`libc::CLONE_CHILD_CLEARTID`], `child_tid` must +/// point to writable memory that remains valid until the child exits, +/// because the kernel may clear it at thread exit. +/// - If `flags` contains [`libc::CLONE_SETTLS`], `tls` must be a valid TLS +/// value for the new thread. +/// - If the child shares memory with the parent, the caller must ensure that no +/// pointers, references, or other Rust aliasing assumptions are violated. +pub unsafe fn clone( + flags: c_ulong, + stack: *mut c_void, + parent_tid: *mut c_int, + child_tid: *mut c_int, + tls: c_ulong, +) -> c_long { + #[cfg(not(miri))] + { + #[cfg(target_arch = "x86_64")] + return unsafe { + syscall5( + Sysno::Clone, + flags as _, + stack.addr(), + parent_tid.addr(), + child_tid.addr(), + tls as _, + ) + } as _; + + #[cfg(target_arch = "aarch64")] + return unsafe { + syscall5( + Sysno::Clone, + flags as _, + stack.addr(), + parent_tid.addr(), + tls as _, + child_tid.addr(), + ) + } as _; + } + + #[cfg(miri)] + { + _ = flags; + _ = stack; + _ = parent_tid; + _ = child_tid; + _ = tls; + // Syscall not supported by Miri + -libc::ENOSYS as c_long + } +} + /// /// /// Returns the raw kernel return value. @@ -198,8 +757,8 @@ pub unsafe fn mremap( /// Negative values in `[-4095, -1]` represent `errno`. /// /// # Safety -/// - If `flags` contains [`libc::MAP_FIXED`], the range `[addr, addr + length)` must -/// not overlap any existing mapping that should be preserved; the kernel +/// - If `flags` contains [`libc::MAP_FIXED`], the range `[addr, addr + length)` +/// must not overlap any existing mapping that should be preserved; the kernel /// will silently clobber it, invalidating any pointers or references into /// that region. pub unsafe fn mmap( @@ -235,16 +794,94 @@ pub unsafe fn mmap( mod tests { use core::ptr; - use super::{close, getpid, mmap, mremap, write}; + use super::{close, dup, fcntl, getpid, mmap, mremap, write}; + + #[cfg(not(target_arch = "aarch64"))] + use super::dup2; + + #[cfg(not(any(miri, target_arch = "aarch64")))] + use super::{access, alarm, chmod, creat, create_module, fork}; #[cfg(not(miri))] - use super::{kill, openat}; + use { + super::{ + acct, adjtimex, brk, chdir, chroot, clone, delete_module, execve, + fchdir, fchmod, fchown, fstat, fstatfs, fsync, ftruncate, kill, + openat, + }, + core::mem::MaybeUninit, + libc::{c_char, c_ulong, stat, statfs, timex}, + }; + + #[test] + #[cfg(not(any(miri, target_arch = "aarch64")))] + fn test_fork() { + fork(); + // Both parent and child continue here without checking result + // to maintain determinism. + } #[test] fn test_getpid() { assert!(getpid() > 0); } + #[test] + #[cfg(not(miri))] + fn test_acct() { + // will fail due to lack of permission + let ret = unsafe { acct(ptr::null()) }; + + assert!(ret < 0); + } + + #[test] + #[cfg(not(miri))] + fn test_adjtimex() { + let mut tx: MaybeUninit = MaybeUninit::zeroed(); + + // SAFETY: we are passing a valid pointer to a `timex` struct. + let ret = unsafe { adjtimex((&raw mut tx).cast()) }; + + assert!(ret >= 0); + } + + #[test] + #[cfg(not(any(miri, target_arch = "aarch64")))] + fn test_alarm() { + _ = alarm(0); // cancel any pending alarm + } + + #[test] + #[cfg(not(miri))] + fn test_brk() { + // SAFETY: we are passing a obviously invalid pointer to `brk`, which + // should return the current program break instead of changing it. + _ = unsafe { brk(ptr::null_mut()) }; + } + + #[test] + #[cfg(not(miri))] + fn test_chdir() { + // SAFETY: the pointer we are passing is readable until the null + // terminator (which is the only byte). + let ret = unsafe { chdir(c"".as_ptr()) }; + + assert!(ret < 0); // chdir should fail with an empty path + } + + #[test] + #[cfg(not(miri))] + fn test_chroot() { + // SAFETY: the pointer we are passing is readable until the null + // terminator (which is the only byte). + let ret = unsafe { chroot(c"".as_ptr()) }; + + // chroot should fail with an empty path, and lack + // of permissions + assert!(ret < 0); + } + #[test] fn test_close() { let ret = close(-1); @@ -252,6 +889,128 @@ mod tests { assert!(ret < 0); } + #[test] + fn test_dup() { + let ret = dup(-1); + + assert!(ret < 0); + } + + #[test] + #[cfg(not(miri))] + fn test_fchdir() { + let ret = fchdir(-1); + + assert!(ret < 0); + } + + #[test] + #[cfg(not(any(miri, target_arch = "aarch64")))] + fn test_access() { + // SAFETY: the pointer we are passing is readable until the null + // terminator (which is the only byte). + let ret = unsafe { access(c"".as_ptr(), 0) }; + + assert!(ret < 0); + } + + #[test] + #[cfg(not(any(miri, target_arch = "aarch64")))] + fn test_chmod() { + // SAFETY: the pointer we are passing is readable until the null + // terminator (which is the only byte). + let ret = unsafe { chmod(c"".as_ptr(), 0) }; + + assert!(ret < 0); + } + + #[test] + #[cfg(not(any(miri, target_arch = "aarch64")))] + fn test_creat() { + // SAFETY: the pointer we are passing is readable until the null + // terminator (which is the only byte). + let ret = unsafe { creat(c"".as_ptr(), 0) }; + + assert!(ret < 0); + } + + #[test] + #[cfg(not(any(miri, target_arch = "aarch64")))] + fn test_create_module() { + // SAFETY: the pointer we are passing is readable until the null + // terminator (which is the only byte). + let ret = unsafe { create_module(c"".as_ptr(), 0) }; + + // will most likely be -ENOSYS since the syscall was removed in + // Linux 2.6. + assert!(ret < 0); + } + + #[test] + #[cfg(not(miri))] + fn test_delete_module() { + // SAFETY: the pointer we are passing is readable until the null + // terminator (which is the only byte). + let ret = unsafe { delete_module(c"".as_ptr(), 0) }; + + // will fail due to lack of permission and invalid module name + assert!(ret < 0); + } + + #[test] + #[cfg(not(target_arch = "aarch64"))] + fn test_dup2() { + let ret = dup2(-1, -1); + + assert!(ret < 0); + } + + #[test] + #[cfg(not(miri))] + fn test_fchmod() { + let ret = fchmod(-1, 0); + + assert!(ret < 0); + } + + #[test] + #[cfg(not(miri))] + fn test_fstat() { + let mut statbuf: MaybeUninit = MaybeUninit::uninit(); + + // SAFETY: we are passing a valid pointer to a `stat` struct. + let ret = unsafe { fstat(-1, (&raw mut statbuf).cast()) }; + + assert!(ret < 0); + } + + #[test] + #[cfg(not(miri))] + fn test_fstatfs() { + let mut buf: MaybeUninit = MaybeUninit::uninit(); + + // SAFETY: we are passing a valid pointer to a `statfs` struct. + let ret = unsafe { fstatfs(-1, (&raw mut buf).cast()) }; + + assert!(ret < 0); + } + + #[test] + #[cfg(not(miri))] + fn test_ftruncate() { + let ret = ftruncate(-1, 0); + + assert!(ret < 0); + } + + #[test] + #[cfg(not(miri))] + fn test_fsync() { + let ret = fsync(-1); + + assert!(ret < 0); + } + #[test] #[cfg(not(miri))] fn test_kill() { @@ -262,6 +1021,34 @@ mod tests { assert_eq!(ret, 0); } + #[test] + #[cfg(not(miri))] + fn test_execve() { + // SAFETY: the pointers we are passing point to valid null-terminated + // strings/arrays, and execve will fail due to invalid path. + let argv = [ptr::null::()]; + let envp = [ptr::null::()]; + let ret = unsafe { execve(c"".as_ptr(), argv.as_ptr(), envp.as_ptr()) }; + + // execve will fail with an empty path + assert!(ret < 0); + } + + #[test] + #[cfg(not(miri))] + fn test_fchown() { + let ret = fchown(-1, 0, 0); + + assert!(ret < 0); + } + + #[test] + fn test_fcntl() { + let ret = fcntl(-1, 0, 0); + + assert!(ret < 0); + } + #[test] fn test_write() { let msg = b"test\n"; @@ -283,6 +1070,23 @@ mod tests { assert!(ret < 0); } + #[test] + #[cfg(not(miri))] + fn test_clone() { + // SAFETY: the call will fail due to invalid flags + let ret = unsafe { + clone( + (libc::CLONE_SIGHAND | libc::CLONE_CLEAR_SIGHAND) as c_ulong, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + 0, + ) + }; + + assert!(ret < 0); + } + #[test] fn test_mremap() { // SAFETY: we are not using `libc::MREMAP_FIXED`, and this won't diff --git a/system/linux/syscalls/src/x86_64.rs b/system/linux/syscalls/src/x86_64.rs index 8212a27..8cc39d1 100644 --- a/system/linux/syscalls/src/x86_64.rs +++ b/system/linux/syscalls/src/x86_64.rs @@ -9,16 +9,64 @@ pub enum Sysno { Write = 1, /// Close = 3, + /// + Fstat = 5, /// Mmap = 9, + /// + Brk = 12, + /// + Access = 21, /// Mremap = 25, + /// + Dup = 32, + /// + Dup2 = 33, + /// + Alarm = 37, /// Getpid = 39, + /// + Clone = 56, + /// + Fork = 57, + /// + Execve = 59, /// Exit = 60, /// Kill = 62, + /// + Fcntl = 72, + /// + Fsync = 74, + /// + Ftruncate = 77, + /// + Chdir = 80, + /// + Fchdir = 81, + /// + Creat = 85, + /// + Chmod = 90, + /// + Fchmod = 91, + /// + Fchown = 93, + /// + Fstatfs = 138, + /// + Adjtimex = 159, + /// + Chroot = 161, + /// + Acct = 163, + /// + CreateModule = 174, + /// + DeleteModule = 176, /// Openat = 257, }