diff options
| author | Valentin Popov <valentin@popov.link> | 2024-01-08 00:21:28 +0300 | 
|---|---|---|
| committer | Valentin Popov <valentin@popov.link> | 2024-01-08 00:21:28 +0300 | 
| commit | 1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch) | |
| tree | 7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/rustix/src/backend/linux_raw/runtime | |
| parent | 5ecd8cf2cba827454317368b68571df0d13d7842 (diff) | |
| download | fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.tar.xz fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.zip  | |
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
Diffstat (limited to 'vendor/rustix/src/backend/linux_raw/runtime')
| -rw-r--r-- | vendor/rustix/src/backend/linux_raw/runtime/mod.rs | 2 | ||||
| -rw-r--r-- | vendor/rustix/src/backend/linux_raw/runtime/syscalls.rs | 318 | ||||
| -rw-r--r-- | vendor/rustix/src/backend/linux_raw/runtime/tls.rs | 98 | 
3 files changed, 418 insertions, 0 deletions
diff --git a/vendor/rustix/src/backend/linux_raw/runtime/mod.rs b/vendor/rustix/src/backend/linux_raw/runtime/mod.rs new file mode 100644 index 0000000..0b48649 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/runtime/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod syscalls; +pub(crate) mod tls; diff --git a/vendor/rustix/src/backend/linux_raw/runtime/syscalls.rs b/vendor/rustix/src/backend/linux_raw/runtime/syscalls.rs new file mode 100644 index 0000000..e00acc6 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/runtime/syscalls.rs @@ -0,0 +1,318 @@ +//! linux_raw syscalls supporting `rustix::runtime`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + +use crate::backend::c; +#[cfg(target_arch = "x86")] +use crate::backend::conv::by_mut; +#[cfg(target_arch = "x86_64")] +use crate::backend::conv::c_uint; +use crate::backend::conv::{ +    by_ref, c_int, ret, ret_c_int, ret_c_int_infallible, ret_error, ret_infallible, ret_void_star, +    size_of, zero, +}; +#[cfg(feature = "fs")] +use crate::fd::BorrowedFd; +use crate::ffi::CStr; +#[cfg(feature = "fs")] +use crate::fs::AtFlags; +use crate::io; +use crate::pid::{Pid, RawPid}; +use crate::runtime::{Fork, How, Sigaction, Siginfo, Sigset, Stack}; +use crate::signal::Signal; +use crate::timespec::Timespec; +use crate::utils::option_as_ptr; +use core::ffi::c_void; +use core::mem::MaybeUninit; +#[cfg(target_pointer_width = "32")] +use linux_raw_sys::general::__kernel_old_timespec; +use linux_raw_sys::general::kernel_sigset_t; +#[cfg(target_arch = "x86_64")] +use linux_raw_sys::general::ARCH_SET_FS; + +#[inline] +pub(crate) unsafe fn fork() -> io::Result<Fork> { +    let mut child_pid = MaybeUninit::<RawPid>::uninit(); + +    // Unix `fork` only returns the child PID in the parent; we'd like it in +    // the child too, so set `CLONE_CHILD_SETTID` and pass in the address of +    // a memory location to store it to in the child. +    // +    // Architectures differ on the order of the parameters. +    #[cfg(target_arch = "x86_64")] +    let pid = ret_c_int(syscall_readonly!( +        __NR_clone, +        c_int(c::SIGCHLD | c::CLONE_CHILD_SETTID), +        zero(), +        zero(), +        &mut child_pid, +        zero() +    ))?; +    #[cfg(any( +        target_arch = "aarch64", +        target_arch = "arm", +        target_arch = "mips", +        target_arch = "mips32r6", +        target_arch = "mips64", +        target_arch = "mips64r6", +        target_arch = "powerpc64", +        target_arch = "riscv64", +        target_arch = "x86" +    ))] +    let pid = ret_c_int(syscall_readonly!( +        __NR_clone, +        c_int(c::SIGCHLD | c::CLONE_CHILD_SETTID), +        zero(), +        zero(), +        zero(), +        &mut child_pid +    ))?; + +    Ok(if let Some(pid) = Pid::from_raw(pid) { +        Fork::Parent(pid) +    } else { +        Fork::Child(Pid::from_raw_unchecked(child_pid.assume_init())) +    }) +} + +#[cfg(feature = "fs")] +pub(crate) unsafe fn execveat( +    dirfd: BorrowedFd<'_>, +    path: &CStr, +    args: *const *const u8, +    env_vars: *const *const u8, +    flags: AtFlags, +) -> io::Errno { +    ret_error(syscall_readonly!( +        __NR_execveat, +        dirfd, +        path, +        args, +        env_vars, +        flags +    )) +} + +pub(crate) unsafe fn execve( +    path: &CStr, +    args: *const *const u8, +    env_vars: *const *const u8, +) -> io::Errno { +    ret_error(syscall_readonly!(__NR_execve, path, args, env_vars)) +} + +pub(crate) mod tls { +    use super::*; +    #[cfg(target_arch = "x86")] +    use crate::backend::runtime::tls::UserDesc; + +    #[cfg(target_arch = "x86")] +    #[inline] +    pub(crate) unsafe fn set_thread_area(u_info: &mut UserDesc) -> io::Result<()> { +        ret(syscall!(__NR_set_thread_area, by_mut(u_info))) +    } + +    #[cfg(target_arch = "arm")] +    #[inline] +    pub(crate) unsafe fn arm_set_tls(data: *mut c::c_void) -> io::Result<()> { +        ret(syscall_readonly!(__ARM_NR_set_tls, data)) +    } + +    #[cfg(target_arch = "x86_64")] +    #[inline] +    pub(crate) unsafe fn set_fs(data: *mut c::c_void) { +        ret_infallible(syscall_readonly!( +            __NR_arch_prctl, +            c_uint(ARCH_SET_FS), +            data, +            zero(), +            zero(), +            zero() +        )) +    } + +    #[inline] +    pub(crate) unsafe fn set_tid_address(data: *mut c::c_void) -> Pid { +        let tid: i32 = ret_c_int_infallible(syscall_readonly!(__NR_set_tid_address, data)); +        Pid::from_raw_unchecked(tid) +    } + +    #[inline] +    pub(crate) fn exit_thread(code: c::c_int) -> ! { +        unsafe { syscall_noreturn!(__NR_exit, c_int(code)) } +    } +} + +#[inline] +pub(crate) unsafe fn sigaction(signal: Signal, new: Option<Sigaction>) -> io::Result<Sigaction> { +    let mut old = MaybeUninit::<Sigaction>::uninit(); +    let new = option_as_ptr(new.as_ref()); +    ret(syscall!( +        __NR_rt_sigaction, +        signal, +        new, +        &mut old, +        size_of::<kernel_sigset_t, _>() +    ))?; +    Ok(old.assume_init()) +} + +#[inline] +pub(crate) unsafe fn sigaltstack(new: Option<Stack>) -> io::Result<Stack> { +    let mut old = MaybeUninit::<Stack>::uninit(); +    let new = option_as_ptr(new.as_ref()); +    ret(syscall!(__NR_sigaltstack, new, &mut old))?; +    Ok(old.assume_init()) +} + +#[inline] +pub(crate) unsafe fn tkill(tid: Pid, sig: Signal) -> io::Result<()> { +    ret(syscall_readonly!(__NR_tkill, tid, sig)) +} + +#[inline] +pub(crate) unsafe fn sigprocmask(how: How, new: Option<&Sigset>) -> io::Result<Sigset> { +    let mut old = MaybeUninit::<Sigset>::uninit(); +    let new = option_as_ptr(new); +    ret(syscall!( +        __NR_rt_sigprocmask, +        how, +        new, +        &mut old, +        size_of::<kernel_sigset_t, _>() +    ))?; +    Ok(old.assume_init()) +} + +#[inline] +pub(crate) fn sigpending() -> Sigset { +    let mut pending = MaybeUninit::<Sigset>::uninit(); +    unsafe { +        ret_infallible(syscall!( +            __NR_rt_sigpending, +            &mut pending, +            size_of::<kernel_sigset_t, _>() +        )); +        pending.assume_init() +    } +} + +#[inline] +pub(crate) fn sigsuspend(set: &Sigset) -> io::Result<()> { +    unsafe { +        ret(syscall_readonly!( +            __NR_rt_sigsuspend, +            by_ref(set), +            size_of::<kernel_sigset_t, _>() +        )) +    } +} + +#[inline] +pub(crate) fn sigwait(set: &Sigset) -> io::Result<Signal> { +    unsafe { +        match Signal::from_raw(ret_c_int(syscall_readonly!( +            __NR_rt_sigtimedwait, +            by_ref(set), +            zero(), +            zero(), +            size_of::<kernel_sigset_t, _>() +        ))?) { +            Some(signum) => Ok(signum), +            None => Err(io::Errno::NOTSUP), +        } +    } +} + +#[inline] +pub(crate) fn sigwaitinfo(set: &Sigset) -> io::Result<Siginfo> { +    let mut info = MaybeUninit::<Siginfo>::uninit(); +    unsafe { +        let _signum = ret_c_int(syscall!( +            __NR_rt_sigtimedwait, +            by_ref(set), +            &mut info, +            zero(), +            size_of::<kernel_sigset_t, _>() +        ))?; +        Ok(info.assume_init()) +    } +} + +#[inline] +pub(crate) fn sigtimedwait(set: &Sigset, timeout: Option<Timespec>) -> io::Result<Siginfo> { +    let mut info = MaybeUninit::<Siginfo>::uninit(); +    let timeout_ptr = option_as_ptr(timeout.as_ref()); + +    // `rt_sigtimedwait_time64` was introduced in Linux 5.1. The old +    // `rt_sigtimedwait` syscall is not y2038-compatible on 32-bit +    // architectures. +    #[cfg(target_pointer_width = "32")] +    unsafe { +        match ret_c_int(syscall!( +            __NR_rt_sigtimedwait_time64, +            by_ref(set), +            &mut info, +            timeout_ptr, +            size_of::<kernel_sigset_t, _>() +        )) { +            Ok(_signum) => (), +            Err(io::Errno::NOSYS) => sigtimedwait_old(set, timeout, &mut info)?, +            Err(err) => return Err(err), +        } +        Ok(info.assume_init()) +    } + +    #[cfg(target_pointer_width = "64")] +    unsafe { +        let _signum = ret_c_int(syscall!( +            __NR_rt_sigtimedwait, +            by_ref(set), +            &mut info, +            timeout_ptr, +            size_of::<kernel_sigset_t, _>() +        ))?; +        Ok(info.assume_init()) +    } +} + +#[cfg(target_pointer_width = "32")] +unsafe fn sigtimedwait_old( +    set: &Sigset, +    timeout: Option<Timespec>, +    info: &mut MaybeUninit<Siginfo>, +) -> io::Result<()> { +    let old_timeout = match timeout { +        Some(timeout) => Some(__kernel_old_timespec { +            tv_sec: timeout.tv_sec.try_into().map_err(|_| io::Errno::OVERFLOW)?, +            tv_nsec: timeout.tv_nsec as _, +        }), +        None => None, +    }; + +    let old_timeout_ptr = option_as_ptr(old_timeout.as_ref()); + +    let _signum = ret_c_int(syscall!( +        __NR_rt_sigtimedwait, +        by_ref(set), +        info, +        old_timeout_ptr, +        size_of::<kernel_sigset_t, _>() +    ))?; + +    Ok(()) +} + +#[inline] +pub(crate) fn exit_group(code: c::c_int) -> ! { +    unsafe { syscall_noreturn!(__NR_exit_group, c_int(code)) } +} + +#[inline] +pub(crate) unsafe fn brk(addr: *mut c::c_void) -> io::Result<*mut c_void> { +    // This is non-`readonly`, to prevent loads from being reordered past it. +    ret_void_star(syscall!(__NR_brk, addr)) +} diff --git a/vendor/rustix/src/backend/linux_raw/runtime/tls.rs b/vendor/rustix/src/backend/linux_raw/runtime/tls.rs new file mode 100644 index 0000000..69bd5ce --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/runtime/tls.rs @@ -0,0 +1,98 @@ +//! TLS utilities. +//! +//! # Safety +//! +//! This file contains code that reads the raw phdr array pointed to by the +//! kernel-provided AUXV values. +#![allow(unsafe_code)] + +use crate::backend::c; +use crate::backend::param::auxv::exe_phdrs; +use core::arch::global_asm; +use core::ptr::{null, NonNull}; +use linux_raw_sys::elf::*; + +/// For use with [`set_thread_area`]. +/// +/// [`set_thread_area`]: crate::runtime::set_thread_area +#[cfg(target_arch = "x86")] +pub type UserDesc = linux_raw_sys::general::user_desc; + +pub(crate) fn startup_tls_info() -> StartupTlsInfo { +    let mut base = null(); +    let mut tls_phdr = null(); +    let mut stack_size = 0; + +    let (first_phdr, phent, phnum) = exe_phdrs(); +    let mut current_phdr = first_phdr.cast::<Elf_Phdr>(); + +    // The dynamic address of the dynamic section, which we can compare with +    // the `PT_DYNAMIC` header's static address, if present. +    let dynamic_addr: *const c::c_void = unsafe { &_DYNAMIC }; + +    // SAFETY: We assume the phdr array pointer and length the kernel provided +    // to the process describe a valid phdr array. +    unsafe { +        let phdrs_end = current_phdr.cast::<u8>().add(phnum * phent).cast(); +        while current_phdr != phdrs_end { +            let phdr = &*current_phdr; +            current_phdr = current_phdr.cast::<u8>().add(phent).cast(); + +            match phdr.p_type { +                // Compute the offset from the static virtual addresses +                // in the `p_vaddr` fields to the dynamic addresses. We don't +                // always get a `PT_PHDR` or `PT_DYNAMIC` header, so use +                // whichever one we get. +                PT_PHDR => base = first_phdr.cast::<u8>().wrapping_sub(phdr.p_vaddr), +                PT_DYNAMIC => base = dynamic_addr.cast::<u8>().wrapping_sub(phdr.p_vaddr), + +                PT_TLS => tls_phdr = phdr, +                PT_GNU_STACK => stack_size = phdr.p_memsz, +                _ => {} +            } +        } + +        if tls_phdr.is_null() { +            StartupTlsInfo { +                addr: NonNull::dangling().as_ptr(), +                mem_size: 0, +                file_size: 0, +                align: 1, +                stack_size: 0, +            } +        } else { +            StartupTlsInfo { +                addr: base.cast::<u8>().wrapping_add((*tls_phdr).p_vaddr).cast(), +                mem_size: (*tls_phdr).p_memsz, +                file_size: (*tls_phdr).p_filesz, +                align: (*tls_phdr).p_align, +                stack_size, +            } +        } +    } +} + +extern "C" { +    /// Declare the `_DYNAMIC` symbol so that we can compare its address with +    /// the static address in the `PT_DYNAMIC` header to learn our offset. Use +    /// a weak symbol because `_DYNAMIC` is not always present. +    static _DYNAMIC: c::c_void; +} +// Rust has `extern_weak` but it isn't stable, so use a `global_asm`. +global_asm!(".weak _DYNAMIC"); + +/// The values returned from [`startup_tls_info`]. +/// +/// [`startup_tls_info`]: crate::runtime::startup_tls_info +pub struct StartupTlsInfo { +    /// The base address of the TLS segment. +    pub addr: *const c::c_void, +    /// The size of the memory region. +    pub mem_size: usize, +    /// The size beyond which all memory is zero-initialized. +    pub file_size: usize, +    /// The required alignment for the TLS segment. +    pub align: usize, +    /// The requested minimum size for stacks. +    pub stack_size: usize, +}  | 
