//
// Syd: rock-solid application kernel
// src/config.rs: Static configuration, edit & recompile!
//
// Copyright (c) 2023, 2024, 2025 Ali Polatel <alip@chesswob.org>
// Based in part upon HardenedBSD's sys/hardenedbsd/hbsd_pax_segvguard.c which is:
//   Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
//   Copyright (c) 2013-2017, by Oliver Pinter <oliver.pinter@hardenedbsd.org>
//   Copyright (c) 2014, by Shawn Webb <shawn.webb@hardenedbsd.org>
//   Copyright (c) 2014, by Danilo Egea Gondolfo <danilo at FreeBSD.org>
//   All rights reserved.
//   SPDX-License-Identifier: BSD-3-Clause
// Based in part upon gVisor's kvm_const*.go which is:
//   Copyright 2018 The gVisor Authors.
//   SPDX-License-Identifier: Apache-2.0
// Based in part upon kvm-ioctls' kvm-ioctls.rs which is:
//   Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//   SPDX-License-Identifier: Apache-2.0 OR MIT
//
// SPDX-License-Identifier: GPL-3.0

use std::{
    os::{
        fd::{BorrowedFd, RawFd},
        unix::ffi::OsStrExt,
    },
    sync::OnceLock,
    time::Duration,
};

use btoi::btoi;
use nix::{
    errno::Errno,
    fcntl::OFlag,
    sys::stat::Mode,
    unistd::{close, sysconf, SysconfVar},
};
// TODO: LazyCell is rust>=1.80.0
use once_cell::sync::Lazy;

use crate::{
    compat::{STATX_MNT_ID, STATX_MNT_ID_UNIQUE},
    fs::duprand,
    fstatx, info,
    path::XPath,
    pool::PidFdMap,
    proc::proc_mmap_min_addr,
    sysinfo::RandTimer,
};

// Convenience type to list {io,pr}ctls with their names.
type KeyValue<'a> = (&'a str, u64);

/// Path to /etc.
pub const PATH_ETC: &[u8] = b"/etc";

/// The default shell to execute.
/// Change this if your system doesn't have /bin/sh,
/// or set the environment variable SYD_SHELL.
pub const SYD_SH: &str = "/bin/sh";

/// The contents of the file `esyd.sh`.
pub const ESYD_SH: &str = include_str!("esyd.sh");

/// The contents of the file `syd.el`.
pub const SYD_EL: &str = include_str!("syd.el");

/// The environment variable to read the default shell from.
pub const ENV_SH: &str = "SYD_SHELL";
/// The environment variable to read the log level from.
pub const ENV_LOG: &str = "SYD_LOG";
/// The environment variable to set to log to a different fd than standard error.
pub const ENV_LOG_FD: &str = "SYD_LOG_FD";
/// The environment variable to read the syslog(2) capacity from.
pub const ENV_LOG_BUF_LEN: &str = "SYD_LOG_BUF_LEN";
/// The environment variable to set the number of core syscall handler threads.
pub const ENV_NPROC: &str = "SYD_NPROC";
/// The environment variable to set the number of maximum syscall handler threads.
pub const ENV_NPROC_MAX: &str = "SYD_NPROC_MAX";
/// The environment variable to read the pid filename from.
pub const ENV_PID_FN: &str = "SYD_PID_FN";
/// The environment variable to set to the poll file descriptor.
///
/// This variable is used internally and must not be set manually.
pub const ENV_POLL_FD: &str = "SYD_POLL_FD";
/// The environment variable to force TTY output.
pub const ENV_FORCE_TTY: &str = "SYD_FORCE_TTY";
/// The environment variable to quiet TTY output.
pub const ENV_QUIET_TTY: &str = "SYD_QUIET_TTY";

/// The environment variable to read the default external address from.
pub const ENV_PROXY_HOST: &str = "SYD_PROXY_HOST";
/// The environment variable to read the default external port from.
pub const ENV_PROXY_PORT: &str = "SYD_PROXY_PORT";

/// The environment variable to set to disable logging to syslog.
pub const ENV_NO_SYSLOG: &str = "SYD_NO_SYSLOG";

/// The environment variable to set to disable cross memory attach, and fallback to /proc/pid/mem.
pub const ENV_NO_CROSS_MEMORY_ATTACH: &str = "SYD_NO_CROSS_MEMORY_ATTACH";

/// The environment variable to set to fallback to /proc/pid/mem if
/// process_vm_{read,write}v(2) is not available (ie returns ENOSYS).
/// The environment variable `ENV_NO_CROSS_MEMORY_ATTACH` has precedence
/// over this variable.
pub const ENV_PROC_PID_MEM_FALLBACK: &str = "SYD_PROC_PID_MEM_FALLBACK";

/// The environment variable to skip seccomp confinement of Syd threads.
pub const ENV_SKIP_SCMP: &str = "SYD_SKIP_SCMP";

/// The environment variable to enable seccomp synchronous mode.
pub const ENV_SYNC_SCMP: &str = "SYD_SYNC_SCMP";

/// The environment variable to set for quick boot.
///
/// This makes Syd startup noticably faster,
/// however it removes a layer of defense against some container breaks.
/// Use this if you frequently re-execute syd{,-oci} such as we do on
/// Exherbo during Paludis' generate metadata phase.
pub const ENV_QUICK_BOOT: &str = "SYD_QUICK_BOOT";

/// SafeSetID does not allow UID transitions for UIDs less than or equal to UID_MIN.
/// 11 is typically the `operator` user.
pub const UID_MIN: u64 = 11;

/// SafeSetID does not allow GID transitions for GIDs less than or equal to GID_MIN.
/// 14 is typically the `uucp` group.
pub const GID_MIN: u64 = 14;

/// Path prefix for magic stat commands.
pub const MAGIC_PREFIX: &[u8] = b"/dev/syd";

/// syd version
pub static VERSION: Lazy<&'static str> = Lazy::new(|| {
    #[allow(clippy::if_same_then_else)]
    #[allow(clippy::branches_sharing_code)]
    if env!("SYD_GIT_HEAD").is_empty() {
        env!("CARGO_PKG_VERSION")
    } else {
        env!("SYD_GIT_HEAD")
    }
});

/// Api version of the configuration.
pub const API_VERSION: &str = env!("CARGO_PKG_VERSION_MAJOR");

/// File format marker for Crypt sandboxing.
pub const CRYPT_MAGIC: &[u8] = &[0x7F, b'S', b'Y', b'D', 3];

/// Path to the file which will be used as file status for magic stat commands.
pub const MAGIC_FILE: &[u8] = b"/dev/null";

/// Limit on the maximum number of path components for path canonicalization.
pub const PATH_MAX_COMP: usize = 128;

/// System page size
#[allow(clippy::cast_sign_loss)]
pub static PAGE_SIZE: Lazy<u64> = Lazy::new(|| {
    sysconf(SysconfVar::PAGE_SIZE)
        .unwrap_or(Some(4096))
        .unwrap_or(4096) as u64
});

/// The system-interent limit for the size of one zero-copy operation
/// is 16 pages. If more data is to be sent to AF_ALG, user space
/// must slice the input into segments with a maximum size of 16
/// pages.
pub const KCAPI_SIZE: usize = 16 * libc::PIPE_BUF;

/// Pipe buffer size.
///
/// Before Linux 2.6.11, the capacity of a pipe was the same as the
/// system page size (e.g., 4096 bytes on i386). Since Linux 2.6.11,
/// the pipe capacity is 16 pages (i.e., 65,536 bytes in a system
/// with a page size of 4096 bytes). Since Linux 2.6.35, the default
/// pipe capacity is 16 pages, but the capacity can be queried and set
/// using the fcntl(2) F_GETPIPE_SZ and F_SETPIPE_SZ operations.
pub const PIPE_BUF: usize = 16 * libc::PIPE_BUF;

/// A version of `PIPE_BUF` that is safe to use with `AF_ALG` sockets.
///
/// This is slightly smaller than `PIPE_BUF` to let kernel some space.
pub const PIPE_BUF_ALG: usize = 15 * libc::PIPE_BUF;

/// Number of CPUs on the system.
pub static NPROC: Lazy<usize> = Lazy::new(num_cpus::get);

/// The size of the syscall handler thread pool.
///
/// Note, the pool is self-growing/shrinking, and this constant defines
/// the number of core threads that are always alive and do not get
/// reaped-off even if they're idle.
#[allow(clippy::disallowed_methods)]
pub static EMU_POOL_SIZE: Lazy<usize> = Lazy::new(|| {
    let n = std::env::var_os(ENV_NPROC)
        .map(|val| btoi::<usize>(val.as_bytes()).expect("SYD_NPROC"))
        .unwrap_or_else(|| *NPROC);
    assert!(n >= 1, "SYD_NPROC must be at least 1!");
    n
});

/// The absolute maximum number of workers. This corresponds to the
/// maximum value that can be stored within half the bits of u64, as two
/// counters (total workers and busy workers) are stored in one
/// AtomicU64.
#[allow(clippy::disallowed_methods)]
pub static EMU_MAX_SIZE: Lazy<usize> = Lazy::new(|| {
    let n = std::env::var_os(ENV_NPROC_MAX)
        .map(|val| btoi::<usize>(val.as_bytes()).expect("SYD_NPROC_MAX"))
        .unwrap_or(usize::MAX);
    assert!(
        n > *EMU_POOL_SIZE,
        "SYD_NPROC_MAX must be greater than SYD_NPROC!"
    );
    n
});

/// Specify the duration in milliseconds for which additional threads
/// outside the core pool remain alive while not receiving any work
/// before giving up and terminating.
/// Defaults to 3 seconds.
pub const EMU_KEEP_ALIVE: u16 = 3000;

/// Specify the graceful wait time for the monitor thread.
/// Defaults to 250 milliseconds.
pub const MON_GRACE_TIME: Duration = Duration::from_millis(250);

/// Specify the cycle period of the monitor thread.
/// Defaults to 25 milliseconds.
pub const MON_CYCLE_TIME: Duration = Duration::from_millis(25);

/// Specify the cycle period of the interrupt thread.
/// Defaults to 5 milliseconds.
pub const INT_CYCLE_TIME: Duration = Duration::from_millis(5);

/// Specify the cycle period of the aes thread.
/// Defaults to 250 milliseconds.
pub const AES_CYCLE_TIME: Duration = Duration::from_millis(250);

/// Stack size for the syscall handler threads.
/// Defaults to 208k.
pub const EMU_STACK_SIZE: usize = 208 * 1024;

/// Stack size for the syscall monitor thread.
/// Defaults to 96k.
pub const MON_STACK_SIZE: usize = 96 * 1024;

/// Stack size for the syscall interrupt thread.
/// Defaults to 256k.
pub const INT_STACK_SIZE: usize = 256 * 1024;

/// Stack size for the AES encryption threads.
/// Defaults to 96k.
pub const AES_STACK_SIZE: usize = 96 * 1024;

/// Stack size for the short-lived micro-threads Syd spawns during
/// system call emulation.
/// Defaults to 8k.
pub const MINI_STACK_SIZE: usize = 8 * 1024;

/// Stack size for the initial _clone_(2) to spawn the sandbox process.
/// Defaults to 2M.
pub const CHLD_STACK_SIZE: usize = 2 * 1024 * 1024;

// Syslog(2) defaults

#[cfg(target_arch = "x86_64")]
const SYSLOG_CAPSHIFT: usize = 18;
#[cfg(target_arch = "x86")]
const SYSLOG_CAPSHIFT: usize = 18;
#[cfg(target_arch = "aarch64")]
const SYSLOG_CAPSHIFT: usize = 14;
#[cfg(target_arch = "arm")]
const SYSLOG_CAPSHIFT: usize = 13;
#[cfg(target_arch = "riscv64")]
const SYSLOG_CAPSHIFT: usize = 14;
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
const SYSLOG_CAPSHIFT: usize = 18;
#[cfg(target_arch = "s390x")]
const SYSLOG_CAPSHIFT: usize = 17;

#[cfg(not(any(
    target_arch = "x86_64",
    target_arch = "x86",
    target_arch = "aarch64",
    target_arch = "arm",
    target_arch = "s390x",
    target_arch = "riscv64",
    target_arch = "powerpc",
    target_arch = "powerpc64",
)))]
const SYSLOG_CAPSHIFT: usize = 14;

/// Default static capacity for syslog(2) stack mode.
///
/// This is the default mode unless a capacity has been specified
/// at startup using the environment variable `SYD_LOG_BUF_LEN`.
///
/// Quoting syslog(2):
/// In early kernels, LOG_BUF_LEN had the value 4096; from Linux 1.3.54,
/// it was 8192; from Linux 2.1.113, it was 16384; since Linux
/// 2.4.23/2.6, the value is a kernel configuration option
/// (CONFIG_LOG_BUF_SHIFT, default value dependent on the architecture).
/// Since Linux 2.6.6, the size can be queried with command type 10 (see
/// below).
pub const SYSLOG_STACK_SIZE: usize = 1 << SYSLOG_CAPSHIFT;

