mirror of
https://github.com/syncthing/syncthing.git
synced 2026-03-24 17:21:56 -04:00
fix(systemd): Add back chown allowed syscalls IFF the user enables the `syncOwnership` feature AND sets `AmbientCapabilities=CAP_CHOWN CAP_FOWNER` as the docs in https://docs.syncthing.net/users/autostart.html#permissions state, THEN syncthing needs to use the `chown` syscall. PR #10421 added a comprehensive sandbox that breaks `syncOwnership`. In PR #10602 we fixed one part, which is expanding the default `CapabilityBoundingSet` (see the PR for details). But there's a very subtle bug that this PR fixes. PR #10421 sets the following properties: SystemCallFilter=@system-service SystemCallFilter=~@privileged io_uring_enter io_uring_register io_uring_setup (Systemd merges `SystemCallFilter` values; we had to set the property twice because to negate syscalls, the whole list has to start with `~`.) The goal was to allow all syscalls in the `@system-service` set, BUT disallow any `@privileged` syscalls and the `io_uring*` syscalls. But the sets are not disjoint; `chown` is in both `@system-service` and in `@privileged`, so it is removed from the allow list by the second property value. This property is also parsed in a very peculiar way. From systemd docs: > If you specify both types of this option (i.e. allow-listing and > deny-listing), the first encountered will take precedence and will > dictate the default action (termination or approval of a system call). > Then the next occurrences of this option will add or delete the listed > system calls from the set of the filtered system calls, depending of its > type and the default action. (For example, if you have started with an > allow list rule for read() and write(), and right after it add a deny > list rule for write(), then write() will be removed from the set.) Not only does the order of `SystemCallFilter` properties matter (later ones can undo effects of prior ones), but the _type_ of the _first_ property sets the overall behavior of the syscall filter: if the first `SystemCallFilter` value is an allow list, then all syscalls that are not specified are disallowed by default (and reverse if the first value is a deny list). Of course, this is completely different from how other allow/deny lists are implemented in systemd; for example, `IPAddress[Allow|Deny]` properties don't work like this at all. >:( Since this complexity has bit us once, we're removing the additional deny list of syscalls and sticking with just `SystemCallFilter=@system-service`. This leaves some privileged syscalls in the allow list. Other options would require entering the "deny list by default" mode and deny lists are less secure than allow lists in general because they have to be maintained (the kernel always adds new syscalls). The rest of the sandbox (capability bounds) should be sufficient. Fixes #10603 Signed-off-by: Val Markovic <val@markovic.io>
222 lines
9.0 KiB
Desktop File
222 lines
9.0 KiB
Desktop File
[Unit]
|
|
Description=Syncthing - Open Source Continuous File Synchronization for %I
|
|
Documentation=man:syncthing(1)
|
|
After=network.target
|
|
StartLimitIntervalSec=60
|
|
StartLimitBurst=4
|
|
|
|
[Service]
|
|
User=%i
|
|
Environment="STLOGFORMATTIMESTAMP="
|
|
Environment="STLOGFORMATLEVELSTRING=false"
|
|
Environment="STLOGFORMATLEVELSYSLOG=true"
|
|
ExecStart=/usr/bin/syncthing serve --no-browser --no-restart
|
|
Restart=on-failure
|
|
RestartSec=1
|
|
SuccessExitStatus=3 4
|
|
RestartForceExitStatus=3 4
|
|
|
|
#############
|
|
# SANDBOXING
|
|
#############
|
|
#
|
|
# This section contains best-effort sandboxing of syncthing. Such sandboxing is
|
|
# useful to reduce the blast damage of a syncthing exploit.
|
|
#
|
|
# The sandboxing is "best-effort" only because some of these options are ignored
|
|
# if your systemd or kernel are too old or configured in unusual ways. Systemd
|
|
# should (but may not) tell you in the journal logs if that's the case. See the
|
|
# logs (after starting the service) with:
|
|
#
|
|
# journalctl --boot --pager-end --unit syncthing@<user-you-used>.service
|
|
#
|
|
# See systemd's analysis of syncthing's sandbox with:
|
|
#
|
|
# systemd-analyze security syncthing@<user-you-used>.service
|
|
#
|
|
# Most of these sandboxing options are documented in `man systemd.exec`.
|
|
#
|
|
# NOTE: Some of these options _appear_ redundant with each other... but
|
|
# depending on the version and configs of systemd and the kernel, some of the
|
|
# "redundant" options may be non-functional while others still work.
|
|
# We recommend leaving the "redundant" options in place.
|
|
|
|
# Makes /usr, /boot, /efi and /etc read-only.
|
|
ProtectSystem=full
|
|
# Protect several system areas syncthing should not be touching.
|
|
ProtectKernelTunables=true
|
|
ProtectKernelModules=true
|
|
ProtectKernelLogs=true
|
|
ProtectControlGroups=true
|
|
ProtectHostname=true
|
|
ProtectClock=true
|
|
# No new privileges through SUID/SGID binaries
|
|
NoNewPrivileges=true
|
|
# Prevents *setting* SUID/SGID bits on files/dirs
|
|
RestrictSUIDSGID=true
|
|
# Prevent memory pages that are both writable and executable. This kills JIT
|
|
# compilers, but syncthing is precompiled.
|
|
MemoryDenyWriteExecute=true
|
|
# Prevents creation of unprivileged user namespaces which are a significant
|
|
# source of privilege escalation exploits.
|
|
#
|
|
# (In 2023, Google saw 44% of kernel exploits using unpriv. user namespaces.
|
|
# Source: https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces)
|
|
#
|
|
# The service can still be placed *inside* such user namespaces (and is, through
|
|
# other sandboxing options), it just can't create any itself.
|
|
RestrictNamespaces=true
|
|
# RT task scheduling can be abused for denial-of-service
|
|
RestrictRealtime=true
|
|
# NOTE: This option is poorly named. It doesn't _restrict_ the listed families,
|
|
# it _allows_ the listed families. Unlisted ones are restricted.
|
|
#
|
|
# Specifically, notice the absence of AF_PACKET (raw packets).
|
|
# AF_UNIX is needed to support binding to UNIX sockets.
|
|
# AF_NETLINK is needed to support hotplugging of network devices and because
|
|
# otherwise we see the following (non-fatal) error on startup:
|
|
#
|
|
# Failed to list network interfaces (error="route ip+net: netlinkrib:
|
|
# address family not supported by protocol" log.pkg=upnp)
|
|
#
|
|
# This option does NOT affect systemd socket passing using .socket units.
|
|
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
|
|
# The lifetime limit of (superuser) capabilities that syncthing can acquire.
|
|
# This option _restricts_ capabilities.
|
|
#
|
|
# NOTE: This is set to `CAP_CHOWN CAP_FOWNER` to avoid breaking users that have
|
|
# set `AmbientCapabilities=CAP_CHOWN CAP_FOWNER` to enable the `syncOwnership`
|
|
# option as described in:
|
|
# https://docs.syncthing.net/users/autostart.html#permissions
|
|
#
|
|
# If you do not use the `syncOwnership` option, you can set this to:
|
|
# CapabilityBoundingSet=
|
|
CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER
|
|
# Start with empty (superuser) capabilities.
|
|
# This option _expands_ capabilities.
|
|
# AmbientCapabilities should equal CapabilityBoundingSet.
|
|
#
|
|
# NOTE: IFF you wish to use the `syncOwnership` option, you must set this to:
|
|
# AmbientCapabilities=CAP_CHOWN CAP_FOWNER
|
|
# in a systemd drop-in file. Be aware that this gives syncthing the ability to
|
|
# change or ignore file ownership across the entire operating system.
|
|
AmbientCapabilities=
|
|
# Disables `personality` system call; it can be used for privilege escalation.
|
|
LockPersonality=true
|
|
# Prevents circumvention of restrictions through the use of x86 syscalls on
|
|
# x86-64 systems.
|
|
SystemCallArchitectures=native
|
|
# Clean up IPC objects after service stops.
|
|
RemoveIPC=true
|
|
# Create private namespace for System V IPC.
|
|
# NOTE: This does not apply to AF_UNIX sockets which are more commonly used.
|
|
PrivateIPC=true
|
|
# Completely isolated /tmp and /var/tmp
|
|
PrivateTmp=disconnected
|
|
# New /dev with safe virtual devices like /dev/null
|
|
PrivateDevices=true
|
|
# Allow access to devices explicitly listed with DeviceAllow and pseudo devices
|
|
# like /dev/null.
|
|
DevicePolicy=closed
|
|
# Creates a new PID namespace. /proc now contains only entries for processes
|
|
# in this PID namespace.
|
|
PrivatePIDs=true
|
|
# Make processes owned by other users hidden in /proc/
|
|
ProtectProc=invisible
|
|
# Prevent access to non-pid interfaces in /proc.
|
|
ProcSubset=pid
|
|
# System call allow-list. `@system-service` is a systemd-provided category that
|
|
# allows common syscalls needed for system services.
|
|
SystemCallFilter=@system-service
|
|
# Return EPERM when a disallowed syscall is made instead of killing the process.
|
|
SystemCallErrorNumber=EPERM
|
|
# Digits from left to right; disallow creation of files with:
|
|
# - special security-related bits like setuid/setgid
|
|
# - (no restrictions on file owner permissions)
|
|
# - group-writable access
|
|
# - world-readable access
|
|
# NOTE: The default value is 0022. We are only restricting special security bits
|
|
# and world-readable access.
|
|
# NOTE: Syncthing can still _explicitly_ change file permissions using `chmod`.
|
|
UMask=7027
|
|
# The default HOME folder for system users on Debian-like systems is
|
|
# /nonexistent, which should never exist.
|
|
# We prevent syncthing from accessing that folder it if was previously created
|
|
# through misconfiguration, or from creating it if it's (correctly) missing.
|
|
InaccessiblePaths=-/nonexistent
|
|
|
|
##################
|
|
# OPTIONAL CONFIG
|
|
##################
|
|
#
|
|
# Users that want to tweak this service file should add a systemd drop-in
|
|
# file to avoid changing the original file.
|
|
#
|
|
# Documentation describing drop-in files:
|
|
# https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html
|
|
#
|
|
# Example drop-in file location (assuming user "syncthing"):
|
|
# /etc/systemd/system/syncthing@syncthing.service.d/override.conf
|
|
#
|
|
## Elevated permissions to sync ownership (disabled by default),
|
|
## see https://docs.syncthing.net/advanced/folder-sync-ownership
|
|
##
|
|
## NOTE:
|
|
## - Use the same value for *both* of these options.
|
|
## - PrivateUsers=false must be set (false is the default, but you might have
|
|
## changed it to true in the "extra credit" section below).
|
|
#AmbientCapabilities=CAP_CHOWN CAP_FOWNER
|
|
#CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER
|
|
|
|
#########################
|
|
# EXTRA CREDIT FOR USERS
|
|
#########################
|
|
#
|
|
# Users that want to harden their systems further should set the following
|
|
# properties. (Also through a systemd drop-in file; see comments above.)
|
|
#
|
|
## Makes all of / read-only *except*:
|
|
## - /dev/, /proc/ and /sys/ (see other Protect* options)
|
|
## - ReadWritePaths=
|
|
## - StateDirectory=, LogsDirectory= and similar
|
|
##
|
|
## This cannot be enabled by default because we don't know which folders you wish to
|
|
## share. If enabling this option, enable it along with ReadWritePaths=, e.g.:
|
|
## ReadWritePaths=/my/shared/dir1 /my/shared/dir2
|
|
#ProtectSystem=strict
|
|
#
|
|
## When enabled, sets up a new user namespace. Maps the "root" user and group as
|
|
## well as the unit's own user and group to themselves and everything else to
|
|
## the "nobody" user and group.
|
|
## This is useful to securely detach the user and group databases used by the
|
|
## unit from the rest of the system, and thus to create an effective sandbox
|
|
## environment.
|
|
#PrivateUsers=true
|
|
#
|
|
## Makes /home, /root and /run/user *invisible* while allowing BindPaths= and
|
|
## BindReadOnlyPaths= to "carve out" access to parts of those dirs.
|
|
## (Use 'true' instead of 'tmpfs' if you don't need to carve out anything.)
|
|
##
|
|
## "Invisible" is superior to read-only provided by ProtectSystem=strict because
|
|
## it prevents information disclosure of private user data in case of service
|
|
## compromise.
|
|
#ProtectHome=tmpfs
|
|
#
|
|
## Disallow execution of all binaries. ExecPaths= below carves out exceptions.
|
|
## Can't be enabled by default due to the External File Versioning feature:
|
|
## https://docs.syncthing.net/users/versioning.html#external-file-versioning
|
|
##
|
|
## If you do not use that feature, you can enable both NoExecPaths and
|
|
## ExecPaths.
|
|
## If you do use that featuer, you can still use these options; just add
|
|
## the paths to the binaries you invoke to ExecPaths so they can be executed.
|
|
#NoExecPaths=/
|
|
## Allow execution of syncthing and system shared libraries.
|
|
## NOTE: If you are seeing an error like
|
|
## "Failed to execute /some/path/to/syncthing: Permission denied", this is the
|
|
## option you need to update to use your non-standard install location.
|
|
#ExecPaths=/usr/bin/syncthing /usr/lib
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|