SYD(5)

πŸ“¦
version 3.59.0 Β· 3 versions
, in arch rolling

πŸ’… SYD(5) β€” the manual page, aka File Formats Manual 😌✨

okay bestie, so this is syd(5) β€” the document format for writing Syd profiles πŸŽ€ yes, the whole "how do I actually write one of these files" situation, and honestly? iconic. let's get into it 🫢


✨ NAME ✨

syd β€” the document format for writing Syd profiles πŸ“πŸ’–


🌈 API 🌈

The current version of the Syd command API is 3. and here's the cute part β€” this version is stable πŸ’š like, no cap, it's not gonna ghost you.


πŸ¦‹ CONFIGURATION πŸ¦‹

Syd gets configured through sandbox commands πŸ› οΈ and here's a rule you gotta internalize fr: when there are multiple matching rules (say, two rules matching the same path), the last matching rule wins πŸ‘‘ so order matters, bestie, don't skip that.

There are two ways to supply sandbox commands πŸ’«

1. the configuration file way πŸ“ β€” the path to the config file is specified using the -P command line switch. and yeah, more than one configuration file may be specified this way 😌. single commands may also be passed via the -m command line switch, and configuration profiles get applied using the -p command line switch. peek the PROFILES section for more deets πŸ’œ

2. the magic stat(2) calls during runtime way πŸͺ„ β€” this is achieved by calling the stat(2) system call on the special path /dev/syd followed by the sandbox command. but β€” runtime configuration is only possible if the sandbox lock is off πŸ”’ so lock it and you're locked out, iykyk.

and why stat(2)? because it's practical to invoke using builtin shell commands like this 🐚

; test -c /dev/syd/sandbox/read:on

which enables Read Sandboxing for a shell running under Syd ✨ slay. you can also query certain values using the return value of the stat(2) call πŸ‘€

test -c /dev/syd/sandbox/read? && echo read sandboxing on || echo read sandboxing off

okay but a lil heads up πŸ™ˆ β€” some of these shell builtins may actually call other system calls such as fstat(2), lstat(2), newfstatat(2), or statx(2). and Syd supports the same interface through all these system calls transparently 🌈 no cap. check the manual page syd(2) for a description of the stat(2) interface πŸ“–πŸ’–


πŸŽ€ NAMING πŸŽ€

Configuration file naming of Syd follows a naming scheme which makes it possible to extract the command API version from the file name πŸ”βœ¨ like a lil detective moment, we love that.

A Syd configuration file must have the extension syd- followed by the API version β€” for example, "syd-3" for API version 3 πŸ’… so yes, the filename is literally telling you which API it's vibing with.


🌸 SYNTAX 🌸

Input files must use the UTF-8 encoding 🧚 and the config format is line oriented πŸ“

  • comments start with #
  • inline comments are not supported πŸ’€ like, none. zero. nada.
  • blank lines are ignored 🫢
  • all the other lines are treated as if they were supplied to Syd via the -m command line switch 🎯

for a list of available sandbox commands, consult syd(2) πŸ“š and for a VIM syntax file for Syd profiles, check here πŸ‘‡

https://gitlab.exherbo.org/sydbox/sydbox/-/tree/main/vim


✨ the 3.15.1 glow-up: two extra parsing features ✨

As of version 3.15.1, Syd adds two additional features to configuration file parsing πŸŽ‰ bestie the parser got hands.

  • Environment variable expansion is performed on arguments using the shellexpand crate πŸ¦‹. Unset environment variables are not expanded to empty strings πŸ™…β€β™€οΈ. On environment variable lookup errors and UTF-8 decoding errors, Syd stops parsing and exits with error 😭 and yeah, this is done for safety β€” because an unintended empty-string expansion can potentially cause the resulting sandboxing rule to allowlist unintended paths without the user easily noticing it πŸ‘€πŸ’€. the user is recommended to set default values for environment variables using the familiar ${HOME:-/var/empty} notation πŸ’–. and if you really want empty-string expansion on unset environment variables, you can get this effect using the notation ${HOME:-} β€” but this is not recommended and should be used with care ⚠️ like fr fr, be careful.
  • include directives can be used to request the inclusion of another configuration file πŸ“‚βœ¨. Upon reading an include line, Syd stops parsing the current file, validates the given include path, and starts to parse the new configuration file. the file must not be writable by group or others for safety πŸ”’. for include files with relative paths, Syd searches the file under the directory of the previous configuration file rather than the current working directory β€” for safety and ease of configuration, periodt πŸ’…. loops in include directives are detected by caching the device id and inode of the configuration files πŸ•΅οΈβ€β™€οΈπŸ”„. and heads up: this directive is not permitted when loading configuration from a file descriptor using the load command πŸ™ˆ