/// The ring buffer capacity for Syslog.
///
/// Note this buffer is allocated on the heap.
/// Defaults to 2M.
pub const SYSLOG_CAPACITY: usize = 2 * 1024 * 1024;

// SegvGuard Defaults

/// SegvGuard entry expiry timeout.
pub const SEGVGUARD_EXPIRY: Duration = Duration::from_secs(2 * 60);
/// SegvGuard entry suspension timeout.
pub const SEGVGUARD_SUSPENSION: Duration = Duration::from_secs(10 * 60);
/// SegvGuard max number of crashes before expiry.
pub const SEGVGUARD_MAXCRASHES: u8 = 5;

// Sandbox Restrictions

/// List of allowlisted prctl requests.
pub const ALLOWLIST_PRCTL: &[KeyValue] = &[
    ("PR_SET_PDEATHSIG", 1),
    ("PR_GET_PDEATHSIG", 2),
    ("PR_GET_DUMPABLE", 3),
    ("PR_SET_DUMPABLE", 4),
    ("PR_GET_ALIGN", 5),
    ("PR_GET_SETALIGN", 6),
    ("PR_GET_KEEPCAPS", 7),
    ("PR_SET_KEEPCAPS", 8),
    ("PR_GET_FPEMU", 9),
    ("PR_SET_FPEMU", 10),
    ("PR_GET_FPEXC", 11),
    ("PR_SET_FPEXC", 12),
    ("PR_GET_TIMING", 13),
    ("PR_SET_TIMING", 14),
    ("PR_SET_NAME", 15),
    ("PR_GET_NAME", 16),
    ("PR_GET_ENDIAN", 19),
    ("PR_SET_ENDIAN", 20),
    ("PR_GET_SECCOMP", 21),
    ("PR_SET_SECCOMP", 22),
    ("PR_CAPBSET_READ", 23),
    ("PR_CAPBSET_DROP", 24),
    ("PR_GET_TSC", 25),
    ("PR_SET_TSC", 26),
    ("PR_GET_SECUREBITS", 27),
    ("PR_SET_SECUREBITS", 28),
    ("PR_SET_TIMERSLACK", 29),
    ("PR_GET_TIMERSLACK", 30),
    // SAFETY: no perf! PR_TASK_PERF_EVENTS_DISABLE
    // SAFETY: no perf! PR_TASK_PERF_EVENTS_ENABLE
    ("PR_MCE_KILL", 33),
    ("PR_MCE_KILL_GET", 34),
    // SAFETY: no self modifying executables! PR_SET_MM
    // SAFETY: no ptrace! PR_SET_PTRACER
    ("PR_SET_CHILD_SUBREAPER", 36),
    ("PR_GET_CHILD_SUBREAPER", 37),
    ("PR_SET_NO_NEW_PRIVS", 38),
    ("PR_GET_NO_NEW_PRIVS", 39),
    ("PR_GET_TID_ADDRESS", 40),
    ("PR_SET_THP_DISABLE", 41),
    ("PR_GET_THP_DISABLE", 42),
    // SAFETY: unimplemented! PR_MPX_ENABLE_MANAGEMENT
    // SAFETY: unimplemented! PR_MPX_DISABLE_MANAGEMENT
    ("PR_SET_FP_MODE", 45),
    ("PR_GET_FP_MODE", 46),
    ("PR_CAP_AMBIENT", 47),
    ("PR_SVE_SET_VL", 50),
    ("PR_SVE_GET_VL", 51),
    // SAFETY: do not access speculation misfeature! PR_GET_SPECULATION_CTRL
    // SAFETY: do not change speculation misfeature! PR_SET_SPECULATION_CTRL
    // Note: ^^ are allowed _only_ if trace/allow_unsafe_spec_exec:1 is set!
    ("PR_PAC_RESET_KEYS", 54),
    ("PR_SET_TAGGED_ADDR_CTRL", 55),
    ("PR_GET_TAGGED_ADDR_CTRL", 56),
    ("PR_SET_IO_FLUSHER", 57),
    ("PR_GET_IO_FLUSHER", 58),
    ("PR_SET_SYSCALL_USER_DISPATCH", 59),
    ("PR_PAC_SET_ENABLED_KEYS", 60),
    ("PR_PAC_GET_ENABLED_KEYS", 61),
    ("PR_SCHED_CORE", 62),
    ("PR_SET_MDWE", 65),
    ("PR_GET_MDWE", 66),
    ("PR_SET_VMA", 0x53564d41),
];

/// Equivalent to the list of environment variables that gl*bc removes for SUID programs.
pub const UNSAFE_ENV: &[&[u8]] = &[
    b"GCONV_PATH",
    b"GETCONF_DIR",
    b"GLIBC_TUNABLES",
    b"HOSTALIASES",
    b"LD_AOUT_LIBRARY_PATH",
    b"LD_AOUT_PRELOAD",
    b"LD_AUDIT",
    b"LD_BIND_NOT",
    b"LD_DEBUG",
    b"LD_DEBUG",
    b"LD_DEBUG_OUTPUT",
    b"LD_DYNAMIC_WEAK",
    b"LD_DYNAMIC_WEAK",
    b"LD_ELF_HINTS_PATH",
    b"LD_HWCAP_MASK",
    b"LD_LIBMAP",
    b"LD_LIBMAP_DISABLE",
    b"LD_LIBRARY_PATH",
    b"LD_LIBRARY_PATH_FDS",
    b"LD_LIBRARY_PATH_RPATH",
    b"LD_LOADFLTR",
    b"LD_ORIGIN_PATH",
    b"LD_PREFER_MAP_32BIT_EXEC",
    b"LD_PRELOAD",
    b"LD_PRELOAD_FDS",
    b"LD_PROFILE",
    b"LD_SHOW_AUXV",
    b"LD_USE_LOAD_BIAS",
    b"LOCALDOMAIN",
    b"LOCPATH",
    b"MALLOC_TRACE",
    b"NIS_PATH",
    b"NLSPATH",
    b"RESOLV_HOST_CONF",
    b"RES_OPTIONS",
    b"TMPDIR",
    b"TZDIR",
];

/// Path prefixes to skip caching.
///
/// Note, trailing slash matters!
pub const SKIP_CACHE_PATH_PREFIXES: &[&[u8]] = &[
    b"/boot",
    b"/root",
    b"/dev/", // we pre-open `/dev`.
    b"/etc",
    b"/proc/", // we pre-open `/proc`.
    b"/run",
    b"/sys/", // we pre-open `/sys`.
    b"/var/log",
    b"/var/run",
];

/// Default ioctl allow/denylist.
/// false -> allow, true -> deny.
pub const DEFAULT_IOCTL: &[(u64, bool)] = &[
    (0x5451, false),     // FIOCLEX
    (0x5450, false),     // FIONCLEX
    (0x5421, false),     // FIONBIO
    (0x5452, false),     // FIOASYNC
    (0x5460, false),     // FIOQSIZE
    (0xc0045877, false), // FIFREEZE
    (0xc0045878, false), // FITHAW
    (0xc020660b, false), // FS_IOC_FIEMAP
    (0x2, false),        // FIGETBSZ
    (0x40049409, false), // FICLONE
    (0x4020940d, false), // FICLONERANGE
    (0xc0189436, false), // FIDEDUPERANGE
    (0x80111500, false), // FS_IOC_GETFSUUID
    (0x80811501, false), // FS_IOC_GETFSSYSFSPATH
    (0x1, true),         // FIBMAP
    (0x4b4d, true),      // KDSETKEYCODE
    (0x4b4e, true),      // KDSIGACCEPT
    (0x5423, true),      // TIOCSETD
    (0x5412, true),      // TIOCSTI
    (0x541c, true),      // TIOCCONS
    (0x541d, true),      // TIOCLINUX
    (0x801c581f, true),  // FS_IOC_FSGETXATTR, (SAFETY: xattr restrictions)
    (0x401c5820, true),  // FS_IOC_FSSETXATTR, (ditto)
    (0x40086602, true),  // FS_IOC_SETFLAGS (to deny immutable and append-only flag changes)
];

// Sandboxing profiles

/// Off sandboxing profile.
/// Used as shorthand to turn all sandboxing off.
pub const PROFILE_OFF: &[&str] = &["sandbox/all:off", "sandbox/net,mem,pid,force,tpe:off"];

/// Libsyd helper sandboxing profile.
/// Turns all sandboxing off and set sandbox lock to Exec.
/// Useful to configure syd in the application via libsyd.
pub const PROFILE_LIB: &[&str] = &["include_profile off", "lock:exec"];

/// Quiet sandboxing profile.
pub const PROFILE_QUIET: &[&str] = &[
    "default/all:filter",
    "default/net,block,mem,pid,force,segvguard,tpe:filter",
    "filter/read+!proc/name", // for PR_SET_NAME.
];

/// Trace sandboxing profile, used by pandora(1).
pub const PROFILE_TRACE: &[&str] = &[
    "log/level:info",
    "log/syslog:false",
    "log/verbose:false",
    "sandbox/ioctl,force:on",
    "default/all,net,force,tpe:warn",
    "filter/read+!proc/name",
];

/// OCI default sandboxing profile, used by syd-oci(1).
pub const PROFILE_OCI: &[&str] = &[
    "include_profile trace",
    "lock:off", // allow esyd.
    "trace/allow_safe_syslog:true",
    "trace/allow_unsafe_nopie:true", // most containers ship non-pie binaries...
];

/// Enforce profile, used to practically undo `oci` and `trace` profiles at runtime.
pub const PROFILE_ENFORCE: &[&str] = &[
    "default/all,net,force,tpe:deny",
    "filter/read-!proc/name",
    "trace/allow_safe_syslog:false",
    "trace/allow_unsafe_nopie:false",
    "lock:exec", // keep esyd.
];

/// No ipv4 sandboxing profile.
pub const PROFILE_NOIPV4: &[&str] = &[
    "sandbox/net:on",
    "allow/net/connect+any6!0-65535",
    "deny/net/connect+any4!0-65535",
];

/// No ipv6 sandboxing profile.
pub const PROFILE_NOIPV6: &[&str] = &[
    "sandbox/net:on",
    "allow/net/connect+any4!0-65535",
    "deny/net/connect+any6!0-65535",
];

/// Privileged sandboxing profile.
pub const PROFILE_PRIVILEGED: &[&str] = &["trace/allow_unsafe_caps:true"];

/// No core dump restrictions profile.
pub const PROFILE_CORE: &[&str] = &["trace/allow_unsafe_prlimit:true"];

/// Debug sandboxing profile.
pub const PROFILE_DEBUG: &[&str] = &[
    "trace/allow_unsafe_prlimit:true",  // enable coredumps.
    "trace/allow_unsafe_ptrace:true",   // strace -f syd
    "trace/allow_unsafe_dumpable:true", // PR_SET_DUMPABLE!
];

/// No memory restrictions sandboxing profile.
pub const PROFILE_NOMEM: &[&str] = &["trace/allow_unsafe_memory:true"];

/// No PIE sandboxing profile.
pub const PROFILE_NOPIE: &[&str] = &["trace/allow_unsafe_nopie:true"];

/// Container sandboxing profile, activated with:
/// `syd --profile container`
pub const PROFILE_CONTAINER: &[&str] = &["unshare/all:true"];

