//
// Syd: rock-solid application kernel
// src/hook.rs: Secure computing hooks
//
// Copyright (c) 2023, 2024, 2025 Ali Polatel <alip@chesswob.org>
// Based in part upon greenhook which is under public domain.
// MDWE code is based in part upon systemd which is LGPL-2.1-or-later.
// Personality code is based on pacwrap which is GPL-3.0-only.
//
// SPDX-License-Identifier: GPL-3.0

use std::{
    borrow::Cow,
    collections::{HashMap, HashSet},
    env,
    ffi::{CStr, CString, OsStr, OsString},
    fs::File,
    hash::{Hash, Hasher},
    io::{self, BufReader, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write},
    mem::MaybeUninit,
    net::IpAddr,
    os::{
        fd::{AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd},
        unix::ffi::OsStrExt,
    },
    str::FromStr,
    sync::{Arc, RwLock},
    thread::JoinHandle,
};

use ahash::RandomState;
use bitflags::bitflags;
use hex::DisplayHex;
use memchr::{arch::all::is_equal, memchr, memmem};
use nix::{
    errno::Errno,
    fcntl::{openat2, renameat, AtFlags, FallocateFlags, OFlag, OpenHow, ResolveFlag},
    libc::{pid_t, AT_FDCWD},
    mount::{mount, MsFlags},
    sys::{
        epoll::{Epoll, EpollCreateFlags},
        inotify::AddWatchFlags,
        prctl::{set_child_subreaper, set_dumpable, set_no_new_privs},
        ptrace,
        resource::{getrlimit, setrlimit, Resource},
        signal::{kill, killpg, SaFlags, Signal},
        socket::{
            bind, connect, getsockname, send, sendmsg, sendto, AddressFamily, ControlMessage,
            MsgFlags, SockFlag, SockType, SockaddrLike, SockaddrStorage, UnixCredentials,
        },
        stat::{fchmod, mkdirat, mknodat, umask, Mode, SFlag},
        time::TimeSpec,
        uio::{process_vm_readv, process_vm_writev, RemoteIoVec},
        wait::{Id, WaitPidFlag},
    },
    unistd::{
        chdir, chroot, fchdir, fchown, fchownat, getpgid, getpgrp, getresgid, getresuid, linkat,
        mkstemp, symlinkat, unlink, unlinkat, AccessFlags, Gid, Pid, Uid, UnlinkatFlags,
    },
    NixPath,
};
use once_cell::sync::Lazy;
use quick_cache::sync::GuardResult;
use serde::{ser::SerializeMap, Serialize};

use crate::{
    cache::{PathCap, SigreturnResult},
    caps,
    compat::{
        addr_family, cmsg_len_32, cmsg_space_32, fstatat64, fstatfs64, fstatx, ftruncate64,
        getdents64, getsockdomain, getxattrat, listxattrat, msghdr, msghdr32, removexattrat,
        setxattrat, statx, truncate64, waitid, TimeSpec32, TimeSpec64, WaitStatus, XattrArgs,
        PF_ALG, PF_INET, PF_INET6, PF_NETLINK, PF_UNIX, PF_UNSPEC, STATX_BASIC_STATS, STATX_INO,
        STATX_MNT_ID, STATX_MNT_ID_UNIQUE, STATX_MODE, STATX_TYPE,
    },
    config::*,
    debug,
    elf::{
        disasm, scmp_syscall_instruction, scmp_sysret_instruction, ElfError, ElfFileType, ElfType,
        ExecutableFile, LinkingType,
    },
    err::{err2no, SydError, SydResult},
    error,
    fs::{
        create_memfd, denyxattr, duprand, fanotify_mark, fd_mode, file_type, filterxattr,
        get_nonblock, has_recv_timeout, inotify_add_watch, is_executable, is_sidechannel_device,
        lock_fd, parse_fd, readlinkat, retry_on_eintr, safe_canonicalize, safe_open,
        safe_open_how_magicsym, safe_open_magicsym, safe_open_path, seal_memfd, set_nonblock,
        unlock_fd, CanonicalPath, FileType, FsFlags, MaybeFd, MFD_ALLOW_SEALING, MFD_CLOEXEC,
        MFD_EXEC, MFD_NOEXEC_SEAL,
    },
    hash::aes_ctr_tmp,
    info, is_coredump,
    landlock::RulesetStatus,
    libseccomp::{
        ScmpAction, ScmpArch, ScmpArgCompare, ScmpCompareOp, ScmpFilterContext, ScmpNotifResp,
        ScmpNotifRespFlags, ScmpSyscall, ScmpVersion,
    },
    libseccomp_sys::{seccomp_notif_addfd, __NR_SCMP_ERROR},
    log::log_untrusted_buf,
    log_enabled, notice, nsflag_name, op2errno, op2name,
    path::{dotdot_with_nul, XPath, XPathBuf, PATH_MAX, PATH_MIN},
    pool,
    pool::{AesMap, AesMod, WorkerCache},
    proc::{
        proc_auxv, proc_comm, proc_executables, proc_fs_file_max, proc_maps, proc_mem_limit,
        proc_set_at_secure, proc_stack_pointer, proc_statm, proc_status, proc_task_limit,
        proc_task_nr_syd, proc_task_nr_sys, proc_tgid, proc_tty, proc_umask,
    },
    ptrace::{
        ptrace_get_error, ptrace_get_syscall_info, ptrace_set_return, ptrace_skip_syscall,
        ptrace_syscall_info, ptrace_syscall_info_seccomp,
    },
    safe_drop_cap,
    sandbox::{
        Action, BindMount, Capability, Flags, IntegrityError, LockState, NetlinkFamily, Sandbox,
        SandboxGuard,
    },
    scmp_arch, scmp_arch_bits, scmp_arch_raw, scmp_big_endian, scmp_cmp, seccomp_add_architectures,
    seccomp_native_has_socketcall, set_cpu_priority_idle, set_io_priority_idle,
    spec::{
        speculation_get, speculation_set, SpeculationControlStatus, SpeculationFeature,
        SpeculationStatus, PR_GET_SPECULATION_CTRL, PR_SET_SPECULATION_CTRL, PR_SPEC_FORCE_DISABLE,
    },
    sysinfo::SysInfo,
    syslog::LogLevel,
    warn, IoctlRequest, ScmpNotifReq, SydArch, Sydcall, NAMESPACE_FLAGS, NAMESPACE_FLAGS_ALL,
    NAMESPACE_NAMES, SCMP_ARCH,
};

const UNIX_PATH_MAX: usize = 108;

const NONE: Option<&XPathBuf> = None::<&XPathBuf>;

const PROT_EXEC: u64 = libc::PROT_EXEC as u64;
const MAP_ANONYMOUS: u64 = libc::MAP_ANONYMOUS as u64;

const FD_MAX: u64 = i32::MAX as u64;

// TODO: Our version of nix does not have TimeSpec::UTIME_NOW.
const UTIME_NOW: TimeSpec = TimeSpec::new(0, libc::UTIME_NOW as libc::c_long);

/*
 * Personality values obtained from personality.h in the Linux kernel
 *
 * https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/uapi/linux/personality.h
 */
const PERSONALITY: u64 = if cfg!(target_pointer_width = "64") {
    0x0000
} else {
    0x0800000
};

/*
 * Seccomp constants
 */

#[cfg(target_env = "musl")]
pub(crate) const SECCOMP_IOCTL_NOTIF_RECV: IoctlRequest = 0xc0502100u32 as IoctlRequest;
#[cfg(not(target_env = "musl"))]
pub(crate) const SECCOMP_IOCTL_NOTIF_RECV: IoctlRequest = 0xc0502100;

#[cfg(target_env = "musl")]
pub(crate) const SECCOMP_IOCTL_NOTIF_SEND: IoctlRequest = 0xc0182101u32 as IoctlRequest;
#[cfg(not(target_env = "musl"))]
pub(crate) const SECCOMP_IOCTL_NOTIF_SEND: IoctlRequest = 0xc0182101;

#[cfg(any(
    target_arch = "mips",
    target_arch = "mips32r6",
    target_arch = "mips64",
    target_arch = "mips64r6",
    target_arch = "powerpc",
    target_arch = "powerpc64"
))]
pub(crate) const SECCOMP_IOCTL_NOTIF_ADDFD: IoctlRequest = 0x80182103;
#[cfg(not(any(
    target_arch = "mips",
    target_arch = "mips32r6",
    target_arch = "mips64",
    target_arch = "mips64r6",
    target_arch = "powerpc",
    target_arch = "powerpc64"
)))]
pub(crate) const SECCOMP_IOCTL_NOTIF_ADDFD: IoctlRequest = 0x40182103;

#[cfg(any(
    target_arch = "mips",
    target_arch = "mips32r6",
    target_arch = "mips64",
    target_arch = "mips64r6",
    target_arch = "powerpc",
    target_arch = "powerpc64"
))]
pub(crate) const SECCOMP_IOCTL_NOTIF_ID_VALID: IoctlRequest = 0x80082102;
#[cfg(not(any(
    target_arch = "mips",
    target_arch = "mips32r6",
    target_arch = "mips64",
    target_arch = "mips64r6",
    target_arch = "powerpc",
    target_arch = "powerpc64"
)))]
pub(crate) const SECCOMP_IOCTL_NOTIF_ID_VALID: IoctlRequest = 0x40082102;

#[cfg(any(
    target_arch = "mips",
    target_arch = "mips32r6",
    target_arch = "mips64",
    target_arch = "mips64r6",
    target_arch = "powerpc",
    target_arch = "powerpc64"
))]
pub(crate) const SECCOMP_IOCTL_NOTIF_SET_FLAGS: IoctlRequest = 0x80082104;
#[cfg(not(any(
    target_arch = "mips",
    target_arch = "mips32r6",
    target_arch = "mips64",
    target_arch = "mips64r6",
    target_arch = "powerpc",
    target_arch = "powerpc64"
)))]
pub(crate) const SECCOMP_IOCTL_NOTIF_SET_FLAGS: IoctlRequest = 0x40082104;

#[allow(clippy::unnecessary_cast)]
pub(crate) const SECCOMP_IOCTL_LIST: &[u64] = &[
    SECCOMP_IOCTL_NOTIF_ADDFD as u64,
    SECCOMP_IOCTL_NOTIF_ID_VALID as u64,
    SECCOMP_IOCTL_NOTIF_RECV as u64,
    SECCOMP_IOCTL_NOTIF_SEND as u64,
    SECCOMP_IOCTL_NOTIF_SET_FLAGS as u64,
];

/// Flag to set synchronous mode for the seccomp notify fd.
pub(crate) const SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP: u32 = 1;

/// Set seccomp notify fd flags, useful to set synchronous mode.
pub(crate) fn seccomp_notify_set_flags(fd: RawFd, flags: u32) -> Result<(), Errno> {
    if !*HAVE_SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP {
        return Err(Errno::ENOSYS);
    }

    retry_on_eintr(|| {
        // SAFETY: In libc we trust.
        Errno::result(unsafe { libc::ioctl(fd, SECCOMP_IOCTL_NOTIF_SET_FLAGS, flags) })
    })
    .map(drop)
}

/*
 * Macros
 */
macro_rules! syscall_handler {
    ($request:ident, $body:expr) => {{
        let request_id = $request.scmpreq.id;

        #[allow(clippy::arithmetic_side_effects)]
        match $body($request) {
            Ok(result) => result,
            Err(Errno::UnknownErrno) => ScmpNotifResp::new(request_id, 0, 0, 0),
            Err(errno) => ScmpNotifResp::new(request_id, 0, -(errno as i32), 0),
        }
    }};
}

/// Seccomp sandbox profile export modes.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum ExportMode {
    /// Berkeley Packet Filter (binary, machine readable)
    BerkeleyPacketFilter,
    /// Pseudo Filter Code (text, human readable)
    PseudoFiltercode,
}

impl FromStr for ExportMode {
    type Err = Errno;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_ascii_lowercase().as_str() {
            "bpf" => Ok(Self::BerkeleyPacketFilter),
            "pfc" => Ok(Self::PseudoFiltercode),
            _ => Err(Errno::EINVAL),
        }
    }
}

bitflags! {
    /// Flags for `SysArg`.
    #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
    pub(crate) struct SysFlags: u8 {
        /// Whether if it's ok for the path to be empty.
        const EMPTY_PATH = 1 << 0;
        /// The system call is not going to be emulated (unsafe!).
        const UNSAFE_CONT = 1 << 1;
    }
}

impl Serialize for SysFlags {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let mut flags: Vec<&str> = vec![];

        if self.is_empty() {
            return serializer.collect_seq(flags);
        }

        if self.contains(Self::EMPTY_PATH) {
            flags.push("empty-path");
        }
        if self.contains(Self::UNSAFE_CONT) {
            flags.push("unsafe-cont");
        }

        flags.sort();
        serializer.collect_seq(flags)
    }
}

// `OpenType` represents possible open family system calls.
//
//  The list of open family system calls are: creat(2), open(2),
//  openat(2), and openat2(2).
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum OpenSyscall {
    Creat,
    Open,
    Openat,
    Openat2,
}

/// `SysArg` represents a system call path argument,
/// coupled with a directory file descriptor as necessary.
#[derive(Copy, Clone, Debug, Default)]
pub(crate) struct SysArg {
    /// DirFd index in syscall args, if applicable.
    dirfd: Option<usize>,
    /// Path index in syscall args, if applicable.
    path: Option<usize>,
    /// Options for the system call.
    flags: SysFlags,
    /// Options for path canonicalization.
    fsflags: FsFlags,
    /// Whether dot as final component must return the given `Errno`.
    dotlast: Option<Errno>,
}

impl Serialize for SysArg {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let mut map = serializer.serialize_map(Some(5))?;
        map.serialize_entry("dirfd", &self.dirfd)?;
        map.serialize_entry("path", &self.path)?;
        map.serialize_entry("flags", &self.flags)?;
        map.serialize_entry("fsflags", &self.fsflags)?;
        map.serialize_entry("dotlast", &self.dotlast.map(|e| e as i32))?;
        map.end()
    }
}

impl SysArg {
    fn open(flags: OFlag, atfunc: bool, rflags: ResolveFlag) -> Self {
        let (dirfd, path) = if atfunc {
            (Some(0), Some(1))
        } else {
            (None, Some(0))
        };

        // SAFETY:
        // We do not resolve symbolic links if O_CREAT|O_EXCL is
        // specified to support creating files through dangling symbolic
        // links, see the creat_thru_dangling test for more information.
        // We also set MISS_LAST in this case so we get to assert EEXIST.
        let is_create = flags.contains(OFlag::O_CREAT);
        let is_exclusive_create = is_create && flags.contains(OFlag::O_EXCL);

        let mut fsflags = FsFlags::empty();
        if is_exclusive_create {
            fsflags.insert(FsFlags::MISS_LAST);
        } else if !(is_create || flags.contains(OFlag::O_TMPFILE)) {
            fsflags.insert(FsFlags::MUST_PATH);
        };

        if flags.contains(OFlag::O_NOFOLLOW) || is_exclusive_create {
            fsflags |= FsFlags::NO_FOLLOW_LAST;
        }

        if rflags.contains(ResolveFlag::RESOLVE_BENEATH) {
            fsflags |= FsFlags::RESOLVE_BENEATH;
        }

        if rflags.contains(ResolveFlag::RESOLVE_NO_SYMLINKS) {
            fsflags |= FsFlags::NO_RESOLVE_PATH;
        }

        if rflags.contains(ResolveFlag::RESOLVE_NO_MAGICLINKS) {
            fsflags |= FsFlags::NO_RESOLVE_PROC;
        }

        if rflags.contains(ResolveFlag::RESOLVE_NO_XDEV) {
            fsflags |= FsFlags::NO_RESOLVE_XDEV;
        }

        Self {
            dirfd,
            path,
            fsflags,
            flags: if flags.contains(OFlag::O_TMPFILE) {
                SysFlags::EMPTY_PATH
            } else {
                SysFlags::empty()
            },
            ..Default::default()
        }
    }
}

// Represents path arguments (max=2).
type PathArg<'a> = Option<CanonicalPath<'a>>;

#[derive(Debug)]
struct PathArgs<'a>(PathArg<'a>, PathArg<'a>);

/// `UNotifyEventRequest` is the type of parameter that user's function
/// would get.
#[derive(Debug)]
pub(crate) struct UNotifyEventRequest {
    scmpreq: ScmpNotifReq,
    syscall: Sydcall,
    notify_fd: RawFd,
    cache: Arc<WorkerCache<'static>>,
    sandbox: Arc<RwLock<Sandbox>>,
    crypt_map: Option<AesMap>,
}

impl Serialize for UNotifyEventRequest {
    #[allow(clippy::cognitive_complexity)]
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let mut map = serializer.serialize_map(Some(8))?;

        map.serialize_entry("pid", &self.scmpreq.pid)?;
        map.serialize_entry("sys", &self.syscall)?;
        map.serialize_entry("args", &self.scmpreq.data.args)?;
        map.serialize_entry("arch", &SydArch(self.scmpreq.data.arch))?;

        #[allow(clippy::cast_possible_wrap)]
        let pid = Pid::from_raw(self.scmpreq.pid as libc::pid_t);

        if let Ok(status) = proc_status(pid) {
            map.serialize_entry("cmd", &status.command)?;
            map.serialize_entry("tgid", &status.pid)?;
            map.serialize_entry("sig_caught", &status.sig_caught)?;
            map.serialize_entry("sig_blocked", &status.sig_blocked)?;
            map.serialize_entry("sig_ignored", &status.sig_ignored)?;
            map.serialize_entry("sig_pending_thread", &status.sig_pending_thread)?;
            map.serialize_entry("sig_pending_process", &status.sig_pending_process)?;
            map.serialize_entry("umask", &status.umask)?;
        }

        #[allow(clippy::unnecessary_cast)]
        if let Ok(auxv) = proc_auxv(pid) {
            // Note: libc::AT_* constant are u32 on 32-bit...

            // Base and entry addresses
            if let Some(val) = auxv.get(&(libc::AT_BASE as u64)) {
                map.serialize_entry("at_base", val)?;
            }
            if let Some(val) = auxv.get(&(libc::AT_ENTRY as u64)) {
                map.serialize_entry("at_entry", val)?;
            }

            // Program headers
            if let Some(val) = auxv.get(&(libc::AT_PHDR as u64)) {
                map.serialize_entry("at_phdr", val)?;
            }
            if let Some(val) = auxv.get(&(libc::AT_PHENT as u64)) {
                map.serialize_entry("at_phent", val)?;
            }
            if let Some(val) = auxv.get(&(libc::AT_PHNUM as u64)) {
                map.serialize_entry("at_phnum", val)?;
            }

            // Read AT_RANDOM bytes which is 16 bytes of
            // random data placed by the kernel at the
            // specified address.
            if let Some(addr) = auxv.get(&(libc::AT_RANDOM as u64)) {
                let mut at_random = [0u8; 16];
                if *addr >= *MMAP_MIN_ADDR && self.read_mem(&mut at_random, *addr).is_ok() {
                    map.serialize_entry("at_random", &at_random.to_lower_hex_string())?;
                }
            }

            // AT_SECURE: we set this ourselves
            // unless trace/allow_unsafe_libc:1 is passed at startup,
            // however when we set it, the value will still incorrectly
            // show as false because this file is not updated after
            // process startup.
            if let Some(val) = auxv.get(&(libc::AT_SECURE as u64)) {
                let sandbox = self.sandbox.read().unwrap_or_else(|err| err.into_inner());
                if !sandbox.allow_unsafe_libc() {
                    map.serialize_entry("at_secure", &true)?;
                } else {
                    map.serialize_entry("at_secure", &(*val != 0))?;
                }
            }
        }

        let sp = proc_stack_pointer(pid)
            .map(|sp| (sp & !0xF).saturating_sub(16))
            .ok();
        map.serialize_entry("sp", &sp)?;

        let si = scmp_syscall_instruction(scmp_arch_raw(self.scmpreq.data.arch));
        let ip = self
            .scmpreq
            .data
            .instr_pointer
            .saturating_sub(si.len() as u64);
        map.serialize_entry("ip", &ip)?;

        let mut ip_mem = [0u8; 64];
        let mut sp_mem = [0u8; 64];
        let mut ip_read = false;
        let mut sp_read = false;

        if ip >= *MMAP_MIN_ADDR && self.read_mem(&mut ip_mem, ip).is_ok() {
            ip_read = true;
        }

        if let Some(sp) = sp {
            #[allow(clippy::arithmetic_side_effects)]
            if sp >= *MMAP_MIN_ADDR && self.read_mem(&mut sp_mem, sp).is_ok() {
                sp_read = true;
            }
        }

        map.serialize_entry(
            "sp_mem",
            &if sp_read {
                Some(sp_mem.to_lower_hex_string())
            } else {
                None
            },
        )?;

        map.serialize_entry(
            "ip_mem",
            &if ip_read {
                Some(ip_mem.to_lower_hex_string())
            } else {
                None
            },
        )?;

        let ip_asm = disasm(&ip_mem, self.scmpreq.data.arch, ip, true, false)
            .map(|instructions| {
                instructions
                    .into_iter()
                    .map(|instruction| instruction.op)
                    .collect::<Vec<_>>()
            })
            .ok();
        map.serialize_entry("ip_asm", &ip_asm)?;

        map.serialize_entry("maps", &proc_maps(pid).ok())?;

        map.end()
    }
}

impl UNotifyEventRequest {
    pub(crate) fn new(
        scmpreq: ScmpNotifReq,
        syscall: Sydcall,
        notify_fd: RawFd,
        cache: Arc<WorkerCache<'static>>,
        sandbox: Arc<RwLock<Sandbox>>,
        crypt_map: Option<AesMap>,
    ) -> Self {
        UNotifyEventRequest {
            scmpreq,
            syscall,
            notify_fd,
            cache,
            sandbox,
            crypt_map,
        }
    }

    /// Get a read lock to the sandbox.
    pub(crate) fn get_sandbox(&self) -> SandboxGuard {
        // Note, if another user of this mutex panicked while holding
        // the mutex, then this call will return an error once the mutex
        // is acquired. We ignore this case here and fall through
        // because Syd emulator threads are free to panic independent of
        // each other.
        SandboxGuard::Read(self.sandbox.read().unwrap_or_else(|err| err.into_inner()))
    }

    /// Get a write lock to the sandbox.
    pub(crate) fn get_mut_sandbox(&self) -> SandboxGuard {
        // Note, if another user of this mutex panicked while holding
        // the mutex, then this call will return an error once the mutex
        // is acquired. We ignore this case here and fall through
        // because Syd emulator threads are free to panic independent of
        // each other.
        SandboxGuard::Write(self.sandbox.write().unwrap_or_else(|err| err.into_inner()))
    }

    /// Read the sa_flags member of `struct sigaction` from the given address.
    pub(crate) fn read_sa_flags(&self, addr: u64) -> Result<SaFlags, Errno> {
        let req = self.scmpreq;
        let is32 = scmp_arch_bits(req.data.arch) == 32;

        // sa_flags is at offset 8 on 64-bit and 4 on 32-bit.
        // unsigned long is 8 bits on 64-bit and 4 on 32-bit.
        let (sa_flags_offset, size_of_long) = if is32 { (4, 4) } else { (8, 8) };

        // Initialize vector on stack.
        let mut buf = [0u8; 8];

        // Read from process memory.
        let mut off = 0;
        #[allow(clippy::arithmetic_side_effects)]
        while off < size_of_long {
            // Adjust current slice.
            let len = size_of_long - off;
            let ptr = &mut buf[off..off + len];

            // Read remote memory.
            let process = RemoteProcess::new(self.scmpreq.pid());
            // SAFETY: The request is going to be validated.
            let len = unsafe { process.read_mem(ptr, addr + sa_flags_offset + off as u64) }?;

            // SAFETY: Assume error on zero-read.
            if len == 0 {
                return Err(Errno::EFAULT);
            }

            off += len;
        }

        // SAFETY: Check request validity after memory read.
        if !self.is_valid() {
            return Err(Errno::ESRCH);
        }

        #[allow(clippy::cast_possible_truncation)]
        #[allow(clippy::cast_possible_wrap)]
        if size_of_long == 8 {
            Ok(SaFlags::from_bits_truncate(
                u64::from_ne_bytes(buf) as libc::c_int
            ))
        } else {
            // SAFETY: size_of_long must always be 4 here.
            #[allow(clippy::disallowed_methods)]
            Ok(SaFlags::from_bits_truncate(u32::from_ne_bytes(
                buf[0..size_of_long].try_into().unwrap(),
            ) as libc::c_int))
        }
    }

    /// Read the `libc::open_how` struct from process memory
    /// at the given address and size.
    pub(crate) fn remote_ohow(&self, addr: u64, size: u64) -> Result<libc::open_how, Errno> {
        if usize::try_from(size).or(Err(Errno::EINVAL))? != std::mem::size_of::<libc::open_how>() {
            return Err(Errno::EINVAL);
        }

        let mut buf = [0u8; std::mem::size_of::<libc::open_how>()];
        self.read_mem(&mut buf, addr)?;

        // SAFETY: The following unsafe block assumes that:
        // 1. The memory layout of open_how in our Rust environment
        //    matches that of the target process.
        // 2. The request.process.read_mem call has populated buf with valid data
        //    of the appropriate size (ensured by the size check above).
        // 3. The buffer is appropriately aligned for reading an
        //    open_how struct. If the remote process's representation of
        //    open_how was correctly aligned, our local buffer should be
        //    too, since it's an array on the stack.
        Ok(unsafe { std::ptr::read_unaligned(buf.as_ptr() as *const _) })
    }

    /// Read the `libc::utimbuf` struct from process memory at the given address.
    /// Convert it to a `libc::timespec[2]` for easy interoperability.
    fn remote_utimbuf(&self, addr: u64) -> Result<(TimeSpec, TimeSpec), Errno> {
        if addr == 0 {
            // utimbuf pointer is NULL: Set to current time.
            return Ok((UTIME_NOW, UTIME_NOW));
        }

        let mut buf = [0u8; std::mem::size_of::<libc::utimbuf>()];
        self.read_mem(&mut buf, addr)?;

        // SAFETY: The following unsafe block assumes that:
        // 1. The memory layout of utimbuf in our Rust environment
        //    matches that of the target process.
        // 2. The request.process.read_mem call has populated buf with valid data
        //    of the appropriate size (ensured by the size check above).
        // 3. The buffer is appropriately aligned for reading a utimbuf
        //    struct. If the remote process's representation of utimbuf
        //    was correctly aligned, our local buffer should be too,
        //    since it's an array on the stack.
        let utimbuf: libc::utimbuf = unsafe { std::ptr::read_unaligned(buf.as_ptr() as *const _) };

        Ok((
            TimeSpec::new(utimbuf.actime, 0),
            TimeSpec::new(utimbuf.modtime, 0),
        ))
    }

    /// Read the `libc::timeval[2]` struct from process memory at the given address.
    /// Convert it to a `libc::timespec[2]` for easy interoperability.
    fn remote_timeval(&self, addr: u64) -> Result<(TimeSpec, TimeSpec), Errno> {
        if addr == 0 {
            // timeval pointer is NULL: Set to current time.
            return Ok((UTIME_NOW, UTIME_NOW));
        }

        let mut buf = [0u8; std::mem::size_of::<libc::timeval>() * 2];
        self.read_mem(&mut buf, addr)?;

        // SAFETY: The following unsafe block assumes that:
        // 1. The memory layout of timeval in our Rust environment
        //    matches that of the target process.
        // 2. The request.process.read_mem call has populated buf with valid data
        //    of the appropriate size (ensured by the size check above).
        // 3. The buffer is appropriately aligned for reading a timeval
        //    struct. If the remote process's representation of timeval
        //    was correctly aligned, our local buffer should be too,
        //    since it's an array on the stack.
        #[allow(clippy::cast_ptr_alignment)]
        let timevals = unsafe {
            // Create a raw pointer to the buffer.
            let ptr = buf.as_ptr() as *const libc::timeval;

            // Read the timeval values from the buffer.
            [
                std::ptr::read_unaligned(ptr),
                std::ptr::read_unaligned(ptr.add(1)),
            ]
        };

        Ok((
            TimeSpec::new(
                timevals[0].tv_sec,
                (timevals[0].tv_usec as libc::c_long).saturating_mul(1_000), /* ms->ns */
            ),
            TimeSpec::new(
                timevals[1].tv_sec,
                (timevals[1].tv_usec as libc::c_long).saturating_mul(1_000), /* ms->ns */
            ),
        ))
    }

    /// Read the `TimeSpec32[2]` struct from process memory at the given address.
    fn remote_timespec32(&self, addr: u64) -> Result<(TimeSpec, TimeSpec), Errno> {
        if addr == 0 {
            // timespec pointer is NULL: Set to current time.
            return Ok((UTIME_NOW, UTIME_NOW));
        }

        let mut buf = [0u8; std::mem::size_of::<TimeSpec32>() * 2];
        self.read_mem(&mut buf, addr)?;

        // SAFETY: The following unsafe block assumes that:
        // 1. The memory layout of timespec in our Rust environment
        //    matches that of the target process.
        // 2. The request.process.read_mem call has populated buf with valid data
        //    of the appropriate size (ensured by the size check above).
        // 3. The buffer is appropriately aligned for reading a timespec
        //    struct. If the remote process's representation of timespec
        //    was correctly aligned, our local buffer should be too,
        //    since it's an array on the stack.
        #[allow(clippy::cast_ptr_alignment)]
        let timespecs = unsafe {
            // Create a raw pointer to the buffer.
            let ptr = buf.as_ptr() as *const TimeSpec32;

            // Read the timespec values from the buffer.
            [
                std::ptr::read_unaligned(ptr),
                std::ptr::read_unaligned(ptr.add(1)),
            ]
        };

        Ok((
            TimeSpec::new(timespecs[0].tv_sec.into(), timespecs[0].tv_nsec.into()),
            TimeSpec::new(timespecs[1].tv_sec.into(), timespecs[1].tv_nsec.into()),
        ))
    }

    /// Read the `TimeSpec64[2]` struct from process memory at the given address.
    fn remote_timespec64(&self, addr: u64) -> Result<(TimeSpec, TimeSpec), Errno> {
        if addr == 0 {
            // timespec pointer is NULL: Set to current time.
            return Ok((UTIME_NOW, UTIME_NOW));
        }

        let mut buf = [0u8; std::mem::size_of::<TimeSpec64>() * 2];
        self.read_mem(&mut buf, addr)?;

        // SAFETY: The following unsafe block assumes that:
        // 1. The memory layout of timespec in our Rust environment
        //    matches that of the target process.
        // 2. The request.process.read_mem call has populated buf with valid data
        //    of the appropriate size (ensured by the size check above).
        // 3. The buffer is appropriately aligned for reading a timespec
        //    struct. If the remote process's representation of timespec
        //    was correctly aligned, our local buffer should be too,
        //    since it's an array on the stack.
        #[allow(clippy::cast_ptr_alignment)]
        let timespecs = unsafe {
            // Create a raw pointer to the buffer.
            let ptr = buf.as_ptr() as *const TimeSpec64;

            // Read the timespec values from the buffer.
            [
                std::ptr::read_unaligned(ptr),
                std::ptr::read_unaligned(ptr.add(1)),
            ]
        };

        #[cfg(target_pointer_width = "32")]
        {
            Ok((
                TimeSpec::new(timespecs[0].tv_sec as i32, timespecs[0].tv_nsec as i32),
                TimeSpec::new(timespecs[1].tv_sec as i32, timespecs[1].tv_nsec as i32),
            ))
        }
        #[cfg(target_pointer_width = "64")]
        {
            Ok((
                TimeSpec::new(timespecs[0].tv_sec, timespecs[0].tv_nsec),
                TimeSpec::new(timespecs[1].tv_sec, timespecs[1].tv_nsec),
            ))
        }
    }

    /// Read path from the given system call argument with the given request.
    /// Check for magic prefix is magic is true.
    #[allow(clippy::cognitive_complexity)]
    #[allow(clippy::type_complexity)]
    pub(crate) fn read_path<'b>(
        &self,
        sandbox: &SandboxGuard,
        arg: SysArg,
        magic: bool,
    ) -> Result<(CanonicalPath<'b>, bool), Errno> {
        let process = RemoteProcess::new(self.scmpreq.pid());

        // SAFETY: The request is validated.
        let (path, magic, doterr) = match unsafe {
            process.read_path(sandbox, self.scmpreq.data.args, arg, magic, Some(self))
        } {
            Ok(_) if !self.is_valid() => return Err(Errno::ESRCH),
            Ok((path, magic, doterr)) => (path, magic, doterr),
            Err(errno) => return Err(errno),
        };

        // (a) Delayed dotlast Errno::ENOENT handler, see above for the rationale.
        // (b) SAFETY: the Missing check is skipped by fs::canonicalize on purpose,
        // so that EEXIST return value cannot be abused to locate hidden paths.
        if !doterr {
            Ok((path, magic))
        } else if path
            .typ
            .as_ref()
            .map(|typ| !typ.is_symlink())
            .unwrap_or(false)
        {
            // Path exists and is not a symbolic link.
            // Return ENOENT if either one of path or parent is hidden.
            // Return EEXIST if not.
            if self.cache.is_hidden(sandbox, path.abs())
                || self.cache.is_hidden(sandbox, path.abs().parent())
            {
                Err(Errno::ENOENT)
            } else {
                Err(Errno::EEXIST)
            }
        } else {
            Err(Errno::ENOENT)
        }
    }

    /// Read data from remote process's memory with `process_vm_readv()`.
    pub(crate) fn read_mem(
        &self,
        local_buffer: &mut [u8],
        remote_addr: u64,
    ) -> Result<usize, Errno> {
        let process = RemoteProcess::new(self.scmpreq.pid());

        // SAFETY: The request is validated.
        match unsafe { process.read_mem(local_buffer, remote_addr) } {
            Ok(n) => {
                if self.is_valid() {
                    Ok(n)
                } else {
                    Err(Errno::ESRCH)
                }
            }
            Err(errno) => Err(errno),
        }
    }

    /// Write data to remote process's memory with `process_vm_writev()`.
    #[inline(always)]
    pub(crate) fn write_mem(&self, local_buffer: &[u8], remote_addr: u64) -> Result<usize, Errno> {
        let process = RemoteProcess::new(self.scmpreq.pid());

        // SAFETY: The request is validated.
        match unsafe { process.write_mem(local_buffer, remote_addr) } {
            Ok(n) => {
                if self.is_valid() {
                    Ok(n)
                } else {
                    Err(Errno::ESRCH)
                }
            }
            Err(errno) => Err(errno),
        }
    }

    /// Get file descriptor from remote process with `pidfd_getfd()`.
    /// This function requires Linux 5.6+.
    pub(crate) fn get_fd(&self, remote_fd: RawFd) -> Result<OwnedFd, Errno> {
        // SAFETY: Check if the RawFd is valid.
        if remote_fd < 0 {
            return Err(Errno::EBADF);
        }

        // Open a PidFd or use an already opened one.
        let pid_fd = self.pidfd_open()?;

        // SAFETY: Transfer the remote fd using the PidFd.
        Errno::result(unsafe {
            libc::syscall(libc::SYS_pidfd_getfd, pid_fd.as_raw_fd(), remote_fd, 0)
        })
        .map(|fd| {
            // SAFETY: pidfd_getfd returnd success, fd is valid.
            unsafe { OwnedFd::from_raw_fd(fd as RawFd) }
        })
    }

    /// Send a signal to the PIDFd of the process.
    pub(crate) fn pidfd_kill(&self, sig: i32) -> Result<(), Errno> {
        // Open a PidFd or use an already opened one.
        let pid_fd = self.pidfd_open()?;

        // SAFETY: libc does not have a wrapper for pidfd_send_signal yet.
        Errno::result(unsafe {
            libc::syscall(libc::SYS_pidfd_send_signal, pid_fd.as_raw_fd(), sig, 0, 0)
        })
        .map(drop)
    }

    /// Open a PidFd and validate it against the request.
    pub(crate) fn pidfd_open(&self) -> Result<RawFd, Errno> {
        // Open a PidFd or use an already opened one.
        //
        // SAFETY: Validate PidFd using the seccomp request id.
        PIDFD_MAP.get().ok_or(Errno::EAGAIN)?.pidfd_open(
            self.scmpreq.pid(),
            false,
            Some(self.scmpreq.id),
        )
    }

    /// Send the request pid a signal based on the given action.
    ///
    /// Non-signaling actions default to SIGKILL.
    pub(crate) fn kill(&self, action: Action) -> Result<(), Errno> {
        self.pidfd_kill(
            action
                .signal()
                .map(|sig| sig as libc::c_int)
                .unwrap_or(libc::SIGKILL),
        )
    }

    /// Let the kernel continue the syscall.
    ///
    /// # Safety
    /// CAUTION! This method is unsafe because it may suffer TOCTOU attack.
    /// Please read `seccomp_unotify(2)` "NOTES/Design goals; use of `SECCOMP_USER_NOTIF_FLAG_CONTINUE`"
    /// before using this method.
    pub(crate) unsafe fn continue_syscall(&self) -> ScmpNotifResp {
        ScmpNotifResp::new(self.scmpreq.id, 0, 0, ScmpNotifRespFlags::CONTINUE.bits())
    }

    /// Returns error to supervised process.
    pub(crate) fn fail_syscall(&self, err: Errno) -> ScmpNotifResp {
        debug_assert!(err != Errno::UnknownErrno);
        #[allow(clippy::arithmetic_side_effects)]
        ScmpNotifResp::new(self.scmpreq.id, 0, -(err as i32), 0)
    }

    /// Returns value to supervised process.
    pub(crate) fn return_syscall(&self, val: i64) -> ScmpNotifResp {
        ScmpNotifResp::new(self.scmpreq.id, val, 0, 0)
    }

    /// Check if this event is still valid.
    /// In some cases this is necessary, please check `seccomp_unotify(2)` for more information.
    pub(crate) fn is_valid(&self) -> bool {
        // SAFETY: This function is a hot path where we don't want to run
        // notify_supported() on each call.
        // libseccomp::notify_id_valid(self.notify_fd, self.scmpreq.id).is_ok()
        unsafe {
            crate::libseccomp_sys::seccomp_notify_id_valid(self.notify_fd, self.scmpreq.id) == 0
        }
    }

    /// Add a file descriptor to the supervised process,
    /// and reply to the seccomp request at the same time.
    /// This could help avoid TOCTOU attack in some cases.
    pub(crate) fn send_fd(
        &self,
        src_fd: &dyn AsRawFd,
        close_on_exec: bool,
    ) -> Result<ScmpNotifResp, Errno> {
        let src_fd = u32::try_from(src_fd.as_raw_fd()).or(Err(Errno::EBADF))?;

        let newfd_flags = if close_on_exec {
            libc::O_CLOEXEC as u32
        } else {
            0
        };
        #[allow(clippy::cast_possible_truncation)]
        let addfd: seccomp_notif_addfd = seccomp_notif_addfd {
            id: self.scmpreq.id,
            flags: libc::SECCOMP_ADDFD_FLAG_SEND as u32,
            srcfd: src_fd,
            newfd: 0,
            newfd_flags,
        };

        // SAFETY: The 'ioctl' function is a low-level interface to the
        // kernel, and its safety depends on the correctness of its
        // arguments. Here, we ensure that 'self.notify_fd' is a valid
        // file descriptor and 'addr_of!(addfd)' provides a valid
        // pointer to 'addfd'. The usage of ioctl is considered safe
        // under these conditions, as it does not lead to undefined
        // behavior.
        Errno::result(unsafe {
            libc::ioctl(
                self.notify_fd,
                SECCOMP_IOCTL_NOTIF_ADDFD,
                std::ptr::addr_of!(addfd),
            )
        })?;

        // We do not need to send a response,
        // return a dummy response which will be
        // skipped by the handler.
        Ok(ScmpNotifResp::new(0, 0, 0, 0))
    }
}

/// By using `RemoteProcess`, you can get information about the
/// supervised process.
#[derive(Clone, Debug)]
pub struct RemoteProcess {
    /// The process ID.
    pub pid: Pid,
    /// The Pid file descriptor.
    pub pid_fd: RawFd,
}

impl PartialEq for RemoteProcess {
    fn eq(&self, other: &Self) -> bool {
        self.pid == other.pid
    }
}

impl Eq for RemoteProcess {}

impl Hash for RemoteProcess {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.pid.hash(state);
    }
}

impl RemoteProcess {
    /// Create a new `RemoteProcess` for the given pid.
    pub(crate) fn new(pid: Pid) -> Self {
        Self {
            pid,
            pid_fd: libc::AT_FDCWD,
        }
    }

    /// Create a `RemoteProcess` object for the given TGID.
    ///
    /// Unsafe because the request cannot be validated.
    pub(crate) unsafe fn from_tgid(request_tgid: Pid) -> Result<Self, Errno> {
        let pid_fd = PIDFD_MAP
            .get()
            .ok_or(Errno::EAGAIN)?
            .pidfd_open(request_tgid, true, None)?;

        Ok(Self {
            pid: request_tgid,
            pid_fd,
        })
    }

    /// Create a `RemoteProcess` object for the given TID.
    ///
    /// Unsafe because the request cannot be validated.
    pub(crate) unsafe fn from_tid(request_tid: Pid) -> Result<Self, Errno> {
        let pid_fd = PIDFD_MAP
            .get()
            .ok_or(Errno::EAGAIN)?
            .pidfd_open(request_tid, false, None)?;

        Ok(Self {
            pid: request_tid,
            pid_fd,
        })
    }

    /// Read path from the given system call argument with the given request.
    /// Check for magic prefix is magic is true.
    ///
    /// # Safety
    ///
    /// This function is unsafe because the request is not validated.
    #[allow(clippy::cognitive_complexity)]
    #[allow(clippy::type_complexity)]
    pub(crate) unsafe fn read_path<'b>(
        &self,
        sandbox: &SandboxGuard,
        args: [u64; 6],
        arg: SysArg,
        mut magic: bool,
        request: Option<&UNotifyEventRequest>,
    ) -> Result<(CanonicalPath<'b>, bool, bool), Errno> {
        #[allow(clippy::cast_possible_truncation)]
        let orig = match arg.path {
            Some(idx) => {
                // SAFETY: Check pointer against mmap_min_addr.
                if args[idx] < *MMAP_MIN_ADDR {
                    return Err(Errno::EFAULT);
                }

                Some(self.remote_path(args[idx])?)
            }
            None => None,
        };
        let mut doterr = false;

        // magic is both an in and out variable.
        // in=t: check for magic path.
        // out=t: path is magic path.
        let check_magic = magic;
        magic = false;

        let canonical_path = if let Some(path) = orig {
            if path.is_empty() && !arg.flags.contains(SysFlags::EMPTY_PATH) {
                return Err(Errno::ENOENT);
            }

            if let Some(errno) = arg.dotlast {
                if path.ends_with_dot() {
                    if errno == Errno::ENOENT {
                        // This will be handled later, as we may
                        // need to return EEXIST instead of ENOENT
                        // if the path exists.
                        doterr = true;
                    } else {
                        return Err(errno);
                    }
                }
            }

            if check_magic && path.is_magic() {
                magic = true;
                CanonicalPath::new_magic(path)
            } else if path.is_empty() || path.is_dot() {
                #[allow(clippy::cast_possible_truncation)]
                let dirfd = if let Some(idx) = arg.dirfd {
                    args[idx] as RawFd
                } else {
                    AT_FDCWD
                };
                let is_dot = !path.is_empty();

                // SAFETY: The ends_with_dot check above
                // ensures we return ENOTDIR when e.g. path is
                // a dot and the file descriptor argument is a
                // regular file. This happens because in this
                // case, joining the directory with an empty
                // path on the next branch essentially adds a
                // trailing slash to the path, making the
                // system call emulator fail with ENOTDIR if
                // the argument is not a directory. This way,
                // we avoid stat'ing the path here to
                // determine whether it's a directory or not.
                if dirfd == AT_FDCWD {
                    CanonicalPath::new_fd(libc::AT_FDCWD.into(), self.pid, libc::AT_FDCWD)?
                } else if let Some(request) = request {
                    // SAFETY: Get the file descriptor before access check
                    // as it may change after which is a TOCTOU vector.
                    let fd = request.get_fd(dirfd)?;

                    let path = CanonicalPath::new_fd(fd.into(), self.pid, dirfd)?;

                    if is_dot && path.typ != Some(FileType::Dir) {
                        // FD-only call, no need to delay ENOTDIR.
                        return Err(Errno::ENOTDIR);
                    }

                    path
                } else {
                    // SAFETY: Get the file descriptor before access check
                    // as it may change after which is a TOCTOU vector.
                    let fd = self.get_fd(dirfd)?;

                    let path = CanonicalPath::new_fd(fd.into(), self.pid, dirfd)?;

                    if is_dot && path.typ != Some(FileType::Dir) {
                        // FD-only call, no need to delay ENOTDIR.
                        return Err(Errno::ENOTDIR);
                    }

                    path
                }
            } else {
                #[allow(clippy::cast_possible_truncation)]
                let fd = arg.dirfd.map(|idx| args[idx] as RawFd);

                safe_canonicalize(self.pid, fd, &path, arg.fsflags, sandbox.flags)?
            }
        } else {
            // SAFETY: SysArg.path is None asserting dirfd is Some.
            #[allow(clippy::cast_possible_truncation)]
            #[allow(clippy::disallowed_methods)]
            let dirfd = args[arg.dirfd.unwrap()] as RawFd;

            if dirfd == libc::AT_FDCWD {
                // SAFETY: Read the CWD link before access check
                // as it may change after which is a TOCTOU vector.
                CanonicalPath::new_fd(libc::AT_FDCWD.into(), self.pid, libc::AT_FDCWD)?
            } else if dirfd < 0 {
                return Err(Errno::EBADF);
            } else if let Some(request) = request {
                // SAFETY: Get the file descriptor before access check
                // as it may change after which is a TOCTOU vector.
                let fd = request.get_fd(dirfd)?;

                CanonicalPath::new_fd(fd.into(), self.pid, dirfd)?
            } else {
                // SAFETY: Get the file descriptor before access check
                // as it may change after which is a TOCTOU vector.
                let fd = self.get_fd(dirfd)?;

                CanonicalPath::new_fd(fd.into(), self.pid, dirfd)?
            }
        };

        if !magic {
            // SAFETY: Deny access to critical and/or suspicious paths.
            canonical_path.abs().check(
                self.pid,
                canonical_path.typ.as_ref(),
                None,
                !sandbox.allow_unsafe_filename(),
            )?;
        }

        Ok((canonical_path, magic, doterr))
    }

    /// Get file descriptor from remote process with `pidfd_getfd()`.
    /// This function requires Linux 5.6+.
    ///
    /// # Safety
    ///
    /// This function is unsafe because the pid cannot be validated with a request id.
    pub(crate) unsafe fn get_fd(&self, remote_fd: RawFd) -> Result<OwnedFd, Errno> {
        // SAFETY: Check if the RawFd is valid.
        if remote_fd < 0 {
            return Err(Errno::EBADF);
        }

        // SAFETY: libc does not have a pidfd_getfd wrapper yet.
        Errno::result(unsafe {
            libc::syscall(libc::SYS_pidfd_getfd, self.pid_fd.as_raw_fd(), remote_fd, 0)
        })
        .map(|fd| fd as RawFd)
        .map(|fd| {
            // SAFETY: pidfd_getfd returnd success, fd is valid.
            unsafe { OwnedFd::from_raw_fd(fd as RawFd) }
        })
    }

    /// Check if the process is still alive using the PIDFd.
    pub(crate) fn is_alive(&self) -> bool {
        self.pidfd_kill(0).is_ok()
    }

    /// Send a signal to the PIDFd of the process.
    pub(crate) fn pidfd_kill(&self, sig: i32) -> Result<(), Errno> {
        // SAFETY: libc does not have a pidfd_send_signal wrapper yet.
        Errno::result(unsafe {
            libc::syscall(
                libc::SYS_pidfd_send_signal,
                self.pid_fd.as_raw_fd(),
                sig,
                0,
                0,
            )
        })
        .map(drop)
    }

    /// Read data from remote process's memory with `process_vm_readv()`.
    ///
    /// # Safety
    ///
    /// This function is unsafe because the request is not validated.
    pub(crate) unsafe fn read_mem(
        &self,
        local_buffer: &mut [u8],
        remote_addr: u64,
    ) -> Result<usize, Errno> {
        static FORCE_PROC: Lazy<bool> =
            Lazy::new(|| std::env::var_os(ENV_NO_CROSS_MEMORY_ATTACH).is_some());
        if *FORCE_PROC {
            return self.read_mem_proc(local_buffer, remote_addr);
        }

        // SAFETY: Falling back to proc_pid_mem(5) is insecure,
        // and is no longer the default as of 3.32.6.
        static PROC_MEM_F: Lazy<bool> =
            Lazy::new(|| std::env::var_os(ENV_PROC_PID_MEM_FALLBACK).is_some());

        // SAFETY: Check pointer against mmap_min_addr.
        if remote_addr < *MMAP_MIN_ADDR {
            return Err(Errno::EFAULT);
        }

        let len = local_buffer.len();
        match process_vm_readv(
            self.pid,
            &mut [IoSliceMut::new(local_buffer)],
            &[RemoteIoVec {
                len,
                base: usize::try_from(remote_addr).or(Err(Errno::EFAULT))?,
            }],
        ) {
            Ok(n) => Ok(n),
            Err(Errno::ENOSYS) if *PROC_MEM_F => self.read_mem_proc(local_buffer, remote_addr),
            Err(e) => Err(e),
        }
    }

    /// Fallback method to read data from `/proc/$pid/mem` when `process_vm_readv()` is unavailable.
    ///
    /// # Safety
    ///
    /// This function is unsafe because the request is not validated.
    pub(crate) unsafe fn read_mem_proc(
        &self,
        local_buffer: &mut [u8],
        remote_addr: u64,
    ) -> Result<usize, Errno> {
        // SAFETY: Check pointer against mmap_min_addr.
        if remote_addr < *MMAP_MIN_ADDR {
            return Err(Errno::EFAULT);
        }

        let mut path = XPathBuf::from_pid(self.pid);
        path.push(b"mem");

        let mut file =
            match retry_on_eintr(|| safe_open_magicsym(Some(&PROC_FILE()), &path, OFlag::O_RDONLY))
            {
                Ok(fd) => File::from(fd),
                Err(_) => return Err(Errno::EACCES),
            };
        file.seek(SeekFrom::Start(remote_addr))
            .or(Err(Errno::EACCES))?;

        let mut nread = 0;
        #[allow(clippy::arithmetic_side_effects)]
        while nread < local_buffer.len() {
            match file.read(&mut local_buffer[nread..]) {
                Ok(0) => return Err(Errno::EACCES),
                Ok(n) => nread += n,
                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
                Err(_) => return Err(Errno::EACCES),
            }
        }

        Ok(nread)
    }

    /// Write data to remote process's memory with `process_vm_writev()`.
    ///
    /// # Safety
    ///
    /// This function is unsafe because the request is not validated.
    pub(crate) unsafe fn write_mem(
        &self,
        local_buffer: &[u8],
        remote_addr: u64,
    ) -> Result<usize, Errno> {
        static FORCE_PROC: Lazy<bool> =
            Lazy::new(|| std::env::var_os(ENV_NO_CROSS_MEMORY_ATTACH).is_some());
        if *FORCE_PROC {
            return self.write_mem_proc(local_buffer, remote_addr);
        }

        // SAFETY: Falling back to proc_pid_mem(5) is insecure,
        // and is no longer the default as of 3.32.6.
        static PROC_MEM_F: Lazy<bool> =
            Lazy::new(|| std::env::var_os(ENV_PROC_PID_MEM_FALLBACK).is_some());

        // SAFETY: Check pointer against mmap_min_addr.
        if remote_addr < *MMAP_MIN_ADDR {
            return Err(Errno::EFAULT);
        }

        let len = local_buffer.len();
        match process_vm_writev(
            self.pid,
            &[IoSlice::new(local_buffer)],
            &[RemoteIoVec {
                len,
                base: usize::try_from(remote_addr).or(Err(Errno::EFAULT))?,
            }],
        ) {
            Ok(n) => Ok(n),
            Err(Errno::ENOSYS) if *PROC_MEM_F => self.write_mem_proc(local_buffer, remote_addr),
            Err(e) => Err(e),
        }
    }

    /// Fallback method to write data to `/proc/$pid/mem` when `process_vm_writev()` is unavailable.
    ///
    /// # Safety
    ///
    /// This function is unsafe because the request is not validated.
    pub(crate) unsafe fn write_mem_proc(
        &self,
        local_buffer: &[u8],
        remote_addr: u64,
    ) -> Result<usize, Errno> {
        // SAFETY: Check pointer against mmap_min_addr.
        if remote_addr < *MMAP_MIN_ADDR {
            return Err(Errno::EFAULT);
        }

        let mut path = XPathBuf::from_pid(self.pid);
        path.push(b"mem");

        let mut file =
            match retry_on_eintr(|| safe_open_magicsym(Some(&PROC_FILE()), &path, OFlag::O_WRONLY))
            {
                Ok(fd) => File::from(fd),
                Err(_) => return Err(Errno::EACCES),
            };
        file.seek(SeekFrom::Start(remote_addr))
            .or(Err(Errno::EACCES))?;

        let mut nwritten = 0;
        #[allow(clippy::arithmetic_side_effects)]
        while nwritten < local_buffer.len() {
            match file.write(&local_buffer[nwritten..]) {
                Ok(0) => return Err(Errno::EACCES),
                Ok(n) => nwritten += n,
                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
                Err(_) => return Err(Errno::EACCES),
            }
        }

        Ok(nwritten)
    }

    /// Read the path from memory of the process with the given `Pid` with the given address.
    unsafe fn remote_path(&self, addr: u64) -> Result<XPathBuf, Errno> {
        // Initialize path on the heap,
        // bail out if memory allocation fails.
        let mut buf = Vec::new();
        buf.try_reserve(PATH_MIN).or(Err(Errno::ENOMEM))?;

        // Read from process memory.
        // We read PATH_MIN bytes at a time,
        // because most paths are short.
        let mut off = 0;
        #[allow(clippy::arithmetic_side_effects)]
        while off < PATH_MAX {
            // Ensure we have enough space for the next read.
            let len = PATH_MIN.min(PATH_MAX - off);

            if buf.len() < off + len {
                // Extend the buffer to the required size,
                // bail out if memory allocation fails.
                buf.try_reserve(len).or(Err(Errno::ENOMEM))?;
                buf.resize(off + len, 0);
            }

            let ptr = &mut buf[off..off + len];

            // Read remote memory.
            // SAFETY: Assume error on zero-read.
            let len = self.read_mem(ptr, addr + off as u64)?;
            if len == 0 {
                return Err(Errno::EFAULT);
            }

            // Check for NUL-byte.
            if let Some(nul) = memchr::memchr(0, &ptr[..len]) {
                // Adjust to actual size up to NUL-byte.
                off += nul;
                buf.truncate(off);
                buf.shrink_to_fit();
                return Ok(buf.into());
            }

            off += len;
        }

        Err(Errno::ENAMETOOLONG)
    }
}

pub(crate) type Handler = Arc<Box<dyn Fn(UNotifyEventRequest) -> ScmpNotifResp + Send + Sync>>;
pub(crate) type HandlerMap = HashMap<Sydcall, Handler, RandomState>;
type AllowSet = HashSet<ScmpSyscall, RandomState>;

/// Supervisor of a Syd sandbox.
pub struct Supervisor {
    export: Option<ExportMode>,
    handlers: Arc<HandlerMap>,
    sysallow: AllowSet,
    sandbox: Arc<RwLock<Sandbox>>,
    crypt_map: Option<AesMap>,
}

impl Supervisor {
    /// Create a new `Supervisor` object. You can specify the number of threads in the thread pool.
    /// This function will also check your kernel version and show warning or return error if necessary.
    #[allow(clippy::cognitive_complexity)]
    pub(crate) fn new(sandbox: Sandbox, export_mode: Option<ExportMode>) -> SydResult<Self> {
        let mut handlers = HashMap::default();
        let mut sysallow = HashSet::default();
        Self::init(&sandbox, &mut handlers, &mut sysallow)?;

        let crypt_map = if sandbox.enabled(Capability::CAP_CRYPT) {
            Some(Arc::new(RwLock::new((HashMap::default(), false))))
        } else {
            None
        };

        let supervisor = Supervisor {
            export: export_mode,
            sysallow,
            handlers: Arc::new(handlers),
            sandbox: Arc::new(RwLock::new(sandbox)),
            crypt_map: crypt_map.as_ref().map(Arc::clone),
        };

        Ok(supervisor)
    }

    /// Initilizes the supervisor by adding the system call handlers.
    #[allow(clippy::cognitive_complexity)]
    fn init(
        sandbox: &Sandbox,
        handlers: &mut HandlerMap,
        sysallow: &mut AllowSet,
    ) -> SydResult<()> {
        // For performance reasons, we apply ioctl and memory
        // sandboxing at startup only.
        let has_ioc = sandbox.enabled(Capability::CAP_IOCTL);
        let has_mem = sandbox.enabled(Capability::CAP_MEM);
        let restrict_chroot = !sandbox.allow_unsafe_chroot();
        let restrict_memfd = !sandbox.allow_unsafe_memfd();
        let restrict_ptrace = !sandbox.allow_unsafe_ptrace();
        let restrict_spec_exec = !sandbox.allow_unsafe_spec_exec();
        let restrict_sysinfo = !sandbox.allow_unsafe_sysinfo();
        let flags = sandbox.flags;
        let ioctl_denylist = sandbox.get_ioctl_deny();
        let deny_namespaces = sandbox.denied_namespaces();
        let netlink_families = sandbox.netlink_families;

        let mut allow_calls = Vec::with_capacity(8);

        // PR_SET_NAME logging.
        Self::insert_handler(handlers, "prctl", sys_prctl);

        // F_SETFL O_APPEND unset prevention for appendonly files.
        Self::insert_handler(handlers, "fcntl", sys_fcntl);
        Self::insert_handler(handlers, "fcntl64", sys_fcntl);

        if !restrict_ptrace {
            // Exec sandboxing, only used with trace/allow_unsafe_ptrace:1
            //
            // Because with seccomp there's no TOCTTOU-free way to
            // implement these system calls.
            //
            // See: https://bugzilla.kernel.org/show_bug.cgi?id=218501
            Self::insert_handler(handlers, "execve", sys_execve);
            Self::insert_handler(handlers, "execveat", sys_execveat);
        }

        // SA_RESTART tracking for syscall interruption.
        Self::insert_handler(handlers, "sigaction", sys_sigaction);
        Self::insert_handler(handlers, "rt_sigaction", sys_sigaction);

        // Ioctl sandboxing
        if has_ioc {
            Self::insert_handler(handlers, "ioctl", sys_ioctl);
        } else {
            // The denylist will be processed in the parent filter.
            allow_calls.push("ioctl");
        }

        if has_mem {
            // Memory sandboxing
            Self::insert_handler(handlers, "brk", sys_brk);
            Self::insert_handler(handlers, "mremap", sys_mremap);
            Self::insert_handler(handlers, "mmap", sys_mmap);
            Self::insert_handler(handlers, "mmap2", sys_mmap2);
        } else {
            allow_calls.extend(["brk", "mremap"]);

            if restrict_ptrace {
                // mmap{,2} are checked for Exec too!
                // We handle them specially in setup_seccomp,
                // as we only want to hook into PROT_EXEC and !MAP_ANONYMOUS.
                Self::insert_handler(handlers, "mmap", sys_mmap);
                Self::insert_handler(handlers, "mmap2", sys_mmap2);
            } else {
                allow_calls.extend(["mmap", "mmap2"]);
            }
        }

        // SafeSetID
        // SAFETY: We do not support diverging FsID from Effective ID.
        // SAFETY: We do not support setgroups (due to pointer deref -> TOCTOU vector)
        // The parent seccomp filter stops setfs*id and setgroups.
        // Parent filter also stops {U,G}ID to privileged user/groups.
        Self::insert_handler(handlers, "setuid", sys_setuid);
        Self::insert_handler(handlers, "setuid32", sys_setuid);
        Self::insert_handler(handlers, "setgid", sys_setgid);
        Self::insert_handler(handlers, "setgid32", sys_setgid);
        Self::insert_handler(handlers, "setreuid", sys_setreuid);
        Self::insert_handler(handlers, "setreuid32", sys_setreuid);
        Self::insert_handler(handlers, "setregid", sys_setregid);
        Self::insert_handler(handlers, "setregid32", sys_setregid);
        Self::insert_handler(handlers, "setresuid", sys_setresuid);
        Self::insert_handler(handlers, "setresuid32", sys_setresuid);
        Self::insert_handler(handlers, "setresgid", sys_setresgid);
        Self::insert_handler(handlers, "setresgid32", sys_setresgid);

        // SAFETY: sysinfo() is a vector of information leak as it
        // provides identical information with the files /proc/meminfo
        // and /proc/loadavg.
        // Since 3.32.4, this can be relaxed with trace/allow_unsafe_sysinfo:1.
        if restrict_sysinfo {
            Self::insert_handler(handlers, "sysinfo", sys_sysinfo);
        }

        // SAFETY: syslog(2) provides the syslog interface in case
        // the sandbox process has access to the sandbox lock.
        #[cfg(feature = "log")]
        Self::insert_handler(handlers, "syslog", sys_syslog);

        // Sanitize uname(2) to protect against information leaks.
        // This is consistent with masking /proc/version.
        Self::insert_handler(handlers, "uname", sys_uname);

        // signal protection
        Self::insert_handler(handlers, "kill", sys_kill);
        Self::insert_handler(handlers, "tkill", sys_tkill);
        Self::insert_handler(handlers, "tgkill", sys_tgkill);
        Self::insert_handler(handlers, "rt_sigqueueinfo", sys_kill);
        Self::insert_handler(handlers, "rt_tgsigqueueinfo", sys_tgkill);
        Self::insert_handler(handlers, "pidfd_open", sys_pidfd_open);

        // network sandboxing
        Self::insert_handler(handlers, "socketcall", sys_socketcall);
        Self::insert_handler(handlers, "socket", sys_socket);
        Self::insert_handler(handlers, "bind", sys_bind);
        Self::insert_handler(handlers, "connect", sys_connect);
        Self::insert_handler(handlers, "sendto", sys_sendto);
        Self::insert_handler(handlers, "sendmsg", sys_sendmsg);
        Self::insert_handler(handlers, "sendmmsg", sys_sendmmsg);
        Self::insert_handler(handlers, "accept", sys_accept);
        Self::insert_handler(handlers, "accept4", sys_accept4);
        Self::insert_handler(handlers, "getsockname", sys_getsockname);

        // chroot sandboxing
        if restrict_chroot {
            Self::insert_handler(handlers, "chroot", sys_chroot);
        } // else trace/allow_unsafe_chroot:1

        // stat sandboxing
        if !restrict_ptrace {
            Self::insert_handler(handlers, "chdir", sys_chdir);
        }
        Self::insert_handler(handlers, "fchdir", sys_fchdir);
        Self::insert_handler(handlers, "getdents64", sys_getdents64);
        Self::insert_handler(handlers, "stat", sys_stat);
        Self::insert_handler(handlers, "stat64", sys_stat64);
        Self::insert_handler(handlers, "statfs", sys_statfs);
        Self::insert_handler(handlers, "statfs64", sys_statfs64);
        Self::insert_handler(handlers, "statx", sys_statx);
        Self::insert_handler(handlers, "lstat", sys_lstat);
        Self::insert_handler(handlers, "lstat64", sys_lstat64);
        Self::insert_handler(handlers, "fstatat64", sys_newfstatat);
        Self::insert_handler(handlers, "newfstatat", sys_newfstatat);
        Self::insert_handler(handlers, "fstat", sys_fstat);
        Self::insert_handler(handlers, "fstat64", sys_fstat64);
        Self::insert_handler(handlers, "fstatfs", sys_fstatfs);
        Self::insert_handler(handlers, "fstatfs64", sys_fstatfs64);
        Self::insert_handler(handlers, "getxattr", sys_getxattr);
        Self::insert_handler(handlers, "fgetxattr", sys_fgetxattr);
        Self::insert_handler(handlers, "lgetxattr", sys_lgetxattr);
        Self::insert_handler(handlers, "getxattrat", sys_getxattrat);
        Self::insert_handler(handlers, "listxattr", sys_listxattr);
        Self::insert_handler(handlers, "flistxattr", sys_flistxattr);
        Self::insert_handler(handlers, "llistxattr", sys_llistxattr);
        Self::insert_handler(handlers, "listxattrat", sys_listxattrat);
        Self::insert_handler(handlers, "fanotify_mark", sys_fanotify_mark);
        Self::insert_handler(handlers, "inotify_add_watch", sys_inotify_add_watch);

        // read/write sandboxing
        Self::insert_handler(handlers, "access", sys_access);
        Self::insert_handler(handlers, "faccessat", sys_faccessat);
        Self::insert_handler(handlers, "faccessat2", sys_faccessat2);
        Self::insert_handler(handlers, "chmod", sys_chmod);
        Self::insert_handler(handlers, "fchmod", sys_fchmod);
        Self::insert_handler(handlers, "fchmodat", sys_fchmodat);
        Self::insert_handler(handlers, "fchmodat2", sys_fchmodat2);
        Self::insert_handler(handlers, "chown", sys_chown);
        Self::insert_handler(handlers, "chown32", sys_chown);
        Self::insert_handler(handlers, "fchown", sys_fchown);
        Self::insert_handler(handlers, "fchown32", sys_fchown);
        Self::insert_handler(handlers, "lchown", sys_lchown);
        Self::insert_handler(handlers, "lchown32", sys_lchown);
        Self::insert_handler(handlers, "fchownat", sys_fchownat);
        Self::insert_handler(handlers, "creat", sys_creat);
        Self::insert_handler(handlers, "link", sys_link);
        Self::insert_handler(handlers, "linkat", sys_linkat);
        Self::insert_handler(handlers, "symlink", sys_symlink);
        Self::insert_handler(handlers, "symlinkat", sys_symlinkat);
        Self::insert_handler(handlers, "unlink", sys_unlink);
        Self::insert_handler(handlers, "unlinkat", sys_unlinkat);
        Self::insert_handler(handlers, "mkdir", sys_mkdir);
        Self::insert_handler(handlers, "rmdir", sys_rmdir);
        Self::insert_handler(handlers, "mkdirat", sys_mkdirat);
        Self::insert_handler(handlers, "mknod", sys_mknod);
        Self::insert_handler(handlers, "mknodat", sys_mknodat);
        Self::insert_handler(handlers, "open", sys_open);
        Self::insert_handler(handlers, "openat", sys_openat);
        Self::insert_handler(handlers, "openat2", sys_openat2);
        Self::insert_handler(handlers, "rename", sys_rename);
        Self::insert_handler(handlers, "renameat", sys_renameat);
        Self::insert_handler(handlers, "renameat2", sys_renameat2);
        Self::insert_handler(handlers, "utime", sys_utime);
        Self::insert_handler(handlers, "utimes", sys_utimes);
        Self::insert_handler(handlers, "futimesat", sys_futimesat);
        Self::insert_handler(handlers, "utimensat", sys_utimensat);
        Self::insert_handler(handlers, "utimensat_time64", sys_utimensat64);
        Self::insert_handler(handlers, "truncate", sys_truncate);
        Self::insert_handler(handlers, "truncate64", sys_truncate64);
        Self::insert_handler(handlers, "ftruncate", sys_ftruncate);
        Self::insert_handler(handlers, "ftruncate64", sys_ftruncate64);
        Self::insert_handler(handlers, "fallocate", sys_fallocate);
        Self::insert_handler(handlers, "setxattr", sys_setxattr);
        Self::insert_handler(handlers, "fsetxattr", sys_fsetxattr);
        Self::insert_handler(handlers, "lsetxattr", sys_lsetxattr);
        Self::insert_handler(handlers, "setxattrat", sys_setxattrat);
        Self::insert_handler(handlers, "removexattr", sys_removexattr);
        Self::insert_handler(handlers, "removexattrat", sys_removexattrat);
        Self::insert_handler(handlers, "fremovexattr", sys_fremovexattr);
        Self::insert_handler(handlers, "lremovexattr", sys_lremovexattr);

        // memfds have mode 777 by default,
        // so we check it for all of Read, Write and Exec sandboxing.
        Self::insert_handler(handlers, "memfd_create", sys_memfd_create);
        if !restrict_memfd {
            allow_calls.push("memfd_secret");
        }

        // Allowlist safe system calls.
        for sysname in SAFE_SYSCALLS
            .iter()
            .chain(&allow_calls)
            .chain(FUTEX_SYSCALLS)
        // SAFETY: get id syscalls are handled by `root/fake' as necessary.
        // .chain(GET_ID_SYSCALLS)
        {
            match ScmpSyscall::from_name(sysname) {
                Ok(syscall) => Self::allow_syscall(sysallow, syscall),
                Err(_) => {
                    info!("ctx": "confine", "op": "allow_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        }

        // SAFETY: Set the no-new-privileges attribute.
        set_no_new_privs()?;
        info!("ctx": "set_no_new_privileges", "msg": "no-new-privileges attribute set");

        // SAFETY: Set Memory-Deny-Write-Execute protection mask.
        // REFUSE_EXEC_GAIN is available since Linux-6.3.
        // NO_INHERIT is available since Linux-6.6.
        // For older systems we also apply a mmap filter in load_seccomp_parent.
        const PR_SET_MDWE: libc::c_int = 65;
        const PR_MDWE_REFUSE_EXEC_GAIN: libc::c_ulong = 1;
        const PR_MDWE_NO_INHERIT: libc::c_ulong = 2;

        let restrict_memory = !flags.contains(Flags::FL_ALLOW_UNSAFE_MEMORY);
        let mdwe_flags = if restrict_memory {
            // Apply restriction globally.
            PR_MDWE_REFUSE_EXEC_GAIN
        } else {
            // Apply restrictions only for syd process.
            PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT
        };

        #[cfg(not(any(
            target_arch = "mips",
            target_arch = "mips32r6",
            target_arch = "mips64",
            target_arch = "mips64r6"
        )))]
        // SAFETY: Set memory-deny-write-execute attribute.
        // Note, mips requires executable stack so we skip on this arch.
        if let Err(errno) = Errno::result(unsafe { libc::prctl(PR_SET_MDWE, mdwe_flags, 0, 0, 0) })
        {
            // EINVAL: MDWE is not supported (Required Linux 6.3 or newer)
            // EPERM: Permission denied (MDWE already enabled?)
            info!("ctx": "set_memory_deny_write_execute",
                "msg": format!("memory-deny-write-execute error: {errno}"));
        } else {
            info!("ctx": "set_memory_deny_write_execute",
                "msg": format!("memory-deny-write-execute set with inherit:{restrict_memory}"));
        }

        if restrict_spec_exec {
            // SAFETY: Set mitigations for speculation misfeatures.
            let nstatus = SpeculationStatus::from_raw(PR_SPEC_FORCE_DISABLE);
            for spec_feat in [
                SpeculationFeature::StoreBypass,
                SpeculationFeature::IndirectBranch,
                SpeculationFeature::L1DFlush,
            ] {
                match speculation_get(spec_feat) {
                    Ok(cstatus) if cstatus.status.can_prctl_set() => {
                        // Fall-through and attempt to set.
                    }
                    Ok(cstatus) => {
                        // prctl cannot set, nothing left to do.
                        info!("ctx": "set_speculative_execution_mitigation",
                            "msg": cstatus.to_string(),
                            "feature": spec_feat.to_string(),
                            "status": cstatus.status.0);
                        continue;
                    }
                    Err(errno) => {
                        info!("ctx": "set_speculative_execution_mitigations",
                            "msg": format!("speculation-get error: {errno}"),
                            "feature": spec_feat.to_string());
                        // Fall-through and attempt to set.
                    }
                }

                match speculation_set(spec_feat, nstatus) {
                    Ok(_) => {
                        let cstatus = SpeculationControlStatus {
                            status: nstatus,
                            feature: spec_feat,
                        };
                        info!("ctx": "set_speculative_execution_mitigation",
                            "msg": cstatus.to_string(),
                            "feature": spec_feat.to_string(),
                            "status": cstatus.status.0);
                    }
                    Err(errno) => {
                        info!("ctx": "set_speculative_execution_mitigations",
                            "msg": format!("speculation-set error: {errno}"),
                            "feature": spec_feat.to_string(),
                            "status": nstatus.0);
                    }
                }
            }
        }

        let unsafe_caps = flags.contains(Flags::FL_ALLOW_UNSAFE_CAPS);
        let unsafe_ptrace = flags.contains(Flags::FL_ALLOW_UNSAFE_PTRACE);
        if !unsafe_caps {
            let mut capdrop: Option<Vec<caps::Capability>> = if log_enabled!(LogLevel::Info) {
                Some(vec![])
            } else {
                None
            };
            for cap in caps::all() {
                match cap {
                    caps::Capability::CAP_SYS_PTRACE => {
                        // SAFETY: CAP_SYS_PTRACE is special because
                        // Syd process needs this capability for
                        // pidfd_getfd(2), that's why we drop this
                        // capability late in the child before exec,
                        // see below.
                        continue;
                    }
                    caps::Capability::CAP_SETUID if flags.contains(Flags::FL_ALLOW_SAFE_SETUID) => {
                        continue
                    }
                    caps::Capability::CAP_SETGID if flags.contains(Flags::FL_ALLOW_SAFE_SETGID) => {
                        continue
                    }
                    caps::Capability::CAP_NET_BIND_SERVICE
                        if flags.contains(Flags::FL_ALLOW_UNSAFE_BIND) =>
                    {
                        continue
                    }
                    caps::Capability::CAP_BPF if flags.contains(Flags::FL_ALLOW_UNSAFE_EBPF) => {
                        continue
                    }
                    caps::Capability::CAP_CHOWN if flags.contains(Flags::FL_ALLOW_UNSAFE_CHOWN) => {
                        continue
                    }
                    caps::Capability::CAP_NET_RAW
                        if flags.contains(Flags::FL_ALLOW_UNSAFE_SOCKET) =>
                    {
                        continue
                    }
                    caps::Capability::CAP_SYSLOG
                        if flags.contains(Flags::FL_ALLOW_UNSAFE_SYSLOG) =>
                    {
                        continue
                    }
                    caps::Capability::CAP_SYS_TIME
                        if flags.contains(Flags::FL_ALLOW_UNSAFE_TIME) =>
                    {
                        continue
                    }
                    _ => {}
                }

                // SAFETY: Drop capabilities as early as possible.
                if caps::has_cap(None, caps::CapSet::Effective, cap)? {
                    caps::drop(None, caps::CapSet::Effective, cap)?;
                    if let Some(ref mut capdrop) = capdrop {
                        capdrop.push(cap)
                    }
                }
            }
            let mut capset = caps::read(None, caps::CapSet::Effective).unwrap_or_default();
            // SAFETY: Ensure we cannot gain the capabilities we dropped ever again.
            caps::set(None, caps::CapSet::Permitted, &capset)?;
            // SAFETY: Drop CAP_SYS_PTRACE from Inheritable capabilities.
            if !unsafe_caps && !unsafe_ptrace {
                capset.remove(&caps::Capability::CAP_SYS_PTRACE);
            }
            caps::set(None, caps::CapSet::Inheritable, &capset)?;
            if let Some(capdrop) = capdrop {
                let capdrop = capdrop
                    .into_iter()
                    .map(|cap| cap.to_string())
                    .collect::<Vec<_>>();
                let capset = capset
                    .into_iter()
                    .map(|cap| cap.to_string())
                    .collect::<Vec<_>>();
                if capdrop.is_empty() && capset.is_empty() {
                    info!("ctx": "restrict_linux_capabilities",
                        "msg": "no Linux capabilities to restrict");
                } else {
                    info!("ctx": "restrict_linux_capabilities",
                        "msg": "Linux capabilities restricted",
                        "caps_set": capset, "caps_rem": capdrop);
                }
            }
        }

        // Register as a process subreaper if we're not already pid1.
        // This is important because otherwise processes will be
        // reparented to the actual pid1, after which we can no longer
        // access their /proc/pid/mem without ptrace rights.
        let pid = Pid::this().as_raw();
        if pid != 1 {
            set_child_subreaper(true)?;
            info!("ctx": "set_child_subreaper",
                "msg": "child-subreaper attribute set",
                "sub": pid);
        }

        // Apply seccomp hardening for the Syd process itself.
        // This also inherits to the child process, and
        // unshare, mount etc. restrictions happen here.
        Self::load_seccomp_parent(flags, &ioctl_denylist, deny_namespaces, netlink_families)?;

        Ok(())
    }

    /// Insert this system call to the list of allowed system calls.
    /// No filtering is done one these system calls and they're allowed at the kernel level.
    fn allow_syscall(sysallow: &mut AllowSet, syscall: ScmpSyscall) {
        sysallow.insert(syscall);
    }

    /// Insert a system call handler.
    #[allow(clippy::cognitive_complexity)]
    fn insert_handler(
        handlers: &mut HandlerMap,
        syscall_name: &'static str,
        handler: impl Fn(UNotifyEventRequest) -> ScmpNotifResp + Clone + Send + Sync + 'static,
    ) {
        for arch in SCMP_ARCH {
            if let Ok(sys) = ScmpSyscall::from_name_by_arch(syscall_name, *arch) {
                handlers.insert(
                    Sydcall(sys, scmp_arch_raw(*arch)),
                    Arc::new(Box::new(handler.clone())),
                );
            } else {
                info!("ctx": "confine", "op": "hook_syscall",
                    "msg": format!("invalid or unsupported syscall {syscall_name}"));
            }

            // Support the new non-multiplexed network syscalls on MIPS, PPC, S390 & X86.
            let sys = match *arch {
                ScmpArch::Mips => match syscall_name {
                    "socket" => 183,
                    "bind" => 169,
                    "accept" => 168,
                    "accept4" => 334,
                    "connect" => 170,
                    "getsockname" => 172,
                    "sendto" => 180,
                    "sendmsg" => 179,
                    "sendmmsg" => 343,
                    _ => continue,
                },
                ScmpArch::Ppc | ScmpArch::Ppc64 | ScmpArch::Ppc64Le => match syscall_name {
                    "socket" => 326,
                    "bind" => 327,
                    "accept" => 330,
                    "accept4" => 344,
                    "connect" => 328,
                    "getsockname" => 331,
                    "sendto" => 335,
                    "sendmsg" => 341,
                    "sendmmsg" => 349,
                    _ => continue,
                },
                ScmpArch::S390X | ScmpArch::S390 => match syscall_name {
                    "socket" => 359,
                    "bind" => 361,
                    // no accept on s390x.
                    "accept4" => 364,
                    "connect" => 362,
                    "getsockname" => 367,
                    "sendto" => 369,
                    "sendmsg" => 370,
                    "sendmmsg" => 358,
                    _ => continue,
                },
                ScmpArch::X86 => match syscall_name {
                    "socket" => 359,
                    "bind" => 361,
                    // no accept on x86.
                    "accept4" => 364,
                    "connect" => 362,
                    "getsockname" => 367,
                    "sendto" => 369,
                    "sendmsg" => 370,
                    "sendmmsg" => 345,
                    _ => continue,
                },
                _ => continue,
            };

            handlers.insert(
                Sydcall(ScmpSyscall::from(sys), scmp_arch_raw(*arch)),
                Arc::new(Box::new(handler.clone())),
            );
        }
    }

    /// Run a command with seccomp filter.
    /// This method will fork a child process, do some preparations and run the command in it.
    #[allow(clippy::cognitive_complexity)]
    #[allow(clippy::type_complexity)]
    fn spawn(
        self,
        mut command: crate::unshare::Command,
    ) -> SydResult<(
        Arc<Epoll>,
        Arc<WorkerCache<'static>>,
        Arc<RwLock<Sandbox>>,
        Option<AesMap>,
        Option<JoinHandle<()>>,
    )> {
        // Create epoll instance.
        // We do this before spawning the child,
        // so the child can safely close their own instance
        // without racing.
        let epoll = Epoll::new(EpollCreateFlags::EPOLL_CLOEXEC)?;

        // SAFETY: Randomize the epoll fd for hardening.
        let epoll_fd = duprand(epoll.0.as_raw_fd()).map(|fd| {
            // SAFETY: duprand returns a valid FD on success.
            unsafe { OwnedFd::from_raw_fd(fd) }
        })?;
        drop(epoll);
        let epoll = Epoll(epoll_fd);
        env::set_var(ENV_POLL_FD, epoll.0.as_raw_fd().to_string());

        let seccomp_filter = self.setup_seccomp()?;
        command.seccomp_filter(seccomp_filter);

        // Spawn child under sandbox.
        let child = command.spawn()?;
        let pid = child.id();
        let fd = child.seccomp_fd;

        #[allow(clippy::cast_possible_wrap)]
        let pid = Pid::from_raw(pid as i32);
        let mut sandbox = self.sandbox.write().unwrap_or_else(|err| err.into_inner());
        sandbox.set_child(pid, child.pid_fd);
        sandbox.set_crypt()?;
        let locked = sandbox.locked();
        let safe_setid = sandbox.allow_safe_setuid() || sandbox.allow_safe_setgid();
        let cache_path_cap = sandbox.cache_path_cap;
        let cache_addr_cap = sandbox.cache_addr_cap;
        let restrict_dumps = !sandbox.allow_unsafe_dumpable();
        let sync_scmp = sandbox.sync_scmp();
        drop(sandbox);

        // Set synchronous mode if requested and supported,
        // so each syscall handler thread wakes up
        // on the same CPU as the respective sandbox process.
        if sync_scmp {
            match seccomp_notify_set_flags(fd, SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP) {
                Ok(_) => {
                    info!("ctx": "set_seccomp_synchronous_mode",
                        "msg": "set seccomp synchronous mode",
                        "fd": fd);
                }
                Err(Errno::ENOSYS) => {
                    info!("ctx": "set_seccomp_synchronous_mode",
                        "msg": "seccomp synchronous mode isn't supported on this system",
                        "fd": fd);
                }
                Err(errno) => {
                    error!("ctx": "set_seccomp_synchronous_mode",
                        "msg": format!("set seccomp synchronous mode error: {errno}"),
                        "fd": fd, "errno": errno as i32);
                    // Continue, as this mode is not significant to our use.
                }
            };
        }

        // SAFETY: Set Syd process dumpable attribute to false,
        // unless trace/allow_unsafe_dumpable:1 was passed at startup.
        // We do this after spawning the child but before spawning the
        // system call handler threads to ensure the sandbox process
        // does not inherit the attribute but cannot attach to Syd.
        if restrict_dumps {
            set_dumpable(false)?;
        }

        // SAFETY: At this point Syd has successfully forked a new
        // process to execute the sandbox process. As such Syd no longer
        // needs the execve, and execveat system calls. Let's
        // disable these critical system calls here to ensure a
        // compromised Syd process cannot abuse them.
        // EXCEPTION: Sandbox is not locked and we need exec for cmd/exec.
        let mut ctx = ScmpFilterContext::new(ScmpAction::Allow)?;
        // Enforce the NO_NEW_PRIVS functionality before
        // loading the seccomp filter into the kernel.
        ctx.set_ctl_nnp(true)?;
        // Synchronize filter to all threads.
        ctx.set_ctl_tsync(true)?;
        // We kill for bad system call and bad arch.
        ctx.set_act_badarch(ScmpAction::KillProcess)?;
        // Use a binary tree sorted by syscall number if possible.
        let _ = ctx.set_ctl_optimize(2);
        // SAFETY: Do NOT add supported architectures to the filter.
        // This ensures Syd can never run a non-native system call,
        // which we do not need at all.
        // seccomp_add_architectures(&mut ctx).map_err(|e| err2no(&e))?;

        // SAFETY: Mitigate ret2mprotect for a compromised Syd process.
        // Be swift and kill process as this attempt is most certainly
        // malicious and the kill action cannot be misused to DOS the
        // Syd process.
        // Note, mips requires executable stack so we skip on this arch.
        #[cfg(not(any(
            target_arch = "mips",
            target_arch = "mips32r6",
            target_arch = "mips64",
            target_arch = "mips64r6"
        )))]
        {
            const X: u64 = libc::PROT_EXEC as u64;
            for sysname in ["mprotect", "pkey_mprotect"] {
                #[allow(clippy::disallowed_methods)]
                let syscall = ScmpSyscall::from_name(sysname).unwrap();
                ctx.add_rule_conditional(
                    ScmpAction::KillProcess,
                    syscall,
                    &[scmp_cmp!($arg2 & X == X)],
                )?;
            }
        }

        // SAFETY: Mitigate kernel heap spraying attacks for a
        // compromised Syd process. Be swift and kill the process as
        // this attempt it most certainly malicious and the kill action
        // cannot be misused to DOS the Syd process.
        match ScmpSyscall::from_name("msgsnd") {
            Ok(syscall) => {
                ctx.add_rule(ScmpAction::KillProcess, syscall)?;
            }
            Err(_) => {
                info!("ctx": "confine", "op": "kill_syscall",
                    "msg": "invalid or unsupported syscall msgsnd");
            }
        }

        if locked {
            // SAFETY: Deny exec(3) calls if locked.
            for sysname in ["execve", "execveat"] {
                // SAFETY: Be swift and kill process as this attempt is most
                // certainly malicious and the kill action cannot be misused
                // to DOS the Syd process.
                #[allow(clippy::disallowed_methods)]
                let syscall = ScmpSyscall::from_name(sysname).unwrap();
                ctx.add_rule(ScmpAction::KillProcess, syscall)?;
            }
        }

        // SAFETY: After this point we no longer need the PTRACE_SEIZE
        // operation. Since this is a powerful operation, we apply a
        // quick seccomp filter to disable it from ever happening again.
        // This way a compromised Syd process cannot attach to any other
        // process in the system.
        // SAFETY: PTRACE_ATTACH is most certainly malicious,
        // add to kill set.
        // SAFETY: We add these ptrace rules without checking the state
        // of allow_unsafe_ptrace, because if allow_unsafe_ptrace is off we
        // have already performed the initial PTRACE_SEIZE, and if
        // allow_unsafe_ptrace is on we never need PTRACE_SEIZE to begin
        // with.
        #[allow(clippy::disallowed_methods)]
        let syscall = ScmpSyscall::from_name("ptrace").unwrap();
        #[allow(clippy::cast_lossless)]
        #[allow(clippy::cast_sign_loss)]
        for op in [libc::PTRACE_ATTACH, libc::PTRACE_SEIZE] {
            ctx.add_rule_conditional(
                ScmpAction::KillProcess,
                syscall,
                &[scmp_cmp!($arg0 == op as u64)],
            )?;
        }

        // Export seccomp rules if requested.
        if env::var_os("SYD_SECX").is_some() {
            println!("# Syd process rules");
            ctx.export_pfc(io::stdout())?;
        }

        // Load the seccomp filter unless running in debug mode.
        if !log_enabled!(LogLevel::Debug) {
            ctx.load()?;
        }

        self.supervise(epoll, fd, safe_setid, cache_path_cap, cache_addr_cap)
    }

    // Set up seccomp for the sandbox process.
    #[allow(clippy::cognitive_complexity)]
    fn setup_seccomp(&self) -> SydResult<ScmpFilterContext> {
        let mut ctx = ScmpFilterContext::new(ScmpAction::Errno(libc::ENOSYS))?;
        // Enforce the NO_NEW_PRIVS functionality before
        // loading the seccomp filter into the kernel.
        ctx.set_ctl_nnp(true)?;
        // Synchronize filter to all threads.
        ctx.set_ctl_tsync(true)?;
        // Request wait killable semantics.
        #[cfg(libseccomp_v2_6)]
        ctx.set_ctl_waitkill(true)?;
        // We deny with ENOSYS for bad/unsupported system call, and kill process for bad arch.
        ctx.set_act_badarch(ScmpAction::KillProcess)?;
        // Use a binary tree sorted by syscall number if possible.
        let _ = ctx.set_ctl_optimize(2);
        // We don't want ECANCELED, we want actual errnos.
        let _ = ctx.set_api_sysrawrc(true);

        seccomp_add_architectures(&mut ctx)?;

        // Acquire the read lock to sandbox configuration.
        let sandbox = self.sandbox.read().unwrap_or_else(|err| err.into_inner());
        // Note: if lock is None, it'll be set to Some(LockState::Set),
        // when the sandbox child starts executing.
        let is_lock = !matches!(sandbox.lock, Some(LockState::Off | LockState::Exec));
        let safe_syslog = sandbox.allow_safe_syslog();
        let deny_tsc = sandbox.deny_tsc();
        let fake_root = sandbox.fake_root();
        let has_mem = sandbox.enabled(Capability::CAP_MEM);
        let restrict_cbpf = !sandbox.allow_unsafe_cbpf();
        let restrict_ebpf = !sandbox.allow_unsafe_ebpf();
        let restrict_chroot = !sandbox.allow_unsafe_chroot();
        let restrict_cpu = !sandbox.allow_unsafe_cpu();
        let restrict_keyring = !sandbox.allow_unsafe_keyring();
        let restrict_iouring = !sandbox.allow_unsafe_iouring();
        let restrict_mount = !sandbox.flags.contains(Flags::FL_ALLOW_UNSAFE_UNSHARE_MOUNT);
        let restrict_msgsnd = !sandbox.allow_unsafe_msgsnd();
        let restrict_nice = !sandbox.allow_unsafe_nice();
        let restrict_perf = !sandbox.allow_unsafe_perf();
        let restrict_pkey = !sandbox.allow_unsafe_pkey();
        let restrict_prctl = !sandbox.allow_unsafe_prctl();
        let restrict_spec_exec = !sandbox.allow_unsafe_spec_exec();
        let restrict_sysinfo = !sandbox.allow_unsafe_sysinfo();
        let restrict_prlimit = !sandbox.allow_unsafe_prlimit();
        let restrict_ptrace = !sandbox.allow_unsafe_ptrace();
        let restrict_sigreturn = !sandbox.allow_unsafe_sigreturn();
        let restrict_sync = !sandbox.allow_unsafe_sync();
        let restrict_time = !sandbox.allow_unsafe_time();
        drop(sandbox); // release the read lock.

        // Fakeroot
        let id_action = if fake_root {
            ScmpAction::Errno(0)
        } else {
            ScmpAction::Allow
        };
        for sysname in GET_ID_SYSCALLS {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule(id_action, syscall)?;
            } else {
                info!("ctx": "confine", "op": "filter_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Add notify rules for system calls with handlers.
        // Collect names into a HashSet to ensure uniqueness across architectures.
        let mut sydset: HashSet<String, RandomState> = HashSet::default();
        for sydcall in self.handlers.keys() {
            if i32::from(sydcall.0) == __NR_SCMP_ERROR {
                // Unsupported system call for the given architecture,
                // move on.
                continue;
            }

            let name = sydcall.to_string();
            if matches!(
                name.as_str(),
                "?" | "chroot"
                    | "mmap"
                    | "mmap2"
                    | "prctl"
                    | "fcntl"
                    | "fcntl64"
                    | "sendto"
                    | "sysinfo"
                    | "syslog"
                    | "kill"
                    | "tkill"
                    | "tgkill"
                    | "rt_sigqueueinfo"
                    | "rt_tgsigqueueinfo"
                    | "sigaction"
                    | "rt_sigaction"
            ) {
                // ? -> unsupported, see Sydcall::Display.
                // We handle chroot specially below.
                // We handle mmap{,2}, and sendto specially below.
                // We handle kill calls specially below.
                // We handle prctl specially where we only hook PR_SET_NAME.
                // We handle fcntl{,64} specially where we only hook F_SETFL with O_APPEND unset.
                // We handle syslog(2) calls specially below.
                // We allow/hook sysinfo(2) based on trace/allow_unsafe_sysinfo:1 since 3.32.4
                continue;
            }

            let syscall = if sydset.insert(name.clone()) {
                if let Ok(syscall) = ScmpSyscall::from_name(&name) {
                    syscall
                } else {
                    info!("ctx": "confine", "op": "hook_syscall",
                        "msg": format!("invalid or unsupported syscall {name}"));
                    continue;
                }
            } else {
                continue;
            };

            ctx.add_rule(ScmpAction::Notify, syscall)?;
        }

        // Add allow rules for system calls in the default allow list.
        let syscall_allow: Vec<_> = self.sysallow.iter().copied().collect();
        for syscall in &syscall_allow {
            ctx.add_rule(ScmpAction::Allow, *syscall)?;
        }

        // Skip hooking into kill syscalls which are called
        // with the dummy signal 0. This is used to determine
        // the existence of processes and is considered safe use.
        for sysname in ["kill", "rt_sigqueueinfo", "tkill"] {
            let syscall = ScmpSyscall::from_name(sysname)?;
            ctx.add_rule_conditional(ScmpAction::Allow, syscall, &[scmp_cmp!($arg1 == 0)])?;
            ctx.add_rule_conditional(ScmpAction::Notify, syscall, &[scmp_cmp!($arg1 != 0)])?;
        }
        for sysname in ["tgkill", "rt_tgsigqueueinfo"] {
            let syscall = ScmpSyscall::from_name(sysname)?;
            ctx.add_rule_conditional(ScmpAction::Allow, syscall, &[scmp_cmp!($arg2 == 0)])?;
            ctx.add_rule_conditional(ScmpAction::Notify, syscall, &[scmp_cmp!($arg2 != 0)])?;
        }

        // Hook {rt_}sigaction(2) for SA_RESTART tracking.
        // Skip hooking into sigaction calls where the new action is NULL.
        for sysname in ["sigaction", "rt_sigaction"] {
            let syscall = ScmpSyscall::from_name(sysname)?;
            ctx.add_rule_conditional(ScmpAction::Allow, syscall, &[scmp_cmp!($arg1 == 0)])?;
            ctx.add_rule_conditional(ScmpAction::Notify, syscall, &[scmp_cmp!($arg1 != 0)])?;
        }

        // Since 3.32.4, we skip hooking into sysinfo(2) syscalls
        // if trace/allow_unsafe_sysinfo:1 is given.
        let sysname = "sysinfo";
        if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
            if restrict_sysinfo {
                ctx.add_rule(ScmpAction::Notify, syscall)?;
            } else {
                ctx.add_rule(ScmpAction::Allow, syscall)?;
            }
        }

        // Skip hooking into syslog(2) syscalls if the log feature
        // is off or if the sandbox has already been locked.
        let sysname = "syslog";
        #[allow(clippy::disallowed_methods)]
        let syscall = ScmpSyscall::from_name(sysname).unwrap();
        if !cfg!(feature = "log") || (!safe_syslog && is_lock) {
            ctx.add_rule(ScmpAction::Errno(libc::EPERM), syscall)?;
        } else {
            ctx.add_rule(ScmpAction::Notify, syscall)?;
        }

        // Skip hooking into sendto syscalls which are called on
        // connection-mode sockets. This type of sendto calls have
        // 4th and 5th arguments set to 0.
        if let Ok(syscall) = ScmpSyscall::from_name("sendto") {
            // NULL address with zero length: Connection-mode socket.
            ctx.add_rule_conditional(
                ScmpAction::Allow,
                syscall,
                &[scmp_cmp!($arg4 == 0), scmp_cmp!($arg5 == 0)],
            )?;
            // Non-NULL address with positive length = Notify.
            ctx.add_rule_conditional(
                ScmpAction::Notify,
                syscall,
                &[scmp_cmp!($arg4 != 0), scmp_cmp!($arg5 != 0)],
            )?;
            // NULL address with positive length = EFAULT.
            ctx.add_rule_conditional(
                ScmpAction::Errno(Errno::EFAULT as i32),
                syscall,
                &[scmp_cmp!($arg4 == 0), scmp_cmp!($arg5 != 0)],
            )?;
            // Non-NULL address with zero length = EINVAL.
            ctx.add_rule_conditional(
                ScmpAction::Errno(Errno::EINVAL as i32),
                syscall,
                &[scmp_cmp!($arg4 != 0), scmp_cmp!($arg5 == 0)],
            )?;
        }

        // Only hook into mmap{,2} calls with PROT_EXEC|!MAP_ANONYMOUS,
        // if Memory sandboxing is off and trace/allow_unsafe_ptrace:0.
        let syscalls = ["mmap", "mmap2"];
        if has_mem {
            for sysname in syscalls {
                #[allow(clippy::disallowed_methods)]
                let syscall = ScmpSyscall::from_name(sysname).unwrap();
                ctx.add_rule(ScmpAction::Notify, syscall)?;
            }
        } else if restrict_ptrace {
            for sysname in syscalls {
                #[allow(clippy::disallowed_methods)]
                let syscall = ScmpSyscall::from_name(sysname).unwrap();
                ctx.add_rule_conditional(
                    ScmpAction::Notify,
                    syscall,
                    &[
                        scmp_cmp!($arg2 & PROT_EXEC == PROT_EXEC),
                        scmp_cmp!($arg3 & MAP_ANONYMOUS == 0),
                        scmp_cmp!($arg4 <= FD_MAX),
                    ],
                )?;
                ctx.add_rule_conditional(
                    ScmpAction::Allow,
                    syscall,
                    &[scmp_cmp!($arg2 & PROT_EXEC == 0)],
                )?;
                ctx.add_rule_conditional(
                    ScmpAction::Allow,
                    syscall,
                    &[scmp_cmp!($arg3 & MAP_ANONYMOUS == MAP_ANONYMOUS)],
                )?;
                ctx.add_rule_conditional(ScmpAction::Allow, syscall, &[scmp_cmp!($arg4 > FD_MAX)])?;
            }
        } else {
            // Allow mmap & mmap2.
            // This was handled already in init,
            // so we don't have to repeat here.
        }

        // Hook chdir(2) via ptrace(2).
        #[allow(clippy::disallowed_methods)]
        let sys_chdir = ScmpSyscall::from_name("chdir").unwrap();
        if restrict_ptrace {
            ctx.add_rule(ScmpAction::Trace(PTRACE_DATA_CHDIR), sys_chdir)?;
        } else {
            // Hook into chdir with seccomp.
            // This was already done in init,
            // so we dont have to repeat here.
        }

        // Hook execve(2) and execveat(2) via ptrace(2).
        if restrict_ptrace {
            #[allow(clippy::disallowed_methods)]
            let sys_execve = ScmpSyscall::from_name("execve").unwrap();
            ctx.add_rule(ScmpAction::Trace(PTRACE_DATA_EXECVE), sys_execve)?;

            #[allow(clippy::disallowed_methods)]
            let sys_execveat = ScmpSyscall::from_name("execveat").unwrap();
            ctx.add_rule(ScmpAction::Trace(PTRACE_DATA_EXECVEAT), sys_execveat)?;
        }

        // Hook {rt_}sigreturn(2) via ptrace(2).
        #[allow(clippy::disallowed_methods)]
        let sys_sigreturn = ScmpSyscall::from_name("sigreturn").unwrap();
        #[allow(clippy::disallowed_methods)]
        let sys_rt_sigreturn = ScmpSyscall::from_name("rt_sigreturn").unwrap();
        if restrict_ptrace && restrict_sigreturn {
            ctx.add_rule(ScmpAction::Trace(PTRACE_DATA_SIGRETURN), sys_sigreturn)?;
            ctx.add_rule(
                ScmpAction::Trace(PTRACE_DATA_RT_SIGRETURN),
                sys_rt_sigreturn,
            )?;
        } else {
            // TODO: Research if something similar is doable with seccomp only.
            ctx.add_rule(ScmpAction::Allow, sys_sigreturn)?;
            ctx.add_rule(ScmpAction::Allow, sys_rt_sigreturn)?;
        }

        // Restriction 0: Turn compiled-in list of noop syscalls into no-ops (see config.rs)
        //
        // chroot being no-op depends on trace/allow_unsafe_chroot:1
        let mut noop_syscalls = NOOP_SYSCALLS.to_vec();
        if restrict_chroot {
            let sysname = "chroot";
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule(ScmpAction::Notify, syscall)?;
            } else {
                info!("ctx": "confine", "op": "noop_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        } else {
            noop_syscalls.push("chroot");
        }
        for sysname in noop_syscalls {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule(ScmpAction::Errno(0), syscall)?;
            } else {
                info!("ctx": "confine", "op": "noop_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Restriction 1: Deny unsafe set-id system calls.
        // Deny with Errno=0 -> Turn the system calls into no-op.
        // This is for compatibility, e.g. postgres invokes
        // setgroups before setuid and aborts on failure.
        for sysname in UNSAFE_ID_SYSCALLS {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule(ScmpAction::Errno(0), syscall)?;
            } else {
                info!("ctx": "confine", "op": "noop_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Restriction 2: Allowlist known-safe prctls.
        // Things like PR_SET_MM, PR_SET_PTRACER, and PR_SET_SPECULATION_CTRL are left out.
        // PR_SET_TSC is out if deny-tsc is set and allow_unsafe_prctl is unset.
        #[allow(clippy::disallowed_methods)]
        let sys_prctl = ScmpSyscall::from_name("prctl").unwrap();
        if restrict_prctl {
            for (name, opt) in ALLOWLIST_PRCTL {
                if deny_tsc && *name == "PR_SET_TSC" {
                    continue;
                }

                let act = if *name == "PR_SET_NAME" {
                    // SAFETY: Warn on PR_SET_NAME calls.
                    ScmpAction::Notify
                } else if restrict_cbpf && *name == "PR_SET_SECCOMP" {
                    // SAFETY:
                    // Deny all seccomp(2) operations with EINVAL
                    // _unless_ trace/allow_unsafe_cbpf:1 is passed at startup.
                    //
                    // Note, allowing strict mode here is going to make no difference,
                    // as the kernel will return `EINVAL` anyway because a secure
                    // computing mode is already set by Syd and strict mode differs
                    // from the current mode (filter).
                    ScmpAction::Errno(libc::EINVAL)
                } else {
                    ScmpAction::Allow
                };

                let cmp = ScmpArgCompare::new(0, ScmpCompareOp::Equal, *opt);
                ctx.add_rule_conditional(act, sys_prctl, &[cmp])?;
            }

            // Restriction 3,5: Allow access to the speculation misfeature
            // if trace/allow_unsafe_spec_exec:
            if !restrict_spec_exec {
                #[allow(clippy::cast_sign_loss)]
                for opt in [PR_GET_SPECULATION_CTRL, PR_SET_SPECULATION_CTRL] {
                    let opt = opt as u64;
                    let cmp = ScmpArgCompare::new(0, ScmpCompareOp::Equal, opt);
                    ctx.add_rule_conditional(ScmpAction::Allow, sys_prctl, &[cmp])?;
                }
            }
        } else {
            ctx.add_rule(ScmpAction::Allow, sys_prctl)?;
        }

        // Restriction 3: Disallow seccomp(2) operations with EINVAL
        // _unless_ trace/allow_unsafe_cbpf:1 is passed at startup.
        //
        // Note, allowing strict mode here is going to make no difference,
        // as the kernel will return `EINVAL` anyway because a secure
        // computing mode is already set by Syd and strict mode differs
        // from the current mode (filter).
        #[allow(clippy::disallowed_methods)]
        let sys_seccomp = ScmpSyscall::from_name("seccomp").unwrap();
        if restrict_cbpf {
            // 1. Allow SECCOMP_GET_ACTION_AVAIL & SECCOMP_GET_NOTIF_SIZES.
            // 2. Deny SECCOMP_SET_MODE_STRICT & SECCOMP_SET_MODE_FILTER with EINVAL.
            // 3. Deny all future seccomp(2) operations.
            for op in [
                libc::SECCOMP_GET_ACTION_AVAIL,
                libc::SECCOMP_GET_NOTIF_SIZES,
            ] {
                ctx.add_rule_conditional(
                    ScmpAction::Allow,
                    sys_seccomp,
                    &[scmp_cmp!($arg0 == u64::from(op))],
                )?;
            }

            for op in [libc::SECCOMP_SET_MODE_STRICT, libc::SECCOMP_SET_MODE_FILTER] {
                ctx.add_rule_conditional(
                    ScmpAction::Errno(libc::EINVAL),
                    sys_seccomp,
                    &[scmp_cmp!($arg0 == u64::from(op))],
                )?;
            }

            // Make the filter future-proof.
            const SECCOMP_OPERATION_MAX: u64 = libc::SECCOMP_GET_NOTIF_SIZES as u64;
            ctx.add_rule_conditional(
                ScmpAction::Errno(libc::EINVAL),
                sys_seccomp,
                &[scmp_cmp!($arg0 > SECCOMP_OPERATION_MAX)],
            )?;
        } else {
            ctx.add_rule(ScmpAction::Allow, sys_seccomp)?;
        }

        // Restriction 4: Disallow eBPF programs unless trace/allow_unsafe_ebpf:1
        if !restrict_ebpf {
            let sysname = "bpf";
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule(ScmpAction::Allow, syscall)?;
            } else {
                info!("ctx": "confine", "op": "allow_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Restriction 5: Disallow unsetting O_APPEND for append-only files.
        const F_SETFL: u64 = libc::F_SETFL as u64;
        const O_APPEND: u64 = libc::O_APPEND as u64;
        for sysname in ["fcntl", "fcntl64"] {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule_conditional(
                    ScmpAction::Allow,
                    syscall,
                    &[scmp_cmp!($arg1 != F_SETFL)],
                )?;
                ctx.add_rule_conditional(
                    ScmpAction::Allow,
                    syscall,
                    &[
                        scmp_cmp!($arg1 == F_SETFL),
                        scmp_cmp!($arg2 & O_APPEND == O_APPEND),
                    ],
                )?;
                ctx.add_rule_conditional(
                    ScmpAction::Notify,
                    syscall,
                    &[
                        scmp_cmp!($arg1 == F_SETFL),
                        scmp_cmp!($arg2 & O_APPEND == 0),
                    ],
                )?;
            } else {
                info!("ctx": "confine", "op": "allow_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Restriction 6: Disallow prlimit from setting resources.
        #[allow(clippy::disallowed_methods)]
        let sys_prlimit = ScmpSyscall::from_name("prlimit64").unwrap();
        if restrict_prlimit {
            // prlimit(pid_t pid, int resource,
            //         const struct rlimit *_Nullable new_limit,
            //         struct rlimit *_Nullable old_limit);
            // SAFETY: new_limit==NULL is safe.
            ctx.add_rule_conditional(ScmpAction::Allow, sys_prlimit, &[scmp_cmp!($arg2 == 0)])?;
        } else {
            #[allow(clippy::disallowed_methods)]
            let sys_setrlimit = ScmpSyscall::from_name("setrlimit").unwrap();
            ctx.add_rule(ScmpAction::Allow, sys_prlimit)?;
            ctx.add_rule(ScmpAction::Allow, sys_setrlimit)?;
        }

        // Restriction 7: Disallow CPU emulation functionality.
        if !restrict_cpu {
            for sysname in CPU_SYSCALLS {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    ctx.add_rule(ScmpAction::Allow, syscall)?;
                } else {
                    info!("ctx": "confine", "op": "allow_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        }

        // Restriction 8: Disallow Kernel keyring access.
        if !restrict_keyring {
            for sysname in KEYRING_SYSCALLS {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    ctx.add_rule(ScmpAction::Allow, syscall)?;
                } else {
                    info!("ctx": "confine", "op": "allow_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        }

        // Restriction 9: Disallow adjusting system time.
        if !restrict_time {
            for sysname in TIME_SYSCALLS {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    ctx.add_rule(ScmpAction::Allow, syscall)?;
                } else {
                    info!("ctx": "confine", "op": "allow_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        }

        // Restriction 10: Disallow io_uring interface.
        if !restrict_iouring {
            for sysname in IOURING_SYSCALLS {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    ctx.add_rule(ScmpAction::Allow, syscall)?;
                } else {
                    info!("ctx": "confine", "op": "allow_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        }

        // Restriction 11: Disallow msgsnd system call.
        if !restrict_msgsnd {
            if let Ok(syscall) = ScmpSyscall::from_name("msgsnd") {
                ctx.add_rule(ScmpAction::Allow, syscall)?;
            } else {
                info!("ctx": "confine", "op": "allow_syscall",
                    "msg": "invalid or unsupported syscall msgsnd");
            }
        }

        // Restriction 12: Disallow sync(2) and syncfs(2) system calls.
        // Use trace/allow_unsafe_sync:1 to relax the restriction.
        let action = if restrict_sync {
            ScmpAction::Errno(0)
        } else {
            ScmpAction::Allow
        };
        for sysname in SYNC_SYSCALLS {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule(action, syscall)?;
            } else {
                info!("ctx": "confine", "op": "noop_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Restriction 13: Provide stealth for PTRACE_TRACEME operation.
        // This ptrace operation is the single one that is allowed in
        // the tracee and therefore is quite often used to detect the
        // existence of a ptracer. Here we provide a best-effort
        // mitigation against this and turn PTRACE_TRACEME into a no-op
        // that always succeeds. This way a naive approach is going to
        // fail to detect a ptracer.
        // As of version 3.19.0, we turn all ptrace operations into
        // no-ops so as to provide a best-effort mitigation against
        // using requests such as PTRACE_ATTACH or PTRACE_SEIZE to
        // detect a ptracer.
        // As of version 3.25.2, we log ptrace(2) calls in case we're
        // allowing them to help with malware analysis.
        let action = if restrict_ptrace {
            ScmpAction::Errno(0)
        } else {
            ScmpAction::Allow
        };
        for sysname in PTRACE_SYSCALLS {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule(action, syscall)?;
            } else {
                info!("ctx": "confine", "op": "noop_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Restriction 14: Disallow perf.
        if !restrict_perf {
            for sysname in PERF_SYSCALLS {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    ctx.add_rule(ScmpAction::Allow, syscall)?;
                } else {
                    info!("ctx": "confine", "op": "allow_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        }

        // Restriction 15: Disallow memory protection keys.
        if !restrict_pkey {
            for sysname in PKEY_SYSCALLS {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    ctx.add_rule(ScmpAction::Allow, syscall)?;
                } else {
                    info!("ctx": "confine", "op": "allow_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        }

        // Restriction 16: Disallow mount family.
        if !restrict_mount {
            for sysname in MOUNT_SYSCALLS {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    ctx.add_rule(ScmpAction::Allow, syscall)?;
                } else {
                    info!("ctx": "confine", "op": "allow_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        }

        // Restriction 17: Disallow nice.
        if !restrict_nice {
            for sysname in NICE_SYSCALLS {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    ctx.add_rule(ScmpAction::Allow, syscall)?;
                } else {
                    info!("ctx": "confine", "op": "allow_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        }

        // Export seccomp rules if requested.
        if let Some(mode) = self.export {
            self.seccomp_export(&ctx, mode)?;
        }

        // Precompute seccomp rules which ensures:
        // 1. We fail early before spawning sandbox process on errors.
        // 2. We reduce number of memory {de,}allocations that are
        //    going to happen in the sandbox process after loading
        //    the seccomp filter but before passing the notification
        //    file descriptor back to Syd. This issue can become apparent
        //    when memory sandboxing is enabled whereby a memory
        //    {de,}allocation request can deadlock this process.
        // Note, we precompute after exporting the seccomp filter to
        // ease debugging in case of potential errors during
        // precomputation.
        #[cfg(libseccomp_v2_6)]
        ctx.precompute()?;

        Ok(ctx)
    }

    /// Set up seccomp for the Syd process which will be inherited by
    /// the child. this is important to restrict potential attack space
    /// in case Syd process is compromised somehow.
    #[allow(clippy::cognitive_complexity)]
    fn load_seccomp_parent(
        flags: Flags,
        ioctl_denylist: &[u64],
        deny_namespaces: libc::c_int,
        allow_netlink_families: NetlinkFamily,
    ) -> SydResult<()> {
        let mut ctx = ScmpFilterContext::new(ScmpAction::Allow)?;
        // Enforce the NO_NEW_PRIVS functionality before
        // loading the seccomp filter into the kernel.
        ctx.set_ctl_nnp(true)?;
        // Synchronize filter to all threads.
        ctx.set_ctl_tsync(true)?;
        // We deny with ENOSYS for bad/unsupported system call, and kill process for bad arch.
        ctx.set_act_badarch(ScmpAction::KillProcess)?;
        // Use a binary tree sorted by syscall number if possible.
        let _ = ctx.set_ctl_optimize(2);
        // We don't want ECANCELED, we want actual errnos.
        let _ = ctx.set_api_sysrawrc(true);

        // Add supported architectures.
        seccomp_add_architectures(&mut ctx)?;

        // Determine restrictions based on sandbox flags.
        let restrict_kcapi = !flags.contains(Flags::FL_ALLOW_SAFE_KCAPI);
        let restrict_personality = flags.contains(Flags::FL_LOCK_PERSONALITY);
        let restrict_socket = !flags.contains(Flags::FL_ALLOW_UNSUPP_SOCKET);

        let restrict_chroot = !flags.contains(Flags::FL_ALLOW_UNSAFE_CHROOT);
        let restrict_memory = !flags.contains(Flags::FL_ALLOW_UNSAFE_MEMORY);
        let restrict_mount = !flags.contains(Flags::FL_ALLOW_UNSAFE_UNSHARE_MOUNT);
        let restrict_nice = !flags.contains(Flags::FL_ALLOW_UNSAFE_NICE);
        let restrict_perf = !flags.contains(Flags::FL_ALLOW_UNSAFE_PERF);
        let restrict_ptrace = !flags.contains(Flags::FL_ALLOW_UNSAFE_PTRACE);
        let restrict_exec = !flags.contains(Flags::FL_ALLOW_UNSAFE_EXEC);

        // Restriction -2:
        // (a) Prevent execve where arg0==NULL||arg1==NULL||arg2==NULL
        // (b) Prevent execveat where arg1==NULL||arg2==NULL||arg3==NULL
        // On Linux, argv and envp can be specified as NULL. In
        // both cases, this has the same effect as specifying the
        // argument as a pointer to a list containing a single null
        // pointer. Do not take advantage of this nonstandard and
        // nonportable misfeature! On many other UNIX systems,
        // specifying argv as NULL will result in an error (EFAULT).
        // Some other UNIX systems treat the envp==NULL case the same as
        // Linux.
        // SAFETY: We kill the process rather than deny with EFAULT
        // because this call is most certainly malicious and this gives
        // the system administrator a notification via dmesg(1) about
        // the potentially malicious activity.
        //
        // This mitigation can be disabled with trace/allow_unsafe_exec:1.
        if restrict_exec {
            #[allow(clippy::disallowed_methods)]
            let sys_execve = ScmpSyscall::from_name("execve").unwrap();
            #[allow(clippy::disallowed_methods)]
            let sys_execveat = ScmpSyscall::from_name("execveat").unwrap();
            ctx.add_rule_conditional(
                ScmpAction::KillProcess,
                sys_execve,
                &[scmp_cmp!($arg0 == 0)],
            )?;
            ctx.add_rule_conditional(
                ScmpAction::KillProcess,
                sys_execve,
                &[scmp_cmp!($arg1 == 0)],
            )?;
            ctx.add_rule_conditional(
                ScmpAction::KillProcess,
                sys_execve,
                &[scmp_cmp!($arg2 == 0)],
            )?;
            ctx.add_rule_conditional(
                ScmpAction::KillProcess,
                sys_execveat,
                &[scmp_cmp!($arg1 == 0)],
            )?;
            ctx.add_rule_conditional(
                ScmpAction::KillProcess,
                sys_execveat,
                &[scmp_cmp!($arg2 == 0)],
            )?;
            ctx.add_rule_conditional(
                ScmpAction::KillProcess,
                sys_execveat,
                &[scmp_cmp!($arg3 == 0)],
            )?;
        }

        // Restriction -1: Prevent mmap(addr<${mmap_min_addr}, MAP_FIXED).
        // Arguably this does not give us much however ensuring mmap_min_addr
        // is constant after the start of the sandbox with zero-cost can't be bad.
        // In addition we kill the process directly rather than denying the call
        // like mmap_min_addr does, thereby giving the system administrator higher
        // chance to notice potentially malicious activity.
        if restrict_memory {
            const MAP_FIXED: u64 = libc::MAP_FIXED as u64;
            const MAP_FIXED_NOREPLACE: u64 = libc::MAP_FIXED_NOREPLACE as u64;
            for sysname in ["mmap", "mmap2"] {
                #[allow(clippy::disallowed_methods)]
                let syscall = ScmpSyscall::from_name(sysname).unwrap();
                ctx.add_rule_conditional(
                    ScmpAction::KillProcess,
                    syscall,
                    &[
                        scmp_cmp!($arg0 < *MMAP_MIN_ADDR),
                        scmp_cmp!($arg3 & MAP_FIXED == MAP_FIXED),
                    ],
                )?;
                ctx.add_rule_conditional(
                    ScmpAction::KillProcess,
                    syscall,
                    &[
                        scmp_cmp!($arg0 < *MMAP_MIN_ADDR),
                        scmp_cmp!($arg3 & MAP_FIXED_NOREPLACE == MAP_FIXED_NOREPLACE),
                    ],
                )?;
            }
        }

        // Restriction 0: Prohibit attempts to create memory mappings
        // that are writable and executable at the same time, or to
        // change existing memory mappings to become executable, or
        // mapping shared memory segments as executable.
        // Note, mips requires executable stack so we skip on this arch.
        #[cfg(not(any(
            target_arch = "mips",
            target_arch = "mips32r6",
            target_arch = "mips64",
            target_arch = "mips64r6"
        )))]
        if restrict_memory {
            const W: u64 = libc::PROT_WRITE as u64;
            const X: u64 = libc::PROT_EXEC as u64;
            const WX: u64 = W | X;
            const SHM_X: u64 = libc::SHM_EXEC as u64;
            const MAP_A: u64 = libc::MAP_ANONYMOUS as u64;
            const MAP_S: u64 = libc::MAP_SHARED as u64;
            for sysname in ["mmap", "mmap2"] {
                // Prevent writable and executable memory.
                #[allow(clippy::disallowed_methods)]
                let syscall = ScmpSyscall::from_name(sysname).unwrap();
                ctx.add_rule_conditional(
                    ScmpAction::KillProcess,
                    syscall,
                    &[scmp_cmp!($arg2 & WX == WX)],
                )?;

                // Prevent executable anonymous memory.
                ctx.add_rule_conditional(
                    ScmpAction::KillProcess,
                    syscall,
                    &[scmp_cmp!($arg2 & X == X), scmp_cmp!($arg3 & MAP_A == MAP_A)],
                )?;

                // Prevent executable shared memory.
                ctx.add_rule_conditional(
                    ScmpAction::KillProcess,
                    syscall,
                    &[scmp_cmp!($arg2 & X == X), scmp_cmp!($arg3 & MAP_S == MAP_S)],
                )?;
            }

            for sysname in ["mprotect", "pkey_mprotect"] {
                #[allow(clippy::disallowed_methods)]
                let syscall = ScmpSyscall::from_name(sysname).unwrap();
                ctx.add_rule_conditional(
                    ScmpAction::KillProcess,
                    syscall,
                    &[scmp_cmp!($arg2 & X == X)],
                )?;
            }

            let sysname = "shmat";
            #[allow(clippy::disallowed_methods)]
            let syscall = ScmpSyscall::from_name(sysname).unwrap();
            ctx.add_rule_conditional(
                ScmpAction::KillProcess,
                syscall,
                &[scmp_cmp!($arg2 & SHM_X == SHM_X)],
            )?;
        }

        // Restriction 1: Disable list of compiled-in dead system calls.
        // These system calls are not used by Syd.
        for sysname in DEAD_SYSCALLS {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule(ScmpAction::Errno(libc::ENOSYS), syscall)?;
            } else {
                info!("ctx": "confine", "op": "deny_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Restriction 2: Turn compiled-in list of noop syscalls into no-ops (see config.rs)
        for sysname in NOOP_SYSCALLS {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule(ScmpAction::Errno(0), syscall)?;
            } else {
                info!("ctx": "confine", "op": "noop_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Restriction 3: Turn chroot(2) into a no-op as necessary.
        if !restrict_chroot {
            let sysname = "chroot";
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule(ScmpAction::Errno(0), syscall)?;
            } else {
                info!("ctx": "confine", "op": "noop_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Restriction 4: Deny unsafe set-id system calls.
        // Deny with Errno=0 -> Turn the system calls into no-op.
        // This is for compatibility, e.g. postgres invokes
        // setgroups before setuid and aborts on failure.
        for sysname in UNSAFE_ID_SYSCALLS {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule(ScmpAction::Errno(0), syscall)?;
            } else {
                info!("ctx": "confine", "op": "noop_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Restriction 5: Deny transition to privileged {U,G}IDs.
        // Step 1: arg0 for UIDs.
        for sysname in &[
            "setuid",
            "setuid32",
            "setreuid",
            "setreuid32",
            "setresuid",
            "setresuid32",
        ] {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule_conditional(
                    ScmpAction::Errno(libc::EACCES),
                    syscall,
                    &[scmp_cmp!($arg0 <= UID_MIN)],
                )?;
            } else {
                info!("ctx": "confine", "op": "deny_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Step 2: arg0 for GIDs.
        for sysname in &[
            "setgid",
            "setgid32",
            "setregid",
            "setregid32",
            "setresgid",
            "setresgid32",
        ] {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule_conditional(
                    ScmpAction::Errno(libc::EACCES),
                    syscall,
                    &[scmp_cmp!($arg0 <= GID_MIN)],
                )?;
            } else {
                info!("ctx": "confine", "op": "deny_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Step 3: arg1 for UIDs.
        for sysname in &["setreuid", "setreuid32", "setresuid", "setresuid32"] {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule_conditional(
                    ScmpAction::Errno(libc::EACCES),
                    syscall,
                    &[scmp_cmp!($arg1 <= UID_MIN)],
                )?;
            } else {
                info!("ctx": "confine", "op": "deny_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Step 4: arg1 for GIDs.
        for sysname in &["setregid", "setregid32", "setresgid", "setresgid32"] {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule_conditional(
                    ScmpAction::Errno(libc::EACCES),
                    syscall,
                    &[scmp_cmp!($arg1 <= GID_MIN)],
                )?;
            } else {
                info!("ctx": "confine", "op": "deny_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Step 5: arg2 for UIDS.
        for sysname in &["setresuid", "setresuid32"] {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule_conditional(
                    ScmpAction::Errno(libc::EACCES),
                    syscall,
                    &[scmp_cmp!($arg2 <= UID_MIN)],
                )?;
            } else {
                info!("ctx": "confine", "op": "deny_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Step 6: arg2 for GIDs.
        for sysname in &["setresgid", "setresgid32"] {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule_conditional(
                    ScmpAction::Errno(libc::EACCES),
                    syscall,
                    &[scmp_cmp!($arg2 <= GID_MIN)],
                )?;
            } else {
                info!("ctx": "confine", "op": "deny_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Restriction 6: Lock changes to personality(2).
        // This restriction is turned on with trace/lock_personality.
        if restrict_personality {
            let sysname = "personality";
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule_conditional(
                    ScmpAction::Errno(libc::EACCES),
                    syscall,
                    &[scmp_cmp!($arg0 != PERSONALITY)],
                )?;
            } else {
                info!("ctx": "confine", "op": "deny_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Restriction 7: Disallow perf calls.
        if restrict_perf {
            for sysname in PERF_SYSCALLS {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    ctx.add_rule(ScmpAction::Errno(libc::EACCES), syscall)?;
                } else {
                    info!("ctx": "confine", "op": "deny_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        }

        // Restriction 8: Restrict ptrace(2) operations.
        // The TOCTOU mitigator only needs PTRACE_{CONT,LISTEN,SEIZE}.
        // The SegvGuard additionally needs PTRACE_GETEVENTMSG.
        // chdir(2) hook additionally needs PTRACE_GET_SYSCALL_INFO,
        // PTRACE_{G,S}ETREG{,SET}, PTRACE_POKEUSER, PTRACE_SYSCALL,
        // and PTRACE_SET_SYSCALL (arm only = 23).
        // chdir(2) hook additionally needs
        // PTRACE_PEEKUSER for ptrace_get_error().
        // If TOCTOU mitigator is disabled, prevent ptrace(2) completely.
        const PTRACE_DENY: &[u64] = &[
            libc::PTRACE_TRACEME as u64,
            libc::PTRACE_PEEKTEXT as u64,
            libc::PTRACE_PEEKDATA as u64,
            //libc::PTRACE_PEEKUSER as u64,
            libc::PTRACE_POKETEXT as u64,
            libc::PTRACE_POKEDATA as u64,
            //libc::PTRACE_POKEUSER as u64,
            //12, // libc::PTRACE_GETREGS as u64,
            //13, // libc::PTRACE_SETREGS as u64,
            14, // libc::PTRACE_GETFPREGS as u64,
            15, // libc::PTRACE_SETFPREGS as u64,
            //libc::PTRACE_GETREGSET as u64,
            //libc::PTRACE_SETREGSET as u64,
            libc::PTRACE_GETSIGINFO as u64,
            libc::PTRACE_SETSIGINFO as u64,
            libc::PTRACE_PEEKSIGINFO as u64,
            0x420a, //libc::PTRACE_GETSIGMASK,
            0x420b, //libc::PTRACE_SETSIGMASK,
            libc::PTRACE_SETOPTIONS as u64,
            // PTRACE_GETEVENTMSG
            // PTRACE_CONT
            // libc::PTRACE_SYSCALL as u64,
            libc::PTRACE_SINGLESTEP as u64,
            #[cfg(not(target_arch = "arm"))]
            23, //libc::PTRACE_SET_SYSCALL,
            31,
            0x1d, // libc::PTRACE_SYSEMU as u64,
            32,
            0x1e, // libc::PTRACE_SYSEMU_SINGLESTEP as u64,
            // PTRACE_LISTEN
            libc::PTRACE_KILL as u64,
            libc::PTRACE_INTERRUPT as u64,
            libc::PTRACE_ATTACH as u64,
            // PTRACE_SEIZE
            0x420c, // libc::PTRACE_SECCOMP_GET_FILTER,
            libc::PTRACE_DETACH as u64,
            22,
            25, // libc::PTRACE_GET_THREAD_AREA,
            26, // libc::PTRACE_SET_THREAD_AREA,
                //0x420e, // libc::PTRACE_GET_SYSCALL_INFO,
        ];
        let sysname = "ptrace";
        #[allow(clippy::disallowed_methods)]
        let syscall = ScmpSyscall::from_name(sysname).unwrap();
        // STATES:
        // a. restrict_ptrace=1 -> LIMITED PTRACE FOR SYD, NO PTRACE FOR BOX
        // b. restrict_ptrace=0 -> FULL PTRACE FOR SYD AND BOX
        if restrict_ptrace {
            // trace/allow_unsafe_ptrace:0 active, deny ptrace(2).
            // This is the secure default.
            // SAFETY: Provide stealth with Errno=0.
            for op in PTRACE_DENY {
                ctx.add_rule_conditional(
                    ScmpAction::Errno(0),
                    syscall,
                    &[scmp_cmp!($arg0 == *op)],
                )?;
            }
        } // else: apply default action which is Allow.

        // Restriction 9: Deny dangerous ioctl requests.
        let sysname = "ioctl";
        #[allow(clippy::disallowed_methods)]
        let syscall = ScmpSyscall::from_name(sysname).unwrap();
        for request in ioctl_denylist {
            ctx.add_rule_conditional(
                ScmpAction::Errno(libc::EACCES),
                syscall,
                &[scmp_cmp!($arg1 == *request)],
            )?;
        }

        // Restriction 10: Deny changes to program, cpu and i/o scheduling priorities.
        if restrict_nice {
            for sysname in NICE_SYSCALLS {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    ctx.add_rule(ScmpAction::Errno(libc::EACCES), syscall)?;
                } else {
                    info!("ctx": "confine", "op": "deny_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        }

        // Restriction 11: Deny mount family unless sub mount-ns is allowed.
        if restrict_mount {
            for sysname in MOUNT_SYSCALLS {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    ctx.add_rule(ScmpAction::Errno(libc::EACCES), syscall)?;
                } else {
                    info!("ctx": "confine", "op": "deny_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        }

        // Restriction 12: Restrict sub namespace creation.
        let (namespace_act, namespace_acl) = if deny_namespaces == 0 {
            (Action::Allow, None)
        } else {
            let sysname_ns = "setns";
            #[allow(clippy::disallowed_methods)]
            let syscall_ns = ScmpSyscall::from_name(sysname_ns).unwrap();
            let deny_all = deny_namespaces & NAMESPACE_FLAGS_ALL == NAMESPACE_FLAGS_ALL;
            let namespace_act = if deny_all {
                // If every single kind of namespace shall be
                // prohibited, then let's block the whole setns()
                // syscall altogether.
                ctx.add_rule(ScmpAction::Errno(libc::EACCES), syscall_ns)?;
                Action::Deny
            } else {
                // Otherwise, block only the invocations with the
                // appropriate flags in the loop below, but also the
                // special invocation with a zero flags argument, right
                // here.
                ctx.add_rule_conditional(
                    ScmpAction::Errno(libc::EACCES),
                    syscall_ns,
                    &[scmp_cmp!($arg1 == 0)],
                )?;
                Action::Filter
            };

            let sysname_cl = "clone";
            let sysname_un = "unshare";
            #[allow(clippy::disallowed_methods)]
            let syscall_cl = ScmpSyscall::from_name(sysname_cl).unwrap();
            #[allow(clippy::disallowed_methods)]
            let syscall_un = ScmpSyscall::from_name(sysname_un).unwrap();
            let mut ns_deny = vec![];
            let mut ns_allow = vec![];
            for flag in NAMESPACE_FLAGS {
                if deny_namespaces & flag == 0 {
                    ns_allow.push(nsflag_name(*flag));
                    continue;
                } else {
                    ns_deny.push(nsflag_name(*flag));
                }

                #[allow(clippy::cast_sign_loss)]
                let flag = *flag as u64;
                ctx.add_rule_conditional(
                    ScmpAction::Errno(libc::EACCES),
                    syscall_un,
                    &[scmp_cmp!($arg0 & flag == flag)],
                )?;

                // On s390/s390x the first two parameters to clone are switched.
                if !cfg!(target_arch = "s390x") {
                    ctx.add_rule_conditional(
                        ScmpAction::Errno(libc::EACCES),
                        syscall_cl,
                        &[scmp_cmp!($arg0 & flag == flag)],
                    )?;
                } else {
                    ctx.add_rule_conditional(
                        ScmpAction::Errno(libc::EACCES),
                        syscall_cl,
                        &[scmp_cmp!($arg1 & flag == flag)],
                    )?;
                }

                if !deny_all {
                    ctx.add_rule_conditional(
                        ScmpAction::Errno(libc::EACCES),
                        syscall_ns,
                        &[scmp_cmp!($arg1 & flag == flag)],
                    )?;
                }
            }

            if namespace_act == Action::Deny {
                (namespace_act, None)
            } else {
                (namespace_act, Some((ns_deny, ns_allow)))
            }
        };

        match (namespace_act, namespace_acl) {
            (Action::Allow, _) => info!(
                "ctx": "restrict_namespaces",
                "msg": "namespace creation allowed",
                "ns_allow": NAMESPACE_NAMES),
            (Action::Deny, _) => info!(
                "ctx": "restrict_namespaces",
                "msg": "namespace creation denied",
                "ns_deny": NAMESPACE_NAMES),
            (_, Some((acl_deny, acl_allow))) => info!(
                "ctx": "restrict_namespaces",
                "msg": "namespace creation filtered",
                "ns_deny": acl_deny,
                "ns_allow": acl_allow),
            _ => unreachable!(),
        };

        // Export seccomp rules if requested.
        if std::env::var_os("SYD_SECX").is_some() {
            println!("# Syd parent rules");
            ctx.export_pfc(io::stdout())?;
        }

        // Load the seccomp filter unless running in debug mode.
        if !log_enabled!(LogLevel::Debug) {
            ctx.load()?;
        }

        // Restriction 13: Restrict socket domains based on flags.
        // SAFETY: socket may not exist on every architecture.
        // On some arches such as x86 there's the socketcall
        // system call which involves a pointer indirection
        // for the domain argument therefore on these arches
        // we rely on our socketcall seccomp-notify hook to
        // achieve the same effect.
        if !restrict_socket && !restrict_kcapi {
            return Ok(()); // No need for an additional socket filter.
        } else if seccomp_native_has_socketcall() {
            // Export seccomp rules if requested.
            if std::env::var_os("SYD_SECX").is_some() {
                println!("# Syd socket rules");
                println!("# Not applicable on this architecture!");
            }
        } else {
            let mut ctx = ScmpFilterContext::new(ScmpAction::Allow)?;
            // Enforce the NO_NEW_PRIVS functionality before
            // loading the seccomp filter into the kernel.
            ctx.set_ctl_nnp(true)?;
            // Synchronize filter to all threads.
            ctx.set_ctl_tsync(true)?;
            // SAFETY: We do allow bad architecture, see the comment above.
            ctx.set_act_badarch(ScmpAction::Allow)?;
            // Use a binary tree sorted by syscall number if possible.
            let _ = ctx.set_ctl_optimize(2);
            // SAFETY: Do not add supported architectures, this filter
            // is for the native architecture only.
            // seccomp_add_architectures(&mut ctx)?;
            // We don't want ECANCELED, we want actual errnos.
            let _ = ctx.set_api_sysrawrc(true);

            #[allow(clippy::disallowed_methods)]
            let syscall = ScmpSyscall::from_name("socket").unwrap();
            if restrict_socket {
                // TODO: libc:: should define this!
                const AF_MAX: libc::c_int = 45;
                // Only allow AF_{UNIX,INET,INET6,NETLINK} by default
                let mut allow_domains: HashSet<libc::c_int, RandomState> = HashSet::from_iter([
                    libc::AF_UNIX,
                    libc::AF_INET,
                    libc::AF_INET6,
                    libc::AF_NETLINK,
                ]);
                if !restrict_kcapi {
                    // Allow KCAPI as well.
                    allow_domains.insert(libc::AF_ALG);
                }

                for domain in 0..AF_MAX {
                    if allow_domains.contains(&domain) {
                        continue;
                    }
                    #[allow(clippy::cast_sign_loss)]
                    ctx.add_rule_conditional(
                        ScmpAction::Errno(libc::EAFNOSUPPORT),
                        syscall,
                        &[scmp_cmp!($arg0 == domain as u64)],
                    )?;
                }

                // SAFETY: Guard against new AF_* that may be added in the future.
                ctx.add_rule_conditional(
                    ScmpAction::Errno(libc::EAFNOSUPPORT),
                    syscall,
                    &[scmp_cmp!($arg0 >= AF_MAX as u64)],
                )?;

                // SAFETY: Restrict AF_NETLINK families.
                if allow_netlink_families.is_empty() {
                    // No netlink families were allowed, deny all of AF_NETLINK.
                    // See comment above on the usage of _exact.
                    ctx.add_rule_conditional(
                        ScmpAction::Errno(libc::EAFNOSUPPORT),
                        syscall,
                        &[scmp_cmp!($arg0 == libc::AF_NETLINK as u64)],
                    )?;
                } else {
                    let allow_netlink_families = allow_netlink_families.to_vec();
                    let netlink_family_max = NetlinkFamily::max();
                    for netlink_family in 0..netlink_family_max {
                        if allow_netlink_families.contains(&netlink_family) {
                            continue;
                        }
                        // See comment above on the usage of _exact.
                        #[allow(clippy::cast_sign_loss)]
                        ctx.add_rule_conditional(
                            ScmpAction::Errno(libc::EAFNOSUPPORT),
                            syscall,
                            &[
                                scmp_cmp!($arg0 == libc::AF_NETLINK as u64),
                                scmp_cmp!($arg2 == netlink_family as u64),
                            ],
                        )?;
                    }
                    // SAFETY: Guard against new netlink families that may be added in the future.
                    #[allow(clippy::cast_sign_loss)]
                    ctx.add_rule_conditional(
                        ScmpAction::Errno(libc::EAFNOSUPPORT),
                        syscall,
                        &[
                            scmp_cmp!($arg0 == libc::AF_NETLINK as u64),
                            scmp_cmp!($arg2 > netlink_family_max as u64),
                        ],
                    )?;
                }
            } else if restrict_kcapi {
                ctx.add_rule_conditional(
                    ScmpAction::Errno(libc::EAFNOSUPPORT),
                    syscall,
                    &[scmp_cmp!($arg0 == libc::AF_ALG as u64)],
                )?;
            }

            // Export seccomp rules if requested.
            if std::env::var_os("SYD_SECX").is_some() {
                println!("# Syd socket rules");
                ctx.export_pfc(io::stdout())?;
            }

            // Load the seccomp filter unless running in debug mode.
            if !log_enabled!(LogLevel::Debug) {
                ctx.load()?;
            }
        }

        Ok(())
    }

    /// Export a seccomp context as bpf or pfc.
    fn seccomp_export(&self, ctx: &ScmpFilterContext, mode: ExportMode) -> SydResult<()> {
        match mode {
            ExportMode::BerkeleyPacketFilter => Ok(ctx.export_bpf(io::stdout())?),
            ExportMode::PseudoFiltercode => {
                let (fd, path) = mkstemp("syd-tmp-XXXXXX")?;
                unlink(path.as_path())?;
                // SAFETY: mkstemp returns a valid FD.
                let mut file = unsafe { File::from_raw_fd(fd) };

                ctx.export_pfc(&mut file)?;

                file.seek(SeekFrom::Start(0))?;
                let mut buffer = Vec::new();
                file.read_to_end(&mut buffer)?;

                let output = String::from_utf8_lossy(&buffer);
                let output = output.replace("0x7fc00000", "NOTIFY");

                let libver = ScmpVersion::current()?;
                println!(
                    "# Syd v{} seccomp rules generated by libseccomp v{}.{}.{}",
                    env!("CARGO_PKG_VERSION"),
                    libver.major,
                    libver.minor,
                    libver.micro
                );
                println!("# API Version: {API_VERSION}");

                #[allow(clippy::disallowed_methods)]
                let mut syscall_allow: Vec<_> = self
                    .sysallow
                    .iter()
                    .copied()
                    .map(|sys| sys.get_name().unwrap())
                    .collect();
                let syscall_notif: HashSet<String, RandomState> = self.handlers
                    .keys()
                    .map(|key| key.0.to_string()) // Extract the name from keys
                    .collect(); // Collect names into a HashSet to ensure uniqueness
                let mut syscall_notif: Vec<String> = syscall_notif.into_iter().collect();
                syscall_allow.sort();
                syscall_notif.sort();

                println!("# System calls with Action=ALLOW: {}", syscall_allow.len());
                println!("# System calls with Action=NOTIF: {}", syscall_notif.len());

                let uidcall = GET_ID_SYSCALLS.to_vec().join(", ");
                let sandbox = self.sandbox.read().unwrap_or_else(|err| err.into_inner());
                println!(
                    "# Fake Root: {} ( {uidcall} )",
                    if sandbox.fake_root() { "yes" } else { "no" }
                );
                println!(
                    "{}",
                    sandbox
                        .to_string()
                        .lines()
                        .map(|line| format!("# {}", line))
                        .collect::<Vec<_>>()
                        .join("\n")
                );
                drop(sandbox);

                println!("# Action=NOTIF: {}", syscall_notif.len());
                for name in &syscall_notif {
                    println!("#    - {name}");
                }
                println!("# Action=ALLOW: {}", syscall_allow.len());
                for name in &syscall_allow {
                    println!("#    - {name}");
                }
                print!("{output}");
                Ok(())
            }
        }
    }

    /// Logic for the supervise child thread.
    #[allow(clippy::type_complexity)]
    fn supervise(
        self,
        epoll: Epoll,
        fd: RawFd,
        safe_setid: bool,
        cache_path_cap: usize,
        cache_addr_cap: usize,
    ) -> SydResult<(
        Arc<Epoll>,
        Arc<WorkerCache<'static>>,
        Arc<RwLock<Sandbox>>,
        Option<AesMap>,
        Option<JoinHandle<()>>,
    )> {
        // Set (process-wide) umask to 0.
        let _ = umask(Mode::empty());

        // Spawn the syscall handler pool.
        let syshandler_pool = pool::ThreadPool::new(
            epoll,
            fd,
            safe_setid,
            *EMU_POOL_SIZE,
            EMU_KEEP_ALIVE,
            Arc::clone(&self.sandbox),
            Arc::clone(&self.handlers),
            self.crypt_map.as_ref().map(Arc::clone),
            cache_path_cap,
            cache_addr_cap,
        )?;

        // Clone the Epoll instance to pass to the main thread.
        let epoll = Arc::clone(&syshandler_pool.epoll);

        // Clone the WorkerCache instance to pass to the main thread.
        let cache = Arc::clone(&syshandler_pool.cache);

        // Boot the thread pool!
        let crypt_handle = syshandler_pool.boot()?;

        // We return a clone of the cache and the sandbox to the caller.
        // exec-TOCTOU-mitigator uses this instance in the wait loop.
        Ok((
            epoll,
            cache,
            Arc::clone(&self.sandbox),
            self.crypt_map.as_ref().map(Arc::clone),
            crypt_handle,
        ))
    }

    /// Wait for the child process to exit.
    /// It returns the exit code of the process.
    #[allow(clippy::cognitive_complexity)]
    fn wait(
        epoll: Arc<Epoll>,
        cache: Arc<WorkerCache>,
        sandbox: Arc<RwLock<Sandbox>>,
        crypt_map: Option<AesMap>,
        crypt_handle: Option<JoinHandle<()>>,
    ) -> SydResult<u8> {
        let my_sandbox = SandboxGuard::Read(sandbox.read().unwrap_or_else(|err| err.into_inner()));
        let child = my_sandbox.get_child_pid();
        let wait_all = my_sandbox.exit_wait_all();
        let safe_setid = my_sandbox.allow_safe_setuid() || my_sandbox.allow_safe_setgid();
        let transit_uids = my_sandbox.transit_uids.clone();
        let transit_gids = my_sandbox.transit_gids.clone();
        drop(my_sandbox); // release the read lock.

        // SAFETY: Confine the main thread.
        let (act, dry_run) = if env::var_os(ENV_SKIP_SCMP).is_some() {
            error!("ctx": "confine", "op": "confine_main_thread",
                "msg": "main thread is running unconfined in debug mode");
            (ScmpAction::Log, true)
        } else {
            (ScmpAction::KillProcess, false)
        };

        let mut ctx = ScmpFilterContext::new(act)?;

        // Enforce the NO_NEW_PRIVS functionality before
        // loading the seccomp filter into the kernel.
        ctx.set_ctl_nnp(true)?;

        // DO NOT synchronize filter to all threads.
        // Thread pool confines itself as necessary.
        ctx.set_ctl_tsync(false)?;

        // We kill for bad system call and bad arch.
        ctx.set_act_badarch(ScmpAction::KillProcess)?;

        // Use a binary tree sorted by syscall number if possible.
        let _ = ctx.set_ctl_optimize(2);

        // SAFETY: Do NOT add supported architectures to the filter.
        // This ensures Syd can never run a non-native system call,
        // which we do not need at all.
        // seccomp_add_architectures(&mut ctx)?;

        // Deny open and {l,}stat with ENOSYS rather than KillProcess.
        // We need this because std::thread::spawn has unwanted
        // side-effects such as opening /sys/devices/system/cpu/online
        // on some architectures.
        for sysname in ["open", "stat", "lstat"] {
            match ScmpSyscall::from_name(sysname) {
                Ok(syscall) => {
                    ctx.add_rule(ScmpAction::Errno(Errno::ENOSYS as i32), syscall)?;
                }
                Err(_) => {
                    info!("ctx": "confine", "op": "allow_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        }

        // Allow epoll(7) API to our single epoll fd only.
        //
        // Only allow the control interface to add new FDs.
        // The main thread does not wait on the epoll FD.
        #[allow(clippy::cast_sign_loss)]
        let epoll_fd = epoll.0.as_raw_fd() as u64;
        for sysname in ["epoll_ctl", "epoll_ctl_old"] {
            match ScmpSyscall::from_name(sysname) {
                Ok(syscall) => {
                    ctx.add_rule_conditional(
                        ScmpAction::Allow,
                        syscall,
                        &[scmp_cmp!($arg0 == epoll_fd)],
                    )?;
                }
                Err(_) => {
                    info!("ctx": "confine", "op": "allow_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        }

        // SAFETY: Allow write(2) _only_ if trace/memory_access allows
        // proc_pid_mem(5) access in which case we cannot avoid it.
        // The default is to use cross memory attach with
        // process_vm_{read,write}v(2) unconditionally since
        // version 3.32.6 unless relaxed.
        let sysname = "write";
        if Sandbox::memory_access() == 2 {
            // Allow write(2) access to syd::log::LOG_FD only.
            // If logging is disabled, deny write(2) completely.
            // Note, we do allow the use-case where LOG_FD is
            // intentionally set to a negative value to disable
            // logging, hence we cast directly to an u64 and not
            // use u64::try_from!
            let log_fd = crate::log::LOG_FD.load(std::sync::atomic::Ordering::Relaxed);
            match ScmpSyscall::from_name(sysname) {
                Ok(syscall) => {
                    ctx.add_rule_conditional(
                        ScmpAction::Allow,
                        syscall,
                        &[scmp_cmp!($arg0 == log_fd as u64)],
                    )?;
                }
                Err(_) => {
                    crate::info!("ctx": "confine", "op": "allow_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        } else {
            // Allow write(2) globally for proc_pid_mem(5) access.
            match ScmpSyscall::from_name(sysname) {
                Ok(syscall) => {
                    ctx.add_rule(ScmpAction::Allow, syscall)?;
                }
                Err(_) => {
                    crate::info!("ctx": "confine", "op": "allow_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        }

        // Allow safe fcntl(2) utility calls.
        for sysname in ["fcntl", "fcntl64"] {
            let syscall = match ScmpSyscall::from_name(sysname) {
                Ok(syscall) => syscall,
                Err(_) => {
                    crate::info!("ctx": "confine", "op": "allow_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                    continue;
                }
            };

            for op in MAIN_FCNTL_OPS {
                ctx.add_rule_conditional(ScmpAction::Allow, syscall, &[scmp_cmp!($arg1 == *op)])?;
            }
        }

        // Allow safe system calls.
        for sysname in MAIN_SYSCALLS {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule(ScmpAction::Allow, syscall)?;
            } else {
                info!("ctx": "confine", "op": "allow_main_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // openat(2) may be used to open the parent directory only by getdir_long()
        // The rest of the attempts are denied with ENOSYS for compat.
        let sysname = "openat";
        #[allow(clippy::cast_sign_loss)]
        match ScmpSyscall::from_name(sysname) {
            Ok(syscall) => {
                let dotdot = dotdot_with_nul();
                let oflags = (libc::O_RDONLY
                    | libc::O_CLOEXEC
                    | libc::O_DIRECTORY
                    | libc::O_LARGEFILE
                    | libc::O_NOCTTY
                    | libc::O_NOFOLLOW) as u64;
                ctx.add_rule_conditional(
                    ScmpAction::Allow,
                    syscall,
                    &[
                        scmp_cmp!($arg0 <= RawFd::MAX as u64),
                        scmp_cmp!($arg1 == dotdot),
                        scmp_cmp!($arg2 & oflags == oflags),
                    ],
                )?;
                ctx.add_rule_conditional(
                    ScmpAction::Errno(Errno::ENOSYS as i32),
                    syscall,
                    &[scmp_cmp!($arg0 > RawFd::MAX as u64)],
                )?;
                ctx.add_rule_conditional(
                    ScmpAction::Errno(Errno::ENOSYS as i32),
                    syscall,
                    &[scmp_cmp!($arg1 != dotdot)],
                )?;
            }
            Err(_) => {
                info!("ctx": "confine", "op": "allow_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Allow futex system calls.
        for sysname in FUTEX_SYSCALLS {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule(ScmpAction::Allow, syscall)?;
            } else {
                info!("ctx": "confine", "op": "allow_main_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Allow getid system calls.
        for sysname in GET_ID_SYSCALLS {
            if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                ctx.add_rule(ScmpAction::Allow, syscall)?;
            } else {
                info!("ctx": "confine", "op": "allow_main_syscall",
                    "msg": format!("invalid or unsupported syscall {sysname}"));
            }
        }

        // Allow AF_UNIX sockets for syslog.
        if env::var_os(ENV_NO_SYSLOG).is_none() {
            const AF_UNIX: u64 = libc::AF_UNIX as u64;
            #[allow(clippy::disallowed_methods)]
            let syscall = ScmpSyscall::from_name("socket").unwrap();
            ctx.add_rule_conditional(ScmpAction::Allow, syscall, &[scmp_cmp!($arg0 == AF_UNIX)])?;

            // Only allow send to connection-mode sockets.
            #[allow(clippy::disallowed_methods)]
            ctx.add_rule_conditional(
                ScmpAction::Allow,
                ScmpSyscall::from_name("sendto").unwrap(),
                &[scmp_cmp!($arg4 == 0), scmp_cmp!($arg5 == 0)],
            )?;

            for sysname in ["connect", "send"] {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    ctx.add_rule(ScmpAction::Allow, syscall)?;
                }
            }
        }

        // Set-ID system calls are per-process!
        if safe_setid {
            // SAFETY:
            // Signal system calls are necessary to handle reserved signals.
            for sysname in ["sigreturn", "rt_sigreturn"] {
                match ScmpSyscall::from_name(sysname) {
                    Ok(syscall) => {
                        ctx.add_rule(ScmpAction::Allow, syscall)?;
                    }
                    Err(_) => {
                        info!("ctx": "confine", "op": "allow_syscall",
                            "msg": format!("invalid or unsupported syscall {sysname}"));
                    }
                }
            }

            // SAFETY: Only allow defined UID/GID transitions.
            let source_uid = Uid::current();
            let source_gid = Gid::current();
            const NULL_ID: u64 = u64::MAX;

            for sysname in &["setuid", "setuid32"] {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    for (s_uid, t_uid) in &transit_uids {
                        if source_uid == *s_uid {
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[scmp_cmp!($arg0 == u64::from(t_uid.as_raw()))],
                            )?;
                        }
                    }
                } else {
                    info!("ctx": "confine", "op": "filter_main_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }

            for sysname in &["setgid", "setgid32"] {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    for (s_gid, t_gid) in &transit_gids {
                        if source_gid == *s_gid {
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[scmp_cmp!($arg0 == u64::from(t_gid.as_raw()))],
                            )?;
                        }
                    }
                } else {
                    info!("ctx": "confine", "op": "filter_main_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }

            for sysname in &["setreuid", "setreuid32"] {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    for (s_uid, t_uid) in &transit_uids {
                        if source_uid == *s_uid {
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == u64::from(t_uid.as_raw())),
                                    scmp_cmp!($arg1 == u64::from(t_uid.as_raw())),
                                ],
                            )?;
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == NULL_ID),
                                    scmp_cmp!($arg1 == u64::from(t_uid.as_raw())),
                                ],
                            )?;
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == u64::from(t_uid.as_raw())),
                                    scmp_cmp!($arg1 == NULL_ID),
                                ],
                            )?;
                        }
                    }
                } else {
                    info!("ctx": "confine", "op": "filter_main_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }

            for sysname in &["setregid", "setregid32"] {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    for (s_gid, t_gid) in &transit_gids {
                        if source_gid == *s_gid {
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == u64::from(t_gid.as_raw())),
                                    scmp_cmp!($arg1 == u64::from(t_gid.as_raw())),
                                ],
                            )?;
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == NULL_ID),
                                    scmp_cmp!($arg1 == u64::from(t_gid.as_raw())),
                                ],
                            )?;
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == u64::from(t_gid.as_raw())),
                                    scmp_cmp!($arg1 == NULL_ID),
                                ],
                            )?;
                        }
                    }
                } else {
                    info!("ctx": "confine", "op": "filter_main_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }

            for sysname in &["setresuid", "setresuid32"] {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    for (s_uid, t_uid) in &transit_uids {
                        if source_uid == *s_uid {
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == u64::from(t_uid.as_raw())),
                                    scmp_cmp!($arg1 == u64::from(t_uid.as_raw())),
                                    scmp_cmp!($arg2 == u64::from(t_uid.as_raw())),
                                ],
                            )?;
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == NULL_ID),
                                    scmp_cmp!($arg1 == u64::from(t_uid.as_raw())),
                                    scmp_cmp!($arg2 == u64::from(t_uid.as_raw())),
                                ],
                            )?;
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == u64::from(t_uid.as_raw())),
                                    scmp_cmp!($arg1 == NULL_ID),
                                    scmp_cmp!($arg2 == u64::from(t_uid.as_raw())),
                                ],
                            )?;
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == u64::from(t_uid.as_raw())),
                                    scmp_cmp!($arg1 == u64::from(t_uid.as_raw())),
                                    scmp_cmp!($arg2 == NULL_ID),
                                ],
                            )?;
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == NULL_ID),
                                    scmp_cmp!($arg1 == NULL_ID),
                                    scmp_cmp!($arg2 == u64::from(t_uid.as_raw())),
                                ],
                            )?;
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == NULL_ID),
                                    scmp_cmp!($arg1 == u64::from(t_uid.as_raw())),
                                    scmp_cmp!($arg2 == NULL_ID),
                                ],
                            )?;
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == u64::from(t_uid.as_raw())),
                                    scmp_cmp!($arg1 == NULL_ID),
                                    scmp_cmp!($arg2 == NULL_ID),
                                ],
                            )?;
                        }
                    }
                } else {
                    info!("ctx": "confine", "op": "filter_main_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }

            for sysname in &["setresgid", "setresgid32"] {
                if let Ok(syscall) = ScmpSyscall::from_name(sysname) {
                    for (s_gid, t_gid) in &transit_gids {
                        if source_gid == *s_gid {
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == u64::from(t_gid.as_raw())),
                                    scmp_cmp!($arg1 == u64::from(t_gid.as_raw())),
                                    scmp_cmp!($arg2 == u64::from(t_gid.as_raw())),
                                ],
                            )?;
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == NULL_ID),
                                    scmp_cmp!($arg1 == u64::from(t_gid.as_raw())),
                                    scmp_cmp!($arg2 == u64::from(t_gid.as_raw())),
                                ],
                            )?;
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == u64::from(t_gid.as_raw())),
                                    scmp_cmp!($arg1 == NULL_ID),
                                    scmp_cmp!($arg2 == u64::from(t_gid.as_raw())),
                                ],
                            )?;
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == u64::from(t_gid.as_raw())),
                                    scmp_cmp!($arg1 == u64::from(t_gid.as_raw())),
                                    scmp_cmp!($arg2 == NULL_ID),
                                ],
                            )?;
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == NULL_ID),
                                    scmp_cmp!($arg1 == NULL_ID),
                                    scmp_cmp!($arg2 == u64::from(t_gid.as_raw())),
                                ],
                            )?;
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == NULL_ID),
                                    scmp_cmp!($arg1 == u64::from(t_gid.as_raw())),
                                    scmp_cmp!($arg2 == NULL_ID),
                                ],
                            )?;
                            ctx.add_rule_conditional(
                                ScmpAction::Allow,
                                syscall,
                                &[
                                    scmp_cmp!($arg0 == u64::from(t_gid.as_raw())),
                                    scmp_cmp!($arg1 == NULL_ID),
                                    scmp_cmp!($arg2 == NULL_ID),
                                ],
                            )?;
                        }
                    }
                } else {
                    info!("ctx": "confine", "op": "filter_main_syscall",
                        "msg": format!("invalid or unsupported syscall {sysname}"));
                }
            }
        }

        // Export seccomp rules if requested.
        if std::env::var_os("SYD_SECX").is_some() {
            println!("# Syd waiter rules");
            let _ = ctx.export_pfc(std::io::stdout());
        }

        // All set, load the filter!
        if !dry_run {
            // Set a logging panic hook. The default panic
            // hook calls system calls not permitted by emulators
            // such as getcwd(2), stat(2) etc.
            std::panic::set_hook(Box::new(|info| {
                let err = match info.payload().downcast_ref::<&'static str>() {
                    Some(s) => *s,
                    None => match info.payload().downcast_ref::<String>() {
                        Some(s) => &**s,
                        None => "?",
                    },
                };
                let file = info.location().map(|l| l.file());
                let line = info.location().map(|l| l.line());
                error!("ctx": "panic", "err": err, "file": file, "line": line);
            }));

            ctx.load()?;

            info!("ctx": "confine", "op": "confine_main_thread",
                "msg": format!("main thread confined with{} SROP mitigation",
                    if safe_setid { "out" } else { "" }));
        }

        let mut exit_code: i32 = 127;
        'waitloop: loop {
            match waitid(Id::All, WaitPidFlag::WEXITED | WaitPidFlag::__WNOTHREAD) {
                Ok(WaitStatus::Exited(pid, code)) => {
                    if pid == child {
                        exit_code = code;
                        if !wait_all {
                            break;
                        }
                    }

                    // Retire the PidFd.
                    if let Some(map) = PIDFD_MAP.get() {
                        map.del_pidfd(pid);
                    }
                }
                Ok(WaitStatus::Signaled(pid, signal, _core)) => {
                    if pid == child {
                        exit_code = 128_i32.saturating_add(signal);
                        if !wait_all {
                            break;
                        }
                    }

                    // Retire the PidFd.
                    if let Some(map) = PIDFD_MAP.get() {
                        map.del_pidfd(pid);
                    }
                }
                Ok(WaitStatus::PtraceEvent(
                    pid,
                    libc::SIGSTOP | libc::SIGTSTP | libc::SIGTTIN | libc::SIGTTOU,
                    libc::PTRACE_EVENT_STOP,
                )) => {
                    // SAFETY: nix does not have a wrapper for PTRACE_LISTEN,s
                    // so we fallback to libc here.
                    let _ = unsafe { libc::ptrace(libc::PTRACE_LISTEN, pid.as_raw(), 0, 0) };
                }
                Ok(WaitStatus::PtraceEvent(
                    pid,
                    _, // Can this ever be !SIGTRAP?
                    libc::PTRACE_EVENT_STOP,
                )) => {
                    // ptrace-stop, do not forward the signal.
                    let _ = ptrace::cont(pid, None);
                }
                Ok(WaitStatus::PtraceEvent(pid, sig, 0)) => {
                    // Pid received genuine signal:
                    // 1. Check if this signal has a handler.
                    // 2. If (1) is yes, increase signal count for SROP mitigation.

                    let process =
                        // SAFETY: We cannot validate the request here,
                        // however we can use a cached PidFd if available!
                        match unsafe { RemoteProcess::from_tid(pid) } {
                            Ok(process) => process,
                            Err(Errno::ESRCH) => continue,
                            Err(_) => {
                                // SAFETY: Failed to open pidfd but process
                                // is still alive. Terminate!
                                let _ = kill(pid, Some(Signal::SIGKILL));
                                continue;
                            }
                        };

                    // SAFETY: Check for signal status in /proc/pid/status.
                    let status = match proc_status(pid) {
                        Ok(status) => status,
                        Err(Errno::ESRCH) => {
                            // SAFETY: Process already dead, continue.
                            continue;
                        }
                        Err(errno) => {
                            // SAFETY: Failed to get process status, terminate the process.
                            error!("ctx": "handle_signal", "op": "read_status",
                                "err": format!("failed to read /proc/{}/status: {errno}", pid.as_raw()),
                                "tip": "check with SYD_LOG=debug and/or submit a bug report");
                            let _ = process.pidfd_kill(libc::SIGKILL);
                            continue;
                        }
                    };

                    if status.sig_caught.contains(sig) {
                        // SAFETY:
                        // 1. Increase expected sigreturn(2) count, now that
                        //    we're forwarding a signal to the sandbox
                        //    process.
                        // 2. Signal handlers are per-process not per-thread!
                        cache.inc_sig_handle(Pid::from_raw(status.pid));
                    }

                    // SAFETY: nix Signal type does not include realtime signals,
                    // so we fallback to libc here.
                    let _ = unsafe { libc::ptrace(libc::PTRACE_CONT, pid.as_raw(), 0, sig) };
                }
                Ok(WaitStatus::PtraceEvent(pid, libc::SIGTRAP, libc::PTRACE_EVENT_SECCOMP)) => {
                    // This is ptrace syscall entry stop.
                    //
                    // SAFETY: Verify with PTRACE_GET_SYSCALL_INFO.
                    let info = match ptrace_get_syscall_info(pid) {
                        Ok(info) if info.seccomp().is_none() => {
                            // unreachable!("BUG: Invalid syscall info returned by Linux: {info:?}")
                            // trinity manages to reliably trigger this with op=0.
                            // SAFETY: Failed to get syscall info but
                            // process is still alive. Terminate!
                            let _ = kill(pid, Some(Signal::SIGKILL));
                            continue;
                        }
                        Ok(info) => info,
                        Err(Errno::ESRCH) => continue,
                        Err(_) => {
                            // SAFETY: Failed to get syscall info but
                            // process is still alive. Terminate!
                            let _ = kill(pid, Some(Signal::SIGKILL));
                            continue;
                        }
                    };

                    let process =
                        // SAFETY: We cannot validate the request here,
                        // however we can use a cached PidFd if available!
                        match unsafe { RemoteProcess::from_tid(pid) } {
                            Ok(process) => process,
                            Err(Errno::ESRCH) => continue,
                            Err(_) => {
                                // SAFETY: Failed to open pidfd but process
                                // is still alive. Terminate!
                                let _ = kill(pid, Some(Signal::SIGKILL));
                                continue;
                            }
                        };

                    // Handle system call entry.
                    let result = handle_ptrace_sysenter(process, info, &cache, &sandbox);

                    // Stop at syscall exit or continue as necessary.
                    //
                    // SAFETY: continue here is unsafe and we only use
                    // it when skipping the system call.
                    match result {
                        Ok(_) => {
                            let _ = ptrace::syscall(pid, None);
                        }
                        Err(Errno::UnknownErrno) => {
                            let _ = ptrace::cont(pid, None);
                        }
                        Err(Errno::ESRCH) => {}
                        Err(_) => {
                            // SAFETY: Unexpected error at sysenter,
                            // terminate the process.
                            let _ = kill(pid, Some(Signal::SIGKILL));
                        }
                    };
                }
                Ok(WaitStatus::PtraceSyscall(pid)) => {
                    // This is ptrace syscall exit stop.
                    //
                    // SAFETY: Verify with PTRACE_GET_SYSCALL_INFO.
                    let info = match ptrace_get_syscall_info(pid) {
                        Ok(info) if info.exit().is_none() => {
                            //unreachable!("BUG: Invalid syscall info returned by Linux: {info:?}")
                            // trinity manages to reliably trigger this with op=0.
                            // SAFETY: Failed to get syscall info but
                            // process is still alive. Terminate!
                            let _ = kill(pid, Some(Signal::SIGKILL));
                            continue;
                        }
                        Ok(info) => info,
                        Err(Errno::ESRCH) => continue,
                        Err(_) => {
                            // SAFETY: Failed to get syscall info but
                            // process is still alive. Terminate!
                            let _ = kill(pid, Some(Signal::SIGKILL));
                            continue;
                        }
                    };

                    // Handle system call exit and continue if Ok.
                    match handle_ptrace_sysexit(pid, info, &cache) {
                        Ok(_) => {
                            let _ = ptrace::cont(pid, None);
                        }
                        Err(Errno::ESRCH) => {}
                        Err(_) => {
                            // SAFETY: Unexpected error during sysexit,
                            // terminate the process.
                            let _ = kill(pid, Some(Signal::SIGKILL));
                        }
                    }
                }
                Ok(WaitStatus::PtraceEvent(
                    pid,
                    libc::SIGTRAP,
                    libc::PTRACE_EVENT_CLONE | libc::PTRACE_EVENT_FORK | libc::PTRACE_EVENT_VFORK,
                )) => {
                    // Check for for PID sandboxing.
                    let sandbox =
                        SandboxGuard::Read(sandbox.read().unwrap_or_else(|err| err.into_inner()));
                    if !sandbox.enabled(Capability::CAP_PID) {
                        let _ = ptrace::cont(pid, None);
                        continue;
                    }
                    let pid_max = if sandbox.pid_max > 0 {
                        sandbox.pid_max
                    } else {
                        // pid_max=0 disables PID sandboxing.
                        let _ = ptrace::cont(pid, None);
                        continue;
                    };
                    let pid_act = sandbox.default_action(Capability::CAP_PID);
                    drop(sandbox); // release the read lock.

                    // Check for PID limit.
                    if let Ok(false) = proc_task_limit(pid, pid_max) {
                        let _ = ptrace::cont(pid, None);
                        continue;
                    }

                    // Report error as necessary.
                    let pgid = getpgid(Some(pid)).map(|p| p.as_raw()).unwrap_or(0);
                    let syd_pgid = getpgrp().as_raw();
                    let kill_gid = pgid != 0 && pgid != syd_pgid;
                    if pid_act != Action::Filter {
                        let cnt_sys = proc_task_nr_sys().unwrap_or(0);
                        let cnt_syd = proc_task_nr_syd().unwrap_or(0);
                        let syd_pid = Pid::this().as_raw();
                        #[allow(clippy::cast_possible_truncation)]
                        let cpid = ptrace::getevent(pid)
                            .map(|p| Pid::from_raw(p as pid_t))
                            .unwrap_or(pid);
                        match pid_act {
                            // Allow|Deny|Filter|Panic cannot happen.
                            action if action.is_signaling() => {
                                // SAFETY: is_signaling() ensures signal() returns Some.
                                #[allow(clippy::disallowed_methods)]
                                let kill_sig = action.signal().unwrap();
                                let kill_it = if kill_gid {
                                    format!("kill process group {pgid} with {kill_sig}")
                                } else {
                                    format!("kill process {pid} with {kill_sig}")
                                };
                                error!("ctx": "limit_pid",
                                    "err": format!("process limit {pid_max} reached, {kill_it}"),
                                    "tip": "increase `pid/max'",
                                    "pid_max": pid_max, "sig": kill_sig as libc::c_int,
                                    "sys_tasks": cnt_sys,  "syd_tasks": cnt_syd,
                                    "pid": cpid.as_raw(), "ppid": pid.as_raw(), "pgid": pgid,
                                    "syd_pid": syd_pid, "syd_pgid": syd_pgid);
                            }
                            Action::Warn => {
                                warn!("ctx": "pid_limit",
                                    "msg": format!("process limit {pid_max} reached with pid {pid}"),
                                    "tip": "increase `pid/max'",
                                    "sys_tasks": cnt_sys,  "syd_tasks": cnt_syd,
                                    "pid": cpid.as_raw(), "ppid": pid.as_raw(), "pgid": pgid,
                                    "syd_pid": syd_pid, "syd_pgid": syd_pgid);
                            }
                            Action::Exit => {
                                let act = pid_act.to_string().to_ascii_lowercase();
                                error!("ctx": "limit_pid",
                                    "err": format!("process limit {pid_max} reached with pid {cpid}, {act}ing!"),
                                    "tip": "increase `pid/max'",
                                    "sys_tasks": cnt_sys,  "syd_tasks": cnt_syd,
                                    "pid": cpid.as_raw(), "ppid": pid.as_raw(), "pgid": pgid,
                                    "syd_pid": syd_pid, "syd_pgid": syd_pgid);
                            }
                            _ => unreachable!(),
                        };
                    }

                    let kill_sig = match pid_act {
                        // Allow|Deny|Panic cannot happen.
                        action if action.is_signaling() => action.signal(),
                        Action::Filter => Some(Signal::SIGKILL),
                        Action::Warn => None,
                        Action::Exit => std::process::exit(libc::EACCES),
                        _ => unreachable!(),
                    };

                    // SAFETY: Send signal to the process group,
                    // unless process shares their process group
                    // with the current process.
                    if let Some(kill_sig) = kill_sig {
                        if kill_gid {
                            let _ = killpg(Pid::from_raw(pgid), Some(kill_sig));
                        } else {
                            let _ = kill(pid, Some(kill_sig));
                        }
                    } else {
                        let _ = ptrace::cont(pid, None);
                    }
                }
                Ok(WaitStatus::PtraceEvent(pid, libc::SIGTRAP, libc::PTRACE_EVENT_EXEC)) => {
                    // This is ptrace syscall exec stop.
                    //
                    // An important caveat is the TGID may have switched.

                    // Retrieve the exec record from the cache.
                    let (process, file, arch, ip, sp, args, ip_mem, sp_mem, memmap) = if let Some(
                        (process, result),
                    ) =
                        cache.get_exec(pid)
                    {
                        (
                            process,
                            result.file,
                            result.arch,
                            result.ip,
                            result.sp,
                            result.args,
                            result.ip_mem,
                            result.sp_mem,
                            result.memmap,
                        )
                    } else {
                        // Note the pid may have been switched to the thread group ID,
                        // so we need to call getevent to get the actual thread ID.
                        #[allow(clippy::cast_possible_truncation)]
                        #[allow(clippy::disallowed_methods)]
                        match ptrace::getevent(pid).map(|tid| Pid::from_raw(tid as i32)) {
                            Ok(tid) if pid != tid => {
                                if let Some((_, result)) = cache.get_exec(tid) {
                                    // SAFETY: We cannot validate the request here,
                                    // however we did use a cached PidFd if available.
                                    let process = match unsafe { RemoteProcess::from_tgid(pid) } {
                                        Ok(process) => process,
                                        Err(Errno::ESRCH) => continue,
                                        Err(_errno) => {
                                            // SAFETY: Failed to open pidfd but process
                                            // is still alive. Terminate!
                                            let _ = kill(pid, Some(Signal::SIGKILL));
                                            continue;
                                        }
                                    };
                                    (
                                        process,
                                        result.file,
                                        result.arch,
                                        result.ip,
                                        result.sp,
                                        result.args,
                                        result.ip_mem,
                                        result.sp_mem,
                                        result.memmap,
                                    )
                                } else {
                                    // SAFETY: Exec sandboxing is/was disabled.
                                    let _ = ptrace::cont(pid, None);

                                    continue;
                                }
                            }
                            Ok(_) => {
                                // SAFETY: Exec sandboxing is/was disabled.
                                let _ = ptrace::cont(pid, None);

                                continue;
                            }
                            Err(errno) => {
                                error!("ctx": "exec", "op": "getevent",
                                        "err": format!("failed to get ptrace event message: {errno}"),
                                        "tip": "check with SYD_LOG=debug and/or submit a bug report");
                                let _ = kill(pid, Some(Signal::SIGKILL));
                                continue;
                            }
                        }
                    };

                    // File points to the executabie file.
                    let mut exe = file;

                    // Read executable paths.
                    // This includes the executable, and the loader if
                    // executable is dynamically linked.
                    let bins = match proc_executables(pid) {
                        Ok(bins) => bins,
                        Err(errno) => {
                            // This should never happen in an ideal world,
                            // let's handle it as gracefully as we can...
                            error!("ctx": "exec", "op": "read_maps",
                                "err": format!("failed to read /proc/{}/maps: {errno}", pid.as_raw()),
                                "tip": "check with SYD_LOG=debug and/or submit a bug report");
                            let _ = process.pidfd_kill(libc::SIGKILL);
                            continue;
                        }
                    };
                    let path = &bins[0].0; // Path to the executable.
                    let mut deny_action: Option<Action> = None;

                    // Determine open flags.
                    let flags = if exe == ExecutableFile::Script {
                        // We will read from the file and parse ELF.
                        OFlag::O_RDONLY | OFlag::O_NOFOLLOW | OFlag::O_NOCTTY
                    } else {
                        // ELF parsing was done at syscall entry, verify paths.
                        OFlag::O_PATH | OFlag::O_NOFOLLOW
                    };

                    // Open paths and verify the open FDs
                    // match the device ID and inode information.
                    // The FDs will be used for two things:
                    // 1. Parsing ELF to determine bitness, PIE etc.
                    // 2. Checksumming binary for Force sandboxing.
                    let mut files = Vec::with_capacity(2);
                    for (path, inode, devid_maj, devid_min) in &bins {
                        match safe_open::<BorrowedFd>(None, path, flags) {
                            Ok(fd) => {
                                // WORKAROUND: Check if the FS reports sane device ids.
                                // Check the comment on has_sane_device_id() function
                                // for more information.
                                // Assume true on errors for safety.
                                let dev_check = match retry_on_eintr(|| fstatfs64(&fd)) {
                                    Ok(statfs) => !statfs.has_broken_device_ids(),
                                    Err(Errno::ENOSYS) => {
                                        // Filesystem type does not support this call.
                                        // Assume true for safety.
                                        true
                                    }
                                    Err(errno) => {
                                        error!("ctx": "open_elf",
                                            "err": format!("statfs error: {errno}"),
                                            "pid": pid.as_raw(), "path": path);
                                        let _ = process.pidfd_kill(libc::SIGKILL);
                                        continue 'waitloop;
                                    }
                                };
                                let statx = match fstatx(&fd, STATX_INO) {
                                    Ok(stat) => stat,
                                    Err(errno) => {
                                        error!("ctx": "open_elf",
                                            "err": format!("statx error: {errno}"),
                                            "pid": pid.as_raw(), "path": path);
                                        let _ = process.pidfd_kill(libc::SIGKILL);
                                        continue 'waitloop;
                                    }
                                };
                                // SAFETY: Verify we opened the same file!
                                #[allow(clippy::cast_sign_loss)]
                                let devid_maj = *devid_maj as libc::c_uint;
                                #[allow(clippy::cast_sign_loss)]
                                let devid_min = *devid_min as libc::c_uint;
                                if *inode != statx.stx_ino
                                    || (dev_check
                                        && (devid_maj != statx.stx_dev_major
                                            || devid_min != statx.stx_dev_minor))
                                {
                                    let error = format!(
                                        "metadata mismatch: {}:{}={} is not {}:{}={}",
                                        statx.stx_dev_major,
                                        statx.stx_dev_minor,
                                        statx.stx_ino,
                                        devid_maj,
                                        devid_min,
                                        inode
                                    );
                                    error!("ctx": "open_elf", "err": error,
                                        "pid": pid.as_raw(),"path": path);
                                    let _ = process.pidfd_kill(libc::SIGKILL);
                                    continue 'waitloop;
                                }
                                files.push(File::from(fd));
                            }
                            Err(errno) => {
                                error!("ctx": "open_elf",
                                    "err": format!("open error: {errno}"),
                                    "pid": pid.as_raw(), "path": path);
                                let _ = process.pidfd_kill(libc::SIGKILL);
                                continue 'waitloop;
                            }
                        }
                    }

                    // Parse ELF file to figure out type,
                    // if the original file we've checked
                    // was a script.
                    let mut my_sandbox =
                        SandboxGuard::Read(sandbox.read().unwrap_or_else(|err| err.into_inner()));
                    if exe == ExecutableFile::Script {
                        // Check SegvGuard.
                        if let Some(action) = my_sandbox.check_segvguard(path) {
                            if action != Action::Filter {
                                error!("ctx": "segvguard",
                                    "err": format!("max crashes {} exceeded, kill process {}",
                                        my_sandbox.segvguard_maxcrashes,
                                        pid.as_raw()),
                                    "tip": "increase `segvguard/maxcrashes'",
                                    "pid": pid.as_raw(), "path": path);
                            }
                            if action == Action::Exit {
                                std::process::exit(libc::EACCES);
                            } else if action.is_signaling() {
                                deny_action = Some(action);
                            } else if action.is_denying() {
                                deny_action = Some(Action::Kill);
                            }
                        }

                        // Check for Exec sandboxing.
                        if deny_action.is_none() && my_sandbox.enabled(Capability::CAP_EXEC) {
                            for (path, _, _, _) in &bins {
                                let path = &path;
                                let (action, filter) = match cache
                                    .path_cache
                                    .0
                                    .get_value_or_guard(&PathCap(Capability::CAP_EXEC, path), None)
                                {
                                    GuardResult::Value(result) => result,
                                    GuardResult::Guard(guard) => {
                                        let result =
                                            my_sandbox.check_path(Capability::CAP_EXEC, path);
                                        let _ = guard.insert(result);
                                        result
                                    }
                                    GuardResult::Timeout => {
                                        // SAFETY: We never pass a timeout, this cannot happen.
                                        unreachable!("BUG: SandboxGuard returned invalid timeout!");
                                    }
                                };
                                if !filter {
                                    warn!("ctx": "access", "cap": Capability::CAP_EXEC, "act": action,
                                        "pid": pid.as_raw(), "sys": "exec", "path": path,
                                        "tip": format!("configure `allow/exec+{path}'"));
                                }
                                match action {
                                    Action::Allow | Action::Warn => {}
                                    Action::Stop => {
                                        deny_action = Some(Action::Stop);
                                        break;
                                    }
                                    Action::Abort => {
                                        deny_action = Some(Action::Abort);
                                        break;
                                    }
                                    Action::Exit => std::process::exit(libc::EACCES),
                                    _ => {
                                        // Deny|Filter|Kill
                                        deny_action = Some(Action::Kill);
                                        break;
                                    }
                                }
                            }
                        }

                        // Check for Trusted Path Execution (TPE).
                        if deny_action.is_none() && my_sandbox.enabled(Capability::CAP_TPE) {
                            for (path, _, _, _) in &bins {
                                let path = &path;
                                let action = my_sandbox.check_tpe(path);
                                if !matches!(action, Action::Allow | Action::Filter) {
                                    error!("ctx": "check_tpe",
                                        "err": "exec from untrusted path blocked",
                                        "pid": pid.as_raw(), "path": path);
                                }
                                match action {
                                    Action::Allow | Action::Warn => {}
                                    Action::Stop => deny_action = Some(Action::Stop),
                                    Action::Abort => deny_action = Some(Action::Abort),
                                    Action::Exit => std::process::exit(libc::EACCES),
                                    _ => {
                                        // Deny|Filter|Kill
                                        deny_action = Some(Action::Kill);
                                    }
                                }
                            }
                        }

                        // Parse ELF as necessary for restrictions.
                        let restrict_32 = my_sandbox.deny_elf32();
                        let restrict_dyn = my_sandbox.deny_elf_dynamic();
                        let restrict_sta = my_sandbox.deny_elf_static();
                        let restrict_pie = !my_sandbox.allow_unsafe_nopie();
                        let restrict_xs = !my_sandbox.allow_unsafe_stack();

                        // Shared library execution depends on trace/allow_unsafe_exec:1.
                        // unsafe_exec also means no ptrace, hence we can never be here.
                        let restrict_ldd = true /* !my_sandbox.allow_unsafe_exec() */;

                        let check_linking = restrict_ldd
                            || restrict_dyn
                            || restrict_sta
                            || restrict_pie
                            || restrict_xs;

                        // Drop sandbox lock before blocking operation.
                        drop(my_sandbox);

                        let result = (|| -> Result<ExecutableFile, ElfError> {
                            // Parse ELF and reset the file offset.
                            let mut file = &files[0];
                            let result = ExecutableFile::parse(file, check_linking);
                            #[allow(clippy::disallowed_methods)]
                            file.seek(SeekFrom::Start(0)).map_err(ElfError::IoError)?;
                            result
                        })();

                        // Re-acquire the read-lock.
                        my_sandbox = SandboxGuard::Read(
                            sandbox.read().unwrap_or_else(|err| err.into_inner()),
                        );

                        match result {
                            // Update ELF information.
                            Ok(exe_bin) => exe = exe_bin,
                            Err(ElfError::IoError(err)) => {
                                deny_action = Some(Action::Kill);
                                if !my_sandbox.filter_path(Capability::CAP_EXEC, path) {
                                    error!("ctx": "parse_elf",
                                        "err": format!("io error: {}", err2no(&err)),
                                        "pid": pid.as_raw(), "path": path);
                                }
                            }
                            Err(ElfError::BadMagic) => {
                                deny_action = Some(Action::Kill);
                                if !my_sandbox.filter_path(Capability::CAP_EXEC, path) {
                                    error!("ctx": "parse_elf",
                                        "err": format!("BUG: not an ELF"),
                                        "pid": pid.as_raw(), "path": path);
                                }
                            }
                            Err(ElfError::Malformed) => {
                                deny_action = Some(Action::Kill);
                                if !my_sandbox.filter_path(Capability::CAP_EXEC, path) {
                                    error!("ctx": "parse_elf",
                                        "err": format!("BUG: malformed ELF"),
                                        "pid": pid.as_raw(), "path": path);
                                }
                            }
                        };

                        if restrict_ldd
                            && !matches!(
                                exe,
                                ExecutableFile::Elf {
                                    file_type: ElfFileType::Executable,
                                    ..
                                }
                            )
                        {
                            deny_action = Some(Action::Kill);
                            if !my_sandbox.filter_path(Capability::CAP_EXEC, path) {
                                error!("ctx": "check_elf",
                                    "err": "ld.so exec-indirection",
                                    "pid": pid.as_raw(), "path": path,
                                    "exe": format!("{exe}"));
                            }
                        }

                        if deny_action.is_none()
                            && restrict_pie
                            && matches!(exe, ExecutableFile::Elf { pie: false, .. })
                        {
                            deny_action = Some(Action::Kill);
                            if !my_sandbox.filter_path(Capability::CAP_EXEC, path) {
                                error!("ctx": "check_elf", "err": "not PIE",
                                    "pid": pid.as_raw(), "path": path,
                                    "tip": "configure `trace/allow_unsafe_nopie:1'",
                                    "exe": format!("{exe}"));
                            }
                        }

                        if deny_action.is_none()
                            && restrict_xs
                            && matches!(exe, ExecutableFile::Elf { xs: true, .. })
                        {
                            deny_action = Some(Action::Kill);
                            if !my_sandbox.filter_path(Capability::CAP_EXEC, path) {
                                error!("ctx": "check_elf", "err": "execstack",
                                    "pid": pid.as_raw(), "path": path,
                                    "tip": "configure `trace/allow_unsafe_stack:1'",
                                    "exe": format!("{exe}"));
                            }
                        }

                        if deny_action.is_none()
                            && restrict_32
                            && matches!(
                                exe,
                                ExecutableFile::Elf {
                                    elf_type: ElfType::Elf32,
                                    ..
                                }
                            )
                        {
                            deny_action = Some(Action::Kill);
                            if !my_sandbox.filter_path(Capability::CAP_EXEC, path) {
                                error!("ctx": "check_elf", "err": "32-bit",
                                    "pid": pid.as_raw(), "path": path,
                                    "tip": "configure `trace/deny_elf32:0'",
                                    "exe": format!("{exe}"));
                            }
                        }

                        if deny_action.is_none()
                            && restrict_dyn
                            && matches!(
                                exe,
                                ExecutableFile::Elf {
                                    linking_type: Some(LinkingType::Dynamic),
                                    ..
                                }
                            )
                        {
                            deny_action = Some(Action::Kill);
                            if !my_sandbox.filter_path(Capability::CAP_EXEC, path) {
                                error!("ctx": "check_elf", "err": "dynamic-link",
                                    "pid": pid.as_raw(), "path": path,
                                    "tip": "configure `trace/deny_elf_dynamic:0'",
                                    "exe": format!("{exe}"));
                            }
                        }

                        if deny_action.is_none()
                            && restrict_sta
                            && matches!(
                                exe,
                                ExecutableFile::Elf {
                                    linking_type: Some(LinkingType::Static),
                                    ..
                                }
                            )
                        {
                            deny_action = Some(Action::Kill);
                            if !my_sandbox.filter_path(Capability::CAP_EXEC, path) {
                                error!("ctx": "check_elf", "err": "static-link",
                                    "pid": pid.as_raw(), "path": path,
                                    "tip": "configure `trace/deny_elf_static:0'",
                                    "exe": format!("{exe}"));
                            }
                        }

                        // Check for Force sandboxing.
                        if deny_action.is_none() && my_sandbox.enabled(Capability::CAP_FORCE) {
                            for (idx, (path, _, _, _)) in bins.iter().enumerate() {
                                match my_sandbox.check_force2(path, &mut files[idx]) {
                                    Ok(Action::Allow) => {}
                                    Ok(Action::Warn) => {
                                        warn!("ctx": "verify_elf", "act": Action::Warn,
                                            "pid": pid.as_raw(), "path": path,
                                            "tip": format!("configure `force+{path}:<checksum>'"));
                                    }
                                    Ok(Action::Stop) => {
                                        deny_action = Some(Action::Stop);
                                        warn!("ctx": "verify_elf", "act": Action::Stop,
                                            "pid": pid.as_raw(), "path": path,
                                            "tip": format!("configure `force+{path}:<checksum>'"));
                                    }
                                    Ok(Action::Abort) => {
                                        deny_action = Some(Action::Abort);
                                        warn!("ctx": "verify_elf", "act": Action::Abort,
                                            "pid": pid.as_raw(), "path": path,
                                            "tip": format!("configure `force+{path}:<checksum>'"));
                                    }
                                    Ok(Action::Exit) => {
                                        error!("ctx": "verify_elf", "act": Action::Exit,
                                            "pid": pid.as_raw(), "path": path,
                                            "tip": format!("configure `force+{path}:<checksum>'"));
                                        std::process::exit(libc::EACCES);
                                    }
                                    Ok(action) => {
                                        // Deny|Filter|Kill
                                        deny_action = Some(Action::Kill);
                                        if action != Action::Filter {
                                            warn!("ctx": "verify_elf", "act": action,
                                                "pid": pid.as_raw(), "path": path,
                                                "tip": format!("configure `force+{path}:<checksum>'"));
                                        }
                                    }
                                    Err(IntegrityError::Sys(errno)) => {
                                        deny_action = Some(Action::Kill);
                                        error!("ctx": "verify_elf",
                                            "err": format!("system error during ELF checksum calculation: {errno}"),
                                            "pid": pid.as_raw(), "path": path,
                                            "tip": format!("configure `force+{path}:<checksum>'"));
                                    }
                                    Err(IntegrityError::Hash {
                                        action,
                                        expected,
                                        found,
                                    }) => {
                                        if !matches!(action, Action::Allow | Action::Filter) {
                                            error!("ctx": "verify_elf", "act": action,
                                                "err": format!("ELF checksum mismatch: {found} is not {expected}"),
                                                "pid": pid.as_raw(), "path": path,
                                                "tip": format!("configure `force+{path}:<checksum>'"));
                                        }
                                        match action {
                                            Action::Allow | Action::Warn => {}
                                            Action::Stop => deny_action = Some(Action::Stop),
                                            Action::Abort => deny_action = Some(Action::Abort),
                                            Action::Exit => std::process::exit(libc::EACCES),
                                            _ =>
                                            /*Deny|Filter|Kill*/
                                            {
                                                deny_action = Some(Action::Kill)
                                            }
                                        };
                                    }
                                }
                            }
                        }
                    }

                    if deny_action.is_none() && !my_sandbox.allow_unsafe_libc() {
                        let elf_type = match exe {
                            ExecutableFile::Elf { elf_type, .. } => elf_type,
                            _ => unreachable!(), // Script is not possible here.
                        };

                        // SAFETY:
                        // 1. Sets AT_SECURE.
                        // 2. Verifies AT_{E,}{U,G}ID matches Syd's own.
                        match proc_set_at_secure(pid, elf_type) {
                            Ok(_) | Err(Errno::ESRCH) => {}
                            Err(errno) => {
                                deny_action = Some(Action::Kill);
                                if !my_sandbox.filter_path(Capability::CAP_EXEC, path) {
                                    error!("ctx": "secure_exec",
                                        "err": format!("error setting AT_SECURE: {errno}"),
                                        "tip": "configure `trace/allow_unsafe_libc:1'",
                                        "pid": pid.as_raw(), "path": path);
                                }
                            }
                        }
                    }

                    // Release the read lock.
                    drop(my_sandbox);

                    if let Some(action) = deny_action {
                        let _ = process.pidfd_kill(
                            action
                                .signal()
                                .map(|sig| sig as i32)
                                .unwrap_or(libc::SIGKILL),
                        );
                    } else {
                        let _ = ptrace::cont(pid, None);

                        let ip_asm = if let Some(ip_mem) = ip_mem {
                            disasm(
                                &ip_mem,
                                scmp_arch(arch).unwrap_or(ScmpArch::Native),
                                ip,
                                true,
                                false,
                            )
                            .map(|instructions| {
                                instructions
                                    .into_iter()
                                    .map(|instruction| instruction.op)
                                    .collect::<Vec<_>>()
                            })
                            .ok()
                        } else {
                            None
                        };

                        let ip_mem = ip_mem.map(|ip_mem| ip_mem.to_lower_hex_string());
                        let sp_mem = sp_mem.map(|sp_mem| sp_mem.to_lower_hex_string());

                        debug!("ctx": "exec", "op": "verify_exec",
                            "msg": format!("execution of `{path}' of type {exe} approved"),
                            "pid": process.pid.as_raw(),
                            "path": &path,
                            "exe": &exe.to_string(),
                            "args": args,
                            "ip": ip,
                            "sp": sp,
                            "ip_mem": ip_mem,
                            "sp_mem": sp_mem,
                            "ip_asm": ip_asm,
                            "memmap": memmap);
                    }
                }
                Ok(WaitStatus::PtraceEvent(pid, libc::SIGTRAP, libc::PTRACE_EVENT_EXIT)) => {
                    // We stopped before return from exit(2).
                    // Apply SegvGuard.
                    let mut my_sandbox =
                        SandboxGuard::Read(sandbox.read().unwrap_or_else(|err| err.into_inner()));
                    let has_segvguard = !my_sandbox.get_segvguard_expiry().is_zero();
                    drop(my_sandbox);

                    // Setting expiry timeout to 0 disables SegvGuard.
                    if has_segvguard {
                        // Step 1:
                        // (a) Check if process produced a core dump.
                        // (b) Check if process received a signal with default action Core.
                        let sig = match ptrace::getevent(pid) {
                            Ok(status) => {
                                #[allow(clippy::cast_possible_truncation)]
                                match WaitStatus::from_raw(pid, status as i32) {
                                    WaitStatus::Signaled(_, sig, true) => Some(sig),
                                    WaitStatus::Signaled(_, sig, _) if is_coredump(sig) => {
                                        Some(sig)
                                    }
                                    _ => None, // Process did not produce a core dump, move on.
                                }
                            }
                            Err(_) => None, // Process dead? move on.
                        };

                        // Step 2: Record the crash as necessary.
                        if let Some(sig) = sig {
                            // Child received a signal that produces a
                            // coredump and SegvGuard is enabled.
                            // Add the exec path to the segvguard expiry
                            // map.
                            let mut exe = XPathBuf::from_pid(pid);
                            exe.push(b"exe");

                            let path = match readlinkat(Some(&PROC_FILE()), &exe) {
                                Ok(path) => path,
                                Err(_) => continue,
                            };

                            // Upgrade the sandbox lock to writable.
                            my_sandbox = SandboxGuard::Write(
                                sandbox.write().unwrap_or_else(|err| err.into_inner()),
                            );

                            // Record the crashing program.
                            let (was_suspended, is_suspended, num_crashes) =
                                my_sandbox.add_segvguard_crash(&path);

                            drop(my_sandbox); // release the write-lock.

                            // Convert sig to Signal for pretty printing.
                            // Note, `Signal` does not support realtime signals,
                            // therefore we log the original raw signal number
                            // as well.
                            let signal = Signal::try_from(sig).unwrap_or(Signal::SIGKILL);
                            let crashes = if num_crashes > 1 { "crashes" } else { "crash" };
                            if is_suspended {
                                error!("ctx": "segvguard",
                                    "err": format!("suspending after {signal} due to {num_crashes} {crashes}"),
                                    "tip": "increase `segvguard/maxcrashes'",
                                    "pid": pid.as_raw(), "path": path, "sig": sig);
                            } else {
                                info!("ctx": "segvguard",
                                    "msg": format!("{num_crashes} {crashes} recorded after {signal}{}",
                                        if was_suspended { " (suspended)" } else { "" }),
                                    "pid": pid.as_raw(), "path": path, "sig": sig);
                            }
                        }
                    }

                    // Step 3: Retire the PidFd.
                    if let Some(map) = PIDFD_MAP.get() {
                        map.del_pidfd(pid);
                    }

                    // Step 4: Continue the process so it exits.
                    let _ = ptrace::cont(pid, None);
                }
                Ok(status) => panic!("Unhandled wait event: {status:?}"),
                Err(Errno::EINTR | Errno::EAGAIN) => {}
                Err(Errno::ECHILD) => break,
                Err(errno) => return Err(errno.into()),
            }
        }

        // Wait for the syd-aes thread.
        #[allow(clippy::disallowed_methods)]
        if let Some(crypt_handle) = crypt_handle {
            let mut crypt_map = crypt_map.as_ref().unwrap().write().unwrap();
            crypt_map.1 = true; // signal end of encryption.
            drop(crypt_map); // release the write-lock.
            crypt_handle.join().expect("join AES encryption thread");
        }

        // SAFETY: Since we do not run epoll on the main thread anymore,
        // seccomp_notify_receive may block forever on seccomp fd even
        // when all processes have exited... Hence we do not join the
        // pools here and this is safe since we can be at this point
        // under two conditions:
        // (a): wait_all == false && exec child has exited.
        // (b): wait_all == true && we received ECHILD on wait().
        // Under both cases it is safe to tear down the sandbox as we
        // ensure we do not interrupt any syscall processing.
        //if wait_all {
        // let _ = thread_handle.join().map_err(|_| Errno::EPIPE)?;
        // pool_handle.join();
        //}

        let exit_code = u8::try_from(exit_code).unwrap_or(127);
        info!("ctx": "wait", "op": "exit",
            "msg": format!("return code {exit_code}, sandboxing ended!"),
            "code": exit_code,
            "cache": &*cache);

        Ok(exit_code)
    }

    /// Run the supervisor, main entry point.
    #[allow(clippy::cognitive_complexity)]
    pub fn run(
        mut sandbox: Sandbox,
        argv0: &OsStr,
        argv: Vec<OsString>,
        envp: Option<&HashSet<OsString, RandomState>>,
        arg0: Option<OsString>,
        export: Option<ExportMode>,
    ) -> SydResult<u8> {
        let (major, minor) = *KERNEL_VERSION;
        if major < 5 {
            error!("ctx": "run", "op": "check_kernel_version",
                "err": "Your kernel version is too old.");
            return Err(Errno::EINVAL.into());
        } else if major == 5 && minor < 5 {
            error!("ctx": "run", "op": "check_kernel_version",
                "err": "Your kernel version is too old: Does not support SECCOMP_USER_NOTIF_FLAG_CONTINUE, ...");
            return Err(Errno::EINVAL.into());
        } else if major == 5 && minor < 6 {
            error!("ctx": "run", "op": "check_kernel_version",
                "err": "Your kernel version is too old: Does not support pidfd_getfd(2) and SECCOMP_IOCTL_NOTIF_ADDFD.");
            return Err(Errno::EINVAL.into());
        } else if major == 5 && minor < 9 {
            error!("ctx": "run", "op": "check_kernel_version",
                "err": "Your kernel version is too old: Does not support SECCOMP_IOCTL_NOTIF_ADDFD.");
            return Err(Errno::EINVAL.into());
        } else if major == 5 && minor < 19 {
            error!("ctx": "run", "op": "check_kernel_version",
                "err": "Your kernel version is too old: Does not support SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV.");
            return Err(Errno::EINVAL.into());
        }
        info!("ctx": "run", "op": "check_kernel_version",
            "msg": "kernel version is compatible",
            "major": major, "minor": minor,
            "pidfd_thread": *HAVE_PIDFD_THREAD,
            "seccomp_sync": *HAVE_SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP,
            "mountid_uniq": *HAVE_STATX_MNT_ID_UNIQUE);

        // Set
        // 1. allow_safe_kcapi flag
        // 2. exit_wait_all flag
        // if Crypt Sandboxing is on.
        if sandbox.enabled(Capability::CAP_CRYPT) {
            sandbox.flags.insert(Flags::FL_ALLOW_SAFE_KCAPI);
            sandbox.flags.insert(Flags::FL_EXIT_WAIT_ALL);
        }

        // Set process and i/o prorities.
        // See the "Process Priority and Resource Management" section of the syd(7) manual page.
        let restrict_nice = !sandbox.allow_unsafe_nice();
        if restrict_nice {
            // SAFETY: Step 1: Set thread priority to a low value.
            match Errno::result(unsafe { nix::libc::setpriority(nix::libc::PRIO_PROCESS, 0, 20) }) {
                Ok(_) => info!("ctx": "run", "op": "set_program_scheduling_priority",
                    "msg": "set program scheduling priority to 20",
                    "val": 20),
                Err(errno @ Errno::ENOSYS) => {
                    info!("ctx": "run", "op": "set_program_scheduling_priority",
                    "err": format!("setpriority error: {errno}"))
                }
                Err(errno) => error!("ctx": "run", "op": "set_program_scheduling_priority",
                    "err": format!("setpriority error: {errno}")),
            }

            // SAFETY: Step 2: Set CPU scheduling priority to idle.
            match set_cpu_priority_idle() {
                Ok(_) => info!("ctx": "run", "op": "set_cpu_scheduling_priority",
                    "msg": "set CPU scheduling priority to idle",
                    "val": "idle"),
                Err(errno @ Errno::ENOSYS) => {
                    info!("ctx": "run", "op": "set_cpu_scheduling_priority",
                    "err": format!("sched_setscheduler error: {errno}"))
                }
                Err(errno) => error!("ctx": "run", "op": "set_cpu_scheduling_priority",
                    "err": format!("sched_setscheduler error: {errno}")),
            }

            // SAFETY: Step 3: Set I/O priority to idle.
            match set_io_priority_idle() {
                Ok(_) => info!("ctx": "run", "op": "set_io_scheduling_priority",
                    "msg": "set i/o scheduling priority to idle",
                    "val": "idle"),
                Err(errno @ Errno::ENOSYS) => {
                    info!("ctx": "run", "op": "set_io_scheduling_priority",
                    "err": format!("ioprio_set error: {errno}"))
                }
                Err(errno) => error!("ctx": "run", "op": "set_io_scheduling_priority",
                    "err": format!("ioprio_set error: {errno}")),
            }
        }

        // Adjust process resources to limit core dumps.
        let restrict_prlimit = !sandbox.allow_unsafe_prlimit();
        if restrict_prlimit {
            match setrlimit(Resource::RLIMIT_CORE, 0, 0) {
                Ok(_) => info!("ctx": "run", "op": "set_rlimit_core",
                    "msg": "coredump generation disabled"),
                Err(errno) => error!("ctx": "run", "op": "set_rlimit_core",
                    "err": format!("setrlimit error: {errno}")),
            };
        }

        // Prepare the command to execute.
        // We create it early here so dynamic library loading
        // works even if we mount the owning fs noexec later.
        let mut command = match crate::unshare::Command::new(argv0) {
            Ok(command) => command,
            Err(errno) => return Ok(u8::try_from(errno as i32).unwrap_or(127)),
        };
        command.deny_tsc(sandbox.deny_tsc());
        if sandbox.allow_unsafe_caps() || sandbox.allow_unsafe_ptrace() {
            // Keep CAP_SYS_PTRACE in the sandbox process.
            command.keep(true);
        }
        if !sandbox.allow_unsafe_ptrace() {
            // Exec TOCTOU mitigation.
            command.stop(true);
        }
        command.args(&argv);
        if let Some(ref arg0) = arg0 {
            command.arg0(arg0);
        }

        // Set mount propagation on the root filesystem for mount namespace.
        // Note, we can only mount /proc after the initial clone as we're now pid=1.
        if sandbox.unshare_mount() {
            if let Some(flags) = sandbox.propagation {
                mount(Some("none"), "/", NONE, flags, NONE)?;
            }

            // Process bind mounts as necessary.
            if let Some(bind_mounts) = sandbox.collect_bind_mounts() {
                const NONE: Option<&XPathBuf> = None;
                for bind in bind_mounts {
                    if bind.src.is_relative() {
                        match mount(
                            Some(&bind.src),
                            &bind.dst,
                            Some(&bind.src),
                            bind.opt,
                            bind.dat.as_ref(),
                        ) {
                            Ok(_) => {
                                info!("ctx": "run", "op": "spec_mount", "mnt": &bind,
                                    "msg": format!("special-fs mount `{bind}' succeeded"));
                            }
                            Err(errno @ Errno::ENOENT) => {
                                info!("ctx": "run", "op": "spec_mount", "mnt": &bind, "err": errno as i32,
                                    "msg": format!("special-fs mount `{bind}' failed: {errno}"));
                            }
                            Err(errno) => {
                                error!("ctx": "run", "op": "spec_mount", "mnt": &bind, "err": errno as i32,
                                    "msg": format!("special-fs mount `{bind}' failed: {errno}"));
                                return Err(SydError::Nix(errno));
                            }
                        }
                    } else {
                        let flags = bind.opt | MsFlags::MS_BIND | MsFlags::MS_REC;
                        match mount(Some(&bind.src), &bind.dst, NONE, flags, NONE) {
                            Ok(_) => {
                                info!("ctx": "run", "op": "bind_mount", "mnt": &bind,
                                    "msg": format!("bind mount `{bind}' succeeded"));
                            }
                            Err(errno @ Errno::ENOENT) => {
                                info!("ctx": "run", "op": "bind_mount", "mnt": &bind, "err": errno as i32,
                                    "msg": format!("bind mount `{bind}' failed: {errno}"));
                            }
                            Err(errno) => {
                                error!("ctx": "run", "op": "bind_mount", "mnt": &bind, "err": errno as i32,
                                    "msg": format!("bind mount `{bind}' failed: {errno}"));
                                return Err(SydError::Nix(errno));
                            }
                        }
                    }
                }
            }
        }

        // Mount private procfs as necessary.
        // The target directory may be under the chroot directory.
        // Use hidepid=2 to hide pid=1.
        // SAFETY: Private procfs is mounted _after_ custom bind mounts
        // to ensure they cannot interfere with this mount.
        if sandbox.unshare_mount() && sandbox.unshare_pid() {
            if let Some(ref proc) = sandbox.proc {
                let flags = MsFlags::MS_NOSUID | MsFlags::MS_NOEXEC | MsFlags::MS_NODEV;
                mount(Some("proc"), proc, Some("proc"), flags, Some("hidepid=2"))?;
                if log_enabled!(LogLevel::Info) {
                    let bind = BindMount {
                        src: XPathBuf::from("proc"),
                        dst: proc.clone(),
                        opt: flags,
                        dat: None,
                    };
                    info!("ctx": "run", "op": "mount_procfs", "mnt": &bind,
                        "msg": format!("proc mount `{bind}' succeeded"));
                }
            }

            // Change root if requested.
            if let Some(ref root) = sandbox.root {
                // Open a FD to the private proc directory.
                // SAFETY: Do not resolve symbolic links.
                let fd = safe_open_path::<BorrowedFd>(None, root, OFlag::O_DIRECTORY)?;

                // For subsequent actions the current directory must equal root.
                fchdir(fd.as_raw_fd())?;

                // All preparations were done in the parent, let's chroot into cwd.
                chroot(".")?;

                // Almost there, let's reensure our current working directory equals root.
                chdir("/")?;
            }
        }

        // Clean up the environment as necessary.
        if !sandbox.allow_unsafe_env() {
            for &var in UNSAFE_ENV {
                let var = OsStr::from_bytes(var);
                if !envp.map(|envp| envp.contains(var)).unwrap_or(false)
                    && env::var_os(var).is_some()
                {
                    env::remove_var(var);
                    if !log_enabled!(LogLevel::Info) {
                        continue;
                    }
                    let var = XPathBuf::from(var.to_os_string());
                    info!("ctx": "run", "op": "sanitize_process_environment",
                        "msg": format!("removed unsafe variable {var} from environment"),
                        "tip": format!("use `syd -e{var}='"));
                }
            }
        }

        // SAFETY: Ensure the static file descriptors are open
        // before sandboxing starts but after the mounts are
        // processed.
        proc_init()?;

        // SAFETY: Ensure randomized timer is initialized as necessary.
        let restrict_sysinfo = !sandbox.allow_unsafe_sysinfo();
        if restrict_sysinfo {
            timer_init()?;
        }

        // Attempt to set file-max to hard limit overriding the soft limit.
        // Since this is just an attempt for convenience, we log errors with info.
        let file_max = proc_fs_file_max().unwrap_or(4096);
        match getrlimit(Resource::RLIMIT_NOFILE)? {
            (soft_limit, hard_limit) if soft_limit < hard_limit => {
                // Careful on 32-bit, setrlimit expects an u32 not an u64!
                #[allow(clippy::useless_conversion)]
                let hard_limit = hard_limit.min(file_max.try_into().or(Err(Errno::EOVERFLOW))?);
                match setrlimit(Resource::RLIMIT_NOFILE, hard_limit, hard_limit) {
                    Ok(_) => {
                        info!("ctx": "run", "op": "set_rlimit_nofile",
                            "msg": format!("file-max limit increased from {soft_limit} to {hard_limit}"));
                    }
                    Err(errno) => {
                        info!("ctx": "run", "op": "set_rlimit_nofile",
                            "err": format!("setrlimit error: {errno}"));
                    }
                }
            }
            (_, hard_limit) => {
                info!("ctx": "run", "op": "set_rlimit_nofile",
                    "msg": format!("file-max limit is already set to hard limit {hard_limit}"));
            }
        };

        // Set up the Landlock sandbox if requested. Note,
        // we set it up here before spawning the child so as to
        // include the Syd sandbox threads into the sandbox as
        // well. This is done for added security.
        // Note, Landlock errors are not fatal.
        if let Some((path_ro, path_rw, port_bind, port_conn)) = sandbox.collect_landlock() {
            let abi = crate::landlock::ABI::new_current();
            match crate::landlock_operation(
                abi, &path_ro, &path_rw, &port_bind, &port_conn, true, true,
            ) {
                Ok(status) => {
                    let status = match status.ruleset {
                        // The FullyEnforced case must be tested by the developer.
                        RulesetStatus::FullyEnforced => "fully enforced",
                        RulesetStatus::PartiallyEnforced => "partially enforced",
                        // Users should be warned that they are not protected.
                        RulesetStatus::NotEnforced => "not enforced",
                    };
                    info!("ctx": "run", "op": "apply_landlock",
                        "msg": format!("Landlock ABI {} is {status}", abi as i32),
                        "abi": abi as i32,
                        "path_ro": path_ro, "path_rw": path_rw,
                        "port_bind": port_bind, "port_conn": port_conn);
                }
                Err(_) => {
                    info!("ctx": "run", "op": "apply_landlock",
                        "msg": format!("Landlock ABI {} is unsupported", abi as i32),
                        "abi": abi as i32,
                        "path_ro": path_ro, "path_rw": path_rw,
                        "port_bind": port_bind, "port_conn": port_conn);
                }
            }
        }

        // Step 6: Initialize sandbox supervisor.
        let supervisor = Supervisor::new(sandbox, export)?;

        // Start profiling if requested.
        #[cfg(feature = "prof")]
        if let Some(val) = env::var_os("SYD_PROF") {
            match val.as_bytes() {
                b"cpu" => crate::start_cpu_profile("main"),
                b"mem" => crate::start_mem_profile("main"),
                _ => {}
            }
        };

        // Spawn the program under sandbox.
        let log = if log_enabled!(LogLevel::Info) {
            let cmd = arg0
                .map(XPathBuf::from)
                .unwrap_or_else(|| XPathBuf::from(argv0.to_os_string()));
            let args = argv.into_iter().map(XPathBuf::from).collect::<Vec<_>>();
            Some((cmd, args))
        } else {
            None
        };
        let (epoll, cache, sandbox, crypt_map, crypt_handle) = match supervisor.spawn(command) {
            Ok(result) => {
                if let Some((cmd, args)) = log {
                    info!("ctx": "run", "op": "run_command",
                        "msg": format!("spawned `{cmd}' with arguments {args:?}"),
                        "cmd": cmd, "argv": args);
                }
                result
            }
            Err(error) => {
                let errno = Errno::last() as i32;
                if let Some((cmd, args)) = log {
                    info!("ctx": "run", "op": "run_command",
                        "err": format!("spawn error executing `{cmd}': {errno}"),
                        "cmd": cmd, "argv": args);
                }
                errno::set_errno(errno::Errno(errno));
                return Err(error);
            }
        };

        // Wait for the process to exit and return the same error code.
        #[allow(clippy::disallowed_methods)]
        let result =
            Supervisor::wait(epoll, cache, sandbox, crypt_map, crypt_handle).map_err(|error| {
                errno::set_errno(errno::Errno(
                    error.errno().map(|e| e as i32).unwrap_or(libc::ENOSYS),
                ));
                error
            });

        // End profiling if requested.
        #[cfg(feature = "prof")]
        if let Some(val) = env::var_os("SYD_PROF") {
            match val.as_bytes() {
                b"cpu" => crate::stop_cpu_profile(),
                b"mem" => {
                    crate::dump_mem_profile("main");
                    crate::stop_mem_profile();
                }
                _ => {}
            }
        }

        // Finally return the result to the caller.
        if export.is_some() {
            Ok(0)
        } else {
            result
        }
    }
}

/// Processes the address family of a `SockaddrStorage` object and performs logging or other
/// required operations specific to the syscall being handled.
///
/// This helper function isolates the logic involved in dealing with different address families
/// and reduces code duplication across different syscall handler functions.
///
/// # Parameters
///
/// - `addr`: Reference to a `SockaddrStorage`, representing the socket address involved in the syscall.
/// - `syscall_name`: A string slice holding the name of the syscall being handled, used for logging purposes.
///
/// # Safety
///
/// The function contains unsafe blocks due to potential TOCTOU (Time-of-Check Time-of-Use)
/// vulnerabilities. Each unsafe block within this function has been annotated with a detailed
/// safety comment to ensure that unsafe operations are used correctly and securely.
///
/// # Errors
///
/// The function returns an `io::Error` in cases where:
/// - The conversion from `SockaddrStorage` to a specific address family representation fails.
/// - Any other unexpected error condition occurs during the processing of the address family.
///
/// # Returns
///
/// Returns an `Result<(), Errno>`:
/// - `Ok(())` if the processing is successful.
/// - `Err(Errno)` containing a description of the error, if any error occurs during processing.
fn sandbox_addr(
    request: &UNotifyEventRequest,
    sandbox: &SandboxGuard,
    addr: &SockaddrStorage,
    root: &Option<CanonicalPath>,
    op: u8,
    caps: Capability,
) -> Result<(), Errno> {
    match addr.family() {
        Some(AddressFamily::Unix) => sandbox_addr_unix(request, sandbox, addr, root, op, caps),
        Some(AddressFamily::Inet) => sandbox_addr_inet(request, sandbox, addr, op, caps),
        Some(AddressFamily::Inet6) => sandbox_addr_inet6(request, sandbox, addr, op, caps),
        Some(_) | None => sandbox_addr_notsup(sandbox),
    }
}

/// Process a `AddressFamily::Unix` socket address.
#[allow(clippy::cognitive_complexity)]
fn sandbox_addr_unix(
    request: &UNotifyEventRequest,
    sandbox: &SandboxGuard,
    addr: &SockaddrStorage,
    root: &Option<CanonicalPath>,
    op: u8,
    caps: Capability,
) -> Result<(), Errno> {
    if sandbox.getcaps(caps).is_empty() {
        // Sandboxing is off.
        return Ok(());
    }

    let addr = addr.as_unix_addr().ok_or(Errno::EINVAL)?;
    let (path, abs) = match (addr.path(), addr.as_abstract()) {
        (Some(path), _) => match root {
            Some(path) => (Cow::Borrowed(path.abs()), false),
            None => {
                // Check for chroot.
                if sandbox.is_chroot() {
                    return Err(Errno::ENOENT);
                }

                let path = path.as_os_str().as_bytes();
                let null = memchr::memchr(0, path).unwrap_or(path.len());
                let p = XPathBuf::from(&path[..null]);
                (Cow::Owned(p), false)
            }
        },
        (_, Some(path)) => {
            // SAFETY: Prefix UNIX abstract sockets with `@' before access check.
            let mut unix = XPathBuf::from("@");
            let null = memchr::memchr(0, path).unwrap_or(path.len());
            unix.append_bytes(&path[..null]);
            (Cow::Owned(unix), true)
        }
        _ => {
            // SAFETY: Use dummy path `!unnamed' for unnamed UNIX sockets.
            (Cow::Borrowed(XPath::from_bytes(b"!unnamed")), true)
        }
    };

    // Convert /proc/${pid} to /proc/self as necessary.
    let path = if let Some(p) = path.split_prefix(b"/proc") {
        let mut buf = itoa::Buffer::new();
        let req = request.scmpreq;
        let pid = buf.format(req.pid);
        if let Some(p) = p.split_prefix(pid.as_bytes()) {
            let mut pdir = XPathBuf::from("/proc/self");
            pdir.push(p.as_bytes());
            Cow::Owned(pdir)
        } else {
            path
        }
    } else {
        path
    };

    // Check for access.
    let (action, filter) = request.cache.check_unix(sandbox, caps, &path);

    if !filter {
        let sys = op2name(op);
        let grp = if sys == "bind" { "bind" } else { "connect" };
        if sandbox.verbose {
            warn!("ctx": "access", "cap": caps, "act": action,
                "sys": sys, "unix": &path, "abs": abs,
                "tip": format!("configure `allow/net/{grp}+{path}'"),
                "req": request);
        } else {
            warn!("ctx": "access", "cap": caps, "act": action,
                "sys": sys, "unix": &path, "abs": abs,
                "tip": format!("configure `allow/net/{grp}+{path}'"),
                "pid": request.scmpreq.pid);
        }
    }

    match action {
        Action::Allow | Action::Warn => Ok(()),
        Action::Deny | Action::Filter => Err(op2errno(op)),
        Action::Panic => panic!(),
        Action::Exit => std::process::exit(op2errno(op) as i32),
        action => {
            // Stop|Kill
            let _ = request.kill(action);
            Err(op2errno(op))
        }
    }
}

/// Process an `AddressFamily::Inet` socket address.
#[allow(clippy::cognitive_complexity)]
fn sandbox_addr_inet(
    request: &UNotifyEventRequest,
    sandbox: &SandboxGuard,
    addr: &SockaddrStorage,
    op: u8,
    caps: Capability,
) -> Result<(), Errno> {
    if sandbox.getcaps(caps).is_empty() {
        // Sandboxing is off.
        return Ok(());
    }

    let addr = addr.as_sockaddr_in().ok_or(Errno::EINVAL)?;
    let port = addr.port();
    let addr = IpAddr::V4(addr.ip());

    let (action, filter) = if matches!(op, 0x5 | 0x12) {
        // accept{,4}: Check for IP blocklist.
        sandbox.check_block(addr)
    } else {
        // Check for access.
        request.cache.check_ip(sandbox, caps, addr, port)
    };

    if !filter {
        let sys = op2name(op);
        let grp = if sys == "bind" { "bind" } else { "connect" };
        if sandbox.verbose {
            warn!("ctx": "access", "cap": caps, "act": action,
                "sys": sys, "addr": format!("{addr}!{port}"),
                "tip": format!("configure `allow/net/{grp}+{addr}!{port}'"),
                "req": request);
        } else {
            warn!("ctx": "access", "cap": caps, "act": action,
                "sys": sys, "addr": format!("{addr}!{port}"),
                "tip": format!("configure `allow/net/{grp}+{addr}!{port}'"),
                "pid": request.scmpreq.pid);
        }
    }

    match action {
        Action::Allow | Action::Warn => Ok(()),
        Action::Deny | Action::Filter => Err(op2errno(op)),
        Action::Panic => panic!(),
        Action::Exit => std::process::exit(op2errno(op) as i32),
        action => {
            // Stop|Kill
            let _ = request.kill(action);
            Err(op2errno(op))
        }
    }
}

/// Process an `AddressFamily::Inet6` socket address.
#[allow(clippy::cognitive_complexity)]
fn sandbox_addr_inet6(
    request: &UNotifyEventRequest,
    sandbox: &SandboxGuard,
    addr: &SockaddrStorage,
    op: u8,
    caps: Capability,
) -> Result<(), Errno> {
    if sandbox.getcaps(caps).is_empty() {
        // Sandboxing is off.
        return Ok(());
    }

    let addr = addr.as_sockaddr_in6().ok_or(Errno::EINVAL)?;
    let port = addr.port();
    // Check if the IPv6 address is a mapped IPv4 address
    let (addr, ipv) = if let Some(v4addr) = addr.ip().to_ipv4_mapped() {
        // It's a mapped IPv4 address, convert to IPv4
        (IpAddr::V4(v4addr), 4)
    } else {
        // It's a regular IPv6 address
        (IpAddr::V6(addr.ip()), 6)
    };

    let (action, filter) = if matches!(op, 0x5 | 0x12) {
        // accept{,4}: Check for IP blocklist.
        sandbox.check_block(addr)
    } else {
        // Check for access.
        request.cache.check_ip(sandbox, caps, addr, port)
    };

    if !filter {
        let sys = op2name(op);
        let grp = if sys == "bind" { "bind" } else { "connect" };
        if sandbox.verbose {
            warn!("ctx": "access", "cap": caps, "act": action,
                "sys": sys, "addr": format!("{addr}!{port}"), "ipv": ipv,
                "tip": format!("configure `allow/net/{grp}+{addr}!{port}'"),
                "req": request);
        } else {
            warn!("ctx": "access", "cap": caps, "act": action,
                "sys": sys, "addr": format!("{addr}!{port}"), "ipv": ipv,
                "tip": format!("configure `allow/net/{grp}+{addr}!{port}'"),
                "pid": request.scmpreq.pid);
        }
    }

    match action {
        Action::Allow | Action::Warn => Ok(()),
        Action::Deny | Action::Filter => Err(op2errno(op)),
        Action::Panic => panic!(),
        Action::Exit => std::process::exit(op2errno(op) as i32),
        action => {
            // Stop|Kill
            let _ = request.kill(action);
            Err(op2errno(op))
        }
    }
}

/// Process a socket address of an unsupported socket family.
fn sandbox_addr_notsup(sandbox: &SandboxGuard) -> Result<(), Errno> {
    if sandbox.allow_unsupp_socket() {
        Ok(())
    } else {
        Err(Errno::EAFNOSUPPORT)
    }
}

/// Process the given path argument.
#[allow(clippy::cognitive_complexity)]
#[allow(clippy::too_many_arguments)]
fn sandbox_path(
    request: Option<&UNotifyEventRequest>,
    cache: &Arc<WorkerCache>,
    sandbox: &SandboxGuard,
    process: &RemoteProcess,
    path: &XPath,
    caps: Capability,
    hide: bool,
    syscall_name: &str,
) -> Result<(), Errno> {
    // Check for chroot.
    if sandbox.is_chroot() {
        return Err(Errno::ENOENT);
    }

    // Check enabled capabilities.
    let caps_old = caps;
    let mut caps = sandbox.getcaps(caps);
    let stat = sandbox.enabled(Capability::CAP_STAT);
    if caps.is_empty() && (!hide || !stat) {
        return if caps_old.intersects(Capability::CAP_WRSET)
            && request
                .map(|req| req.cache.is_append(sandbox, path))
                .unwrap_or(false)
        {
            // SAFETY: Protect append-only paths against writes.
            // We use UnknownErrno which will result in a no-op.
            Err(Errno::UnknownErrno)
        } else {
            Ok(())
        };
    }

    // Convert /proc/${pid} to /proc/self as necessary.
    let path = if let Some(p) = path.split_prefix(b"/proc") {
        let mut buf = itoa::Buffer::new();
        let pid = buf.format(process.pid.as_raw());
        if let Some(p) = p.split_prefix(pid.as_bytes()) {
            let mut pdir = XPathBuf::from("/proc/self");
            pdir.push(p.as_bytes());
            Cow::Owned(pdir)
        } else {
            Cow::Borrowed(path)
        }
    } else {
        Cow::Borrowed(path)
    };

    let mut action = Action::Allow;
    let mut filter = false;
    let mut deny_errno = Errno::EACCES;

    // Sandboxing.
    for cap in Capability::CAP_PATH {
        if caps.contains(cap) {
            let (new_action, new_filter) = cache.check_path(sandbox, cap, &path);

            if new_action >= action {
                action = new_action;
            }
            if !filter && new_filter {
                filter = true;
            }
        }
    }

    // SAFETY: Do an additional stat check to correct errno to ENOENT,
    // for sandboxing types other than Stat.
    let check_hidden = stat && hide && (caps.is_empty() || action.is_denying());
    if check_hidden || caps.contains(Capability::CAP_STAT) {
        let (new_action, new_filter) = cache.check_path(sandbox, Capability::CAP_STAT, &path);

        if !check_hidden {
            deny_errno = Errno::ENOENT;
            action = new_action;
            filter = new_filter;
        } else if new_action.is_denying() {
            deny_errno = Errno::ENOENT;
            if caps.is_empty() {
                action = new_action;
                filter = new_filter;
                caps.insert(Capability::CAP_STAT);
            }
        }

        if path.is_rootfs() && deny_errno == Errno::ENOENT {
            // SAFETY: No point in hiding `/`.
            deny_errno = Errno::EACCES;
        }
    }

    if !filter && action >= Action::Warn {
        // Log warn for normal cases.
        // Log info for path hiding unless explicitly specified to warn.
        let is_warn = if caps != Capability::CAP_STAT {
            true
        } else {
            !matches!(
                sandbox.default_action(Capability::CAP_STAT),
                Action::Filter | Action::Deny
            )
        };

        if let Some(request) = request {
            let args = request.scmpreq.data.args;
            if sandbox.verbose {
                if is_warn {
                    warn!("ctx": "access", "cap": caps, "act": action,
                        "sys": syscall_name, "path": &path, "args": args,
                        "tip": format!("configure `allow/{}+{}'",
                            caps.to_string().to_ascii_lowercase(),
                            path),
                        "req": request);
                } else {
                    notice!("ctx": "access", "cap": caps, "act": action,
                        "sys": syscall_name, "path": &path, "args": args,
                        "tip": format!("configure `allow/{}+{}'",
                            caps.to_string().to_ascii_lowercase(),
                            path),
                        "req": request);
                }
            } else if is_warn {
                warn!("ctx": "access", "cap": caps, "act": action,
                    "sys": syscall_name, "path": &path, "args": args,
                    "tip": format!("configure `allow/{}+{}'",
                        caps.to_string().to_ascii_lowercase(),
                        path),
                    "pid": request.scmpreq.pid);
            } else {
                notice!("ctx": "access", "cap": caps, "act": action,
                    "sys": syscall_name, "path": &path, "args": args,
                    "tip": format!("configure `allow/{}+{}'",
                        caps.to_string().to_ascii_lowercase(),
                        path),
                    "pid": request.scmpreq.pid);
            }
        } else if is_warn {
            warn!("ctx": "access", "cap": caps, "act": action,
                "sys": syscall_name, "path": &path,
                "tip": format!("configure `allow/{}+{}'",
                    caps.to_string().to_ascii_lowercase(),
                    path),
                "pid": process.pid.as_raw());
        } else {
            notice!("ctx": "access", "cap": caps, "act": action,
                "sys": syscall_name, "path": &path,
                "tip": format!("configure `allow/{}+{}'",
                    caps.to_string().to_ascii_lowercase(),
                    path),
                "pid": process.pid.as_raw());
        }
    }

    match action {
        Action::Allow | Action::Warn => {
            if caps.intersects(Capability::CAP_WRSET)
                && request
                    .map(|req| req.cache.is_append(sandbox, &path))
                    .unwrap_or(false)
            {
                // SAFETY: Protect append-only paths against writes.
                // We use UnknownErrno which will result in a no-op.
                Err(Errno::UnknownErrno)
            } else {
                Ok(())
            }
        }
        Action::Deny | Action::Filter => Err(deny_errno),
        Action::Panic => panic!(),
        Action::Exit => std::process::exit(deny_errno as i32),
        Action::Stop => {
            if let Some(request) = request {
                let _ = request.pidfd_kill(libc::SIGSTOP);
            } else {
                let _ = process.pidfd_kill(libc::SIGSTOP);
            }
            Err(deny_errno)
        }
        Action::Abort => {
            if let Some(request) = request {
                let _ = request.pidfd_kill(libc::SIGABRT);
            } else {
                let _ = process.pidfd_kill(libc::SIGABRT);
            }
            Err(deny_errno)
        }
        Action::Kill => {
            if let Some(request) = request {
                let _ = request.pidfd_kill(libc::SIGKILL);
            } else {
                let _ = process.pidfd_kill(libc::SIGKILL);
            }
            Err(deny_errno)
        }
    }
}

/*
 * System call handlers
 */

fn sys_sysinfo(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        let req = request.scmpreq;
        if req.data.args[0] == 0 {
            return Err(Errno::EFAULT);
        }

        // Generate a randomized sysinfo(2) structure.
        let info = SysInfo::new()?.as_raw();

        // SAFETY: The use of `from_raw_parts` here is safe because
        // `info` is fully initialized at this point by the preceding
        // `fillrandom` call, ensuring that the memory region from
        // `&info` up to the size of `libc::sysinfo` is valid. The
        // conversion to a byte slice is done to facilitate copying the
        // structure to another memory location without altering its
        // contents. This operation does not extend the lifetime of
        // `info` beyond this function, nor does it modify the content
        // of `info`, adhering to Rust's safety and borrowing rules.
        let info = unsafe {
            std::slice::from_raw_parts(
                std::ptr::addr_of!(info) as *const u8,
                std::mem::size_of_val(&info),
            )
        };

        request.write_mem(info, req.data.args[0])?;
        Ok(request.return_syscall(0))
    })
}

#[cfg(feature = "log")]
fn sys_syslog(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        // SAFETY: syslog(2) is only allowed if the sandbox lock is off,
        // unless trace/allow_safe_syslog:1 is set at startup.
        let req = request.scmpreq;
        let sandbox = request.get_sandbox();
        if !sandbox.allow_safe_syslog() && (Sandbox::locked_once() || sandbox.locked_for(req.pid()))
        {
            return Err(Errno::EPERM);
        }
        drop(sandbox); // release the read-lock.

        // SAFETY: Return EPERM if the global Syslog has not be initialized.
        let syslog = if let Some(syslog) = crate::syslog::global_syslog() {
            syslog
        } else {
            return Err(Errno::EPERM);
        };

        let action: libc::c_int = req.data.args[0].try_into().or(Err(Errno::EINVAL))?;
        let len: usize = req.data.args[2].try_into().unwrap_or(0);
        let (count, buf) = syslog.syslog(action, len)?;
        #[allow(clippy::cast_possible_wrap)]
        if let Some(buf) = buf {
            let n = request.write_mem(&buf, req.data.args[1])?;
            Ok(request.return_syscall(n as i64))
        } else {
            Ok(request.return_syscall(count as i64))
        }
    })
}

fn sys_uname(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        let req = request.scmpreq;
        if req.data.args[0] == 0 {
            return Err(Errno::EFAULT);
        }

        let mut name = MaybeUninit::<libc::utsname>::uninit();
        // SAFETY: In libc we trust.
        if unsafe { libc::uname(name.as_mut_ptr()) } != 0 {
            return Err(Errno::last());
        }

        // SAFETY: uname() has initialized `name` if it succeeded.
        let mut name = unsafe { name.assume_init() };

        // Wipe the version fields with zeros.
        // SAFETY: Unsafe is needed because we are directly manipulating
        // C structure fields. Here we trust the return value of
        // uname(2).
        unsafe {
            std::ptr::write_bytes(name.version.as_mut_ptr(), 0, 65);
        }

        // SAFETY: The use of `from_raw_parts` here is safe because
        // `name` is fully initialized at this point by the preceding
        // `uname` system call, ensuring that the memory region from
        // `&name` up to the size of `libc::utsname` is valid. The
        // conversion to a byte slice is done to facilitate copying the
        // structure to another memory location without altering its
        // contents. This operation does not extend the lifetime of
        // `name` beyond this function, nor does it modify the content
        // of `name`, adhering to Rust's safety and borrowing rules.
        let name = unsafe {
            std::slice::from_raw_parts(
                std::ptr::addr_of!(name) as *const u8,
                std::mem::size_of_val(&name),
            )
        };

        request.write_mem(name, req.data.args[0])?;
        Ok(request.return_syscall(0))
    })
}

fn sys_brk(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_mem_handler(request, "brk", Capability::CAP_MEM)
}

fn sys_mmap(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_mem_handler(
        request,
        "mmap",
        Capability::CAP_MEM | Capability::CAP_EXEC | Capability::CAP_FORCE | Capability::CAP_TPE,
    )
}

fn sys_mmap2(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_mem_handler(
        request,
        "mmap2",
        Capability::CAP_MEM | Capability::CAP_EXEC | Capability::CAP_FORCE | Capability::CAP_TPE,
    )
}

fn sys_mremap(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;
    let old_size = req.data.args[1];
    let new_size = req.data.args[2];
    if new_size < old_size {
        // SAFETY: System call wants to shrink memory.
        return unsafe { request.continue_syscall() };
    }
    syscall_mem_handler(request, "mremap", Capability::CAP_MEM)
}

#[allow(clippy::cognitive_complexity)]
fn syscall_mem_handler(
    request: UNotifyEventRequest,
    name: &str,
    caps: Capability,
) -> ScmpNotifResp {
    let req = request.scmpreq;

    // Get mem & vm max.
    let sandbox = request.get_sandbox();
    let verbose = sandbox.verbose;
    let caps = sandbox.getcaps(caps);
    let exec = caps.contains(Capability::CAP_EXEC);
    let force = caps.contains(Capability::CAP_FORCE);
    let tpe = caps.contains(Capability::CAP_TPE);
    let mem = caps.contains(Capability::CAP_MEM);
    let mem_max = sandbox.mem_max;
    let mem_vm_max = sandbox.mem_vm_max;
    let mem_act = sandbox.default_action(Capability::CAP_MEM);
    let restrict_stack = !sandbox.allow_unsafe_stack();

    if !exec && !force && !tpe && !restrict_stack && (!mem || (mem_max == 0 && mem_vm_max == 0)) {
        // SAFETY: No pointer dereference in security check.
        // This is safe to continue.
        return unsafe { request.continue_syscall() };
    }

    if (exec || force || tpe || restrict_stack)
        && matches!(name, "mmap" | "mmap2")
        && req.data.args[2] & PROT_EXEC != 0
        && req.data.args[3] & MAP_ANONYMOUS == 0
    {
        // Check file descriptor for Exec access.
        // Read and Write were already checked at open(2).
        let remote_fd = req.data.args[4] as RawFd;
        if remote_fd < 0 {
            return request.fail_syscall(Errno::EBADF);
        }

        // SAFETY: Get the file descriptor before access check
        // as it may change after which is a TOCTOU vector.
        let fd = match request.get_fd(remote_fd) {
            Ok(fd) => fd,
            Err(_) => return request.fail_syscall(Errno::EBADF),
        };
        let mut path = match CanonicalPath::new_fd(fd.into(), req.pid(), remote_fd) {
            Ok(path) => path,
            Err(errno) => return request.fail_syscall(errno),
        };

        // Step 1: Check for Exec sandboxing.
        if exec {
            // Unused when request.is_some()
            let process = RemoteProcess::new(request.scmpreq.pid());

            if let Err(errno) = sandbox_path(
                Some(&request),
                &request.cache,
                &sandbox,
                &process,
                path.abs(),
                Capability::CAP_EXEC,
                false,
                name,
            ) {
                return request.fail_syscall(errno);
            }
        }

        // Step 2: Check for TPE sandboxing.
        if tpe {
            let action = sandbox.check_tpe(path.abs());
            if !matches!(action, Action::Allow | Action::Filter) {
                if verbose {
                    error!("ctx": "trusted_path_execution",
                        "err": "library load from untrusted path blocked",
                        "sys": request.syscall, "path": &path,
                        "req": &request,
                        "tip": "move the library to a safe location or use `sandbox/tpe:off'");
                } else {
                    error!("ctx": "trusted_path_execution",
                        "err": "library load from untrusted path blocked",
                        "sys": request.syscall, "path": &path,
                        "pid": request.scmpreq.pid,
                        "tip": "move the library to a safe location or use `sandbox/tpe:off'");
                }
            }
            match action {
                Action::Allow | Action::Warn => {}
                Action::Deny | Action::Filter => return request.fail_syscall(Errno::EACCES),
                Action::Panic => panic!(),
                Action::Exit => std::process::exit(libc::EACCES),
                action => {
                    // Stop|Kill
                    let _ = request.kill(action);
                    return request.fail_syscall(Errno::EACCES);
                }
            }
        }

        if force || restrict_stack {
            // The following checks require the contents of the file.
            // SAFETY:
            // 1. Reopen the file via `/proc/self/fd` to avoid sharing the file offset.
            // 2. `path` is a remote-fd transfer which asserts `path.dir` is Some.
            #[allow(clippy::disallowed_methods)]
            let fd = path.dir.take().unwrap();

            let mut pfd = XPathBuf::from("self/fd");
            pfd.push_fd(fd.as_raw_fd());

            let mut file = match retry_on_eintr(|| {
                safe_open_magicsym(Some(&PROC_FILE()), &pfd, OFlag::O_RDONLY)
            }) {
                Ok(fd) => File::from(fd),
                Err(_) => {
                    return request.fail_syscall(Errno::EBADF);
                }
            };

            if restrict_stack {
                // Step 3: Check for non-executable stack.
                // An execstack library that is dlopened into an executable
                // that is otherwise mapped no-execstack can change the
                // stack permissions to executable! This has been
                // (ab)used in at least one CVE:
                // https://www.qualys.com/2023/07/19/cve-2023-38408/rce-openssh-forwarded-ssh-agent.txt
                let result = (|file: &mut File| -> Result<(), Errno> {
                    let exe = ExecutableFile::parse(&mut *file, true).or(Err(Errno::EBADF))?;
                    if matches!(exe, ExecutableFile::Elf { xs: true, .. }) {
                        if !sandbox.filter_path(Capability::CAP_EXEC, path.abs()) {
                            if verbose {
                                error!("ctx": "check_lib",
                                    "err": "library load with executable stack blocked",
                                    "sys": request.syscall, "path": path.abs(),
                                    "tip": "configure `trace/allow_unsafe_stack:1'",
                                    "lib": format!("{exe}"),
                                    "req": &request);
                            } else {
                                error!("ctx": "check_lib",
                                    "err": "library load with executable stack blocked",
                                    "sys": request.syscall, "path": path.abs(),
                                    "tip": "configure `trace/allow_unsafe_stack:1'",
                                    "lib": format!("{exe}"),
                                    "pid": request.scmpreq.pid);
                            }
                        }
                        Err(Errno::EACCES)
                    } else {
                        Ok(())
                    }
                })(&mut file);

                if let Err(errno) = result {
                    return request.fail_syscall(errno);
                }
            }

            if force {
                // Step 4: Check for Force sandboxing.
                if restrict_stack && file.rewind().is_err() {
                    drop(sandbox); // release the read-lock.
                    return request.fail_syscall(Errno::EBADF);
                }
                let result = sandbox.check_force2(path.abs(), &mut file);

                let deny = match result {
                    Ok(action) => {
                        if !matches!(action, Action::Allow | Action::Filter) {
                            if verbose {
                                warn!("ctx": "verify_lib", "act": action,
                                    "sys": request.syscall, "path": path.abs(),
                                    "tip": format!("configure `force+{}:<checksum>'", path.abs()),
                                    "sys": request.syscall, "req": &request);
                            } else {
                                warn!("ctx": "verify_lib", "act": action,
                                    "sys": request.syscall, "path": path.abs(),
                                    "tip": format!("configure `force+{}:<checksum>'", path.abs()),
                                    "pid": request.scmpreq.pid);
                            }
                        }
                        match action {
                            Action::Allow | Action::Warn => false,
                            Action::Deny | Action::Filter => true,
                            Action::Panic => panic!(),
                            Action::Exit => std::process::exit(libc::EACCES),
                            _ => {
                                // Stop|Kill
                                let _ = request.kill(action);
                                true
                            }
                        }
                    }
                    Err(IntegrityError::Sys(errno)) => {
                        if verbose {
                            error!("ctx": "verify_lib",
                                "err": format!("system error during library checksum calculation: {errno}"),
                                "sys": request.syscall, "path": path.abs(),
                                "tip": format!("configure `force+{}:<checksum>'", path.abs()),
                                "req": &request);
                        } else {
                            error!("ctx": "verify_lib",
                                "err": format!("system error during library checksum calculation: {errno}"),
                                "sys": request.syscall, "path": path.abs(),
                                "tip": format!("configure `force+{}:<checksum>'", path.abs()),
                                "pid": request.scmpreq.pid);
                        }
                        true
                    }
                    Err(IntegrityError::Hash {
                        action,
                        expected,
                        found,
                    }) => {
                        if action != Action::Filter {
                            if sandbox.verbose {
                                error!("ctx": "verify_lib", "act": action,
                                    "err": format!("library checksum mismatch: {found} is not {expected}"),
                                    "sys": request.syscall, "path": path.abs(),
                                    "tip": format!("configure `force+{}:<checksum>'", path.abs()),
                                    "req": &request);
                            } else {
                                error!("ctx": "verify_lib", "act": action,
                                    "err": format!("library checksum mismatch: {found} is not {expected}"),
                                    "sys": request.syscall, "path": path.abs(),
                                    "tip": format!("configure `force+{}:<checksum>'", path.abs()),
                                    "pid": request.scmpreq.pid);
                            }
                        }
                        match action {
                            // Allow cannot happen.
                            Action::Warn => false,
                            Action::Deny | Action::Filter => true,
                            Action::Panic => panic!(),
                            Action::Exit => std::process::exit(libc::EACCES),
                            _ => {
                                // Stop|Kill
                                let _ = request.kill(action);
                                true
                            }
                        }
                    }
                };

                if deny {
                    return request.fail_syscall(Errno::EACCES);
                }
            }
        }
    }
    drop(sandbox); // release the read-lock.

    if !mem || (mem_max == 0 && mem_vm_max == 0) {
        // SAFETY:
        // (a) Exec and Memory sandboxing are both disabled.
        // (b) Exec granted access, Memory sandboxing is disabled.
        // The first candidate is safe as sandboxing is disabled,
        // however (b) should theoretically suffer from VFS TOCTOU as
        // the fd can change after the access check. However, our tests
        // show this is not the case, see vfsmod_toctou_mmap integration
        // test.
        return unsafe { request.continue_syscall() };
    }

    // Check VmSize
    if mem_vm_max > 0 {
        let mem_vm_cur = match proc_statm(req.pid()) {
            Ok(statm) => statm.size.saturating_mul(*PAGE_SIZE),
            Err(errno) => return request.fail_syscall(errno),
        };
        if mem_vm_cur >= mem_vm_max {
            if mem_act != Action::Filter {
                if verbose {
                    warn!("ctx": "access", "cap": Capability::CAP_MEM, "act": mem_act,
                        "sys": request.syscall, "mem_vm_max": mem_vm_max, "mem_vm_cur": mem_vm_cur,
                        "tip": "increase `mem/vm_max'",
                        "req": &request);
                } else {
                    warn!("ctx": "access", "cap": Capability::CAP_MEM, "act": mem_act,
                        "sys": request.syscall, "mem_vm_max": mem_vm_max, "mem_vm_cur": mem_vm_cur,
                        "tip": "increase `mem/vm_max'",
                        "pid": request.scmpreq.pid);
                }
            }
            match mem_act {
                // Allow cannot happen.
                Action::Warn => {}
                Action::Deny | Action::Filter => return request.fail_syscall(Errno::ENOMEM),
                Action::Panic => panic!(),
                Action::Exit => std::process::exit(libc::ENOMEM),
                _ => {
                    // Stop|Kill
                    let _ = request.kill(mem_act);
                    return request.fail_syscall(Errno::ENOMEM);
                }
            }
        }
    }

    // Check PSS
    if mem_max > 0 {
        match proc_mem_limit(req.pid(), mem_max) {
            Ok(false) => {
                // SAFETY: No pointer dereference in security check.
                unsafe { request.continue_syscall() }
            }
            Ok(true) => {
                if mem_act != Action::Filter {
                    if verbose {
                        warn!("ctx": "access", "cap": Capability::CAP_MEM, "act": mem_act,
                            "sys": request.syscall, "mem_max": mem_max,
                            "tip": "increase `mem/max'",
                            "req": &request);
                    } else {
                        warn!("ctx": "access", "cap": Capability::CAP_MEM, "act": mem_act,
                            "mem_max": mem_max,
                            "tip": "increase `mem/max'",
                            "pid": request.scmpreq.pid);
                    }
                }
                match mem_act {
                    // Allow cannot happen.
                    Action::Warn => {
                        // SAFETY: No pointer dereference in security check.
                        unsafe { request.continue_syscall() }
                    }
                    Action::Deny | Action::Filter => request.fail_syscall(Errno::ENOMEM),
                    Action::Panic => panic!(),
                    Action::Exit => std::process::exit(libc::ENOMEM),
                    _ => {
                        // Stop|Kill
                        let _ = request.kill(mem_act);
                        request.fail_syscall(Errno::ENOMEM)
                    }
                }
            }
            Err(errno) => request.fail_syscall(errno),
        }
    } else {
        // SAFETY: No pointer dereference in security check.
        unsafe { request.continue_syscall() }
    }
}

#[allow(clippy::cognitive_complexity)]
fn sys_setuid(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        let req = request.scmpreq;

        let target_uid =
            Uid::from_raw(libc::uid_t::try_from(req.data.args[0]).or(Err(Errno::EINVAL))?);
        let source_uid = Uid::current();

        if u64::from(target_uid.as_raw()) <= UID_MIN {
            // SAFETY: This is already asserted with the parent
            // seccomp-bpf filter, this is the second layer.
            return Ok(request.return_syscall(0));
        } else if source_uid == target_uid {
            // SAFETY: There's no pointer dereference in the access check.
            return unsafe { Ok(request.continue_syscall()) };
        }

        let sandbox = request.get_sandbox();
        let allowed = sandbox.chk_uid_transit(source_uid, target_uid);
        let verbose = sandbox.verbose;
        drop(sandbox); // release the read lock.

        if !allowed {
            if verbose {
                warn!("ctx": "safesetid", "err": libc::EACCES,
                    "sys": request.syscall, "target_uid": target_uid.as_raw(), "source_uid": source_uid.as_raw(),
                    "req": request);
            } else {
                warn!("ctx": "safesetid", "err": libc::EACCES,
                    "sys": request.syscall, "target_uid": target_uid.as_raw(), "source_uid": source_uid.as_raw(),
                    "pid": request.scmpreq.pid);
            }
            return Err(Errno::EACCES);
        }

        // SAFETY: nix version of setuid does not allow -1 as argument.
        if let Err(errno) = Errno::result(unsafe { libc::setuid(target_uid.as_raw()) }) {
            if verbose {
                warn!("ctx": "safesetid", "err": errno as i32,
                    "sys": request.syscall, "target_uid": target_uid.as_raw(), "source_uid": source_uid.as_raw(),
                    "req": request);
            } else {
                warn!("ctx": "safesetid", "err": errno as i32,
                    "sys": request.syscall, "target_uid": target_uid.as_raw(), "source_uid": source_uid.as_raw(),
                    "pid": request.scmpreq.pid);
            }
            return Err(errno);
        } else if safe_drop_cap(caps::Capability::CAP_SETUID).is_err() {
            // SAFETY: We cannot do much on errors,
            // and on panic the thread will be restarted.
            // The best we can do from a security POV is
            // to enter Ghost mode. This is certainly
            // unexpected but it's safe.
            return Err(Errno::EOWNERDEAD);
        }

        // SAFETY: There's no pointer dereference in the access check.
        unsafe { Ok(request.continue_syscall()) }
    })
}

#[allow(clippy::cognitive_complexity)]
fn sys_setgid(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        let req = request.scmpreq;

        let target_gid =
            Gid::from_raw(libc::gid_t::try_from(req.data.args[0]).or(Err(Errno::EINVAL))?);
        let source_gid = Gid::current();

        if u64::from(target_gid.as_raw()) <= GID_MIN {
            // SAFETY: This is already asserted with the parent
            // seccomp-bpf filter, this is the second layer.
            return Ok(request.return_syscall(0));
        } else if source_gid == target_gid {
            // SAFETY: There's no pointer dereference in the access check.
            return unsafe { Ok(request.continue_syscall()) };
        }

        let sandbox = request.get_sandbox();
        let allowed = sandbox.chk_gid_transit(source_gid, target_gid);
        let verbose = sandbox.verbose;
        drop(sandbox); // release the read lock.

        if !allowed {
            if verbose {
                warn!("ctx": "safesetid", "err": libc::EACCES,
                    "sys": request.syscall, "target_gid": target_gid.as_raw(), "source_gid": source_gid.as_raw(),
                    "req": request);
            } else {
                warn!("ctx": "safesetid", "err": libc::EACCES,
                    "sys": request.syscall, "target_gid": target_gid.as_raw(), "source_gid": source_gid.as_raw(),
                    "pid": request.scmpreq.pid);
            }
            return Err(Errno::EACCES);
        }

        // SAFETY: nix version of setgid does not allow -1 as argument.
        if let Err(errno) = Errno::result(unsafe { libc::setgid(target_gid.as_raw()) }) {
            if verbose {
                warn!("ctx": "safesetid", "err": errno as i32,
                    "sys": request.syscall, "target_gid": target_gid.as_raw(), "source_gid": source_gid.as_raw(),
                    "req": request);
            } else {
                warn!("ctx": "safesetid", "err": errno as i32,
                    "sys": request.syscall, "target_gid": target_gid.as_raw(), "source_gid": source_gid.as_raw(),
                    "pid": request.scmpreq.pid);
            }
            return Err(errno);
        } else if safe_drop_cap(caps::Capability::CAP_SETGID).is_err() {
            // SAFETY: We cannot do much on errors,
            // and on panic the thread will be restarted.
            // The best we can do from a security POV is
            // to enter Ghost mode. This is certainly
            // unexpected but it's safe.
            return Err(Errno::EOWNERDEAD);
        }

        // SAFETY: There's no pointer dereference in the access check.
        unsafe { Ok(request.continue_syscall()) }
    })
}

#[allow(clippy::cognitive_complexity)]
fn sys_setreuid(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        let req = request.scmpreq;

        #[allow(clippy::cast_possible_truncation)]
        #[allow(clippy::cast_possible_wrap)]
        let target_ruid = match req.data.args[0] as i32 {
            -1 => None,
            n if n >= 0 => Some(Uid::from_raw(
                libc::uid_t::try_from(n).or(Err(Errno::EINVAL))?,
            )),
            _ => return Err(Errno::EINVAL),
        };
        #[allow(clippy::cast_possible_truncation)]
        #[allow(clippy::cast_possible_wrap)]
        let target_euid = match req.data.args[1] as i32 {
            -1 => None,
            n if n >= 0 => Some(Uid::from_raw(
                libc::uid_t::try_from(n).or(Err(Errno::EINVAL))?,
            )),
            _ => return Err(Errno::EINVAL),
        };

        if target_ruid.is_none() && target_euid.is_none() {
            return Ok(request.return_syscall(0));
        }

        // getresuid can only fail with EFAULT which should not happen.
        let resuid = getresuid()?;
        let source_ruid = resuid.real;
        let source_euid = resuid.effective;

        let mut change = false;
        if let Some(target_ruid) = target_ruid {
            if u64::from(target_ruid.as_raw()) <= UID_MIN {
                // SAFETY: This is already asserted with the parent
                // seccomp-bpf filter, this is the second layer.
                return Ok(request.return_syscall(0));
            } else if source_ruid != target_ruid {
                change = true;
            }
        }
        if let Some(target_euid) = target_euid {
            if u64::from(target_euid.as_raw()) <= UID_MIN {
                // SAFETY: This is already asserted with the parent
                // seccomp-bpf filter, this is the second layer.
                return Ok(request.return_syscall(0));
            } else if source_euid != target_euid {
                change = true;
            }
        }

        if !change {
            // SAFETY: There's no pointer dereference in the access check.
            return unsafe { Ok(request.continue_syscall()) };
        }

        let sandbox = request.get_sandbox();
        let verbose = sandbox.verbose;

        // SAFETY: We do not support RUID != EUID
        if let Some(target_ruid) = target_ruid {
            if let Some(target_euid) = target_euid {
                if target_ruid != target_euid {
                    if verbose {
                        warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                            "target_euid": target_euid.as_raw(), "target_ruid": target_ruid.as_raw(),
                            "source_euid": source_euid.as_raw(), "source_ruid": source_ruid.as_raw(),
                            "req": &request);
                    } else {
                        warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                            "target_euid": target_euid.as_raw(), "target_ruid": target_ruid.as_raw(),
                            "source_euid": source_euid.as_raw(), "source_ruid": source_ruid.as_raw(),
                            "pid": request.scmpreq.pid);
                    }
                    return Err(Errno::EACCES);
                }
            }
        }

        let mut allowed = true;
        if let Some(target_ruid) = target_ruid {
            if !sandbox.chk_uid_transit(source_ruid, target_ruid) {
                allowed = false;
            }
        }
        if allowed {
            if let Some(target_euid) = target_euid {
                if !sandbox.chk_uid_transit(source_euid, target_euid) {
                    allowed = false;
                }
            }
        }
        drop(sandbox); // release the read lock.

        let target_ruid = target_ruid.map(|uid| i64::from(uid.as_raw())).unwrap_or(-1);
        let target_euid = target_euid.map(|uid| i64::from(uid.as_raw())).unwrap_or(-1);
        if !allowed {
            if verbose {
                warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                    "target_euid": target_euid, "target_ruid": target_ruid,
                    "source_euid": source_euid.as_raw(), "source_ruid": source_ruid.as_raw(),
                    "req": request);
            } else {
                warn!("ctx": "safesetid", "err": libc::EACCES,
                    "target_euid": target_euid, "target_ruid": target_ruid,
                    "source_euid": source_euid.as_raw(), "source_ruid": source_ruid.as_raw(),
                    "pid": request.scmpreq.pid);
            }
            return Err(Errno::EACCES);
        }

        if let Err(errno) =
            // SAFETY: nix version of setreuid does not allow -1 as argument.
            Errno::result(unsafe {
                libc::syscall(libc::SYS_setreuid, target_ruid, target_euid)
            })
        {
            if verbose {
                warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                    "target_euid": target_euid, "target_ruid": target_ruid,
                    "source_euid": source_euid.as_raw(), "source_ruid": source_ruid.as_raw(),
                    "req": request);
            } else {
                warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                    "target_euid": target_euid, "target_ruid": target_ruid,
                    "source_euid": source_euid.as_raw(), "source_ruid": source_ruid.as_raw(),
                    "pid": request.scmpreq.pid);
            }
            return Err(errno);
        } else if safe_drop_cap(caps::Capability::CAP_SETUID).is_err() {
            // SAFETY: We cannot do much on errors,
            // and on panic the thread will be restarted.
            // The best we can do from a security POV is
            // to enter Ghost mode. This is certainly
            // unexpected but it's safe.
            return Err(Errno::EOWNERDEAD);
        }

        // SAFETY: There's no pointer dereference in the access check.
        unsafe { Ok(request.continue_syscall()) }
    })
}

#[allow(clippy::cognitive_complexity)]
fn sys_setregid(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        let req = request.scmpreq;

        #[allow(clippy::cast_possible_truncation)]
        #[allow(clippy::cast_possible_wrap)]
        let target_rgid = match req.data.args[0] as i32 {
            -1 => None,
            n if n >= 0 => Some(Gid::from_raw(
                libc::gid_t::try_from(n).or(Err(Errno::EINVAL))?,
            )),
            _ => return Err(Errno::EINVAL),
        };
        #[allow(clippy::cast_possible_truncation)]
        #[allow(clippy::cast_possible_wrap)]
        let target_egid = match req.data.args[1] as i32 {
            -1 => None,
            n if n >= 0 => Some(Gid::from_raw(
                libc::gid_t::try_from(n).or(Err(Errno::EINVAL))?,
            )),
            _ => return Err(Errno::EINVAL),
        };

        if target_rgid.is_none() && target_egid.is_none() {
            return Ok(request.return_syscall(0));
        }

        // getresgid can only fail with EFAULT which should not happen.
        let resgid = getresgid()?;
        let source_rgid = resgid.real;
        let source_egid = resgid.effective;

        let mut change = false;
        if let Some(target_rgid) = target_rgid {
            if u64::from(target_rgid.as_raw()) <= GID_MIN {
                // SAFETY: This is already asserted with the parent
                // seccomp-bpf filter, this is the second layer.
                return Ok(request.return_syscall(0));
            } else if source_rgid != target_rgid {
                change = true;
            }
        }
        if let Some(target_egid) = target_egid {
            if u64::from(target_egid.as_raw()) <= GID_MIN {
                // SAFETY: This is already asserted with the parent
                // seccomp-bpf filter, this is the second layer.
                return Ok(request.return_syscall(0));
            } else if source_egid != target_egid {
                change = true;
            }
        }

        if !change {
            // SAFETY: There's no pointer dereference in the access check.
            return unsafe { Ok(request.continue_syscall()) };
        }

        let sandbox = request.get_sandbox();
        let verbose = sandbox.verbose;

        // SAFETY: We do not support Rgid != Egid
        if let Some(target_rgid) = target_rgid {
            if let Some(target_egid) = target_egid {
                if target_rgid != target_egid {
                    if verbose {
                        warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                            "target_egid": target_egid.as_raw(), "target_rgid": target_rgid.as_raw(),
                            "source_egid": source_egid.as_raw(), "source_rgid": source_rgid.as_raw(),
                            "req": &request);
                    } else {
                        warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                            "target_egid": target_egid.as_raw(), "target_rgid": target_rgid.as_raw(),
                            "source_egid": source_egid.as_raw(), "source_rgid": source_rgid.as_raw(),
                            "err": request.scmpreq.pid);
                    }
                    return Err(Errno::EACCES);
                }
            }
        }

        let mut allowed = true;
        if let Some(target_rgid) = target_rgid {
            if !sandbox.chk_gid_transit(source_rgid, target_rgid) {
                allowed = false;
            }
        }
        if allowed {
            if let Some(target_egid) = target_egid {
                if !sandbox.chk_gid_transit(source_egid, target_egid) {
                    allowed = false;
                }
            }
        }
        drop(sandbox); // release the read lock.

        let target_rgid = target_rgid.map(|gid| i64::from(gid.as_raw())).unwrap_or(-1);
        let target_egid = target_egid.map(|gid| i64::from(gid.as_raw())).unwrap_or(-1);
        if !allowed {
            if verbose {
                warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                    "target_egid": target_egid, "target_rgid": target_rgid,
                    "source_egid": source_egid.as_raw(), "source_rgid": source_rgid.as_raw(),
                    "req": request);
            } else {
                warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                    "target_egid": target_egid, "target_rgid": target_rgid,
                    "source_egid": source_egid.as_raw(), "source_rgid": source_rgid.as_raw(),
                    "pid": request.scmpreq.pid);
            }
            return Err(Errno::EACCES);
        }

        if let Err(errno) =
            // SAFETY: nix version of setregid does not allow -1 as argument.
            Errno::result(unsafe {
                libc::syscall(libc::SYS_setregid, target_rgid, target_egid)
            })
        {
            if verbose {
                warn!("ctx": "safesetid", "err": errno as i32,
                    "target_egid": target_egid, "target_rgid": target_rgid, "sys": request.syscall,
                    "source_egid": source_egid.as_raw(), "source_rgid": source_rgid.as_raw(),
                    "req": request);
            } else {
                warn!("ctx": "safesetid", "err": errno as i32,
                    "target_egid": target_egid, "target_rgid": target_rgid, "sys": request.syscall,
                    "source_egid": source_egid.as_raw(), "source_rgid": source_rgid.as_raw(),
                    "pid": request.scmpreq.pid);
            }
            return Err(errno);
        } else if safe_drop_cap(caps::Capability::CAP_SETGID).is_err() {
            // SAFETY: We cannot do much on errors,
            // and on panic the thread will be restarted.
            // The best we can do from a security POV is
            // to enter Ghost mode. This is certainly
            // unexpected but it's safe.
            return Err(Errno::EOWNERDEAD);
        }

        // SAFETY: There's no pointer dereference in the access check.
        unsafe { Ok(request.continue_syscall()) }
    })
}

#[allow(clippy::cognitive_complexity)]
fn sys_setresuid(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        let req = request.scmpreq;

        #[allow(clippy::cast_possible_truncation)]
        #[allow(clippy::cast_possible_wrap)]
        let target_ruid = match req.data.args[0] as i32 {
            -1 => None,
            n if n >= 0 => Some(Uid::from_raw(
                libc::uid_t::try_from(n).or(Err(Errno::EINVAL))?,
            )),
            _ => return Err(Errno::EINVAL),
        };
        #[allow(clippy::cast_possible_truncation)]
        #[allow(clippy::cast_possible_wrap)]
        let target_euid = match req.data.args[1] as i32 {
            -1 => None,
            n if n >= 0 => Some(Uid::from_raw(
                libc::uid_t::try_from(n).or(Err(Errno::EINVAL))?,
            )),
            _ => return Err(Errno::EINVAL),
        };
        #[allow(clippy::cast_possible_truncation)]
        #[allow(clippy::cast_possible_wrap)]
        let target_suid = match req.data.args[2] as i32 {
            -1 => None,
            n if n >= 0 => Some(Uid::from_raw(
                libc::uid_t::try_from(n).or(Err(Errno::EINVAL))?,
            )),
            _ => return Err(Errno::EINVAL),
        };

        if target_ruid.is_none() && target_euid.is_none() && target_suid.is_none() {
            return Ok(request.return_syscall(0));
        }

        // getresuid can only fail with EFAULT which should not happen.
        let resuid = getresuid()?;
        let source_ruid = resuid.real;
        let source_euid = resuid.effective;
        let source_suid = resuid.saved;

        let mut change = false;
        if let Some(target_ruid) = target_ruid {
            if u64::from(target_ruid.as_raw()) <= UID_MIN {
                // SAFETY: This is already asserted with the parent
                // seccomp-bpf filter, this is the second layer.
                return Ok(request.return_syscall(0));
            } else if source_ruid != target_ruid {
                change = true;
            }
        }
        if let Some(target_euid) = target_euid {
            if u64::from(target_euid.as_raw()) <= UID_MIN {
                // SAFETY: This is already asserted with the parent
                // seccomp-bpf filter, this is the second layer.
                return Ok(request.return_syscall(0));
            } else if source_euid != target_euid {
                change = true;
            }
        }
        if let Some(target_suid) = target_suid {
            if u64::from(target_suid.as_raw()) <= UID_MIN {
                // SAFETY: This is already asserted with the parent
                // seccomp-bpf filter, this is the second layer.
                return Ok(request.return_syscall(0));
            } else if source_suid != target_suid {
                change = true;
            }
        }

        if !change {
            // SAFETY: There's no pointer dereference in the access check.
            return unsafe { Ok(request.continue_syscall()) };
        }

        let sandbox = request.get_sandbox();
        let verbose = sandbox.verbose;

        // SAFETY: We do not support RUID != EUID != SUID
        if let Some(target_ruid) = target_ruid {
            if let Some(target_euid) = target_euid {
                if target_ruid != target_euid {
                    if verbose {
                        warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                            "target_suid": target_suid.map(|u| u.as_raw()),
                            "target_euid": target_euid.as_raw(),
                            "target_ruid": target_ruid.as_raw(),
                            "source_euid": source_euid.as_raw(),
                            "source_ruid": source_ruid.as_raw(),
                            "source_suid": source_suid.as_raw(),
                            "req": &request);
                    } else {
                        warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                            "target_suid": target_suid.map(|u| u.as_raw()),
                            "target_euid": target_euid.as_raw(),
                            "target_ruid": target_ruid.as_raw(),
                            "source_euid": source_euid.as_raw(),
                            "source_ruid": source_ruid.as_raw(),
                            "source_suid": source_suid.as_raw(),
                            "pid": request.scmpreq.pid);
                    }
                    return Err(Errno::EACCES);
                }
            }
        }
        if let Some(target_ruid) = target_ruid {
            if let Some(target_suid) = target_suid {
                if target_ruid != target_suid {
                    if verbose {
                        warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                            "target_suid": target_suid.as_raw(),
                            "target_euid": target_euid.map(|u| u.as_raw()),
                            "target_ruid": target_ruid.as_raw(),
                            "source_euid": source_euid.as_raw(),
                            "source_ruid": source_ruid.as_raw(),
                            "source_suid": source_suid.as_raw(),
                            "req": &request);
                    } else {
                        warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                            "target_suid": target_suid.as_raw(),
                            "target_euid": target_euid.map(|u| u.as_raw()),
                            "target_ruid": target_ruid.as_raw(),
                            "source_euid": source_euid.as_raw(),
                            "source_ruid": source_ruid.as_raw(),
                            "source_suid": source_suid.as_raw(),
                            "pid": request.scmpreq.pid);
                    }
                    return Err(Errno::EACCES);
                }
            }
        }
        if let Some(target_euid) = target_euid {
            if let Some(target_suid) = target_suid {
                if target_euid != target_suid {
                    if verbose {
                        warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                            "target_suid": target_suid.as_raw(),
                            "target_euid": target_euid.as_raw(),
                            "target_ruid": target_ruid.map(|u| u.as_raw()),
                            "source_euid": source_euid.as_raw(),
                            "source_ruid": source_ruid.as_raw(),
                            "source_suid": source_suid.as_raw(),
                            "req": &request);
                    } else {
                        warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                            "target_suid": target_suid.as_raw(),
                            "target_euid": target_euid.as_raw(),
                            "target_ruid": target_ruid.map(|u| u.as_raw()),
                            "source_euid": source_euid.as_raw(),
                            "source_ruid": source_ruid.as_raw(),
                            "source_suid": source_suid.as_raw(),
                            "pid": request.scmpreq.pid);
                    }
                    return Err(Errno::EACCES);
                }
            }
        }

        let mut allowed = true;
        if let Some(target_ruid) = target_ruid {
            if !sandbox.chk_uid_transit(source_ruid, target_ruid) {
                allowed = false;
            }
        }
        if allowed {
            if let Some(target_euid) = target_euid {
                if !sandbox.chk_uid_transit(source_euid, target_euid) {
                    allowed = false;
                }
            }
        }
        if allowed {
            if let Some(target_suid) = target_suid {
                if !sandbox.chk_uid_transit(source_suid, target_suid) {
                    allowed = false;
                }
            }
        }
        drop(sandbox); // release the read lock.

        let target_ruid = target_ruid.map(|uid| i64::from(uid.as_raw())).unwrap_or(-1);
        let target_euid = target_euid.map(|uid| i64::from(uid.as_raw())).unwrap_or(-1);
        let target_suid = target_suid.map(|uid| i64::from(uid.as_raw())).unwrap_or(-1);
        if !allowed {
            if verbose {
                warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                    "target_suid": target_suid,
                    "target_euid": target_euid,
                    "target_ruid": target_ruid,
                    "source_euid": source_euid.as_raw(),
                    "source_ruid": source_ruid.as_raw(),
                    "source_suid": source_suid.as_raw(),
                    "req": request);
            } else {
                warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                    "target_suid": target_suid,
                    "target_euid": target_euid,
                    "target_ruid": target_ruid,
                    "source_euid": source_euid.as_raw(),
                    "source_ruid": source_ruid.as_raw(),
                    "source_suid": source_suid.as_raw(),
                    "pid": request.scmpreq.pid);
            }
            return Err(Errno::EACCES);
        }

        // SAFETY: nix version of setresuid does not allow -1 as argument.
        if let Err(errno) = Errno::result(unsafe {
            libc::syscall(libc::SYS_setresuid, target_ruid, target_euid, target_suid)
        }) {
            if verbose {
                warn!("ctx": "safesetid", "err": errno as i32, "sys": request.syscall,
                    "target_suid": target_suid,
                    "target_euid": target_euid,
                    "target_ruid": target_ruid,
                    "source_euid": source_euid.as_raw(),
                    "source_ruid": source_ruid.as_raw(),
                    "source_suid": source_suid.as_raw(),
                    "req": request);
            } else {
                warn!("ctx": "safesetid", "err": errno as i32, "sys": request.syscall,
                    "target_suid": target_suid,
                    "target_euid": target_euid,
                    "target_ruid": target_ruid,
                    "source_euid": source_euid.as_raw(),
                    "source_ruid": source_ruid.as_raw(),
                    "source_suid": source_suid.as_raw(),
                    "pid": request.scmpreq.pid);
            }
            return Err(errno);
        } else if safe_drop_cap(caps::Capability::CAP_SETUID).is_err() {
            // SAFETY: We cannot do much on errors,
            // and on panic the thread will be restarted.
            // The best we can do from a security POV is
            // to enter Ghost mode. This is certainly
            // unexpected but it's safe.
            return Err(Errno::EOWNERDEAD);
        }

        // SAFETY: There's no pointer dereference in the access check.
        unsafe { Ok(request.continue_syscall()) }
    })
}

#[allow(clippy::cognitive_complexity)]
fn sys_setresgid(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        let req = request.scmpreq;

        #[allow(clippy::cast_possible_truncation)]
        #[allow(clippy::cast_possible_wrap)]
        let target_rgid = match req.data.args[0] as i32 {
            -1 => None,
            n if n >= 0 => Some(Gid::from_raw(
                libc::gid_t::try_from(n).or(Err(Errno::EINVAL))?,
            )),
            _ => return Err(Errno::EINVAL),
        };
        #[allow(clippy::cast_possible_truncation)]
        #[allow(clippy::cast_possible_wrap)]
        let target_egid = match req.data.args[1] as i32 {
            -1 => None,
            n if n >= 0 => Some(Gid::from_raw(
                libc::gid_t::try_from(n).or(Err(Errno::EINVAL))?,
            )),
            _ => return Err(Errno::EINVAL),
        };
        #[allow(clippy::cast_possible_truncation)]
        #[allow(clippy::cast_possible_wrap)]
        let target_sgid = match req.data.args[2] as i32 {
            -1 => None,
            n if n >= 0 => Some(Gid::from_raw(
                libc::gid_t::try_from(n).or(Err(Errno::EINVAL))?,
            )),
            _ => return Err(Errno::EINVAL),
        };

        if target_rgid.is_none() && target_egid.is_none() && target_sgid.is_none() {
            return Ok(request.return_syscall(0));
        }

        // getresgid can only fail with EFAULT which should not happen.
        let resgid = getresgid()?;
        let source_rgid = resgid.real;
        let source_egid = resgid.effective;
        let source_sgid = resgid.saved;

        let mut change = false;
        if let Some(target_rgid) = target_rgid {
            if u64::from(target_rgid.as_raw()) <= GID_MIN {
                // SAFETY: This is already asserted with the parent
                // seccomp-bpf filter, this is the second layer.
                return Ok(request.return_syscall(0));
            } else if source_rgid != target_rgid {
                change = true;
            }
        }
        if let Some(target_egid) = target_egid {
            if u64::from(target_egid.as_raw()) <= GID_MIN {
                // SAFETY: This is already asserted with the parent
                // seccomp-bpf filter, this is the second layer.
                return Ok(request.return_syscall(0));
            } else if source_egid != target_egid {
                change = true;
            }
        }
        if let Some(target_sgid) = target_sgid {
            if u64::from(target_sgid.as_raw()) <= GID_MIN {
                // SAFETY: This is already asserted with the parent
                // seccomp-bpf filter, this is the second layer.
                return Ok(request.return_syscall(0));
            } else if source_sgid != target_sgid {
                change = true;
            }
        }

        if !change {
            // SAFETY: There's no pointer dereference in the access check.
            return unsafe { Ok(request.continue_syscall()) };
        }

        let sandbox = request.get_sandbox();
        let verbose = sandbox.verbose;

        // SAFETY: We do not support Rgid != Egid != Sgid
        if let Some(target_rgid) = target_rgid {
            if let Some(target_egid) = target_egid {
                if target_rgid != target_egid {
                    if verbose {
                        warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                            "target_sgid": target_sgid.map(|u| u.as_raw()),
                            "target_egid": target_egid.as_raw(),
                            "target_rgid": target_rgid.as_raw(),
                            "source_egid": source_egid.as_raw(),
                            "source_rgid": source_rgid.as_raw(),
                            "source_sgid": source_sgid.as_raw(),
                            "req": &request);
                    } else {
                        warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                            "target_sgid": target_sgid.map(|u| u.as_raw()),
                            "target_egid": target_egid.as_raw(),
                            "target_rgid": target_rgid.as_raw(),
                            "source_egid": source_egid.as_raw(),
                            "source_rgid": source_rgid.as_raw(),
                            "source_sgid": source_sgid.as_raw(),
                            "pid": request.scmpreq.pid);
                    }
                    return Err(Errno::EACCES);
                }
            }
        }
        if let Some(target_rgid) = target_rgid {
            if let Some(target_sgid) = target_sgid {
                if target_rgid != target_sgid {
                    if verbose {
                        warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                            "target_sgid": target_sgid.as_raw(),
                            "target_egid": target_egid.map(|u| u.as_raw()),
                            "target_rgid": target_rgid.as_raw(),
                            "source_egid": source_egid.as_raw(),
                            "source_rgid": source_rgid.as_raw(),
                            "source_sgid": source_sgid.as_raw(),
                            "req": &request);
                    } else {
                        warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                            "target_sgid": target_sgid.as_raw(),
                            "target_egid": target_egid.map(|u| u.as_raw()),
                            "target_rgid": target_rgid.as_raw(),
                            "source_egid": source_egid.as_raw(),
                            "source_rgid": source_rgid.as_raw(),
                            "source_sgid": source_sgid.as_raw(),
                            "pid": request.scmpreq.pid);
                    }
                    return Err(Errno::EACCES);
                }
            }
        }
        if let Some(target_egid) = target_egid {
            if let Some(target_sgid) = target_sgid {
                if target_egid != target_sgid {
                    if verbose {
                        warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                            "target_sgid": target_sgid.as_raw(),
                            "target_egid": target_egid.as_raw(),
                            "target_rgid": target_rgid.map(|u| u.as_raw()),
                            "source_egid": source_egid.as_raw(),
                            "source_rgid": source_rgid.as_raw(),
                            "source_sgid": source_sgid.as_raw(),
                            "req": &request);
                    } else {
                        warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                            "target_sgid": target_sgid.as_raw(),
                            "target_egid": target_egid.as_raw(),
                            "target_rgid": target_rgid.map(|u| u.as_raw()),
                            "source_egid": source_egid.as_raw(),
                            "source_rgid": source_rgid.as_raw(),
                            "source_sgid": source_sgid.as_raw(),
                            "pid": request.scmpreq.pid);
                    }
                    return Err(Errno::EACCES);
                }
            }
        }

        let mut allowed = true;
        if let Some(target_rgid) = target_rgid {
            if !sandbox.chk_gid_transit(source_rgid, target_rgid) {
                allowed = false;
            }
        }
        if allowed {
            if let Some(target_egid) = target_egid {
                if !sandbox.chk_gid_transit(source_egid, target_egid) {
                    allowed = false;
                }
            }
        }
        if allowed {
            if let Some(target_sgid) = target_sgid {
                if !sandbox.chk_gid_transit(source_sgid, target_sgid) {
                    allowed = false;
                }
            }
        }
        drop(sandbox); // release the read lock.

        let target_rgid = target_rgid.map(|gid| i64::from(gid.as_raw())).unwrap_or(-1);
        let target_egid = target_egid.map(|gid| i64::from(gid.as_raw())).unwrap_or(-1);
        let target_sgid = target_sgid.map(|gid| i64::from(gid.as_raw())).unwrap_or(-1);
        if !allowed {
            if verbose {
                warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                    "target_sgid": target_sgid,
                    "target_egid": target_egid,
                    "target_rgid": target_rgid,
                    "source_egid": source_egid.as_raw(),
                    "source_rgid": source_rgid.as_raw(),
                    "source_sgid": source_sgid.as_raw(),
                    "req": request);
            } else {
                warn!("ctx": "safesetid", "err": libc::EACCES, "sys": request.syscall,
                    "target_sgid": target_sgid,
                    "target_egid": target_egid,
                    "target_rgid": target_rgid,
                    "source_egid": source_egid.as_raw(),
                    "source_rgid": source_rgid.as_raw(),
                    "source_sgid": source_sgid.as_raw(),
                    "pid": request.scmpreq.pid);
            }
            return Err(Errno::EACCES);
        }

        // SAFETY: nix version of setregid does not allow -1 as argument.
        if let Err(errno) = Errno::result(unsafe {
            libc::syscall(libc::SYS_setresgid, target_rgid, target_egid, target_sgid)
        }) {
            if verbose {
                warn!("ctx": "safesetid", "err": errno as i32, "sys": request.syscall,
                    "target_sgid": target_sgid,
                    "target_egid": target_egid,
                    "target_rgid": target_rgid,
                    "source_egid": source_egid.as_raw(),
                    "source_rgid": source_rgid.as_raw(),
                    "source_sgid": source_sgid.as_raw(),
                    "req": request);
            } else {
                warn!("ctx": "safesetid", "err": errno as i32, "sys": request.syscall,
                    "target_sgid": target_sgid,
                    "target_egid": target_egid,
                    "target_rgid": target_rgid,
                    "source_egid": source_egid.as_raw(),
                    "source_rgid": source_rgid.as_raw(),
                    "source_sgid": source_sgid.as_raw(),
                    "pid": request.scmpreq.pid);
            }
            return Err(errno);
        } else if safe_drop_cap(caps::Capability::CAP_SETGID).is_err() {
            // SAFETY: We cannot do much on errors,
            // and on panic the thread will be restarted.
            // The best we can do from a security POV is
            // to enter Ghost mode. This is certainly
            // unexpected but it's safe.
            return Err(Errno::EOWNERDEAD);
        }

        // SAFETY: There's no pointer dereference in the access check.
        unsafe { Ok(request.continue_syscall()) }
    })
}

fn sys_kill(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_signal_handler(request, false, false)
}

fn sys_tgkill(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_signal_handler(request, true, true)
}

fn sys_tkill(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_signal_handler(request, true, false)
}

fn sys_pidfd_open(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_signal_handler(request, false, false)
}

#[allow(clippy::cognitive_complexity)]
fn sys_socketcall(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    // Determine system call
    // 0x1 => socket
    // 0x2 => bind
    // 0x3 => connect
    // 0x5 => accept
    // 0x6 => getsockname
    // 0xb => sendto
    // 0x10 => sendmsg
    // 0x12 => accept4
    // 0x14 => sendmmsg
    #[allow(clippy::cast_possible_truncation)]
    let op = match req.data.args[0] {
        n @ (0x1 | 0x2 | 0x3 | 0x5 | 0x6 | 0xb | 0x10 | 0x12 | 0x14) => n as u8,
        _ => {
            // SAFETY: Safe network call, continue.
            // No pointer-dereference in access check.
            return unsafe { request.continue_syscall() };
        }
    };

    // Determine system call arguments.
    // On x86 unsigned long is 4 bytes, and on s390x 8 bytes.
    let is32 = scmp_arch_bits(req.data.arch) == 32;
    let sizeof_ulong: usize = if is32 { 4 } else { 8 };
    const ARGLEN: usize = 6;
    let mut args = [0u64; ARGLEN];
    #[allow(clippy::arithmetic_side_effects)]
    let bufsiz = sizeof_ulong * ARGLEN;
    let mut buf = Vec::new();
    if buf.try_reserve(bufsiz).is_err() {
        return request.fail_syscall(Errno::ENOMEM);
    }
    buf.resize(bufsiz, 0);
    match request.read_mem(&mut buf, req.data.args[1]) {
        Ok(n) if n == bufsiz => {
            for (i, chunk) in buf.chunks_exact(sizeof_ulong).enumerate() {
                match sizeof_ulong {
                    4 => match chunk.try_into() {
                        Ok(bytes) => args[i] = u64::from(u32::from_ne_bytes(bytes)),
                        Err(_) => return request.fail_syscall(Errno::EFAULT),
                    },
                    8 => match chunk.try_into() {
                        Ok(bytes) => args[i] = u64::from_ne_bytes(bytes),
                        Err(_) => return request.fail_syscall(Errno::EFAULT),
                    },
                    _ => {
                        // SAFETY: The is32 check above
                        // ensures this branch is never reached.
                        unreachable!("BUG: Invalid sizeof unsigned long: {sizeof_ulong}!");
                    }
                }
            }
        }
        _ => {
            // Short read or error.
            return request.fail_syscall(Errno::EFAULT);
        }
    }

    syscall_network_handler(request, &args, op)
}

fn sys_socket(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;
    syscall_network_handler(request, &req.data.args, 0x1)
}

fn sys_bind(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;
    syscall_network_handler(request, &req.data.args, 0x2)
}

fn sys_accept(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;
    syscall_network_handler(request, &req.data.args, 0x5)
}

fn sys_accept4(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;
    syscall_network_handler(request, &req.data.args, 0x12)
}

fn sys_getsockname(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;
    syscall_network_handler(request, &req.data.args, 0x6)
}

fn sys_connect(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;
    syscall_network_handler(request, &req.data.args, 0x3)
}

fn sys_sendto(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;
    syscall_network_handler(request, &req.data.args, 0xb)
}

fn sys_sendmsg(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;
    syscall_network_handler(request, &req.data.args, 0x10)
}

fn sys_sendmmsg(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;
    syscall_network_handler(request, &req.data.args, 0x14)
}

fn sys_execve(request: UNotifyEventRequest) -> ScmpNotifResp {
    let arg = SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH,
        ..Default::default()
    };
    syscall_exec_handler(request, "execve", arg)
}

fn sys_execveat(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    #[allow(clippy::cast_possible_truncation)]
    let flags = AtFlags::from_bits_truncate(req.data.args[4] as libc::c_int);

    let mut fsflags = FsFlags::MUST_PATH;
    if flags.contains(AtFlags::AT_SYMLINK_NOFOLLOW) {
        fsflags.insert(FsFlags::NO_FOLLOW_LAST);
    }

    let empty_path = flags.contains(AtFlags::AT_EMPTY_PATH);
    let arg = SysArg {
        dirfd: Some(0),
        path: Some(1),
        flags: if empty_path {
            SysFlags::EMPTY_PATH
        } else {
            SysFlags::empty()
        },
        fsflags,
        ..Default::default()
    };
    syscall_exec_handler(request, "execveat", arg)
}

#[allow(clippy::cognitive_complexity)]
fn handle_ptrace_sysenter(
    process: RemoteProcess,
    info: ptrace_syscall_info,
    cache: &Arc<WorkerCache>,
    sandbox: &Arc<RwLock<Sandbox>>,
) -> Result<(), Errno> {
    #[allow(clippy::disallowed_methods)]
    let info_scmp = info.seccomp().unwrap();

    #[allow(clippy::cast_possible_truncation)]
    let scmp_trace_data = info_scmp.ret_data as u16;

    match scmp_trace_data {
        PTRACE_DATA_CHDIR => {
            // Acquire a read lock to the sandbox.
            let my_sandbox =
                SandboxGuard::Read(sandbox.read().unwrap_or_else(|err| err.into_inner()));

            if !my_sandbox.enabled(Capability::CAP_CHDIR) {
                // SAFETY: Chdir sandboxing is not enabled,
                // continue the system call without any
                // checking.
                return Err(Errno::UnknownErrno);
            }

            let result = sysenter_chdir(&process, cache, &my_sandbox, info_scmp);

            drop(my_sandbox); // release the read lock.

            let path = match result {
                Ok(path) => path,
                Err(errno) => {
                    // Set system call to -1 to skip the system call.
                    // Write error value into the return register.
                    return if ptrace_skip_syscall(process.pid, info.arch, errno).is_err() {
                        // SAFETY: Failed to set return value,
                        // terminate the process.
                        let _ = process.pidfd_kill(libc::SIGKILL);
                        Err(Errno::ESRCH)
                    } else if cfg!(any(
                        target_arch = "mips",
                        target_arch = "mips32r6",
                        target_arch = "mips64",
                        target_arch = "mips64r6",
                        target_arch = "s390x"
                    )) {
                        // Skip to syscall-stop to write return value.
                        cache.add_error(process, errno)
                    } else {
                        // Continue process.
                        Err(Errno::UnknownErrno)
                    };
                }
            };

            // Record the chdir result.
            //
            // SAFETY: Terminate the process on errors.
            cache.add_chdir(process, path)?;

            // Stop at syscall exit.
            Ok(())
        }
        PTRACE_DATA_EXECVE | PTRACE_DATA_EXECVEAT => {
            // Acquire a read lock to the sandbox.
            let my_sandbox =
                SandboxGuard::Read(sandbox.read().unwrap_or_else(|err| err.into_inner()));

            // Call the system call handler, and record the result.
            let result = sysenter_exec(&process, cache, &my_sandbox, info);

            drop(my_sandbox); // release the read lock.

            let file = match result {
                Ok(file) => file,
                Err(errno) => {
                    // Set system call to -1 to skip the system call.
                    // Write error value into the return register.
                    return if ptrace_skip_syscall(process.pid, info.arch, errno).is_err() {
                        // SAFETY: Failed to set return value,
                        // terminate the process.
                        let _ = process.pidfd_kill(libc::SIGKILL);
                        Err(Errno::ESRCH)
                    } else if cfg!(any(
                        target_arch = "mips",
                        target_arch = "mips32r6",
                        target_arch = "mips64",
                        target_arch = "mips64r6",
                        target_arch = "s390x"
                    )) {
                        // Skip to syscall-stop to write return value.
                        cache.add_error(process, errno)
                    } else {
                        // Continue process.
                        Err(Errno::UnknownErrno)
                    };
                }
            };

            // Read memory pointed by IP and SP for logging.
            let si = scmp_syscall_instruction(info.arch);
            let ip = info.instruction_pointer.saturating_sub(si.len() as u64);
            let sp = (info.stack_pointer & !0xF).saturating_sub(16);

            let ip_mem = if ip >= *MMAP_MIN_ADDR {
                let mut ip_mem = [0u8; 64];
                // SAFETY: We validate the PidFd after memory read.
                match unsafe { process.read_mem(&mut ip_mem, ip) } {
                    Ok(_) => Some(ip_mem),
                    Err(Errno::EFAULT) => None,
                    Err(Errno::ESRCH) => return Err(Errno::ESRCH),
                    Err(_) => {
                        // SAFETY: Process is alive, but
                        // we cannot read memory: Terminate!
                        let _ = process.pidfd_kill(libc::SIGKILL);
                        return Err(Errno::ESRCH);
                    }
                }
            } else {
                None
            };

            let sp_mem = if sp >= *MMAP_MIN_ADDR {
                let mut sp_mem = [0u8; 64];
                #[allow(clippy::arithmetic_side_effects)]
                // SAFETY: We validate the PidFd after memory read.
                match unsafe { process.read_mem(&mut sp_mem, sp) } {
                    Ok(_) => Some(sp_mem),
                    Err(Errno::EFAULT) => None,
                    Err(Errno::ESRCH) => return Err(Errno::ESRCH),
                    Err(_) => {
                        // SAFETY: Process is alive, but
                        // we cannot read memory: Terminate!
                        let _ = process.pidfd_kill(libc::SIGKILL);
                        return Err(Errno::ESRCH);
                    }
                }
            } else {
                None
            };

            // Save `/proc/$pid/maps`.
            let memmap = proc_maps(process.pid).ok();

            // Record the exec result.
            //
            // SAFETY: Terminate the process on errors.
            cache.add_exec(
                process,
                file,
                info.arch,
                ip,
                sp,
                info_scmp.args,
                ip_mem,
                sp_mem,
                memmap,
            )?;

            // Continue process, it will stop at EVENT_EXEC.
            Err(Errno::UnknownErrno)
        }
        PTRACE_DATA_SIGRETURN | PTRACE_DATA_RT_SIGRETURN => {
            // Upgrade to write lock, and record the sigreturn entry.
            let is_realtime = scmp_trace_data == PTRACE_DATA_RT_SIGRETURN;

            // Read memory pointed by IP and SP.
            let si = scmp_syscall_instruction(info.arch);
            let ip = info.instruction_pointer.saturating_sub(si.len() as u64);
            let sp = (info.stack_pointer & !0xF).saturating_sub(16);

            let ip_mem = if ip >= *MMAP_MIN_ADDR {
                let mut ip_mem = [0u8; 64];

                // SAFETY: We validate the PidFd after memory read.
                match unsafe { process.read_mem(&mut ip_mem, ip) } {
                    Ok(_) => Some(ip_mem),
                    Err(Errno::EFAULT) => None,
                    Err(Errno::ESRCH) => return Err(Errno::ESRCH),
                    Err(_) => {
                        // SAFETY: Process is alive, but
                        // we cannot read memory: Terminate!
                        let _ = process.pidfd_kill(libc::SIGKILL);
                        return Err(Errno::ESRCH);
                    }
                }
            } else {
                None
            };

            let sp_mem = if sp >= *MMAP_MIN_ADDR {
                let mut sp_mem = [0u8; 64];

                #[allow(clippy::arithmetic_side_effects)]
                // SAFETY: We validate the PidFd after memory read.
                match unsafe { process.read_mem(&mut sp_mem, sp) } {
                    Ok(_) => Some(sp_mem),
                    Err(Errno::EFAULT) => None,
                    Err(Errno::ESRCH) => return Err(Errno::ESRCH),
                    Err(_) => {
                        // SAFETY: Process is alive, but
                        // we cannot read memory: Terminate!
                        let _ = process.pidfd_kill(libc::SIGKILL);
                        return Err(Errno::ESRCH);
                    }
                }
            } else {
                None
            };

            // SAFETY: Signal handlers are per-process not per-thread!
            let status = match proc_status(process.pid) {
                Ok(status) => status,
                Err(_) => {
                    // SAFETY: Failed to get TGID,
                    // terminate the process.
                    let _ = process.pidfd_kill(libc::SIGKILL);
                    return Err(Errno::ESRCH);
                }
            };

            // SAFETY: Validate PidFd after memory and `/proc` read.
            if !process.is_alive() {
                return Err(Errno::ESRCH);
            }

            // Record the sigreturn entry.
            // SAFETY: Check for signal counts for SROP mitigation.
            let tgid = Pid::from_raw(status.pid);
            if !cache.dec_sig_handle(tgid) {
                // !!! SIGRETURN W/O SIGNAL AKA SROP !!!

                // Read memory maps for logging.
                let memmap = proc_maps(process.pid).ok();

                // Terminate the process.
                let _ = process.pidfd_kill(libc::SIGKILL);

                // Disassemble IP for logging.
                let ip_asm = if let Some(ref ip_mem) = ip_mem {
                    if let Ok(arch) = scmp_arch(info.arch) {
                        disasm(ip_mem, arch, ip, true, false)
                            .map(|instructions| {
                                instructions
                                    .into_iter()
                                    .map(|instruction| instruction.op)
                                    .collect::<Vec<_>>()
                            })
                            .ok()
                    } else {
                        None
                    }
                } else {
                    None
                };

                let ip_mem = ip_mem.as_ref().map(|ip_mem| ip_mem.to_lower_hex_string());
                let sp_mem = sp_mem.as_ref().map(|sp_mem| sp_mem.to_lower_hex_string());

                // Log and return ESRCH.
                #[allow(clippy::disallowed_methods)]
                let arch = SydArch(scmp_arch(info.arch).unwrap());
                error!("ctx": "sigreturn", "op": "check_SROP",
                    "err": "artificial sigreturn detected!",
                    "act": Action::Kill,
                    "pid": process.pid.as_raw(),
                    "sys": if is_realtime { "rt_sigreturn" } else { "sigreturn" },
                    "args": info_scmp.args,
                    "arch": arch,
                    "tgid": tgid.as_raw(),
                    "sig_caught": status.sig_caught,
                    "sig_blocked": status.sig_blocked,
                    "sig_ignored": status.sig_ignored,
                    "sig_pending_thread": status.sig_pending_thread,
                    "sig_pending_process": status.sig_pending_process,
                    "ip": ip,
                    "sp": sp,
                    "ip_asm": ip_asm,
                    "ip_mem": ip_mem,
                    "sp_mem": sp_mem,
                    "memmap": memmap);

                return Err(Errno::ESRCH);
            }

            // Signal handle, add sigreturn for
            // the second round of mitigations at exit.
            //
            // SAFETY: Terminate the process on errors.
            cache.add_sigreturn(process, is_realtime, ip, sp, info_scmp.args, ip_mem, sp_mem)?;

            // Stop at sigreturn exit.
            Ok(())
        }

        data => unreachable!("BUG: invalid syscall data {data}!"),
    }
}

fn handle_ptrace_sysexit(
    pid: Pid,
    info: ptrace_syscall_info,
    cache: &Arc<WorkerCache>,
) -> Result<(), Errno> {
    // Get and remove the syscall entry from the cache,
    // and call the respective syscall handler.
    if let Some((process, path)) = cache.get_chdir(pid) {
        sysexit_chdir(process, info, path)
    } else if let Some((process, result)) = cache.get_sigreturn(pid) {
        sysexit_sigreturn(process, info, result)
    } else if let Some((process, errno)) = cache.get_error(pid) {
        // Architectures like mips, s390x where return value has to be written twice.
        ptrace_set_return(process.pid, info.arch, Some(errno))
    } else {
        unreachable!("BUG: Invalid syscall exit stop: {info:?}");
    }
}

// Note, exec is a ptrace(2) hook, not a seccomp hook!
#[allow(clippy::cognitive_complexity)]
fn sysenter_exec(
    process: &RemoteProcess,
    cache: &Arc<WorkerCache>,
    sandbox: &SandboxGuard,
    info: ptrace_syscall_info,
) -> Result<ExecutableFile, Errno> {
    let data = if let Some(data) = info.seccomp() {
        data
    } else {
        unreachable!("BUG: Invalid system call information returned by kernel!");
    };

    #[allow(clippy::cast_possible_truncation)]
    let (syscall_name, arg) = match data.ret_data as u16 {
        PTRACE_DATA_EXECVE => (
            "execve",
            SysArg {
                path: Some(0),
                fsflags: FsFlags::MUST_PATH | FsFlags::WANT_READ,
                ..Default::default()
            },
        ),
        PTRACE_DATA_EXECVEAT => {
            #[allow(clippy::cast_possible_truncation)]
            let flags = AtFlags::from_bits_truncate(data.args[4] as libc::c_int);

            let mut fsflags = FsFlags::MUST_PATH | FsFlags::WANT_READ;
            if flags.contains(AtFlags::AT_SYMLINK_NOFOLLOW) {
                fsflags.insert(FsFlags::NO_FOLLOW_LAST);
            }

            let empty_path = flags.contains(AtFlags::AT_EMPTY_PATH);
            (
                "execveat",
                SysArg {
                    dirfd: Some(0),
                    path: Some(1),
                    flags: if empty_path {
                        SysFlags::EMPTY_PATH
                    } else {
                        SysFlags::empty()
                    },
                    fsflags,
                    ..Default::default()
                },
            )
        }
        data => unreachable!("BUG: invalid syscall data {data}!"),
    };

    // Read remote path.
    let (mut path, _, _) =
        // SAFETY: We will validate the PidFd afterwards.
        unsafe { process.read_path(sandbox, data.args, arg, false, None) }?;
    if !process.is_alive() {
        return Err(Errno::ESRCH);
    }

    // Call sandbox access checker.
    let caps = sandbox.getcaps(Capability::CAP_EXEC | Capability::CAP_TPE);
    let hide = sandbox.enabled(Capability::CAP_STAT);
    if caps.contains(Capability::CAP_EXEC) {
        sandbox_path(
            None,
            cache,
            sandbox,
            process,
            path.abs(),
            Capability::CAP_EXEC,
            hide,
            syscall_name,
        )?;
    }

    if !arg.fsflags.follow_last()
        && path
            .typ
            .as_ref()
            .map(|typ| typ.is_symlink() || typ.is_magic_link())
            .unwrap_or(false)
    {
        // SAFETY: AT_SYMLINK_NOFOLLOW: If the file identified by dirfd
        // and a non-NULL pathname is a symbolic link, then the call
        // fails with the error ELOOP.
        return Err(Errno::ELOOP);
    }

    // SAFETY:
    // 1. Return EACCES without any more processing if the file is not
    //    executable.
    // 2. We set MUST_PATH in FsFlags, path.dir is always Some.
    #[allow(clippy::disallowed_methods)]
    if !is_executable(path.dir.as_ref().unwrap()) {
        return Err(Errno::EACCES);
    }

    // Check SegvGuard.
    if let Some(action) = sandbox.check_segvguard(path.abs()) {
        if action != Action::Filter {
            let (_, bin) = path.abs().split();
            error!("ctx": "segvguard",
                "err": format!("max crashes {} exceeded, execution of `{bin}' denied",
                    sandbox.segvguard_maxcrashes),
                "tip": "increase `segvguard/maxcrashes'",
                "pid": process.pid.as_raw(), "path": path.abs());
        }

        match action {
            Action::Allow | Action::Warn => {}
            Action::Deny | Action::Filter => return Err(Errno::EACCES),
            Action::Panic => panic!(),
            Action::Exit => std::process::exit(libc::EACCES),
            Action::Stop => {
                let _ = process.pidfd_kill(libc::SIGSTOP);
                return Err(Errno::EACCES);
            }
            Action::Abort => {
                let _ = process.pidfd_kill(libc::SIGABRT);
                return Err(Errno::EACCES);
            }
            Action::Kill => {
                let _ = process.pidfd_kill(libc::SIGKILL);
                return Err(Errno::EACCES);
            }
        }
    }

    // Trusted Path Execution.
    if caps.contains(Capability::CAP_TPE) {
        let action = sandbox.check_tpe(path.abs());
        if !matches!(action, Action::Allow | Action::Filter) {
            // TODO: Fix proc_mmap to work in ptrace hooks.
            error!("ctx": "trusted_path_execution",
                "err": "exec from untrusted path blocked",
                "pid": process.pid.as_raw(), "path": path.abs(),
                "sys": syscall_name, "arch": info.arch, "args": data.args,
                "tip": "move the binary to a safe location or use `sandbox/tpe:off'");
        }
        match action {
            Action::Allow | Action::Warn => {}
            Action::Deny | Action::Filter => return Err(Errno::EACCES),
            Action::Panic => panic!(),
            Action::Exit => std::process::exit(libc::EACCES),
            Action::Stop => {
                let _ = process.pidfd_kill(libc::SIGSTOP);
                return Err(Errno::EACCES);
            }
            Action::Abort => {
                let _ = process.pidfd_kill(libc::SIGABRT);
                return Err(Errno::EACCES);
            }
            Action::Kill => {
                let _ = process.pidfd_kill(libc::SIGKILL);
                return Err(Errno::EACCES);
            }
        }
    }

    // SAFETY: We will read from the regular files only and parse ELF.
    if let Some(file_type) = path.typ.as_ref() {
        if file_type.is_dir() {
            return Err(Errno::EISDIR);
        } else if !file_type.is_file() {
            return Err(Errno::EACCES);
        }
    } else {
        return Err(Errno::ENOENT);
    }

    // SAFETY: Use safe open to avoid TOCTOU!
    let flags = OFlag::O_RDONLY | OFlag::O_NOFOLLOW | OFlag::O_NOCTTY | OFlag::O_CLOEXEC;

    let mut file = if path.base.is_empty() {
        match path.dir.take() {
            Some(MaybeFd::Owned(fd)) => {
                set_nonblock(&fd, false)?;
                Ok(fd)
            }
            _ => return Err(Errno::ENOEXEC),
        }
    } else if let Some(dirfd) = path.dir.as_ref() {
        safe_open(Some(dirfd), path.base, flags)
    } else {
        safe_open::<BorrowedFd>(None, path.abs(), flags)
    }
    .map(File::from)?;

    // Parse ELF as necessary for restrictions.
    let deny_script = sandbox.deny_script();
    let restrict_32 = sandbox.deny_elf32();
    let restrict_dyn = sandbox.deny_elf_dynamic();
    let restrict_sta = sandbox.deny_elf_static();
    let restrict_pie = !sandbox.allow_unsafe_nopie();
    let restrict_xs = !sandbox.allow_unsafe_stack();

    // Shared library execution depends on trace/allow_unsafe_exec:1.
    // unsafe_exec also means no ptrace, hence we can never be here.
    let restrict_ldd = true /* !sandbox.allow_unsafe_exec() */;

    let check_linking = restrict_ldd || restrict_dyn || restrict_sta || restrict_pie || restrict_xs;

    let result = (|| -> Result<ExecutableFile, ElfError> {
        // Parse ELF and reset the file offset.
        let result = ExecutableFile::parse(&file, check_linking);
        file.seek(SeekFrom::Start(0)).map_err(ElfError::IoError)?;
        result
    })();

    let exe = match result {
        Ok(exe) => exe,
        Err(ElfError::IoError(err)) => {
            let errno = err2no(&err);
            if !sandbox.filter_path(Capability::CAP_EXEC, path.abs()) {
                error!("ctx": "parse_elf",
                    "err": format!("io error: {errno}"),
                    "pid": process.pid.as_raw(), "path": path.abs());
            }
            return Err(errno);
        }
        Err(ElfError::BadMagic) => {
            if !sandbox.filter_path(Capability::CAP_EXEC, path.abs()) {
                error!("ctx": "parse_elf",
                    "err": "invalid ELF file",
                    "pid": process.pid.as_raw(), "path": path.abs());
            }
            return Err(Errno::ENOEXEC);
        }
        Err(ElfError::Malformed) => {
            if !sandbox.filter_path(Capability::CAP_EXEC, path.abs()) {
                error!("ctx": "parse_elf",
                    "err": "malformed ELF file",
                    "pid": process.pid.as_raw(), "path": path.abs());
            }
            return Err(Errno::ENOEXEC);
        }
    };

    let is_script = exe == ExecutableFile::Script;
    if is_script && deny_script {
        if !sandbox.filter_path(Capability::CAP_EXEC, path.abs()) {
            error!("ctx": "deny_script",
                "err": "script execution denied",
                "pid": process.pid.as_raw(), "path": path.abs(),
                "exe": format!("{exe}"));
        }
        return Err(Errno::EACCES);
    }

    if !is_script
        && restrict_ldd
        && !matches!(
            exe,
            ExecutableFile::Elf {
                file_type: ElfFileType::Executable,
                ..
            }
        )
    {
        if !sandbox.filter_path(Capability::CAP_EXEC, path.abs()) {
            error!("ctx": "check_elf",
                "err": "ld.so exec-indirection",
                "pid": process.pid.as_raw(), "path": path.abs(),
                "exe": format!("{exe}"));
        }
        return Err(Errno::EACCES);
    }

    if !is_script && restrict_pie && matches!(exe, ExecutableFile::Elf { pie: false, .. }) {
        if !sandbox.filter_path(Capability::CAP_EXEC, path.abs()) {
            error!("ctx": "check_elf", "err": "not PIE",
                "pid": process.pid.as_raw(), "path": path.abs(),
                "tip": "configure `trace/allow_unsafe_nopie:1'",
                "exe": format!("{exe}"));
        }
        return Err(Errno::EACCES);
    }

    if !is_script && restrict_xs && matches!(exe, ExecutableFile::Elf { xs: true, .. }) {
        if !sandbox.filter_path(Capability::CAP_EXEC, path.abs()) {
            error!("ctx": "check_elf", "err": "execstack",
                "pid": process.pid.as_raw(), "path": path.abs(),
                "tip": "configure `trace/allow_unsafe_stack:1'",
                "exe": format!("{exe}"));
        }
        return Err(Errno::EACCES);
    }

    if !is_script
        && restrict_32
        && matches!(
            exe,
            ExecutableFile::Elf {
                elf_type: ElfType::Elf32,
                ..
            }
        )
    {
        if !sandbox.filter_path(Capability::CAP_EXEC, path.abs()) {
            error!("ctx": "check_elf", "err": "32-bit",
                "pid": process.pid.as_raw(), "path": path.abs(),
                "tip": "configure `trace/deny_elf32:0'",
                "exe": format!("{exe}"));
        }
        return Err(Errno::EACCES);
    }

    if !is_script
        && restrict_dyn
        && matches!(
            exe,
            ExecutableFile::Elf {
                linking_type: Some(LinkingType::Dynamic),
                ..
            }
        )
    {
        if !sandbox.filter_path(Capability::CAP_EXEC, path.abs()) {
            error!("ctx": "check_elf", "err": "dynamic-link",
                "pid": process.pid.as_raw(), "path": path.abs(),
                "tip": "configure `trace/deny_elf_dynamic:0'",
                "exe": format!("{exe}"));
        }
        return Err(Errno::EACCES);
    }

    if !is_script
        && restrict_sta
        && matches!(
            exe,
            ExecutableFile::Elf {
                linking_type: Some(LinkingType::Static),
                ..
            }
        )
    {
        if !sandbox.filter_path(Capability::CAP_EXEC, path.abs()) {
            error!("ctx": "check_elf", "err": "static-link",
                "pid": process.pid.as_raw(), "path": path,
                "tip": "configure `trace/deny_elf_static:0'",
                "exe": format!("{exe}"));
        }
        return Err(Errno::EACCES);
    }

    // Check for Force sandboxing.
    if sandbox.enabled(Capability::CAP_FORCE) {
        match sandbox.check_force2(path.abs(), &mut file) {
            Ok(Action::Allow) => {}
            Ok(Action::Warn) => {
                warn!("ctx": "verify_elf", "act": Action::Warn,
                    "pid": process.pid.as_raw(), "path": path.abs(),
                    "tip": format!("configure `force+{path}:<checksum>'"));
            }
            Ok(Action::Filter) => return Err(Errno::EACCES),
            Ok(Action::Deny) => {
                warn!("ctx": "verify_elf", "act": Action::Deny,
                    "pid": process.pid.as_raw(), "path": path.abs(),
                    "tip": format!("configure `force+{path}:<checksum>'"));
                return Err(Errno::EACCES);
            }
            Ok(Action::Stop) => {
                warn!("ctx": "verify_elf", "act": Action::Stop,
                    "pid": process.pid.as_raw(), "path": path.abs(),
                    "tip": format!("configure `force+{path}:<checksum>'"));
                let _ = process.pidfd_kill(libc::SIGSTOP);
                return Err(Errno::EACCES);
            }
            Ok(Action::Abort) => {
                warn!("ctx": "verify_elf", "act": Action::Abort,
                    "pid": process.pid.as_raw(), "path": path.abs(),
                    "tip": format!("configure `force+{path}:<checksum>'"));
                let _ = process.pidfd_kill(libc::SIGABRT);
                return Err(Errno::EACCES);
            }
            Ok(Action::Kill) => {
                warn!("ctx": "verify_elf", "act": Action::Kill,
                    "pid": process.pid.as_raw(), "path": path.abs(),
                    "tip": format!("configure `force+{path}:<checksum>'"));
                let _ = process.pidfd_kill(libc::SIGKILL);
                return Err(Errno::EACCES);
            }
            Ok(Action::Exit) => {
                error!("ctx": "verify_elf", "act": Action::Exit,
                    "pid": process.pid.as_raw(), "path": path.abs(),
                    "tip": format!("configure `force+{path}:<checksum>'"));
                std::process::exit(libc::EACCES);
            }
            Ok(Action::Panic) => panic!(),
            Err(IntegrityError::Sys(errno)) => {
                error!("ctx": "verify_elf",
                    "err": format!("system error during ELF checksum calculation: {errno}"),
                    "pid": process.pid.as_raw(), "path": path.abs(),
                    "tip": format!("configure `force+{path}:<checksum>'"));
                return Err(Errno::EACCES);
            }
            Err(IntegrityError::Hash {
                action,
                expected,
                found,
            }) => {
                if !matches!(action, Action::Allow | Action::Filter) {
                    error!("ctx": "verify_elf", "act": action,
                        "err": format!("ELF checksum mismatch: {found} is not {expected}"),
                        "pid": process.pid.as_raw(), "path": path.abs(),
                        "tip": format!("configure `force+{path}:<checksum>'"));
                }
                match action {
                    Action::Allow | Action::Warn => {}
                    Action::Filter | Action::Deny => return Err(Errno::EACCES),
                    Action::Stop | Action::Abort | Action::Kill => {
                        let _ = process.pidfd_kill(
                            action
                                .signal()
                                .map(|sig| sig as i32)
                                .unwrap_or(libc::SIGKILL),
                        );
                        return Err(Errno::EACCES);
                    }
                    Action::Panic => panic!(),
                    Action::Exit => std::process::exit(libc::EACCES),
                };
            }
        }
    }

    Ok(exe)
}

// Note sigreturn is a ptrace(2) hook, not a seccomp hook!
#[allow(clippy::cognitive_complexity)]
fn sysexit_sigreturn(
    process: RemoteProcess,
    info: ptrace_syscall_info,
    result: SigreturnResult,
) -> Result<(), Errno> {
    let is_realtime = result.is_realtime;
    let args = result.args;
    let ip_entry = result.ip;
    let sp_entry = result.sp;
    let ip_entry_mem = result.ip_mem;
    let sp_entry_mem = result.sp_mem;

    let mut error: Option<&'static str> = None;

    // SAFETY: Check if stack pointer is invalid.
    if info.stack_pointer < *MMAP_MIN_ADDR || info.instruction_pointer < *MMAP_MIN_ADDR {
        error = Some("stack smashing detected!");
    }

    let mut ip_mem = [0u8; 64];
    let mut ip_read = false;

    // SAFETY: Check for a syscall instruction at memory pointed by ip.
    if error.is_some() {
        // SAFETY: We validate the PidFd after memory read.
        match unsafe { process.read_mem(&mut ip_mem, info.instruction_pointer) } {
            Ok(_) if !process.is_alive() => return Err(Errno::ESRCH),
            Ok(_) => ip_read = true,
            Err(Errno::ESRCH) => return Err(Errno::ESRCH),
            Err(_) => {
                // SAFETY: Process is alive, but
                // we cannot read memory: Terminate!
                let _ = process.pidfd_kill(libc::SIGKILL);
                return Err(Errno::ESRCH);
            }
        }
    }

    let sys_instr = scmp_syscall_instruction(info.arch);
    let sys_instr_len = sys_instr.len();
    if sys_instr_len == 0 {
        // SAFETY: Unsupported architecture, continue process.
        return Ok(());
    }

    if error.is_none() && is_equal(&sys_instr[..sys_instr_len], &ip_mem[..sys_instr_len]) {
        error = Some("SROP detected!");
    }

    let error = if let Some(error) = error {
        error
    } else {
        // SAFETY: No SROP detected, continue process.
        return Ok(());
    };

    let mut sp_mem = [0u8; 64];
    let mut sp_read = false;

    if info.stack_pointer >= *MMAP_MIN_ADDR {
        #[allow(clippy::arithmetic_side_effects)]
        // SAFETY: No validation, data is used for logging only.
        match unsafe { process.read_mem(&mut sp_mem, (info.stack_pointer & !0xF) - 16) } {
            Ok(_) => sp_read = true,
            Err(Errno::ESRCH) => {}
            Err(_) => {
                // SAFETY: Process is alive, but
                // we cannot read memory: Terminate!
                let _ = process.pidfd_kill(libc::SIGKILL);
                return Err(Errno::ESRCH);
            }
        }
    }

    // Read memory maps for logging.
    let memmap = proc_maps(process.pid).ok();

    // SAFETY: SROP detected, terminate process!
    let _ = process.pidfd_kill(libc::SIGKILL);

    // SAFETY: We have checked for supported arch before this point.
    #[allow(clippy::disallowed_methods)]
    let arch = scmp_arch(info.arch).unwrap();

    let ip_asm = if ip_read {
        disasm(&ip_mem, arch, info.instruction_pointer, true, false)
            .map(|instructions| {
                instructions
                    .into_iter()
                    .map(|instruction| instruction.op)
                    .collect::<Vec<_>>()
            })
            .ok()
    } else {
        None
    };

    let ip_entry_asm = if let Some(ip_entry_mem) = ip_entry_mem {
        disasm(&ip_entry_mem, arch, ip_entry, true, false)
            .map(|instructions| {
                instructions
                    .into_iter()
                    .map(|instruction| instruction.op)
                    .collect::<Vec<_>>()
            })
            .ok()
    } else {
        None
    };

    let ip_mem = if ip_read {
        Some(ip_mem.to_lower_hex_string())
    } else {
        None
    };

    let sp_mem = if sp_read {
        Some(sp_mem.to_lower_hex_string())
    } else {
        None
    };

    let ip_entry_mem = ip_entry_mem.map(|ip_entry_mem| ip_entry_mem.to_lower_hex_string());
    let sp_entry_mem = sp_entry_mem.map(|sp_entry_mem| sp_entry_mem.to_lower_hex_string());

    #[allow(clippy::disallowed_methods)]
    let arch = SydArch(scmp_arch(info.arch).unwrap());
    error!("ctx": "sigreturn", "op": "check_SROP",
        "err": error,
        "act": Action::Kill,
        "pid": process.pid.as_raw(),
        "sys": if is_realtime { "rt_sigreturn" } else { "sigreturn" },
        "args": args,
        "arch": arch,
        "ret": scmp_sysret_instruction(info.arch).to_lower_hex_string(),
        "ip": info.instruction_pointer,
        "sp": info.stack_pointer,
        "ip_entry": ip_entry,
        "sp_entry": sp_entry,
        "ip_asm": ip_asm,
        "ip_entry_asm": ip_entry_asm,
        "ip_mem": ip_mem,
        "sp_mem": sp_mem,
        "ip_entry_mem": ip_entry_mem,
        "sp_entry_mem": sp_entry_mem,
        "memmap": memmap);

    Err(Errno::ESRCH)
}

// Note, chdir is a ptrace(2) hook, not a seccomp hook!
fn sysenter_chdir<'a>(
    process: &RemoteProcess,
    cache: &Arc<WorkerCache>,
    sandbox: &SandboxGuard,
    data: ptrace_syscall_info_seccomp,
) -> Result<CanonicalPath<'a>, Errno> {
    let mut arg = SysArg {
        path: Some(0),
        ..Default::default()
    };

    // SAFETY: Apply deny_dotdot as necessary for chdir.
    if sandbox.deny_dotdot() {
        arg.fsflags.insert(FsFlags::NO_RESOLVE_DOTDOT);
    }

    // Read remote path.
    let (path, _, _) =
        // SAFETY: PidFd is validated.
        unsafe { process.read_path(sandbox, data.args, arg, false, None) }?;
    if !process.is_alive() {
        return Err(Errno::ESRCH);
    }

    // Check for chroot, allow for the
    // common `cd /` use case.
    if sandbox.is_chroot() {
        return if path.abs().is_rootfs() {
            Ok(CanonicalPath::new_root())
        } else {
            Err(Errno::ENOENT)
        };
    }

    let mut caps = Capability::empty();
    if let Some(typ) = path.typ.as_ref() {
        if typ.is_dir() {
            caps.insert(Capability::CAP_CHDIR);
        }
    } else {
        return Err(Errno::ENOENT);
    }

    sandbox_path(
        None,
        cache,
        sandbox,
        process,
        path.abs(),
        caps,
        true,
        "chdir",
    )?;

    if !caps.contains(Capability::CAP_CHDIR) {
        // SAFETY: Return this after sandboxing
        // to honour hidden paths.
        return Err(Errno::ENOTDIR);
    }

    Ok(path)
}

#[allow(clippy::cognitive_complexity)]
fn sysexit_chdir(
    process: RemoteProcess,
    info: ptrace_syscall_info,
    path: CanonicalPath,
) -> Result<(), Errno> {
    // Check for successful sigaction exit.
    match ptrace_get_error(process.pid, info.arch) {
        Ok(None) => {
            // Successful chdir call, validate CWD magiclink.
        }
        Ok(Some(_)) => {
            // Unsuccessful chdir call, continue process.
            return Ok(());
        }
        Err(_) => {
            // SAFETY: Failed to get return value,
            // terminate the process.
            let _ = process.pidfd_kill(libc::SIGKILL);
            return Err(Errno::ESRCH);
        }
    };

    // SAFETY: Validate /proc/$pid/cwd against TOCTTOU!
    let mut pfd = XPathBuf::from_pid(process.pid);
    pfd.push(b"cwd");

    let mut mask = STATX_INO;
    mask |= if *HAVE_STATX_MNT_ID_UNIQUE {
        STATX_MNT_ID_UNIQUE
    } else {
        STATX_MNT_ID
    };

    #[allow(clippy::disallowed_methods)]
    let fd = path.dir.as_ref().unwrap();

    let stx_fd = match fstatx(fd, mask) {
        Ok(stx) => stx,
        Err(errno) => {
            // SAFETY: Failed to stat FD,
            // assume TOCTTOU: terminate the process.
            error!("ctx": "chdir", "op": "fstat_dir_fd",
                "err": format!("failed to fstat dir-fd for `{path}': {errno}"),
                "pid": process.pid.as_raw(),
                "path": &path,
                "errno": errno as i32);
            let _ = process.pidfd_kill(libc::SIGKILL);
            return Err(Errno::ESRCH);
        }
    };

    let stx_cwd = match statx(Some(&PROC_FD()), &pfd, 0, mask) {
        Ok(stx) => stx,
        Err(errno) => {
            // SAFETY: Failed to stat CWD,
            // assume TOCTTOU: terminate the process.
            error!("ctx": "chdir", "op": "stat_cwd_symlink",
                "err": format!("failed to stat cwd-symlink for `{path}': {errno}"),
                "pid": process.pid.as_raw(),
                "path": &path,
                "errno": errno as i32);
            let _ = process.pidfd_kill(libc::SIGKILL);
            return Err(Errno::ESRCH);
        }
    };

    // SAFETY: Validate CWD stat information.
    let mut is_match = true;

    // Step 1: Check inodes.
    if stx_fd.stx_ino != stx_cwd.stx_ino {
        is_match = false;
    }

    // Step 2: Compare mount ids.
    if stx_fd.stx_mnt_id != stx_cwd.stx_mnt_id {
        is_match = false;
    }

    if !is_match {
        // SAFETY: CWD changed, which indicates
        // successful TOCTTOU attempt: terminate the process.
        let cwd = readlinkat(Some(&PROC_FILE()), &pfd)
            .ok()
            .unwrap_or_else(|| XPathBuf::from("?"));
        error!("ctx": "chdir", "op": "dir_mismatch",
            "err": format!("dir mismatch detected for directory `{path}' -> `{cwd}': assume TOCTTOU!"),
            "pid": process.pid.as_raw(),
            "path": &path,
            "real": cwd,
            "cwd_mount_id": stx_cwd.stx_mnt_id,
            "dir_mount_id": stx_fd.stx_mnt_id,
            "cwd_inode": stx_cwd.stx_ino,
            "dir_inode": stx_fd.stx_ino);
        let _ = process.pidfd_kill(libc::SIGKILL);
        return Err(Errno::ESRCH);
    } else {
        debug!("ctx": "chdir", "op": "verify_chdir",
            "msg": format!("dir change to `{path}' approved"),
            "pid": process.pid.as_raw(),
            "path": &path,
            "cwd_mount_id": stx_cwd.stx_mnt_id,
            "dir_mount_id": stx_fd.stx_mnt_id,
            "cwd_inode": stx_cwd.stx_ino,
            "dir_inode": stx_fd.stx_ino);
    }

    // Continue process.
    Ok(())
}

fn sys_chroot(request: UNotifyEventRequest) -> ScmpNotifResp {
    let argv = &[SysArg {
        path: Some(0),
        ..Default::default()
    }];

    syscall_path_handler(
        request,
        "chroot",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read lock.

            // SAFETY: SysArg has one element.
            #[allow(clippy::disallowed_methods)]
            let path = path_args.0.as_ref().unwrap();

            if path.abs().is_rootfs() {
                // chroot("/") is a no-op.
                return Ok(request.return_syscall(0));
            } else if let Some(typ) = path.typ.as_ref() {
                if !typ.is_dir() {
                    return Ok(request.fail_syscall(Errno::ENOTDIR));
                }
            } else {
                return Ok(request.fail_syscall(Errno::ENOENT));
            }

            // Acquire a write lock and chroot the sandbox.
            let mut sandbox = request.get_mut_sandbox();
            sandbox.chroot();
            drop(sandbox); // release the write-lock.

            Ok(request.return_syscall(0))
        },
    )
}

fn sys_chdir(request: UNotifyEventRequest) -> ScmpNotifResp {
    let argv = &[SysArg {
        path: Some(0),
        flags: SysFlags::UNSAFE_CONT,
        ..Default::default()
    }];

    syscall_path_handler(
        request,
        "chdir",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            // SAFETY: SysArg has one element.
            #[allow(clippy::disallowed_methods)]
            if let Some(typ) = path_args.0.as_ref().unwrap().typ.as_ref() {
                if !typ.is_dir() {
                    return Ok(request.fail_syscall(Errno::ENOTDIR));
                }
            } else {
                return Ok(request.fail_syscall(Errno::ENOENT));
            }

            // SAFETY: This is vulnerable to TOCTTOU.
            // We only use this hook with trace/allow_unsafe_ptrace:1
            // hence the user is aware of the consequences.
            Ok(unsafe { request.continue_syscall() })
        },
    )
}

fn sys_fchdir(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: fchdir is fd-only, so UNSAFE_CONT is ok.
    let argv = &[SysArg {
        dirfd: Some(0),
        flags: SysFlags::UNSAFE_CONT,
        ..Default::default()
    }];

    syscall_path_handler(
        request,
        "fchdir",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            // SAFETY: SysArg has one element.
            #[allow(clippy::disallowed_methods)]
            if let Some(typ) = path_args.0.as_ref().unwrap().typ.as_ref() {
                if !typ.is_dir() {
                    return Ok(request.fail_syscall(Errno::ENOTDIR));
                }
            } else {
                return Ok(request.fail_syscall(Errno::ENOENT));
            }

            // SAFETY: fchdir is fd-only.
            Ok(unsafe { request.continue_syscall() })
        },
    )
}

#[allow(clippy::cognitive_complexity)]
fn sys_ioctl(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: Deny if the ioctl request is denylisted.
    let req = request.scmpreq;
    let arg = req.data.args[1];

    let sandbox = request.get_sandbox();

    if let Some(deny) = sandbox.has_ioctl(&arg) {
        return if deny {
            // Request is denylisted.
            let cap = Capability::CAP_IOCTL;
            let action = sandbox.default_action(cap);
            let filter = action == Action::Filter;

            if !filter && action >= Action::Warn && log_enabled!(LogLevel::Warn) {
                let grp = cap.to_string().to_ascii_lowercase();
                if sandbox.verbose {
                    warn!("ctx": "access", "cap": cap, "act": action,
                        "sys": "ioctl", "ioctl": arg,
                        "tip": format!("configure `{grp}/allow+{arg:#x}'"),
                        "req": &request);
                } else {
                    warn!("ctx": "access", "cap": cap, "act": action,
                        "sys": "ioctl", "ioctl": arg,
                        "tip": format!("configure `{grp}/allow+{arg:#x}'"),
                        "pid": request.scmpreq.pid);
                }
            }

            match action {
                Action::Allow | Action::Warn => {
                    // SAFETY: ioctl is fd-only.
                    unsafe { request.continue_syscall() }
                }
                Action::Filter | Action::Deny => request.fail_syscall(Errno::EACCES),
                Action::Panic => panic!(),
                Action::Exit => std::process::exit(libc::EACCES),
                action => {
                    // Stop|Kill
                    let _ = request.kill(action);
                    request.fail_syscall(Errno::EACCES)
                }
            }
        } else {
            // Request is allowlisted.
            // SAFETY: ioctl is fd-only.
            unsafe { request.continue_syscall() }
        };
    }
    drop(sandbox); // release the read-lock.

    // SAFETY: ioctl is fd-only, so UNSAFE_CONT is ok.
    let argv = &[SysArg {
        dirfd: Some(0),
        flags: SysFlags::UNSAFE_CONT,
        ..Default::default()
    }];

    syscall_path_handler(request, "ioctl", argv, |_, request, sandbox| {
        drop(sandbox); // release the read-lock.

        // SAFETY: ioctl is fd-only.
        Ok(unsafe { request.continue_syscall() })
    })
}

#[allow(clippy::cognitive_complexity)]
fn sys_sigaction(request: UNotifyEventRequest) -> ScmpNotifResp {
    // Check if the handler is a restarting one.
    // This allows us to selectively unblock system calls.

    let req = request.scmpreq;

    // SAFETY: Ensure signal number is a valid signal.
    // We deliberately include reserved signals here.
    let sig_num: libc::c_int = match req.data.args[0].try_into() {
        Ok(libc::SIGKILL | libc::SIGSTOP) => return request.fail_syscall(Errno::EINVAL),
        Ok(sig_num) if sig_num < 1 || sig_num >= libc::SIGRTMAX() => {
            return request.fail_syscall(Errno::EINVAL)
        }
        Ok(sig_num) => sig_num,
        Err(_) => return request.fail_syscall(Errno::EINVAL),
    };

    // SAFETY: We do not hook into sigaction
    // when the first argument is NULL.
    let addr = req.data.args[1];
    assert_ne!(addr, 0);

    let sa_flags = match request.read_sa_flags(addr) {
        Ok(sa_flags) => sa_flags,
        Err(errno) => return request.fail_syscall(errno),
    };

    // SAFETY: Signal handlers are per-process not per-thread!
    let tgid = match proc_tgid(request.scmpreq.pid()) {
        Ok(tgid) => tgid,
        Err(errno) => return request.fail_syscall(errno),
    };

    let _is_restart = if sa_flags.contains(SaFlags::SA_RESTART) {
        if let Err(errno) = request.cache.add_sig_restart(tgid, sig_num) {
            return request.fail_syscall(errno);
        }
        true
    } else {
        request.cache.del_sig_restart(tgid, sig_num);
        false
    };

    /*
    if log_enabled!(LogLevel::Debug) {
        let sandbox = request.get_sandbox();
        let verbose = sandbox.verbose;
        drop(sandbox); // release the read-lock.

        if verbose {
            debug!("ctx": "sigaction", "op": "add_handler",
                "msg": format!("added {}restarting handler for signal {sig_num}",
                    if is_restart { "" } else { "non " }),
                "sig": sig_num, "flags": format!("{sa_flags:?}"),
                "pid": tgid.as_raw(), "tid": req.pid,
                "req": &request);
        } else {
            debug!("ctx": "sigaction", "op": "add_handler",
                "msg": format!("added {}restarting handler for signal {sig_num}",
                    if is_restart { "" } else { "non " }),
                "sig": sig_num, "flags": format!("{sa_flags:?}"),
                "pid": tgid.as_raw(), "tid": req.pid);
        }
    }
    */

    // Let the syscall continue.
    // SAFETY: There's nothing we can do if the system call fails,
    // or if an attacker changes the sa_flags element of `struct sigaction`.
    // but we did our best by validating all the things we can.
    unsafe { request.continue_syscall() }
}

#[allow(clippy::cognitive_complexity)]
fn sys_prctl(request: UNotifyEventRequest) -> ScmpNotifResp {
    // Note, we only hook into the PR_SET_NAME request.
    let req = request.scmpreq;
    let ptr = req.data.args[1];
    if ptr == 0 {
        return request.fail_syscall(Errno::EFAULT);
    }

    // Check if logging is enabled.
    if !log_enabled!(LogLevel::Warn) {
        return request.return_syscall(0);
    }

    // `!proc/name` is a dummy path we use
    // to disable logging, use e.g.
    // `filter/read+!proc/name'.
    let sandbox = request.get_sandbox();
    let verbose = sandbox.verbose;
    if sandbox.filter_path(Capability::CAP_READ, XPath::from_bytes(b"!proc/name")) {
        return request.return_syscall(0);
    }
    drop(sandbox); // release the read-lock.

    let mut buf = [0u8; 15];
    let name = match request.read_mem(&mut buf, ptr) {
        Ok(len) => {
            let nil = memchr(0, &buf[..len]).unwrap_or(len);
            &buf[..nil]
        }
        Err(err) => return request.fail_syscall(err),
    };

    // See if this is a request for change,
    // silently deny if no change was attempted.
    match proc_comm(req.pid()) {
        Ok(comm) if comm.is_equal(name) => {}
        Ok(comm) => {
            let (name, hex) = log_untrusted_buf(name);
            if verbose {
                warn!("ctx": "change_process_name",
                    "msg": format!("attempt to change process name from `{comm}' to `{name}' prevented"),
                    "tip": "use filter/read+!proc/name to silence, trace/allow_unsafe_prctl:1 to allow",
                    "sys": request.syscall, "name": name, "hex": hex, "comm": comm, "pid": req.pid,
                    "req": &request);
            } else {
                warn!("ctx": "change_process_name",
                    "msg": format!("attempt to change process name from `{comm}' to `{name}' prevented"),
                    "tip": "use filter/read+!proc/name to silence, trace/allow_unsafe_prctl:1 to allow",
                    "sys": request.syscall, "name": name, "hex": hex, "comm": comm, "pid": req.pid,
                    "pid": request.scmpreq.pid);
            }
        }
        Err(_) => {
            let (name, hex) = log_untrusted_buf(name);
            if verbose {
                warn!("ctx": "change_process_name",
                    "msg": format!("attempt to change process name to `{name}' prevented"),
                    "tip": "use filter/read+!proc/name to silence, trace/allow_unsafe_prctl:1 to allow",
                    "sys": request.syscall, "name": name, "hex": hex, "pid": req.pid,
                    "req": &request);
            } else {
                warn!("ctx": "change_process_name",
                    "msg": format!("attempt to change process name to `{name}' prevented"),
                    "tip": "use filter/read+!proc/name to silence, trace/allow_unsafe_prctl:1 to allow",
                    "sys": request.syscall, "name": name, "hex": hex, "pid": req.pid);
            }
        }
    }

    request.return_syscall(0)
}

fn sys_fcntl(request: UNotifyEventRequest) -> ScmpNotifResp {
    // Note, we only hook into F_SETFL requests
    // which do not have O_APPEND set!
    let req = request.scmpreq;
    let fd = if let Ok(fd) = RawFd::try_from(req.data.args[0]) {
        fd
    } else {
        return request.fail_syscall(Errno::EBADF);
    };

    let mut pfd = XPathBuf::from_pid(req.pid());
    pfd.push(b"fd");
    pfd.push_fd(fd);
    let path = match readlinkat(Some(&PROC_FILE()), &pfd) {
        Ok(path) => {
            if !request.is_valid() {
                return request.fail_syscall(Errno::ESRCH);
            }
            path
        }
        Err(_) => return request.fail_syscall(Errno::EBADF),
    };

    let sandbox = request.get_sandbox();
    let is_crypt = sandbox.enabled(Capability::CAP_CRYPT);
    let is_append = request.cache.is_append(&sandbox, &path);
    drop(sandbox);
    if is_append {
        // Deny silently.
        return request.return_syscall(0);
    }

    if is_crypt {
        let fd = if let Ok(fd) = request.get_fd(fd) {
            fd
        } else {
            return request.fail_syscall(Errno::EBADF);
        };
        if let Ok(inode) = fstatx(&fd, STATX_INO).map(|s| s.stx_ino) {
            #[allow(clippy::disallowed_methods)]
            let files = request.crypt_map.as_ref().unwrap();
            for map in files
                .read()
                .unwrap_or_else(|err| err.into_inner())
                .0
                .values()
            {
                if inode == map.4 {
                    // Deny with EACCES, caller should know.
                    return request.fail_syscall(Errno::EACCES);
                }
            }
        }
    }

    // SAFETY: fcntl is fd-only.
    // No pointer dereference in access check.
    unsafe { request.continue_syscall() }
}

#[allow(clippy::cognitive_complexity)]
fn sys_getdents64(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        let req = request.scmpreq;

        if req.data.args[1] == 0 {
            // SAFETY: If the second argument which must hold a pointer to a
            // linux_dirent structure is NULL, we must return EFAULT
            // without further processing here.
            return Err(Errno::EFAULT);
        } else if req.data.args[2] == 0 {
            // SAFETY:Result buffer is too small
            return Err(Errno::EINVAL);
        }

        // Initial getdents call has Readdir capability,
        // but each file gets listed gets checked for Stat.
        let mut sandbox = request.get_sandbox();
        let hide = sandbox.enabled(Capability::CAP_STAT);
        let safe_name = !sandbox.allow_unsafe_filename();

        // Get remote fd and readlink /proc/self/fd/$fd.
        let fd = request.get_fd(req.data.args[0] as RawFd)?;
        let mut pfd = XPathBuf::from("self/fd");
        pfd.push_fd(fd.as_raw_fd());
        let mut dir = match readlinkat(Some(&PROC_FILE()), &pfd) {
            Ok(dir) => {
                if dir.is_relative() {
                    // /proc/1/fd/0 -> pipe:42
                    return Err(Errno::EBADF);
                } else {
                    // Unused when request.is_some()
                    let process = RemoteProcess::new(request.scmpreq.pid());

                    // genuine dir, check for readdir access.
                    if file_type(&fd, None, false)?.is_dir() {
                        sandbox_path(
                            Some(&request),
                            &request.cache,
                            &sandbox,
                            &process,
                            &dir,
                            Capability::CAP_READDIR,
                            false,
                            "getdents64",
                        )?;
                    } else {
                        // FD-only call, hiding is not necessary.
                        return Err(Errno::ENOTDIR);
                    }

                    dir
                }
            }
            Err(_) => return Err(Errno::ENOENT),
        };

        // SAFETY: The count argument to the getdents call
        // must not be fully trusted, it can be overly large,
        // and allocating a Vector of that capacity may overflow.
        // This bug was discovered by trinity in this build:
        // https://builds.sr.ht/~alip/job/1077263
        let count = usize::try_from(req.data.args[2])
            .or(Err(Errno::EINVAL))?
            .min(1000000);
        let pid = req.pid();
        let len = dir.len();
        let mut dot: u8 = 0;
        let mut ret: u64 = 0;
        while ret == 0 {
            // Release the read-lock before emulation.
            drop(sandbox);

            let mut entries = match getdents64(&fd, count) {
                Ok(entries) => entries,
                Err(Errno::UnknownErrno) => break,
                Err(errno) => return Err(errno),
            };

            // Re-acquire the read-lock for access check.
            sandbox = request.get_sandbox();

            #[allow(clippy::arithmetic_side_effects)]
            for entry in &mut entries {
                if dot < 2 && entry.is_dot() {
                    // SAFETY: Allow the special dot entries `.` and `..`.
                    // Note, `..` may point to a denylisted directory,
                    // however at this point there's not much we can do:
                    // even the root directory, ie `/`, has a `..`. In
                    // this exceptional case `..` points to `.`.
                    dot += 1;
                } else {
                    // Append entry name to the directory.
                    dir.push(entry.name_bytes());

                    // SAFETY: Run XPath::check() with file type for global restrictions.
                    if dir
                        .check(
                            pid,
                            Some(&entry.file_type()),
                            Some(entry.as_xpath()),
                            safe_name,
                        )
                        .is_err()
                    {
                        // skip entry.
                        dir.truncate(len);
                        continue;
                    }

                    // Unused when request.is_some()
                    let process = RemoteProcess::new(request.scmpreq.pid());

                    // SAFETY: Run sandbox access check with stat capability.
                    let err = sandbox_path(
                        Some(&request),
                        &request.cache,
                        &sandbox,
                        &process,
                        &dir,
                        Capability::CAP_STAT,
                        hide,
                        "stat",
                    )
                    .is_err();
                    dir.truncate(len);
                    if err {
                        // skip entry.
                        continue;
                    }
                }

                // Access granted, write entry to sandbox process memory.
                match request.write_mem(entry.as_bytes(), req.data.args[1] + ret) {
                    Ok(n) => {
                        ret += n as u64;
                        if n != entry.size() {
                            break;
                        }
                    }
                    Err(_) if ret > 0 => break,
                    Err(errno) => return Err(errno),
                };
            }
        }

        #[allow(clippy::cast_possible_wrap)]
        Ok(request.return_syscall(ret as i64))
    })
}

fn sys_access(request: UNotifyEventRequest) -> ScmpNotifResp {
    let argv = &[SysArg {
        path: Some(0),
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "access",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            let req = request.scmpreq;
            #[allow(clippy::cast_possible_truncation)]
            let mode = AccessFlags::from_bits_truncate(req.data.args[1] as libc::c_int);
            syscall_access_handler(request, path_args, mode)
        },
    )
}

fn sys_faccessat(request: UNotifyEventRequest) -> ScmpNotifResp {
    let argv = &[SysArg {
        dirfd: Some(0),
        path: Some(1),
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "faccessat",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            let req = request.scmpreq;
            #[allow(clippy::cast_possible_truncation)]
            let mode = AccessFlags::from_bits_truncate(req.data.args[2] as libc::c_int);
            syscall_access_handler(request, path_args, mode)
        },
    )
}

fn sys_faccessat2(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;
    #[allow(clippy::cast_possible_truncation)]
    let flags = AtFlags::from_bits_truncate(req.data.args[3] as libc::c_int);
    #[allow(clippy::cast_possible_truncation)]
    let mode = AccessFlags::from_bits_truncate(req.data.args[2] as libc::c_int);
    let fsflags = if flags.contains(AtFlags::AT_SYMLINK_NOFOLLOW) {
        FsFlags::NO_FOLLOW_LAST
    } else {
        FsFlags::empty()
    };
    let argv = &[SysArg {
        dirfd: Some(0),
        path: Some(1),
        flags: if flags.contains(AtFlags::AT_EMPTY_PATH) {
            SysFlags::EMPTY_PATH
        } else {
            SysFlags::empty()
        },
        fsflags,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "faccessat2",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.
            syscall_access_handler(request, path_args, mode)
        },
    )
}

fn sys_fchmod(request: UNotifyEventRequest) -> ScmpNotifResp {
    let argv = &[SysArg {
        dirfd: Some(0),
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "fchmod",
        argv,
        |path_args: PathArgs, request, sandbox| {
            // SAFETY:
            // 1. SysArg has one element.
            // 2. SysArg.path is None asserting dir is Some.
            #[allow(clippy::disallowed_methods)]
            let fd = path_args.0.as_ref().unwrap().dir.as_ref().unwrap();

            let req = request.scmpreq;
            #[allow(clippy::cast_possible_truncation)]
            let mut mode = Mode::from_bits_truncate(req.data.args[1] as libc::mode_t);

            // SAFETY: We apply force_umask to chmod modes to ensure consistency.
            let umask = sandbox.umask.unwrap_or(Mode::empty());
            mode &= !umask;

            fchmod(fd.as_raw_fd(), mode).map(|_| request.return_syscall(0))
        },
    )
}

fn sys_chmod(request: UNotifyEventRequest) -> ScmpNotifResp {
    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH,
        ..Default::default()
    }];

    syscall_path_handler(
        request,
        "chmod",
        argv,
        |path_args: PathArgs, request, sandbox| {
            let req = request.scmpreq;
            #[allow(clippy::cast_possible_truncation)]
            let mode = Mode::from_bits_truncate(req.data.args[1] as libc::mode_t);
            syscall_chmod_handler(request, &sandbox, path_args, mode)
        },
    )
}

fn sys_fchmodat(request: UNotifyEventRequest) -> ScmpNotifResp {
    // Note: Unlike fchmodat2, fchmodat always resolves symbolic links.
    let argv = &[SysArg {
        dirfd: Some(0),
        path: Some(1),
        fsflags: FsFlags::MUST_PATH,
        ..Default::default()
    }];

    syscall_path_handler(
        request,
        "fchmodat",
        argv,
        |path_args: PathArgs, request, sandbox| {
            let req = request.scmpreq;
            #[allow(clippy::cast_possible_truncation)]
            let mode = Mode::from_bits_truncate(req.data.args[2] as libc::mode_t);
            syscall_chmod_handler(request, &sandbox, path_args, mode)
        },
    )
}

fn sys_fchmodat2(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    let mut fsflags = FsFlags::MUST_PATH;
    if req.data.args[3] & libc::AT_SYMLINK_NOFOLLOW as u64 != 0 {
        fsflags |= FsFlags::NO_FOLLOW_LAST
    }

    let argv = &[SysArg {
        dirfd: Some(0),
        path: Some(1),
        fsflags,
        ..Default::default()
    }];

    #[allow(clippy::cast_possible_truncation)]
    let mode = Mode::from_bits_truncate(req.data.args[2] as libc::mode_t);

    syscall_path_handler(
        request,
        "fchmodat2",
        argv,
        |path_args: PathArgs, request, sandbox| {
            syscall_chmod_handler(request, &sandbox, path_args, mode)
        },
    )
}

fn sys_fchown(request: UNotifyEventRequest) -> ScmpNotifResp {
    let argv = &[SysArg {
        dirfd: Some(0),
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "fchown",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            // SAFETY:
            // 1. SysArg has one element.
            // 2. SysArg.path is None asserting dir is Some.
            #[allow(clippy::disallowed_methods)]
            let fd = path_args.0.as_ref().unwrap().dir.as_ref().unwrap();

            let req = request.scmpreq;
            let owner = libc::uid_t::try_from(req.data.args[1])
                .map(Uid::from_raw)
                .ok();
            let group = libc::gid_t::try_from(req.data.args[2])
                .map(Gid::from_raw)
                .ok();
            if owner.is_none() && group.is_none() {
                // Nothing to change.
                return Ok(request.return_syscall(0));
            }

            fchown(fd.as_raw_fd(), owner, group).map(|_| request.return_syscall(0))
        },
    )
}

fn sys_chown(request: UNotifyEventRequest) -> ScmpNotifResp {
    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "chown",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            let req = request.scmpreq;
            let owner = libc::uid_t::try_from(req.data.args[1])
                .map(Uid::from_raw)
                .ok();
            let group = libc::gid_t::try_from(req.data.args[2])
                .map(Gid::from_raw)
                .ok();
            syscall_chown_handler(request, path_args, owner, group)
        },
    )
}

fn sys_lchown(request: UNotifyEventRequest) -> ScmpNotifResp {
    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::NO_FOLLOW_LAST,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "lchown",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            let req = request.scmpreq;
            let owner = libc::uid_t::try_from(req.data.args[1])
                .map(Uid::from_raw)
                .ok();
            let group = libc::gid_t::try_from(req.data.args[2])
                .map(Gid::from_raw)
                .ok();
            syscall_chown_handler(request, path_args, owner, group)
        },
    )
}

fn sys_fchownat(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    let mut fsflags = FsFlags::MUST_PATH;
    if req.data.args[4] & libc::AT_SYMLINK_NOFOLLOW as u64 != 0 {
        fsflags |= FsFlags::NO_FOLLOW_LAST;
    }

    let empty = req.data.args[4] & libc::AT_EMPTY_PATH as u64 != 0;
    let mut flags = SysFlags::empty();
    if empty {
        flags |= SysFlags::EMPTY_PATH;
    }

    let argv = &[SysArg {
        dirfd: Some(0),
        path: Some(1),
        flags,
        fsflags,
        ..Default::default()
    }];

    syscall_path_handler(
        request,
        "fchownat",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            let owner = libc::uid_t::try_from(req.data.args[2])
                .map(Uid::from_raw)
                .ok();
            let group = libc::gid_t::try_from(req.data.args[3])
                .map(Gid::from_raw)
                .ok();
            syscall_chown_handler(request, path_args, owner, group)
        },
    )
}

fn sys_link(request: UNotifyEventRequest) -> ScmpNotifResp {
    let argv = &[
        SysArg {
            path: Some(0),
            fsflags: FsFlags::MUST_PATH | FsFlags::NO_FOLLOW_LAST | FsFlags::WANT_BASE,
            ..Default::default()
        },
        SysArg {
            path: Some(1),
            dotlast: Some(Errno::ENOENT),
            fsflags: FsFlags::MISS_LAST | FsFlags::NO_FOLLOW_LAST,
            ..Default::default()
        },
    ];

    syscall_path_handler(
        request,
        "link",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            syscall_link_handler(request, path_args)
        },
    )
}

fn sys_linkat(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    #[allow(clippy::cast_possible_truncation)]
    let flags = req.data.args[4] as libc::c_int;

    let empty = flags & libc::AT_EMPTY_PATH != 0;

    let mut fsflags = FsFlags::MUST_PATH;
    if flags & libc::AT_SYMLINK_FOLLOW == 0 {
        fsflags |= FsFlags::NO_FOLLOW_LAST;
    }

    let mut flags = SysFlags::empty();
    if empty {
        flags |= SysFlags::EMPTY_PATH;
    } else {
        fsflags |= FsFlags::WANT_BASE;
    }

    let argv = &[
        SysArg {
            dirfd: Some(0),
            path: Some(1),
            flags,
            fsflags,
            ..Default::default()
        },
        SysArg {
            dirfd: Some(2),
            path: Some(3),
            dotlast: Some(Errno::ENOENT),
            fsflags: FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            ..Default::default()
        },
    ];

    syscall_path_handler(
        request,
        "linkat",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            syscall_link_handler(request, path_args)
        },
    )
}

fn sys_symlink(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        // SAFETY: No checking of the target is done.
        // This is consistent with the system call.
        let arg = SysArg {
            path: Some(1),
            dotlast: Some(Errno::EINVAL),
            fsflags: FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            ..Default::default()
        };
        syscall_symlink_handler(request, arg)
    })
}

fn sys_symlinkat(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        // SAFETY: No checking of the target is done.
        // This is consistent with the system call.
        let arg = SysArg {
            dirfd: Some(1),
            path: Some(2),
            dotlast: Some(Errno::EINVAL),
            fsflags: FsFlags::NO_FOLLOW_LAST | FsFlags::MISS_LAST,
            ..Default::default()
        };
        syscall_symlink_handler(request, arg)
    })
}

fn sys_unlink(request: UNotifyEventRequest) -> ScmpNotifResp {
    // unlink() does not work on fds!
    // Hence, we have to use WANT_BASE to split base.
    let argv = &[SysArg {
        path: Some(0),
        dotlast: Some(Errno::EINVAL),
        fsflags: FsFlags::NO_FOLLOW_LAST | FsFlags::MUST_PATH | FsFlags::WANT_BASE,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "unlink",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            // SAFETY: SysArg has one element.
            #[allow(clippy::disallowed_methods)]
            let path = path_args.0.as_ref().unwrap();

            unlinkat(
                path.dir.as_ref().map(|fd| fd.as_raw_fd()),
                path.base,
                UnlinkatFlags::NoRemoveDir,
            )
            .map(|_| request.return_syscall(0))
        },
    )
}

fn sys_unlinkat(request: UNotifyEventRequest) -> ScmpNotifResp {
    // unlinkat() does not work on fds!
    // Hence, we have to use WANT_BASE to split base.
    let argv = &[SysArg {
        dirfd: Some(0),
        path: Some(1),
        dotlast: Some(Errno::EINVAL),
        fsflags: FsFlags::NO_FOLLOW_LAST | FsFlags::MUST_PATH | FsFlags::WANT_BASE,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "unlinkat",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            // SAFETY: SysArg has one element.
            #[allow(clippy::disallowed_methods)]
            let path = path_args.0.as_ref().unwrap();

            let req = request.scmpreq;
            #[allow(clippy::cast_possible_truncation)]
            let flags = if req.data.args[2] as libc::c_int & libc::AT_REMOVEDIR != 0 {
                UnlinkatFlags::RemoveDir
            } else {
                UnlinkatFlags::NoRemoveDir
            };

            unlinkat(path.dir.as_ref().map(|fd| fd.as_raw_fd()), path.base, flags)
                .map(|_| request.return_syscall(0))
        },
    )
}

fn sys_mkdir(request: UNotifyEventRequest) -> ScmpNotifResp {
    // We want NO_FOLLOW_LAST because creating an entry
    // through a dangling symbolic link should return EEXIST!
    let req = request.scmpreq;
    #[allow(clippy::cast_possible_truncation)]
    let mode = Mode::from_bits_truncate(req.data.args[1] as libc::mode_t);
    let argv = &[SysArg {
        path: Some(0),
        dotlast: Some(Errno::ENOENT),
        fsflags: FsFlags::MISS_LAST | FsFlags::NO_FOLLOW_LAST,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "mkdir",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            syscall_mkdir_handler(request, path_args, mode)
        },
    )
}

fn sys_rmdir(request: UNotifyEventRequest) -> ScmpNotifResp {
    // rmdir() does not work on fds!
    // Hence, we have to use WANT_BASE to split base.
    let argv = &[SysArg {
        path: Some(0),
        dotlast: Some(Errno::EINVAL),
        fsflags: FsFlags::MUST_PATH | FsFlags::WANT_BASE,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "rmdir",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            // SAFETY: SysArg has one element.
            #[allow(clippy::disallowed_methods)]
            let path = path_args.0.as_ref().unwrap();

            unlinkat(
                path.dir.as_ref().map(|fd| fd.as_raw_fd()),
                path.base,
                UnlinkatFlags::RemoveDir,
            )
            .map(|_| request.return_syscall(0))
        },
    )
}

fn sys_mkdirat(request: UNotifyEventRequest) -> ScmpNotifResp {
    // We want NO_FOLLOW_LAST because creating an entry
    // through a dangling symbolic link should return EEXIST!
    let req = request.scmpreq;
    #[allow(clippy::cast_possible_truncation)]
    let mode = Mode::from_bits_truncate(req.data.args[2] as libc::mode_t);
    let argv = &[SysArg {
        dirfd: Some(0),
        path: Some(1),
        dotlast: Some(Errno::ENOENT),
        fsflags: FsFlags::MISS_LAST | FsFlags::NO_FOLLOW_LAST,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "mkdirat",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            syscall_mkdir_handler(request, path_args, mode)
        },
    )
}

fn sys_mknod(request: UNotifyEventRequest) -> ScmpNotifResp {
    // We want NO_FOLLOW_LAST because creating an entry
    // through a dangling symbolic link should return EEXIST!
    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MISS_LAST | FsFlags::NO_FOLLOW_LAST,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "mknod",
        argv,
        |path_args: PathArgs, request, sandbox| {
            let req = request.scmpreq;
            #[allow(clippy::cast_possible_truncation)]
            let dev = req.data.args[2] as libc::dev_t;
            // Careful here, zero file type if equivalent to S_IFREG.
            #[allow(clippy::cast_possible_truncation)]
            let kind = req.data.args[1] as libc::mode_t & SFlag::S_IFMT.bits();
            let kind = if kind != 0 {
                SFlag::from_bits_truncate(kind)
            } else {
                SFlag::S_IFREG
            };
            #[allow(clippy::cast_possible_truncation)]
            let perm =
                Mode::from_bits_truncate(req.data.args[1] as libc::mode_t & !SFlag::S_IFMT.bits());

            syscall_mknod_handler(request, path_args, kind, perm, dev, sandbox.umask)
        },
    )
}

fn sys_mknodat(request: UNotifyEventRequest) -> ScmpNotifResp {
    // We want NO_FOLLOW_LAST because creating an entry
    // through a dangling symbolic link should return EEXIST!
    let argv = &[SysArg {
        dirfd: Some(0),
        path: Some(1),
        fsflags: FsFlags::MISS_LAST | FsFlags::NO_FOLLOW_LAST,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "mknodat",
        argv,
        |path_args: PathArgs, request, sandbox| {
            let req = request.scmpreq;
            #[allow(clippy::cast_possible_truncation)]
            let dev = req.data.args[3] as libc::dev_t;
            // Careful here, zero file type if equivalent to S_IFREG.
            #[allow(clippy::cast_possible_truncation)]
            let kind = req.data.args[2] as libc::mode_t & SFlag::S_IFMT.bits();
            let kind = if kind != 0 {
                SFlag::from_bits_truncate(kind)
            } else {
                SFlag::S_IFREG
            };
            #[allow(clippy::cast_possible_truncation)]
            let perm =
                Mode::from_bits_truncate(req.data.args[2] as libc::mode_t & !SFlag::S_IFMT.bits());

            syscall_mknod_handler(request, path_args, kind, perm, dev, sandbox.umask)
        },
    )
}

fn sys_creat(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    // SAFETY:
    // 1. If path is NULL we must return EFAULT here w/o further
    //    processing.
    if req.data.args[0] == 0 {
        return request.fail_syscall(Errno::EFAULT);
    }

    // SAFETY:
    // 1. Omit MUST_PATH in fsflags as path may not exist yet.
    // 2. Use WANT_BASE to split base which will be opened by the handler.
    #[allow(clippy::cast_possible_truncation)]
    let mode = Mode::from_bits_truncate(req.data.args[1] as libc::mode_t);
    let arg = SysArg {
        path: Some(0),
        fsflags: FsFlags::WANT_BASE,
        ..Default::default()
    };
    let flags = OFlag::O_CREAT | OFlag::O_WRONLY | OFlag::O_TRUNC;

    syscall_open_handler(request, OpenSyscall::Creat, arg, flags, mode)
}

fn sys_open(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    // SAFETY:
    // 1. If path is NULL we must return EFAULT here w/o further
    //    processing.
    if req.data.args[0] == 0 {
        return request.fail_syscall(Errno::EFAULT);
    }

    #[allow(clippy::cast_possible_truncation)]
    let flags = OFlag::from_bits_truncate(req.data.args[1] as libc::c_int);
    #[allow(clippy::cast_possible_truncation)]
    let mode = Mode::from_bits_truncate(req.data.args[2] as libc::mode_t);
    let arg = SysArg::open(flags, false, ResolveFlag::empty());

    syscall_open_handler(request, OpenSyscall::Open, arg, flags, mode)
}

fn sys_openat(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    // SAFETY:
    // 1. If path is NULL we must return EFAULT here w/o further
    //    processing.
    // Note, using a bad directory is okay for absolute paths,
    // so we cannot validate the dirfd early here.
    if req.data.args[1] == 0 {
        return request.fail_syscall(Errno::EFAULT);
    }

    #[allow(clippy::cast_possible_truncation)]
    let flags = OFlag::from_bits_truncate(req.data.args[2] as libc::c_int);
    #[allow(clippy::cast_possible_truncation)]
    let mode = Mode::from_bits_truncate(req.data.args[3] as libc::mode_t);
    let arg = SysArg::open(flags, true, ResolveFlag::empty());

    syscall_open_handler(request, OpenSyscall::Openat, arg, flags, mode)
}

fn sys_openat2(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    // SAFETY:
    // 1. If path is NULL we must return EFAULT here w/o further
    //    processing.
    // Note, using a bad directory is okay for absolute paths,
    // so we cannot validate the dirfd early here.
    if req.data.args[1] == 0 {
        return request.fail_syscall(Errno::EFAULT);
    }

    let open_how = match request.remote_ohow(req.data.args[2], req.data.args[3]) {
        Ok(open_how) => open_how,
        Err(errno) => {
            return request.fail_syscall(errno);
        }
    };

    #[allow(clippy::cast_possible_truncation)]
    let flags = OFlag::from_bits_truncate(open_how.flags as libc::c_int);
    #[allow(clippy::cast_possible_truncation)]
    let mode = Mode::from_bits_truncate(open_how.mode as libc::mode_t);
    // SAFETY:
    // 1. Return ENOSYS for valid but unsupported openat2 resolve flags.
    // 2. Return EINVAL for invalid resolve flags.
    let rflags = match ResolveFlag::from_bits(open_how.resolve) {
        Some(rflags) if rflags.contains(ResolveFlag::RESOLVE_IN_ROOT) => {
            return request.fail_syscall(Errno::ENOSYS)
        }
        Some(rflags) => rflags,
        None => return request.fail_syscall(Errno::EINVAL),
    };
    let arg = SysArg::open(flags, true, rflags);

    syscall_open_handler(request, OpenSyscall::Openat2, arg, flags, mode)
}

fn sys_rename(request: UNotifyEventRequest) -> ScmpNotifResp {
    let argv = &[
        SysArg {
            path: Some(0),
            dotlast: Some(Errno::EINVAL),
            fsflags: FsFlags::MUST_PATH | FsFlags::NO_FOLLOW_LAST | FsFlags::WANT_BASE,
            ..Default::default()
        },
        SysArg {
            path: Some(1),
            dotlast: Some(Errno::EINVAL),
            fsflags: FsFlags::NO_FOLLOW_LAST | FsFlags::WANT_BASE,
            ..Default::default()
        },
    ];

    syscall_path_handler(
        request,
        "rename",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            syscall_rename_handler(request, path_args)
        },
    )
}

fn sys_renameat(request: UNotifyEventRequest) -> ScmpNotifResp {
    let argv = &[
        SysArg {
            dirfd: Some(0),
            path: Some(1),
            dotlast: Some(Errno::EINVAL),
            fsflags: FsFlags::MUST_PATH | FsFlags::NO_FOLLOW_LAST | FsFlags::WANT_BASE,
            ..Default::default()
        },
        SysArg {
            dirfd: Some(2),
            path: Some(3),
            dotlast: Some(Errno::EINVAL),
            fsflags: FsFlags::NO_FOLLOW_LAST | FsFlags::WANT_BASE,
            ..Default::default()
        },
    ];

    syscall_path_handler(
        request,
        "renameat",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            syscall_rename_handler(request, path_args)
        },
    )
}

fn sys_renameat2(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;
    #[allow(clippy::cast_possible_truncation)]
    let flags = req.data.args[4] as u32;
    let noreplace = flags & libc::RENAME_NOREPLACE != 0;

    let argv = &[
        SysArg {
            dirfd: Some(0),
            path: Some(1),
            dotlast: Some(Errno::EINVAL),
            fsflags: FsFlags::MUST_PATH | FsFlags::NO_FOLLOW_LAST | FsFlags::WANT_BASE,
            ..Default::default()
        },
        SysArg {
            dirfd: Some(2),
            path: Some(3),
            dotlast: Some(Errno::EINVAL),
            fsflags: if noreplace {
                FsFlags::MISS_LAST | FsFlags::NO_FOLLOW_LAST | FsFlags::WANT_BASE
            } else {
                FsFlags::NO_FOLLOW_LAST | FsFlags::WANT_BASE
            },
            ..Default::default()
        },
    ];

    syscall_path_handler(
        request,
        "renameat2",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            // SAFETY: SysArg has two elements.
            #[allow(clippy::disallowed_methods)]
            let old_path = path_args.0.as_ref().unwrap();
            #[allow(clippy::disallowed_methods)]
            let new_path = path_args.1.as_ref().unwrap();

            let old_dirfd = old_path
                .dir
                .as_ref()
                .map(|fd| fd.as_raw_fd())
                .ok_or(Errno::EBADF)?;
            let new_dirfd = new_path
                .dir
                .as_ref()
                .map(|fd| fd.as_raw_fd())
                .ok_or(Errno::EBADF)?;

            // musl does not define renameat2 yet,
            // so we have to resort to syscall!
            let sys_renameat2: i32 = ScmpSyscall::from_name("renameat2")
                .or(Err(Errno::ENOSYS))?
                .into();
            old_path
                .base
                .with_nix_path(|old_cstr| {
                    new_path.base.with_nix_path(|new_cstr| {
                        // SAFETY: musl does not define renameat2!
                        Errno::result(unsafe {
                            libc::syscall(
                                sys_renameat2.into(),
                                old_dirfd,
                                old_cstr.as_ptr(),
                                new_dirfd,
                                new_cstr.as_ptr(),
                                flags,
                            )
                        })
                    })
                })??
                .map(|_| request.return_syscall(0))
        },
    )
}

fn sys_stat(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    let is32 = scmp_arch_bits(req.data.arch) == 32;

    let arg = SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH,
        ..Default::default()
    };

    syscall_stat_handler(request, arg, 1, is32)
}

fn sys_stat64(request: UNotifyEventRequest) -> ScmpNotifResp {
    let arg = SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH,
        ..Default::default()
    };

    syscall_stat_handler(request, arg, 1, false)
}

fn sys_fstat(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    let is32 = scmp_arch_bits(req.data.arch) == 32;

    let arg = SysArg {
        dirfd: Some(0),
        ..Default::default()
    };

    syscall_stat_handler(request, arg, 1, is32)
}

fn sys_fstat64(request: UNotifyEventRequest) -> ScmpNotifResp {
    let arg = SysArg {
        dirfd: Some(0),
        ..Default::default()
    };

    syscall_stat_handler(request, arg, 1, false)
}

fn sys_lstat(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    let is32 = scmp_arch_bits(req.data.arch) == 32;

    let arg = SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::NO_FOLLOW_LAST,
        ..Default::default()
    };

    syscall_stat_handler(request, arg, 1, is32)
}

fn sys_lstat64(request: UNotifyEventRequest) -> ScmpNotifResp {
    let arg = SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::NO_FOLLOW_LAST,
        ..Default::default()
    };

    syscall_stat_handler(request, arg, 1, false)
}

fn sys_statx(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    let empty = req.data.args[2] & libc::AT_EMPTY_PATH as u64 != 0;
    let follow = req.data.args[2] & libc::AT_SYMLINK_NOFOLLOW as u64 == 0;

    let mut flags = SysFlags::empty();
    let mut fsflags = FsFlags::MUST_PATH;

    if empty {
        flags |= SysFlags::EMPTY_PATH;
    }

    if !follow {
        fsflags |= FsFlags::NO_FOLLOW_LAST;
    }

    let arg = SysArg {
        dirfd: Some(0),
        path: Some(1),
        flags,
        fsflags,
        ..Default::default()
    };

    syscall_stat_handler(request, arg, 4, false)
}

fn sys_newfstatat(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    let empty = req.data.args[3] & libc::AT_EMPTY_PATH as u64 != 0;
    let follow = req.data.args[3] & libc::AT_SYMLINK_NOFOLLOW as u64 == 0;
    let mut flags = SysFlags::empty();
    let mut fsflags = FsFlags::MUST_PATH;

    if empty {
        flags |= SysFlags::EMPTY_PATH;
    }

    if !follow {
        fsflags |= FsFlags::NO_FOLLOW_LAST;
    }

    let arg = SysArg {
        dirfd: Some(0),
        path: Some(1),
        flags,
        fsflags,
        ..Default::default()
    };

    syscall_stat_handler(request, arg, 2, false)
}

fn sys_utime(request: UNotifyEventRequest) -> ScmpNotifResp {
    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH,
        ..Default::default()
    }];

    syscall_path_handler(
        request,
        "utime",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            let req = request.scmpreq;
            let (atime, mtime) = request.remote_utimbuf(req.data.args[1])?;
            syscall_utime_handler(request, path_args, &atime, &mtime)
        },
    )
}

fn sys_utimes(request: UNotifyEventRequest) -> ScmpNotifResp {
    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH,
        ..Default::default()
    }];

    syscall_path_handler(
        request,
        "utime",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            let req = request.scmpreq;
            let (atime, mtime) = request.remote_utimbuf(req.data.args[1])?;
            syscall_utime_handler(request, path_args, &atime, &mtime)
        },
    )
}

fn sys_futimesat(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    let fsflags = FsFlags::MUST_PATH;
    let path = if req.data.args[1] != 0 { Some(1) } else { None };

    let argv = &[SysArg {
        dirfd: Some(0),
        path,
        fsflags,
        ..Default::default()
    }];

    syscall_path_handler(
        request,
        "futimesat",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            let (atime, mtime) = request.remote_timeval(req.data.args[2])?;
            syscall_utime_handler(request, path_args, &atime, &mtime)
        },
    )
}

fn sys_utimensat(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    #[allow(clippy::cast_possible_truncation)]
    let flags = req.data.args[3] as libc::c_int;

    let empty = flags & libc::AT_EMPTY_PATH != 0;
    let follow = flags & libc::AT_SYMLINK_NOFOLLOW == 0;
    let mut flags = SysFlags::empty();
    let mut fsflags = FsFlags::MUST_PATH;

    if empty {
        flags |= SysFlags::EMPTY_PATH;
    }

    if !follow {
        fsflags |= FsFlags::NO_FOLLOW_LAST;
    }

    let argv = &[SysArg {
        dirfd: Some(0),
        path: if req.data.args[1] != 0 { Some(1) } else { None },
        flags,
        fsflags,
        ..Default::default()
    }];

    syscall_path_handler(
        request,
        "utimensat",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            let addr = req.data.args[2];
            let is32 = scmp_arch_bits(req.data.arch) == 32;

            let (atime, mtime) = if is32 {
                request.remote_timespec32(addr)
            } else {
                request.remote_timespec64(addr)
            }?;

            syscall_utime_handler(request, path_args, &atime, &mtime)
        },
    )
}

fn sys_utimensat64(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    #[allow(clippy::cast_possible_truncation)]
    let flags = req.data.args[3] as libc::c_int;

    let empty = flags & libc::AT_EMPTY_PATH != 0;
    let follow = flags & libc::AT_SYMLINK_NOFOLLOW == 0;
    let mut flags = SysFlags::empty();
    let mut fsflags = FsFlags::MUST_PATH;

    if empty {
        flags |= SysFlags::EMPTY_PATH;
    }

    if !follow {
        fsflags |= FsFlags::NO_FOLLOW_LAST;
    }

    let argv = &[SysArg {
        dirfd: Some(0),
        path: if req.data.args[1] != 0 { Some(1) } else { None },
        flags,
        fsflags,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "utimensat_time64",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            let (atime, mtime) = request.remote_timespec64(req.data.args[2])?;
            syscall_utime_handler(request, path_args, &atime, &mtime)
        },
    )
}

fn sys_truncate(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY:
    // 1. If first argument is NULL, return EFAULT.
    // 2. If second argument is negative, return EINVAL.
    let req = request.scmpreq;
    let is32 = scmp_arch_bits(req.data.arch) == 32;

    #[allow(clippy::cast_lossless)]
    #[allow(clippy::cast_possible_truncation)]
    #[allow(clippy::cast_possible_wrap)]
    let len = if is32 {
        libc::off_t::from(req.data.args[1] as i32)
    } else {
        req.data.args[1] as libc::off_t
    };

    if len < 0 {
        return request.fail_syscall(Errno::EINVAL);
    } else if req.data.args[0] == 0 {
        return request.fail_syscall(Errno::EFAULT);
    }

    let argv = &[SysArg {
        path: Some(0),
        ..Default::default()
    }];

    syscall_path_handler(
        request,
        "truncate",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            // SAFETY:
            // 1. SysArg has one element.
            // 2. `/` is not a regular file -> EINVAL.
            #[allow(clippy::disallowed_methods)]
            let fd = path_args
                .0
                .as_ref()
                .map(|path| path.dir.as_ref().unwrap().as_raw_fd())
                .ok_or(Errno::EINVAL)?;

            // SAFETY: ftruncate(2) requires write fds.
            // We fallback to `/proc` indirection to avoid opening the file as write.
            //
            // path to fd is open already!
            let mut pfd = XPathBuf::from("/proc/self/fd");
            pfd.push_fd(fd);

            // SAFETY: Record blocking call so it can get invalidated.
            request.cache.add_sys_block(req, false)?;

            let result = pfd
                .with_nix_path(|cstr| {
                    // SAFETY: libc version may call truncate64 behind our back!
                    Errno::result(unsafe { libc::syscall(libc::SYS_truncate, cstr.as_ptr(), len) })
                })?
                .map(|_| request.return_syscall(0));

            if !matches!(result, Err(Errno::EINTR)) {
                request.cache.del_sys_block(req.id);
            }

            result
        },
    )
}

fn sys_truncate64(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY:
    // 1. If first argument is NULL, return EFAULT.
    // 2. If second argument is negative, return EINVAL.
    let req = request.scmpreq;
    let is32 = scmp_arch_bits(req.data.arch) == 32;

    // truncate64 needs argument translation on some architectures.
    #[allow(clippy::arithmetic_side_effects)]
    #[allow(clippy::cast_possible_truncation)]
    #[allow(clippy::cast_possible_wrap)]
    let len = if is32 {
        // Align arg_no to the next even number for specific 32-bit architectures.
        let arg_no = match req.data.arch {
            ScmpArch::Arm | ScmpArch::Ppc => 2,
            _ => 1,
        };

        let len_low = req.data.args[arg_no] as u32;
        let len_high = req.data.args[arg_no + 1] as u32;

        if scmp_big_endian(req.data.arch) {
            (libc::off64_t::from(len_low) << 32) | libc::off64_t::from(len_high)
        } else {
            (libc::off64_t::from(len_high) << 32) | libc::off64_t::from(len_low)
        }
    } else {
        // Align arg_no to the next even number for specific 64-bit architectures.
        let arg_no = match req.data.arch {
            ScmpArch::Aarch64 | ScmpArch::Ppc64 | ScmpArch::Ppc64Le => 2,
            _ => 1,
        };

        req.data.args[arg_no] as libc::off64_t
    };

    if len < 0 {
        return request.fail_syscall(Errno::EINVAL);
    } else if req.data.args[0] == 0 {
        return request.fail_syscall(Errno::EFAULT);
    }

    let argv = &[SysArg {
        path: Some(0),
        ..Default::default()
    }];

    syscall_path_handler(
        request,
        "truncate64",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            // SAFETY:
            // 1. SysArg has one element.
            // 2. `/` is not a regular file -> EINVAL.
            #[allow(clippy::disallowed_methods)]
            let fd = path_args
                .0
                .as_ref()
                .unwrap()
                .dir
                .as_ref()
                .ok_or(Errno::EINVAL)?;

            // SAFETY: ftruncate64(2) requires write fds.
            // We fallback to `/proc` indirection to avoid opening the file as write.
            //
            // path to fd is open already!
            let mut pfd = XPathBuf::from("/proc/self/fd");
            pfd.push_fd(fd.as_raw_fd());

            // SAFETY: Record blocking call so it can get invalidated.
            request.cache.add_sys_block(req, false)?;

            let result = truncate64(&pfd, len).map(|_| request.return_syscall(0));

            if !matches!(result, Err(Errno::EINTR)) {
                request.cache.del_sys_block(req.id);
            }

            result
        },
    )
}

fn sys_ftruncate(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: If second argument is negative, return EINVAL.
    let req = request.scmpreq;
    let is32 = scmp_arch_bits(req.data.arch) == 32;

    #[allow(clippy::cast_lossless)]
    #[allow(clippy::cast_possible_truncation)]
    #[allow(clippy::cast_possible_wrap)]
    let len = if is32 {
        libc::off_t::from(req.data.args[1] as i32)
    } else {
        req.data.args[1] as libc::off_t
    };

    if len < 0 {
        return request.fail_syscall(Errno::EINVAL);
    }

    let argv = &[SysArg {
        dirfd: Some(0),
        ..Default::default()
    }];

    syscall_path_handler(
        request,
        "ftruncate",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            // SAFETY:
            // 1. SysArg has one element.
            // 2. SysArg.path is None asserting dir is Some.
            #[allow(clippy::disallowed_methods)]
            let fd = path_args
                .0
                .as_ref()
                .map(|path| path.dir.as_ref().unwrap().as_raw_fd())
                .ok_or(Errno::EINVAL)?;

            // SAFETY: Record blocking call so it can get invalidated.
            request.cache.add_sys_block(req, false)?;

            // SAFETY: Libc version may call ftruncate64 behind our back.
            let result = Errno::result(unsafe { libc::syscall(libc::SYS_ftruncate, fd, len) })
                .map(|_| request.return_syscall(0));

            if !matches!(result, Err(Errno::EINTR)) {
                request.cache.del_sys_block(req.id);
            }

            result
        },
    )
}

fn sys_ftruncate64(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: If second argument is negative, return EINVAL.
    let req = request.scmpreq;
    let is32 = scmp_arch_bits(req.data.arch) == 32;

    // truncate64 needs argument translation on some architectures.
    #[allow(clippy::arithmetic_side_effects)]
    #[allow(clippy::cast_possible_truncation)]
    #[allow(clippy::cast_possible_wrap)]
    let len = if is32 {
        // Align arg_no to the next even number for specific 32-bit architectures.
        let arg_no = match req.data.arch {
            ScmpArch::Arm | ScmpArch::Ppc => 2,
            _ => 1,
        };

        let len_low = req.data.args[arg_no] as u32;
        let len_high = req.data.args[arg_no + 1] as u32;

        if scmp_big_endian(req.data.arch) {
            (libc::off64_t::from(len_low) << 32) | libc::off64_t::from(len_high)
        } else {
            (libc::off64_t::from(len_high) << 32) | libc::off64_t::from(len_low)
        }
    } else {
        // Align arg_no to the next even number for specific 64-bit architectures.
        let arg_no = match req.data.arch {
            ScmpArch::Aarch64 | ScmpArch::Ppc64 | ScmpArch::Ppc64Le => 2,
            _ => 1,
        };

        req.data.args[arg_no] as libc::off64_t
    };

    if len < 0 {
        return request.fail_syscall(Errno::EINVAL);
    }

    let argv = &[SysArg {
        dirfd: Some(0),
        ..Default::default()
    }];

    syscall_path_handler(
        request,
        "ftruncate64",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            // SAFETY:
            // 1. SysArg has one element.
            // 2. SysArg.path is None asserting dir is Some.
            #[allow(clippy::disallowed_methods)]
            let fd = path_args.0.as_ref().unwrap().dir.as_ref().unwrap();

            // SAFETY: Record blocking call so it can get invalidated.
            request.cache.add_sys_block(req, false)?;

            let result = ftruncate64(fd.as_raw_fd(), len).map(|_| request.return_syscall(0));

            if !matches!(result, Err(Errno::EINTR)) {
                request.cache.del_sys_block(req.id);
            }

            result
        },
    )
}

fn sys_fallocate(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: EINVAL offset was less than 0, or len was less than or equal to 0.
    let req = request.scmpreq;
    let is32 = scmp_arch_bits(req.data.arch) == 32;

    // fallocate needs argument translation for offset argument on some architectures.
    #[allow(clippy::arithmetic_side_effects)]
    #[allow(clippy::cast_possible_truncation)]
    #[allow(clippy::cast_possible_wrap)]
    let off = if is32 {
        let len_low = req.data.args[2] as u32;
        let len_high = req.data.args[3] as u32;

        if scmp_big_endian(req.data.arch) {
            (libc::off64_t::from(len_low) << 32) | libc::off64_t::from(len_high)
        } else {
            (libc::off64_t::from(len_high) << 32) | libc::off64_t::from(len_low)
        }
    } else {
        req.data.args[2] as libc::off64_t
    };

    if off < 0 {
        return request.fail_syscall(Errno::EINVAL);
    }

    // fallocate needs argument translation for length argument on some architectures.
    #[allow(clippy::arithmetic_side_effects)]
    #[allow(clippy::cast_possible_truncation)]
    #[allow(clippy::cast_possible_wrap)]
    let len = if is32 {
        let len_low = req.data.args[4] as u32;
        let len_high = req.data.args[5] as u32;

        if scmp_big_endian(req.data.arch) {
            (libc::off64_t::from(len_low) << 32) | libc::off64_t::from(len_high)
        } else {
            (libc::off64_t::from(len_high) << 32) | libc::off64_t::from(len_low)
        }
    } else {
        // Align arg_no to the next even number for specific 64-bit architectures.
        let arg_no = match req.data.arch {
            ScmpArch::Aarch64 | ScmpArch::Ppc64 | ScmpArch::Ppc64Le => 4,
            _ => 3,
        };

        req.data.args[arg_no] as libc::off64_t
    };

    if len <= 0 {
        return request.fail_syscall(Errno::EINVAL);
    }

    #[allow(clippy::cast_possible_truncation)]
    let mode = FallocateFlags::from_bits_truncate(req.data.args[1] as libc::c_int);
    let argv = &[SysArg {
        dirfd: Some(0),
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "fallocate",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            // SAFETY:
            // 1. SysArg has one element.
            // 2. SysArg.path is None asserting dir is Some.
            #[allow(clippy::disallowed_methods)]
            let fd = path_args.0.as_ref().unwrap().dir.as_ref().unwrap();

            // SAFETY: Record blocking call so it can get invalidated.
            request.cache.add_sys_block(req, false)?;

            let result =
                // SAFETY: nix does not have an interface for fallocate64.
                Errno::result(unsafe { libc::fallocate64(fd.as_raw_fd(), mode.bits(), off, len) })
                    .map(|_| request.return_syscall(0));

            if !matches!(result, Err(Errno::EINTR)) {
                request.cache.del_sys_block(req.id);
            }

            result
        },
    )
}

fn sys_getxattr(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: We set WANT_BASE because fgetxattr requires a read-only
    // fd but we may not have access to open the file! Note, getxattr is
    // a Stat access not Read access! Potential TOCTOU-vectors are
    // handled in syscall_getxattr_handler() where we no longer resolve
    // symlinks.
    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::WANT_BASE,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "getxattr",
        argv,
        |path_args: PathArgs, request, sandbox| {
            syscall_getxattr_handler(request, &sandbox, path_args)
        },
    )
}

fn sys_lgetxattr(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: We set WANT_BASE because fgetxattr requires a read-only
    // fd but we may not have access to open the file! Note, getxattr is
    // a Stat access not Read access! Potential TOCTOU-vectors are
    // handled in syscall_getxattr_handler() where we no longer resolve
    // symlinks.
    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::NO_FOLLOW_LAST | FsFlags::WANT_BASE,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "lgetxattr",
        argv,
        |path_args: PathArgs, request, sandbox| {
            syscall_getxattr_handler(request, &sandbox, path_args)
        },
    )
}

fn sys_fgetxattr(request: UNotifyEventRequest) -> ScmpNotifResp {
    // fgetxattr does not work with O_PATH fds.
    // Hence, we have to use WANT_READ.
    let argv = &[SysArg {
        dirfd: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::WANT_READ,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "fgetxattr",
        argv,
        |path_args: PathArgs, request, sandbox| {
            // SAFETY:
            // 1. SysArg has one element.
            // 2. SysArg.path is None asserting dir is Some.
            #[allow(clippy::disallowed_methods)]
            let fd = path_args.0.as_ref().unwrap().dir.as_ref().unwrap();

            let req = request.scmpreq;
            let name = if req.data.args[1] != 0 {
                const SIZ: usize = libc::PATH_MAX as usize;
                let mut buf = Vec::new();
                buf.try_reserve(SIZ).or(Err(Errno::ENOMEM))?;
                buf.resize(SIZ, 0);
                request.read_mem(&mut buf, req.data.args[1])?;
                Some(buf)
            } else {
                None
            };
            let name = if let Some(ref name) = name {
                CStr::from_bytes_until_nul(name)
                    .or(Err(Errno::E2BIG))?
                    .as_ptr()
            } else {
                std::ptr::null()
            };

            if Sandbox::locked_once() || sandbox.locked_for(req.pid()) {
                // SAFETY: Deny user.syd* extended attributes. name is either
                // NULL or a valid nul-terminated C-String.
                // SAFETY: Deny with ENODATA for stealth.
                // SAFETY: Deny only if the Sandbox is locked for the process.
                unsafe { denyxattr(name) }?;
            }

            // SAFETY: The size argument to the getxattr call
            // must not be fully trusted, it can be overly large,
            // and allocating a Vector of that capacity may overflow.
            let len = usize::try_from(req.data.args[3]).or(Err(Errno::E2BIG))?;
            let len = len.min(libc::PATH_MAX as usize); // Cap count at PATH_MAX
            let mut buf = if len > 0 {
                let mut buf = Vec::new();
                buf.try_reserve(len).or(Err(Errno::ENOMEM))?;
                buf.resize(len, 0);
                Some(buf)
            } else {
                None
            };
            let ptr = match buf.as_mut() {
                Some(b) => b.as_mut_ptr(),
                None => std::ptr::null_mut(),
            };
            // SAFETY: In libc we trust.
            let n = unsafe {
                libc::fgetxattr(
                    fd.as_raw_fd(),
                    name,
                    ptr as *mut _ as *mut libc::c_void,
                    len,
                )
            };
            #[allow(clippy::cast_sign_loss)]
            let n = if n == -1 {
                return Err(Errno::last());
            } else {
                n as usize
            };
            if let Some(buf) = buf {
                request.write_mem(&buf[..n], req.data.args[2])?;
            }
            #[allow(clippy::cast_possible_wrap)]
            Ok(request.return_syscall(n as i64))
        },
    )
}

fn sys_getxattrat(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: We set WANT_BASE because fgetxattr requires a read-only
    // fd but we may not have access to open the file! Note, getxattrat is
    // a Stat access not Read access! Potential TOCTOU-vectors are
    // handled in syscall_getxattrat_handler() where we no longer resolve
    // symlinks.
    let req = request.scmpreq;

    #[allow(clippy::cast_possible_truncation)]
    let flags = AtFlags::from_bits_truncate(req.data.args[2] as libc::c_int);

    let mut fsflags = FsFlags::MUST_PATH | FsFlags::WANT_BASE;
    if flags.contains(AtFlags::AT_SYMLINK_NOFOLLOW) {
        fsflags.insert(FsFlags::NO_FOLLOW_LAST);
    }

    let empty_path = flags.contains(AtFlags::AT_EMPTY_PATH);
    let argv = &[SysArg {
        dirfd: Some(0),
        path: Some(1),
        flags: if empty_path {
            SysFlags::EMPTY_PATH
        } else {
            SysFlags::empty()
        },
        fsflags,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "getxattrat",
        argv,
        |path_args: PathArgs, request, sandbox| {
            syscall_getxattrat_handler(request, &sandbox, path_args)
        },
    )
}

fn sys_setxattr(request: UNotifyEventRequest) -> ScmpNotifResp {
    // fsetxattr does not work with O_PATH fds.
    // Hence, we have to use WANT_READ.
    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::WANT_READ,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "setxattr",
        argv,
        |path_args: PathArgs, request, sandbox| {
            syscall_setxattr_handler(request, &sandbox, path_args)
        },
    )
}

fn sys_fsetxattr(request: UNotifyEventRequest) -> ScmpNotifResp {
    // fsetxattr does not work with O_PATH fds.
    // Hence, we have to use WANT_READ.
    let argv = &[SysArg {
        dirfd: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::WANT_READ,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "fsetxattr",
        argv,
        |path_args: PathArgs, request, sandbox| {
            syscall_setxattr_handler(request, &sandbox, path_args)
        },
    )
}

fn sys_lsetxattr(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: We set WANT_BASE because fsetxattr requires a read-only
    // fd but we may not have access to open the file!
    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::NO_FOLLOW_LAST | FsFlags::WANT_BASE,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "lsetxattr",
        argv,
        |path_args: PathArgs, request, sandbox| {
            // SAFETY: SysArg has one element.
            #[allow(clippy::disallowed_methods)]
            let path = path_args.0.as_ref().unwrap();

            let base = if path.base.is_empty() {
                XPath::from_bytes(b".")
            } else {
                path.base
            };

            let req = request.scmpreq;

            let name = if req.data.args[1] != 0 {
                const SIZ: usize = libc::PATH_MAX as usize;
                let mut buf = Vec::new();
                buf.try_reserve(SIZ).or(Err(Errno::ENOMEM))?;
                buf.resize(SIZ, 0);
                request.read_mem(&mut buf, req.data.args[1])?;
                Some(buf)
            } else {
                None
            };
            let name = if let Some(ref name) = name {
                CStr::from_bytes_until_nul(name)
                    .or(Err(Errno::E2BIG))?
                    .as_ptr()
            } else {
                std::ptr::null()
            };

            if Sandbox::locked_once() || sandbox.locked_for(req.pid()) {
                // SAFETY: Deny user.syd* extended attributes. name is either
                // NULL or a valid nul-terminated C-String.
                // SAFETY: Deny with ENODATA for stealth.
                // SAFETY: Deny only if the Sandbox is locked for the process.
                unsafe { denyxattr(name) }?;
            }

            // SAFETY: The size argument to the setxattr call
            // must not be fully trusted, it can be overly large,
            // and allocating a Vector of that capacity may overflow.
            let (buf, len) = if req.data.args[3] == 0 {
                (None, 0)
            } else {
                let len = usize::try_from(req.data.args[3]).or(Err(Errno::E2BIG))?;
                let len = len.min(libc::PATH_MAX as usize); // Cap count at PATH_MAX.
                let mut buf = Vec::new();
                buf.try_reserve(len).or(Err(Errno::ENOMEM))?;
                buf.resize(len, 0);
                request.read_mem(&mut buf, req.data.args[2])?;
                (Some(buf), len)
            };
            let buf = buf.as_ref().map_or(std::ptr::null(), |b| b.as_ptr()) as *const libc::c_void;

            #[allow(clippy::cast_possible_truncation)]
            let flags = req.data.args[4] as libc::c_int;

            match &path.dir {
                Some(fd) => {
                    // SAFETY: We use fchdir which is TOCTOU-free!
                    fchdir(fd.as_raw_fd())?;
                }
                None => {
                    // SAFETY: `/` is never a symlink!
                    fchdir(ROOT_FD())?;
                }
            };

            // SAFETY: In libc we trust.
            let res = base.with_nix_path(|cstr| unsafe {
                libc::lsetxattr(cstr.as_ptr(), name, buf, len, flags)
            })?;
            Errno::result(res).map(|_| request.return_syscall(0))
        },
    )
}

fn sys_setxattrat(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: We set WANT_BASE because fsetxattr requires a read-only
    // fd but we may not have access to open the file! Note, setxattrat is
    // a Chattr access not Read access! Potential TOCTOU-vectors are
    // handled in syscall_setxattrat_handler() where we no longer resolve
    // symlinks.
    let req = request.scmpreq;

    #[allow(clippy::cast_possible_truncation)]
    let flags = AtFlags::from_bits_truncate(req.data.args[2] as libc::c_int);

    let mut fsflags = FsFlags::MUST_PATH | FsFlags::WANT_BASE;
    if flags.contains(AtFlags::AT_SYMLINK_NOFOLLOW) {
        fsflags.insert(FsFlags::NO_FOLLOW_LAST);
    }

    let empty_path = flags.contains(AtFlags::AT_EMPTY_PATH);
    let argv = &[SysArg {
        dirfd: Some(0),
        path: Some(1),
        flags: if empty_path {
            SysFlags::EMPTY_PATH
        } else {
            SysFlags::empty()
        },
        fsflags,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "setxattrat",
        argv,
        |path_args: PathArgs, request, sandbox| {
            syscall_setxattrat_handler(request, &sandbox, path_args)
        },
    )
}

fn sys_flistxattr(request: UNotifyEventRequest) -> ScmpNotifResp {
    // flistxattr does not work with O_PATH fds.
    // Hence, we have to use WANT_READ.
    let argv = &[SysArg {
        dirfd: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::WANT_READ,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "flistxattr",
        argv,
        |path_args: PathArgs, request, sandbox| {
            // SAFETY:
            // 1. SysArg has one element.
            // 2. SysArg.path is None asserting dir is Some.
            #[allow(clippy::disallowed_methods)]
            let fd = path_args.0.as_ref().unwrap().dir.as_ref().unwrap();

            let req = request.scmpreq;

            // SAFETY: The size argument to the flistxattr call
            // must not be fully trusted, it can be overly large,
            // and allocating a Vector of that capacity may overflow.
            let len = usize::try_from(req.data.args[2]).or(Err(Errno::E2BIG))?;
            let len = len.min(10240); // Cap count at 10240.
            let mut buf = if len > 0 {
                let mut buf = Vec::new();
                buf.try_reserve(len).or(Err(Errno::ENOMEM))?;
                buf.resize(len, 0);
                Some(buf)
            } else {
                None
            };
            let ptr = buf
                .as_mut()
                .map_or(std::ptr::null_mut(), |b| b.as_mut_ptr())
                as *mut libc::c_char;

            // SAFETY: In libc we trust.
            let n = unsafe { libc::flistxattr(fd.as_raw_fd(), ptr, len) };
            #[allow(clippy::cast_sign_loss)]
            let n = if n == -1 {
                return Err(Errno::last());
            } else {
                n as usize
            };
            let n = if let Some(buf) = buf {
                // SAFETY: Filter out attributes that start with "user.syd".
                // SAFETY: Deny only if the Sandbox is locked for the process.
                #[allow(clippy::cast_possible_wrap)]
                let buf = if Sandbox::locked_once() || sandbox.locked_for(req.pid()) {
                    filterxattr(&buf[..n], n)?
                } else {
                    buf
                };

                request.write_mem(&buf, req.data.args[1])?;
                buf.len()
            } else {
                n
            };
            #[allow(clippy::cast_possible_wrap)]
            Ok(request.return_syscall(n as i64))
        },
    )
}

fn sys_listxattr(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: We set WANT_BASE because flistxattr requires a read-only
    // fd but we may not have access to open the file! Note, listxattr
    // is a Stat access not Read access! Potential TOCTOU-vectors are
    // handled in syscall_listxattr_handler() where we no longer resolve
    // symlinks.
    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::WANT_BASE,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "listxattr",
        argv,
        |path_args: PathArgs, request, sandbox| {
            syscall_listxattr_handler(request, &sandbox, path_args)
        },
    )
}

fn sys_llistxattr(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: We set WANT_BASE because flistxattr requires a read-only
    // fd but we may not have access to open the file! Note, listxattr
    // is a Stat access not Read access! Potential TOCTOU-vectors are
    // handled in syscall_listxattr_handler() where we no longer resolve
    // symlinks.
    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::NO_FOLLOW_LAST | FsFlags::WANT_BASE,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "llistxattr",
        argv,
        |path_args: PathArgs, request, sandbox| {
            syscall_listxattr_handler(request, &sandbox, path_args)
        },
    )
}

fn sys_removexattr(request: UNotifyEventRequest) -> ScmpNotifResp {
    // fremovexattr does not work with O_PATH fds.
    // Hence, we have to use WANT_READ.
    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::WANT_READ,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "removexattr",
        argv,
        |path_args: PathArgs, request, sandbox| {
            syscall_removexattr_handler(request, &sandbox, path_args)
        },
    )
}

fn sys_listxattrat(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: We set WANT_BASE because flistxattr requires a read-only
    // fd but we may not have access to open the file! Note, listxattr
    // is a Stat access not Read access! Potential TOCTOU-vectors are
    // handled in syscall_listxattrat_handler() where we no longer resolve
    // symlinks.
    let req = request.scmpreq;

    #[allow(clippy::cast_possible_truncation)]
    let flags = AtFlags::from_bits_truncate(req.data.args[2] as libc::c_int);

    let mut fsflags = FsFlags::MUST_PATH | FsFlags::WANT_BASE;
    if flags.contains(AtFlags::AT_SYMLINK_NOFOLLOW) {
        fsflags.insert(FsFlags::NO_FOLLOW_LAST);
    }

    let empty_path = flags.contains(AtFlags::AT_EMPTY_PATH);
    let argv = &[SysArg {
        dirfd: Some(0),
        path: Some(1),
        flags: if empty_path {
            SysFlags::EMPTY_PATH
        } else {
            SysFlags::empty()
        },
        fsflags,
        ..Default::default()
    }];

    syscall_path_handler(
        request,
        "listxattrat",
        argv,
        |path_args: PathArgs, request, sandbox| {
            syscall_listxattrat_handler(request, &sandbox, path_args)
        },
    )
}

fn sys_fremovexattr(request: UNotifyEventRequest) -> ScmpNotifResp {
    // fremovexattr does not work with O_PATH fds.
    // Hence, we have to use WANT_READ.
    let argv = &[SysArg {
        dirfd: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::WANT_READ,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "fremovexattr",
        argv,
        |path_args: PathArgs, request, sandbox| {
            syscall_removexattr_handler(request, &sandbox, path_args)
        },
    )
}

fn sys_lremovexattr(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: We set WANT_BASE because fremovexattr requires a read-only
    // fd but we may not have access to open the file!
    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::NO_FOLLOW_LAST | FsFlags::WANT_BASE,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "lremovexattr",
        argv,
        |path_args: PathArgs, request, sandbox| {
            // SAFETY: SysArg has one element.
            #[allow(clippy::disallowed_methods)]
            let path = path_args.0.as_ref().unwrap();

            let base = if path.base.is_empty() {
                XPath::from_bytes(b".")
            } else {
                path.base
            };

            let req = request.scmpreq;

            let name = if req.data.args[1] != 0 {
                const SIZ: usize = libc::PATH_MAX as usize;
                let mut buf = Vec::new();
                buf.try_reserve(SIZ).or(Err(Errno::ENOMEM))?;
                buf.resize(SIZ, 0);
                request.read_mem(&mut buf, req.data.args[1])?;
                Some(buf)
            } else {
                None
            };
            let name = if let Some(ref name) = name {
                CStr::from_bytes_until_nul(name)
                    .or(Err(Errno::E2BIG))?
                    .as_ptr()
            } else {
                std::ptr::null()
            };

            #[allow(clippy::cast_possible_wrap)]
            if Sandbox::locked_once() || sandbox.locked_for(req.pid()) {
                // SAFETY: Deny user.syd* extended attributes.
                // name is either NULL or a valid nul-terminated C-String.
                // SAFETY: Deny with ENODATA for stealth.
                // SAFETY: Deny only if the Sandbox is locked for the process.
                unsafe { denyxattr(name) }?;
            }

            match &path.dir {
                Some(fd) => {
                    // SAFETY: We use fchdir which is TOCTOU-free!
                    fchdir(fd.as_raw_fd())?
                }
                None => {
                    // SAFETY: `/` is never a symlink!
                    fchdir(ROOT_FD())?;
                }
            };

            let res = base
                // SAFETY: In libc we trust.
                .with_nix_path(|cstr| unsafe { libc::lremovexattr(cstr.as_ptr(), name) })?;
            Errno::result(res).map(|_| request.return_syscall(0))
        },
    )
}

fn sys_removexattrat(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: We set WANT_BASE because fsetxattr requires a read-only
    // fd but we may not have access to open the file! Note, setxattrat is
    // a Chattr access not Read access! Potential TOCTOU-vectors are
    // handled in syscall_removexattrat_handler() where we no longer resolve
    // symlinks.
    let req = request.scmpreq;

    #[allow(clippy::cast_possible_truncation)]
    let flags = AtFlags::from_bits_truncate(req.data.args[2] as libc::c_int);

    let mut fsflags = FsFlags::MUST_PATH | FsFlags::WANT_BASE;
    if flags.contains(AtFlags::AT_SYMLINK_NOFOLLOW) {
        fsflags.insert(FsFlags::NO_FOLLOW_LAST);
    }

    let empty_path = flags.contains(AtFlags::AT_EMPTY_PATH);
    let argv = &[SysArg {
        dirfd: Some(0),
        path: Some(1),
        flags: if empty_path {
            SysFlags::EMPTY_PATH
        } else {
            SysFlags::empty()
        },
        fsflags,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "removexattrat",
        argv,
        |path_args: PathArgs, request, sandbox| {
            syscall_removexattrat_handler(request, &sandbox, path_args)
        },
    )
}

fn sys_statfs(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY:
    // 1. If second argument is NULL, return EFAULT.
    // 2. We may need to run statfs on (magic) symlinks.
    //    Hence, we have to use WANT_BASE to split base.
    let req = request.scmpreq;
    if req.data.args[1] == 0 {
        return request.fail_syscall(Errno::EFAULT);
    }
    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::WANT_BASE,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "statfs",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            // SAFETY:
            // 1. SysArg has one element.
            // 2. `/` is not permitted -> EACCES.
            #[allow(clippy::disallowed_methods)]
            let fd = path_args
                .0
                .as_ref()
                .unwrap()
                .dir
                .as_ref()
                .ok_or(Errno::EACCES)?;

            const SIZ: usize = std::mem::size_of::<libc::statfs>();
            let mut buf: Vec<u8> = Vec::new();
            buf.try_reserve(SIZ).or(Err(Errno::ENOMEM))?;
            buf.resize(SIZ, 0);
            let ptr: *mut libc::statfs = buf.as_mut_ptr().cast();

            // SAFETY: Record blocking call so it can get invalidated.
            request.cache.add_sys_block(req, false)?;

            let result =
                // SAFETY: Libc version may call fstatfs64 behind our back!
                Errno::result(unsafe { libc::syscall(libc::SYS_fstatfs, fd.as_raw_fd(), ptr) });

            if !matches!(result, Err(Errno::EINTR)) {
                request.cache.del_sys_block(req.id);
            }

            result?;
            request.write_mem(&buf, req.data.args[1])?;
            Ok(request.return_syscall(0))
        },
    )
}

fn sys_statfs64(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY:
    // 1. If second argument is NULL, return EFAULT.
    // 2. We may need to run statfs on (magic) symlinks.
    //    Hence, we have to use WANT_BASE to split base.
    let req = request.scmpreq;
    if req.data.args[1] == 0 {
        return request.fail_syscall(Errno::EFAULT);
    }
    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MUST_PATH | FsFlags::WANT_BASE,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "statfs64",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            // SAFETY:
            // 1. SysArg has one element.
            // 2. `/` is not permitted -> EACCES.
            #[allow(clippy::disallowed_methods)]
            let fd = path_args
                .0
                .as_ref()
                .unwrap()
                .dir
                .as_ref()
                .ok_or(Errno::EACCES)?;

            const SIZ: usize = std::mem::size_of::<libc::statfs64>();
            let mut buf = Vec::new();
            buf.try_reserve(SIZ).or(Err(Errno::ENOMEM))?;
            buf.resize(SIZ, 0);
            let ptr = buf.as_mut_ptr().cast();

            // SAFETY: Record blocking call so it can get invalidated.
            request.cache.add_sys_block(req, false)?;

            // SAFETY: In libc we trust.
            let result = Errno::result(unsafe { libc::fstatfs64(fd.as_raw_fd(), ptr) });

            if !matches!(result, Err(Errno::EINTR)) {
                request.cache.del_sys_block(req.id);
            }

            result?;
            request.write_mem(&buf, req.data.args[1])?;
            Ok(request.return_syscall(0))
        },
    )
}

fn sys_fstatfs(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: If second argument is NULL, return EFAULT.
    let req = request.scmpreq;
    if req.data.args[1] == 0 {
        return request.fail_syscall(Errno::EFAULT);
    }
    let argv = &[SysArg {
        dirfd: Some(0),
        ..Default::default()
    }];
    syscall_path_handler(request, "fstatfs", argv, |path_args, request, sandbox| {
        drop(sandbox); // release the read-lock.

        // SAFETY:
        // 1. SysArg has one element.
        // 2. SysArg.path is None asserting dir is Some.
        #[allow(clippy::disallowed_methods)]
        let fd = path_args.0.as_ref().unwrap().dir.as_ref().unwrap();

        const SIZ: usize = std::mem::size_of::<libc::statfs>();
        let mut buf: Vec<u8> = Vec::new();
        buf.try_reserve(SIZ).or(Err(Errno::ENOMEM))?;
        buf.resize(SIZ, 0);
        let ptr: *mut libc::statfs = buf.as_mut_ptr().cast();

        // SAFETY: Record blocking call so it can get invalidated.
        request.cache.add_sys_block(req, false)?;

        let result =
            // SAFETY: Libc version may call fstatfs64 behind our back!
            Errno::result(unsafe { libc::syscall(libc::SYS_fstatfs, fd.as_raw_fd(), ptr) });

        if !matches!(result, Err(Errno::EINTR)) {
            request.cache.del_sys_block(req.id);
        }

        result?;
        request.write_mem(&buf, req.data.args[1])?;
        Ok(request.return_syscall(0))
    })
}

fn sys_fstatfs64(request: UNotifyEventRequest) -> ScmpNotifResp {
    // SAFETY: If second argument is NULL, return EFAULT.
    let req = request.scmpreq;
    if req.data.args[1] == 0 {
        return request.fail_syscall(Errno::EFAULT);
    }
    let argv = &[SysArg {
        dirfd: Some(0),
        ..Default::default()
    }];
    syscall_path_handler(request, "fstatfs64", argv, |path_args, request, sandbox| {
        drop(sandbox); // release the read-lock.

        // SAFETY:
        // 1. SysArg has one element.
        // 2. SysArg.path is None asserting dir is Some.
        #[allow(clippy::disallowed_methods)]
        let fd = path_args.0.as_ref().unwrap().dir.as_ref().unwrap();

        const SIZ: usize = std::mem::size_of::<libc::statfs64>();
        let mut buf = Vec::new();
        buf.try_reserve(SIZ).or(Err(Errno::ENOMEM))?;
        buf.resize(SIZ, 0);
        let ptr = buf.as_mut_ptr().cast();

        // SAFETY: Record blocking call so it can get invalidated.
        request.cache.add_sys_block(req, false)?;

        // SAFETY: In libc we trust.
        let result = Errno::result(unsafe { libc::fstatfs64(fd.as_raw_fd(), ptr) });

        if !matches!(result, Err(Errno::EINTR)) {
            request.cache.del_sys_block(req.id);
        }

        result?;
        request.write_mem(&buf, req.data.args[1])?;
        Ok(request.return_syscall(0))
    })
}

fn sys_fanotify_mark(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    let is32 = scmp_arch_bits(req.data.arch) == 32;

    let mut fsflags = FsFlags::MUST_PATH;
    if req.data.args[1] & u64::from(libc::FAN_MARK_DONT_FOLLOW) != 0 {
        fsflags |= FsFlags::NO_FOLLOW_LAST | FsFlags::WANT_BASE;
    }

    let pidx = if is32 { 5 } else { 4 };
    let argv = &[SysArg {
        dirfd: Some(if is32 { 4 } else { 3 }),
        path: if req.data.args[pidx] != 0 {
            Some(pidx)
        } else {
            None
        },
        fsflags,
        ..Default::default()
    }];

    syscall_path_handler(
        request,
        "fanotify_mark",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            // SAFETY: SysArg has one element.
            #[allow(clippy::disallowed_methods)]
            let path = path_args.0.as_ref().unwrap();

            let base = if path.base.is_empty() {
                // Regular file.
                Some(XPath::from_bytes(b"."))
            } else {
                // Symbolic link.
                Some(path.base)
            };

            // Get the FANotify FD.
            let fd = request.get_fd(req.data.args[0] as RawFd)?;

            // SAFETY: Strip FAN_{ACCESS,ACCESS_PERM,MODIFY}
            // if we're marking a sidechannel device.
            let mut mask = req.data.args[2];
            if let Some(fd) = &path.dir {
                if is_sidechannel_device(fd_mode(fd)?) {
                    mask &= !(libc::FAN_ACCESS | libc::FAN_ACCESS_PERM | libc::FAN_MODIFY);
                }
            }

            // SAFETY: Handle base path in a TOCTOU-free way.
            let mut flags: libc::c_uint = req.data.args[1].try_into().or(Err(Errno::EINVAL))?;
            flags |= libc::FAN_MARK_DONT_FOLLOW;

            fanotify_mark(
                &fd,
                flags,
                mask,
                path.dir.as_ref().map(|fd| fd.as_raw_fd()),
                base,
            )
            .map(|_| request.return_syscall(0))
        },
    )
}

fn sys_inotify_add_watch(request: UNotifyEventRequest) -> ScmpNotifResp {
    let req = request.scmpreq;

    #[allow(clippy::cast_possible_truncation)]
    let mask = AddWatchFlags::from_bits_truncate(req.data.args[2] as u32);

    // inotify(7) requires read access to the file or directory,
    // with the exception of symbolic links.
    let mut fsflags = FsFlags::MUST_PATH;
    if mask.contains(AddWatchFlags::IN_DONT_FOLLOW) {
        fsflags |= FsFlags::NO_FOLLOW_LAST;
    } else {
        fsflags |= FsFlags::WANT_READ;
    }

    let argv = &[SysArg {
        dirfd: None,
        path: Some(1),
        fsflags,
        ..Default::default()
    }];
    syscall_path_handler(
        request,
        "inotify_add_watch",
        argv,
        |path_args: PathArgs, request, sandbox| {
            drop(sandbox); // release the read-lock.

            // SAFETY: SysArg has one element.
            #[allow(clippy::disallowed_methods)]
            let path = path_args.0.as_ref().unwrap();

            if !path.base.is_empty() {
                // SAFETY: Ensure we have a direct FD.
                unreachable!("BUG: inotify_add_watch with base path!");
            }

            // SAFETY: ^^ empty base asserts dir is Some.
            #[allow(clippy::disallowed_methods)]
            let dfd = path.dir.as_ref().map(|fd| fd.as_raw_fd()).unwrap();

            // SAFETY:
            // 1. Strip IN_{ACCESS,MODIFY} if we're marking a sidechannel device.
            // 2. Strip IN_DONT_FOLLOW which has already been handled during canonicalization.
            let st_mode = fd_mode(&dfd)?;
            let mut mask = mask & !AddWatchFlags::IN_DONT_FOLLOW;
            if is_sidechannel_device(st_mode) {
                mask.remove(AddWatchFlags::IN_ACCESS);
                mask.remove(AddWatchFlags::IN_MODIFY);
            }

            // SAFETY: We open a FD to the path and then use the
            // proc path /proc/self/fd/$fd in address' path argument
            // to avoid symlink TOCTOU.
            let mut pfd = XPathBuf::from("/proc/self/fd");
            pfd.push_fd(dfd);

            // Get the INotify FD.
            let fd = request.get_fd(req.data.args[0] as RawFd)?;

            inotify_add_watch(&fd, &pfd, mask)
                .map(|retval| request.return_syscall(i64::from(retval)))
        },
    )
}

fn sys_memfd_create(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        const NAME_MAX: usize = 255;
        const MFD_NAME_PREFIX: &[u8] = b"/memfd:"; // The slash is not included in the limit.
        const MFD_NAME_PREFIX_LEN: usize = MFD_NAME_PREFIX.len() - 1;
        const MFD_NAME_MAX_LEN: usize = NAME_MAX - MFD_NAME_PREFIX_LEN;

        let req = request.scmpreq;
        let addr = req.data.args[0];
        if addr == 0 {
            // SAFETY: Return EFAULT for NULL name.
            return Err(Errno::EFAULT);
        }

        // If sandboxing for create capability is off, return immediately.
        let sandbox = request.get_sandbox();
        let check = sandbox.enabled(Capability::CAP_CREATE);
        let restrict_memfd = !sandbox.allow_unsafe_memfd();

        #[allow(clippy::cast_possible_truncation)]
        let mut flags = req.data.args[1] as libc::c_uint;
        if restrict_memfd {
            // SAFETY: Drop the executable flag and seal as nonexecutable.
            flags &= !MFD_EXEC;
            flags |= MFD_NOEXEC_SEAL;
        }

        let mut buf = [0u8; MFD_NAME_MAX_LEN];
        request.read_mem(&mut buf, addr)?;

        // SAFETY: If buffer has no null byte, return EINVAL as the path
        // is too long for us to handle.
        let name = CStr::from_bytes_until_nul(&buf).or(Err(Errno::EINVAL))?;

        // SAFETY: If name starts with `syd', return EINVAL as these
        // memory file descriptors are for Syd's internal use.
        if name.to_bytes().starts_with(b"syd") {
            return Err(Errno::EINVAL);
        }

        if check {
            // `check` may be false if restrict_memfd=1.
            // Check for access by appending the memfd prefix.
            let mut path = XPathBuf::from(MFD_NAME_PREFIX);
            path.append_bytes(name.to_bytes());

            // Unused when request.is_some()
            let process = RemoteProcess::new(request.scmpreq.pid());

            sandbox_path(
                Some(&request),
                &request.cache,
                &sandbox,
                &process,
                &path,
                Capability::CAP_CREATE,
                false,
                "memfd_create",
            )
            .or(Err(Errno::EACCES))?;
        }
        drop(sandbox); // release the read-lock.

        // Set CLOEXEC for our fd always, and
        // Set CLOEXEC for remote fd as necessary.
        let cloexec = flags & MFD_CLOEXEC != 0;
        flags |= MFD_CLOEXEC;

        // Access granted, emulate call and return the fd to the process.
        // SAFETY: nix does not support all flags we want to pass toe memfd_create(2).
        let fd = match Errno::result(unsafe { libc::memfd_create(name.as_ptr(), flags) }) {
            Ok(fd) => {
                // SAFETY: memfd_create returns a valid FD.
                unsafe { OwnedFd::from_raw_fd(fd as RawFd) }
            }
            Err(Errno::EINVAL) => {
                // Return ENOSYS rather than EINVAL if MFD_NOEXEC_SEAL is unsupported.
                // FIXME: This case includes other invalid flag combinations!
                return Err(Errno::ENOSYS);
            }
            Err(errno) => return Err(errno),
        };
        request.send_fd(&fd, cloexec)
    })
}

#[allow(clippy::cognitive_complexity)]
fn syscall_exec_handler(
    request: UNotifyEventRequest,
    syscall_name: &str,
    arg: SysArg,
) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        // If sandboxing for Exec is off, return immediately.
        let sandbox = request.get_sandbox();
        if !sandbox.enabled(Capability::CAP_EXEC) {
            // SAFETY: No restrictions requested, continue.
            // This is vulnerable to TOCTOU,
            // unfortunately we cannot emulate exec,
            // Check: https://bugzilla.kernel.org/show_bug.cgi?id=218501
            // The exec-TOCTOU-mitigator gives us a fair protection
            // against this, see the wait() function for context.
            return Ok(unsafe { request.continue_syscall() });
        }

        // Read remote path.
        let (path, _) = request.read_path(&sandbox, arg, false)?;

        // Call sandbox access checker.
        sandbox_path(
            Some(&request),
            &request.cache,
            &sandbox,
            &RemoteProcess::new(request.scmpreq.pid()), // Unused when request.is_some()
            path.abs(),
            Capability::CAP_EXEC,
            sandbox.enabled(Capability::CAP_STAT),
            syscall_name,
        )?;
        drop(sandbox); // release the read-lock.

        // SAFETY: This is vulnerable to TOCTOU,
        // unfortunately we cannot emulate exec,
        // Check: https://bugzilla.kernel.org/show_bug.cgi?id=218501
        // The exec-TOCTOU-mitigator gives us a fair protection
        // against this, see the wait() function for context.
        Ok(unsafe { request.continue_syscall() })
    })
}

/// Handles syscalls related to signal handling, protecting the syd
/// process and their threads from signals.
///
/// # Parameters
///
/// - `request`: User notification request from seccomp.
/// - `thread`: true if the system call is directed to a thread rather
///   than a process.
/// - `group`: true if the system call has both progress group id and
///   process id (tgkill), false otherwise.
///
/// - `ScmpNotifResp`: Response indicating the result of the syscall handling.
#[allow(clippy::cognitive_complexity)]
fn syscall_signal_handler(
    request: UNotifyEventRequest,
    thread: bool,
    group: bool,
) -> ScmpNotifResp {
    let req = request.scmpreq;
    #[allow(clippy::cast_possible_truncation)]
    #[allow(clippy::cast_possible_wrap)]
    let pid = req.data.args[0] as libc::pid_t;
    #[allow(clippy::cast_possible_truncation)]
    #[allow(clippy::cast_possible_wrap)]
    let tid = req.data.args[1] as libc::pid_t;

    // Validate pid/tid.
    if thread && (pid <= 0 || (group && tid <= 0)) {
        return request.fail_syscall(Errno::EINVAL);
    }

    // Guard syd tasks.
    //
    // SAFETY: Return success when denying for stealth.
    // Otherwise the allowed 0 signal can be misused
    // to identify a Syd process.
    //
    // pid <=0 only for kill/sigqueue here.
    match pid {
        0 => {
            // SAFETY: Guard against group signals.
            // kill(0, 9) -> Send signal to _current_ process group.
            match getpgid(Some(req.pid())) {
                Ok(pgrp) if pgrp == getpgrp() => {
                    // SAFETY: This is a version of killpg().
                    // We must stop this signal if Syd is in
                    // the same process group as the process, otherwise
                    // continue is safe. EACCES is no further
                    // information leak as sig==0 is pass-through.
                    return request.fail_syscall(Errno::EACCES);
                }
                Err(_) => {
                    // ESRCH is no further information leak as
                    // sig==0 is pass-through.
                    return request.fail_syscall(Errno::ESRCH);
                }
                _ => {}
            }
        }
        -1 => {
            // SAFETY: We do not allow mass signaling with -1.
            return request.fail_syscall(Errno::EACCES);
        }
        _ => {}
    }

    // kill and sigqueue support negative PIDs.
    let pid_abs = if thread { pid } else { pid.abs() };

    // Check for Syd tasks.
    let syd = Pid::this().as_raw();

    // SAFETY: Note, we deny with EACCES, rather than returning success
    // because we have a kernel-level bpf filter that _allows_ the
    // respective signaler system call _only when_ the signal is 0.
    // Therefore we're not leaking any further information by returning
    // EACCES here.
    if !thread && syd == pid_abs {
        return request.fail_syscall(Errno::EACCES);
    }

    if thread && syd == pid {
        return request.fail_syscall(Errno::EACCES);
    }

    if thread && group && syd == tid {
        return request.fail_syscall(Errno::EACCES);
    }

    // SAFETY: Check for Syd threads with the abstract PID.
    if !thread && Errno::result(unsafe { libc::syscall(libc::SYS_tgkill, syd, pid_abs, 0) }).is_ok()
    {
        return request.fail_syscall(Errno::EACCES);
    }

    // SAFETY: Check for Syd threads with the PID.
    if thread && Errno::result(unsafe { libc::syscall(libc::SYS_tgkill, syd, pid, 0) }).is_ok() {
        return request.fail_syscall(Errno::EACCES);
    }

    if thread
        && group
        && pid != tid
        && Errno::result(
            // SAFETY: Check for Syd threads with the TID.
            unsafe { libc::syscall(libc::SYS_tgkill, syd, tid, 0) },
        )
        .is_ok()
    {
        return request.fail_syscall(Errno::EACCES);
    }

    // Check signals directed to Syd's process group.
    let syd_pgid = getpgrp().as_raw();
    if !thread && syd_pgid == pid_abs {
        return request.fail_syscall(Errno::EACCES);
    }
    if thread && syd_pgid == pid {
        return request.fail_syscall(Errno::EACCES);
    }
    if thread && group && syd_pgid == tid {
        return request.fail_syscall(Errno::EACCES);
    }

    // SAFETY: This is safe because we haven't dereferenced
    // any pointers during access check.
    unsafe { request.continue_syscall() }
}

///
/// Handles syscalls related to paths, reducing code redundancy and ensuring a uniform way of dealing with paths.
///
/// # Parameters
///
/// - `request`: User notification request from seccomp.
/// - `syscall_name`: The name of the syscall being handled, used for logging and error reporting.
/// - `arg_mappings`: Non-empty list of argument mappings containing dirfd and path indexes, if applicable.
/// - `handler`: Closure that processes the constructed canonical paths and performs additional syscall-specific operations.
///
/// # Returns
///
/// - `ScmpNotifResp`: Response indicating the result of the syscall handling.
#[allow(clippy::cognitive_complexity)]
fn syscall_path_handler<H>(
    request: UNotifyEventRequest,
    syscall_name: &str,
    path_argv: &[SysArg],
    handler: H,
) -> ScmpNotifResp
where
    H: Fn(PathArgs, &UNotifyEventRequest, SandboxGuard) -> Result<ScmpNotifResp, Errno>,
{
    syscall_handler!(request, |request: UNotifyEventRequest| {
        let req = request.scmpreq;

        // Determine system call capabilities.
        let mut caps = Capability::try_from((req, syscall_name))?;

        // Check for chroot:
        //
        // Delay Chdir to allow the common `cd /`. use case
        // right after chroot.
        let sandbox = request.get_sandbox();
        if sandbox.is_chroot() && !caps.contains(Capability::CAP_CHDIR) {
            return Err(Errno::ENOENT);
        }

        // If sandboxing for all the selected capabilities is off, return immediately.
        let crypt = sandbox.enabled(Capability::CAP_CRYPT);
        let hide = sandbox.enabled(Capability::CAP_STAT);

        // EXCEPTION: We do want to return success
        // to _access_(2) calls to magic paths in
        // case the sandbox lock allows it.
        let mut magic = !(Sandbox::locked_once() || sandbox.locked_for(req.pid()))
            && memmem::find_iter(syscall_name.as_bytes(), b"access")
                .next()
                .is_some();

        let mut paths: [Option<CanonicalPath>; 2] = [None, None];
        for (idx, arg) in path_argv.iter().enumerate() {
            // Handle system calls that take a FD only,
            // such as fchmod, fchown, falllocate, ftruncate,
            // fgetxattr, fsetxattr safely and efficiently.
            if arg.path.is_some() {
                let (path, is_magic) = request.read_path(&sandbox, *arg, magic)?;
                magic = is_magic;

                if sandbox.is_chroot() {
                    return if caps.contains(Capability::CAP_CHDIR) && path.abs().is_rootfs() {
                        // SAFETY: Allow `cd /` after chroot.
                        Ok(unsafe { request.continue_syscall() })
                    } else {
                        Err(Errno::ENOENT)
                    };
                }

                paths[idx] = Some(path);
            } else if let Some(arg_dirfd) = arg.dirfd {
                let dirfd = req.data.args[arg_dirfd] as RawFd;

                if sandbox.is_chroot() {
                    return if caps.contains(Capability::CAP_CHDIR) {
                        // SAFETY: Do not allow fchdir after chroot.
                        Err(Errno::EACCES)
                    } else {
                        Err(Errno::ENOENT)
                    };
                }

                if dirfd != AT_FDCWD {
                    // SAFETY: Get the file descriptor before access check
                    // as it may change after which is a TOCTOU vector.
                    let fd = request.get_fd(dirfd)?;

                    // Handle ftruncate etc. for files with encryption in progress.
                    let crypt_path = if crypt {
                        if let Ok(inode) = fstatx(&fd, STATX_INO).map(|s| s.stx_ino) {
                            let mut found = None;
                            #[allow(clippy::disallowed_methods)]
                            let files = request.crypt_map.as_ref().unwrap();
                            for (path, map) in
                                &files.read().unwrap_or_else(|err| err.into_inner()).0
                            {
                                if inode == map.4 {
                                    found = Some(path.clone());
                                    break;
                                }
                            }
                            found
                        } else {
                            None
                        }
                    } else {
                        None
                    };

                    let mut path = if let Some(path) = crypt_path {
                        // SAFETY: Only regular files are encrypted.
                        CanonicalPath::new(path, FileType::Reg, arg.fsflags)?
                    } else {
                        CanonicalPath::new_fd(fd.into(), req.pid(), dirfd)?
                    };

                    if arg.flags.contains(SysFlags::UNSAFE_CONT) {
                        // FD not required if we're continuing...
                        path.dir = None;
                    }

                    paths[idx] = Some(path);
                } else {
                    let mut path =
                        CanonicalPath::new_fd(libc::AT_FDCWD.into(), req.pid(), libc::AT_FDCWD)?;

                    if arg.flags.contains(SysFlags::UNSAFE_CONT) {
                        // FD not required if we're continuing...
                        path.dir = None;
                    }

                    paths[idx] = Some(path);
                }
            } else {
                unreachable!("BUG: Both dirfd and path are None in SysArg!");
            }
        }

        if !magic {
            // Unused when request.is_some()
            let process = RemoteProcess::new(request.scmpreq.pid());

            // Call sandbox access checker, skip magic paths.
            match (&paths[0], &paths[1]) {
                (Some(path), None) => {
                    // Adjust capabilities.
                    if caps.contains(Capability::CAP_CREATE) && path.typ.is_some() {
                        caps.remove(Capability::CAP_CREATE);
                    }
                    if caps.contains(Capability::CAP_DELETE) && path.typ.is_none() {
                        caps.remove(Capability::CAP_DELETE);
                    }
                    if caps.contains(Capability::CAP_CHDIR) && path.typ != Some(FileType::Dir) {
                        caps.remove(Capability::CAP_CHDIR);
                    }
                    if caps.contains(Capability::CAP_MKDIR) && path.typ.is_some() {
                        caps.remove(Capability::CAP_MKDIR);
                    }

                    sandbox_path(
                        Some(&request),
                        &request.cache,
                        &sandbox,
                        &process,
                        path.abs(),
                        caps,
                        hide,
                        syscall_name,
                    )?
                }
                (Some(path_0), Some(path_1)) => {
                    // link, linkat, rename, renameat, renameat2.
                    // All of which have RENAME capability.
                    // It's the second argument that is being
                    // created.
                    sandbox_path(
                        Some(&request),
                        &request.cache,
                        &sandbox,
                        &process,
                        path_0.abs(),
                        Capability::CAP_RENAME,
                        hide,
                        syscall_name,
                    )?;

                    // Careful, rename* may overwrite, link* must create.
                    if path_1.typ.is_none() || !path_argv[1].fsflags.missing() {
                        sandbox_path(
                            Some(&request),
                            &request.cache,
                            &sandbox,
                            &process,
                            path_1.abs(),
                            Capability::CAP_CREATE,
                            hide,
                            syscall_name,
                        )?;
                    }
                }
                _ => unreachable!("BUG: number of path arguments is not 1 or 2!"),
            }
        }

        // SAFETY: Path hiding is done, now it is safe to:
        //
        // 1. Return EEXIST if options had MISS_LAST.
        // 2. Return ENOTDIR for non-directories with trailing slash.
        for (idx, path) in paths.iter_mut().enumerate() {
            if let Some(path) = path {
                let arg = if let Some(arg) = path_argv.get(idx) {
                    arg
                } else {
                    break;
                };

                if arg.fsflags.missing() && path.typ.is_some() {
                    return Err(Errno::EEXIST);
                }

                if let Some(file_type) = &path.typ {
                    if !matches!(file_type, FileType::Dir | FileType::MagicLnk(_, _))
                        && path.abs().last() == Some(b'/')
                    {
                        return Err(Errno::ENOTDIR);
                    }
                }
            }
        }

        // Call the system call handler.
        handler(
            PathArgs(paths[0].take(), paths[1].take()),
            &request,
            sandbox,
        )
    })
}

#[allow(clippy::cognitive_complexity)]
fn syscall_open_handler(
    request: UNotifyEventRequest,
    syscall: OpenSyscall,
    arg: SysArg,
    flags: OFlag,
    mode: Mode,
) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        // SAFETY: When emulating the open call we always open the file
        // descriptor with O_CLOEXEC flag for safety. Here, we mark the
        // state of the O_CLOEXEC flag to use it in seccomp_addfd call.
        // Mutability:
        //   1. flags is mutable because trace/allow_unsafe_open:0
        //      may change its value for O_PATH. Append-only may
        //      also edit flags.
        let o_cloexec = flags.contains(OFlag::O_CLOEXEC);
        let mut flags = flags | OFlag::O_CLOEXEC;

        // Determine capabilities based on access mode:
        //
        // 1. glibc does not include O_PATH to O_ACCMODE.
        // 2. musl defines O_PATH equal to O_EXEC and O_SEARCH,
        //    and O_ACCMODE is defined as O_ACCMODE|O_SEARCH.
        // Here we force the second behaviour by explicitly
        // adding O_PATH into O_ACCMODE. This works on both libcs.
        // See: https://www.openwall.com/lists/musl/2013/02/22/1
        //
        // TODO: Confine O_PATH file descriptors with Stat category,
        // rather than Read category when they can be properly emulated.
        // See: https://bugzilla.kernel.org/show_bug.cgi?id=218501
        let (mut caps, o_path, o_rdwr) = match flags.bits() & (libc::O_ACCMODE | libc::O_PATH) {
            libc::O_RDONLY => (Capability::CAP_READ, false, false),
            libc::O_WRONLY => (Capability::CAP_WRITE, false, false),
            libc::O_RDWR => (Capability::CAP_READ | Capability::CAP_WRITE, false, true),
            libc::O_PATH => (Capability::CAP_READ, true, false),
            _ => return Err(Errno::EINVAL), // Invalid access mode.
        };

        let o_creat = flags.contains(OFlag::O_CREAT);
        let o_tmpfl = flags.contains(OFlag::O_TMPFILE);
        let o_trunc = flags.contains(OFlag::O_TRUNC);
        let mut o_mask = o_creat || o_tmpfl;

        // O_PATH|O_CREAT and O_PATH|O_TMPFILE combinations are invalid.
        if o_path && o_mask {
            return Err(Errno::EINVAL);
        }

        // Quoting open(2):
        //
        // Currently, it is not possible to enable signal-driven I/O by
        // specifying O_ASYNC when calling open(); use fcntl(2) to
        // enable this flag.
        //
        // TODO: When this is possible, we must use fcntl to redirect signals
        // to the sandbox thread making the actual open call or else we break
        // async I/O.
        // let o_async = flags.contains(OFlag::O_ASYNC);

        let req = request.scmpreq;

        // SAFETY: For exclusive creating opens we need to take a write
        // lock, otherwise there can be a race condition where two
        // syd_emu threads race to create the same file
        // simultaneously...
        let sandbox = if arg.fsflags.missing() {
            request.get_mut_sandbox()
        } else {
            request.get_sandbox()
        };

        // Check for chroot.
        if sandbox.is_chroot() {
            return Err(Errno::ENOENT);
        }

        #[allow(clippy::cast_possible_wrap)]
        let is_lock = Sandbox::locked_once() || sandbox.locked_for(req.pid());

        // We use exactly one of Mktemp, Create, Truncate sandboxing
        // categories to improve usability, ie the priority is
        // O_TMPFILE > O_CREAT > O_TRUNC.
        if o_tmpfl {
            caps.insert(Capability::CAP_MKTEMP);
        } else if o_creat {
            caps.insert(Capability::CAP_CREATE);
        } else if o_trunc {
            caps.insert(Capability::CAP_TRUNCATE);
        }

        /*
        if sandbox.verbose {
            debug!("ctx": "open", "op": "init",
                "cap": caps,
                "sbc": sandbox.state,
                "cwr": caps.intersects(Capability::CAP_WRSET),
                "arg": format!("{arg:?}"),
                "flg": format!("{flags:?}"),
                "mod": format!("{mode:?}"),
                "req": &request);
        } else {
            debug!("ctx": "open", "op": "init",
                "cap": caps,
                "sbc": sandbox.state,
                "cwr": caps.intersects(Capability::CAP_WRSET),
                "arg": format!("{arg:?}"),
                "flg": format!("{flags:?}"),
                "mod": format!("{mode:?}"),
                "pid": request.scmpreq.pid);
        }
        */

        // SAFETY: Apply deny_dotdot as necessary for open family.
        let mut arg = arg;
        if sandbox.deny_dotdot() {
            arg.fsflags.insert(FsFlags::NO_RESOLVE_DOTDOT);
        }

        // Read the remote path.
        // If lock is on do not check for magic path.
        let (mut path, magic) = request.read_path(&sandbox, arg, !is_lock)?;

        /*
        if sandbox.verbose {
            debug!("ctx": "open", "op": "read_path",
                "path": &path, "magic": magic,
                "req": &request);
        } else {
            debug!("ctx": "open", "op": "read_path",
                "path": &path, "magic": magic,
                "pid": request.scmpreq.pid().as_raw());
        }
        */

        // Handle the special /dev/syd paths.
        if magic {
            if o_path {
                return Err(Errno::EINVAL);
            }

            let fd = if caps.contains(Capability::CAP_READ) {
                let fd = create_memfd(b"syd-box\0", MFD_ALLOW_SEALING)?;
                let mut file = File::from(fd);

                const FLEN: usize = MAGIC_PREFIX.len() + 3; /* .{el,sh} */
                let fack = path.abs().len() == FLEN;
                let fext = path.abs().extension();
                let data = if path.abs().is_equal(MAGIC_PREFIX) {
                    Cow::Owned(serde_json::to_string_pretty(&*sandbox).or(Err(Errno::EINVAL))?)
                } else if fack && fext.map(|ext| ext.is_equal(b"el")).unwrap_or(false) {
                    Cow::Borrowed(SYD_EL)
                } else if fack && fext.map(|ext| ext.is_equal(b"sh")).unwrap_or(false) {
                    Cow::Borrowed(ESYD_SH)
                } else {
                    return Err(Errno::EINVAL);
                };
                drop(sandbox); // release the lock (may be read or write).

                file.write_all(data.as_bytes()).or(Err(Errno::EIO))?;
                file.rewind().or(Err(Errno::EIO))?;

                // SAFETY: Deny further writes to the file descriptor.
                seal_memfd(&file)?;

                MaybeFd::Owned(OwnedFd::from(file))
            } else {
                MaybeFd::RawFd(NULL_FD())
            };

            // Send the file descriptor to the process and return the fd no.
            return request.send_fd(&fd, true);
        }

        // Validate file flags based on file type information.
        let (is_blocking, may_crypt) = if let Some(ref file_type) = path.typ {
            if o_creat && !o_tmpfl {
                // Creating open with existing file:
                //
                // Remove Create from capabilities, and add back
                // Truncate capability as necessary to improve
                // usability.
                caps.remove(Capability::CAP_CREATE);
                if o_trunc {
                    caps.insert(Capability::CAP_TRUNCATE);
                }
            }

            match *file_type {
                FileType::Reg => {
                    // SAFETY:
                    // 1. We only ever attempt to encrypt regular files.
                    // 2. We do not support interruptions on regular file blocks.
                    (false, true)
                }
                FileType::Dir => {
                    // We know it's a directory, so let's assert it.
                    // Unless path ends with a slash, in that case
                    // we don't want to break expectations.
                    if path.abs().last() != Some(b'/') {
                        flags.insert(OFlag::O_DIRECTORY);
                    }

                    // Change capability from Read to Readdir.
                    caps.remove(Capability::CAP_READ);
                    caps.insert(Capability::CAP_READDIR);

                    (false, false)
                }
                FileType::Blk | FileType::Unk => {
                    // SAFETY:
                    // 1. Do not allow access to block devices.
                    // 2. Do not allow access to files with unknown types.
                    // 3. Deny with ENOENT for stealth.
                    return Err(Errno::ENOENT);
                }
                FileType::MagicLnk(_, _) => {
                    // SAFETY/TODO: Implement further restrictions on magic-links here.
                    if file_type.is_magic_dir() {
                        // Change capability from Read to Readdir.
                        caps.remove(Capability::CAP_READ);
                        caps.insert(Capability::CAP_READDIR);
                    }

                    // SAFETY: This may or may not block, better safe than sorry.
                    (
                        !(flags.contains(OFlag::O_NONBLOCK) || flags.contains(OFlag::O_NDELAY)),
                        false,
                    )
                }
                FileType::Lnk => {
                    // SAFETY: This may or may not block, better safe than sorry.
                    (
                        !(flags.contains(OFlag::O_NONBLOCK) || flags.contains(OFlag::O_NDELAY)),
                        false,
                    )
                }
                FileType::Chr | FileType::Fifo | FileType::Sock => {
                    // SAFETY: character devices, fifos and sockets may block.
                    (
                        !(flags.contains(OFlag::O_NONBLOCK) || flags.contains(OFlag::O_NDELAY)),
                        false,
                    )
                }
            }
        } else if !o_creat {
            // Non-creating open on non-existing file.
            return Err(Errno::ENOENT);
        } else {
            // Creating open on non-existing file.
            //
            // Note, adding O_EXCL to flags here to assert file creation
            // may result in a race condition where a fellow Syd thread
            // can race with this one in creating the same file, making
            // the thread losing the race return a confusing EEXIST error.
            // Therefore we avoid doing that, see:
            // https://gitlab.exherbo.org/sydbox/sydbox/-/issues/211
            //
            // flags.insert(OFlag::O_EXCL);

            // Non-existing files do not block.
            // Non-existing files may be encrypted from scratch.
            (false, true)
        };

        // SAFETY:
        // 1. We must provide safe access to sandbox process' controlling terminal.
        // 2. Both "/dev/tty" and the original tty path are checked for access.
        let pid = req.pid();
        let dev_tty = Cow::Borrowed(XPath::from_bytes(b"/dev/tty"));
        let has_tty = if path.abs().is_equal(dev_tty.as_bytes()) {
            let dev_tty = proc_tty(pid)?;
            if !request.is_valid() {
                return Err(Errno::ESRCH);
            }
            path = CanonicalPath::new_tty(dev_tty)?;

            true // TTY.
        } else {
            // SAFETY: Ensure the sandbox process cannot
            // acquire a new controlling terminal other
            // than what they already have.
            // Note, O_NOCTTY is invalid with O_PATH,
            // but we don't care for now since we'll change it
            // to O_RDONLY later as a mitigation due to our
            // inability to emulate them.
            // See: https://bugzilla.kernel.org/show_bug.cgi?id=218501
            flags.insert(OFlag::O_NOCTTY);

            false // Not a TTY.
        };

        // Sandboxing.
        let has_write = caps.intersects(Capability::CAP_WRSET);
        let orig_caps = caps;
        let caps = sandbox.getcaps(orig_caps); // Get enabled caps.

        let mut action = Action::Allow;
        let mut filter = false;

        let mut path_check = if !caps.is_empty() {
            // Convert /proc/${pid} to /proc/self as necessary.
            let path_check = if let Some(p) = path.abs().split_prefix(b"/proc") {
                let mut buf = itoa::Buffer::new();
                let req = request.scmpreq;
                let pid = buf.format(req.pid);
                if let Some(p) = p.split_prefix(pid.as_bytes()) {
                    let mut pdir = XPathBuf::from("/proc/self");
                    pdir.push(p.as_bytes());
                    Cow::Owned(pdir)
                } else {
                    Cow::Borrowed(path.abs())
                }
            } else {
                Cow::Borrowed(path.abs())
            };

            if !has_tty {
                for cap in caps {
                    let (new_action, new_filter) =
                        request.cache.check_path(&sandbox, cap, &path_check);
                    if new_action >= action {
                        action = new_action;
                    }
                    if !filter && new_filter {
                        filter = true;
                    }
                }
            } else {
                // Both "/dev/tty" and the original tty path are checked for access.
                // The more critical action wins.
                for path in [&path_check, &dev_tty] {
                    for cap in caps {
                        let (new_action, new_filter) =
                            request.cache.check_path(&sandbox, cap, path);
                        if new_action >= action {
                            action = new_action;
                        }
                        if !filter && new_filter {
                            filter = true;
                        }
                    }
                }
            }
            path_check
        } else {
            Cow::Borrowed(path.abs())
        };

        let (hidden, mut crypted) = if action.is_denying() {
            // No need to check for mask when denying.
            // No need to check for encryption when denying.
            (request.cache.is_hidden(&sandbox, &path_check), false)
        } else {
            // No need for hidden check if we're allowing.
            // SAFETY:
            // 1. Check for encrypted path and mark for later.
            // 2. Check for masked path and change path to /dev/null.
            // 3. Check for append-only path and edit flags argument.
            // We perform these check only if we're allowing.
            let crypted = if request.cache.is_masked(&sandbox, &path_check) {
                path = CanonicalPath::new_null();
                path_check = Cow::Borrowed(path.abs());
                false // masked path is not encrypted.
            } else if sandbox.enabled(Capability::CAP_CRYPT) {
                may_crypt && request.cache.is_crypt(&sandbox, &path_check)
            } else {
                false // encryption not enabled for path.
            };

            // Check for append-only path and edit flags argument.
            // Temporary files can not be made append-only.
            if has_write && request.cache.is_append(&sandbox, &path_check) {
                flags.insert(OFlag::O_APPEND);
                flags.remove(OFlag::O_TRUNC);

                if sandbox.verbose {
                    info!("ctx": "open", "op": "set_append_only",
                            "msg": "added O_APPEND and removed O_TRUNC from open flags",
                            "sys": request.syscall, "path": &path_check,
                            "flags": format!("{flags:?}"),
                            "cap": caps,
                            "cap_write_set": Capability::CAP_WRSET,
                            "req": &request);
                } else {
                    info!("ctx": "open", "op": "set_append_only",
                            "msg": "added O_APPEND and removed O_TRUNC from open flags",
                            "sys": request.syscall, "path": &path_check,
                            "flags": format!("{flags:?}"),
                            "cap": caps,
                            "cap_write_set": Capability::CAP_WRSET,
                            "pid": request.scmpreq.pid);
                }
            }

            (false, crypted)
        };

        let force_umask = sandbox.umask;
        let verbose = sandbox.verbose;
        let unsafe_open_path = sandbox.allow_unsafe_open_path();
        let unsafe_open_cdev = sandbox.allow_unsafe_open_cdev();
        let restrict_memfd = !sandbox.allow_unsafe_memfd();
        let setup_fds = sandbox.crypt_setup();
        let crypt_tmp = if crypted {
            sandbox.crypt_tmp.as_ref().map(|fd| fd.as_raw_fd())
        } else {
            None
        };
        drop(sandbox); // release the lock (may be read or write).

        // Perform action: allow->emulate, deny->log.
        if !filter && action >= Action::Warn && log_enabled!(LogLevel::Warn) {
            let grp = caps.to_string().to_ascii_lowercase();
            if verbose {
                warn!("ctx": "access", "cap": caps, "act": action,
                    "sys": request.syscall, "path": &path_check,
                    "open_flags": format!("{flags:?}"),
                    "open_mode": format!("{mode:?}"),
                    "tip": format!("configure `allow/{grp}+{path_check}'"),
                    "req": &request);
            } else {
                warn!("ctx": "access", "cap": caps, "act": action,
                    "sys": request.syscall, "path": &path_check,
                    "open_flags": format!("{flags:?}"),
                    "open_mode": format!("{mode:?}"),
                    "tip": format!("configure `allow/{grp}+{path_check}'"),
                    "pid": request.scmpreq.pid);
            }
        }

        // SAFETY: Access check is done, now it is safe to:
        //
        // 1. Return ENOENT if path is hidden.
        // 2. Return EEXIST if options include MISS_LAST.
        // 3. Return ENOTDIR for non-directories with trailing slash.
        // 4. Return EISDIR for write opens on directories.
        // 5. Return ELOOP for symlinks unless O_NOFOLLOW was passed.

        // We check for the actions Deny|Filter here as other actions
        // such as Panic, Stop, Kill are handled afterwards as necessary.
        if hidden && matches!(action, Action::Deny | Action::Filter) {
            return Err(Errno::ENOENT);
        }

        if arg.fsflags.missing() && path.typ.is_some() {
            // Exclusive open for existing file.
            return Err(Errno::EEXIST);
        }

        if let Some(file_type) = &path.typ {
            if !matches!(file_type, FileType::Dir | FileType::MagicLnk(_, _))
                && path.abs().last() == Some(b'/')
            {
                return Err(Errno::ENOTDIR);
            }
        }

        if let Some(FileType::Dir) = &path.typ {
            if !o_tmpfl {
                if orig_caps.can_write() {
                    // Open for write on directory.
                    return Err(Errno::EISDIR);
                } else if o_creat && path.abs().last() == Some(b'/') {
                    // Creating open on directory.
                    return Err(Errno::EISDIR);
                }
            }
        }

        // SAFETY: Return EPERM for {/dev,/proc}/kmsg,
        // so dmesg(1) falls back to syslog(2) which we provide.
        // EPERM is fine as we do this after the access check
        // so path hiding was already done as necessary.
        if !has_tty
            && ((path.typ == Some(FileType::Chr) && path.abs().is_equal(b"/dev/kmsg"))
                || path.abs().is_equal(b"/proc/kmsg"))
        {
            return Err(Errno::EPERM);
        }

        // SAFETY: Do not follow (magic) symlinks after canonicalization.
        // Exception: Last component is allowed with O_NOFOLLOW.
        if let Some(FileType::Lnk) = &path.typ {
            if !flags.contains(OFlag::O_NOFOLLOW) {
                return Err(Errno::ELOOP);
            }
        }

        match action {
            Action::Allow | Action::Warn => {
                // The system call is allowed.
                // To prevent TOCTOU, we open the file ourselves,
                // and put the file descriptor to the process'
                // address space with SECCOMP_IOCTL_NOTIF_ADDFD.
                if o_path {
                    if unsafe_open_path {
                        // SAFETY:
                        // seccomp addfd operation returns EBADF for O_PATH file
                        // descriptors so there's no TOCTOU-free way to emulate
                        // this as of yet. However we did our best by
                        // delaying continue up to this point, thereby
                        // including the open request to the sandbox access
                        // check.
                        return unsafe { Ok(request.continue_syscall()) };
                    }
                    // SAFETY: Turn O_PATH flag to O_RDONLY for successful emulation.
                    flags.remove(OFlag::O_PATH);
                    flags.insert(OFlag::O_RDONLY);
                } else if unsafe_open_cdev
                    && o_rdwr
                    && !o_creat
                    && !o_trunc
                    && !o_tmpfl
                    && path.typ == Some(FileType::Chr)
                {
                    // SAFETY:
                    //
                    // trace/allow_unsafe_open_cdev:true
                    //
                    // 1. Some character devices, such as AMD GPUs,
                    //    require per-application access to the GPU
                    //    device, therefore opening the device in the
                    //    Syd emulator thread and then continuing the
                    //    subsequent ioctl(2) system calls in the
                    //    sandbox process is going to return EBADF.
                    //    Until, Syd has a way to fully emulate the
                    //    ioctl(2) request space and are able to call
                    //    ioctl(2) directly from Syd emulator threads,
                    //    this option may be used to access such
                    //    character devices. Note, setting this option
                    //    opens a TOCTOU attack vector, whereby the
                    //    sandbox process can open an arbitrary file
                    //    instead of the character device in question!
                    // 2. Syd does not CONTINUE the system call if at
                    //    least one of the flags
                    //    O_CREAT|O_TRUNC|O_TMPFILE is set in flags
                    //    argument to limit the scope of the TOCTOU
                    //    attack vector.
                    //  3. Syd CONTINUEs the system call if and only if
                    //     O_RDWR is set in the flags argument to limit
                    //     the scope of the TOCTOU attack vector.
                    //  4. Syd returns ENOSYS for openat2(2) rather than
                    //     CONTINUE'ing the system call to prevent the
                    //     "struct open_how" pointer indirection to
                    //     bypass the restrictions applied to the flags
                    //     argument.
                    //  5. This option may be changed at runtime, so it
                    //     is highly recommended to unset this option
                    //     right after the respective character device
                    //     is open using the syd(2) API to prevent the
                    //     TOCTOU attack vector.
                    return if syscall != OpenSyscall::Openat2 {
                        // SAFETY: See above, stupid clippy.
                        unsafe { Ok(request.continue_syscall()) }
                    } else {
                        Err(Errno::ENOSYS)
                    };
                }

                // SAFETY: We have already resolved the symbolic
                // links in the path as necessary, to prevent a
                // time-of-check to time-of-use vector:
                // 1. Add O_NOFOLLOW to flags.
                // 2. Add RESOLVE_BENEATH to flags.
                // 3. Add RESOLVE_NO_MAGICLINKS | RESOLVE_NO_SYMLINKS to flags.
                // 4. Mode must be 0 if O_CREAT or O_TMPFILE is not in flags.
                // Note, magic symbolic links are an exception here.
                let mut resolve_flags = ResolveFlag::empty();
                if matches!(path.typ, Some(FileType::MagicLnk(_, _))) {
                    if flags.contains(OFlag::O_NOFOLLOW) {
                        // Magic symlink O_PATH fds were continued
                        // as necessary if relevant unsafe options
                        // were set. After this point, we have to
                        // ELOOP.
                        return Err(Errno::ELOOP);
                    }

                    // SAFETY: Ensure we can never acquire a
                    // controlling terminal by misguided magic symlink.
                    flags.insert(OFlag::O_NOCTTY);

                    // SAFETY: Ensure no encryption or file creation
                    // attempts can ever happen for magic symlinks.
                    o_mask = false;
                    crypted = false;
                    flags.remove(OFlag::O_CREAT);
                    flags.remove(OFlag::O_TMPFILE);
                } else {
                    flags.insert(OFlag::O_NOFOLLOW);
                    resolve_flags.insert(ResolveFlag::RESOLVE_BENEATH);
                    resolve_flags.insert(ResolveFlag::RESOLVE_NO_MAGICLINKS);
                    resolve_flags.insert(ResolveFlag::RESOLVE_NO_SYMLINKS);
                }

                // Prepare `struct open_how`.
                // Mode is empty because we handle creation differently.
                let how = OpenHow::new().flags(flags).resolve(resolve_flags);

                let fd: OwnedFd = if crypted {
                    // Handle Encryption.
                    if let Some(fd) = handle_crypt(
                        setup_fds,
                        &request,
                        &path,
                        crypt_tmp,
                        flags,
                        mode,
                        force_umask,
                        o_cloexec,
                        restrict_memfd,
                    )? {
                        // read-only encryption.
                        fd
                    } else {
                        // read-write encryption.
                        // We do not need to send a response,
                        // return a dummy response which will be
                        // skipped by the handler.
                        return Ok(ScmpNotifResp::new(0, 0, 0, 0));
                    }
                } else if path.base.is_empty() {
                    // Existing path: Construct path to /proc magic symlink,
                    // or pre-open file descriptor.
                    //
                    // SAFETY: Note, the path may be borrowed here, ie
                    // it can be a fd to the preopen `/`, `/proc` or
                    // `/dev/null` fds. In these cases, we still want to
                    // reopen, because the fd we're going to send will
                    // share the same open file description and we do
                    // not want to mess up file offsets for everyone.
                    let mut pfd = XPathBuf::from("self/fd");

                    // SAFETY: ^^ empty base asserts dir is Some.
                    #[allow(clippy::disallowed_methods)]
                    pfd.push_fd(path.dir.as_ref().map(|fd| fd.as_raw_fd()).unwrap());

                    // Reopen the `O_PATH` path fd with the requested flags.
                    flags.remove(OFlag::O_NOFOLLOW);
                    let how = safe_open_how_magicsym(flags);

                    // SAFETY: Record blocking call so it can get invalidated.
                    if is_blocking {
                        request.cache.add_sys_block(req, false)?;
                    }

                    #[allow(clippy::disallowed_methods)]
                    let result = openat2(PROC_FD(), &pfd, how).map(|fd| {
                        // SAFETY: openat2 returns a valid FD.
                        unsafe { OwnedFd::from_raw_fd(fd) }
                    });

                    // Remove invalidation record unless interrupted.
                    if is_blocking && !matches!(result, Err(Errno::EINTR)) {
                        request.cache.del_sys_block(req.id);
                    }

                    result?
                } else if o_mask {
                    // Cannot be O_PATH or encrypted fd!
                    // SAFETY: If we're creating the file,
                    // we must fork so we can apply the umask
                    // and still honour POSIX ACLs.
                    handle_creat(&request, &path, flags, mode, force_umask)?
                } else {
                    // SAFETY: Record blocking call so it can get invalidated.
                    if is_blocking {
                        request.cache.add_sys_block(req, false)?;
                    }

                    // All set, open the file.
                    let fd = path
                        .dir
                        .as_ref()
                        .map(|fd| fd.as_raw_fd())
                        .unwrap_or(libc::AT_FDCWD);

                    #[allow(clippy::disallowed_methods)]
                    let result = openat2(fd, path.base, how).map(|fd| {
                        // SAFETY: openat2 returns a valid FD.
                        unsafe { OwnedFd::from_raw_fd(fd) }
                    });

                    // Remove invalidation record unless interrupted.
                    if is_blocking && !matches!(result, Err(Errno::EINTR)) {
                        request.cache.del_sys_block(req.id);
                    }

                    result?
                };

                // File opened successfully, return to caller at one go.
                request.send_fd(&fd, o_cloexec)
            }
            Action::Deny | Action::Filter if hidden => Err(Errno::ENOENT),
            Action::Deny | Action::Filter => Err(Errno::EACCES),
            Action::Panic => panic!(),
            Action::Exit => std::process::exit(libc::EACCES),
            action => {
                // Stop|Kill
                let _ = request.kill(action);
                Err(Errno::EACCES)
            }
        }
    })
}

/// Handle open() calls.
#[allow(clippy::disallowed_methods)]
fn do_open(path: &CanonicalPath, mut safe_flags: OFlag) -> Result<OwnedFd, Errno> {
    if path.base.is_empty() {
        // Existing path: Construct path to proc magic symlink.
        let mut pfd = XPathBuf::from("self/fd");

        // SAFETY: ^^ empty base asserts dir is Some.
        #[allow(clippy::disallowed_methods)]
        pfd.push_fd(path.dir.as_ref().map(|fd| fd.as_raw_fd()).unwrap());

        // Reopen the `O_PATH` path fd with the requested flags.
        safe_flags.remove(OFlag::O_NOFOLLOW);

        safe_open_magicsym(Some(&PROC_FILE()), &pfd, safe_flags)
    } else {
        // Return a read-only fd to the underlying encrypted file.
        let how = OpenHow::new().flags(safe_flags).resolve(
            ResolveFlag::RESOLVE_BENEATH
                | ResolveFlag::RESOLVE_NO_MAGICLINKS
                | ResolveFlag::RESOLVE_NO_SYMLINKS,
        );

        let (fd, base) = if let Some(ref fd) = path.dir {
            (fd.as_raw_fd(), path.base)
        } else if path.abs().is_dev() {
            (
                DEV_FD(),
                XPath::from_bytes(&path.abs().as_bytes()[b"/dev/".len()..]),
            )
        } else if path.abs().is_proc() {
            (
                PROC_FD(),
                XPath::from_bytes(&path.abs().as_bytes()[b"/proc/".len()..]),
            )
        } else if path.abs().is_sys() {
            (
                SYS_FD(),
                XPath::from_bytes(&path.abs().as_bytes()[b"/sys/".len()..]),
            )
        } else {
            (
                ROOT_FD(),
                XPath::from_bytes(&path.abs().as_bytes()[b"/".len()..]),
            )
        };

        openat2(fd, base, how).map(|fd| {
            // SAFETY: openat2 returns a valid FD.
            unsafe { OwnedFd::from_raw_fd(fd) }
        })
    }
}

/// Handle open() calls for encrypted files.
#[allow(clippy::too_many_arguments)]
fn handle_crypt(
    setup_fds: Result<(RawFd, RawFd), Errno>,
    request: &UNotifyEventRequest,
    path: &CanonicalPath,
    tmpdir: Option<RawFd>,
    safe_flags: OFlag,
    mode: Mode,
    force_umask: Option<Mode>,
    o_cloexec: bool,
    restrict_memfd: bool,
) -> Result<Option<OwnedFd>, Errno> {
    let my_mode = AesMod::from(safe_flags);
    #[allow(clippy::disallowed_methods)]
    let files = request.crypt_map.as_ref().unwrap();
    let maybe = {
        files
            .read()
            .unwrap_or_else(|err| err.into_inner())
            .0
            .get(path.abs())
            .map(|(fd, _, mode, _, _, _)| (*fd, *mode))
    };
    if let Some((fd, file_mode)) = maybe {
        // Open a new file description.
        // Lock it for read and pass to sandbox process.
        let mut flags = safe_flags;
        flags.remove(OFlag::O_NOFOLLOW);
        if flags.contains(OFlag::O_WRONLY) {
            // Promote O_WRONLY to O_RDWR,
            // so that we can hold an OFD read-lock.
            flags.remove(OFlag::O_WRONLY);
            flags.insert(OFlag::O_RDWR);
        }

        let mut pfd = XPathBuf::from("self/fd");
        pfd.push_fd(fd.as_raw_fd());

        if let Ok(fd) = safe_open_magicsym(Some(&PROC_FILE()), &pfd, flags) {
            // SAFETY: If our attempt to lock fails,
            // aes thread has already taken over!
            if lock_fd(&fd, false, false).is_ok() {
                if my_mode > file_mode {
                    // File mode upgraded, update AesMap.
                    let mut files = files.write().unwrap_or_else(|err| err.into_inner());
                    if let Some(entry) = files.0.get_mut(path.abs()) {
                        entry.2 = my_mode;
                    }
                }
                return Ok(Some(fd));
            }
        }
    }

    // Promote O_WRONLY to O_RDWR and drop O_APPEND.
    // SAFETY: This fd is not exposed to sandbox process.
    let mut flags = safe_flags;
    flags.remove(OFlag::O_WRONLY);
    flags.insert(OFlag::O_RDWR);
    flags.remove(OFlag::O_APPEND);

    // Strip O_ASYNC|O_NDELAY|O_NONBLOCK.
    // We want blocking writes to the underlying fd.
    flags.remove(OFlag::O_ASYNC | OFlag::O_NDELAY | OFlag::O_NONBLOCK);

    // Open or create the file as read-write.
    //
    // Note, if `path.base.is_empty()` we have an existing file
    // which do_open is going to reopen using proc magic symlink.
    let create = !path.base.is_empty() && safe_flags.contains(OFlag::O_CREAT);
    let enc_fd = if create {
        handle_creat(request, path, flags, mode, force_umask)
    } else {
        do_open(path, flags)
    }?;

    // Hold a write-lock to ensure no concurrent Syd aes writes.
    // SAFETY: Block until we can acquire the lock to ensure safe
    // concurrent access _unless_ the open was a non-blocking open
    // in which case we happily return EAGAIN so the caller can
    // retry. Similarly, `aes_ctr_tmp` respects non-blocking
    // opens too and returns a non-blocking fd as necessary.
    let wait = !(safe_flags.contains(OFlag::O_NONBLOCK) || safe_flags.contains(OFlag::O_NDELAY));
    match lock_fd(&enc_fd, true, create || wait) {
        Ok(()) => {}
        Err(Errno::EAGAIN) if !wait => return Err(Errno::EAGAIN),
        Err(Errno::EAGAIN) => {
            // Wait a bit and try again to let the
            // writer thread finish so that we can
            // hopefully join in with the shared-fd.
            std::thread::sleep(AES_CYCLE_TIME);
            return handle_crypt(
                setup_fds,
                request,
                path,
                tmpdir,
                safe_flags,
                mode,
                force_umask,
                o_cloexec,
                restrict_memfd,
            );
        }
        Err(errno) => return Err(errno),
    };

    // Acquire encryption sockets.
    let setup_fds = setup_fds?;

    // Map decrypted version to memory/temporary FD.
    // SAFETY: This does not read plaintext into memory!
    // We use zero-copy with splice and pipes.
    // Note, enc_fd is an OwnedFd so in the event of
    // an aes_ctr_tmp error it'll be closed and the lock
    // will be released.
    let (fd, iv) = if let Some((fd, iv)) =
        aes_ctr_tmp(setup_fds, &enc_fd, safe_flags, tmpdir, restrict_memfd)?
    {
        (fd, iv)
    } else {
        // SAFETY:
        // 1. This is not a new file.
        // 2. This is not a Syd encrypted file.
        // Unlock and open as-is.
        unlock_fd(&enc_fd)?;
        return Ok(Some(enc_fd));
    };

    // Reopen a new instance to pass to the sandbox process.
    // This instance points to a different open file description!
    let mut pfd = XPathBuf::from("self/fd");
    pfd.push_fd(fd);

    let mut flags = safe_flags;
    flags.remove(
        OFlag::O_WRONLY | OFlag::O_ASYNC | OFlag::O_CREAT | OFlag::O_EXCL | OFlag::O_NOFOLLOW,
    );
    flags.insert(OFlag::O_RDWR);

    let aes_fd = safe_open_magicsym(Some(&PROC_FILE()), &pfd, flags)?;

    // SAFETY: No need to wait on this lock,
    // as we've just opened the file.
    lock_fd(&aes_fd, false, false)?;
    request.send_fd(&aes_fd, o_cloexec)?;
    // Record the inode so we can answer reliably on fstat.
    let inode = fstatx(&aes_fd, STATX_INO)
        .map(|statx| statx.stx_ino)
        .unwrap_or(0);
    // Close the send fd to get rid off our copy of the lock.
    drop(aes_fd);

    // Record encryption process information.
    {
        files
            .write()
            .unwrap_or_else(|err| err.into_inner())
            .0
            .insert(
                path.abs().to_owned(),
                (fd, enc_fd, my_mode, iv, inode, false),
            );
    }

    Ok(None)
}

/// Handle open() calls that can potentially create files.
#[allow(clippy::disallowed_methods)]
fn handle_creat(
    request: &UNotifyEventRequest,
    path: &CanonicalPath,
    safe_flags: OFlag,
    mut mode: Mode,
    force_umask: Option<Mode>,
) -> Result<OwnedFd, Errno> {
    // SAFETY: force_umask overrides POSIX ACLs.
    if let Some(mask) = force_umask {
        mode &= !mask;
    }

    let how = OpenHow::new().flags(safe_flags).mode(mode).resolve(
        ResolveFlag::RESOLVE_BENEATH
            | ResolveFlag::RESOLVE_NO_MAGICLINKS
            | ResolveFlag::RESOLVE_NO_SYMLINKS,
    );

    // Determine process umask to apply in the thread.
    let req = request.scmpreq;
    let mask = proc_umask(req.pid())?;

    // Set umask which is per-thread here.
    umask(mask);

    // All set, make the open call.
    let fd = path
        .dir
        .as_ref()
        .map(|fd| fd.as_raw_fd())
        .unwrap_or(libc::AT_FDCWD);
    openat2(fd, path.base, how).map(|fd| {
        // SAFETY: openat2 returns a valid FD on success.
        unsafe { OwnedFd::from_raw_fd(fd) }
    })
}

#[allow(clippy::cognitive_complexity)]
fn syscall_stat_handler(
    request: UNotifyEventRequest,
    arg: SysArg,
    arg_stat: usize,
    is32: bool,
) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        // Note: This is a virtual call handler,
        // `sandbox` is an upgradable read lock with exclusive access.
        // We'll either upgrade it or downgrade it based on magic lock.
        // Exception: Sandbox lock had been set and there's no turning back.
        let req = request.scmpreq;
        let sandbox = request.get_sandbox();
        let is_lock = Sandbox::locked_once() || sandbox.locked_for(req.pid());

        let is_crypt = sandbox.enabled(Capability::CAP_CRYPT);
        let is_stat = sandbox.enabled(Capability::CAP_STAT);

        // Check for chroot.
        if sandbox.is_chroot() {
            return Err(Errno::ENOENT);
        }

        // Read the remote path.
        // If lock is on do not check for magic path.
        let (mut path, magic) = request.read_path(&sandbox, arg, !is_lock)?;

        if !is_lock && magic {
            drop(sandbox); // release the read-lock.

            // Handle magic prefix (ie /dev/syd)
            let mut cmd = path
                .abs()
                .strip_prefix(MAGIC_PREFIX)
                .unwrap_or_else(|| XPath::from_bytes(&path.abs().as_bytes()[MAGIC_PREFIX.len()..]))
                .to_owned();
            // Careful here, Path::strip_prefix removes trailing slashes.
            if path.abs().ends_with_slash() {
                cmd.push(b"");
            }

            // Acquire a write lock to the sandbox.
            let mut sandbox = request.get_mut_sandbox();

            // Execute magic command.
            match cmd.as_os_str().as_bytes() {
                b"ghost" => {
                    // SAFETY: Reset sandbox to ensure no run-away execs.
                    sandbox.reset()?;

                    // Signal the poll process to exit.
                    return Err(Errno::EOWNERDEAD);
                }
                b"panic" => sandbox.panic()?,
                _ => {}
            }

            if cmd.is_empty() || cmd.is_equal(b".el") || cmd.is_equal(b".sh") {
                sandbox.config("")?;
            } else if let Some(cmd) = cmd.strip_prefix(b"load") {
                // We handle load specially here as it involves process access.
                // 1. Attempt to parse as FD, pidfd_getfd and load it.
                // 2. Attempt to parse as profile name if (1) fails.
                match parse_fd(cmd) {
                    Ok(remote_fd) => {
                        let fd = request.get_fd(remote_fd)?;
                        let file = BufReader::new(File::from(fd));
                        let mut imap = HashSet::default();
                        // SAFETY: parse_config() checks for the file name
                        // /dev/syd/load and disables config file include
                        // feature depending on this check.
                        if sandbox
                            .parse_config(file, XPath::from_bytes(b"/dev/syd/load"), &mut imap)
                            .is_err()
                        {
                            return Ok(request.fail_syscall(Errno::EINVAL));
                        }
                        // Fall through to emulate as /dev/null.
                    }
                    Err(Errno::EBADF) => {
                        if sandbox.parse_profile(&cmd.to_string()).is_err() {
                            return Ok(request.fail_syscall(Errno::EINVAL));
                        }
                        // Fall through to emulate as /dev/null.
                    }
                    Err(errno) => {
                        return Ok(request.fail_syscall(errno));
                    }
                }
            } else if let Ok(cmd) = std::str::from_utf8(cmd.as_bytes()) {
                sandbox.config(cmd)?;
            } else {
                // SAFETY: Invalid UTF-8 is not permitted.
                // To include non-UTF-8, hex-encode them.
                return Err(Errno::EINVAL);
            }
            drop(sandbox); // release the write-lock.

            // Magic command was successful:
            // Clear caches to ensure consistency.
            request.cache.path_cache.0.clear();
            request.cache.addr_cache.0.clear();

            // If the stat buffer is NULL, return immediately.
            if req.data.args[arg_stat] == 0 {
                return Ok(request.return_syscall(0));
            }
        } else {
            // Handle fstat for files with encryption in progress.
            let mut crypt_stat = false;
            if is_crypt && arg.path.is_none() {
                // SAFETY: SysArg.path is None asserting dirfd is Some fd!=AT_FDCWD.
                #[allow(clippy::disallowed_methods)]
                let fd = path.dir.as_ref().unwrap();
                if let Ok(inode) = fstatx(fd, STATX_INO).map(|s| s.stx_ino) {
                    #[allow(clippy::disallowed_methods)]
                    let files = request.crypt_map.as_ref().unwrap();
                    for (enc_path, map) in &files.read().unwrap_or_else(|err| err.into_inner()).0 {
                        if inode == map.4 {
                            // Found underlying encrypted file for the memory fd.
                            // Note, we only ever attempt to encrypt regular files.
                            path =
                                CanonicalPath::new(enc_path.clone(), FileType::Reg, arg.fsflags)?;
                            crypt_stat = true;
                            break;
                        }
                    }
                }
            }

            // SAFETY:
            // 1. Allow access to fd-only calls.
            // 2. Allow access to files with encryption in progress.
            // 3. Allow access to /memfd:syd-*. This prefix is internal
            //    to Syd and sandbox process cannot create memory file
            //    descriptors with this name prefix.
            if is_stat
                && !crypt_stat
                && arg.path.is_some()
                && !path.abs().starts_with(b"/memfd:syd-")
            {
                // Unused when request.is_some()
                let process = RemoteProcess::new(request.scmpreq.pid());

                sandbox_path(
                    Some(&request),
                    &request.cache,
                    &sandbox,
                    &process,
                    path.abs(),
                    Capability::CAP_STAT,
                    false,
                    "stat",
                )?;
            }

            drop(sandbox); // release the read-lock.
        }

        // SAFETY: Path hiding is done, now it is safe to:
        //
        // Return ENOTDIR for non-directories with trailing slash.
        if let Some(file_type) = &path.typ {
            if !matches!(file_type, FileType::Dir | FileType::MagicLnk(_, _))
                && path.abs().last() == Some(b'/')
            {
                return Err(Errno::ENOTDIR);
            }
        }

        let mut flags = if path.base.is_empty() {
            libc::AT_EMPTY_PATH
        } else {
            // SAFETY: After this point we are not permitted to resolve
            // symbolic links any longer or else we risk TOCTOU.
            libc::AT_SYMLINK_NOFOLLOW
        };

        #[allow(clippy::cast_possible_truncation)]
        if arg_stat == 4 {
            // statx

            // Support AT_STATX_* flags.
            flags |= req.data.args[2] as libc::c_int
                & !(libc::AT_SYMLINK_NOFOLLOW | libc::AT_EMPTY_PATH);

            // SAFETY: The sidechannel check below requires the mask
            // to have the following items:
            // 1. STATX_TYPE (to check for char/block device)
            // 2. STATX_MODE (to check for world readable/writable)
            // To ensure that here, we inject these two flags into
            // mask noting if they were set originally. This can be
            // in three ways,
            // (a) Explicitly setting STATX_{TYPE,MODE}.
            // (b) Explicitly setting STATX_BASIC_STATS.
            // (c) Setting the catch-all STATX_ALL flag.
            // After the statx call if the flags STATX_{TYPE,MODE}
            // were not set we clear stx_mode's type and mode bits
            // as necessary and also remove STATX_{TYPE,MODE} from
            // stx_mask as necessary.
            let mut mask = req.data.args[3] as libc::c_uint;
            let orig_mask = mask;
            let basic_stx = (orig_mask & STATX_BASIC_STATS) != 0;
            if !basic_stx {
                mask |= STATX_TYPE | STATX_MODE;
            }

            // Note, unlike statfs, stat does not EINTR.
            let mut statx = statx(path.dir.as_ref(), path.base, flags, mask)?;

            // SAFETY: Check if the file is a sidechannel device and
            // update its access and modification times to match the
            // creation time if it is. This prevents timing attacks on
            // block or character devices like /dev/ptmx using stat.
            if is_sidechannel_device(statx.stx_mode.into()) {
                statx.stx_atime = statx.stx_ctime;
                statx.stx_mtime = statx.stx_ctime;
            }

            // SAFETY: Restore mask, type and mode, see the comment above.
            #[allow(clippy::cast_possible_truncation)]
            if !basic_stx {
                if (orig_mask & STATX_TYPE) == 0 {
                    statx.stx_mode &= !libc::S_IFMT as u16;
                    statx.stx_mask &= !STATX_TYPE;
                }
                if (orig_mask & STATX_MODE) == 0 {
                    statx.stx_mode &= libc::S_IFMT as u16;
                    statx.stx_mask &= !STATX_MODE;
                }
            }

            // SAFETY: The following block creates an immutable byte
            // slice representing the memory of `statx`. We ensure that
            // the slice covers the entire memory of `statx` using
            // `std::mem::size_of_val`. Since `statx` is a stack
            // variable and we're only borrowing its memory for the
            // duration of the slice, there's no risk of `statx` being
            // deallocated while the slice exists. Additionally, we
            // ensure that the slice is not used outside of its valid
            // lifetime.
            let statx = unsafe {
                std::slice::from_raw_parts(
                    std::ptr::addr_of!(statx) as *const u8,
                    std::mem::size_of_val(&statx),
                )
            };
            let addr = req.data.args[4];
            if addr != 0 {
                request.write_mem(statx, addr)?;
            }
        } else {
            // "stat" | "fstat" | "lstat" | "newfstatat"

            // SAFETY: In libc we trust.
            // Note, unlike statfs, stat does not EINTR.
            let mut stat = fstatat64(path.dir.as_ref().map(|fd| fd.as_raw_fd()), path.base, flags)?;

            // SAFETY: Check if the file is a sidechannel device and
            // update its access and modification times to match the
            // creation time if it is. This prevents timing attacks on
            // block or character devices like /dev/ptmx using stat.
            if is_sidechannel_device(stat.st_mode) {
                stat.st_atime = stat.st_ctime;
                stat.st_mtime = stat.st_ctime;
                stat.st_atime_nsec = stat.st_ctime_nsec;
                stat.st_mtime_nsec = stat.st_ctime_nsec;
            }

            let addr = req.data.args[arg_stat];
            if addr != 0 {
                if is32 {
                    let stat32: crate::compat::stat32 = stat.into();

                    // SAFETY: The following block creates an immutable
                    // byte slice representing the memory of `stat`.  We
                    // ensure that the slice covers the entire memory of
                    // `stat` using `std::mem::size_of_val`. Since
                    // `stat` is a stack variable and we're only
                    // borrowing its memory for the duration of the
                    // slice, there's no risk of `stat` being
                    // deallocated while the slice exists.
                    // Additionally, we ensure that the slice is not
                    // used outside of its valid lifetime.
                    let stat = unsafe {
                        std::slice::from_raw_parts(
                            std::ptr::addr_of!(stat32) as *const u8,
                            std::mem::size_of_val(&stat32),
                        )
                    };
                    request.write_mem(stat, addr)?;
                } else {
                    // SAFETY: The following block creates an immutable
                    // byte slice representing the memory of `stat`.  We
                    // ensure that the slice covers the entire memory of
                    // `stat` using `std::mem::size_of_val`. Since
                    // `stat` is a stack variable and we're only
                    // borrowing its memory for the duration of the
                    // slice, there's no risk of `stat` being
                    // deallocated while the slice exists.
                    // Additionally, we ensure that the slice is not
                    // used outside of its valid lifetime.
                    let stat = unsafe {
                        std::slice::from_raw_parts(
                            std::ptr::addr_of!(stat) as *const u8,
                            std::mem::size_of_val(&stat),
                        )
                    };
                    request.write_mem(stat, addr)?;
                }
            }
        }

        // stat system call successfully emulated.
        Ok(request.return_syscall(0))
    })
}

/// A helper function to handle mkdir* syscalls.
fn syscall_mkdir_handler(
    request: &UNotifyEventRequest,
    args: PathArgs,
    mode: Mode,
) -> Result<ScmpNotifResp, Errno> {
    // SAFETY: SysArg has one element.
    #[allow(clippy::disallowed_methods)]
    let path = args.0.as_ref().unwrap();

    // SAFETY: Return EEXIST if the path already exists.
    // We do this after the access check to ensure
    // the EEXIST errno cannot be misused to detect
    // hidden files.
    if path.typ.is_some() {
        return Err(Errno::EEXIST);
    }

    let req = request.scmpreq;
    let mask = proc_umask(req.pid())?;

    // SAFETY: Honour process' umask.
    // Note, the umask is per-thread here.
    // Note, POSIX ACLs may override this.
    umask(mask);

    mkdirat(path.dir.as_ref().map(|fd| fd.as_raw_fd()), path.base, mode)
        .map(|_| request.return_syscall(0))
}

/// A helper function to handle mknod* syscalls.
fn syscall_mknod_handler(
    request: &UNotifyEventRequest,
    args: PathArgs,
    kind: SFlag,
    mut perm: Mode,
    dev: libc::dev_t,
    force_umask: Option<Mode>,
) -> Result<ScmpNotifResp, Errno> {
    // SAFETY: SysArg has one element.
    #[allow(clippy::disallowed_methods)]
    let path = args.0.as_ref().unwrap();

    // SAFETY:
    // 1. force_umask is only applied to regular files.
    // 2. force_umask overrides POSIX ACLs.
    if kind == SFlag::S_IFREG {
        if let Some(mask) = force_umask {
            perm &= !mask;
        }
    }

    let req = request.scmpreq;
    let mask = proc_umask(req.pid())?;

    // SAFETY: Honour process' umask.
    // Note, the umask is per-thread here.
    // Note, POSIX ACLs may override this.
    umask(mask);

    mknodat(
        path.dir.as_ref().map(|fd| fd.as_raw_fd()),
        path.base,
        kind,
        perm,
        dev,
    )
    .map(|_| request.return_syscall(0))
}

/// A helper function to handle access, faccessat, and faccessat2 syscalls.
fn syscall_access_handler(
    request: &UNotifyEventRequest,
    args: PathArgs,
    mode: AccessFlags,
) -> Result<ScmpNotifResp, Errno> {
    // SAFETY: SysArg has one element.
    #[allow(clippy::disallowed_methods)]
    let path = args.0.as_ref().unwrap();

    // SAFETY: Handle base path in a TOCTOU-free way.
    let flags = if path.base.is_empty() {
        libc::AT_EMPTY_PATH
    } else {
        libc::AT_SYMLINK_NOFOLLOW
    };

    let fd = path
        .dir
        .as_ref()
        .map(|fd| fd.as_raw_fd())
        .ok_or(Errno::EBADF)?;

    path.base
        .with_nix_path(|cstr| {
            // SAFETY: No libc wrapper for faccessat2 yet.
            Errno::result(unsafe {
                libc::syscall(
                    libc::SYS_faccessat2,
                    fd.as_raw_fd(),
                    cstr.as_ptr(),
                    mode.bits(),
                    flags,
                )
            })
        })?
        .map(|_| request.return_syscall(0))
}

// Note fchmodat2 may not be available,
// and libc::SYS_fchmodat2 may not be defined.
// Therefore we query the number using libseccomp.
static SYS_FCHMODAT2: Lazy<libc::c_long> = Lazy::new(|| {
    ScmpSyscall::from_name("fchmodat2")
        .map(i32::from)
        .map(libc::c_long::from)
        .unwrap_or(-1) // Invalid system call.
});

/// A helper function to handle chmod, fchmodat, and fchmodat2 syscalls.
fn syscall_chmod_handler(
    request: &UNotifyEventRequest,
    sandbox: &SandboxGuard,
    args: PathArgs,
    mut mode: Mode,
) -> Result<ScmpNotifResp, Errno> {
    // SAFETY: SysArg has one element.
    #[allow(clippy::disallowed_methods)]
    let path = args.0.as_ref().unwrap();

    // SAFETY: We apply force_umask to chmod modes to ensure consistency.
    let umask = sandbox.umask.unwrap_or(Mode::empty());
    mode &= !umask;

    let fd = path
        .dir
        .as_ref()
        .map(|fd| fd.as_raw_fd())
        .ok_or(Errno::EBADF)?;

    let flags = if path.base.is_empty() {
        // FD-only call, e.g remote-fd transfer due to fchmod(2).
        libc::AT_EMPTY_PATH
    } else {
        // SAFETY: Do not resolve symlinks in base to prevent TOCTTOU.
        libc::AT_SYMLINK_NOFOLLOW
    };

    path.base
        .with_nix_path(|cstr| {
            match if *SYS_FCHMODAT2 > 0 {
                // SAFETY: No libc wrapper for fchmodat2 yet.
                Errno::result(unsafe {
                    libc::syscall(
                        *SYS_FCHMODAT2,
                        fd.as_raw_fd(),
                        cstr.as_ptr(),
                        mode.bits(),
                        flags,
                    )
                })
            } else {
                Err(Errno::ENOSYS)
            } {
                Ok(_) => Ok(()),
                Err(Errno::ENOSYS) if path.base.is_empty() => {
                    // Fallback to `/proc` indirection,
                    //
                    // path to fd is open already!
                    let mut pfd = XPathBuf::from("self/fd");
                    pfd.push_fd(fd.as_raw_fd());
                    pfd.with_nix_path(|cstr| {
                        // SAFETY: We deliberately bypass the libc wrapper here.
                        Errno::result(unsafe {
                            libc::syscall(libc::SYS_fchmodat, PROC_FD(), cstr.as_ptr(), mode.bits())
                        })
                    })?
                    .map(drop)
                }
                Err(Errno::ENOSYS) => {
                    // Fallback to `/proc` indirection.
                    //
                    // open an `O_PATH` fd without following symlinks.
                    let fd = safe_open_path(path.dir.as_ref(), path.base, OFlag::O_NOFOLLOW)?;
                    let mut pfd = XPathBuf::from("self/fd");
                    pfd.push_fd(fd.as_raw_fd());
                    pfd.with_nix_path(|cstr| {
                        // SAFETY: We deliberately bypass the libc wrapper here.
                        Errno::result(unsafe {
                            libc::syscall(libc::SYS_fchmodat, PROC_FD(), cstr.as_ptr(), mode.bits())
                        })
                    })?
                    .map(drop)
                }
                Err(errno) => Err(errno),
            }
        })?
        .map(|_| request.return_syscall(0))
}

/// A helper function to handle chown, lchown, and fchownat syscalls.
fn syscall_chown_handler(
    request: &UNotifyEventRequest,
    args: PathArgs,
    owner: Option<Uid>,
    group: Option<Gid>,
) -> Result<ScmpNotifResp, Errno> {
    if owner.is_none() && group.is_none() {
        // Nothing to change.
        return Ok(request.return_syscall(0));
    }

    // SAFETY: SysArg has one element.
    #[allow(clippy::disallowed_methods)]
    let path = args.0.as_ref().unwrap();

    let fd = path
        .dir
        .as_ref()
        .map(|fd| fd.as_raw_fd())
        .ok_or(Errno::EBADF)?;

    let flags = if path.base.is_empty() {
        // FD-only call, e.g remote-fd transfer due to fchown(2).
        libc::AT_EMPTY_PATH
    } else {
        // SAFETY: Do not resolve symlinks in base to prevent TOCTTOU.
        libc::AT_SYMLINK_NOFOLLOW
    };
    let flags = AtFlags::from_bits_truncate(flags);

    fchownat(Some(fd), path.base, owner, group, flags).map(|_| request.return_syscall(0))
}

/// A helper function to handle rename and renameat syscalls.
fn syscall_rename_handler(
    request: &UNotifyEventRequest,
    args: PathArgs,
) -> Result<ScmpNotifResp, Errno> {
    // SAFETY: SysArg has two elements.
    #[allow(clippy::disallowed_methods)]
    let old_path = args.0.as_ref().unwrap();
    #[allow(clippy::disallowed_methods)]
    let new_path = args.1.as_ref().unwrap();

    renameat(
        old_path.dir.as_ref().map(|fd| fd.as_raw_fd()),
        old_path.base,
        new_path.dir.as_ref().map(|fd| fd.as_raw_fd()),
        new_path.base,
    )
    .map(|_| request.return_syscall(0))
}

/// A helper function to handle utime* syscalls.
fn syscall_utime_handler(
    request: &UNotifyEventRequest,
    args: PathArgs,
    atime: &TimeSpec,
    mtime: &TimeSpec,
) -> Result<ScmpNotifResp, Errno> {
    // SAFETY: SysArg has one element.
    #[allow(clippy::disallowed_methods)]
    let path = args.0.as_ref().unwrap();

    let fd = path
        .dir
        .as_ref()
        .map(|fd| fd.as_raw_fd())
        .ok_or(Errno::EBADF)?;
    let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];

    // SAFETY:
    // 1. After this point we are not permitted to resolve
    //    symbolic links any longer or else we risk TOCTOU.
    // 2. nix does not define AT_EMPTY_PATH in `UtimensatFlags`,
    //    so we have to use libc instead.
    Errno::result(unsafe {
        libc::utimensat(fd, c"".as_ptr().cast(), &times[0], libc::AT_EMPTY_PATH)
    })
    .map(|_| request.return_syscall(0))
}

/// A helper function to handle link{,at} syscalls.
fn syscall_link_handler(
    request: &UNotifyEventRequest,
    args: PathArgs,
) -> Result<ScmpNotifResp, Errno> {
    // SAFETY: SysArg has two elements.
    #[allow(clippy::disallowed_methods)]
    let old_path = args.0.as_ref().unwrap();
    #[allow(clippy::disallowed_methods)]
    let new_path = args.1.as_ref().unwrap();

    // SAFETY: linkat does not follow symbolic links in old path by
    // default unless AT_SYMLINK_FOLLOW flag is passed. As such,
    // AT_SYMLINK_NOFOLLOW is an invalid flag for linkat.
    linkat(
        old_path.dir.as_ref().map(|fd| fd.as_raw_fd()),
        old_path.base,
        new_path.dir.as_ref().map(|fd| fd.as_raw_fd()),
        new_path.base,
        if old_path.base.is_empty() {
            AtFlags::AT_EMPTY_PATH
        } else {
            AtFlags::empty()
        },
    )
    .map(|_| request.return_syscall(0))
}

/// A helper function to handle symlink{,at} syscalls.
fn syscall_symlink_handler(
    request: UNotifyEventRequest,
    arg: SysArg,
) -> Result<ScmpNotifResp, Errno> {
    let req = request.scmpreq;

    let process = RemoteProcess::new(request.scmpreq.pid());

    // SAFETY: symlink() returns ENOENT if target is an empty string.
    let target = unsafe { process.remote_path(req.data.args[0]) }?;
    if target.is_empty() {
        return Err(Errno::ENOENT);
    }

    // Read remote path.
    let sandbox = request.get_sandbox();
    let (path, _) = request.read_path(&sandbox, arg, false)?;

    // Check for access.
    let hide = sandbox.enabled(Capability::CAP_STAT);
    sandbox_path(
        Some(&request),
        &request.cache,
        &sandbox,
        &process,
        path.abs(),
        Capability::CAP_SYMLINK,
        hide,
        "symlink",
    )?;
    drop(sandbox); // release the read-lock.

    // All done, call underlying system call.
    symlinkat(
        &target,
        path.dir.as_ref().map(|fd| fd.as_raw_fd()),
        path.base,
    )
    .map(|_| request.return_syscall(0))
}

/// A helper function to handle getxattr-family syscalls.
fn syscall_getxattr_handler(
    request: &UNotifyEventRequest,
    sandbox: &SandboxGuard,
    args: PathArgs,
) -> Result<ScmpNotifResp, Errno> {
    let req = request.scmpreq;

    // SAFETY: SysArg has one element.
    #[allow(clippy::disallowed_methods)]
    let path = args.0.as_ref().unwrap();

    let base = if path.base.is_empty() {
        XPath::from_bytes(b".")
    } else {
        path.base
    };

    let name = if req.data.args[1] != 0 {
        const SIZ: usize = libc::PATH_MAX as usize;
        let mut buf = Vec::new();
        buf.try_reserve(SIZ).or(Err(Errno::ENOMEM))?;
        buf.resize(SIZ, 0);
        request.read_mem(&mut buf, req.data.args[1])?;
        Some(buf)
    } else {
        None
    };
    let name = if let Some(ref name) = name {
        CStr::from_bytes_until_nul(name)
            .or(Err(Errno::E2BIG))?
            .as_ptr()
    } else {
        std::ptr::null()
    };

    #[allow(clippy::cast_possible_wrap)]
    if Sandbox::locked_once() || sandbox.locked_for(req.pid()) {
        // SAFETY: Deny user.syd* extended attributes. name is either
        // NULL or a valid nul-terminated C-String.
        // SAFETY: Deny with ENODATA for stealth.
        // SAFETY: Deny only if the Sandbox is locked for the process.
        unsafe { denyxattr(name) }?;
    }

    // SAFETY: The size argument to the getxattr call
    // must not be fully trusted, it can be overly large,
    // and allocating a Vector of that capacity may overflow.
    #[allow(clippy::cast_possible_truncation)]
    let len = req.data.args[3] as usize;
    let len = len.min(libc::PATH_MAX as usize); // Cap count at PATH_MAX.

    let mut buf = if len > 0 {
        let mut buf = Vec::new();
        buf.try_reserve(len).or(Err(Errno::ENOMEM))?;
        buf.resize(len, 0);
        Some(buf)
    } else {
        None
    };

    let ptr = match buf.as_mut() {
        Some(b) => b.as_mut_ptr(),
        None => std::ptr::null_mut(),
    };

    match &path.dir {
        Some(fd) => {
            // SAFETY: We use fchdir which is TOCTOU-free!
            fchdir(fd.as_raw_fd())?;
        }
        None => fchdir(ROOT_FD())?,
    };

    let res = base
        // SAFETY: We do not resolve symbolic links here!
        .with_nix_path(|cstr| unsafe { libc::lgetxattr(cstr.as_ptr(), name, ptr.cast(), len) })?;

    #[allow(clippy::cast_sign_loss)]
    let n = Errno::result(res)? as usize;

    if let Some(buf) = buf {
        request.write_mem(&buf[..n], req.data.args[2])?;
    }

    #[allow(clippy::cast_possible_wrap)]
    Ok(request.return_syscall(n as i64))
}

/// A helper function to handle getxattrat syscall.
fn syscall_getxattrat_handler(
    request: &UNotifyEventRequest,
    sandbox: &SandboxGuard,
    args: PathArgs,
) -> Result<ScmpNotifResp, Errno> {
    let req = request.scmpreq;

    // SAFETY: SysArg has one element.
    #[allow(clippy::disallowed_methods)]
    let path = args.0.as_ref().unwrap();

    let base = if path.base.is_empty() {
        XPath::from_bytes(b".")
    } else {
        path.base
    };

    // Read struct xattr_args which holds the return pointer, buffer size and flags.
    let mut args = MaybeUninit::<XattrArgs>::uninit();

    // SAFETY: Ensure size of XattrArgs matches with user argument.
    if req.data.args[5] != std::mem::size_of::<XattrArgs>() as u64 {
        return Err(Errno::EINVAL);
    }

    // SAFETY: `args` is sized for XattrArgs, and we're just writing bytes to it.
    // We don't read uninitialized memory, and after `read_mem` fills it,
    // we're good to assume it's valid.
    let buf = unsafe {
        std::slice::from_raw_parts_mut(
            args.as_mut_ptr().cast::<u8>(),
            std::mem::size_of::<XattrArgs>(),
        )
    };

    // Read the remote data structure.
    request.read_mem(buf, req.data.args[4])?;

    // SAFETY: read_mem() has initialized `args` if it succeeded.
    let args = unsafe { args.assume_init() };

    // SAFETY: For getxattrat `flags` member must be zero!
    if args.flags != 0 {
        return Err(Errno::EINVAL);
    }

    let name = if req.data.args[3] != 0 {
        const SIZ: usize = libc::PATH_MAX as usize;
        let mut buf = Vec::new();
        buf.try_reserve(SIZ).or(Err(Errno::ENOMEM))?;
        buf.resize(SIZ, 0);
        request.read_mem(&mut buf, req.data.args[3])?;
        Some(buf)
    } else {
        None
    };
    let name = if let Some(ref name) = name {
        CStr::from_bytes_until_nul(name)
            .or(Err(Errno::E2BIG))?
            .as_ptr()
    } else {
        std::ptr::null()
    };

    #[allow(clippy::cast_possible_wrap)]
    if Sandbox::locked_once() || sandbox.locked_for(req.pid()) {
        // SAFETY: Deny user.syd* extended attributes. name is either
        // NULL or a valid nul-terminated C-String.
        // SAFETY: Deny with ENODATA for stealth.
        // SAFETY: Deny only if the Sandbox is locked for the process.
        unsafe { denyxattr(name) }?;
    }

    // SAFETY: The size element of the struct xattr_args
    // must not be fully trusted, it can be overly large,
    // and allocating a Vector of that capacity may overflow.
    #[allow(clippy::cast_possible_truncation)]
    let len = args.size as usize;
    let len = len.min(libc::PATH_MAX as usize); // Cap count at PATH_MAX.

    let mut buf = if len > 0 {
        let mut buf = Vec::new();
        buf.try_reserve(len).or(Err(Errno::ENOMEM))?;
        buf.resize(len, 0);
        Some(buf)
    } else {
        None
    };

    let fd = match &path.dir {
        Some(fd) => fd.as_raw_fd(),
        None => return Err(Errno::EBADF),
    };

    #[allow(clippy::cast_possible_truncation)]
    let mut my_args = XattrArgs {
        value: match buf.as_mut() {
            Some(b) => b.as_mut_ptr() as *mut libc::c_void as u64,
            None => 0,
        },
        size: len as u32,
        flags: 0,
    };

    // SAFETY:
    // 1. `name` is a valid raw pointer (may be NULL)!
    // 2. We do not resolve symbolic links here!
    let n = unsafe {
        getxattrat(
            Some(&fd),
            base,
            name,
            &mut my_args,
            AtFlags::AT_SYMLINK_NOFOLLOW,
        )
    }?;

    if let Some(buf) = buf {
        request.write_mem(&buf[..n], args.value)?;
    }

    #[allow(clippy::cast_possible_wrap)]
    Ok(request.return_syscall(n as i64))
}

/// A helper function to handle setxattr-family syscalls.
fn syscall_setxattr_handler(
    request: &UNotifyEventRequest,
    sandbox: &SandboxGuard,
    args: PathArgs,
) -> Result<ScmpNotifResp, Errno> {
    // SAFETY:
    // 1. SysArg has one element.
    // 2. `/` is not permitted -> EACCES.
    #[allow(clippy::disallowed_methods)]
    let fd = args.0.as_ref().unwrap().dir.as_ref().ok_or(Errno::EACCES)?;

    let req = request.scmpreq;
    let name = if req.data.args[1] != 0 {
        const SIZ: usize = libc::PATH_MAX as usize;
        let mut buf = Vec::new();
        buf.try_reserve(SIZ).or(Err(Errno::ENOMEM))?;
        buf.resize(SIZ, 0);
        request.read_mem(&mut buf, req.data.args[1])?;
        Some(buf)
    } else {
        None
    };
    let name = if let Some(ref name) = name {
        CStr::from_bytes_until_nul(name)
            .or(Err(Errno::E2BIG))?
            .as_ptr()
    } else {
        std::ptr::null()
    };

    #[allow(clippy::cast_possible_wrap)]
    if Sandbox::locked_once() || sandbox.locked_for(req.pid()) {
        // SAFETY: Deny user.syd* extended attributes. name is either
        // NULL or a valid nul-terminated C-String.
        // SAFETY: Deny with EACCES to denote access violation.
        // SAFETY: Deny only if the Sandbox is locked for the process.
        unsafe { denyxattr(name) }.map_err(|_| Errno::EACCES)?;
    }

    // SAFETY: The size argument to the setxattr call
    // must not be fully trusted, it can be overly large,
    // and allocating a Vector of that capacity may overflow.
    let (buf, len) = if req.data.args[3] == 0 {
        (None, 0)
    } else {
        let len = usize::try_from(req.data.args[3]).or(Err(Errno::E2BIG))?;
        let len = len.min(libc::PATH_MAX as usize); // Cap count at PATH_MAX.
        let mut buf = Vec::new();
        buf.try_reserve(len).or(Err(Errno::ENOMEM))?;
        buf.resize(len, 0);
        request.read_mem(&mut buf, req.data.args[2])?;
        (Some(buf), len)
    };
    let buf = buf.as_ref().map_or(std::ptr::null(), |b| b.as_ptr()) as *const libc::c_void;

    #[allow(clippy::cast_possible_truncation)]
    let flags = req.data.args[4] as libc::c_int;

    // SAFETY: In libc we trust.
    if unsafe { libc::fsetxattr(fd.as_raw_fd(), name, buf, len, flags) } == 0 {
        Ok(request.return_syscall(0))
    } else {
        Err(Errno::last())
    }
}

/// A helper function to handle setxattrat syscall.
fn syscall_setxattrat_handler(
    request: &UNotifyEventRequest,
    sandbox: &SandboxGuard,
    args: PathArgs,
) -> Result<ScmpNotifResp, Errno> {
    let req = request.scmpreq;

    // SAFETY: SysArg has one element.
    #[allow(clippy::disallowed_methods)]
    let path = args.0.as_ref().unwrap();

    let base = if path.base.is_empty() {
        XPath::from_bytes(b".")
    } else {
        path.base
    };

    // Read struct xattr_args which holds the extension name, buffer size and flags.
    let mut args = MaybeUninit::<XattrArgs>::uninit();

    // SAFETY: Ensure size of XattrArgs matches with user argument.
    if req.data.args[5] != std::mem::size_of::<XattrArgs>() as u64 {
        return Err(Errno::EINVAL);
    }

    // SAFETY: `args` is sized for XattrArgs, and we're just writing bytes to it.
    // We don't read uninitialized memory, and after `read_mem` fills it,
    // we're good to assume it's valid.
    let buf = unsafe {
        std::slice::from_raw_parts_mut(
            args.as_mut_ptr().cast::<u8>(),
            std::mem::size_of::<XattrArgs>(),
        )
    };

    // Read the remote data structure.
    request.read_mem(buf, req.data.args[4])?;

    // SAFETY: read_mem() has initialized `args` if it succeeded.
    let args = unsafe { args.assume_init() };

    let name = if req.data.args[3] != 0 {
        const SIZ: usize = libc::PATH_MAX as usize;
        let mut buf = Vec::new();
        buf.try_reserve(SIZ).or(Err(Errno::ENOMEM))?;
        buf.resize(SIZ, 0);
        request.read_mem(&mut buf, req.data.args[3])?;
        Some(buf)
    } else {
        None
    };
    let name = if let Some(ref name) = name {
        CStr::from_bytes_until_nul(name)
            .or(Err(Errno::E2BIG))?
            .as_ptr()
    } else {
        std::ptr::null()
    };

    #[allow(clippy::cast_possible_wrap)]
    if Sandbox::locked_once() || sandbox.locked_for(req.pid()) {
        // SAFETY: Deny user.syd* extended attributes. name is either
        // NULL or a valid nul-terminated C-String.
        // SAFETY: Deny with EACCES to denote access violation.
        // SAFETY: Deny only if the Sandbox is locked for the process.
        unsafe { denyxattr(name) }.map_err(|_| Errno::EACCES)?;
    }

    // SAFETY: The size argument to the setxattr call
    // must not be fully trusted, it can be overly large,
    // and allocating a Vector of that capacity may overflow.
    let (buf, len) = if args.size == 0 {
        (None, 0)
    } else {
        let len = usize::try_from(args.size).or(Err(Errno::E2BIG))?;
        let len = len.min(libc::PATH_MAX as usize); // Cap count at PATH_MAX.
        let mut buf = Vec::new();
        buf.try_reserve(len).or(Err(Errno::ENOMEM))?;
        buf.resize(len, 0);
        request.read_mem(&mut buf, args.value)?;
        (Some(buf), len)
    };
    let buf = buf.as_ref().map_or(std::ptr::null(), |b| b.as_ptr()) as *const libc::c_void;

    let fd = match &path.dir {
        Some(fd) => fd.as_raw_fd(),
        None => return Err(Errno::EBADF),
    };

    #[allow(clippy::cast_possible_truncation)]
    let my_args = XattrArgs {
        value: buf as u64,
        size: len as u32,
        flags: args.flags,
    };

    // SAFETY:
    // 1. `name` is a valid raw pointer (may be NULL)!
    // 2. We do not resolve symbolic links here!
    unsafe {
        setxattrat(
            Some(&fd),
            base,
            name,
            &my_args,
            AtFlags::AT_SYMLINK_NOFOLLOW,
        )
    }
    .map(|_| request.return_syscall(0))
}

/// A helper function to handle listxattr-family syscalls.
fn syscall_listxattr_handler(
    request: &UNotifyEventRequest,
    sandbox: &SandboxGuard,
    args: PathArgs,
) -> Result<ScmpNotifResp, Errno> {
    let req = request.scmpreq;

    // SAFETY: SysArg has one element.
    #[allow(clippy::disallowed_methods)]
    let path = args.0.as_ref().unwrap();

    let base = if path.base.is_empty() {
        XPath::from_bytes(b".")
    } else {
        path.base
    };

    // SAFETY: The size argument to the llistxattr call
    // must not be fully trusted, it can be overly large,
    // and allocating a Vector of that capacity may overflow.
    let len = usize::try_from(req.data.args[2])
        .or(Err(Errno::E2BIG))?
        .min(10240); // Cap count at 10240.

    let mut buf = if len > 0 {
        let mut buf = Vec::new();
        buf.try_reserve(len).or(Err(Errno::ENOMEM))?;
        buf.resize(len, 0);
        Some(buf)
    } else {
        None
    };

    let ptr = buf
        .as_mut()
        .map_or(std::ptr::null_mut(), |b| b.as_mut_ptr()) as *mut libc::c_char;

    match &path.dir {
        Some(fd) => {
            // SAFETY: We use fchdir which is TOCTOU-free!
            fchdir(fd.as_raw_fd())?;
        }
        None => fchdir(ROOT_FD())?,
    };

    let res = base
        // SAFETY: We do not resolve symbolic links here!
        .with_nix_path(|cstr| unsafe { libc::llistxattr(cstr.as_ptr(), ptr, len) })?;

    #[allow(clippy::cast_sign_loss)]
    let mut n = Errno::result(res)? as usize;

    if let Some(buf) = buf {
        // SAFETY: Filter out attributes that start with "user.syd".
        // SAFETY: Deny only if the Sandbox is locked for the process.
        #[allow(clippy::cast_possible_wrap)]
        let buf = if Sandbox::locked_once() || sandbox.locked_for(req.pid()) {
            filterxattr(&buf[..n], n)?
        } else {
            buf[..n].to_vec()
        };

        request.write_mem(&buf, req.data.args[1])?;
        n = buf.len();
    }

    #[allow(clippy::cast_possible_wrap)]
    Ok(request.return_syscall(n as i64))
}

/// A helper function to handle listxattrat syscall.
fn syscall_listxattrat_handler(
    request: &UNotifyEventRequest,
    sandbox: &SandboxGuard,
    args: PathArgs,
) -> Result<ScmpNotifResp, Errno> {
    let req = request.scmpreq;

    // SAFETY: SysArg has one element.
    #[allow(clippy::disallowed_methods)]
    let path = args.0.as_ref().unwrap();

    let base = if path.base.is_empty() {
        XPath::from_bytes(b".")
    } else {
        path.base
    };

    // SAFETY: The size argument to the llistxattr call
    // must not be fully trusted, it can be overly large,
    // and allocating a Vector of that capacity may overflow.
    let len = usize::try_from(req.data.args[4])
        .or(Err(Errno::E2BIG))?
        .min(10240); // Cap count at 10240.

    let mut buf = if len > 0 {
        let mut buf = Vec::new();
        buf.try_reserve(len).or(Err(Errno::ENOMEM))?;
        buf.resize(len, 0);
        Some(buf)
    } else {
        None
    };

    let ptr = buf
        .as_mut()
        .map_or(std::ptr::null_mut(), |b| b.as_mut_ptr()) as *mut libc::c_char;

    let fd = match &path.dir {
        Some(fd) => fd.as_raw_fd(),
        None => return Err(Errno::EBADF),
    };

    // SAFETY:
    // 1. `ptr` is a valid raw pointer (may be NULL)!
    // 2. We do not resolve symbolic links here!
    let mut n = unsafe { listxattrat(Some(&fd), base, AtFlags::AT_SYMLINK_NOFOLLOW, ptr, len) }?;

    if let Some(buf) = buf {
        // SAFETY: Filter out attributes that start with "user.syd".
        // SAFETY: Deny only if the Sandbox is locked for the process.
        #[allow(clippy::cast_possible_wrap)]
        let buf = if Sandbox::locked_once() || sandbox.locked_for(req.pid()) {
            filterxattr(&buf[..n], n)?
        } else {
            buf[..n].to_vec()
        };

        request.write_mem(&buf, req.data.args[3])?;
        n = buf.len();
    }

    #[allow(clippy::cast_possible_wrap)]
    Ok(request.return_syscall(n as i64))
}

/// A helper function to handle removexattr-family syscalls.
fn syscall_removexattr_handler(
    request: &UNotifyEventRequest,
    sandbox: &SandboxGuard,
    args: PathArgs,
) -> Result<ScmpNotifResp, Errno> {
    // SAFETY:
    // 1. SysArg has one element.
    // 2. `/` is not permitted -> EACCES.
    #[allow(clippy::disallowed_methods)]
    let fd = args.0.as_ref().unwrap().dir.as_ref().ok_or(Errno::EACCES)?;

    let req = request.scmpreq;

    let name = if req.data.args[1] != 0 {
        const SIZ: usize = libc::PATH_MAX as usize;
        let mut buf = Vec::new();
        buf.try_reserve(SIZ).or(Err(Errno::ENOMEM))?;
        buf.resize(SIZ, 0);
        request.read_mem(&mut buf, req.data.args[1])?;
        Some(buf)
    } else {
        None
    };
    let name = if let Some(ref name) = name {
        CStr::from_bytes_until_nul(name)
            .or(Err(Errno::E2BIG))?
            .as_ptr()
    } else {
        std::ptr::null()
    };

    #[allow(clippy::cast_possible_wrap)]
    if Sandbox::locked_once() || sandbox.locked_for(req.pid()) {
        // SAFETY: Deny user.syd* extended attributes.
        // name is either NULL or a valid nul-terminated C-String.
        // SAFETY: Deny with ENODATA for stealth.
        // SAFETY: Deny only if the Sandbox is locked for the process.
        unsafe { denyxattr(name) }?;
    }

    // SAFETY: In libc we trust.
    if unsafe { libc::fremovexattr(fd.as_raw_fd(), name) } == 0 {
        Ok(request.return_syscall(0))
    } else {
        Err(Errno::last())
    }
}

/// A helper function to handle removexattrat syscall.
fn syscall_removexattrat_handler(
    request: &UNotifyEventRequest,
    sandbox: &SandboxGuard,
    args: PathArgs,
) -> Result<ScmpNotifResp, Errno> {
    let req = request.scmpreq;

    // SAFETY: SysArg has one element.
    #[allow(clippy::disallowed_methods)]
    let path = args.0.as_ref().unwrap();

    let base = if path.base.is_empty() {
        XPath::from_bytes(b".")
    } else {
        path.base
    };

    let name = if req.data.args[3] != 0 {
        const SIZ: usize = libc::PATH_MAX as usize;
        let mut buf = Vec::new();
        buf.try_reserve(SIZ).or(Err(Errno::ENOMEM))?;
        buf.resize(SIZ, 0);
        request.read_mem(&mut buf, req.data.args[3])?;
        Some(buf)
    } else {
        None
    };
    let name = if let Some(ref name) = name {
        CStr::from_bytes_until_nul(name)
            .or(Err(Errno::E2BIG))?
            .as_ptr()
    } else {
        std::ptr::null()
    };

    #[allow(clippy::cast_possible_wrap)]
    if Sandbox::locked_once() || sandbox.locked_for(req.pid()) {
        // SAFETY: Deny user.syd* extended attributes.
        // name is either NULL or a valid nul-terminated C-String.
        // SAFETY: Deny with ENODATA for stealth.
        // SAFETY: Deny only if the Sandbox is locked for the process.
        unsafe { denyxattr(name) }?;
    }

    let fd = match &path.dir {
        Some(fd) => fd.as_raw_fd(),
        None => return Err(Errno::EBADF),
    };

    // SAFETY:
    // 1. `name` is a valid raw pointer (may be NULL)!
    // 2. We do not resolve symbolic links here!
    unsafe { removexattrat(Some(&fd), base, name, AtFlags::AT_SYMLINK_NOFOLLOW) }
        .map(|_| request.return_syscall(0))
}

/// A helper function to handle network-related syscalls.
///
/// This function abstracts the common logic involved in handling network syscalls such as `bind`,
/// `connect`, `and `sendto` in a seccomp-based sandboxing environment. It reduces code duplication
/// across different syscall handler functions.
///
/// # Returns
///
/// Returns `ScmpNotifResp` indicating the result of the syscall handling:
/// - If successful, it contains a continued syscall.
/// - If an error occurs, it contains a failed syscall with an `EACCES` error code.
#[allow(clippy::cognitive_complexity)]
fn syscall_network_handler(request: UNotifyEventRequest, args: &[u64; 6], op: u8) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        let sandbox = request.get_sandbox();
        let allow_safe_bind = sandbox.allow_safe_bind();
        let allow_safe_kcapi = sandbox.allow_safe_kcapi();
        let allow_unsupp_socket = sandbox.allow_unsupp_socket();

        let cap = match op {
            0x1 => {
                // a. socket(2) system call.
                // b. socketcall(2) -> socket(2) indirection.
                // SAFETY: Limit available domains based on sandbox flags.
                let domain = libc::c_int::try_from(args[0]).or(Err(Errno::EAFNOSUPPORT))?;
                if !allow_unsupp_socket {
                    match domain {
                        libc::AF_UNIX | libc::AF_INET | libc::AF_INET6 => {}
                        libc::AF_ALG if allow_safe_kcapi => {}
                        libc::AF_NETLINK => {
                            // Restrict AF_NETLINK to the allowlisted families.
                            let netlink_family =
                                u32::try_from(args[2]).or(Err(Errno::EAFNOSUPPORT))?;
                            #[allow(clippy::cast_sign_loss)]
                            if netlink_family > NetlinkFamily::max() as u32 {
                                return Err(Errno::EAFNOSUPPORT);
                            }
                            let netlink_family = NetlinkFamily::from_bits(1 << netlink_family)
                                .ok_or(Errno::EAFNOSUPPORT)?;
                            if !sandbox.netlink_families.contains(netlink_family) {
                                // SAFETY: Unsafe netlink family, deny.
                                return Err(Errno::EAFNOSUPPORT);
                            }
                        }
                        _ => return Err(Errno::EAFNOSUPPORT),
                    }
                } else if !allow_safe_kcapi && domain == libc::AF_ALG {
                    return Err(Errno::EAFNOSUPPORT);
                } else {
                    // SAFETY: allow_unsupp_socket:1
                    // Safe domain, allow.
                }
                drop(sandbox); // drop the read-lock before emulation.

                let stype = libc::c_int::try_from(args[1]).or(Err(Errno::EINVAL))?;
                let proto = libc::c_int::try_from(args[2]).or(Err(Errno::EAFNOSUPPORT))?;
                let cloexec = stype & libc::SOCK_CLOEXEC != 0;
                let stype = stype | libc::SOCK_CLOEXEC;

                let fd =
                    // SAFETY: We use libc version for convenience.
                    Errno::result(unsafe { libc::socket(domain, stype, proto) }).map(|fd| {
                        // SAFETY: socket returns a valid FD.
                        unsafe { OwnedFd::from_raw_fd(fd) }
                    })?;

                if log_enabled!(LogLevel::Debug) {
                    let inode = fstatx(&fd, STATX_INO)
                        .map(|statx| statx.stx_ino)
                        .unwrap_or(0);
                    let domain = AddressFamily::from_i32(domain)
                        .map(|af| format!("{af:?}"))
                        .unwrap_or_else(|| "?".to_string());
                    let flags = SockFlag::from_bits_truncate(
                        stype & (libc::SOCK_CLOEXEC | libc::SOCK_NONBLOCK),
                    );
                    let stype =
                        SockType::try_from(stype & !(libc::SOCK_CLOEXEC | libc::SOCK_NONBLOCK))
                            .map(|st| format!("{st:?}"))
                            .unwrap_or_else(|_| "?".to_string());
                    debug!("ctx": "net", "op": "create_socket",
                        "msg": format!("created {domain} {stype} socket with inode:{inode:#x}"),
                        "domain": domain,
                        "type": stype,
                        "protocol": proto,
                        "flags": flags.bits(),
                        "inode": inode);
                }

                return request.send_fd(&fd, cloexec);
            }
            0x2 | 0x6 => Capability::CAP_NET_BIND,
            _ => Capability::CAP_NET_CONNECT,
        };
        drop(sandbox); // release the read-lock before get-fd.

        // SAFETY: Get the file descriptor before access check
        // as it may change after which is a TOCTOU vector.
        // This also allows us to early return on invalid file
        // descriptors without having to resort to access()'ing
        // /proc/$pid/fd/$fd which will return ENOENT with
        // /proc mounted as hidepid=2.
        let fd = request.get_fd(args[0] as RawFd)?;

        match op {
            0x5 | 0x12 => {
                // accept{,4} uses a different data structure, so we handle it in its own branch.
                return handle_accept(fd, &request, args, op);
            }
            0x6 => {
                // getsockname is used for informational purposes only.
                return handle_getsockname(fd, &request, args);
            }
            0x10 => {
                // sendmsg uses a different data structure, so we handle it in its own branch.
                return handle_sendmsg(fd, &request, args, allow_unsupp_socket);
            }
            0x14 => {
                // sendmmsg uses a different data structure, so we handle it in its own branch.
                return handle_sendmmsg(fd, &request, args, allow_unsupp_socket);
            }
            _ => {} // fall through.
        }

        let idx = if op == 0xb /* sendto */ { 4 } else { 1 };
        let addr_remote = args[idx];
        #[allow(clippy::arithmetic_side_effects)]
        #[allow(clippy::cast_possible_truncation)]
        let addr_len = args[idx + 1] as libc::socklen_t;
        if addr_remote == 0 && addr_len == 0 {
            if op == 0xb {
                // sendto
                // SAFETY: Connection mode socket.
                // Note, we don't hook into sendto anymore when both
                // these arguments are NULL so we can never be here
                // practically. However, this can still happen in
                // theory, e.g. when the syscall is originating from a
                // multiplexed socketcall() syscall. In this case
                // continuing the system call here obviously would open a
                // TOCTOU window so instead we pass a None address to
                // handle_sendto() where we'll invoke the send() syscall
                // on our own and return the result to the sandbox
                // process.
                return handle_sendto(fd, args, &request, None);
            } else {
                return Err(Errno::EFAULT);
            }
        } else if addr_remote == 0 || addr_len == 0 {
            return Err(Errno::EFAULT);
        } // else we have a valid address to check for access.

        let sandbox = request.get_sandbox();
        let (addr, root) = canon_addr(
            &request,
            &sandbox,
            get_addr(&request, addr_remote, addr_len)?,
            cap,
            sandbox.flags,
        )?;
        match addr_family(&addr) {
            PF_UNIX | PF_INET | PF_INET6 => {
                // Check for access.
                sandbox_addr(&request, &sandbox, &addr, &root, op, cap)?;
            }
            PF_UNSPEC => {
                // SAFETY: We do not check address for AF_UNSPEC:
                //
                // Some  protocol sockets (e.g., TCP sockets as well as datagram sockets in the
                // UNIX and Internet domains) may dissolve the association by connecting to an
                // address with the sa_family member of sockaddr set to AF_UNSPEC; thereafter, the
                // socket can be connected to another address. (AF_UNSPEC is supported since
                // Linux 2.2.)
            }
            PF_NETLINK => {
                // SAFETY: We do not check Netlink address for access.
                // We apply filtering on netlink families at socket level.
            }
            PF_ALG if allow_safe_kcapi && op == 0x2 => {
                // SAFETY: Admin requested access to KCAPI.
            }
            PF_ALG => {
                // a. SAFETY: Access to KCAPI is disabled by default.
                // b. Non-bind() call is not supported for AF_ALG socket.
                return Err(Errno::EOPNOTSUPP);
            }
            _ if allow_unsupp_socket => {
                // SAFETY: This is also restricted at socket(2) boundary
                // where there is no pointer-dereference in access
                // check. However, socketcall() multiplexing is an
                // exception which introduces a TOCTOU window here.
                return unsafe { Ok(request.continue_syscall()) };
            }
            _ => return Err(Errno::EAFNOSUPPORT),
        };
        drop(sandbox); // release the read-lock.

        // Emulate syscall.
        match op {
            0x2 => handle_bind(fd, &addr, root.as_ref(), allow_safe_bind, &request),
            0x3 => handle_connect(fd, &addr, &request),
            0xb => handle_sendto(fd, args, &request, Some(&addr)),
            _ => unreachable!(),
        }
    })
}

#[allow(clippy::cognitive_complexity)]
fn handle_bind(
    fd: OwnedFd,
    addr: &SockaddrStorage,
    root: Option<&CanonicalPath>,
    allow_safe_bind: bool,
    request: &UNotifyEventRequest,
) -> Result<ScmpNotifResp, Errno> {
    if addr.as_unix_addr().and_then(|a| a.path()).is_some() {
        let fd = fd.as_raw_fd();
        let size = addr.len();
        let addr = addr.as_ptr();

        let req = request.scmpreq;
        let mask = proc_umask(req.pid())?;

        // SAFETY:
        // 1. Honour directory for too long sockets.
        //    Note, the current working directory is per-thread here.
        // 2. We cannot resolve symlinks in root or we risk TOCTOU!
        #[allow(clippy::disallowed_methods)]
        let dirfd = root.as_ref().unwrap().dir.as_ref().unwrap();
        fchdir(dirfd.as_raw_fd())?;

        // SAFETY: Honour process' umask.
        // Note, the umask is per-thread here.
        umask(mask);

        // SAFETY: bind() does not work through dangling
        // symbolic links even with SO_REUSEADDR. When called
        // with a dangling symlink as argument, bind() fails
        // with EADDRINUSE unlike creat() which is going to
        // attempt to create the symlink target. Hence basename
        // in addr here is not vulnerable to TOCTOU.
        Errno::result(unsafe { libc::bind(fd, addr, size) })?;
    } else {
        // SAFETY: addr is not a UNIX domain socket.
        bind(fd.as_raw_fd(), addr)?;
    }

    // Handle allow_safe_bind and bind_map.
    // Ignore errors as bind has already succeeded.
    let _result = (|fd: OwnedFd, request: &UNotifyEventRequest| -> Result<(), Errno> {
        let mut sandbox: Option<SandboxGuard> = None;
        let addr = match addr.family() {
            Some(AddressFamily::Unix) => {
                let addr = addr.as_unix_addr().ok_or(Errno::EINVAL)?;
                match (addr.path(), addr.as_abstract()) {
                    (Some(_), _) => {
                        // Case 1: UNIX domain socket

                        // SAFETY: addr.path()=Some asserts root is Some.
                        #[allow(clippy::disallowed_methods)]
                        let path = &root.unwrap().abs();

                        // Clear caches to ensure consistency.
                        // Note: Do this outside sandbox lock!
                        if allow_safe_bind {
                            request.cache.path_cache.0.clear();
                        }

                        // Handle bind_map after successful bind for UNIX sockets.
                        // We ignore errors because there's nothing we can do
                        // about them.
                        let mut my_sandbox = request.get_mut_sandbox();
                        let _ = my_sandbox.add_bind(&fd, path);
                        drop(fd); // Close our copy of the socket.

                        if !allow_safe_bind {
                            return Ok(());
                        }

                        // Avoid taking the lock twice.
                        sandbox = Some(my_sandbox);

                        // Display hex encodes as necessary.
                        Some(path.to_string())
                    }
                    (_, Some(path)) => {
                        // Case 2: UNIX abstract socket

                        drop(fd); // Close our copy of the socket.

                        if !allow_safe_bind {
                            return Ok(());
                        }

                        // Clear caches to ensure consistency.
                        request.cache.path_cache.0.clear();

                        // SAFETY: Prefix UNIX abstract sockets with `@' before access check.
                        let mut unix = XPathBuf::from("@");
                        let null = memchr::memchr(0, path).unwrap_or(path.len());
                        unix.append_bytes(&path[..null]);

                        // Display hex encodes as necessary.
                        Some(unix.to_string())
                    }
                    _ => {
                        // Case 3: unnamed UNIX socket.

                        // SAFETY: Use dummy path `!unnamed' for unnamed UNIX sockets.
                        Some("!unnamed".to_string())
                    }
                }
            }
            Some(AddressFamily::Inet) => {
                if !allow_safe_bind {
                    return Ok(());
                }

                let addr = addr.as_sockaddr_in().ok_or(Errno::EINVAL)?;
                let mut port = addr.port();

                let addr = IpAddr::V4(addr.ip());
                if port == 0 {
                    port = getsockname::<SockaddrStorage>(fd.as_raw_fd())?
                        .as_sockaddr_in()
                        .ok_or(Errno::EINVAL)?
                        .port();
                }
                drop(fd); // Close our copy of the socket.

                // Clear caches to ensure consistency.
                request.cache.addr_cache.0.clear();

                Some(format!("{addr}!{port}"))
            }
            Some(AddressFamily::Inet6) => {
                if !allow_safe_bind {
                    return Ok(());
                }

                let addr = addr.as_sockaddr_in6().ok_or(Errno::EINVAL)?;
                let mut port = addr.port();

                let addr = IpAddr::V6(addr.ip());
                if port == 0 {
                    port = getsockname::<SockaddrStorage>(fd.as_raw_fd())?
                        .as_sockaddr_in6()
                        .ok_or(Errno::EINVAL)?
                        .port();
                }
                drop(fd); // Close our copy of the socket.

                // Clear caches to ensure consistency.
                request.cache.addr_cache.0.clear();

                Some(format!("{addr}!{port}"))
            }
            _ => {
                drop(fd); // Close our copy of the socket.

                None
            }
        };

        if let Some(addr) = addr {
            // Configure sandbox, note we remove
            // and readd the address so repeated
            // binds to the same address cannot
            // overflow the vector.
            let config: &[String] = &[
                format!("allow/net/connect-{addr}"),
                format!("allow/net/connect+{addr}"),
            ];

            // TODO: Log errors!
            if let Some(mut sandbox) = sandbox {
                for cmd in config {
                    sandbox.config(cmd)?;
                }
            } else {
                let mut sandbox = request.get_mut_sandbox();
                for cmd in config {
                    sandbox.config(cmd)?;
                }
            }
        }

        // 1. The sandbox lock will be released on drop here.
        // 2. The socket fd will be closed on drop here.
        Ok(())
    })(fd, request);

    Ok(request.return_syscall(0))
}

fn handle_connect(
    fd: OwnedFd,
    addr: &SockaddrStorage,
    request: &UNotifyEventRequest,
) -> Result<ScmpNotifResp, Errno> {
    // SAFETY: Record blocking call so it can get invalidated.
    let req = request.scmpreq;
    let is_blocking = if !get_nonblock(&fd)? {
        let ignore_restart = has_recv_timeout(&fd)?;

        // Record the blocking call.
        request.cache.add_sys_block(req, ignore_restart)?;

        true
    } else {
        false
    };

    let result = connect(fd.as_raw_fd(), addr).map(|_| request.return_syscall(0));
    drop(fd); // Close our copy of the socket.

    // Remove invalidation record unless interrupted.
    if is_blocking && !matches!(result, Err(Errno::EINTR)) {
        request.cache.del_sys_block(req.id);
    }

    result
}

fn handle_sendto(
    fd: OwnedFd,
    args: &[u64; 6],
    request: &UNotifyEventRequest,
    addr: Option<&SockaddrStorage>,
) -> Result<ScmpNotifResp, Errno> {
    // SAFETY: The length argument to the sendto call
    // must not be fully trusted, it can be overly large,
    // and allocating a Vector of that capacity may overflow.
    let len = usize::try_from(args[2])
        .or(Err(Errno::EINVAL))?
        .min(1000000); // Cap count at 1mio.
    #[allow(clippy::cast_possible_truncation)]
    let flags = MsgFlags::from_bits_truncate(args[3] as libc::c_int);
    let mut buf = Vec::new();
    buf.try_reserve(len).or(Err(Errno::ENOMEM))?;
    buf.resize(len, 0);
    request.read_mem(&mut buf, args[1])?;

    // SAFETY: Record blocking call so it can get invalidated.
    let req = request.scmpreq;
    let is_blocking = if !flags.contains(MsgFlags::MSG_DONTWAIT) && !get_nonblock(&fd)? {
        let ignore_restart = has_recv_timeout(&fd)?;

        // Record the blocking call.
        request.cache.add_sys_block(req, ignore_restart)?;

        true
    } else {
        false
    };

    #[allow(clippy::cast_possible_wrap)]
    let result = if let Some(addr) = addr {
        // Connection-less socket.
        sendto(fd.as_raw_fd(), &buf, addr, flags)
    } else {
        // Connection mode socket, no address specified.
        send(fd.as_raw_fd(), &buf, flags)
    }
    .map(|n| request.return_syscall(n as i64));
    drop(fd); // Close our copy of the socket.

    // Remove invalidation record unless interrupted.
    if is_blocking && !matches!(result, Err(Errno::EINTR)) {
        request.cache.del_sys_block(req.id);
    }

    result
}

fn handle_accept(
    fd: OwnedFd,
    request: &UNotifyEventRequest,
    args: &[u64; 6],
    op: u8,
) -> Result<ScmpNotifResp, Errno> {
    // Determine the socket family.
    let fml = getsockdomain(&fd).or(Err(op2errno(op)))?;
    let ipv6 = match fml {
        libc::AF_INET6 => true,
        libc::AF_INET => false,
        _ => {
            // Not an IPv{4,6} socket, continue.
            // SAFETY: No pointer-dereference in access check.
            return unsafe { Ok(request.continue_syscall()) };
        }
    };

    // Determine address length if specified.
    let addrlen = if args[2] != 0 {
        const SIZEOF_SOCKLEN_T: usize = std::mem::size_of::<libc::socklen_t>();
        let mut buf = [0u8; SIZEOF_SOCKLEN_T];
        if request.read_mem(&mut buf, args[2])? == SIZEOF_SOCKLEN_T {
            // libc defines socklen_t as u32,
            // however we should check for negative values
            // and return EINVAL as necessary.
            let len = i32::from_ne_bytes(buf);
            let len = libc::socklen_t::try_from(len).or(Err(Errno::EINVAL))?;
            if args[1] == 0 {
                // address length is positive however address is NULL,
                // return EFAULT.
                return Err(Errno::EFAULT);
            }
            Some(len)
        } else {
            // Invalid/short read, assume invalid address length.
            return Err(Errno::EINVAL);
        }
    } else {
        None
    };

    #[allow(clippy::cast_possible_truncation)]
    let mut flags = if op == 0x12 {
        // accept4
        SockFlag::from_bits_truncate(args[3] as i32)
    } else {
        // accept
        SockFlag::empty()
    };
    let cloexec = flags.contains(SockFlag::SOCK_CLOEXEC);
    flags.insert(SockFlag::SOCK_CLOEXEC);

    // SAFETY: Record blocking call so it can get invalidated.
    let req = request.scmpreq;
    let is_blocking = if !get_nonblock(&fd)? {
        let ignore_restart = has_recv_timeout(&fd)?;

        // Record the blocking call.
        request.cache.add_sys_block(req, ignore_restart)?;

        true
    } else {
        false
    };

    // Do the accept call.
    let result = do_accept4(fd, flags);

    // Remove invalidation record unless interrupted.
    if is_blocking && !matches!(result, Err(Errno::EINTR)) {
        request.cache.del_sys_block(req.id);
    }

    // Only now, bail if accept failed.
    let (fd, addr, addrlen_out) = result?;

    // Check the returned address for access.
    let sandbox = request.get_sandbox();
    if ipv6 {
        sandbox_addr_inet6(request, &sandbox, &addr, op, Capability::CAP_NET_CONNECT)?;
    } else {
        sandbox_addr_inet(request, &sandbox, &addr, op, Capability::CAP_NET_CONNECT)?;
    }
    drop(sandbox); // release the read lock.

    // Write address buffer as necessary.
    if let Some(addrlen) = addrlen {
        // Create a byte slice from the socket address pointer.
        // SAFETY:
        // 1. `addrlen_out` value is returned by the host Linux kernel
        //    and is therefore trusted.
        // 2. `ptr` is a valid pointer to memory of at least
        //    `addrlen_out` bytes, as it is provided by the
        //    `SockaddrStorage` instance.
        // 3. The `SockaddrStorage` type ensures that the memory pointed
        //    to by `ptr` is valid and properly aligned.
        let buf = unsafe { std::slice::from_raw_parts(addr.as_ptr().cast(), addrlen_out as usize) };

        // Write the truncated socket address into memory.
        // SAFETY: We truncate late to avoid potential UB in
        // std::slice::slice_from_raw_parts().
        let len = addrlen_out.min(addrlen) as usize;
        request.write_mem(&buf[..len], args[1])?;

        // Convert `addrlen_out` into a vector of bytes.
        // SAFETY: This must be socklen_t and _not_ usize!
        let buf = addrlen_out.to_ne_bytes();

        // Write `addrlen_out` into memory.
        request.write_mem(&buf, args[2])?;
    }

    // Send the fd and return.
    request.send_fd(&fd, cloexec)
}

fn do_accept4(
    fd: OwnedFd,
    flags: SockFlag,
) -> Result<(OwnedFd, SockaddrStorage, libc::socklen_t), Errno> {
    // Allocate storage for the address.
    let mut addr: [u8; std::mem::size_of::<SockaddrStorage>()] =
        [0u8; std::mem::size_of::<SockaddrStorage>()];
    #[allow(clippy::cast_possible_truncation)]
    let mut len = std::mem::size_of::<SockaddrStorage>() as libc::socklen_t;

    // Cast the storage buffer to a sockaddr pointer.
    #[allow(clippy::cast_ptr_alignment)]
    let ptr = addr.as_mut_ptr() as *mut libc::sockaddr;

    // SAFETY: In libc we trust.
    let fd = Errno::result(unsafe { libc::accept4(fd.as_raw_fd(), ptr, &mut len, flags.bits()) })
        .map(|fd| {
        // SAFETY: accept4 returns a valid FD.
        unsafe { OwnedFd::from_raw_fd(fd) }
    })?;

    // SAFETY:
    // Convert the raw address into a SockaddrStorage structure.
    // accept4 returned success so the pointer is valid.
    let addr = unsafe { SockaddrStorage::from_raw(ptr, Some(len)) }.ok_or(Errno::EINVAL)?;

    Ok((fd, addr, len))
}

fn handle_getsockname(
    fd: OwnedFd,
    request: &UNotifyEventRequest,
    args: &[u64; 6],
) -> Result<ScmpNotifResp, Errno> {
    // Get socket inode.
    let inode = fstatx(&fd, STATX_INO).map(|statx| statx.stx_ino)?;
    drop(fd); // Close our copy of the socket.

    // Lookup path by inode in sandbox bind map.
    let sandbox = request.get_sandbox();
    let addr = if let Some(addr) = sandbox.get_bind(inode) {
        addr
    } else {
        // Not a UNIX socket, continue.
        // SAFETY: No pointer-dereference in access check.
        return unsafe { Ok(request.continue_syscall()) };
    };
    drop(sandbox); // release the read-lock.

    // Determine address length.
    let addrlen = if args[2] != 0 {
        const SIZEOF_SOCKLEN_T: usize = std::mem::size_of::<libc::socklen_t>();
        let mut buf = [0u8; SIZEOF_SOCKLEN_T];
        if request.read_mem(&mut buf, args[2])? == SIZEOF_SOCKLEN_T {
            // libc defines socklen_t as u32,
            // however we should check for negative values
            // and return EINVAL as necessary.
            let len = i32::from_ne_bytes(buf);
            let len = libc::socklen_t::try_from(len).or(Err(Errno::EINVAL))?;
            if args[1] == 0 {
                // address length is positive however address is NULL,
                // return EFAULT.
                return Err(Errno::EFAULT);
            }
            len
        } else {
            // Invalid/short read, assume invalid address length.
            return Err(Errno::EINVAL);
        }
    } else {
        // addrlen must not be NULL.
        return Err(Errno::EFAULT);
    };

    // Write address buffer.
    let ptr = addr.as_ptr() as *const u8;
    let len = addr.len() as usize;

    // Create a byte slice from the socket address pointer.
    // SAFETY: `ptr` is a valid pointer to memory of at least `len`
    // bytes, as it is provided by the `SockaddrStorage` instance.
    // The `SockaddrStorage` type ensures that the memory pointed to
    // by `ptr` is valid and properly aligned.
    let buf = unsafe { std::slice::from_raw_parts(ptr, len) };

    // Write the truncated socket address into memory.
    let len = len.min(addrlen as usize);
    request.write_mem(&buf[..len], args[1])?;

    // Convert address length into a vector of bytes.
    let buf = addr.len().to_ne_bytes();

    // Write address length into memory.
    request.write_mem(&buf, args[2])?;

    Ok(request.return_syscall(0))
}

#[allow(clippy::cognitive_complexity)]
#[allow(clippy::too_many_arguments)]
fn handle_sendmsg(
    fd: OwnedFd,
    request: &UNotifyEventRequest,
    args: &[u64; 6],
    allow_unsupp_socket: bool,
) -> Result<ScmpNotifResp, Errno> {
    #[allow(clippy::cast_possible_truncation)]
    let flags = MsgFlags::from_bits_truncate(args[2] as libc::c_int);

    let req = request.scmpreq;
    let is32 = scmp_arch_bits(req.data.arch) == 32;
    let mut buf = if is32 {
        // SAFETY: socketcall is the same number on all:
        // x86, mips, mipsel, ppc, ppc64, ppc64le, s390 and s390x.
        const SIZ: usize = std::mem::size_of::<msghdr32>();
        let mut buf = Vec::new();
        buf.try_reserve(SIZ).or(Err(Errno::ENOMEM))?;
        buf.resize(SIZ, 0);
        buf
    } else {
        const SIZ: usize = std::mem::size_of::<msghdr>();
        let mut buf = Vec::new();
        buf.try_reserve(SIZ).or(Err(Errno::ENOMEM))?;
        buf.resize(SIZ, 0);
        buf
    };
    request.read_mem(&mut buf, args[1])?;

    let msg = if is32 {
        // SAFETY: See below.
        let msg: msghdr32 = unsafe { std::ptr::read_unaligned(buf.as_ptr() as *const _) };
        crate::compat::msghdr::from(msg)
    } else {
        // SAFETY: The following unsafe block assumes that:
        // 1. The memory layout of open_how in our Rust environment
        //    matches that of the target process.
        // 2. The request.process.read_mem call has populated buf with valid data
        //    of the appropriate size (ensured by the size check above).
        // 3. The buffer is appropriately aligned for reading an
        //    open_how struct. If the remote process's representation of
        //    open_how was correctly aligned, our local buffer should be
        //    too, since it's an array on the stack.
        unsafe { std::ptr::read_unaligned(buf.as_ptr() as *const _) }
    };

    let addr_remote = msg.msg_name;
    let addr_len = msg.msg_namelen;

    // Step 1: Handle the address.
    let sandbox = request.get_sandbox();
    let addr = if !addr_remote.is_null() && addr_len > 0 {
        let (addr, root) = canon_addr(
            request,
            &sandbox,
            get_addr(request, addr_remote as u64, addr_len)?,
            Capability::CAP_NET_CONNECT,
            sandbox.flags,
        )?;
        match addr_family(&addr) {
            PF_UNIX | PF_INET | PF_INET6 => {
                // Check for access.
                sandbox_addr(
                    request,
                    &sandbox,
                    &addr,
                    &root,
                    0x10,
                    Capability::CAP_NET_CONNECT,
                )?;
            }
            PF_ALG | PF_NETLINK => {
                // SAFETY: We do not check AF_ALG or AF_NETLINK for access.
            }
            _ if allow_unsupp_socket => {
                // SAFETY: No pointer-dereference in access check.
                return unsafe { Ok(request.continue_syscall()) };
            }
            _ => return Err(Errno::EAFNOSUPPORT),
        };

        Some((addr, root))
    } else {
        // Connection-mode socket.
        // SAFETY: We cannot continue here due to the added level of
        // pointer indirection.
        None
    };

    // Step 2: Handle control messages.
    #[allow(clippy::collection_is_never_read)]
    let mut control_messages = Vec::new();
    let control_data = if !msg.msg_control.is_null() && msg.msg_controllen > 0 {
        #[allow(clippy::useless_conversion)]
        let cmsg_len = usize::try_from(msg.msg_controllen)
            .or(Err(Errno::EINVAL))?
            .min(1000000); // SAFETY: Cap at 1mio.
        let mut cmsg_buf = Vec::new();
        cmsg_buf.try_reserve(cmsg_len).or(Err(Errno::ENOMEM))?;
        cmsg_buf.resize(cmsg_len, 0);
        request.read_mem(&mut cmsg_buf, msg.msg_control as u64)?;
        Some(parse_control_messages(request, &cmsg_buf)?)
    } else {
        None
    };

    if let Some((
        ref _control_fds, // Keep the OwnedFd alive!
        ref control_raw_fds,
        ref control_creds,
        ref control_ivs,
        ref control_ops,
        ref control_aead_assoclens,
        ref control_udp_gso_segments,
        ref control_ipv4_packet_infos,
        ref control_ipv6_packet_infos,
        ref control_rxq_ovfls,
        ref control_tx_times,
    )) = control_data
    {
        // Check for sendfd access as necessary.
        if !control_raw_fds.is_empty() {
            if let Some((ref addr, ref root)) = addr {
                sandbox_addr(
                    request,
                    &sandbox,
                    addr,
                    root,
                    0x10,
                    Capability::CAP_NET_SENDFD,
                )?;
            } else {
                // Unused when request.is_some()
                let process = RemoteProcess::new(request.scmpreq.pid());

                // SAFETY: For cases where address is not available, we
                // perform an access check with a dummy path so as to
                // enable user to practically confine this case.
                sandbox_path(
                    Some(request),
                    &request.cache,
                    &sandbox,
                    &process,
                    XPath::from_bytes(b"!unnamed"),
                    Capability::CAP_NET_SENDFD,
                    false,
                    "sendmsg",
                )?;
            }
        }

        for raw_fds in control_raw_fds {
            // SAFETY: Deny sending file descriptors referring to
            // 1. Block devices
            // 2. Directories
            // 3. Symbolic links
            //
            // Note, we do allow files of unknown type such as epoll
            // fds and event fds as some programs such as pipewire
            // depend on this. See test-pw-filter test of pipewire
            // for more information about this.
            for raw_fd in raw_fds {
                if matches!(
                    file_type(raw_fd, None, false)?,
                    FileType::Blk | FileType::Dir | FileType::Lnk
                ) {
                    // TODO: Log this deny!
                    return Err(Errno::EACCES);
                }
            }

            control_messages.push(ControlMessage::ScmRights(raw_fds));
        }

        for creds in control_creds {
            control_messages.push(ControlMessage::ScmCredentials(creds));
        }

        for iv_data in control_ivs {
            control_messages.push(ControlMessage::AlgSetIv(iv_data));
        }

        for op in control_ops {
            control_messages.push(ControlMessage::AlgSetOp(op));
        }

        for assoclen in control_aead_assoclens {
            control_messages.push(ControlMessage::AlgSetAeadAssoclen(assoclen));
        }

        for gso_segments in control_udp_gso_segments {
            control_messages.push(ControlMessage::UdpGsoSegments(gso_segments));
        }

        for pktinfo in control_ipv4_packet_infos {
            control_messages.push(ControlMessage::Ipv4PacketInfo(pktinfo));
        }

        for pktinfo in control_ipv6_packet_infos {
            control_messages.push(ControlMessage::Ipv6PacketInfo(pktinfo));
        }

        for rxq_ovfl in control_rxq_ovfls {
            control_messages.push(ControlMessage::RxqOvfl(rxq_ovfl));
        }

        for tx_time in control_tx_times {
            control_messages.push(ControlMessage::TxTime(tx_time));
        }
    }
    drop(sandbox); // release the read-lock.

    // Step 3: Handle the payload which is an array of struct iovecs.
    let mut io_buffers: Vec<Vec<u8>> = Vec::new();
    let mut io_slices: Vec<IoSlice> = Vec::new();
    if !(msg.msg_iov.is_null() || msg.msg_iovlen == 0) {
        // SAFETY: The msg_iovlen member of the msghdr struct
        // must not be fully trusted, it can be overly large,
        // and allocating a Vector of that capacity may overflow.
        #[allow(clippy::useless_conversion)]
        let len = usize::try_from(msg.msg_iovlen)
            .or(Err(Errno::EINVAL))?
            .min(1000000); // Cap count at 1mio
        let size = if is32 {
            len.checked_mul(std::mem::size_of::<crate::compat::iovec32>())
        } else {
            len.checked_mul(std::mem::size_of::<libc::iovec>())
        }
        .ok_or(Errno::EINVAL)?;
        let mut buf = Vec::new();
        buf.try_reserve(size).or(Err(Errno::ENOMEM))?;
        buf.resize(size, 0);
        request.read_mem(&mut buf, msg.msg_iov as u64)?;

        // SAFETY: This operation assumes that the buffer (`buf`) contains a valid sequence of bytes
        // that correctly represent an array of `iovec` structures. This is ensured by the preceding
        // code that reads memory into `buf` with proper length calculation. The length `len` is
        // derived from `msg.msg_iovlen` and capped to prevent overflow, ensuring that we do not
        // exceed the allocation size of `buf`. The conversion to a pointer and then to a slice
        // of `iovec` is safe under these conditions, assuming the memory layout of `iovec` is
        // correct and `buf` is correctly sized and aligned.
        let mut iovecs: Vec<libc::iovec> = Vec::new();
        if is32 {
            for chunk in buf.chunks(std::mem::size_of::<crate::compat::iovec32>()) {
                // SAFETY: See above.
                let iov32: crate::compat::iovec32 =
                    unsafe { std::ptr::read_unaligned(chunk.as_ptr() as *const _) };
                iovecs.push(iov32.into());
            }
        } else {
            for chunk in buf.chunks(std::mem::size_of::<libc::iovec>()) {
                // SAFETY: See above.
                iovecs.push(unsafe { std::ptr::read_unaligned(chunk.as_ptr() as *const _) });
            }
        };

        for iov in iovecs {
            if iov.iov_base.is_null() || iov.iov_len == 0 {
                // XXX: This happens with socketcall on x86, why?
                continue;
            }

            // Cap the length to a maximum value to avoid large allocations.
            // SAFETY: The maximum length cap prevents excessive memory
            // allocation based on untrusted `iov_len`.
            let iov_len = iov.iov_len.min(1000000); // Cap count at 1mio

            // Allocate a buffer to read into. This buffer size is now capped.
            let mut data_buf = Vec::new();
            data_buf.try_reserve(iov_len).or(Err(Errno::ENOMEM))?;
            data_buf.resize(iov_len, 0);

            // Read the memory from the remote process into our buffer.
            // SAFETY: This operation relies on the correctness of
            // `iov_base` as a pointer into the remote process's memory and
            // the capped `iov_len`.
            request.read_mem(&mut data_buf, iov.iov_base as u64)?;

            // Keep the pointer accessible, IoSlice needs a valid reference.
            io_buffers.try_reserve(1).or(Err(Errno::ENOMEM))?;
            io_buffers.push(data_buf);
        }
        io_slices
            .try_reserve(io_buffers.len())
            .or(Err(Errno::ENOMEM))?;
        for buffer in &io_buffers {
            io_slices.push(IoSlice::new(buffer));
        }
    }

    // SAFETY: Record blocking call so it can get invalidated.
    let is_blocking = if !flags.contains(MsgFlags::MSG_DONTWAIT) && !get_nonblock(&fd)? {
        let req = request.scmpreq;
        let ignore_restart = has_recv_timeout(&fd)?;

        // Record the blocking call.
        request.cache.add_sys_block(req, ignore_restart)?;

        true
    } else {
        false
    };

    #[allow(clippy::cast_possible_wrap)]
    let result = if let Some((addr, _)) = addr {
        // UNIX domain/abstract socket.
        sendmsg(
            fd.as_raw_fd(),
            &io_slices,
            &control_messages,
            flags,
            Some(&addr),
        )
    } else {
        // Connection-mode socket.
        sendmsg::<SockaddrStorage>(fd.as_raw_fd(), &io_slices, &control_messages, flags, None)
    }
    .map(|n| request.return_syscall(n as i64));
    drop(fd); // Close our copy of the socket.

    // Remove invalidation record unless interrupted.
    if is_blocking && !matches!(result, Err(Errno::EINTR)) {
        request.cache.del_sys_block(req.id);
    }

    result
}

#[allow(clippy::cognitive_complexity)]
#[allow(clippy::too_many_arguments)]
fn handle_sendmmsg(
    fd: OwnedFd,
    request: &UNotifyEventRequest,
    args: &[u64; 6],
    allow_unsupp_socket: bool,
) -> Result<ScmpNotifResp, Errno> {
    #[allow(clippy::cast_possible_truncation)]
    let msgflags = MsgFlags::from_bits_truncate(args[3] as libc::c_int);

    // NULL check was performed already.
    let addr = args[1];
    let vlen = usize::try_from(args[2]).or(Err(Errno::EINVAL))?;
    if vlen == 0 {
        return Ok(request.return_syscall(0));
    }
    let vlen = vlen.min(1024); // Cap at IOV_MAX

    let req = request.scmpreq;
    let is32 = scmp_arch_bits(req.data.arch) == 32;

    let size = if is32 {
        vlen.checked_mul(std::mem::size_of::<crate::compat::mmsghdr32>())
    } else {
        vlen.checked_mul(std::mem::size_of::<crate::compat::mmsghdr>())
    }
    .ok_or(Errno::EINVAL)?;

    // Read mmsghdr structures from remote process memory
    let mut buf = Vec::new();
    buf.try_reserve(size).or(Err(Errno::ENOMEM))?;
    buf.resize(size, 0);
    request.read_mem(&mut buf, addr)?;

    let mut mmsghdrs: Vec<crate::compat::mmsghdr> = Vec::new();
    if is32 {
        for chunk in buf.chunks(std::mem::size_of::<crate::compat::mmsghdr32>()) {
            // SAFETY: See the relevant comment in handle_sendmsg.
            let mmsghdr: crate::compat::mmsghdr32 =
                unsafe { std::ptr::read_unaligned(chunk.as_ptr() as *const _) };
            mmsghdrs.try_reserve(1).or(Err(Errno::ENOMEM))?;
            mmsghdrs.push(mmsghdr.into());
        }
    } else {
        for chunk in buf.chunks(std::mem::size_of::<crate::compat::mmsghdr>()) {
            mmsghdrs.try_reserve(1).or(Err(Errno::ENOMEM))?;
            // SAFETY: See the relevant comment in handle_sendmsg.
            mmsghdrs.push(unsafe { std::ptr::read_unaligned(chunk.as_ptr() as *const _) });
        }
    };

    // Check if the call is a blocking call which we need to invalidate as necessary.
    let (is_blocking, ignore_restart) =
        if !msgflags.contains(MsgFlags::MSG_DONTWAIT) && !get_nonblock(&fd)? {
            (true, has_recv_timeout(&fd)?)
        } else {
            (false, false)
        };

    // Prepare a series of sendmsg calls.
    for mmsg in &mut mmsghdrs {
        let msg = &mut mmsg.msg_hdr;

        // Step 1: Handle the address.
        let addr_remote = msg.msg_name;
        let addr_len = msg.msg_namelen;
        let sandbox = request.get_sandbox();
        let addr_root = if !addr_remote.is_null() && addr_len > 0 {
            let (addr, root) = canon_addr(
                request,
                &sandbox,
                get_addr(request, addr_remote as u64, addr_len)?,
                Capability::CAP_NET_CONNECT,
                sandbox.flags,
            )?;
            match addr_family(&addr) {
                PF_UNIX | PF_INET | PF_INET6 => {
                    // Check for access.
                    sandbox_addr(
                        request,
                        &sandbox,
                        &addr,
                        &root,
                        0x14,
                        Capability::CAP_NET_CONNECT,
                    )?;
                }
                PF_ALG | PF_NETLINK => {
                    // SAFETY: We do not check AF_ALG and AF_NETLINK for access.
                }
                _ if allow_unsupp_socket => {
                    // SAFETY: No pointer-dereference in access check.
                    return unsafe { Ok(request.continue_syscall()) };
                }
                _ => return Err(Errno::EAFNOSUPPORT),
            };

            Some((addr, root))
        } else {
            // Connection-mode socket.
            // SAFETY: We cannot continue here due to the added level of
            // pointer indirection.
            None
        };

        // Step 2: Handle control messages.
        let mut control_data = Vec::new();
        let control_datum = if !msg.msg_control.is_null() && msg.msg_controllen > 0 {
            #[allow(clippy::useless_conversion)]
            let cmsg_len = usize::try_from(msg.msg_controllen)
                .or(Err(Errno::EINVAL))?
                .min(1000000); // SAFETY: Cap at 1mio.
            let mut cmsg_buf = Vec::new();
            cmsg_buf.try_reserve(cmsg_len).or(Err(Errno::ENOMEM))?;
            cmsg_buf.resize(cmsg_len, 0);
            request.read_mem(&mut cmsg_buf, msg.msg_control as u64)?;
            Some(parse_control_messages(request, &cmsg_buf)?)
        } else {
            None
        };
        control_data.try_reserve(1).or(Err(Errno::ENOMEM))?;
        control_data.push(control_datum); // Keep OwnedFd alive!

        let mut control_messages = Vec::new();
        for control_datum in &control_data {
            if let Some((
                ref _control_fds, // Keep the OwnedFd alive!
                ref control_raw_fds,
                ref control_creds,
                ref control_ivs,
                ref control_ops,
                ref control_aead_assoclens,
                ref control_udp_gso_segments,
                ref control_ipv4_packet_infos,
                ref control_ipv6_packet_infos,
                ref control_rxq_ovfls,
                ref control_tx_times,
            )) = &control_datum
            {
                // Check for sendfd access as necessary.
                if !control_raw_fds.is_empty() {
                    if let Some((ref addr, ref root)) = addr_root {
                        sandbox_addr(
                            request,
                            &sandbox,
                            addr,
                            root,
                            0x10,
                            Capability::CAP_NET_SENDFD,
                        )?;
                    } else {
                        // Unused when request.is_some()
                        let process = RemoteProcess::new(request.scmpreq.pid());

                        // SAFETY: For cases where address is not available, we
                        // perform an access check with a dummy path so as to
                        // enable user to practically confine this case.
                        sandbox_path(
                            Some(request),
                            &request.cache,
                            &sandbox,
                            &process,
                            XPath::from_bytes(b"!unnamed"),
                            Capability::CAP_NET_SENDFD,
                            false,
                            "sendmmsg",
                        )?;
                    }
                }

                for raw_fds in control_raw_fds {
                    // SAFETY: Deny sending file descriptors referring to
                    // 1. Block devices
                    // 2. Directories
                    // 3. Symbolic links
                    //
                    // Note, we do allow files of unknown type such as epoll
                    // fds and event fds as some programs such as pipewire
                    // depend on this. See test-pw-filter test of pipewire
                    // for more information about this.
                    for raw_fd in raw_fds {
                        if matches!(
                            file_type(raw_fd, None, false)?,
                            FileType::Blk | FileType::Dir | FileType::Lnk
                        ) {
                            // TODO: Log this deny!
                            return Err(Errno::EACCES);
                        }
                    }

                    control_messages.push(ControlMessage::ScmRights(raw_fds));
                }

                for creds in control_creds {
                    control_messages.push(ControlMessage::ScmCredentials(creds));
                }

                for iv_data in control_ivs {
                    control_messages.push(ControlMessage::AlgSetIv(iv_data));
                }

                for op in control_ops {
                    control_messages.push(ControlMessage::AlgSetOp(op));
                }

                for assoclen in control_aead_assoclens {
                    control_messages.push(ControlMessage::AlgSetAeadAssoclen(assoclen));
                }

                for gso_segments in control_udp_gso_segments {
                    control_messages.push(ControlMessage::UdpGsoSegments(gso_segments));
                }

                for pktinfo in control_ipv4_packet_infos {
                    control_messages.push(ControlMessage::Ipv4PacketInfo(pktinfo));
                }

                for pktinfo in control_ipv6_packet_infos {
                    control_messages.push(ControlMessage::Ipv6PacketInfo(pktinfo));
                }

                for rxq_ovfl in control_rxq_ovfls {
                    control_messages.push(ControlMessage::RxqOvfl(rxq_ovfl));
                }

                for tx_time in control_tx_times {
                    control_messages.push(ControlMessage::TxTime(tx_time));
                }
            }
        }
        drop(sandbox); // release the read-lock before emulation.

        // Step 3: Handle the payload which is an array of struct iovecs.
        let mut io_buffers = Vec::new();
        let mut io_slices: Vec<IoSlice> = Vec::new();
        if !(msg.msg_iov.is_null() || msg.msg_iovlen == 0) {
            // SAFETY: The msg_iovlen member of the msghdr struct
            // must not be fully trusted, it can be overly large,
            // and allocating a Vector of that capacity may overflow.
            #[allow(clippy::useless_conversion)]
            let len = usize::try_from(msg.msg_iovlen)
                .or(Err(Errno::EINVAL))?
                .min(1000000); // Cap count at 1mio.
            let size = if is32 {
                len.checked_mul(std::mem::size_of::<crate::compat::iovec32>())
            } else {
                len.checked_mul(std::mem::size_of::<libc::iovec>())
            }
            .ok_or(Errno::EINVAL)?;
            let mut buf = Vec::new();
            buf.try_reserve(size).or(Err(Errno::ENOMEM))?;
            buf.resize(size, 0);
            request.read_mem(&mut buf, msg.msg_iov as u64)?;

            let mut iovecs: Vec<libc::iovec> = Vec::new();
            if is32 {
                for chunk in buf.chunks(std::mem::size_of::<crate::compat::iovec32>()) {
                    // SAFETY: See the relevant comment in handle_sendmsg.
                    let iov32: crate::compat::iovec32 =
                        unsafe { std::ptr::read_unaligned(chunk.as_ptr() as *const _) };
                    iovecs.try_reserve(1).or(Err(Errno::ENOMEM))?;
                    iovecs.push(iov32.into());
                }
            } else {
                for chunk in buf.chunks(std::mem::size_of::<libc::iovec>()) {
                    iovecs.try_reserve(1).or(Err(Errno::ENOMEM))?;
                    // SAFETY: See the relevant comment in handle_sendmsg.
                    iovecs.push(unsafe { std::ptr::read_unaligned(chunk.as_ptr() as *const _) });
                }
            };

            for iov in iovecs {
                // Cap the length to a maximum value to avoid large allocations.
                // SAFETY: The maximum length cap prevents excessive memory
                // allocation based on untrusted `iov_len`.
                let iov_len = iov.iov_len.min(1000000); // Cap count at 1mio

                // Allocate a buffer to read into. This buffer size is now capped.
                let mut data_buf = Vec::new();
                data_buf.try_reserve(iov_len).or(Err(Errno::ENOMEM))?;
                data_buf.resize(iov_len, 0);

                // Read the memory from the remote process into our buffer.
                // SAFETY: This operation relies on the correctness of
                // `iov_base` as a pointer into the remote process's memory and
                // the capped `iov_len`.
                request.read_mem(&mut data_buf, iov.iov_base as u64)?;

                // Keep the pointer accessible, IoSlice needs a valid reference.
                io_buffers.push(data_buf);
            }
            for buffer in &io_buffers {
                io_slices.try_reserve(1).or(Err(Errno::ENOMEM))?;
                io_slices.push(IoSlice::new(buffer));
            }

            // SAFETY: Record blocking call so it can get invalidated.
            if is_blocking {
                request.cache.add_sys_block(req, ignore_restart)?;
            }

            // Make the sendmsg call.
            let result = if let Some((addr, _)) = addr_root {
                // Connection-less socket.
                sendmsg(
                    fd.as_raw_fd(),
                    &io_slices,
                    &control_messages,
                    msgflags,
                    Some(&addr),
                )
            } else {
                // Connection-mode socket.
                sendmsg::<SockaddrStorage>(
                    fd.as_raw_fd(),
                    &io_slices,
                    &control_messages,
                    msgflags,
                    None,
                )
            };

            // Remove invalidation record unless interrupted.
            if is_blocking && !matches!(result, Err(Errno::EINTR)) {
                request.cache.del_sys_block(req.id);
            }

            mmsg.msg_len = result?.try_into().or(Err(Errno::EINVAL))?;
        }
    }
    drop(fd); // Close our copy of the socket.

    // Write back mmsghdr structures to remote process memory
    let mut buf: Vec<u8> = Vec::new();
    if is32 {
        for mmsghdr in &mmsghdrs {
            let mmsghdr32: crate::compat::mmsghdr32 = (*mmsghdr).into();
            // SAFETY: Convert each mmsghdr (or mmsghdr32 within the
            // conversion logic) back to its byte representation.
            let bytes: [u8; std::mem::size_of::<crate::compat::mmsghdr32>()] =
                unsafe { std::mem::transmute(mmsghdr32) };
            buf.try_reserve(bytes.len()).or(Err(Errno::ENOMEM))?;
            buf.extend_from_slice(&bytes);
        }
    } else {
        for mmsghdr in &mmsghdrs {
            // SAFETY: See above.
            let bytes: [u8; std::mem::size_of::<crate::compat::mmsghdr>()] =
                unsafe { std::mem::transmute(*mmsghdr) };
            buf.try_reserve(bytes.len()).or(Err(Errno::ENOMEM))?;
            buf.extend_from_slice(&bytes);
        }
    }
    request.write_mem(&buf, addr)?;

    // FIXME: We do not handle partial success.
    #[allow(clippy::cast_possible_wrap)]
    Ok(request.return_syscall(mmsghdrs.len() as i64))
}

// SAFETY: Below lie daemons...
#[allow(clippy::type_complexity)]
fn parse_control_messages(
    request: &UNotifyEventRequest,
    cmsg_buf: &[u8],
) -> Result<
    (
        Vec<Vec<OwnedFd>>,
        Vec<Vec<RawFd>>,
        Vec<UnixCredentials>,
        Vec<Vec<u8>>,     // ivs
        Vec<libc::c_int>, // ops
        Vec<u32>,         // aead_assoclens
        Vec<u16>,         // udp_gso_segments
        Vec<libc::in_pktinfo>,
        Vec<libc::in6_pktinfo>,
        Vec<u32>, // rxq_ovfls
        Vec<u64>, // tx_times
    ),
    Errno,
> {
    let mut control_fds = Vec::new();
    let mut control_raw_fds = Vec::new();
    let mut control_creds = Vec::new();
    let mut control_ivs = Vec::new();
    let mut control_ops = Vec::new();
    let mut control_aead_assoclens = Vec::new();
    let mut control_udp_gso_segments = Vec::new();
    let mut control_ipv4_packet_infos = Vec::new();
    let mut control_ipv6_packet_infos = Vec::new();
    let mut control_rxq_ovfls = Vec::new();
    let mut control_tx_times = Vec::new();

    let mut offset = 0;
    let req = request.scmpreq;
    let is32 = scmp_arch_bits(req.data.arch) == 32;
    while offset < cmsg_buf.len() {
        // SAFETY: Ensuring alignment for `cmsghdr` by starting from a u8 pointer.  The
        // `cmsg_buf` is originally a u8 buffer, which may not satisfy the alignment
        // requirements of `cmsghdr`.  This cast assumes that the buffer provided by
        // `request.process.read_mem` is correctly aligned for `cmsghdr` structures, which is true if
        // the buffer is initially populated in a manner adhering to the alignment
        // requirements of `cmsghdr`.  The caller is responsible for ensuring that `offset`
        // is correctly aligned for `cmsghdr` when accessing the buffer.
        #[allow(clippy::cast_ptr_alignment)]
        let (cmsg_header, cmsg_len0): (crate::compat::cmsghdr, usize) = if is32 {
            // SAFETY: See the comment above.
            let cmsg_header_32: crate::compat::cmsghdr32 = unsafe {
                std::ptr::read_unaligned(
                    cmsg_buf[offset..].as_ptr() as *const crate::compat::cmsghdr32
                )
            };
            (cmsg_header_32.into(), cmsg_len_32(0))
        } else {
            (
                // SAFETY: See the comment above.
                unsafe {
                    std::ptr::read_unaligned(
                        cmsg_buf[offset..].as_ptr() as *const crate::compat::cmsghdr
                    )
                },
                // SAFETY: See the comment above.
                unsafe { libc::CMSG_LEN(0) } as usize,
            )
        };
        if cmsg_header.cmsg_len < cmsg_len0 {
            return Err(Errno::EINVAL); // Invalid header length
        }
        #[allow(clippy::useless_conversion)]
        let data_len: usize = cmsg_header.cmsg_len.try_into().or(Err(Errno::EINVAL))?;
        let data_len = data_len.checked_sub(cmsg_len0).ok_or(Errno::EINVAL)?;

        let data_off = offset.checked_add(cmsg_len0).ok_or(Errno::EINVAL)?;
        let data_end = data_off.checked_add(data_len).ok_or(Errno::EINVAL)?;
        if data_end > cmsg_buf.len() {
            return Err(Errno::EINVAL); // Data goes beyond buffer.
        }
        let data = &cmsg_buf[data_off..data_end];

        match (cmsg_header.cmsg_level, cmsg_header.cmsg_type) {
            (libc::SOL_SOCKET, libc::SCM_RIGHTS) => {
                #[allow(clippy::arithmetic_side_effects)]
                let fd_count = data_len / std::mem::size_of::<RawFd>();
                let mut raw_fds = Vec::with_capacity(fd_count);
                let mut fds = Vec::with_capacity(fd_count);
                // SAFETY: Multiplying `i` by `std::mem::size_of::<RawFd>()` calculates the
                // offset for each file descriptor in the control message data. This is safe
                // under the assumption that `data_len` (used to derive `fd_count`)
                // correctly represents a buffer containing `RawFd`s. `data_len` is checked
                // to ensure it's an exact multiple of `std::mem::size_of::<RawFd>()`,
                // preventing out-of-bounds access. Accessing the file descriptor using this
                // offset and converting it with `request.get_fd()` is based on the valid and
                // expected layout of file descriptors in the control message. This layout
                // and access method align with the conventions used by the underlying
                // system for `SCM_RIGHTS` control messages, ensuring that we read valid
                // file descriptor values from the buffer.
                for i in 0..fd_count {
                    #[allow(clippy::arithmetic_side_effects)]
                    let fd_offset = i * std::mem::size_of::<RawFd>();
                    #[allow(clippy::cast_ptr_alignment)]
                    // SAFETY: See the comment above.
                    let fd = unsafe { *(data[fd_offset..].as_ptr() as *const RawFd) };
                    let fd = request.get_fd(fd)?;
                    raw_fds.push(fd.as_raw_fd());
                    fds.push(fd); // Keep a ref to the OwnedFd.
                }
                control_raw_fds.push(raw_fds);
                control_fds.push(fds);
            }
            (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => {
                #[allow(clippy::cast_ptr_alignment)]
                // SAFETY: Casting `data.as_ptr()` to `*const libc::ucred` is safe
                // under the assumption that `data` contains bytes that correctly represent
                // a `libc::ucred` structure, and that `data_len` matches the size of
                // `libc::ucred`.  This assumption is based on the control message type
                // `SCM_CREDENTIALS`, which is expected to contain exactly one `libc::ucred`
                // structure representing the credentials of the sending process.  The
                // conversion to `UnixCredentials` is a safe operation that simply wraps the
                // raw credentials in a Rust-friendly type. The use of `unsafe` is necessary
                // to dereference the raw pointer obtained from the byte buffer, but the
                // operation is ensured to be valid by adhering to the expected control
                // message format and size.  This access pattern is consistent with the
                // standard way of handling `SCM_CREDENTIALS` control messages.
                let mut creds = *(unsafe { &*(data.as_ptr() as *const libc::ucred) });
                // SAFETY: The sender must specify its own pid (unless it has the capability
                // CAP_SYS_ADMIN, in which case the PID of any existing process may be specified.)
                creds.pid = Pid::this().as_raw();
                let unix_creds = UnixCredentials::from(creds);
                control_creds.push(unix_creds); // Keep a ref to the UnixCredentials.
            }
            (libc::SOL_ALG, libc::ALG_SET_IV) => {
                // IV data is directly contained in the data part of the control message
                // First four bytes represent the length of the IV.
                if data_len < 4 {
                    return Err(Errno::EINVAL); // Data length mismatch
                }
                let iv_size = u32::from_ne_bytes([data[0], data[1], data[2], data[3]]) as usize;
                let iv_size = iv_size.saturating_add(4);
                if iv_size <= data_len {
                    // Extract the IV while respecting the indicated size,
                    // if the size is valid.
                    let iv_data = Vec::from(&data[4..iv_size]);
                    control_ivs.push(iv_data); // Store the IV data
                } else {
                    return Err(Errno::EINVAL); // Data length mismatch.
                }
            }
            (libc::SOL_ALG, libc::ALG_SET_OP) => {
                // SAFETY: Casting `data.as_ptr()` to `*const libc::c_int` is based on
                // the expectation that `data` contains a buffer representing an operation
                // code of type `c_int` for the `ALG_SET_OP` control message.  This cast
                // assumes the beginning of `data` is correctly aligned for an `i32`, which
                // is valid if the control message was constructed correctly by the sender
                // according to the `AF_ALG` socket requirements. The check `data_len !=
                // std::mem::size_of::<libc::c_int>()` ensures that the buffer length
                // exactly matches the size of an `i32`, mitigating the risk of undefined
                // behavior due to incorrect buffer size. However, this operation bypasses
                // Rust's guarantees on data alignment, relying on the correct alignment by
                // the sender and adherence to the protocol's specification, which mandates
                // proper alignment for control message data.
                if data_len != std::mem::size_of::<libc::c_int>() {
                    return Err(Errno::EINVAL); // Data length mismatch
                }
                #[allow(clippy::cast_ptr_alignment)]
                // SAFETY: See the comment above.
                let op = unsafe { *(data.as_ptr() as *const libc::c_int) };
                control_ops.push(op); // Store the operation code
            }
            (libc::SOL_ALG, libc::ALG_SET_AEAD_ASSOCLEN) => {
                // SAFETY: The cast from `*const u8` to `*const u32` here assumes that the
                // data buffer, although initially handled as a sequence of bytes, is
                // correctly aligned for a `u32`. This assumption is contingent upon the
                // sender properly constructing the control message with the
                // `ALG_SET_AEAD_ASSOCLEN` type, ensuring the alignment meets the
                // requirements for `u32` data. The prerequisite check `data_len !=
                // std::mem::size_of::<u32>()` ensures the buffer is exactly the size of a
                // `u32`, mitigating risks associated with accessing beyond the buffer or
                // misinterpreting the data type.  While this operation inherently trusts
                // the message sender to adhere to alignment requirements, it aligns with
                // common practices for handling similarly structured control messages in
                // systems programming, where protocol adherence guarantees data alignment.
                if data_len != std::mem::size_of::<u32>() {
                    return Err(Errno::EINVAL); // Data length mismatch
                }
                #[allow(clippy::cast_ptr_alignment)]
                // SAFETY: See the comment above.
                let assoclen = unsafe { *(data.as_ptr() as *const u32) };
                control_aead_assoclens.push(assoclen); // Store the AEAD assoclen
            }
            (libc::SOL_UDP, libc::UDP_SEGMENT) => {
                // SAFETY: This unsafe block casts a pointer from `*const u8` to `*const
                // u16` under the assumption that the data at `data.as_ptr()` is correctly
                // aligned for `u16`. This is based on the expectation that the sender of
                // the control message aligns the data according to the `u16` requirements
                // when constructing the message for `UDP_SEGMENT`. The check `data_len !=
                // std::mem::size_of::<u16>()` ensures that the buffer is precisely the size
                // expected for a single `u16` value, thus avoiding potential overreads or
                // misinterpretation of the buffer content. This cast and dereference
                // operation is predicated on the alignment and size of the data being
                // appropriate for a `u16`, as per the protocol's definition for UDP segment
                // control messages, thereby justifying the bypass of Rust's alignment
                // safety checks.
                if data_len != std::mem::size_of::<u16>() {
                    return Err(Errno::EINVAL); // Data length mismatch
                }
                #[allow(clippy::cast_ptr_alignment)]
                // SAFETY: See the comment above.
                let gso_segments = unsafe { *(data.as_ptr() as *const u16) };
                control_udp_gso_segments.push(gso_segments); // Store the GSO segment count
            }
            (libc::IPPROTO_IP, libc::IP_PKTINFO) => {
                // SAFETY: The cast from `*const u8` to `*const libc::in_pktinfo` assumes
                // that the alignment requirements for `libc::in_pktinfo` are met. This
                // assumption is based on the contract that control message data, in this
                // case for `IP_PKTINFO`, is correctly aligned according to the
                // specifications of the underlying C and network protocols. The preceding
                // size check ensures that the buffer `data` contains exactly the amount of
                // bytes necessary to represent a single `libc::in_pktinfo` structure,
                // thereby avoiding both overreads and misinterpretation of the data.  The
                // dereference to access the `in_pktinfo` is then justified under the
                // assumption of proper alignment and correct data length, as mandated by
                // the control message's protocol definition.
                if data_len != std::mem::size_of::<libc::in_pktinfo>() {
                    return Err(Errno::EINVAL); // Data length mismatch
                }
                #[allow(clippy::cast_ptr_alignment)]
                // SAFETY: See the comment above.
                let pktinfo = unsafe { &*(data.as_ptr() as *const libc::in_pktinfo) };
                control_ipv4_packet_infos.push(*pktinfo); // Store the IPv4 packet info
            }
            (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => {
                // SAFETY: The cast from `*const u8` to `*const libc::in6_pktinfo` is made
                // under the assumption that the buffer is properly aligned for the
                // `libc::in6_pktinfo` structure. This is based on the expectation that the
                // sender of the control message correctly aligns the packet information
                // according to the IPv6 standard requirements. The check ensuring
                // `data_len` matches the size of `libc::in6_pktinfo` guarantees the buffer
                // contains enough data to represent an `in6_pktinfo` structure without
                // overreading. Aligning to and dereferencing the pointer to access the data
                // is therefore considered safe, assuming adherence to the protocol by the
                // message sender and that the data has been formatted and aligned correctly
                // for the type of control message being processed.
                if data_len != std::mem::size_of::<libc::in6_pktinfo>() {
                    return Err(Errno::EINVAL); // Data length mismatch
                }
                #[allow(clippy::cast_ptr_alignment)]
                // SAFETY: See the comment above.
                let pktinfo = unsafe { &*(data.as_ptr() as *const libc::in6_pktinfo) };
                control_ipv6_packet_infos.push(*pktinfo); // Store the IPv6 packet info
            }
            (libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => {
                // SAFETY: Casting from `*const u8` to `*const u32` here assumes that the
                // starting position of `data` is correctly aligned for `u32`. This
                // assumption is valid if the control message, specifically for
                // `SO_RXQ_OVFL`, is constructed with alignment considerations for `u32` as
                // per the protocol's specification. The precondition check that `data_len`
                // equals the size of `u32` ensures that we are accessing exactly one `u32`
                // value, preventing any overread or misinterpretation of the buffer's
                // content. This operation presumes that the control message's sender aligns
                // the data correctly and that the entire length of `data` is intended to
                // represent a single `u32` value, corresponding to the RX queue overflow
                // count. The correctness of this operation depends on adherence to these
                // alignment and size specifications by the sender.
                if data_len != std::mem::size_of::<u32>() {
                    return Err(Errno::EINVAL); // Data length mismatch
                }
                #[allow(clippy::cast_ptr_alignment)]
                // SAFETY: See the comment above.
                let rxq_ovfl = unsafe { *(data.as_ptr() as *const u32) };
                control_rxq_ovfls.push(rxq_ovfl); // Store the Rx queue overflow count
            }
            (libc::SOL_SOCKET, libc::SCM_TXTIME) => {
                // SAFETY: The casting from `*const u8` to `*const u64` is contingent upon
                // the assumption that the `data` buffer is aligned according to `u64`
                // alignment requirements. This operation is premised on the protocol's or
                // sender's adherence to correctly aligning the data for a `u64` value,
                // which is the expected format for `SCM_TXTIME` control messages. The check
                // against `data_len` being equal to the size of a `u64` ensures that only a
                // single `u64` value is accessed, mitigating the risk of buffer overreads
                // and ensuring the data is interpreted correctly as a transmission time.
                // This cast and dereference assume that the control message's composition
                // and alignment practices properly account for the alignment needs of a
                // `u64`, making the operation safe under these controlled conditions.
                if data_len != std::mem::size_of::<u64>() {
                    return Err(Errno::EINVAL); // Data length mismatch
                }
                #[allow(clippy::cast_ptr_alignment)]
                // SAFETY: See the comment above.
                let tx_time = unsafe { *(data.as_ptr() as *const u64) };
                control_tx_times.push(tx_time); // Store the Tx time
            }
            // TODO: DO we want to CONTINUE here if allow_unsupported_socket?
            _ => return Err(Errno::EINVAL),
        }

        // SAFETY: Incrementing `offset` by the result of `CMSG_SPACE(data_len as u32)` is safe
        // under the assumption that `data_len` accurately reflects the length of the current
        // control message's data, and the calculation of space accounts for any padding needed
        // for alignment in subsequent control messages.  The use of `CMSG_SPACE` ensures that
        // `offset` is correctly aligned for the start of the next control message in the
        // buffer, adhering to the alignment requirements of control messages. This operation
        // is guarded by checks on `data_len` and buffer bounds to prevent arithmetic overflows
        // or buffer over-reads, ensuring that the new `offset` value is within the bounds of
        // `cmsg_buf`. The reliance on `CMSG_SPACE` for alignment adjustment is standard
        // practice for parsing sequences of control messages in a buffer, provided that the
        // control message buffer (`cmsg_buf`) is initially aligned and structured correctly
        // according to control message protocols.
        #[allow(clippy::arithmetic_side_effects)]
        #[allow(clippy::cast_possible_truncation)]
        if !is32 {
            // SAFETY: See the comment above.
            offset += unsafe { libc::CMSG_SPACE(data_len as u32) } as usize;
        } else {
            offset += cmsg_space_32(data_len as u32);
        }
    }

    Ok((
        control_fds,
        control_raw_fds,
        control_creds,
        control_ivs,
        control_ops,
        control_aead_assoclens,
        control_udp_gso_segments,
        control_ipv4_packet_infos,
        control_ipv6_packet_infos,
        control_rxq_ovfls,
        control_tx_times,
    ))
}

fn get_addr(
    request: &UNotifyEventRequest,
    addr_remote: u64,
    addr_len: libc::socklen_t,
) -> Result<SockaddrStorage, Errno> {
    // SAFETY: Do not fully trust addr_len.
    #[allow(clippy::arithmetic_side_effects)]
    #[allow(clippy::cast_possible_truncation)]
    let addr_len =
        addr_len.min((std::mem::size_of::<libc::sockaddr_un>() + UNIX_PATH_MAX) as libc::socklen_t);
    let mut addr = Vec::new();
    addr.try_reserve(addr_len as usize).or(Err(Errno::ENOMEM))?;
    addr.resize(addr_len as usize, 0);
    request.read_mem(&mut addr, addr_remote)?;
    let addr = addr.as_ptr().cast();

    // SAFETY: Invoking `SockaddrStorage::from_raw` is safe because:
    // 1. The memory location of `sockaddr_ptr` is valid, correctly aligned.
    // 2. The memory is allocated based on a valid `sockaddr` structure.
    // 3. There are no concurrent writes to the memory location while reading.
    match unsafe {
        #[allow(clippy::cast_ptr_alignment)]
        SockaddrStorage::from_raw(addr, Some(addr_len))
    } {
        Some(addr) => Ok(addr),
        None => {
            // Invalid socket address.
            Err(Errno::EINVAL)
        }
    }
}

// Canonicalizes UNIX domain socket names.
// Returns address and directory.
// Directory is None for non-UNIX addresses.
fn canon_addr<'a>(
    request: &UNotifyEventRequest,
    sandbox: &SandboxGuard,
    addr: SockaddrStorage,
    cap: Capability,
    flags: Flags,
) -> Result<(SockaddrStorage, Option<CanonicalPath<'a>>), Errno> {
    #[allow(clippy::cast_possible_truncation)]
    if let Some(path) = addr.as_unix_addr().and_then(|a| a.path()) {
        // Check for chroot.
        if sandbox.is_chroot() {
            return Err(Errno::ENOENT);
        }

        // SAFETY: Path may have trailing nul-bytes.
        // Truncate the path at the first occurrence of a null byte
        // Note this is _not_ an abstract UNIX socket so it's safe.
        let path = path.as_os_str().as_bytes();
        let null = memchr::memchr(0, path).unwrap_or(path.len());
        let path = XPathBuf::from(&path[..null]);

        // If bind, the path may or may not exist depending on SO_REUSEADDR
        // Else, the path must exist.
        let fsflags = if cap == Capability::CAP_NET_BIND {
            FsFlags::empty()
        } else {
            FsFlags::MUST_PATH
        };

        // SAFETY:
        //
        // 1. Always resolve symlinks.
        // 2. Ensure relative UNIX socket paths match process CWD.
        let pid = request.scmpreq.pid();
        let path = safe_canonicalize(pid, None, &path, fsflags, flags)?;

        let cstr = if path.base.is_empty() {
            // SAFETY: We open a FD to the path and then use the
            // proc path /proc/self/fd/$fd in address' path argument
            // to avoid symlink TOCTOU because connect and sendto
            // follow symlinks in basename unlike bind.
            #[allow(clippy::disallowed_methods)]
            let fd = path.dir.as_ref().unwrap();
            let mut pfd = XPathBuf::from("/proc/self/fd");
            pfd.push_fd(fd.as_raw_fd());
            CString::new(pfd.as_os_str().as_bytes())
        } else {
            // SAFETY: We split the address into directory and basename
            // regardless of UNIX_PATH_MAX as we are later going to use
            // the handler thread to mitigate the TOCTOU vector in the
            // basename of the UNIX socket address. This is only used
            // for bind() which does not resolve symbolic links in
            // basename.
            CString::new(path.base.as_os_str().as_bytes())
        }
        .or(Err(Errno::EINVAL))?;

        // Create sockaddr_un struct.
        let mut sockaddr = libc::sockaddr_un {
            sun_family: libc::AF_UNIX as libc::sa_family_t,
            sun_path: [0; UNIX_PATH_MAX],
        };

        // Manually copy the bytes.
        // TODO: Is there a better way?
        #[allow(clippy::cast_possible_wrap)]
        for (dst, &src) in sockaddr.sun_path.iter_mut().zip(cstr.as_bytes_with_nul()) {
            *dst = src as libc::c_char;
        }

        // Calculate the correct size of the sockaddr_un struct,
        // including the family and the path. The size is the offset of
        // the sun_path field plus the length of the path (including the
        // null terminator).
        #[allow(clippy::arithmetic_side_effects)]
        let size = std::mem::size_of::<libc::sa_family_t>() + cstr.as_bytes_with_nul().len();

        // SAFETY: We are converting a sockaddr_un to a
        // SockaddrStorage using a raw pointer. The sockaddr_un
        // is valid for the duration of this operation, ensuring
        // the safety of the pointer. However, this operation is
        // inherently unsafe due to direct pointer manipulation.
        let addr = unsafe {
            SockaddrStorage::from_raw(
                std::ptr::addr_of!(sockaddr) as *const _,
                Some(size as libc::socklen_t),
            )
        }
        .ok_or(Errno::EINVAL)?;

        Ok((addr, Some(path)))
    } else {
        // No need to canonicalize.
        Ok((addr, None))
    }
}