πŸ¦‹ and the 3.17.6 moment πŸ¦‹

As of version 3.17.6, Syd adds the include_profile directive which may be used to include a Syd profile πŸ’–βœ¨. see syd-cat -plist for the list of profiles πŸ“‹πŸ‘‘

🌈 PROFILES 🌈

okay so this is the part where Syd just hands you a whole closet full of pre-styled outfits πŸŽ€ β€” these are the predefined profiles, and they exist so you don't have to hand-write every single rule yourself. You can wear one standalone, or stack them with other profiles and your own custom config to build whatever level of isolation and confinement you're feeling. Mix and match, it's giving capsule wardrobe ✨

  • To see the complete list of profiles: syd-cat -plist
  • To list the rules of one specific profile: syd-cat -p<profile-name>

Below is a brief rundown of the common ones and what they actually do πŸ’…

  • container (short: c) β€” Enables Linux namespaces.
  • immutable (short: i) β€” Enables Linux namespaces and remounts these directories read-only in the new mount namespace: /etc, /home, /media, /mnt, /opt, /srv, and /usr. Further mount options such as nodev, noexec, nosuid, and noatime are also applied as necessary. On top of that, /dev/shm and /tmp are mounted private and kernel filesystems are masked. Run syd-cat -p immutable for the full list of mount options. 🧊
  • privileged (short: p) β€” Do not drop Linux capabilities at startup. Used to construct privileged containers.
  • readonly (short: ro) β€” Deny all write sandbox capabilities to the entire root filesystem.
  • landlock (short: l) β€” Enables LandLock and allows system directories for Lock Sandboxing.
  • linux (short: L) β€” Common Linux system profile, used by oci, paludis and user profiles.
  • oci β€” Used by syd-oci(1) as the default container profile.
  • paludis β€” Used by the Paludis package mangler.
  • local (short: @) β€” Force local networking, rewrite all addresses to loopback at bind/connect, used by user profile.
  • noipv4 (short: 6) β€” Disables IPv4 connectivity.
  • noipv6 (short: 4) β€” Disables IPv6 connectivity.
  • cwd, pwd (short: d) β€” Grant all access to the current working directory. Syd sets the environment variable SYD_PWD before parsing this profile. If the process has no current working directory, SYD_PWD variable is set to /proc/self/fdinfo. πŸ—‚οΈ
  • core (short: C) β€” Allows generation of coredumps.
  • debug (short: D) β€” Allows debuggers inside the sandbox. Syd does not use ptrace(1) with this profile, so tracers may attach.
  • nomem (short: M) β€” Allows unsafe memory (no W^X, no Memory-Deny-Write-Execute, allows e.g. JITs).
  • nopie (short: P) β€” Relaxes PIE (Position Independent Executable) restriction.
  • nomagic (short: S) β€” Enforce no magic links during path resolution. Used by user profile.
  • noscm β€” Denies receiving file descriptors via SCM_RIGHTS using SO_PASSRIGHTS socket option. This profile is a noop on kernels older than Linux-6.16. Used by user profile.
  • noxdev (short: X) β€” Enforce no cross mounts during path resolution. Used by user profile.
  • quiet (short: q) β€” Silences all access violations. 🀫
  • hide (short: h) β€” Turns on Chdir, List, Stat, Readlink, Notify, and Walk sandboxing for path hiding.
  • fs (short: f) β€” Turns on Filesystem sandboxing to confine file opens based on filesystem type. Allows access to all filesystem types except some special filesystem types. Refer to the output of syd-cat -pfs for the list of denied filesystem types. Used by linux profile.
  • gui (short: g) β€” Turns off PTY sandboxing and passes through unsafe GUI environment variables. Used by chrome and firefox profiles.
  • lang β€” Allows language and timezone environment variables. Used by chrome and firefox profiles.
  • ldd β€” Disables setting AT_SECURE and allows ld.so(8) exec redirection. Used by syd-ldd(1).
  • rand (short: r) β€” Enables randomized file descriptors, used by user profile. See Force Randomized File Descriptors section of the syd(7) manual page for more information.
  • wx β€” Enables Write XOR Execute, aka W^X, confinement for the filesystem, used by user profile. This profile prevents executable file creation, and writes to executable files. πŸ”’
  • xdg β€” Allows XDG environment variables. Used by gui and firefox profiles.
  • off β€” Turns all sandboxing off.
  • lib β€” libsyd helper profile. Turns all sandboxing off and sets sandbox lock to exec. Useful to configure Syd in the application using libsyd.
  • user (short: u) β€” Allows user-specific directories, and connections, and parses the files /etc/user.syd-3, and ~/.user.syd-3 if they exist. To enforce system-wide settings, set lock:on at the end of /etc/user.syd-3. πŸ‘‘
  • kvm β€” Profile to allowlist KVM ioctl(2) requests without path check. Read: https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt
  • tty (short: t) β€” Profile to allow TTY access, used by oci, paludis, and user profiles.
  • chrome β€” Profile to relax restrictions to enable running Chrome family browsers. Syd sandbox isn't compatible with Chrome sandbox, so --no-sandbox should be used.
  • firefox (short: ff) β€” Profile to relax restrictions to enable running Firefox family browsers. 🦊