/// Immutable container sandboxing profile, activated with:
/// `syd --profile immutable`
pub const PROFILE_IMMUTABLE: &[&str] = &[
    "include_profile container",
    "bind+/var/empty:/boot:ro,nodev,noexec,nosuid",
    "bind+tmpfs:/dev/shm:nodev,nosuid,noexec,nosymfollow,mode=1777",
    "bind+tmpfs:/run:nodev,nosuid,nosymfollow,mode=1777",
    "bind+tmpfs:/tmp:nodev,nosuid,nosymfollow,mode=1777",
    "bind+/run:/var/run:nodev,nosuid,nosymfollow,mode=1777",
    "bind+/etc:/etc:ro,nodev,noexec,nosuid",
    "bind+/home:/home:ro,nodev,noexec,nosuid",
    "bind+/media:/media:ro,nodev,noexec,nosuid",
    "bind+/mnt:/mnt:ro,nodev,noexec,nosuid",
    "bind+/opt:/opt:ro,nodev,nosuid",
    "bind+/srv:/srv:ro,nodev,noexec,nosuid",
    "bind+/usr:/usr:ro,nodev,nosuid",
    "bind+/etc/shells:/proc/kcore:ro,nodev,noexec,nosuid",
    "bind+/etc/shells:/proc/keys:ro,nodev,noexec,nosuid",
    "bind+/etc/shells:/proc/latency_stats:ro,nodev,noexec,nosuid",
    "bind+/etc/shells:/proc/sys/kernel/modprobe:ro,nodev,noexec,nosuid",
    "bind+/etc/shells:/proc/sysrq-trigger:ro,nodev,noexec,nosuid",
    "bind+/etc/shells:/proc/timer_list:ro,nodev,noexec,nosuid",
    "bind+/etc/shells:/proc/timer_stats:ro,nodev,noexec,nosuid",
    "bind+/etc/shells:/sys/kernel/notes:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/proc/acpi:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/proc/asound:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/proc/bus:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/proc/driver:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/proc/dynamic_debug:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/proc/fs:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/proc/irq:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/proc/pressure:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/proc/scsi:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/proc/sys/debug:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/proc/sys/dev:ro,nodev,noexec,nosuid",
    "bind+/proc/sys/fs:/proc/sys/fs:ro,nodev,noexec,nosuid",
    "bind+/proc/sys/kernel:/proc/sys/kernel:ro,nodev,noexec,nosuid",
    "bind+/proc/sys/vm:/proc/sys/vm:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/proc/sysvipc:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/proc/tty:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/sys/dev/block:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/sys/devices/virtual/powercap:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/sys/firmware:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/sys/fs/bpf:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/sys/fs/ext4:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/sys/fs/fuse:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/sys/fs/pstore:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/sys/fs/selinux:ro,nodev,noexec,nosuid",
    "bind+/var/empty:/sys/fs/smackfs:ro,nodev,noexec,nosuid",
];

/// Landlock sandboxing profile, activated with:
/// `syd --profile landlock`.
pub const PROFILE_LANDLOCK: &[&str] = &[
    "sandbox/lock:on",
    "allow/lock/read+/bin",
    "allow/lock/read+/dev",
    "allow/lock/read+/etc",
    "allow/lock/read+/lib",
    "allow/lock/read+/opt",
    // /proc is always allowed.
    "allow/lock/read+/run",
    "allow/lock/read+/sbin",
    "allow/lock/read+/snap",
    "allow/lock/read+/sys",
    "allow/lock/read+/usr",
    "allow/lock/read+/var",
    "allow/lock/write+/dev/fd",
    "allow/lock/write+/dev/full",
    // /dev/null is always allowed.
    "allow/lock/write+/dev/zero",
    "allow/lock/write+/selinux/context",
    "allow/lock/write+/dev/shm",
    "allow/lock/write+/tmp",
    "allow/lock/write+/var/tmp",
];

/// Paludis sandboxing profile, activated with:
/// `syd --profile paludis`.
pub const PROFILE_PALUDIS: &[&str] = &[
    "include_profile linux",
    "include_profile tty",
    "name/host:localhost",   // only effective when combined with unshare/uts:1
    "lock:exec",             // esandbox
    "log/verbose:false",     // verbose logging is intended for malware analysis.
    "trace/memory_access:0", // fallback to unsafe proc_pid_mem(5) if cross memory attach fails.
    "trace/allow_safe_bind:true",
    "trace/allow_safe_kcapi:true",
    "trace/allow_unsafe_chroot:true",   // turn chroot(2) into no-op
    "trace/allow_unsafe_cbpf:true",     // stacked seccomp cbpf filters
    "trace/allow_unsafe_dumpable:true", // allows strace -f syd
    "trace/allow_unsafe_env:true",
    "trace/allow_unsafe_exec:true",
    "trace/allow_unsafe_filename:true", // sydbox#118
    "trace/allow_unsafe_libc:true",
    "trace/allow_unsafe_magiclinks:true", // tests love to access /proc/1.
    "trace/allow_unsafe_memory:true",
    "trace/allow_unsafe_msgsnd:true",
    "trace/allow_unsafe_nice:true",
    "trace/allow_unsafe_nopie:true",
    "trace/allow_unsafe_open_path:true",
    "trace/allow_unsafe_perf:true",
    "trace/allow_unsafe_ptrace:true",
    "trace/allow_unsafe_prctl:true", // perl tests want to set process name.
    "trace/allow_unsafe_prlimit:true",
    "trace/allow_unsafe_sigreturn:true",
    "trace/allow_unsafe_spec_exec:true",
    "trace/allow_unsafe_socket:true",
    "trace/allow_unsafe_stack:true",
    "trace/allow_unsafe_sysinfo:true", // disables sysinfo(2) randomizer, >3.23.4
    "trace/allow_unsupp_socket:true",
    "trace/allow_unsafe_time:true",
    // Allow FS_IOC_SETFLAGS (used by libarchive, cpio, tar etc.)
    "ioctl/deny-0x40086602", // needed because it's denied by default.
    "ioctl/allow+0x40086602",
    // Turned on by esandbox in metadata phase.
    "sandbox/exec:off",
    // TPE is unnecessary for package builds.
    "sandbox/tpe:off",
    // Filter noisy systemd access.
    "filter/net/connect+/run/systemd/userdb/io.systemd.DynamicUser",
    // Defaults for procfs.
    "allow/read,stat+/proc/crypto",
    "allow/read,stat+/proc/cpuinfo",
    "allow/read,stat+/proc/loadavg",
    "allow/read,stat+/proc/meminfo",
    "allow/read,stat+/proc/uptime",
    "allow/read,stat+/proc/version",
    "mask-/proc/version", // override mask in linux profile.
    // SAFETY: We allow relaxed stat access (/proc wide).
    // This must be combined with trace/allow_unsafe_magiclinks:1.
    "allow/read,stat+/proc/[0-9]*/stat",
    "allow/read,stat+/proc/[0-9]*/task/[0-9]*/stat",
    // SAFETY: Allow /proc PID traversals.
    // Tests often assume they can identify fellow processes
    // by readdir'ing /proc hence we allow it here but deny
    // in the default secure `linux` profile.
    "allow/stat+/proc/[0-9]*",
    // Defaults for network sandboxing.
    "allow/net/bind+loopback!0",
    "allow/net/bind+loopback!1024-65535",
    // Defaults for Landlock networking which is ABI>=4.
    "allow/lock/bind+0",
    "allow/lock/bind+1024-65535",
    "allow/lock/connect+1024-65535",
    // Allow creation of memory file descriptors.
    "allow/create+/memfd:**",
    // Repository directory
    "allow/read,stat,chdir,readdir+/var/db/paludis/***",
];

/// User sandboxing profile, activated with:
/// `syd --profile user`.
/// Syd sets the environment variables
/// UID, GID, USER, and HOME before parsing this
/// profile.
pub const PROFILE_USER: &[&str] = &[
    "include_profile landlock",
    "include_profile linux",
    "include_profile tty",
    "include_profile immutable",
    "unshare/all:try",  // use namespaces only if supported.
    "bind-/home:/home", // immutable mounts this ro.
    "bind+/home:/home:rw,nodev,nosuid",
    // dmesg(8)
    "trace/allow_safe_syslog:true",
    // TPE
    "tpe/negate:1",
    "tpe/user_owned:1",
    "tpe/gid:${SYD_GID}",
    // Enforce strict file modes:
    // Disallow s{u,g}id bits on files.
    // Disallow setting group+other bits.
    "trace/force_umask:7077",
    // /etc
    "allow/read,stat,chdir,readdir+/etc/*sh*/***",
    "allow/read,stat,chdir,readdir+/etc/profile*/***",
    // /home
    // 1. We disallow editing dotfiles.
    // 2. We mark shell-history files as append-only.
    // 3. We allow read(${HOME}) but not write(${HOME}),
    //    read|write(${HOME}/**) is ok, i.e. the user can not delete
    //    their home directory under the sandbox which is a nice and
    //    funny protection.
    "deny/all+/home/**/.*/***",
    "allow/read,stat,chdir,readdir+/home/**/.*/***",
    "allow/all+/home/**/.*history*",
    "append+${HOME}/.*history",
    "allow/all+/dev/shm/**", // immutable mounts a tmpfs here.
    "allow/all+/run/**",     // ditto.
    "allow/all+/var/run/**", // ditto.
    "allow/read,stat,chdir,readdir+/dev/shm",
    "allow/read,stat,chdir,readdir+/run",
    "allow/read,stat,chdir,readdir+/var/run",
    "allow/lock/write+/dev/shm", // immutable mounts a tmpfs here.
    "allow/lock/write+/run",     // ditto.
    "allow/lock/write+/var/run", // ditto.
    "allow/lock/write+${HOME}",
    "allow/read,stat,chdir,readdir+${HOME}/***",
    "allow/all+${HOME}/**",
    "allow/net/bind+${HOME}/**",
    "allow/net/connect+${HOME}/**",
    "allow/net/sendfd+${HOME}/**",
    // /run/user/uid
    "allow/lock/write+/run/user/${SYD_UID}",
    "allow/all+/run/user/${SYD_UID}/**",
    "allow/read,stat,chdir,readdir+/run/user/${SYD_UID}/***",
    "allow/net/connect+/run/user/${SYD_UID}/**",
    // Allow access to DRI and sound.
    "allow/read,stat,chdir,readdir+/proc/asound/***",
    "allow/lock/write+/dev/dri",
    "allow/lock/write+/dev/input",
    "allow/lock/write+/dev/snd",
    "allow/read,stat,chdir,readdir,write+/dev/dri/**",
    "allow/read,stat,chdir,readdir,write+/dev/input/**",
    "allow/read,stat,chdir,readdir,write+/dev/snd/**",
    // Allow access to HID devices
    // FIXME: Landlock for hidraw?
    "allow/read,stat,write+/dev/hidraw[0-9]*",
    // Allow access to syslog.
    "allow/net/connect+/dev/log",
    // Allow access to systemd journal.
    "allow/read,stat,chdir,readdir+/var/log/journal/***",
];

