Stop server-provided values from reaching a shell or escaping /dsc/seafile

Commands were joined into a string and passed to "su -c", so a login shell
parsed every interpolated value. A library name is chosen on the server, and
"sync -d /dsc/seafile/<name>" put it straight into that string: a library
named 'Docs; touch /tmp/pwned; #' ran as an arbitrary command. Confirmed
against the built image before and after this change.

Every command is now an argument list executed by "runuser --", which execs
directly with no shell. runuser -u sets the same HOME and a PATH that still
finds the seaf-cli wrapper, so the daemon environment is unchanged.

The password no longer needs its surrounding quotes, which also fixes
passwords containing quotes, dollar signs, and backticks.

Library names are untrusted, so dsc/paths.py reduces each one to a single
path component and proves the result stays under the libraries directory
with symlinks resolved. Empty, ".", "..", and names containing a separator
are skipped with a warning; names that would collide are suffixed with their
library ID rather than sharing a directory.

Tests cover quotes, command substitutions, separators, newlines, absolute
paths, parent traversal, Unicode, and colliding names. They run in a separate
CI job so application failures stay distinguishable from packaging failures.
This commit is contained in:
Maxim Shulga committed 2026-08-02 16:53:19 -07:00
1 parent 50ede0b2f9
commit c15763d9f8
12 files changed
+478 -38

No files matched your search

+8
View File
@@ -58,6 +58,14 @@ volumes:
Libraries will be synced in subdirectories of `/dsc/seafile` directory inside
container. You can mount it to host directory to access files.
The subdirectory is named after the library, with whitespace replaced by
underscores. A library is skipped with a warning when its name cannot be a
directory of its own: an empty name, `.`, `..`, or a name containing `/`. Two
libraries whose names would produce the same directory both get their library
ID appended, so they never share one. Everything is created under the
libraries directory (`/dsc/seafile`, or the deprecated `/data` when that
exists); a library name can never place it elsewhere.
`hostname` parameter is optional, but it's recommended to set it to some unique
value, it will be shown in Seafile webUI as client name (`terminal-dsc` in
given example).