Stacking Profiles

bestie you can stack multiple profiles to configure a more restricted sandbox πŸ’– but listen β€” the order you stack them in matters, because the last matching rule wins. So yes, it's an outfit-layering situation and the top layer is the one people see πŸ‘—

Some examples:

syd -puser -pimmutable -mroot:/mnt/gnu ...
syd -ppaludis -plandlock -mallow/lock/write+/var/tmp ...

You can also combine the one-character shortcuts of helper profiles, in order to stack them together. Like so:

syd -pMPX ... # Disable MDWE, PIE and exec restrictions.
syd -puiq ... # Parse user profile, create an immutable container, and silence access violations.

Honestly? -puiq is such a serve, three profiles in four characters 😭πŸ”₯


Login shell and the User Profile

When invoked without arguments, rbash(1) is executed under Syd with the user profile as a login shell. Use the SYD_SHELL environment variable to override the shell to execute. 🐚


πŸ” SECURITY πŸ”

okay this part is the serious part, no clowning around, but I'm still gonna hold your hand through it 🫢

As of version 3.30.0, Syd aborts with error if the path to a specified configuration file has a symbolic link in any of its path components. So basically: the user must supply canonicalized paths as configuration file arguments. No shortcut paths, no symlink shenanigans πŸ™…β€β™€οΈ

As of version 3.46.0, parent (..) components are not permitted in configuration file path, and configuration files must be regular files. Periodt.

As of version 3.56.0, Syd confines include directive path resolution to the directory containing the configuration file, using the RESOLVE_IN_ROOT and RESOLVE_NO_XDEV flags of openat2(2). What that means in practice:

  • Included files must reside within (or beneath) the same directory as the including configuration file.
  • Absolute paths in include directives are interpreted relative to that directory root, rather than the true filesystem root.
  • Symbolic links, path traversals via .., and cross-device includes are rejected.
This hardening measure prevents configuration injection from directories outside the trusted configuration tree. Do not fight it, it's literally doing its job πŸ’€

🌸 ENVIRONMENT 🌸

Syd makes the following environment variables available to configuration:

  • SYD_ID β€” Sandbox identity is 64 hexadecimal digits. It is generated using AT_RANDOM bytes at Syd startup. 🎲
  • SYD_UID β€” Real user identity
  • SYD_GID β€” Real group identity
  • SYD_EUID β€” Effective user identity
  • SYD_EGID β€” Effective group identity
  • SYD_USER β€” User name is equivalent to USER. No passwd(5) lookup is done. If USER is unset at startup, it is set to nobody.
  • SYD_HOME β€” Home directory is equivalent to HOME. No passwd(5) lookup is done. If HOME is unset at startup, it is set to /var/empty.
  • SYD_PWD β€” Current working directory is canonicalized. On getcwd(2) and canonicalization errors, it is set to /proc/self/fdinfo.
  • SYD_PAGE_SIZE β€” System page size. On sysconf(3) errors, it is set to 4096.
  • SYD_PIPE_MAX β€” System maximum pipe(2) buffer size. On errors reading from proc(5), it is set to system page size.
  • SYD_XATTR_MAX β€” Maximum extended attribute value size. Set to the system maximum of 65536 bytes.
  • SYD_HAVE_FORCE β€” Set to 1 if Syd is built with the force Cargo feature, 0 otherwise.
  • SYD_HAVE_SO_PASSRIGHTS β€” Set to 1 on Linux-6.16 or newer, 0 otherwise.
⚠️ Heads up: environment variables with the SYD_ prefix are not passed to the sandbox process. Use setenv! to pass them explicitly, e.g. setenv!PWD=$SYD_PWD. Refer to the setenv section of the syd(2) manual page for more information.

✨ EXAMPLE ✨

okay bestie, this is the example β€” a full-blown Syd profile for OpenNTPD, and it's honestly iconic. It's long, so just vibe with it, everything's commented so you know exactly what each bit is doing πŸ’…