/// Common Linux system profile, used by oci, paludis and user profiles.
pub const PROFILE_LINUX: &[&str] = &[
    // List root is safe.
    "allow/stat,chdir,readdir+/",
    // Safe defaults for Exec sandboxing
    "allow/exec,read,stat,chdir,readdir+/bin/***",
    "allow/exec,read,stat,chdir,readdir+/sbin/***",
    "allow/exec,read,stat,chdir,readdir+/lib*/***",
    "allow/exec,read,stat,chdir,readdir+/usr/***",
    "allow/exec,read,stat,chdir,readdir+/opt/***",
    // Safe defaults for Network sandboxing
    "allow/net/link+route", // allow NETLINK_ROUTE.
    "allow/net/connect+/run/nscd/socket",
    "allow/net/connect+/var/run/nscd/socket",
    "allow/net/connect+/var/lib/sss/pipes/nss",
    "allow/net/connect+loopback!65535", // getaddrinfo() with AI_ADDRCONFIG on musl.
    // /dev
    "allow/read,stat,chdir,readdir+/dev",
    "allow/read,stat,chdir,readdir+/dev/fd",
    "allow/read,stat,chdir,readdir,mktemp+/dev/shm/***",
    "allow/write,create,delete,rename,symlink,truncate,chown,chgrp,chmod,chattr,utime,mkdir,mkfifo+/dev/shm/**",
    "allow/read,stat,write,ioctl+/dev/full",
    "allow/read,stat,write,ioctl+/dev/zero",
    "allow/read,stat,write,ioctl,truncate+/dev/null",
    "allow/read,stat,write,chdir,readdir+/dev/fd/**",
    "allow/read,stat,write+/dev/stderr",
    "allow/read,stat,write+/dev/stdout",
    "allow/read,stat,write+/dev/stdin",
    "allow/read,stat,write+/dev/random",
    "allow/read,stat,write+/dev/urandom",
    // /proc
    //
    // SAFETY: Note we allow readdir to `/proc`,
    // however we do _not_ allow PID traversals,
    // ie identifying fellow processing by readdir'ing `/proc`.
    // Notably, this is allowed in the `paludis` profile.
    "allow/read,stat,chdir,readdir+/proc",
    "allow/read,stat+/proc/filesystems",
    // SAFETY: We allow basic stat access (global, per-process, per-task).
    // trace/allow_unsafe_magiclinks:0 default is another layer of
    // protection against potential malicious activity with proc
    // magiclinks.
    "allow/read,stat+/proc/stat",
    "allow/read,stat+/proc/self/stat",
    "allow/read,stat+/proc/self/task/[0-9]*/stat",
    // SAFETY: We provide an empty file in place of /proc/cmdline
    // for compatibility rather than denying outright. In any case,
    // syd does not leak the contents of this file to the sandbox
    // process. See: https://gitlab.exherbo.org/sydbox/sydbox/-/issues/106
    "allow/read,stat+/proc/cmdline",
    "mask+/proc/cmdline",
    // SAFETY: Provide an empty file in place of /proc/version.
    // This is consistent with uname(2) restrictions.
    "allow/read,stat+/proc/version",
    "mask+/proc/version",
    "allow/read,stat,chdir,readdir+/proc/sys",
    "allow/read,stat,chdir,readdir+/proc/sys/fs/***",
    "allow/read,stat,chdir,readdir+/proc/sys/kernel/***",
    "allow/read,stat,chdir,readdir+/proc/sys/vm/***",
    // SAFETY: Modification of /proc/sys/kernel/modprobe requires no
    // capabilities (can cause arbitrary code to be inserted into the
    // kernel via a replacement modprobe)!
    // https://forums.grsecurity.net/viewtopic.php?f=7&t=2522
    "deny/read,stat+/proc/sys/kernel/modprobe",
    "mask+/proc/sys/kernel/modprobe",
    // SAFETY: Provide an empty file in place of /sys/kernel/notes.
    // See: https://lwn.net/Articles/962782/
    "mask+/sys/kernel/notes",
    "allow/stat,chdir,readdir+/proc/self",
    "allow/stat,chdir,readdir+/proc/thread-self",
    "allow/read,stat+/proc/self/comm",
    "allow/read,stat+/proc/self/task/[0-9]*/comm",
    "allow/read,stat+/proc/self/cmdline",
    "allow/read,stat+/proc/self/task/[0-9]*/cmdline",
    "allow/stat,chdir,readdir+/proc/self/cwd",
    "allow/stat,chdir,readdir+/proc/self/task/[0-9]*/cwd",
    "allow/stat+/proc/self/exe",
    "allow/stat+/proc/self/task/[0-9]*/exe",
    "allow/stat,chdir,readdir+/proc/self/fd",
    "allow/stat,chdir,readdir+/proc/self/fdinfo",
    "allow/stat,chdir,readdir+/proc/self/task",
    "allow/stat,chdir,readdir+/proc/self/task/[0-9]*",
    "allow/stat,chdir,readdir+/proc/self/task/[0-9]*/fd",
    "allow/stat,chdir,readdir+/proc/self/task/[0-9]*/fdinfo",
    "allow/read,stat,chdir,readdir,write,truncate+/proc/self/fd/[0-9]*",
    "allow/read,stat,chdir,readdir,write,truncate+/proc/self/task/[0-9]*/fd/[0-9]*",
    r"allow/read,stat,write,ioctl+/proc/self/fd/pipe:\[[0-9]*\]",
    r"allow/read,stat,write,ioctl+/proc/self/fd/socket:\[[0-9]*\]",
    r"allow/read,stat,write,ioctl+/proc/self/task/[0-9]*/fd/pipe:\[[0-9]*\]",
    r"allow/read,stat,write,ioctl+/proc/self/task/[0-9]*/fd/socket:\[[0-9]*\]",
    "allow/read,stat,chdir,readdir+/proc/self/fdinfo/[0-9]*",
    "allow/read,stat,chdir,readdir+/proc/self/task/[0-9]*/fdinfo/[0-9]*",
    "allow/read,stat,chdir,readdir+/proc/self/attr/***",
    "allow/read,stat,chdir,readdir+/proc/self/task/[0-9]*/attr/***",
    "allow/read,stat+/proc/self/maps",
    "allow/read,stat+/proc/self/task/[0-9]*/maps",
    "allow/read,stat+/proc/self/mounts",
    "allow/read,stat+/proc/self/task/[0-9]*/mounts",
    "allow/read,stat+/proc/mounts", // symlink to self/mounts
    "allow/stat,chdir,readdir+/proc/self/root",
    "allow/stat,chdir,readdir+/proc/self/task/[0-9]*/root",
    "allow/read,stat+/proc/self/stat",
    "allow/read,stat+/proc/self/task/[0-9]*/stat",
    "allow/read,stat+/proc/self/statm",
    "allow/read,stat+/proc/self/task/[0-9]*/statm",
    "allow/read,stat+/proc/self/status",
    "allow/read,stat+/proc/self/task/[0-9]*/status",
    // /sys
    "allow/stat,chdir,readdir+/sys",
    "allow/stat,chdir,readdir+/sys/devices",
    "allow/stat,chdir,readdir+/sys/devices/system",
    "allow/stat,chdir,readdir+/sys/devices/system/cpu",
    "allow/read,stat+/sys/devices/system/cpu/isolated",
    "allow/read,stat+/sys/devices/system/cpu/kernel_max",
    "allow/read,stat+/sys/devices/system/cpu/online",
    "allow/read,stat+/sys/devices/system/cpu/offline",
    "allow/read,stat+/sys/devices/system/cpu/possible",
    "allow/read,stat+/sys/devices/system/cpu/present",
    "allow/stat,chdir,readdir+/sys/fs",
    "allow/read,stat,chdir,readdir+/sys/fs/cgroup/***",
    "allow/stat,chdir,readdir+/sys/kernel",
    "allow/stat,chdir,readdir+/sys/kernel/mm",
    "allow/read,stat,chdir,readdir+/sys/kernel/mm/transparent_hugepage/***",
    "allow/stat,chdir,readdir+/sys/kernel/security",
    "allow/read,stat,chdir,readdir+/sys/kernel/security/apparmor/***",
    // /run
    "allow/stat,chdir,readdir+/run",
    "allow/stat,chdir,readdir+/run/systemd",
    "allow/stat,chdir,readdir+/run/systemd/resolve",
    "allow/read,stat+/run/systemd/resolve/*.conf",
    // /selinux
    "allow/stat,chdir,readdir+/selinux",
    "allow/stat,chdir,readdir+/selinux/context",
    "allow/read,stat,chdir,readdir,write+/selinux/context/**",
    // /tmp and /var/tmp
    "allow/read,stat,chdir,readdir,mktemp+/tmp/***",
    "allow/read,stat,chdir,readdir,mktemp+/var/tmp/***",
    "allow/write,create,delete,rename,symlink,truncate,chown,chgrp,chmod,chattr,utime,mkdir,mkfifo+/tmp/**",
    "allow/write,create,delete,rename,symlink,truncate,chown,chgrp,chmod,chattr,utime,mkdir,mkfifo+/var/tmp/**",
    // /var
    "allow/stat,chdir,readdir+/var",
    "allow/stat,chdir,readdir,chroot+/var/empty",
    "allow/read,stat,chdir,readdir,mktemp+/var/cache/***",
    "allow/write,create,delete,rename,symlink,truncate,chown,chgrp,chmod,chattr,utime,mkdir,mkfifo+/var/cache/**",
    "allow/read,stat+/var/lib/sss/mc/passwd", // Required for LDAP.
    "allow/read,stat+/var/lib/sss/mc/group",  // ditto.
    // /etc
    "allow/stat,chdir,readdir+/etc",
    "allow/read,stat+/etc/DIR_COLORS",
    "allow/read,stat+/etc/GREP_COLORS",
    "allow/read,stat,chdir,readdir+/etc/bash*/***",
    "allow/read,stat,chdir,readdir+/etc/ca-certificates/***",
    "allow/read,stat,chdir,readdir+/etc/env.d/***",
    "allow/read,stat,chdir,readdir+/etc/groff/***",
    "allow/read,stat+/etc/environment",
    "allow/read,stat+/etc/ethertypes",
    "allow/read,stat+/etc/group",
    "allow/read,stat+/etc/hosts",
    "allow/read,stat+/etc/inputrc",
    "allow/read,stat+/etc/issue",
    "allow/read,stat+/etc/ld*",
    "allow/read,stat+/etc/locale.alias",
    "allow/read,stat+/etc/locale.conf",
    "allow/read,stat+/etc/localtime",
    "allow/read,stat+/etc/machine-id",
    "mask+/etc/machine-id",
    "allow/read,stat+/etc/man_db.conf",
    "allow/read,stat+/etc/nanorc",
    "allow/read,stat+/etc/**/nsswitch.conf",
    "allow/read,stat+/etc/passwd",
    "allow/read,stat,chdir,readdir+/etc/profile*/***",
    "allow/read,stat+/etc/services",
    "allow/read,stat+/etc/*-release",
    "allow/read,stat+/etc/protocols",
    "allow/read,stat+/etc/resolv.conf",
    "allow/read,stat,chdir,readdir+/etc/skel/***",
    "allow/stat,chdir,readdir+/etc/ssl",
    "allow/read,stat,chdir,readdir+/etc/ssl/certs/***",
    "allow/read,stat,chdir,readdir+/etc/ssl/misc/***",
    "allow/read,stat+/etc/ssl/openssl.cnf",
    "allow/read,stat,chdir,readdir+/etc/terminfo/***",
    "allow/read,stat,chdir,readdir+/etc/zsh/***",
    // /home
    //
    // Do _not_ allow readdir which allows enumerating other users!
    "allow/read,stat,chdir+/home",
    // Defaults for Network sandboxing:
    //
    // Allow network access to unnamed UNIX sockets.
    "allow/net/bind+!unnamed",
    "allow/net/connect+!unnamed",
    "allow/net/sendfd+!unnamed",
];

/// Profile to allowlist TTY ioctls without path check, used by oci,
/// paludis and user profiles.
/// Syd sets the environment variable TTY before parsing this profile.
pub const PROFILE_TTY: &[&str] = &[
    // TTY lock rules to be used with Landlock.
    "allow/lock/write+/dev/ptmx",
    "allow/lock/write+/dev/pts",
    "allow/lock/write+/dev/tty",
    "allow/lock/write+${SYD_TTY}",
    // TTY seccomp rules to act as the second layer.
    "allow/read,stat,write,ioctl+/dev/ptmx",
    "allow/read,stat,write,ioctl+/dev/pts/ptmx",
    "allow/read,stat,write,ioctl+/dev/pts/[0-9]*",
    "allow/read,stat,write,ioctl+/dev/tty",
    "allow/read,stat,write,ioctl+${SYD_TTY}",
    // PTY handling
    "ioctl/allow+0x5410",     // TIOCSPGRP
    "ioctl/allow+0x5432",     // TCGETX
    "ioctl/allow+0x5433",     // TCSETX
    "ioctl/allow+0x5434",     // TCSETXF
    "ioctl/allow+0x5435",     // TCSETXW
    "ioctl/allow+0x5456",     // TIOCGLCKTRMIOS
    "ioctl/allow+0x5457",     // TIOCSLCKTRMIOS
    "ioctl/allow+0x5413",     // TIOCGWINSZ
    "ioctl/allow+0x5414",     // TIOCSWINSZ
    "ioctl/allow+0x80045432", // TIOCGDEV
    "ioctl/allow+0x80045440", // TIOCGEXCL
    "ioctl/allow+0x80045438", // TIOCGPKT
    "ioctl/allow+0x80045439", // TIOCGPTLCK
    "ioctl/allow+0x80045430", // TIOCGPTN
    "ioctl/allow+0x5441",     // TIOCGPTPEER
    "ioctl/allow+0x540e",     // TIOCSCTTY
    "ioctl/allow+0x40045436", // TIOCSIG
    "ioctl/allow+0x5437",     // TIOCVHANGUP
    // Pseudoterminal ioctls
    "ioctl/allow+0x80045438", // TIOCGPKT
    "ioctl/allow+0x80045439", // TIOCGPTLCK
    "ioctl/allow+0x5441",     // TIOCGPTPEER
    "ioctl/allow+0x5420",     // TIOCPKT
    "ioctl/allow+0x40045431", // TIOCSPTLCK
];

