.\" Generated by scdoc 1.11.5 .\" Complete documentation for this program is not available as a GNU info page .ie \n(.g .ds Aq \(aq .el .ds Aq ' .nh .ad l .\" Begin generated content: .TH "SYDTUTORIAL" "7" "2026\-09\-01" .PP .SH NAME .PP \fBsydtutorial\fR \- A tutorial introduction to Syd .PP .SH SYNOPSIS .PP \fBsyd\fR [\-acefhlmpqtxEPV] [\-\-] {command [arg.\&.\&.\&]} .PP .SH DESCRIPTION .PP Syd intercepts system calls made by Linux processes and decides, according to a set of rules, whether each call should proceed, be denied, or be emulated.\& It does this without kernel modules, without setuid binaries, and without eBPF, using only \fIseccomp\fR(2) user notification, \fIptrace\fR(2), \fIlandlock\fR(7), and \fInamespaces\fR(7).\& .PP Run Syd with no arguments and it drops you into a login shell.\& Run it with a command and it sandboxes that command: .PP .nf .RS 4 $ syd \-poff \-\- echo hello hello .fi .RE .PP The \fI\-poff\fR selects the "off" profile, which disables all sandboxing.\& Without \fI\-poff\fR, Syd denies everything by default including exec: .PP .nf .RS 4 $ syd \-\- true syd: exec error: Permission denied $ echo $? 13 .fi .RE .PP Exit code 13 is \fBEACCES\fR ("Permission denied").\& This is what "secure by default" looks like in practice: you must opt in to every operation the sandboxed process is allowed to perform.\& .PP This tutorial walks through Syd'\&s sandbox rules, starting from the simplest case ("allow everything and run") through incrementally tighter configurations.\& It is written for someone who has used the Linux command line and has heard of system calls, but has never touched \fIseccomp\fR(2), \fIlandlock\fR(7), or any sandboxing tool.\& .PP The examples are tested against Syd 3.\&51.\&0 on Linux 6.\&19.\& You can type them verbatim on your own system.\& .PP .SH GETTING STARTED .PP .SS Prerequisites .PP Syd requires a Linux kernel with \fIseccomp\fR(2) user notification support.\& The following kernel features are required, listed with the minimum kernel version that introduced each one: .PP .PD 0 .IP \(bu 4 Linux 5.\&0: \fBSECCOMP_RET_USER_NOTIF\fR, allowing a supervisor process to intercept system calls and respond on behalf of the caller.\& .IP \(bu 4 Linux 5.\&5: \fBSECCOMP_USER_NOTIF_FLAG_CONTINUE\fR, needed to let intercepted system calls proceed unmodified after inspection.\& .IP \(bu 4 Linux 5.\&6: \fIpidfd_getfd\fR(2) and \fIpidfd_send_signal\fR(2), needed for file descriptor operations and signal delivery via process file descriptors.\& \fIopenat2\fR(2) is also required for safe path resolution with \fBRESOLVE_BENEATH\fR, \fBRESOLVE_NO_SYMLINKS\fR, and \fBRESOLVE_NO_MAGICLINKS\fR.\& .IP \(bu 4 Linux 5.\&9: \fBSECCOMP_IOCTL_NOTIF_ADDFD\fR, needed to inject file descriptors into the address space of a sandboxed process during system call emulation.\& .IP \(bu 4 Linux 5.\&19: \fBSECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV\fR, which places the intercepted thread in a killable wait state during notification handling; this eliminates a class of unkillable\-process bugs and is required for production use.\& .PD .PP The following kernel configuration options must be enabled: .PP .PD 0 .IP \(bu 4 \fBCONFIG_SECCOMP\fR and \fBCONFIG_SECCOMP_FILTER\fR are required for system call interception via \fIseccomp\fR(2).\& .IP \(bu 4 \fBCONFIG_SECURITY_LANDLOCK\fR is required for \fIlandlock\fR(7) filesystem and network access control.\& This option must be set to \fIy\fR at kernel build time, and \fIlandlock\fR must appear in the boot\-time \fBCONFIG_LSM\fR list (or be appended via the \fIlsm=\fR kernel command line parameter).\& Most major distributions enable \fIlandlock\fR(7) by default, including Ubuntu (since 20.\&04), Fedora (since 35), Arch Linux, and Debian Sid.\& .IP \(bu 4 \fBCONFIG_UNIX_DIAG\fR is required for UNIX domain socket diagnostics, which Syd uses to identify peer processes on UNIX sockets.\& .IP \(bu 4 \fBCONFIG_CROSS_MEMORY_ATTACH\fR is recommended; enables \fIprocess_vm_readv\fR(2) and \fIprocess_vm_writev\fR(2) for reading and writing process memory.\& Unlike \fIproc_pid_mem\fR(5), cross memory attach honours the address space permissions of the target process, providing a safer mechanism for inspecting system call arguments.\& If \fBCONFIG_CROSS_MEMORY_ATTACH\fR is not available, Syd falls back to \fIproc_pid_mem\fR(5) automatically when the \fBSYD_PROC_PID_MEM_FALLBACK\fR environment variable is set, refer to \fIsyd\fR(1) manual page for details.\& .IP \(bu 4 \fBCONFIG_KCMP\fR is recommended; enables \fIkcmp\fR(2), which Syd uses to determine whether two file descriptors refer to the same open file description across processes and to check whether two processes share the same address space.\& .PD .PP Syd is written in Rust.\& Building from source requires a Rust toolchain (edition 2024, Rust 1.\&83 or later) and \fIlibseccomp\fR headers.\& .PP .SS Installation .PP The quickest path to a working Syd installation is Cargo, the Rust package manager: .PP .nf .RS 4 $ cargo install \-\-locked syd .fi .RE .PP For OCI container runtime support (currently available on x86_64 and aarch64), enable the \fIoci\fR feature: .PP .nf .RS 4 $ cargo install \-\-locked \-\-features oci syd .fi .RE .PP If you are working from a git checkout, run: .PP .nf .RS 4 $ make install .fi .RE .PP This compiles an optimized release build of Syd and all companion utilities and installs them, along with man pages and Vim syntax files, under \fI\(ti/.\&local\fR.\& The resulting binaries are statically linked by default and can be copied to other systems without additional dependencies.\& Ensure that \fI\(ti/.\&local/bin\fR is in your \fBPATH\fR.\& .PP To build with OCI support from a git checkout: .PP .nf .RS 4 $ make CARGOFEATS=oci install .fi .RE .PP .SS Kernel support .PP After installation, run \fIsyd \-\-check\fR to print a diagnostic summary of your system'\&s sandboxing capabilities: .PP .nf .RS 4 $ syd \-\-check syd 3\&.51\&.0 (Crazy Goldberg) Rock solid application kernel \&.\&.\&. LibSeccomp: v2\&.9\&.9 api:7 Landlock ABI 7 is fully enforced\&. User namespaces are supported\&. Cross memory attach is supported\&. Memory sealing is supported\&. \&.\&.\&. LSMs: capability, landlock, lockdown, yama, bpf\&. .fi .RE .PP This output lists the \fIseccomp\fR(2) API level, the \fIlandlock\fR(7) ABI version, \fInamespaces\fR(7) support, which Linux Security Modules (LSMs) are active, open file descriptor limits, and the kernel version together with its supported features.\& If Syd depends on a kernel capability that is absent, this command will tell you.\& .PP To query the \fIlandlock\fR(7) ABI version in isolation: .PP .nf .RS 4 $ syd\-lock \-V .fi .RE .PP .SS Login shell .PP When invoked with no positional arguments, Syd enters login shell mode.\& It loads the builtin \fIuser\fR profile and spawns a restricted \fIbash\fR(1) session: .PP .nf .RS 4 $ syd bash\-5\&.3$ .fi .RE .PP The shell Syd starts is not an ordinary bash session.\& As defined in \fIsrc/config.\&rs\fR, the default command is: .PP .RS 4 /usr/bin/env HISTFILE= /usr/bin/bash \-\-login \-\-noprofile \-\-norc \-\-restricted .PP .RE Several properties of this invocation are worth noting.\& First, \fBHISTFILE\fR is set to the empty string, which disables command history.\& No record of the session is written to disk.\& Second, the \fI\-\-noprofile\fR and \fI\-\-norc\fR flags suppress \fI\(ti/.\&bash_profile\fR, \fI\(ti/.\&bashrc\fR, and \fI/etc/profile\fR, preventing user and system startup scripts from modifying the sandbox environment.\& Third, the \fI\-\-restricted\fR flag activates restricted shell mode (\fIrbash\fR), which among other things prohibits changing directories with \fIcd\fR, redirecting output, and modifying \fBPATH\fR.\& Together, these flags produce a minimal, hardened shell with minimal capabilities.\& .PP The login shell applies the \fIuser\fR profile, which enables sandbox rules for common interactive use.\& Try a few commands to see what the profile permits: .PP .nf .RS 4 bash\-5\&.3$ pwd /proc/42/fdinfo bash\-5\&.3$ ls \-la ls: cannot open directory \&'\&.\&': No such file or directory bash\-5\&.3$ echo hello hello bash\-5\&.3$ ls / ls: cannot open directory \&'/\&': Permission denied bash\-5\&.3$ cat /etc/hostname cat: /etc/hostname: No such file or directory bash\-5\&.3$ exit logout .fi .RE .PP Several things happened here.\& First, \fIpwd\fR reports a path under \fIproc_pid_fdinfo\fR(5).\& This is Syd'\&s own \fIproc\fR(5) directory, the sandbox manager'\&s process ID.\& Syd restricts access to its own \fIproc\fR(5) entries to prevent sandboxed processes from inspecting or interfering with the sandbox itself (refer to the \fBSECURITY\fR section of \fIsyd\fR(7)).\& Consequently, \fIls \-la\fR cannot open the directory: it returns \fBENOENT\fR ("No such file or directory") because the path is hidden by \fIproc\fR(5) restrictions.\& The shell effectively starts in a location that exists in the kernel'\&s VFS but is invisible to the sandboxed process.\& .PP The \fIecho\fR builtin works because builtins do not invoke \fIexecve\fR(2); they run inside the shell process itself.\& The \fIls /\fR command is an external binary whose execution the \fIuser\fR profile permits, but reading the root directory is denied by the profile'\&s read sandbox rules.\& The \fIcat /etc/hostname\fR result is more subtle: it reports \fBENOENT\fR ("No such file or directory") rather than \fBEACCES\fR ("Permission denied").\& This happens because Syd'\&s Stat Sandboxing hides the file entirely, \fIstat\fR(2) returns \fBENOENT\fR ("No such file or directory") and \fIgetdents64\fR(2) omits the entry from directory listings, so from the process'\&s perspective the file does not exist.\& .PP The \fBSYD_SHELL\fR environment variable overrides the default shell command: .PP .nf .RS 4 $ SYD_SHELL=/bin/sh syd $ .fi .RE .PP .SS Single command .PP Syd'\&s command line parsing follows POSIX conventions (options first, then positional arguments), so the \fI\-\-\fR separator is not required.\& You can sandbox a single command by providing it directly: .PP .nf .RS 4 $ syd true syd: exec error: Permission denied $ echo $? 13 .fi .RE .PP Without a profile, Syd denies \fIexecve\fR(2) and returns exit code 13 aka \fBEACCES\fR ("Permission denied").\& The \fIsyd\-sys\fR(1) utility can translate between numbers and names for system calls, \fIerrno\fR(3) values, \fIioctl\fR(2) requests, \fIopen\fR(2) flags, and \fIsignal\fR(7) numbers.\& It can also list UNIX domain socket inodes via \fInetlink\fR(7).\& For example: .PP .nf .RS 4 $ syd\-sys \-e 13 13 EACCES Permission denied $ syd\-sys 1 write 1 .fi .RE .PP This is the default: every operation is forbidden unless a rule explicitly permits it.\& To run a command that actually executes, select a profile: .PP .nf .RS 4 $ syd \-poff echo hello hello .fi .RE .PP The \fI\-poff\fR flag loads the \fIoff\fR profile, which disables all sandbox categories.\& This is useful for verifying that Syd itself is working before adding restrictions.\& .PP .SS Profiles .PP Profiles are pre\-defined sets of sandbox rules compiled into the Syd binary.\& Each profile configures which sandboxing categories are active and which paths, addresses, and system calls are allowed or denied.\& The \fBPROFILES\fR section of \fIsyd\fR(5) manual page documents the full set of available profiles and their intended use.\& .PP To list the available profiles: .PP .nf .RS 4 $ syd\-cat \-p list chrome container core cwd debug enforce firefox fs gui hide immutable landlock lang ldd lib linux ltp nix nixstore \&.\&.\&. .fi .RE .PP Some profiles serve as building blocks for others.\& For example, the \fIlinux\fR profile provides a common set of rules for Linux systems and is included by the \fIuser\fR, \fIpaludis\fR, and \fIoci\fR profiles.\& .PP The \fIuser\fR profile is the default for the login shell and is suitable for general interactive use.\& The \fIimmutable\fR profile treats the entire root filesystem as read\-only, permitting writes only to explicitly allowed locations.\& The \fIoff\fR profile disables all sandboxing.\& .PP To examine the rules that a profile contains: .PP .nf .RS 4 $ syd\-cat \-p user .fi .RE .PP Multiple profiles can be combined on the command line; later profiles override rules from earlier ones: .PP .nf .RS 4 $ syd \-pimmutable \-mallow/write+/var/cache/*** make install .fi .RE .PP .SS \-m Flag .PP The \fI\-m\fR flag passes individual sandbox commands on the command line.\& Each \fI\-m\fR takes one command as documented in \fIsyd\fR(2).\& All \fI\-p\fR, \fI\-P\fR, and \fI\-m\fR flags are processed in the order they are given on the command line.\& Because Syd uses a "last match wins" rule resolution strategy (documented in \fIsyd\fR(2)), later flags override earlier ones for the same sandbox category regardless of type.\& .PP A basic example enables Write Sandboxing atop the \fIoff\fR profile: .PP .nf .RS 4 $ syd \-poff \-msandbox/write:on \-mallow/write+/tmp/*** touch /tmp/hello $ echo $? 0 .fi .RE .PP Here \fI\-poff\fR disables all sandboxing, \fI\-msandbox/write:on\fR re\-enables Write Sandboxing, and \fI\-mallow/write+/tmp/***\fR adds \fI/tmp\fR and everything below it to the write allowlist.\& Because \fI/tmp/hello\fR matches the allow rule, \fItouch\fR(1) succeeds.\& .PP Multiple \fI\-m\fR flags for the same category layer in order.\& You can first allow a broad directory tree and then deny a subtree within it: .PP .nf .RS 4 $ mkdir \-p /tmp/secret $ syd \-poff \-msandbox/write:on \-mallow/write+/tmp/*** \-mdeny/write+/tmp/secret/*** touch /tmp/secret/plans {"ctx":"access","cap":"write","act":"deny","sys":"openat", "path":"/tmp/secret/plans", "tip":"configure `allow/write+/tmp/secret/plans\&'"} touch: cannot touch \&'/tmp/secret/plans\&': Permission denied $ echo $? 1 .fi .RE .PP Syd logs the denied access as a JSON object on standard error, including the system call that was denied (\fIopenat\fR), the path, and a \fItip\fR field suggesting how to allow it.\& The deny rule for \fI/tmp/secret\fR comes after the allow rule for \fI/tmp\fR, so the deny wins.\& Reversing the order would produce the opposite result, the allow would override the deny.\& .PP The \fI\-m\fR rules layer atop the selected profile.\& Without \fI\-poff\fR or another profile that allows execution, the default sandbox denies \fIexecve\fR(2) before any write rule has a chance to take effect: .PP .nf .RS 4 $ syd \-msandbox/write:on touch /tmp/hello syd: exec error: Permission denied .fi .RE .PP This is a common mistake when first using Syd.\& Always start from a profile that permits execution, then layer restrictions with \fI\-m\fR.\& The \fIoff\fR profile followed by selective sandbox enables is one approach; the \fIuser\fR profile with additional deny rules is another.\& .PP .SH CONFIGURATION .PP The previous section introduced profiles through the \fI\-p\fR flag and individual commands through \fI\-m\fR.\& This section covers the full configuration machinery: what profiles contain, how configuration files work, how rules are resolved, and how patterns match paths.\& .PP .SS Profile anatomy .PP A profile is a named set of sandbox commands compiled into the Syd binary.\& To inspect its contents, pass its name to \fIsyd\-cat\fR(1): .PP .nf .RS 4 $ syd\-cat \-poff # Syd profile: Off # Number of rules: 2 # Copyright (c) 2023, 2024 Ali Polatel # SPDX\-License\-Identifier: GPL\-3\&.0 sandbox/all:off sandbox/fs,ioctl,lock,net,mem,pid,pty,force,tpe:off .fi .RE .PP The \fIoff\fR profile consists of exactly two commands: one that turns off all primary sandbox categories, and one that turns off every secondary category.\& Compare this with the \fIuser\fR profile: .PP .nf .RS 4 $ syd\-cat \-puser # Syd profile: User "user" # Number of rules: 17 include_profile linux include_profile landlock include_profile local include_profile nomagic include_profile noscm include_profile rand include_profile tty sandbox/lpath:${SYD_USER_LPATH:\-on} trace/allow_safe_syslog:true tpe/negate:1 tpe/user_owned:1 tpe/gid:${SYD_GID} trace/force_umask:7177 allow/lock/all+${SYD_HOME} allow/all+${SYD_HOME}/** allow/lpath,rpath+${SYD_HOME}/*** deny/all+${SYD_HOME}/**/\&.*/*** allow/all+${SYD_HOME}/**/\&._history_ .fi .RE .PP Several features are visible here.\& The \fIinclude_profile\fR directive includes other profiles by name: \fIlinux\fR, \fIlandlock\fR, \fIlocal\fR, \fInomagic\fR, \fInoscm\fR, \fIrand\fR, and \fItty\fR are all pulled in, making the \fIuser\fR profile a composition of lower\-level building blocks.\& Environment variables such as \fB${SYD_HOME}\fR and \fB${SYD_GID}\fR are expanded at parse time; Syd sets these automatically before loading the profile.\& Refer to the \fBENVIRONMENT\fR section of \fIsyd\fR(5) manual page.\& The notation \fB${SYD_USER_LPATH:\-on}\fR provides a default value: if the variable is unset, the value \fIon\fR is used.\& .PP .SS Profile Stacking .PP Multiple \fI\-p\fR flags can appear on the command line.\& Profiles are loaded in order, and because Syd uses a last\-match\-wins strategy, later profiles override rules from earlier ones.\& This allows incremental refinement: .PP .nf .RS 4 $ syd \-puser \-pimmutable ls / ls: cannot open directory \&'/\&': Permission denied $ echo $? 2 .fi .RE .PP The \fIuser\fR profile permits reading most of the filesystem, but the \fIimmutable\fR profile, loaded second, remounts system directories read\-only inside a \fImount_namespaces\fR(7) and applies stricter access rules that override the \fIuser\fR defaults.\& .PP Some profiles have one\-character shortcuts.\& These shortcuts can be combined into a single \fI\-p\fR argument: .PP .nf .RS 4 $ syd \-puiq \&.\&.\&. .fi .RE .PP This stacks the \fIuser\fR (u), \fIimmutable\fR (i), and \fIquiet\fR (q) profiles.\& The full list of profiles and their shortcuts is documented in the \fBPROFILES\fR section of \fIsyd\fR(5), and can always be queried with \fIsyd\-cat \-plist\fR.\& .PP .SS Configuration Files .PP Configuration files provide the same commands as \fI\-m\fR flags, one per line.\& Comments begin with \fI#\fR; blank lines are ignored.\& The file extension must be \fI.\&syd\-3\fR, reflecting the current API version.\& .PP A minimal configuration file that confines writes to \fI/tmp\fR: .PP .nf .RS 4 # /tmp/example\&.syd\-3: Allow writes under /tmp only sandbox/write:on allow/write+/tmp/*** .fi .RE .PP Load it with the \fI\-P\fR flag: .PP .nf .RS 4 $ syd \-poff \-P/tmp/example\&.syd\-3 touch /tmp/syd_test_file $ echo $? 0 .fi .RE .PP Multiple \fI\-P\fR flags can be specified.\& All \fI\-p\fR, \fI\-P\fR, and \fI\-m\fR arguments are processed strictly in the order they appear on the command line\-\-there is no precedence between them.\& A \fI\-m\fR that appears before a \fI\-P\fR takes effect first.\& .PP The \fIsyd\-cat\fR(1) utility can parse and validate configuration files independently of Syd itself.\& Pass one or more file paths and it will report syntax errors or print the resolved sandbox state: .PP .nf .RS 4 $ syd\-cat /tmp/example\&.syd\-3 Syd: Sandbox ID: ? \&.\&.\&. Glob Rules: (1\&.66K, total 1, highest precedence first) 1\&. Action: allow, Capability: write, Pattern: `/tmp\&' \&.\&.\&. .fi .RE .PP If the file contains errors, \fIsyd\-cat\fR(1) exits with a non\-zero status and an error message, making it useful for testing configuration before deploying it.\& .PP Configuration files support two inclusion directives: .PP .PD 0 .IP \(bu 4 \fIinclude\fR \fIpath\fR includes another configuration file.\& Relative paths are resolved from the directory of the including file, not the current working directory.\& The included file must not be writable by group or others for security.\& Circular includes are detected by caching device and inode numbers.\& .IP \(bu 4 \fIinclude_profile\fR \fIname\fR includes a built\-in profile by name, exactly as if \fI\-p\fR had been specified.\& .PD .PP Environment variables are expanded in all arguments using \fIshellexpand\fR syntax.\& If a variable is unset, Syd aborts with an error rather than expanding to the empty string.\& This prevents accidental over\-permissive rules.\& Use \fB${VAR:\-default}\fR to supply fallback values.\& .PP .SS Pattern Matching .PP Path rules use \fIglob\fR(3p) patterns.\& The standard wildcards apply: \fB*\fR matches any sequence of characters within a single path component, \fB?\&\fR matches a single character, and \fB[.\&.\&.\&]\fR matches a character class.\& .PP Syd extends standard globbing with the triple\-star pattern \fB***\fR, which matches the prefix directory itself and everything below it to arbitrary depth.\& A pattern like \fI/tmp/***\fR first matches the directory \fI/tmp\fR on its own, then matches any path beneath it.\& The three wildcard levels are: .PP .PD 0 .IP \(bu 4 \fI/tmp/*\fR matches \fI/tmp/foo\fR but not \fI/tmp/foo/bar\fR.\& .IP \(bu 4 \fI/tmp/**\fR matches files in immediate subdirectories of \fI/tmp\fR.\& .IP \(bu 4 \fI/tmp/***\fR matches \fI/tmp\fR itself, \fI/tmp/foo\fR, \fI/tmp/foo/bar\fR, and so on to arbitrary depth.\& .PD .PP .SS Rule Ordering .PP Syd evaluates rules in the order they appear.\& For multiple rules that match the same path, the last matching rule determines the outcome.\& All \fI\-p\fR, \fI\-P\fR, and \fI\-m\fR arguments are processed strictly in command\-line order; there is no precedence between them.\& .PP This means you can start with a broad allow and carve out exceptions with later deny rules, or start restrictive and add targeted allows.\& .PP .SS Runtime Configuration .PP In addition to startup\-time configuration, Syd supports runtime reconfiguration through magic \fIstat\fR(2) calls.\& A sandboxed process can issue: .PP .nf .RS 4 test \-c /dev/syd/sandbox/read:on .fi .RE .PP This \fIstat\fR(2) call on the virtual path \fI/dev/syd/sandbox/read:on\fR enables read sandboxing at runtime.\& The \fIstat\fR(2) interface accepts the same commands as \fI\-m\fR and is documented in \fIsyd\fR(2).\& Runtime configuration is permitted when the sandbox lock is \fIoff\fR, \fIexec\fR, \fIipc\fR, or \fIdrop\fR.\& With \fIlock:off\fR, any process in the sandbox can issue runtime commands.\& With \fIlock:exec\fR, only the initial exec child retains this ability.\& With \fIlock:ipc\fR, commands must be sent through the IPC socket.\& With \fIlock:drop\fR, commands can only reduce privileges, commands relaxing the sandbox policy aren'\&t permitted.\& This mode is similar to OpenBSD \fIpledge\fR(2).\& When the lock is \fIon\fR or \fIread\fR, runtime changes are not accepted.\& .PP .SS User Profile and Configuration Files .PP The \fIuser\fR profile, loaded by default in login shell mode, searches for two additional configuration files at startup: .PP .PD 0 .IP \(bu 4 \fI/etc/user.\&syd\-3\fR \-\- system\-wide rules applied to all users.\& .IP \(bu 4 \fI\(ti/.\&user.\&syd\-3\fR \-\- per\-user rules.\& .PD .PP These files are parsed after the \fIuser\fR profile itself.\& Because last\-match\-wins semantics apply, rules in \fI\(ti/.\&user.\&syd\-3\fR override rules in \fI/etc/user.\&syd\-3\fR, which in turn override the built\-in \fIuser\fR profile defaults.\& .PP To lock the system\-wide configuration so that per\-user files cannot weaken it, place \fIlock:on\fR or \fIlock:drop\fR at the end of \fI/etc/user.\&syd\-3\fR.\& After the lock is set, no further configuration changes are accepted, neither from subsequent files nor from runtime \fIstat\fR(2) calls.\& .PP .SH SANDBOX LOCK .PP The sandbox lock controls whether and how sandbox rules can be modified after Syd starts executing the sandboxed process.\& It is set with the \fIlock\fR command (documented in \fIsyd\fR(2)) and has six possible states: \fIon\fR, \fIoff\fR, \fIexec\fR, \fIipc\fR, \fIdrop\fR, and \fIread\fR.\& Single\-character abbreviations are also accepted: \fI1\fR, \fI0\fR, \fIx\fR, \fIi\fR, \fId\fR, and \fIr\fR.\& Specifying \fIlock\fR without a value is equivalent to \fIlock:on\fR.\& .PP .SS Lock States .PP \fIlock:on\fR seals the sandbox policy entirely.\& No runtime configuration is accepted from any source: .PP .nf .RS 4 $ syd \-poff \-mlock:on sh \-c \&'test \-c /dev/syd/sandbox/write:on && echo "enabled" || echo "locked out"\&' locked out .fi .RE .PP \fIlock:off\fR leaves the sandbox fully open to runtime changes.\& Any process in the sandbox can issue \fIstat\fR(2) commands on \fI/dev/syd/\fR paths to modify the policy.\& .PP \fIlock:exec\fR sets the lock to \fIon\fR for all processes except the initial exec child.\& This allows the initial process to configure the sandbox at startup and then seal it: .PP .nf .RS 4 $ syd \-poff \-mlock:exec sh \-c \&'test \-c /dev/syd/sandbox/write:on && echo "write on"; test \-c /dev/syd/lock:on && echo "locked"; test \-c /dev/syd/sandbox/read:on && echo "read on" || echo "config rejected after lock"\&' write on locked config rejected after lock .fi .RE .PP The initial shell enables write sandboxing at runtime, then transitions to \fIlock:on\fR.\& After that, the attempt to enable read sandboxing is rejected.\& .PP \fIlock:ipc\fR restricts runtime commands to the IPC socket.\& The IPC socket is a UNIX domain socket whose accessibility depends on the sandbox ACL rules.\& Processes that cannot reach the socket cannot modify the policy.\& .PP \fIlock:drop\fR permits commands that further restrict the sandbox but rejects commands that would loosen it.\& This is useful for processes that need to progressively tighten their own confinement: .PP .nf .RS 4 $ syd \-poff \-mlock:drop sh \-c \&'test \-c /dev/syd/sandbox/write:on && echo "write on"\&' write on .fi .RE .PP Enabling a sandbox category counts as dropping privileges, so the command is accepted.\& .PP \fIlock:read\fR makes the \fIsyd\fR(2) virtual system call API available in read\-only mode.\& The sandboxed process can query the current policy state through the \fIopen\fR(2) hooks but cannot modify it.\& .PP .SS Default Lock State .PP If no \fIlock\fR command appears in any profile, configuration file, or \fI\-m\fR argument, Syd defaults to \fIlock:on\fR at the moment it executes the initial sandbox process.\& This ensures that the sandbox policy is sealed by default.\& .PP .SS Lock Transitions and Sealing .PP Transitions from \fIlock:off\fR, \fIlock:exec\fR, \fIlock:ipc\fR, and \fIlock:drop\fR into \fIlock:on\fR or \fIlock:read\fR are one\-way.\& Once the lock reaches \fIon\fR or \fIread\fR, the sandbox policy is sealed in memory using \fImseal\fR(2) and cannot be changed.\& Transitions between \fIlock:on\fR and \fIlock:read\fR are not permitted.\& .PP .SH PATH SANDBOXING .PP Syd intercepts system calls that operate on filesystem paths and checks them against per\-category allow and deny lists.\& Each sandbox category corresponds to a class of file operations and can be enabled or disabled independently.\& .PP .SS Sandbox Categories .PP The primary path sandbox categories are: .PP .PD 0 .IP \(bu 4 \fIread\fR \-\- \fIopen\fR(2) with \fBO_RDONLY\fR or \fBO_RDWR\fR, \fIgetxattr\fR(2) and related extended attribute reads.\& .IP \(bu 4 \fIwrite\fR \-\- \fIopen\fR(2) with \fBO_WRONLY\fR or \fBO_RDWR\fR.\& .IP \(bu 4 \fIexec\fR \-\- \fIexecve\fR(2), \fIexecveat\fR(2), \fImmap\fR(2) with \fBPROT_EXEC\fR, and dynamic library loading.\& .IP \(bu 4 \fIstat\fR \-\- \fIstat\fR(2), \fIstatx\fR(2), \fIaccess\fR(2), \fIreadlink\fR(2), \fIgetdents64\fR(2), and related metadata calls.\& .IP \(bu 4 \fIwalk\fR \-\- Path traversal during canonicalization, split from \fIstat\fR to prevent unhiding of hidden paths.\& .PD .PP Syd also provides fine\-grained categories for specific operations: .PP .PD 0 .IP \(bu 4 \fIcreate\fR \-\- \fIcreat\fR(2), \fIopen\fR(2) with \fBO_CREAT\fR, \fImemfd_create\fR(2).\& .IP \(bu 4 \fIdelete\fR \-\- \fIunlink\fR(2), \fIunlinkat\fR(2) without \fBAT_REMOVEDIR\fR.\& .IP \(bu 4 \fIrename\fR \-\- \fIrename\fR(2), \fIrenameat\fR(2), \fIlink\fR(2), \fIlinkat\fR(2).\& .IP \(bu 4 \fIsymlink\fR \-\- \fIsymlink\fR(2), \fIsymlinkat\fR(2).\& .IP \(bu 4 \fItruncate\fR \-\- \fItruncate\fR(2), \fIfallocate\fR(2), \fIopen\fR(2) with \fBO_TRUNC\fR.\& .IP \(bu 4 \fIchdir\fR \-\- \fIchdir\fR(2), \fIfchdir\fR(2).\& .IP \(bu 4 \fIreaddir\fR \-\- \fIopen\fR(2) on existing directories.\& .IP \(bu 4 \fImkdir\fR \-\- \fImkdir\fR(2), \fImkdirat\fR(2).\& .IP \(bu 4 \fIrmdir\fR \-\- \fIrmdir\fR(2), \fIunlinkat\fR(2) with \fBAT_REMOVEDIR\fR.\& .IP \(bu 4 \fIchown\fR, \fIchgrp\fR \-\- \fIchown\fR(2), \fIfchownat\fR(2) and variants.\& .IP \(bu 4 \fIchmod\fR \-\- \fIchmod\fR(2), \fIfchmodat\fR(2), \fIfchmodat2\fR(2).\& .IP \(bu 4 \fIchattr\fR \-\- \fIsetxattr\fR(2), \fIremovexattr\fR(2) and variants.\& .IP \(bu 4 \fIchroot\fR \-\- \fIchroot\fR(2).\& .IP \(bu 4 \fInotify\fR \-\- \fIfanotify_mark\fR(2), \fIinotify_add_watch\fR(2).\& .IP \(bu 4 \fIutime\fR \-\- \fIutimensat\fR(2), \fIutimes\fR(2).\& .IP \(bu 4 \fImkdev\fR \-\- \fImknod\fR(2) for block devices.\& .IP \(bu 4 \fImkfifo\fR \-\- \fImknod\fR(2) for FIFOs.\& .IP \(bu 4 \fImktemp\fR \-\- \fIopen\fR(2) with \fBO_TMPFILE\fR.\& .PD .PP Refer to \fIsyd\fR(7) manual page for the complete list of system calls filtered by each category.\& .PP .SS Sandbox Category Sets .PP Working with individual categories can be verbose.\& Syd provides shorthand names inspired by the promise names of OpenBSD'\&s \fIpledge\fR(2) and FreeBSD'\&s capsicum \fIrights\fR(4freebsd).\& These names group related categories into sets that can be used anywhere a category name is accepted: .PP .PD 0 .IP \(bu 4 \fIrpath\fR \-\- read, readdir.\& Named after the \fIpledge\fR(2) \fIrpath\fR promise.\& In \fIpledge\fR(2), \fIrpath\fR also covers \fIstat\fR(2), \fIaccess\fR(2), \fIreadlinkat\fR(2), and \fIchdir\fR(2); Syd separates those into the \fIlpath\fR set.\& .IP \(bu 4 \fIwpath\fR \-\- write, truncate.\& Named after the \fIpledge\fR(2) \fIwpath\fR promise.\& .IP \(bu 4 \fIcpath\fR \-\- create, delete, rename.\& Named after the \fIpledge\fR(2) \fIcpath\fR promise, which also covers \fImkdir\fR(2) and \fIrmdir\fR(2); Syd separates those into the \fItpath\fR set.\& .IP \(bu 4 \fIfattr\fR \-\- chmod, chattr, utime.\& Named after the \fIpledge\fR(2) \fIfattr\fR promise.\& In \fIpledge\fR(2), \fIfattr\fR also covers \fIchown\fR(2) and \fIfchown\fR(2); Syd separates ownership changes into the \fIfown\fR set.\& .IP \(bu 4 \fIfown\fR \-\- chown, chgrp.\& A Syd\-specific set that splits ownership changes out of the \fIpledge\fR(2) \fIfattr\fR promise.\& .IP \(bu 4 \fIdpath\fR \-\- mkbdev, mkcdev.\& Named after the \fIpledge\fR(2) \fIdpath\fR promise, which covers \fImknod\fR(2) and \fImkfifo\fR(2).\& Syd narrows this set to block and character device creation only; FIFOs are in the separate \fIspath\fR set.\& .IP \(bu 4 \fIspath\fR \-\- mkfifo, symlink.\& A Syd\-specific set; \fIpledge\fR(2) places \fImkfifo\fR(2) under \fIdpath\fR and \fIsymlink\fR(2) under \fIcpath\fR.\& .IP \(bu 4 \fItpath\fR \-\- mkdir, rmdir.\& A Syd\-specific set that splits directory creation and removal out of the \fIpledge\fR(2) \fIcpath\fR promise.\& .IP \(bu 4 \fIlpath\fR \-\- walk, stat, chdir, notify.\& A Syd\-specific set with no \fIpledge\fR(2) analogue.\& It corresponds to the path visibility controls of \fIunveil\fR(2) and groups the categories responsible for path lookup, metadata access, and directory change.\& .IP \(bu 4 \fInet\fR \-\- net/bind, net/connect.\& .IP \(bu 4 \fIinet\fR \-\- net/bind, net/connect.\& Named after the \fIpledge\fR(2) \fIinet\fR promise.\& .IP \(bu 4 \fIpassfd\fR \-\- sendfd, recvfd.\& .IP \(bu 4 \fIall\fR \-\- every category.\& .IP \(bu 4 \fIall\-x\fR \-\- every category except \fIexec\fR.\& .PD .PP Each set also has a \fIlock/\fR variant that controls the corresponding \fIlandlock\fR(7) access rights rather than the \fIseccomp\fR(2) sandbox rules.\& For instance, \fIlock/rpath\fR controls \fIlandlock\fR(7) read and readdir access rights, while \fIrpath\fR controls the \fIseccomp\fR(2) read and readdir sandbox categories.\& .PP These sets make rules more concise.\& Compare the two equivalent rules: .PP .nf .RS 4 deny/read,readdir,write,truncate,create,delete,rename+${HOME}/\&.ssh/*** deny/rpath,wpath,cpath+${HOME}/\&.ssh/*** .fi .RE .PP .SS Enabling Sandbox Categories .PP Categories are enabled with the \fIsandbox/\fR command and can be grouped with commas: .PP .nf .RS 4 sandbox/read,write,exec:on .fi .RE .PP The shorthand \fIsandbox/all:on\fR enables every primary category at once.\& Individual categories can then be turned off selectively.\& .PP .SS Allow and Deny Rules .PP Once a category is enabled, all operations in that category are denied by default.\& The default action can be changed per category with the \fIdefault/\fR command.\& The available actions are: .PP .PD 0 .IP \(bu 4 \fIallow\fR \-\- Permit the system call.\& .IP \(bu 4 \fIdeny\fR \-\- Deny the system call with \fIEACCES\fR (default).\& .IP \(bu 4 \fIfilter\fR \-\- Deny the system call silently, without logging.\& .IP \(bu 4 \fIwarn\fR \-\- Allow the system call but log a warning (learning mode, used by \fIpandora\fR(1)).\& .IP \(bu 4 \fIkill\fR \-\- Deny the system call and terminate the offending process with \fBSIGKILL\fR (see \fIsignal\fR(7)).\& .IP \(bu 4 \fIstop\fR \-\- Deny the system call and send \fBSIGSTOP\fR to the offending process (see \fIsignal\fR(7)).\& .IP \(bu 4 \fIabort\fR \-\- Deny the system call and send \fBSIGABRT\fR to the offending process (see \fIsignal\fR(7)).\& Unlike \fBSIGKILL\fR, \fBSIGABRT\fR can be caught, so this action should only be used for debugging in trusted environments where a \fIcore\fR(5) dump file is useful.\& .IP \(bu 4 \fIpanic\fR \-\- Deny the system call and panic the Syd emulator thread.\& Currently equivalent to \fIdeny\fR.\& .IP \(bu 4 \fIexit\fR \-\- Log a warning and exit Syd immediately with the deny \fIerrno\fR(3) as exit value.\& All sandbox processes are terminated: direct children receive \fBSIGKILL\fR via the parent death signal (see \fIPR_SET_PDEATHSIG\fR(2const)), traced processes are killed via \fBPTRACE_O_EXITKILL\fR (see \fIptrace\fR(2)), and closing the \fIseccomp\fR(2) notification file descriptor causes any pending system calls to fail.\& .PD .PP Refer to \fIsyd\fR(7) for the full description of sandbox actions and \fIsyd\fR(2) for the \fIdefault/\fR command documentation.\& .PP Allow rules open specific paths; deny rules close them.\& Both use \fIglob\fR(3p) patterns as described in the Pattern Matching section.\& .PP The following example enables write sandboxing, allows writes under \fI/tmp\fR, and then attempts to write outside the allowed area: .PP .nf .RS 4 $ syd \-poff \-msandbox/write:on \-mallow/write+/tmp/*** \-mallow/read+/*** touch /tmp/pathtest $ echo $? 0 $ syd \-poff \-msandbox/write:on \-mallow/read+/*** touch /home/alip/forbidden {"ctx":"access","cap":"write","act":"deny","sys":"openat","path":"/home/alip/forbidden","tip":"configure `allow/write+/home/alip/forbidden\&'"} touch: cannot touch \&'/home/alip/forbidden\&': Permission denied .fi .RE .PP The first \fItouch\fR(1) succeeds because \fI/tmp/pathtest\fR matches the allow rule.\& The second is denied because no allow rule covers \fI/home/alip/forbidden\fR.\& .PP .SS Path Hiding .PP The \fIstat\fR and \fIwalk\fR categories can hide files and directories from the sandboxed process entirely.\& When a \fIstat\fR(2) call is denied, Syd returns \fBENOENT\fR ("No such file or directory") to the caller, making the path appear non\-existent: .PP .nf .RS 4 $ syd \-poff \-msandbox/stat:on \-mallow/stat+/*** \-mdeny/stat+/etc/shadow ls \-la /etc/shadow ls: cannot access \&'/etc/shadow\&': No such file or directory .fi .RE .PP The process receives no indication that \fI/etc/shadow\fR exists.\& Programs that enumerate directory contents via \fIgetdents64\fR(2) also have the hidden entries filtered out.\& .PP The \fIwalk\fR category complements \fIstat\fR by preventing hidden paths from being discovered during path canonicalization.\& Without \fIwalk\fR, a process could detect a hidden path by traversing through it (e.\&g.\& resolving \fI/etc/shadow/.\&.\&/passwd\fR).\& Together, \fIstat\fR and \fIwalk\fR provide a complete path hiding mechanism analogous to \fIunveil\fR(2) on OpenBSD.\& .PP .SS Path Masking .PP Where hiding makes a path invisible, masking replaces its contents.\& The \fImask\fR command redirects \fIopen\fR(2) calls on matching paths to a different file\-\-by default \fI/dev/null\fR.\& At the \fIstat\fR(2) boundary, a masked path returns the metadata of the mask target, not the original file.\& .PP A masked \fI/etc/hostname\fR reads as empty: .PP .nf .RS 4 $ syd \-poff \-mmask+/etc/hostname \-mallow/read+/*** cat /etc/hostname $ echo $? 0 .fi .RE .PP The \fIcat\fR(1) call succeeds but produces no output because \fIopen\fR(2) returns a file descriptor to \fI/dev/null\fR.\& A \fIstat\fR(2) call on the same path returns the mask target'\&s metadata: .PP .nf .RS 4 $ syd \-poff \-msandbox/lpath:on \-mallow/lpath+/*** \-mmask+/etc/hostname \-mallow/read+/*** stat /etc/hostname File: /etc/hostname Size: 0 Blocks: 0 IO Block: 4096 character special file Device: 0,6 Inode: 4 Links: 1 Device type: 1,3 Access: (0666/crw\-rw\-rw\-) Uid: ( 0/ root) Gid: ( 0/ root) .fi .RE .PP The file name still reads \fI/etc/hostname\fR, but the metadata reports a character special file with device 1,3 which are the attributes of \fI/dev/null\fR.\& .PP The default mask target can be changed by appending a colon\-separated path.\& For example, masking with \fI/dev/zero\fR causes reads to return zero bytes: .PP .nf .RS 4 $ syd \-poff \-mmask+/etc/hostname:/dev/zero \-mallow/read+/*** sh \-c \&'head \-c 8 /etc/hostname | xxd\&' 00000000: 0000 0000 0000 0000 \&.\&.\&.\&.\&.\&.\&.\&. .fi .RE .PP For directories, a second colon\-separated path specifies the directory target: .PP .nf .RS 4 mask+/proc/acpi/***:/dev/null:/var/empty .fi .RE .PP This masks regular files under \fI/proc/acpi\fR with \fI/dev/null\fR and subdirectories with \fI/var/empty\fR.\& Mask targets must be fully canonicalized paths without symbolic links.\& .PP Masked paths are also protected against filesystem writes.\& The file cannot be truncated, overwritten, renamed, deleted, or have its metadata changed.\& .PP The \fImask\fR command does not require creating a \fImount_namespaces\fR(7), providing a non\-privileged alternative to bind mounts.\& Mask commands can also be specified dynamically after startup using the \fIsyd\fR(2) API, allowing for incremental confinement.\& .PP .SS Practical Example .PP The following configuration sandboxes a build tool.\& It allows reading and stat access everywhere, restricts writes to the build directory, terminates with \fBSIGKILL\fR any process that attempts to access \fI\(ti/.\&ssh\fR or \fI\(ti/.\&gnupg\fR, hides \fI/etc/shadow\fR from stat, masks \fI/etc/hostname\fR with \fI/dev/null\fR, and permits execution only from \fI/usr\fR: .PP .nf .RS 4 include_profile tty sandbox/read,write,exec,stat:on allow/read+/*** allow/stat+/*** allow/write+/home/alip/project/build/*** allow/exec+/usr/*** kill/rpath,wpath,cpath+${HOME}/\&.ssh/*** kill/rpath,wpath,cpath+${HOME}/\&.gnupg/*** kill/stat+/etc/shadow mask+/etc/hostname .fi .RE .PP Any attempt to write outside \fI/home/alip/project/build\fR, execute a binary from outside \fI/usr\fR, or access \fI\(ti/.\&ssh\fR is terminated with \fISIGKILL\fR.\& A \fIstat\fR(2) call on \fI/etc/shadow\fR returns \fBENOENT\fR ("No such file or directory"), and reading \fI/etc/hostname\fR yields empty output.\& .PP .SH LOCK SANDBOXING .PP Lock Sandboxing uses the Landlock Linux Security Module (\fIlandlock\fR(7)) for kernel\-enforced unprivileged access control.\& Unlike the \fIseccomp\fR(2) based sandbox, Landlock rules are enforced entirely in kernel space and apply to the Syd process itself.\& A compromised Syd process is still confined by the Landlock sandbox, making Lock sandboxing a second layer of defence.\& .PP .SS Lock Categories .PP Lock Sandboxing is enabled by default.\& The \fIoff\fR profile disables it with \fIsandbox/lock:off\fR.\& Paths and port ranges are populated using \fIlock/\fR categories: .PP .nf .RS 4 allow/lock/read+/usr allow/lock/read,write+/tmp allow/lock/exec+/usr/bin allow/lock/bind+8080 allow/lock/connect+0\-65535 .fi .RE .PP The available \fIlock/\fR categories are: \fIlock/read\fR, \fIlock/write\fR, \fIlock/exec\fR, \fIlock/ioctl\fR, \fIlock/create\fR, \fIlock/delete\fR, \fIlock/rename\fR, \fIlock/symlink\fR, \fIlock/truncate\fR, \fIlock/readdir\fR, \fIlock/mkdir\fR, \fIlock/rmdir\fR, \fIlock/mkdev\fR, \fIlock/mkfifo\fR, and \fIlock/bind\fR.\& The shorthand \fIlock/all\fR stands for the union of all these categories, and \fIlock/all\-x\fR stands for all except \fIlock/exec\fR.\& .PP Lock category sets group related \fIlock/\fR categories, mirroring the structure of the \fIseccomp\fR(2) category sets but covering only the operations that \fIlandlock\fR(7) can enforce: .PP .PD 0 .IP \(bu 4 \fIlock/rpath\fR \-\- lock/read, lock/readdir.\& .IP \(bu 4 \fIlock/wpath\fR \-\- lock/write, lock/truncate.\& .IP \(bu 4 \fIlock/cpath\fR \-\- lock/create, lock/delete, lock/rename.\& .IP \(bu 4 \fIlock/dpath\fR \-\- lock/mkbdev, lock/mkcdev.\& .IP \(bu 4 \fIlock/spath\fR \-\- lock/mkfifo, lock/symlink.\& .IP \(bu 4 \fIlock/tpath\fR \-\- lock/mkdir, lock/rmdir.\& .IP \(bu 4 \fIlock/net\fR \-\- lock/bind, lock/connect.\& .IP \(bu 4 \fIlock/inet\fR \-\- lock/bind, lock/connect.\& .IP \(bu 4 \fIlock/bnet\fR \-\- lock/bind.\& .IP \(bu 4 \fIlock/cnet\fR \-\- lock/connect.\& .PD .PP Notably, there are no \fIlock/fattr\fR, \fIlock/fown\fR, or \fIlock/lpath\fR sets because \fIlandlock\fR(7) does not govern ownership, attribute changes, or path traversal.\& .PP .SS Network Port Rules .PP As of version 3.\&29.\&0, Landlock network confinement is supported.\& Use \fIallow/lock/bind+port\fR and \fIallow/lock/connect+port\fR to allowlist specific ports.\& A closed range \fIport1\-port2\fR is also accepted: .PP .nf .RS 4 allow/lock/bind+8080\-8090 allow/lock/connect+443 .fi .RE .PP UNIX domain socket creation, renames, and links can be confined using the \fIlock/bind\fR category with an absolute path: .PP .nf .RS 4 allow/lock/bind+/run/user/${SYD_UID} .fi .RE .PP .SS Compatibility levels .PP The default compatibility level is \fIkill\fR (since version 3.\&35.\&0), which maps to Hard Requirement: paths specified in \fIlock/\fR rules must exist, and missing paths cause a fatal \fIENOENT\fR error.\& The level can be changed at startup with \fIdefault/lock\fR: .PP .PD 0 .IP \(bu 4 \fIkill\fR \-\- Hard Requirement; missing paths are fatal (default).\& .IP \(bu 4 \fIdeny\fR \-\- Soft Requirement; missing paths produce a warning but are skipped.\& .IP \(bu 4 \fIwarn\fR \-\- Best Effort; log a warning for missing paths and skip them, apply whatever the running kernel ABI supports.\& .PD .PP Refer to \fIsyd\fR(2) manual page for the full \fIdefault/lock\fR documentation.\& .PP .SS syd\-lock Utility .PP The \fIsyd\-lock\fR(1) utility runs a single command under a Landlock sandbox without Syd'\&s full \fIseccomp\fR(2) machinery.\& The \fI\-l\fR flag specifies categories and paths in the same syntax as \fIlock/\fR commands: .PP .nf .RS 4 $ syd\-lock \-l read,exec+/ \-l write+/tmp wget \-O /tmp/file https://example\&.com .fi .RE .PP This confines \fIwget\fR(1) to read and execute from \fI/\fR, write only to \fI/tmp\fR, and deny all other filesystem access at the Landlock level.\& Use \fIsyd\-lock \-V\fR to print the Landlock ABI version supported by the running kernel.\& .PP .SH NETWORK SANDBOXING .PP Syd confines network operations through four categories: .PP .PD 0 .IP \(bu 4 \fInet/bind\fR \-\- \fIbind\fR(2), UNIX domain socket creation via \fImknod\fR(2), and \fIsocketpair\fR(2).\& .IP \(bu 4 \fInet/connect\fR \-\- \fIconnect\fR(2), \fIsendto\fR(2), \fIsendmsg\fR(2), and \fIsendmmsg\fR(2).\& .IP \(bu 4 \fIsendfd\fR \-\- Sending file descriptors via \fIsendmsg\fR(2) and \fIsendmmsg\fR(2) with \fBSCM_RIGHTS\fR.\& The file descriptor being sent is matched, not the peer it is sent to.\& .IP \(bu 4 \fIrecvfd\fR \-\- Receiving file descriptors via \fIrecvmsg\fR(2) and \fIrecvmmsg\fR(2) with \fBSCM_RIGHTS\fR.\& The file descriptor being received is matched, not the peer it is received from.\& .PD .PP Supported socket families are UNIX, IPv4, IPv6, Netlink, and KCAPI.\& The option \fItrace/allow_unsupp_socket:1\fR passes through sockets of unsupported types.\& .PP .SS Address Matching .PP Network rules use a simple address scheme.\& UNIX and abstract UNIX socket addresses use \fIglob\fR(3p) patterns.\& IPv4 and IPv6 addresses use CIDR notation followed by a port range separated by \fI!\&\fR: .PP .nf .RS 4 allow/net/connect+192\&.168\&.1\&.0/24!80\-443 deny/net/bind+0\&.0\&.0\&.0/0!0\-1023 allow/net/bind+/run/user/${SYD_UID}/*** .fi .RE .PP A port range can be a single port (\fI80\fR) or a closed range (\fI1024\-65535\fR).\& UNIX domain socket paths always start with \fI/\fR, abstract sockets are prefixed with \fI@\fR, and unnamed sockets use the dummy path \fI!\&unnamed\fR.\& .PP .SS Dial Strings .PP Network rules also accept Plan9/go style \fIdial\fR(3) strings in the form \fInetwork!\&netaddr!\&service\fR, which add protocol filtering on top of address matching: .PP .nf .RS 4 allow/net/connect+tcp!127\&.0\&.0\&.1!80 allow/net/connect+udp!9\&.9\&.9\&.9!53 allow/net/bind+tcp6!::1!8080 allow/net/connect+udp!loopback!* allow/net/connect+unix!/run/foo\&.sock allow/net/bind+unix!@dbus\-* allow/net/bind,net/connect+unix!!unnamed .fi .RE .PP Network names \fItcp\fR, \fItcp4\fR, and \fItcp6\fR match TCP sockets only, \fIudp\fR, \fIudp4\fR, and \fIudp6\fR match UDP sockets only, and \fInet\fR, \fInet4\fR, and \fInet6\fR match any protocol.\& The \fI4\fR and \fI6\fR suffixes constrain the address family.\& Netaddr is an IP address, a CIDR network, an address alias (see below), or the wildcard \fI*\fR matching any address.\& Service is a port range or the wildcard \fI*\fR matching any port.\& Network names \fIunix\fR, \fIunixgram\fR, and \fIunixpacket\fR take a \fIglob\fR(3p) pattern instead, matching UNIX socket addresses with the usual conventions: Paths start with \fI/\fR, abstract socket names are prefixed with \fI@\fR, and unnamed sockets use the dummy address \fI!\&unnamed\fR.\& Addresses in the plain format match any protocol, so existing configuration keeps working as before.\& .PP .SS Address Aliases .PP Syd provides aliases for common address ranges to avoid hardcoding CIDR blocks: .PP .PD 0 .IP \(bu 4 \fIany\fR \-\- \fI0.\&0.\&0.\&0/0\fR + \fI::/0\fR (all IPv4 and IPv6).\& .IP \(bu 4 \fIloopback\fR \-\- \fI127.\&0.\&0.\&0/8\fR + \fI::1/128\fR.\& .IP \(bu 4 \fIlocal\fR \-\- RFC 1918 private ranges: \fI10.\&0.\&0.\&0/8\fR, \fI172.\&16.\&0.\&0/12\fR, \fI192.\&168.\&0.\&0/16\fR, and IPv6 equivalents.\& .IP \(bu 4 \fIlinklocal\fR \-\- \fI169.\&254.\&0.\&0/16\fR + \fIfe80::/10\fR.\& .IP \(bu 4 \fImulticast\fR \-\- \fI224.\&0.\&0.\&0/4\fR + \fIff00::/8\fR.\& .PD .PP Each alias also has \fI4\fR and \fI6\fR variants (e.\&g.\& \fIloopback4\fR, \fIloopback6\fR) to target a single address family.\& .PP .SS Practical Example .PP The following enables network sandboxing and allows only outbound connections to loopback on port 80.\& A connection to an external address is denied: .PP .nf .RS 4 $ syd \-poff \-msandbox/net:on \-mallow/read+/*** \-mallow/net/connect+loopback!80 curl \-so /dev/null http://1\&.1\&.1\&.1 {"cap":"net/connect","act":"deny","sys":"connect","addr":"1\&.1\&.1\&.1!80", "tip":"configure `allow/net/connect+1\&.1\&.1\&.1!80\&'"} .fi .RE .PP The \fIcurl\fR(1) connection to \fI1.\&1.\&1.\&1\fR is denied because only loopback port 80 is allowed.\& Allowing HTTPS outbound to any address is as simple as: .PP .nf .RS 4 allow/net/connect+any!443 .fi .RE .PP Refer to \fIsyd\fR(7) manual page for the full network sandboxing documentation and \fIsyd\fR(2) manual page for the address matching syntax.\& .PP .SS IP Blocklists .PP The \fIblock\fR command maintains a set of IP networks that are blocked on \fIconnect\fR(2), \fIsendto\fR(2), \fIsendmsg\fR(2), \fIsendmmsg\fR(2), and checked against source addresses returned by \fIaccept\fR(2) and \fIaccept4\fR(2).\& Use \fIblock+\fR and \fIblock\-\fR to add and remove networks.\& Syd can import IP blocklists in \fIipset\fR and \fInetset\fR formats directly from configuration: .PP .nf .RS 4 include /usr/src/blocklist\-ipsets/feodo\&.ipset include /usr/src/blocklist\-ipsets/dshield\&.netset block! .fi .RE .PP The \fIblock!\&\fR command aggregates the imported networks to reduce memory consumption and improve matching performance.\& Use \fIblock\(ha\fR to clear the blocklist.\& Refer to \fIsyd\fR(2) manual page for the full \fIblock\fR command documentation.\& .PP .SH EXECUTION CONTROL .PP .SS Exec Sandboxing .PP The \fIexec\fR category confines binary execution and dynamic library loading.\& The filtered system calls are \fIexecve\fR(2), \fIexecveat\fR(2), \fImmap\fR(2), \fImmap2\fR(2), and \fImemfd_create\fR(2).\& For scripts, both the script and its interpreter are checked.\& Dynamic libraries linked to ELF executables are checked at exec time, and \fImmap\fR(2) calls with \fBPROT_EXEC\fR (typically \fIdlopen\fR(3)) are checked at runtime.\& Enable it with \fIsandbox/exec:on\fR and allowlist trusted paths: .PP .nf .RS 4 sandbox/exec:on allow/exec+/usr/*** .fi .RE .PP Any attempt to execute a binary outside the allowed paths is denied with \fBEACCES\fR ("Permission denied"): .PP .nf .RS 4 $ syd \-poff \-msandbox/exec:on \-mallow/exec+/usr/*** \\ \-mallow/read+/*** /tmp/test_echo hello {"cap":"exec","act":"deny","sys":"execve","path":"/tmp/test_echo", "tip":"configure `allow/exec+/tmp/test_echo\&'"} syd: exec error: Permission denied .fi .RE .PP The default action for exec violations can be changed with \fIdefault/exec\fR, for example \fIdefault/exec:kill\fR terminates the process with \fBSIGKILL\fR on any exec violation.\& .PP .SS Trusted Path Execution .PP Trusted Path Execution (TPE) restricts execution to binaries that reside in \fItrusted directories\fR.\& Enable it with \fIsandbox/tpe:on\fR.\& A binary is trusted if both the file and its parent directory satisfy: .PP .PD 0 .IP \(bu 4 Not writable by group or others.\& .IP \(bu 4 Owned by root (optional, enable with \fItpe/root_owned:1\fR).\& .IP \(bu 4 Owned by the current user or root (optional, enable with \fItpe/user_owned:1\fR).\& .IP \(bu 4 On the root filesystem (optional, enable with \fItpe/root_mount:1\fR).\& .PD .PP If these criteria are not met, execution is denied with \fBEACCES\fR ("Permission denied").\& The default action can be changed with \fIdefault/tpe\fR, for example \fIdefault/tpe:kill\fR terminates the offending process with \fISIGKILL\fR (see \fIsignal\fR(7)).\& .PP TPE checks at three stages: .PP .PD 0 .IP \(bu 4 \fIexecve\fR(2) / \fIexecveat\fR(2) system call entry to check scripts.\& .IP \(bu 4 \fIptrace\fR(2) exec event to check the ELF executable and dynamic loader.\& .IP \(bu 4 \fImmap\fR(2) when dynamic libraries are mapped, typically via \fIdlopen\fR(3).\& .PD .PP By default, TPE applies to all users.\& To restrict it to a specific group, set \fItpe/gid\fR to the untrusted group ID.\& The \fItpe/negate\fR option inverts this logic, making the specified group \fItrusted\fR instead.\& .PP Syd'\&s TPE implementation is based on HardenedBSD'\&s, which is inspired by GrSecurity'\&s TPE.\& Refer to \fIsyd\fR(2) manual page for the full list of \fItpe/\fR options.\& .PP .SS Force Sandboxing .PP Force sandboxing verifies binary integrity at execution time.\& Enable it with \fIsandbox/force:on\fR.\& The \fIforce\fR command populates an Integrity Force map that associates file paths with checksums: .PP .nf .RS 4 force+/usr/bin/curl:sha256:a1b2c3\&.\&.\&.hexdigest\&.\&.\&.:deny .fi .RE .PP The format is \fIforce+/path:algorithm:hashhex:action\fR where \fI:action\fR is optional and defaults to \fIdeny\fR.\& Available algorithms are the supported userspace hashes (see \fIsyd\-sum\fR(1) \fB\-a list\fR), e.\&g.\& \fIsha256\fR, \fIsha3\-512\fR, \fIblake2b\-256\fR, \fIcrc32c\fR.\& Available actions are \fIwarn\fR, \fIfilter\fR, \fIdeny\fR (the default), \fIpanic\fR, \fIstop\fR, \fIabort\fR, \fIkill\fR, and \fIexit\fR.\& Use \fIforce\-/path\fR to remove an entry, or \fIforce\(ha\fR to clear the map.\& .PP Upon \fIexecve\fR(2), Syd computes the checksum of the target binary and compares it against the map.\& A mismatch triggers the configured action.\& Beyond \fIexecve\fR(2), Force sandboxing also checks: .PP .PD 0 .IP \(bu 4 Dynamic libraries linked to ELF executables.\& .IP \(bu 4 Libraries loaded at runtime via \fImmap\fR(2) with \fBPROT_EXEC\fR (typically \fIdlopen\fR(3)).\& .PD .PP Helper tools: .PP .PD 0 .IP \(bu 4 \fIsyd\-sum\fR(1) calculates checksums of files.\& .IP \(bu 4 \fIsyd\-path\fR(1) generates integrity force rules for all binaries under \fBPATH\fR.\& .PD .PP Refer to \fIsyd\fR(2) manual page for the full \fIforce\fR command documentation.\& .PP .SS SegvGuard .PP SegvGuard blocks execution of binaries that crash repeatedly, mitigating brute\-force exploitation attacks.\& Inspired by HardenedBSD'\&s implementation with identical defaults: .PP .PD 0 .IP \(bu 4 \fIsegvguard/maxcrashes\fR \-\- maximum crashes before suspension (default: 5).\& .IP \(bu 4 \fIsegvguard/expiry\fR \-\- time window for counting crashes in seconds (default: 120, i.\&e.\& 2 minutes).\& .IP \(bu 4 \fIsegvguard/suspension\fR \-\- suspension duration in seconds (default: 600, i.\&e.\& 10 minutes).\& .PD .PP If a sandboxed process receives a crash signal \fIsegvguard/maxcrashes\fR times within \fIsegvguard/expiry\fR seconds, subsequent attempts to execute the same binary are denied for \fIsegvguard/suspension\fR seconds.\& Disable SegvGuard by setting \fIsegvguard/expiry:0\fR.\& .PP The trigger signals are \fBSIGABRT\fR, \fBSIGBUS\fR, \fBSIGFPE\fR, \fBSIGILL\fR, \fBSIGIOT\fR, \fBSIGKILL\fR, \fBSIGQUIT\fR, \fBSIGSEGV\fR, \fBSIGSYS\fR, \fBSIGTRAP\fR, \fBSIGXCPU\fR, and \fBSIGXFSZ\fR (see \fIsignal\fR(7)).\& \fBSIGKILL\fR is intentionally included even though it does not produce a \fIcore\fR(5) dump, so that \fIkill\fR sandbox rules trigger SegvGuard.\& .PP SegvGuard depends on \fIptrace\fR(2) and can be disabled by setting \fItrace/allow_unsafe_ptrace:1\fR.\& Refer to \fIsyd\fR(2) for the full list of \fIsegvguard/\fR options and \fIsyd\fR(7) for further reading.\& .PP .SH SECURITY HARDENINGS .PP .SS Memory\-Deny\-Write\-Execute .PP Syd enforces W\(haX (Write XOR Execute) memory protection by default using \fBPR_SET_MDWE\fR (see \fIPR_SET_MDWE\fR(2const)) and \fIseccomp\fR(2) filters on \fImmap\fR(2), \fImmap2\fR(2), \fImprotect\fR(2), \fIpkey_mprotect\fR(2), and \fIshmat\fR(2).\& Memory mappings that are simultaneously writable and executable are rejected by the kernel\-level \fIseccomp\fR(2) filter, which terminates the offending process with \fBSIGSYS\fR (see \fIsignal\fR(7)).\& .PP Syd also validates file descriptor writability during executable memory mapping to prevent a W\(haX bypass where writable file descriptors could modify executable code after mapping.\& .PP To relax this restriction, use \fItrace/allow_unsafe_exec_memory:1\fR at startup.\& Even with this option, Syd still calls \fBPR_SET_MDWE\fR but sets \fBPR_MDWE_NO_INHERIT\fR to prevent propagation to child processes on \fIfork\fR(2).\& .PP The standalone tool \fIsyd\-mdwe\fR(1) applies MDWE protection to a single command without the full Syd sandbox.\& .PP .SS Memory and PID sandboxing .PP Memory sandboxing limits per\-process memory consumption by checking allocations on \fIbrk\fR(2), \fImmap\fR(2), \fImmap2\fR(2), and \fImremap\fR(2): .PP .PD 0 .IP \(bu 4 \fImem/max\fR \-\- Maximum physical memory per process.\& The default action is \fIdeny\fR, return \fBENOMEM\fR ("Out of memory"); change it with \fIdefault/mem\fR, e.\&g.\& \fIdefault/mem:kill\fR to terminate with \fBSIGKILL\fR.\& .IP \(bu 4 \fImem/vm_max\fR \-\- Maximum virtual memory per process.\& .PD .PP Memory use is estimated from \fI/proc/pid/smaps_rollup\fR summing \fIPss\fR, \fBPrivate_Dirty\fR, and \fBShared_Dirty\fR.\& .PP PID sandboxing limits the number of tasks by checking \fIfork\fR(2), \fIvfork\fR(2), \fIclone\fR(2), and \fIclone3\fR(2): .PP .PD 0 .IP \(bu 4 \fIpid/max\fR \-\- maximum concurrent tasks.\& The default action is \fIkill\fR (terminate with \fBSIGKILL\fR); change it with \fIdefault/pid\fR.\& .PD .PP Best coupled with \fIunshare/pid:1\fR so the count applies per PID namespace.\& Both memory and PID sandboxing are \fInot\fR alternatives to \fIcgroups\fR(7); use \fIcgroups\fR(7) when available.\& .PP Refer to \fIsyd\fR(2) manual page for \fImem/\fR and \fIpid/\fR option documentation.\& .PP .SS Namespace Isolation .PP Syd isolates sandboxed processes using Linux \fInamespaces\fR(7).\& Enable namespaces with \fIunshare/\fR commands: .PP .PD 0 .IP \(bu 4 \fIunshare/user:1\fR \-\- \fIuser_namespace\fR(7).\& .IP \(bu 4 \fIunshare/mount:1\fR \-\- \fImount_namespaces\fR(7).\& .IP \(bu 4 \fIunshare/pid:1\fR \-\- \fIpid_namespaces\fR(7).\& .IP \(bu 4 \fIunshare/net:1\fR \-\- \fInetwork_namespaces\fR(7).\& .IP \(bu 4 \fIunshare/uts:1\fR \-\- \fIuts_namespaces\fR(7) (hostname).\& .IP \(bu 4 \fIunshare/ipc:1\fR \-\- \fIipc_namespaces\fR(7) .IP \(bu 4 \fIunshare/cgroup:1\fR \-\- \fIcgroup_namespaces\fR(7) .IP \(bu 4 \fIunshare/time:1\fR \-\- \fItime_namespaces\fR(7) (resets boot clock).\& .PD .PP The \fIbind\fR command creates bind mounts inside the mount namespace.\& The format is \fIbind+source:target:options\fR where options is a comma\-separated list of \fIro\fR, \fInoexec\fR, \fInosuid\fR, \fInodev\fR, \fInosymfollow\fR, \fInoatime\fR, \fInodiratime\fR, and \fIrelatime\fR.\& If the source is not an absolute path, it is interpreted as a filesystem type: .PP .nf .RS 4 # Read\-only bind mount of / onto itself bind+/:/:ro # Private tmpfs on /tmp bind+tmpfs:/tmp:noexec,size=16M # Cgroup filesystem bind+cgroup2:/sys/fs/cgroup:nodev,noexec,nosuid # Overlay mount bind+overlay:/mnt:lowerdir=/lower,upperdir=/upper,workdir=/work .fi .RE .PP The \fIroot\fR command changes the root mount at startup using \fIpivot_root\fR(2).\& Use \fIroot:tmpfs\fR (or \fIroot:ramfs\fR) to build an empty mount namespace from a private temporary filesystem mounted with \fInodev\fR, \fInoexec\fR, \fInosuid\fR, \fInosymfollow\fR, \fInoatime\fR, and \fImode=700\fR.\& Destination paths of \fIbind\fR commands are interpreted relative to the root directory.\& .PP Private \fIproc\fR(5) is mounted with \fIhidepid=4\fR and \fIsubset=pid\fR for process hiding.\& .PP Namespace creation by sandboxed processes is denied by default to prevent path sandboxing bypass.\& Use \fItrace/allow_unsafe_namespace\fR to selectively allow specific namespace types.\& Similarly, \fImount\fR(2) and \fIumount2\fR(2) are denied unless a mount namespace is active.\& .PP Refer to \fIsyd\fR(7) manual page for the full namespace isolation documentation and \fIsyd\fR(2) manual page for the \fIbind\fR and \fIroot\fR command reference.\& .PP .SS SafeSetID .PP SafeSetID controls UID and GID transitions.\& To allow a specific transition, e.\&g.\& root to nobody: .PP .nf .RS 4 setuid+0:65534 setgid+0:65534 .fi .RE .PP All set\fBuid and set\fRgid system calls with target UID <= 11 (typically the \fIoperator\fR user) or GID <= 14 (typically the \fIuucp\fR group) are denied by a kernel\-level \fIseccomp\fR(2) filter, even if Syd itself is compromised.\& After the first successful transition, Syd drops \fBCAP_SETUID\fR / \fBCAP_SETGID\fR so only one transition is permitted per Syd lifetime.\& Subsequent transitions in the sandbox process continue to the UID/GID that Syd transitioned to, supporting daemons like \fInginx\fR(1) that spawn unprivileged workers.\& .PP Refer to \fIsyd\fR(2) manual page for the full \fIsetuid\fR and \fIsetgid\fR command documentation.\& .PP .SS PTY Sandboxing .PP PTY Sandboxing runs the target process inside a dedicated pseudoterminal managed by \fIsyd\-pty\fR(1), isolating terminal I/O from the host TTY.\& I/O is proxied via an edge\-triggered \fIepoll\fR(7) loop with zero\-copy \fIsplice\fR(2).\& A \fIseccomp\fR(2) filter allows only safe PTY ioctls (e.\&g.\& \fBTIOCGWINSZ\fR, \fBTIOCSWINSZ\fR) and denies dangerous ones such as \fBTIOCSTI\fR (terminal input injection).\& \fIlandlock\fR(7) further restricts filesystem and network access for the PTY helper.\& .PP PTY Sandboxing is enabled by default (\fIsandbox/pty:on\fR) but only activates when both standard input and standard output are terminals (see \fIisatty\fR(3)).\& In non\-interactive contexts such as pipes or \fIcron\fR(8) jobs, PTY sandboxing is silently skipped.\& Syd is a multicall binary: it re\-executes itself via \fIproc_pid_exe\fR(5) with \fBargv[0]\fR set to \fIsyd\-pty\fR to spawn the helper process.\& Disable PTY Sandboxing with \fIsandbox/pty:off\fR.\& .PP .SH ADVANCED TOPICS .PP .SS Proxy Sandboxing .PP Proxy Sandboxing routes all network traffic through a designated SOCKS proxy.\& Enable it with \fIsandbox/proxy:on\fR, which implies \fIunshare/net:1\fR to isolate the network namespace.\& Syd re\-executes itself via \fIproc_pid_exe\fR(5) with \fBargv[0]\fR set to \fIsyd\-tor\fR to spawn the proxy helper.\& .PP .nf .RS 4 sandbox/proxy:on proxy/port:9050 proxy/ext/host:127\&.0\&.0\&.1 proxy/ext/port:9050 .fi .RE .PP As of version 3.\&34.\&1, an external UNIX domain socket may be used instead: \fIproxy/ext/unix:/path/socks5.\&sock\fR.\& Traffic is proxied using zero\-copy transfers and edge\-triggered \fIepoll\fR(7).\& .PP .SS /dev/syd API .PP Sandboxed processes communicate with Syd at runtime through virtual paths under \fI/dev/syd/\fR.\& The \fIstat\fR(2) system call on these paths delivers sandbox commands, while \fIopen\fR(2) and \fIread\fR(2) retrieve sandbox state: .PP .nf .RS 4 /* Set a sandbox command at runtime */ struct stat buf; stat("/dev/syd/allow/read+/tmp/***", &buf); /* Lock the sandbox */ stat("/dev/syd/lock:on", &buf); /* Query the sandbox configuration (read\-only) */ int fd = open("/dev/syd", O_RDONLY); .fi .RE .PP The interface is only available when the sandbox lock permits it.\& Refer to \fIsyd\fR(2) manual page for the complete virtual path reference.\& .PP The sandbox lock modes (\fIon\fR, \fIoff\fR, \fIexec\fR, \fIipc\fR, \fIread\fR, \fIdrop\fR) are described in the \fBPATH SANDBOXING\fR section above.\& Refer to \fIsyd\fR(2) manual page for the full \fIlock\fR command documentation.\& .PP .SS Ghost Mode .PP Ghost mode is an irreversible transition to near\-seccomp strict mode.\& A sandboxed process enters Ghost mode by calling \fIstat\fR(2) on \fI/dev/syd/ghost\fR.\& Syd then closes the \fIseccomp_unotify\fR(2) file descriptor, elevating all previously hooked system calls to a kernel\-level deny with \fBENOSYS\fR ("Function not implemented").\& The monitor and emulator threads exit, and the main thread simply waits for the sandbox process to terminate.\& .PP Ghost mode cannot be entered once the sandbox lock is set to \fIon\fR or \fIread\fR, but it works with \fIlock:drop\fR.\& As an alternative, setting the process dumpable attribute to zero via \fIPR_SET_DUMPABLE\fR(2const) achieves a similar effect because Syd can no longer access the per\-process \fIproc\fR(5) directory.\& .PP .SH CONTAINER INTEGRATION .PP .SS syd\-oci .PP \fIsyd\-oci\fR(1) is an OCI container runtime built on top of \fIyouki\fR(1).\& It integrates Syd'\&s sandbox into standard container workflows and is compatible with \fIdocker\fR(1) and \fIpodman\fR(1).\& Build Syd with the \fIoci\fR Cargo feature to obtain syd\-oci.\& .PP To use with \fIdocker\fR(1), add the runtime to \fB/etc/docker/daemon.\&json\fR: .PP .nf .RS 4 { "runtimes": { "syd\-oci": { "path": "/bin/syd\-oci" } }, "default\-runtime": "syd\-oci" } .fi .RE .PP Then run containers with \fIdocker run \-\-runtime=syd\-oci alpine\fR.\& For \fIpodman\fR(1), pass \fI\-\-runtime=/bin/syd\-oci\fR.\& .PP .SS OCI Configuration .PP \fIsyd\-oci\fR(1) searches for sandbox configuration in the following order, using the first file it finds: .PP .PD 0 .IP 1. 4 \fI${hostname}.\&${domainname}.\&syd\-3\fR .IP 2. 4 \fI${domainname}.\&syd\-3\fR .IP 3. 4 \fI${hostname}.\&syd\-3\fR .IP 4. 4 \fIdefault.\&syd\-3\fR .IP 5. 4 The built\-in \fIoci\fR profile.\& .PD .PP The configuration directory is \fI/etc/syd/oci\fR for system\-wide containers, or \fI${XDG_CONFIG_HOME}/syd/oci\fR for rootless containers.\& Set \fBSYD_OCI_NO_CONFIG\fR to skip file lookup and fall through to the built\-in \fIoci\fR profile.\& .PP The \fIinclude\fR directives in these files are resolved within the container image.\& This allows storing Force sandboxing checksums of executables and their dynamic libraries inside the image itself for binary verification at runtime.\& .PP Use \fIsyd\-cat \-p oci\fR to view the built\-in OCI profile.\& The profile is designed to be combined with \fIpandora\fR and learning mode.\& .PP .SH LEARNING MODE .PP .SS Trace Mode .PP Syd'\&s \fI\-x\fR flag enables trace mode (dry run) by applying the built\-in \fItrace\fR profile.\& This profile turns off the sandbox lock, enables Force and ioctl sandboxing, and sets the default action for all sandbox categories to \fIwarn\fR: system calls that would normally be denied are allowed, but Syd logs a detailed JSON warning for each violation.\& Use \fIsyd\-cat \-p trace\fR to view the full list of rules in the trace profile.\& .PP .SS pandora .PP \fIpandora\fR(1) is Syd'\&s log inspector and profile writer.\& It has two subcommands: .PP \fIpandora profile\fR executes a command under Syd'\&s trace mode, reads the violation log through an internal pipe, and writes a sandbox profile: .PP .nf .RS 4 $ pandora profile \-o app\&.syd\-3 \-\- \&./my\-application .fi .RE .PP The \fI\-s\fR flag passes options to Syd during init and may be repeated.\& Each \fI\-s\fR value is forwarded to Syd as a single dash\-prefixed argument.\& This maps to Syd'\&s \fI\-m\fR (inline config), \fI\-p\fR (profile), and \fI\-P\fR (config file) flags: .PP .nf .RS 4 $ pandora profile \-s mtrace/allow_unsafe_exec_memory:1 \-o app\&.syd\-3 \-\- \&./my\-application $ pandora profile \-s P\&./base\&.syd\-3 \-o app\&.syd\-3 \-\- \&./my\-application $ pandora profile \-s puser \-o app\&.syd\-3 \-\- \&./my\-application .fi .RE .PP \fIpandora inspect\fR reads an existing Syd log and produces a profile.\& The input source is set with \fI\-i\fR: a file path, \fI\-\fR for standard input, or \fIsyslog\fR to read from Syd'\&s \fIsyslog\fR(2) ring buffer via \fIdmesg\fR(1): .PP .nf .RS 4 $ pandora inspect \-i violations\&.log \-o app\&.syd\-3 $ pandora inspect \-i syslog \-o app\&.syd\-3 .fi .RE .PP The generated profile is a valid \fIsyd\fR(5) configuration file.\& Load it with \fIsyd \-P .\&/app.\&syd\-3 \-\- .\&/my\-application\fR.\& If new violations appear under the generated profile, repeat the profiling step to refine.\& .PP See https://lib.\&rs/pandora_box for the project homepage.\& .PP .SH LOGGING .PP .SS Log Levels .PP Syd has eight log levels: \fIemerg\fR, \fIalert\fR, \fIcrit\fR, \fIerror\fR, \fIwarn\fR, \fInotice\fR, \fIinfo\fR, and \fIdebug\fR.\& The level is set with \fBSYD_LOG\fR or the \fIlog/level\fR command.\& Logs go to standard error by default; set \fBSYD_LOG_FD\fR to redirect to another file descriptor (negative values disable logging).\& .PP Syd maintains its own \fIsyslog\fR(2) ring buffer where all log messages are stored in kernel format (\fI[boottime] message\fR).\& Access to \fI/dev/kmsg\fR and \fI/proc/kmsg\fR is denied with \fBEPERM\fR ("Operation not permitted"), so \fIdmesg\fR(1) falls back to the \fIsyslog\fR(2) system call, which Syd intercepts via \fIseccomp\fR(2) notify and serves from its ring buffer.\& This enables tools such as \fIpandora\fR to read Syd'\&s access violation logs from inside the sandbox using standard \fIdmesg\fR(1).\& Enable this emulation at startup with \fItrace/allow_safe_syslog:1\fR.\& The default ring buffer is stack\-allocated with an architecture\-dependent size that mirrors Linux \fBCONFIG_LOG_BUF_SHIFT\fR (256K on x86_64, 16K on aarch64, 8K on arm); set \fBSYD_LOG_BUF_LEN\fR to a human\-readable size (e.\&g.\& \fI64K\fR, \fI1M\fR) to allocate a larger heap\-based ring buffer.\& .PP .SS JSON Output .PP Syd logs in JSON lines.\& Key fields in access violation entries: .PP .PD 0 .IP \(bu 4 \fIid\fR \-\- Sandbox ID (128 hex characters).\& .IP \(bu 4 \fIsid\fR \-\- Sandbox name (human\-readable).\& .IP \(bu 4 \fIctx\fR \-\- Context: \fIaccess\fR, \fIsafesetid\fR, \fIsegvguard\fR, etc.\& .IP \(bu 4 \fIcap\fR \-\- Sandbox capability (e.\&g.\& \fIread\fR, \fIwrite\fR, \fIexec\fR).\& .IP \(bu 4 \fIact\fR \-\- Sandbox action: \fIallow\fR, \fIwarn\fR, \fIdeny\fR, \fIkill\fR, etc.\& .IP \(bu 4 \fIsys\fR \-\- System call name.\& .IP \(bu 4 \fIpid\fR \-\- Process ID.\& .IP \(bu 4 \fIpath\fR \-\- Path argument of the system call.\& .IP \(bu 4 \fIaddr\fR \-\- Network address (e.\&g.\& \fI127.\&0.\&0.\&1!\&22\fR).\& .IP \(bu 4 \fIcmd\fR \-\- Process command line.\& .IP \(bu 4 \fIcwd\fR \-\- Current working directory.\& .IP \(bu 4 \fIuid\fR \-\- User ID.\& .IP \(bu 4 \fItime\fR \-\- ISO 8601 timestamp (\fIYYYYMMDDThhmmssZ\fR).\& .IP \(bu 4 \fItip\fR \-\- Suggested sandbox command to allow the access.\& .PD .PP .SS Exit Codes .PP Syd exits with the same code as the sandbox process.\& If the sandbox process is killed by a signal, Syd exits with 128 plus the signal number.\& If Syd itself encounters an error, it exits with the corresponding \fIerrno\fR(3) value.\& Sandbox timeout produces exit code 124.\& .PP .SS Export Seccomp Filters .PP Use \fIsyd \-Epfc\fR to print Syd'\&s \fIseccomp\fR(2) filters in human\-readable Pseudo Filter Code (PFC).\& Use \fIsyd \-Ebpf\fR for raw Berkeley Packet Filter format.\& .PP .SH UTILITIES .PP Syd ships with a suite of utilities.\& Each utility has its own manual page.\& The utilities are grouped by function below.\& .PP .PD 0 .IP \(bu 4 Sandboxing: \fIsyd\-lock\fR(1) (run under \fIlandlock\fR(7)), \fIsyd\-mdwe\fR(1) (Memory\-Deny\-Write\-Execute), \fIsyd\-tsc\fR(1) (deny timestamp counter), \fIsyd\-pds\fR(1) (parent death signal), \fIsyd\-ofd\fR(1) (OFD file locking), \fIsyd\-pause\fR(1) (block until signaled).\& .IP \(bu 4 Integrity: \fIsyd\-sum\fR(1) (file checksums), \fIsyd\-path\fR(1) (Force sandboxing rules for PATH binaries).\& .IP \(bu 4 Inspection: \fIsyd\-ls\fR(1) (list capabilities, syscalls, ioctls), \fIsyd\-stat\fR(1) (process information in JSON), \fIsyd\-elf\fR(1) (ELF file details), \fIsyd\-ldd\fR(1) (secure shared object dependencies), \fIsyd\-cap\fR(1) (Linux capabilities), \fIsyd\-fd\fR(1) (remote file descriptors), \fIsyd\-mem\fR(1) (process memory usage), \fIsyd\-x\fR(1) (check executability), \fIsyd\-cat\fR(1) (parse \fIsyd\fR(5) configuration).\& .IP \(bu 4 System: \fIsyd\-sys\fR(1) (lookup syscalls, errnos, ioctls), \fIsyd\-uts\fR(1) (kernel information), \fIsyd\-info\fR(1) (system information), \fIsyd\-utc\fR(1) (UTC time), \fIsyd\-fs\fR(1) (filesystem type), \fIsyd\-net\fR(1) (aggregate IP networks), \fIsyd\-sec\fR(1) (secure bits), \fIsyd\-tty\fR(1) (controlling terminal), \fIsyd\-aux\fR(1) (auxiliary vector).\& .IP \(bu 4 Data: \fIsyd\-hex\fR(1) (hex encode/decode), \fIsyd\-read\fR(1) (resolve symlinks), \fIsyd\-size\fR(1) (parse human\-formatted sizes).\& .IP \(bu 4 Execution: \fIsyd\-exec\fR(1) (construct sandbox exec commands), \fIsyd\-run\fR(1) (run inside a container), \fIsyd\-emacs\fR(1) (run Emacs under Syd).\& .IP \(bu 4 Container: \fIsyd\-oci\fR(1) (OCI container runtime), \fIsyd\-pty\fR(1) (PTY forwarder), \fIsyd\-tor\fR(1) (SOCKS proxy forwarder).\& .IP \(bu 4 Testing: \fIsyd\-test\fR(1) (integration tests), \fIsyd\-poc\fR(1) (sandbox break demonstrations).\& .PD .PP .SH SEE ALSO .PP \fIsyd\fR(1), \fIsyd\fR(2), \fIsyd\fR(5), \fIsyd\fR(7) .PP \fIsyd\fR homepage: https://sydbox.\&exherbo.\&org .PP .SH AUTHORS .PP Maintained by Ali Polatel.\& Up\-to\-date sources can be found at https://gitlab.\&exherbo.\&org/sydbox/sydbox.\&git and on Radicle at rad:z38HCnbmcDegA2BMxuPaPRPMdp6wF.\& Bugs/patches can be submitted to https://gitlab.\&exherbo.\&org/groups/sydbox/\-/issues.\& Discuss in #sydbox on Libera Chat or in #sydbox:mailstation.\&de on Matrix.\&