# Syd profile for OpenNTPD

# Seccomp sandbox
sandbox/read,stat,write,exec,net:on

# Landlock
sandbox/lock:on

# Provide isolation using namespaces.
unshare/mount,uts,pid,ipc,cgroup:1

# Allow adjtimex and keep CAP_SYS_TIME.
trace/allow_unsafe_time:1

# Mount everything ro except /var
bind+tmpfs:/dev/shm:nodev,nosuid,noexec
bind+tmpfs:/tmp:nodev,nosuid
bind+/etc:/etc:ro,nodev,noexec,nosuid,noatime
bind+/home:/home:ro,nodev,noexec,nosuid,noatime
bind+/media:/media:ro,nodev,noexec,nosuid,noatime
bind+/mnt:/mnt:ro,nodev,noexec,nosuid,noatime
bind+/opt:/opt:ro,nodev,nosuid,noatime
bind+/srv:/srv:ro,nodev,noexec,nosuid,noatime
bind+/usr:/usr:ro,nodev,noatime

# Hide Syd
deny/read,stat,write+/proc/1/***

# Allow listen to the ntp port on loopback.
allow/net/bind+loopback!123

# Allow connections to NTP servers.
allow/net/connect+any!53
allow/net/connect+any!123
allow/net/connect+any!65535

# Allow logging to syslog.
allow/net/connect+/dev/log

# Allow `listen wildcard`
allow/net/bind+0.0.0.0!0
allow/net/connect+0.0.0.0!0

# Allow listen to the ntpd socket.
allow/net/bind+/run/ntpd.sock
allow/net/bind+/var/run/ntpd.sock
allow/write+/run/ntpd.sock
allow/write+/var/run/ntpd.sock

# Allow access to system paths
allow/read,stat+/dev/urandom
allow/lock/read+/dev/urandom
allow/read,stat+/etc/hosts
allow/lock/read+/etc/hosts
allow/read,stat+/etc/ntpd.conf
allow/lock/read+/etc/ntpd.conf
allow/read,stat+/etc/passwd
allow/lock/read+/etc/passwd
allow/read,stat+/etc/resolv.conf
allow/lock/read+/etc/resolv.conf
allow/read,stat+/etc/services
allow/lock/read+/etc/services
allow/read,stat+/usr/share/zoneinfo-posix/UTC

# chroot /var/empty && cd /
allow/stat+/
allow/stat+/var/empty
allow/write+/dev/null
allow/lock/write+/dev/null

# Allow executing the ntp binary.
allow/lock/read+/proc
allow/lock/read+/usr
allow/lock/write+/run
allow/lock/write+/var/run
allow/exec+/usr/**/bin/openntpd*

# Allow writing the drift file.
allow/write+/var/db/ntpd.drift
allow/lock/write+/var/db/ntpd.drift

# Lock configuration
lock:on

πŸŽ€ the little highlights that ate

if you're skimming (no judgement, bestie), here's the tl;dr of the shoutier lines:

  • sandbox/read,stat,write,exec,net:on β€” that's the seccomp sandbox turned on for those operations πŸ›‘οΈ
  • sandbox/lock:on β€” and that's Landlock πŸ’–
  • unshare/mount,uts,pid,ipc,cgroup:1 β€” isolation via namespaces, slay
  • trace/allow_unsafe_time:1 β€” lets you allow adjtimex while keeping CAP_SYS_TIME ⏰
  • the whole bind+ block mounts everything ro except /var β€” like, everything. /dev/shm, /tmp, /etc, /home, /media, /mnt, /opt, /srv, /usr 🌸
  • deny/read,stat,write+/proc/1/*** β€” hide Syd πŸ™ˆ
  • the allow/net/bind + allow/net/connect lines handle the ntp port on loopback, connections to NTP servers, logging to syslog, listen wildcard, and the ntpd socket πŸ”₯
  • allow/exec+/usr/**/bin/openntpd* β€” allowing execution of the ntp binary ✨
  • lock:on β€” last line, and it locks the configuration. periodt. πŸ”’
fr fr, read the comments in the profile β€” they're literally the whole explanation and they're giving main character energy πŸ‘‘

🌈 SEE ALSO 🌈

syd homepage: https://sydbox.exherbo.org/ β€” go be nosy, iykyk πŸ’–


πŸ‘‘ AUTHORS πŸ‘‘

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. 🫢


and that's a wrap on SYD(5) bestie!! πŸŽ‰ this one's from syd source/version page SYD(5), dated 2026-09-01 β€” go forth and sandbox, you absolute icon πŸ’…βœ¨πŸ¦‹

πŸ“¦ where this page comes from