/// Profile to allowlist KVM ioctls without path check.
/// Read: https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt
pub const PROFILE_KVM: &[&str] = &[
    "allow/read,stat,write,ioctl+/dev/kvm",
    "include_profile kvm_native",
    "ioctl/allow+0x0000ae00", // KVM_GET_API_VERSION
    "ioctl/allow+0xae01",     // KVM_CREATE_VM
    "ioctl/allow+0xae04",     // KVM_GET_VCPU_MMAP_SIZE
    "ioctl/allow+0xae41",     // KVM_CREATE_VCPU
    "ioctl/allow+0x4010ae42", // KVM_GET_DIRTY_LOG
    "ioctl/allow+0xae47",     // KVM_SET_TSS_ADDR
    "ioctl/allow+0xae80",     // KVM_RUN
    "ioctl/allow+0xae9a",     // KVM_NMI
    "ioctl/allow+0xae03",     // KVM_CHECK_EXTENSION
    "ioctl/allow+0xaea3",     // KVM_GET_TSC_KHZ
    "ioctl/allow+0xaea2",     // KVM_SET_TSC_KHZ
    "ioctl/allow+0x4004ae86", // KVM_INTERRUPT
    "ioctl/allow+0x4008ae89", // KVM_SET_MSRS
    "ioctl/allow+0x4020ae46", // KVM_SET_USER_MEMORY_REGION
    "ioctl/allow+0x4090ae82", // KVM_SET_REGS
    "ioctl/allow+0x4138ae84", // KVM_SET_SREGS
    "ioctl/allow+0xc008ae88", // KVM_GET_MSRS
    "ioctl/allow+0x8090ae81", // KVM_GET_REGS
    "ioctl/allow+0x8138ae83", // KVM_GET_SREGS
    "ioctl/allow+0xc008ae05", // KVM_GET_SUPPORTED_CPUID
    "ioctl/allow+0xc008ae09", // KVM_GET_EMULATED_CPUID
    "ioctl/allow+0x4008ae90", // KVM_SET_CPUID2
    "ioctl/allow+0x4004ae8b", // KVM_SET_SIGNAL_MASK
    "ioctl/allow+0x8040ae9f", // KVM_GET_VCPU_EVENTS
    "ioctl/allow+0x4040aea0", // KVM_SET_VCPU_EVENTS
    "ioctl/allow+0x4018aee1", // KVM_SET_DEVICE_ATTR
    "ioctl/allow+0x4008ae48", // KVM_SET_IDENTITY_MAP_ADDR
    "ioctl/allow+0x0000ae60", // KVM_CREATE_IRQCHIP
    "ioctl/allow+0x4008ae61", // KVM_IRQ_LINE
    "ioctl/allow+0x4010ae67", // KVM_REGISTER_COALESCED_MMIO
    "ioctl/allow+0x4010ae68", // KVM_UNREGISTER_COALESCED_MMIO
    "ioctl/allow+0x4030ae6a", // KVM_SET_GSI_ROUTING
    "ioctl/allow+0x4020ae76", // KVM_IRQFD
    "ioctl/allow+0x4040ae79", // KVM_IOEVENTFD
    "ioctl/allow+0x8004ae98", // KVM_GET_MP_STATE
    "ioctl/allow+0x4004ae99", // KVM_SET_MP_STATE
    "ioctl/allow+0x4200aea5", // KVM_SIGNAL_MSI
    "ioctl/allow+0x404ae09b", // KVM_SET_GUEST_DEBUG
    "ioctl/allow+0xc00caee0", // KVM_CREATE_DEVICE
    "ioctl/allow+0x4018aee1", // KVM_SET_DEVICE_ATTR
    "ioctl/allow+0x8018aee2", // KVM_GET_DEVICE_ATTR
    "ioctl/allow+0x4018aee3", // KVM_HAS_DEVICE_ATTR
];

/// Profile to allowlist KVM arch-native ioctls without path check.
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
pub const PROFILE_KVM_NATIVE: &[&str] = &[
    "ioctl/allow+0x4680aea3",         // _KVM_ENABLE_CAP
    "ioctl/allow+0x4010aeab",         // _KVM_GET_ONE_REG
    "ioctl/allow+0x4010aeac",         // _KVM_SET_ONE_REG
    "ioctl/allow+0xc008aeb0",         // _KVM_GET_REG_LIST
    "ioctl/allow+5",                  // _KVM_ARM_TARGET_GENERIC_V8
    "ioctl/allow+0x8020aeaf",         // _KVM_ARM_PREFERRED_TARGET
    "ioctl/allow+0x4020aeae",         // _KVM_ARM_VCPU_INIT
    "ioctl/allow+0x4040aec2",         // _KVM_ARM_VCPU_FINALIZE
    "ioctl/allow+0x6030000000100042", // _KVM_ARM64_REGS_PSTATE
    "ioctl/allow+0x6030000000100044", // _KVM_ARM64_REGS_SP_EL1
    "ioctl/allow+0x6030000000100000", // _KVM_ARM64_REGS_R0
    "ioctl/allow+0x6030000000100002", // _KVM_ARM64_REGS_R1
    "ioctl/allow+0x6030000000100004", // _KVM_ARM64_REGS_R2
    "ioctl/allow+0x6030000000100006", // _KVM_ARM64_REGS_R3
    "ioctl/allow+0x6030000000100010", // _KVM_ARM64_REGS_R8
    "ioctl/allow+0x6030000000100024", // _KVM_ARM64_REGS_R18
    "ioctl/allow+0x6030000000100040", // _KVM_ARM64_REGS_PC
    "ioctl/allow+0x603000000013c510", // _KVM_ARM64_REGS_MAIR_EL1
    "ioctl/allow+0x603000000013c102", // _KVM_ARM64_REGS_TCR_EL1
    "ioctl/allow+0x603000000013c100", // _KVM_ARM64_REGS_TTBR0_EL1
    "ioctl/allow+0x603000000013c101", // _KVM_ARM64_REGS_TTBR1_EL1
    "ioctl/allow+0x603000000013c080", // _KVM_ARM64_REGS_SCTLR_EL1
    "ioctl/allow+0x603000000013c082", // _KVM_ARM64_REGS_CPACR_EL1
    "ioctl/allow+0x603000000013c600", // _KVM_ARM64_REGS_VBAR_EL1
    "ioctl/allow+0x603000000013df1a", // _KVM_ARM64_REGS_TIMER_CNT
    "ioctl/allow+0x603000000013df00", // _KVM_ARM64_REGS_CNTFRQ_EL0
    "ioctl/allow+0x6030000000138012", // _KVM_ARM64_REGS_MDSCR_EL1
    "ioctl/allow+0x603000000013c708", // _KVM_ARM64_REGS_CNTKCTL_EL1
    "ioctl/allow+0x603000000013c684", // _KVM_ARM64_REGS_TPIDR_EL1
];

/// Profile to allowlist KVM arch-native ioctls without path check.
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub const PROFILE_KVM_NATIVE: &[&str] = &[
    "ioctl/allow+0x0",        // _KVM_VCPU_TSC_CTRL
    "ioctl/allow+0x0",        // _KVM_VCPU_TSC_OFFSET
    "ioctl/allow+0xc004ae02", // _KVM_GET_MSR_INDEX_LIST
    "ioctl/allow+0xc004ae0a", // _KVM_GET_MSR_FEATURE_INDEX_LIST
    "ioctl/allow+0x4040ae77", // _KVM_CREATE_PIT2
    "ioctl/allow+0xc208ae62", // _KVM_GET_IRQCHIP
    "ioctl/allow+0x4208ae63", // _KVM_SET_IRQCHIP
    "ioctl/allow+0x4030ae7b", // _KVM_SET_CLOCK
    "ioctl/allow+0x8030ae7c", // _KVM_GET_CLOCK
    "ioctl/allow+0x8070ae9f", // _KVM_GET_PIT2
    "ioctl/allow+0x4070aea0", // _KVM_SET_PIT2
    "ioctl/allow+0xc008aeba", // _KVM_MEMORY_ENCRYPT_OP
    "ioctl/allow+0x8010aebb", // _KVM_MEMORY_ENCRYPT_REG_REGION
    "ioctl/allow+0x8010aebc", // _KVM_MEMORY_ENCRYPT_UNREG_REGION
    "ioctl/allow+0xc018ae85", // _KVM_TRANSLATE
    "ioctl/allow+0x81a0ae8c", // _KVM_GET_FPU
    "ioctl/allow+0x41a0ae8d", // _KVM_SET_FPU
    "ioctl/allow+0x8400ae8e", // _KVM_GET_LAPIC
    "ioctl/allow+0x4400ae8f", // _KVM_SET_LAPIC
    "ioctl/allow+0x4008ae90", // _KVM_SET_CPUID2
    "ioctl/allow+0xc008ae91", // _KVM_GET_CPUID2
    "ioctl/allow+0x8080aea1", // _KVM_GET_DEBUGREGS
    "ioctl/allow+0x4080aea2", // _KVM_SET_DEBUGREGS
    "ioctl/allow+0x9000aea4", // _KVM_GET_XSAVE
    "ioctl/allow+0x5000aea5", // _KVM_SET_XSAVE
    "ioctl/allow+0x8188aea6", // _KVM_GET_XCRS
    "ioctl/allow+0x4188aea7", // _KVM_SET_XCRS
    "ioctl/allow+0xaead",     // _KVM_KVMCLOCK_CTRL
];

/// Profile to allowlist KVM arch-native ioctls without path check.
#[cfg(not(any(
    target_arch = "arm",
    target_arch = "x86",
    target_arch = "x86_64",
    target_arch = "aarch64"
)))]
pub const PROFILE_KVM_NATIVE: &[&str] = &[];

/// The list of mount family syscalls
pub const MOUNT_SYSCALLS: &[&str] = &[
    "mount",
    "mount_setattr",
    "umount",
    "umount2",
    "listmount",
    "statmount",
];

/// The list of process, i/o priority changing system calls.
pub const NICE_SYSCALLS: &[&str] = &[
    "ioprio_set",
    "sched_setattr",
    "sched_setscheduler",
    "sched_setparam",
    "setpriority",
];

/// The list of perf/debugging system calls.
pub const PERF_SYSCALLS: &[&str] = &[
    "lookup_dcookie",
    "perf_event_open",
    "rtas",
    "s390_runtime_instr",
    "sys_debug_setcontext",
];

/// The list of ptrace system calls.
pub const PTRACE_SYSCALLS: &[&str] = &["ptrace", "process_vm_readv", "process_vm_writev"];

/// The list of system calls which are of the getid family.
pub const GET_ID_SYSCALLS: &[&str] = &[
    "getuid",
    "getuid32",
    "getgid",
    "getgid32",
    "geteuid",
    "geteuid32",
    "getegid",
    "getegid32",
    "getresuid",
    "getresuid32",
    "getresgid",
    "getresgid32",
];

/// The list of system calls which are of the futex family.
pub const FUTEX_SYSCALLS: &[&str] = &[
    "futex",
    "futex_requeue",
    "futex_time64",
    "futex_wait",
    "futex_waitv",
    "futex_wake",
    "swapcontext",
    "sys_debug_swapcontext",
];

/// The list of system calls which are of the setid family.
pub const SET_ID_SYSCALLS: &[&str] = &[
    "setuid",
    "setuid32",
    "setgid",
    "setgid32",
    "setreuid",
    "setreuid32",
    "setregid",
    "setregid32",
    "setresuid",
    "setresuid32",
    "setresgid",
    "setresgid32",
];

/// SAFETY: We do not support diverging FsID from Effective ID.
/// SAFETY: We do not support setgroups (due to pointer deref -> TOCTOU vector)
pub const UNSAFE_ID_SYSCALLS: &[&str] = &[
    "setfsgid",
    "setfsgid32",
    "setfsuid",
    "setfsuid32",
    "setgroups",
    "setgroups32",
];

/// The list of system calls which syd has a `UNotify` callback for
pub const HOOK_SYSCALLS: &[&str] = &[
    "accept",
    "accept4",
    "bind",
    "connect",
    "getsockname",
    "sendto",
    "sendmsg",
    "sendmmsg",
    "socket",
    "execve",
    "execveat",
    "getdents64",
    "stat",
    "access",
    "fstat",
    "fstat64",
    "fstatat64",
    "lstat",
    "newfstatat",
    "stat64",
    "statx",
    "faccessat",
    "faccessat2",
    "chdir",
    "fchdir",
    "chmod",
    "fchmod",
    "fchmodat",
    "fchmodat2",
    "fchown",
    "fchown32",
    "chown",
    "lchown",
    "fchownat",
    "creat",
    "link",
    "symlink",
    "unlink",
    "linkat",
    "symlinkat",
    "unlinkat",
    "mkdir",
    "rmdir",
    "mkdirat",
    "mknod",
    "mknodat",
    "open",
    "openat",
    "openat2",
    "rename",
    "renameat",
    "renameat2",
    "utime",
    "utimes",
    "futimesat",
    "utimensat",
    "truncate",
    "truncate64",
    "ftruncate",
    "ftruncate64",
    "getxattr",
    "getxattrat",
    "fgetxattr",
    "lgetxattr",
    "setxattr",
    "setxattrat",
    "fsetxattr",
    "lsetxattr",
    "listxattr",
    "listxattrat",
    "flistxattr",
    "llistxattr",
    "removexattr",
    "removexattrat",
    "fremovexattr",
    "lremovexattr",
    "ioctl",
    "prctl",
    "kill",
    "tkill",
    "tgkill",
    "rt_sigqueueinfo",
    "rt_tgsigqueueinfo",
    "pidfd_open",
    "brk",
    "mmap",
    "mmap2",
    "mremap",
    "setrlimit",
    "prlimit64",
    "statfs",
    "statfs64",
    "fstatfs",
    "fstatfs64",
    "fallocate",
    "uname",
    "fanotify_mark",
    "inotify_add_watch",
    "memfd_create",
    "fcntl",
    "fcntl64",
    "sysinfo",
    "sigaction",
    "rt_sigaction",
    "chroot",
    "syslog",
];

/// The list of system calls which are no-ops.
///
/// As of 3.30.0 we use SafeChroot so chroot(2) is not here anymore.
pub const NOOP_SYSCALLS: &[&str] = &["pivot_root"];

