_pidfile
_pidfile
¶
Safe PID-file read and unlink helpers — closes the CWE-59 symlink race.
The naive Path.read_text / Path.unlink pattern follows symlinks,
which is the CWE-59
file-clobber vector: an attacker who can write the runtime dir
(normally a 0700 $XDG_RUNTIME_DIR owned by the same UID, but
overridable via TEROK_SANDBOX_RUNTIME_DIR or pathological setups
running with elevated privileges) can swap the pidfile for a symlink
to an unrelated file and cause the wrong PID to be read, or the
symlink's target to be deleted.
read_pidfile_safely
opens with O_NOFOLLOW plus a regular-file fstat check;
unlink_pidfile_safely
lstat-verifies before unlink and refuses symlinks. Both
short-circuit silently on every failure path — this is best-effort
cleanup, not a critical path.
Originally landed inline in the vault daemon lifecycle (PR #308) and
moved here so other service-lifecycle paths can reuse the identical
pattern (issue #311). Public names (no leading underscore) so
service-lifecycle modules in other subpackages can import them through
the standard from terok_sandbox._util import … surface.
read_pidfile_safely(pidfile)
¶
Read a PID from pidfile without following symlinks.
Returns the integer PID on success, or None on any failure path
(missing file, symlink, non-regular file, invalid contents).
Source code in src/terok_sandbox/_util/_pidfile.py
unlink_pidfile_safely(pidfile)
¶
Unlink pidfile only if it's a regular file (refusing symlinks).
The lstat check is what makes the difference: a plain
Path.unlink() happily removes a symlink target, which is the
file-clobber vector
(CWE-59) the
safe-handling guidance calls out. Any failure is silently ignored
— this is cleanup, not a critical path.