Xpra has experimental Linux-only Landlock policies for the whole client or server process. Confinement is disabled by default.
xpra attach :100 --landlock=default
xpra start :100 --landlock=strict
--landlock= |
Filesystem policy |
|---|---|
no |
Do not install an Xpra Landlock policy. |
default |
Broad system and user reads; writes limited to application directories. |
strict |
Reads limited to required resources; writes limited to dedicated application directories. |
Append +gpu to either enabled mode to allow access to the GPU devices, ie: --landlock=strict+gpu,
see GPU devices.
The option also works as landlock = MODE in configuration. Command line
settings override configuration. Values are case insensitive.
no, false, 0 and off select no; yes, true, 1 and on select default.
The mode is not exported to the environment: the commands started by the server inherit
the Landlock policy itself, but xpra commands run from the session do not try to install their own.
Server upgrades use the current Landlock option rather than reloading the
previous server’s saved mode.
Selecting no cannot remove restrictions inherited from a parent process.
Both enabled modes require Landlock ABI 9 or newer and fail startup on Linux if confinement cannot be installed. The option has no effect on other platforms. Thread synchronization, introduced in ABI 8, confines existing initialization threads as well as future threads. ABI 9 adds pathname Unix-socket resolution restrictions. Xpra requires both facilities.
The client LandLock subsystem parses its options in init(). The listener
subsystem creates its sockets in load(), before confinement. LandLock installs
the policy in run(), before the main loop starts connection work, including
remote starts and listen mode. Its setup_connection() hook also ensures that
confinement is installed before Xpra protocol processing. Failed enforcement
raises InitExit and aborts startup; repeated hooks do not install additional
policy layers. Both LandLock subsystems report the mode, enforcement state, ABI
and private temporary directory through get_info().
Qt, Pyglet and Tk clients do not support Landlock and require --landlock=no.
They connect synchronously and do not use the client subsystem lifecycle.
The server LandLock subsystem installs its policy in setup(), before the
remaining subsystems and listeners start.
All the server subsystems’ early_setup() methods are called before that,
which is where the session D-Bus, the PulseAudio server and the input method daemon (ibus-daemon)
are started, so these are not confined.
Subsystems declare the paths they need once confined with get_landlock_paths(),
ie: the menu subsystem’s icon cache directory.
Both client and server subsystems remove their owned private
temporary directories during lifecycle cleanup, including failed enforcement.
Each subsystem stores its temporary path and owner PID; cleanup only removes
storage owned by the current process.
default allows reads from standard system roots, the active Python installation,
the current directory, HOME, and the XDG configuration, data, cache, state and
runtime directories. It does not protect unrelated home files from being read.
Clients can write to their configured download directory and temporary directories.
Servers can write to their session and temporary directories,
and to the menu-icon cache directory when the start menu is enabled.
strict removes blanket access to HOME, the current directory, arbitrary Python
search paths and entire user XDG directories. It allows system code and resources,
the actual Python runtime and Xpra package, Xpra configuration, fonts/themes,
desktop configuration, and individual authentication files. Explicitly configured
certificate, key and password files must exist before startup. For SSH, default
identity files, known-hosts files and host-configured identities are readable;
the rest of the SSH directory remains outside the policy.
Strict writes are limited to the client’s download directory or the server’s
session and menu-icon cache directories (the latter only when the start menu is enabled),
plus explicitly configured mmap resources.
Grants for /, the whole home directory, /tmp, /var/tmp or /dev/shm are
rejected. Configure a dedicated download directory before using strict if your
normal download directory falls back to /tmp, for example in xpra.conf:
download-path = ~/Downloads
landlock = strict
Required writable directories are prepared before enforcement. Private temporary
storage is created with mode 0700 inside the download/session directory, and
temporary files and automatically allocated mmap files use it. It is reused on
exec and removed during normal client/server cleanup; helpers do not remove their parent’s
temporary files. An abrupt termination may leave it behind.
Reconnect after cleanup creates fresh private temporary storage.
Client listener sockets, including listen-mode sockets, are created before confinement. Separate directory rules
permit socket lookup and cleanup without granting general file writes. In strict
mode, new pathname sockets are denied afterward. Server display, network and
session sockets and session D-Bus are also created before enforcement.
Strict grants socket lookup for Xpra connections, the display, session/system D-Bus,
PulseAudio and SSH agents using their known paths, rather than broad runtime roots.
The PulseAudio server started by Xpra is granted socket lookup in its whole directory,
because its socket does not exist yet when the policy is installed.
Likewise for the ibus socket directory, and the directory containing its address files is readable.
Both modes allow standard devices such as /dev/null, /dev/urandom and pseudo-terminals.
Device entries cannot be created, removed or renamed. Strict permits the process’s own procfs directory and public
kernel and graphics-driver version files.
Unless explicitly configured otherwise, strict uses the in-memory GSettings
backend so desktop settings do not require shared dconf writes. Directory rules
also permit removing the emptied server session directory.
The GPU devices are not accessible unless the gpu flag is added to the mode,
ie: --landlock=default+gpu or --landlock=strict+gpu.
The kernel GPU drivers are a large attack surface, and most processes do not need them,
so they must be enabled explicitly, for:
The gpu flag grants read, write and ioctl access to the devices below /dev/dri and /dev/accel,
and to the NVIDIA devices required by CUDA: /dev/nvidiactl, /dev/nvidia-uvm and /dev/nvidia0, /dev/nvidia1, etc.
Without it, the policy logs a hint when GPU devices are present, as the codec errors may not mention Landlock,
ie: CUDA fails with no CUDA-capable device is detected.
For local mmap connections involving strict confinement, configure the same
dedicated shared directory explicitly on both peers, for example
--mmap=/run/user/1000/xpra/mmap. Create it before startup so it is recognized as
a directory. Automatic private mmap storage is not accessible to another confined
process; without a shared location, negotiation can fall back to network encoding.
Restrictions are inherited across fork and exec. Applications and helpers
started after confinement receive the same policy, including late server
commands, audio and printing helpers, and commands used to open files or URLs.
Strict mode can limit uploads, credential updates, desktop helpers and applications
which need other paths. There is no file-access broker or runtime permission prompt.
File descriptors opened before confinement retain their existing access.
Landlock denies disallowed operations; strict does not kill the process like
--seccomp=strict. Filesystem rules govern pathname Unix sockets, not the general
socket() syscall, TCP/UDP ports or abstract Unix sockets. Network-port and
IPC-scope restrictions are not enabled. Landlock can be combined with seccomp.
Add -d landlock to log the selected mode, ABI and filesystem grants. Denials
normally produce EACCES; audit details may be available in the system audit log
or kernel journal. A trace can identify the denied operation and path:
strace -f -e trace=%file,network -o /tmp/xpra-landlock.strace xpra attach :100 --landlock=strict
rg 'EACCES|EPERM' /tmp/xpra-landlock.strace