/// The list of system calls that are denied in syd parent seccomp filter.
/// This filter is inherited by the sandbox process.
/// These system calls must not be used by syd.
pub const DEAD_SYSCALLS: &[&str] = &[
    "_sysctl", // deprecated
    "acct",
    // Hard disabled due to pointer-indirection during NS check.
    "clone3",
    "create_module",
    "delete_module",
    "finit_module",
    "fsconfig",
    "fsmount",
    "fsopen",
    "fspick",
    "get_kernel_syms",
    "init_module",
    "ioperm",
    "iopl",
    "kexec_file_load",
    "kexec_load",
    "lsm_get_self_attr",
    "lsm_set_self_attr",
    "lsm_list_modules",
    "mbind",
    "migrate_pages",
    "mincore",
    "mount_setattr",
    "move_pages",
    "name_to_handle_at",
    "nfsservctl",
    "open_tree",
    "pciconfig_iobase",
    "pciconfig_read",
    "pciconfig_write",
    "query_module",
    "quotactl",
    "quotactl_fd",
    "reboot",
    "request_key",
    "stime", // deprecated use clock_settime
    "swapoff",
    "swapon",
    "sysfs",
    "uselib",
    // Added in Linux-4.3
    // (Ab)used by most Project Zero Linux kernel exploits.
    "userfaultfd",
    "ustat", // deprecated
    "vhangup",
    "vmsplice", // https://lore.kernel.org/linux-mm/X+PoXCizo392PBX7@redhat.com/
];

/// The list of system calls which are confined by the Stat sandboxing category.
///
/// Note, this list _must_ be sorted!
pub const STAT_SYSCALLS: &[&str] = &[
    "access",
    "faccessat",
    "faccessat2",
    "fanotify_mark",
    "fgetxattr",
    "flistxattr",
    "fstatat64",
    "fstatfs",
    "fstatfs64",
    "getxattr",
    "getxattrat",
    "inotify_add_watch",
    "lgetxattr",
    "listxattr",
    "listxattrat",
    "llistxattr",
    "lstat",
    "lstat64",
    "newfstatat",
    "stat",
    "stat64",
    "statfs",
    "statfs64",
    "statx",
];

/// The list of system calls which are confined by the Delete sandboxing category.
///
/// Note, this list _must_ be sorted!
pub const DELETE_SYSCALLS: &[&str] = &["rmdir", "unlink", "unlinkat"];

/// The list of system calls which are confined by the Rename sandboxing category.
///
/// Note, this list _must_ be sorted!
pub const RENAME_SYSCALLS: &[&str] = &["link", "linkat", "rename", "renameat", "renameat2"];

/// The list of system calls which are confined by the Truncate sandboxing category.
///
/// Note, this list _must_ be sorted!
pub const TRUNCATE_SYSCALLS: &[&str] = &[
    "fallocate",
    "ftruncate",
    "ftruncate64",
    "truncate",
    "truncate64",
];

/// The list of system calls which are confined by the Connect network sandboxing category.
///
/// Note, this list _must_ be sorted!
pub const CONNECT_SYSCALLS: &[&str] = &[
    "accept", "accept4", "connect", "sendmmsg", "sendmsg", "sendto",
];

/// The list of system calls which are for CPU emulation functionality.
pub const CPU_SYSCALLS: &[&str] = &[
    "modify_ldt",
    "subpage_prot",
    "switch_endian",
    "vm86",
    "vm86old",
];

/// The list of system calls which are for Kernel keyring access.
pub const KEYRING_SYSCALLS: &[&str] = &["add_key", "keyctl", "request_key"];

/// The list of system calls which are used for memory protection keys.
pub const PKEY_SYSCALLS: &[&str] = &["pkey_alloc", "pkey_free", "pkey_mprotect"];

/// The list of system calls which are part of time/clock adjustment.
pub const TIME_SYSCALLS: &[&str] = &[
    "adjtimex",
    "clock_adjtime",
    "clock_adjtime64",
    "clock_settime",
    "clock_settime64",
    "settimeofday",
    //"stime", deprecated do not use!
];

/// The list of system calls for filesystem sync.
/// SAFETY: By default sync(2), syncfs(2) are no-ops to prevent potential local DoS.
pub const SYNC_SYSCALLS: &[&str] = &["sync", "syncfs"];

/// The list of system calls which are part of the io_uring interface.
pub const IOURING_SYSCALLS: &[&str] = &["io_uring_enter", "io_uring_register", "io_uring_setup"];

/// The list of system calls which are allowlisted without any filtering.
pub const SAFE_SYSCALLS: &[&str] = &[
    "_llseek",
    "_newselect",
    //"_sysctl",
    //"accept",
    //"accept4",
    //"acct",
    //add_key, restrictions applied, see setup_seccomp.
    //adjtimex, restrictions applied, see setup_seccomp.
    //afs_syscall
    "alarm",
    "arch_prctl", // Used during platform-specific initialization by ld-linux.so.
    "arm_fadvise64_64",
    "arm_sync_file_range",
    "atomic_barrier",
    "atomic_cmpxchg_32",
    //"bpf", restrictions applied, see setup_seccomp.
    "breakpoint", // arm
    //"brk",
    "cachestat",  // fd-only.
    "cacheflush", // arm
    "capget",
    "capset",
    //"chdir",
    //"chroot",
    //clock_adjtime, restrictions applied, see setup_seccomp.
    //clock_adjtime64, restrictions applied, see setup_seccomp.
    "clock_getres",
    "clock_getres_time64",
    "clock_gettime",
    "clock_gettime64",
    "clock_nanosleep",
    "clock_nanosleep_time64",
    //"clock_settime", restrictions applied, see setup_seccomp.
    //"clock_settime64", ditto
    "clone",
    // "clone3", // unsafe because namespaces cannot be restricted.
    "close",
    "close_range",
    "copy_file_range",
    //create_module
    //delete_module
    "dup",
    "dup2",
    "dup3",
    "epoll_create",
    "epoll_create1",
    "epoll_ctl",
    "epoll_ctl_old",
    "epoll_pwait",
    "epoll_pwait2",
    "epoll_wait",
    "epoll_wait_old",
    "eventfd",
    "eventfd2",
    "exit",
    "exit_group",
    "fadvise64",
    "fadvise64_64",
    //"fallocate",
    "fanotify_init",
    //"fanotify_mark", device side-channel mitigations
    //"fchdir",
    //"fchmod",
    //"fchown",
    //"fchown32",
    //"fcntl", restrictions applied for appendonly!
    //"fcntl64", ditto
    "fdatasync",
    //finit_module
    "flock",
    "fork",
    //fsconfig
    //fsmount
    //fsopen
    //fspick
    //"fstat",
    //"fstat64",
    //"oldfstat",
    //"fstatfs",
    //"fstatfs64",
    "fsync",
    //"ftruncate",
    //"ftruncate64",
    // "futex", See: FUTEX_SYSCALLS for futex family.
    //get_kernel_syms
    "getpagesize",
    "get_mempolicy",
    "get_robust_list",
    "get_thread_area",
    "getcpu",
    "getcwd",
    //"getdents",
    //"getdents64",
    //"getegid",
    //"getegid32",
    //"geteuid",
    //"geteuid32",
    //"getgid",
    //"getgid32",
    "getgroups",
    "getgroups32",
    "getitimer",
    "getpeername",
    "getpgid",
    "getpgrp",
    "getpid",
    "getpmsg",
    "getppid",
    "getpriority",
    "getrandom", // Hola VDSO!
    "getresgid",
    "getresuid",
    "getrlimit",
    "getrusage",
    "getsid",
    // "getuid", See: GET_ID_SYSCALLS for getid family.
    //"getsockname",
    "getsockopt",
    "gettid",
    "gettimeofday",
    //init_module
    //"inotify_add_watch",
    "inotify_init",
    "inotify_init1",
    "inotify_rm_watch",
    "io_cancel",
    "io_destroy",
    "io_getevents",
    "io_pgetevents",
    "io_pgetevents_time64",
    "io_setup",
    "io_submit",
    /*
     * io-uring: restrictions applied, see setup_seccomp.
    "io_uring_enter",
    "io_uring_register",
    "io_uring_setup",
    */
    //"ioctl", restrictions applied, see setup_seccomp.
    //"ioperm",
    //"iopl",
    "ioprio_get",
    //"ioprio_set", restrictions applied, see setup_seccomp.
    "kcmp",
    //kexec_file_load,
    //kexec_load,
    //keyctl, restrictions applied, see setup_seccomp.
    //"kill", restrictions applied, see setup_seccomp.
    "landlock_add_rule",
    "landlock_create_ruleset",
    "landlock_restrict_self",
    "listen",
    //"lookup_dcookie", restrictions applied, see setup_seccomp.
    "lseek",
    "madvise",
    //"mbind",
    "membarrier",
    //"memfd_create",
    //"memfd_secret",
    //"migrate_pages",
    //"mincore", NO! https://arxiv.org/pdf/1901.01161
    "mlock",
    "mlock2",
    "mlockall",
    //"mmap",
    //"mmap2",
    //"modify_ldt", restrictions applied, see setup_seccomp.
    //"mount", restrictions applied, see setup_seccomp.
    //"mount_setattr", // ditto
    //"move_pages",
    "mprotect",
    "mq_getsetattr",
    "mq_notify",
    "mq_open",
    "mq_timedreceive",
    "mq_timedreceive_time64",
    "mq_timedsend",
    "mq_timedsend_time64",
    "mq_unlink",
    //"mremap",
    "mseal",
    "msgctl",
    "msgget",
    "msgrcv",
    //"msgsnd", restrictions applied, see setup_seccomp.
    "msync",
    "munlock",
    "munlockall",
    "munmap",
    //name_to_handle_at
    "nanosleep",
    //nfsservctl,
    //"open_by_handle_at",
    //open_tree
    "pause",
    //"perf_event_open", restrictions applied see load_seccomp_parent and setup_seccomp.
    "personality", // restrictions applied in load_seccomp_parent.
    "pidfd_getfd",
    //"pidfd_open", restrictions applied, see setup_seccomp.
    "pidfd_send_signal",
    "pipe",
    "pipe2",
    //pivot_root,
    //"pkey_alloc", restrictions applied, see setup_seccomp.
    //"pkey_free", ditto
    //"pkey_mprotect", ditto
    "poll",
    "ppoll",
    "ppoll_time64",
    // "prctl", restrictions applied, see setup_seccomp.
    "pread64",
    "preadv",
    "preadv2",
    //"prlimit64",
    "process_madvise",
    "process_mrelease",
    //process_vm_readv // restrictions applied, see setup_seccomp.
    //process_vm_writev // ditto.
    "pselect6",
    "pselect6_time64",
    //"ptrace", // restrictions applied see load_seccomp_parent and setup_seccomp.
    //"putpmsg",
    "pwrite64",
    "pwritev",
    "pwritev2",
    //query_module,
    //quotactl
    //quotactl_fd
    "read",
    "readahead",
    "readlink",
    "readlinkat",
    "readv",
    //reboot
    "recv",
    "recvfrom",
    "recvmmsg",
    "recvmmsg_time64",
    "recvmsg",
    "remap_file_pages",
    //request_key, restrictions applied, see setup_seccomp.
    "restart_syscall",
    "riscv_flush_icache",
    //"riscv_hwprobe", info leak, see: https://www.kernel.org/doc/html/v6.6/riscv/hwprobe.html
    "rseq",
    //"rt_sigaction", SA_RESTART tracking.
    "rt_sigpending",
    "rt_sigprocmask",
    //"rt_sigqueueinfo", restrictions applied, see setup_seccomp.
    //"rt_sigreturn", SROP mitigations
    "rt_sigsuspend",
    "rt_sigtimedwait",
    "rt_sigtimedwait_time64",
    //"rt_tgsigqueueinfo", restrictions applied, see setup_seccomp.
    "s390_pci_mmio_read",
    "s390_pci_mmio_write",
    "s390_runtime_instr",
    "sched_get_priority_max",
    "sched_get_priority_min",
    "sched_getaffinity",
    "sched_getattr",
    "sched_rr_get_interval",
    "sched_rr_get_interval_time64",
    "sched_getparam",
    "sched_getscheduler",
    "sched_setaffinity",
    //"sched_setattr", restrictions applied, see setup_seccomp.
    //"sched_setscheduler", restrictions applied, see setup_seccomp.
    //"sched_setparam", restrictions applied, see setup_seccomp.
    "sched_yield",
    //"seccomp", restrictions applied, see setup_seccomp.
    //security
    "select",
    "semctl",
    "semget",
    "semop",
    "semtimedop",
    "semtimedop_time64",
    "send",
    "sendfile",
    "sendfile64",
    //"sendmmsg", emulated.
    //"sendmsg", emulated.
    "set_mempolicy",
    "set_mempolicy_home_node",
    "set_robust_list",
    "set_thread_area",
    "set_tid_address",
    "setdomainname",
    //"setfsgid",
    //"setfsgid32",
    //"setfsuid",
    //"setfsuid32",
    //"setgid",
    //"setgid32",
    //"setgroups",
    //"setgroups32",
    "sethostname",
    "setitimer",
    "setns", // restrictions applied in load_seccomp_parent.
    "setpgid",
    //"setpriority", restrictions applied, see setup_seccomp.
    //"setregid",
    //"setregid32",
    //"setresgid",
    //"setresgid32",
    //"setresuid",
    //"setresuid32",
    //"setreuid",
    //"setreuid32",
    //"setrlimit",
    "setsid",
    "setsockopt",
    //"settimeofday"
    //"setuid",
    //"setuid32",
    "set_tls", // arm
    //"sgetmask", // x86, OBSOLETE!
    //"ssetmask", // x86, OBSOLETE!
    "shmat",
    "shmctl",
    "shmdt",
    "shmget",
    "shutdown",
    "signal",
    //"sigaction", SA_RESTART tracking.
    "sigaltstack",
    "signalfd",
    "signalfd4",
    "sigpending",
    "sigprocmask",
    "sigsuspend",
    //"sigreturn", SROP mitigations
    //"socket",
    "socketpair",
    "splice",
    //"statfs",
    //"statfs64",
    //swapoff
    //swapon
    //"sync",
    "sync_file_range",
    //"syncfs",
    //"sysinfo", information-leak, see setup_seccomp.
    //"syslog",
    "tee",
    //"tgkill", restrictions applied, see setup_seccomp.
    "time",
    "timer_create",
    "timer_delete",
    "timer_getoverrun",
    "timer_gettime",
    "timer_gettime64",
    "timer_settime",
    "timer_settime64",
    "timerfd_create",
    "timerfd_gettime",
    "timerfd_gettime64",
    "timerfd_settime",
    "timerfd_settime64",
    "times",
    //"tkill", an obsolete predecessor to tgkill, should be avoided.
    //tuxcall
    "ugetrlimit",
    "umask",
    //"uname", restrictions applied, see setup_seccomp.
    //olduname,
    //oldolduname,
    //"umount", restrictions applied, see setup_seccomp.
    //"umount2", // ditto
    "unshare", // restrictions applied in load_seccomp_parent.
    //"uselib",
    //"userfaultfd",
    //"ustat",
    "vfork",
    //"vhangup",
    //"vmsplice", // see DEAD_SYSCALLS!
    //vserver
    "wait4",
    "waitid",
    "waitpid",
    "write",
    "writev",
];

/// System calls allowed for emulator threads.
// TODO: Further restrict open & socket calls.
pub const EMU_SYSCALLS: &[&str] = &[
    "_llseek",
    "accept4",
    "bind",
    "brk",
    "clock_gettime",
    "clock_gettime64",
    "clock_nanosleep",
    "clone",
    "clone3",
    "close",
    "connect",
    "exit",
    "exit_group",
    "fallocate",
    "fanotify_mark",
    "fchdir",
    "fchmod",
    "fchown",
    "fdatasync", // for logging.
    "fgetxattr",
    "flistxattr",
    "fremovexattr",
    "fsetxattr",
    "fstat",
    "fstat64",
    "fstatfs",
    "fstatfs64",
    "ftruncate",
    "ftruncate64",
    // "futex", See: FUTEX_SYSCALLS for futex family.
    "get_robust_list",
    "getdents64",
    "getpgid",
    "getpgrp",
    "getpid",
    "getrandom",
    "getsockname",
    "getsockopt",
    "gettid",
    "getxattrat",
    "inotify_add_watch",
    "landlock_create_ruleset",
    "landlock_restrict_self",
    "lgetxattr",
    "linkat",
    "listxattrat",
    "llistxattr",
    "lremovexattr",
    "lseek",
    "lsetxattr",
    "lstat",
    "madvise",
    "memfd_create",
    "mlock",
    "mmap",
    "mmap2",
    "mprotect",
    "mremap",
    "munlock",
    "munmap",
    "nanosleep",
    "pidfd_getfd",
    "pidfd_open",
    "pidfd_send_signal",
    "pipe2",
    "prctl",
    "process_vm_readv",
    "process_vm_writev",
    "read",
    "readv",
    "removexattrat",
    "restart_syscall",
    "rseq",
    "rt_sigprocmask",
    "sched_getaffinity",
    "sched_setaffinity",
    "sched_yield",
    "send",
    "sendmsg",
    "sendto",
    "set_robust_list",
    "setxattrat",
    "sigaltstack",
    "sigprocmask",
    "socket",
    "splice",
    "symlinkat",
    "tee",
    "tgkill",
    "tkill",
    "truncate",
    "truncate64",
    "umask",
    "uname",
    "waitid",
    // Required to unblock FIFOs.
    "sigreturn",
    "rt_sigreturn",
    //TODO:deny installing new signal handlers!
    "sigaction",
    "rt_sigaction",
    // fd calls
    "faccessat2",
    "fchmodat",
    "fchmodat2",
    "fchownat",
    "mkdirat",
    "mknodat",
    "newfstatat",
    "openat2",
    "readlinkat",
    "renameat",
    "renameat2",
    "statx",
    "unlinkat",
    "utimensat",
];

/// Fcntl operations allowed for emulator threads.
pub const EMU_FCNTL_OPS: &[u64] = &[
    libc::F_GETFD as u64,
    libc::F_SETFD as u64,
    libc::F_GETFL as u64,
    libc::F_SETFL as u64,
    libc::F_OFD_SETLK as u64,
    libc::F_OFD_SETLKW as u64,
];

/// System calls allowed for Interrupter thread.
pub const INT_SYSCALLS: &[&str] = &[
    "clock_nanosleep",
    "close",
    "exit",
    "exit_group", // to exit if inter-thread signaling does not work.
    // "futex", See: FUTEX_SYSCALLS for futex family.
    "getpid",
    "gettid",
    "munmap", // memory deallocation is allowed but allocation is not.
    "nanosleep",
    "read",
    "restart_syscall",
    "rt_sigprocmask",
    "sched_yield",
    "sigaltstack", // rare but necessary.
    "sigprocmask", // ditto.
];

/// Fcntl operations allowed for Interrupter thread.
pub const INT_FCNTL_OPS: &[u64] = &[libc::F_GETFD as u64];

/// System calls allowed for AES threads.
pub const AES_SYSCALLS: &[&str] = &[
    "_llseek",
    "accept4",
    "brk",
    "clock_gettime",
    "clock_gettime64",
    "clock_nanosleep",
    "clone",
    "clone3",
    "close",
    "connect",
    "exit",
    //"fcntl", See: AES_FCNTL_OPS for allowed fcntl operations.
    //"fcntl64",
    "fremovexattr",
    "ftruncate",
    "ftruncate64",
    // "futex", See: FUTEX_SYSCALLS for futex family.
    "get_robust_list",
    "getpid",
    "getrandom",
    "getsockopt",
    "gettid",
    "landlock_create_ruleset",
    "landlock_restrict_self",
    "lseek",
    "madvise",
    "mlock",
    "mmap",
    "mmap2",
    "mprotect",
    "mremap",
    "munlock",
    "munmap",
    "nanosleep",
    "pipe2",
    "prctl",
    "recvmsg",
    "restart_syscall",
    "rseq",
    "rt_sigprocmask",
    "sched_getaffinity",
    "sched_yield",
    "send",
    "sendmsg",
    "sendto",
    "set_robust_list",
    "sigaltstack",
    "sigprocmask",
    "splice",
    "tee",
    //TODO:deny installing new signal handlers!
    "sigaction",
    "rt_sigaction",
];

/// Fcntl operations allowed for AES threads.
pub const AES_FCNTL_OPS: &[u64] = &[
    libc::F_GETFD as u64,
    libc::F_SETFD as u64,
    libc::F_OFD_SETLKW as u64,
];

/// System calls allowed for main wait thread.
pub const MAIN_SYSCALLS: &[&str] = &[
    "_llseek",
    "brk",
    "clock_gettime",
    "clock_gettime64",
    "clock_nanosleep",
    "close",
    "exit_group",
    "fdatasync", // for logging.
    "fstat",
    "fstat64",
    "fstatfs",
    "fstatfs64",
    // "futex", See: FUTEX_SYSCALLS for futex family.
    "get_robust_list",
    "getdents64", // used by pid-limiter.
    "getpgid",
    "getpgrp",
    "getpid",
    "getrandom",
    "gettid",
    "kill", // used by pid-limiter.
    "lseek",
    "madvise",
    "mmap",
    "mmap2",
    "mprotect",
    "mremap",
    "munlock",
    "munmap",
    "nanosleep",
    "pidfd_open",
    "pidfd_getfd",
    "pidfd_send_signal",
    "process_vm_readv",  // needed to get AT_{RANDOM,SECURE}.
    "process_vm_writev", // needed to set AT_SECURE.
    "ptrace",
    "read",
    "readv",
    "restart_syscall",
    "rseq",
    "rt_sigprocmask",
    "sched_getaffinity",
    //"sched_setaffinity", set before confinement, unneeded after.
    "sched_yield",
    "set_robust_list",
    "sigaltstack",
    "sigprocmask",
    "statx",
    "sysinfo", // used by pid-limiter.
    "tgkill",
    "tkill",
    "waitid",
    //TODO:deny installing new signal handlers!
    "sigaction",
    "rt_sigaction",
    // fd-calls
    "faccessat2",
    "newfstatat",
    "openat2",
    "readlinkat",
];

/// Fcntl operations allowed for main wait thread.
pub const MAIN_FCNTL_OPS: &[u64] = &[
    libc::F_GETFD as u64,
    libc::F_SETFD as u64,
    libc::F_GETFL as u64,
    libc::F_SETFL as u64,
    libc::F_OFD_SETLK as u64,
    libc::F_OFD_SETLKW as u64,
];

/// Define a static (global) Lazy value for the kernel version.
#[allow(clippy::disallowed_methods)]
pub static KERNEL_VERSION: Lazy<(u32, u32)> = Lazy::new(|| {
    use std::os::unix::ffi::OsStrExt;

    use btoi::btoi;
    use memchr::memchr;
    use nix::sys::utsname::uname;

    let version = uname().unwrap();
    let version = version.release().as_bytes();
    let nextdot = memchr(b'.', version).unwrap();
    let major = btoi::<u32>(&version[..nextdot]).unwrap();
    let version = &version[nextdot + 1..];
    let nextdot = memchr(b'.', version).unwrap();
    let minor = btoi::<u32>(&version[..nextdot]).unwrap();

    (major, minor)
});

/// Check for PIDFD_THREAD support (Linux-6.9 or newer).
pub static HAVE_PIDFD_THREAD: Lazy<bool> = Lazy::new(|| {
    let (major, minor) = *KERNEL_VERSION;
    major > 6 || (major == 6 && minor >= 9)
});

/// Check for SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP support (Linux-6.6 or newer).
pub static HAVE_SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP: Lazy<bool> = Lazy::new(|| {
    let (major, minor) = *KERNEL_VERSION;
    major > 6 || (major == 6 && minor >= 6)
});

/// Check for STATX_MNT_ID_UNIQUE support (Linux-6.8 or newer).
pub(crate) static HAVE_STATX_MNT_ID_UNIQUE: Lazy<bool> = Lazy::new(|| {
    let (major, minor) = *KERNEL_VERSION;
    major > 6 || (major == 6 && minor >= 8)
});

//
// Below is internal territory, you have been warned.
//
/// Determine minimum allowed mmap address by reading `/proc/sys/vm/mmap_min_addr`.
pub(crate) static MMAP_MIN_ADDR: Lazy<u64> = Lazy::new(|| proc_mmap_min_addr().unwrap_or(4096));

// Trace data for ptrace(2) hooked system calls.
//
// This we we don't rely on system call number
// which is architecture/personality specific.
pub(crate) const PTRACE_DATA_CHDIR: u16 = 0;
pub(crate) const PTRACE_DATA_EXECVE: u16 = 1;
pub(crate) const PTRACE_DATA_EXECVEAT: u16 = 2;
pub(crate) const PTRACE_DATA_SIGRETURN: u16 = 3;
pub(crate) const PTRACE_DATA_RT_SIGRETURN: u16 = 4;

/// Returns a new randomized timer.
pub(crate) static _RAND_TIMER: OnceLock<RandTimer> = OnceLock::new();

/// Returns a reference to the static randomized timer.
///
/// Calling this before `timer_init` will panic!
#[allow(clippy::disallowed_methods)]
#[allow(non_snake_case)]
#[inline(always)]
pub(crate) fn RAND_TIMER() -> &'static RandTimer {
    _RAND_TIMER.get().unwrap()
}

/// Initialize randomized timer.
#[allow(clippy::cognitive_complexity)]
#[allow(clippy::disallowed_methods)]
pub fn timer_init() -> Result<(), Errno> {
    let timer = RandTimer::new()?;

    info!("ctx": "run", "op": "sysinfo_init_timer",
        "msg": "initialized internal sysinfo(2) randomized timer",
        "off": [timer.uptime_offset, timer.idle_offset]);
    _RAND_TIMER.set(timer).or(Err(Errno::EAGAIN))?;

    Ok(())
}

/// Returns a reference to the static `/` dirfd.
///
/// Calling this before calling `proc_init` will panic!
#[allow(clippy::disallowed_methods)]
#[allow(non_snake_case)]
#[inline(always)]
pub(crate) fn ROOT_FD() -> RawFd {
    *_ROOT_FD.get().unwrap()
}

/// Returns a reference to the static `/` unique mount id.
///
/// Calling this before calling `proc_init` will panic!
#[allow(clippy::disallowed_methods)]
#[allow(non_snake_case)]
#[inline(always)]
pub(crate) fn ROOT_MNT_ID() -> u64 {
    *_ROOT_MNT_ID.get().unwrap()
}

/// Returns a reference to the static `/` dirfd.
///
/// Calling this before calling `proc_init` will panic!
#[allow(clippy::disallowed_methods)]
#[allow(non_snake_case)]
#[inline(always)]
pub(crate) fn ROOT_FILE() -> BorrowedFd<'static> {
    // SAFETY: `proc_init' is called beforehand.
    unsafe { BorrowedFd::borrow_raw(ROOT_FD()) }
}

/// Returns a reference to the static `/dev` dirfd.
///
/// Calling this before calling `proc_init` will panic!
#[allow(clippy::disallowed_methods)]
#[allow(non_snake_case)]
#[inline(always)]
pub(crate) fn DEV_FD() -> RawFd {
    *_DEV_FD.get().unwrap()
}

/// Returns a reference to the static `/dev` unique mount id.
///
/// Calling this before calling `proc_init` will panic!
#[allow(clippy::disallowed_methods)]
#[allow(non_snake_case)]
#[inline(always)]
pub(crate) fn DEV_MNT_ID() -> u64 {
    *_DEV_MNT_ID.get().unwrap()
}

/// Returns a reference to the static `/dev` dirfd.
///
/// Calling this before calling `proc_init` will panic!
#[allow(clippy::disallowed_methods)]
#[allow(non_snake_case)]
#[inline(always)]
pub(crate) fn DEV_FILE() -> BorrowedFd<'static> {
    // SAFETY: `proc_init' is called beforehand.
    unsafe { BorrowedFd::borrow_raw(DEV_FD()) }
}

/// Returns a reference to the static `/proc` dirfd.
///
/// Calling this before calling `proc_init` will panic!
#[allow(clippy::disallowed_methods)]
#[allow(non_snake_case)]
#[inline(always)]
pub(crate) fn PROC_FD() -> RawFd {
    *_PROC_FD.get().unwrap()
}

/// Returns a reference to the static `/proc` unique mount id.
///
/// Calling this before calling `proc_init` will panic!
#[allow(clippy::disallowed_methods)]
#[allow(non_snake_case)]
#[inline(always)]
pub(crate) fn PROC_MNT_ID() -> u64 {
    *_PROC_MNT_ID.get().unwrap()
}

/// Returns a reference to the static `/proc` dirfd.
///
/// Calling this before calling `proc_init` will panic!
#[allow(clippy::disallowed_methods)]
#[allow(non_snake_case)]
#[inline(always)]
pub(crate) fn PROC_FILE() -> BorrowedFd<'static> {
    // SAFETY: `proc_init' is called beforehand.
    unsafe { BorrowedFd::borrow_raw(PROC_FD()) }
}

/// Returns a reference to the static `/sys` dirfd.
///
/// Calling this before calling `proc_init` will panic!
#[allow(clippy::disallowed_methods)]
#[allow(non_snake_case)]
#[inline(always)]
pub fn SYS_FD() -> RawFd {
    *_SYS_FD.get().unwrap()
}

/// Returns a reference to the static `/sys` unique mount id.
///
/// Calling this before calling `proc_init` will panic!
#[allow(clippy::disallowed_methods)]
#[allow(non_snake_case)]
#[inline(always)]
pub(crate) fn SYS_MNT_ID() -> u64 {
    *_SYS_MNT_ID.get().unwrap()
}

/// Returns a reference to the static `/sys` dirfd.
///
/// Calling this before calling `proc_init` will panic!
#[allow(clippy::disallowed_methods)]
#[allow(non_snake_case)]
#[inline(always)]
pub(crate) fn SYS_FILE() -> BorrowedFd<'static> {
    // SAFETY: `proc_init' is called beforehand.
    unsafe { BorrowedFd::borrow_raw(SYS_FD()) }
}

/// Returns a reference to the static `/dev/null` fd.
///
/// Calling this before calling `proc_init` will panic!
#[allow(clippy::disallowed_methods)]
#[allow(non_snake_case)]
#[inline(always)]
pub(crate) fn NULL_FD() -> RawFd {
    *_NULL_FD.get().unwrap()
}

/// Returns a reference to the static `/dev/null` unique mount id.
///
/// Calling this before calling `proc_init` will panic!
#[allow(clippy::disallowed_methods)]
#[allow(non_snake_case)]
#[inline(always)]
pub(crate) fn NULL_MNT_ID() -> u64 {
    *_NULL_MNT_ID.get().unwrap()
}

/*
/// Returns a reference to the static `/dev/null` fd.
///
/// Calling this before calling `proc_init` will panic!
#[allow(clippy::disallowed_methods)]
#[allow(non_snake_case)]
#[inline(always)]
pub(crate) fn NULL_FILE() -> BorrowedFd<'static> {
    // SAFETY: `proc_init' is called beforehand.
    unsafe { BorrowedFd::borrow_raw(NULL_FD()) }
}
*/

/// File descriptor to `/`, ie the root file system.
pub(crate) static _ROOT_FD: OnceLock<RawFd> = OnceLock::new();

/// Unique mount id to `/`, ie the root file system.
pub(crate) static _ROOT_MNT_ID: OnceLock<u64> = OnceLock::new();

/// File descriptor to /dev file system.
pub(crate) static _DEV_FD: OnceLock<RawFd> = OnceLock::new();

/// Unique mount id to /dev file system.
pub(crate) static _DEV_MNT_ID: OnceLock<u64> = OnceLock::new();

/// File descriptor to /proc file system.
pub(crate) static _PROC_FD: OnceLock<RawFd> = OnceLock::new();

/// Unique mount id to /proc file system.
pub(crate) static _PROC_MNT_ID: OnceLock<u64> = OnceLock::new();

/// File descriptor to /sys file system.
pub(crate) static _SYS_FD: OnceLock<RawFd> = OnceLock::new();

/// Unique mount id to /sys file system.
pub(crate) static _SYS_MNT_ID: OnceLock<u64> = OnceLock::new();

/// File descriptor to /dev/null character device.
pub(crate) static _NULL_FD: OnceLock<RawFd> = OnceLock::new();

/// Unique mount id to /dev/null character device.
pub(crate) static _NULL_MNT_ID: OnceLock<u64> = OnceLock::new();

/// Initialize static file descriptors for use by syd::proc any friends.
#[allow(clippy::cognitive_complexity)]
#[allow(clippy::disallowed_methods)]
pub fn proc_init() -> Result<(), Errno> {
    let mask = if *HAVE_STATX_MNT_ID_UNIQUE {
        STATX_MNT_ID_UNIQUE
    } else {
        STATX_MNT_ID
    };

    let fd_root = nix::fcntl::open("/", OFlag::O_RDONLY | OFlag::O_DIRECTORY, Mode::empty())?;
    let id_root = fstatx(&fd_root, mask).map(|stx| stx.stx_mnt_id)?;

    // SAFETY: To make this file descriptor harder to spot by an
    // attacker we duplicate it to a random fd number.
    let fd_rand = duprand(fd_root)?;
    let _ = close(fd_root);
    let fd_root = fd_rand;

    info!("ctx": "run", "op": "opendir_root",
        "msg": "opened root directory",
        "fd": fd_root,
        "id": id_root);
    _ROOT_FD.set(fd_root).or(Err(Errno::EAGAIN))?;
    _ROOT_MNT_ID.set(id_root).or(Err(Errno::EAGAIN))?;

    let fd_dev = nix::fcntl::openat(
        Some(fd_root),
        XPath::from_bytes(b"dev"),
        OFlag::O_DIRECTORY,
        Mode::empty(),
    )?;
    let id_dev = fstatx(&fd_dev, mask).map(|stx| stx.stx_mnt_id)?;

    // SAFETY: To make this file descriptor harder to spot by an
    // attacker we duplicate it to a random fd number.
    let fd_rand = duprand(fd_dev)?;
    let _ = close(fd_dev);
    let fd_dev = fd_rand;

    info!("ctx": "run", "op": "opendir_dev",
        "msg": "opened /dev directory",
        "fd": fd_dev,
        "id": id_dev);
    _DEV_FD.set(fd_dev).or(Err(Errno::EAGAIN))?;
    _DEV_MNT_ID.set(id_dev).or(Err(Errno::EAGAIN))?;

    let fd_proc = nix::fcntl::openat(
        Some(fd_root),
        XPath::from_bytes(b"proc"),
        OFlag::O_DIRECTORY,
        Mode::empty(),
    )?;
    let id_proc = fstatx(&fd_proc, mask).map(|stx| stx.stx_mnt_id)?;

    // SAFETY: To make this file descriptor harder to spot by an
    // attacker we duplicate it to a random fd number.
    let fd_rand = duprand(fd_proc)?;
    let _ = close(fd_proc);
    let fd_proc = fd_rand;

    info!("ctx": "run", "op": "opendir_proc",
        "msg": "opened /proc directory",
        "fd": fd_proc,
        "id": id_proc);
    _PROC_FD.set(fd_proc).or(Err(Errno::EAGAIN))?;
    _PROC_MNT_ID.set(id_proc).or(Err(Errno::EAGAIN))?;

    let fd_sys = nix::fcntl::openat(
        Some(fd_root),
        XPath::from_bytes(b"sys"),
        OFlag::O_DIRECTORY,
        Mode::empty(),
    )?;
    let id_sys = fstatx(&fd_sys, mask).map(|stx| stx.stx_mnt_id)?;

    // SAFETY: To make this file descriptor harder to spot by an
    // attacker we duplicate it to a random fd number.
    let fd_rand = duprand(fd_sys)?;
    let _ = close(fd_sys);
    let fd_sys = fd_rand;

    info!("ctx": "run", "op": "opendir_sys",
        "msg": "opened /sys directory",
        "fd": fd_sys,
        "id": id_sys);
    _SYS_FD.set(fd_sys).or(Err(Errno::EAGAIN))?;
    _SYS_MNT_ID.set(id_sys).or(Err(Errno::EAGAIN))?;

    let fd_null = nix::fcntl::openat(
        Some(fd_dev),
        XPath::from_bytes(b"null"),
        OFlag::empty(),
        Mode::empty(),
    )?;
    let id_null = fstatx(&fd_null, mask).map(|stx| stx.stx_mnt_id)?;

    // SAFETY: Validate what we've opened is indeed `/dev/null`.
    crate::validate_dev_null(fd_null)?;

    // SAFETY: To make this file descriptor harder to spot by an
    // attacker we duplicate it to a random fd number.
    let fd_rand = duprand(fd_null)?;
    let _ = close(fd_null);
    let fd_null = fd_rand;

    info!("ctx": "run", "op": "opendev_null",
        "msg": "opened /dev/null",
        "fd": fd_null,
        "id": id_null);
    _NULL_FD.set(fd_null).or(Err(Errno::EAGAIN))?;
    _NULL_MNT_ID.set(id_null).or(Err(Errno::EAGAIN))?;

    Ok(())
}

/// Close static file descriptors for use by syd::proc and friends.
#[allow(static_mut_refs)]
pub fn proc_close() {
    if let Some(fd) = _ROOT_FD.get() {
        let _ = close(*fd);
    }

    if let Some(fd) = _DEV_FD.get() {
        let _ = close(*fd);
    }

    if let Some(fd) = _PROC_FD.get() {
        let _ = close(*fd);
    }

    if let Some(fd) = _SYS_FD.get() {
        let _ = close(*fd);
    }

    if let Some(fd) = _NULL_FD.get() {
        let _ = close(*fd);
    }
}

/// Reference to the global PidFd map.
pub static PIDFD_MAP: OnceLock<PidFdMap> = OnceLock::new();
