core: fix owner check of PIDFile=, and update document (#38115)

Closes #38108.
This commit is contained in:
Yu Watanabe
2025-07-08 23:58:19 +09:00
committed by GitHub
2 changed files with 16 additions and 12 deletions

View File

@@ -357,15 +357,17 @@
<varlistentry>
<term><varname>PIDFile=</varname></term>
<listitem><para>Takes a path referring to the PID file of the service. Usage of this option is recommended for
services where <varname>Type=</varname> is set to <option>forking</option>. The path specified typically points
to a file below <filename>/run/</filename>. If a relative path is specified it is hence prefixed with
<filename>/run/</filename>. The service manager will read the PID of the main process of the service from this
file after start-up of the service. The service manager will not write to the file configured here, although it
will remove the file after the service has shut down if it still exists. The PID file does not need to be owned
by a privileged user, but if it is owned by an unprivileged user additional safety restrictions are enforced:
the file may not be a symlink to a file owned by a different user (neither directly nor indirectly), and the
PID file must refer to a process already belonging to the service.</para>
<listitem><para>Takes a path referring to the PID file of the service. Usage of this option is
recommended for services where <varname>Type=</varname> is set to <option>forking</option>. The path
specified typically points to a file below <filename>/run/</filename>. If a relative path is
specified for system service, then it is hence prefixed with <filename>/run/</filename>, and prefixed
with <filename>$XDG_RUNTIME_DIR</filename> if specified in a user service. The service manager will
read the PID of the main process of the service from this file after start-up of the service. The
service manager will not write to the file configured here, although it will remove the file after
the service has shut down if it still exists. The PID file does not need to be owned by a privileged
user, but if it is owned by an unprivileged user additional safety restrictions are enforced: the
file may not be a symlink to a file owned by a different user (neither directly nor indirectly), and
the PID file must refer to a process already belonging to the service.</para>
<para>Note that PID files should be avoided in modern projects. Use <option>Type=notify</option>,
<option>Type=notify-reload</option> or <option>Type=simple</option> where possible, which does not

View File

@@ -1204,11 +1204,13 @@ static int service_load_pid_file(Service *s, bool may_warn) {
if (fstat(fileno(f), &st) < 0)
return log_unit_error_errno(UNIT(s), errno, "Failed to fstat() PID file '%s': %m", s->pid_file);
if (st.st_uid != 0)
if (st.st_uid != getuid())
return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(EPERM),
"New main PID "PID_FMT" from PID file does not belong to service, and PID file is not owned by root. Refusing.", pidref.pid);
"New main PID "PID_FMT" from PID file does not belong to service, and PID file is owned by "UID_FMT" (must be owned by "UID_FMT"). Refusing.",
pidref.pid, st.st_uid, getuid());
log_unit_debug(UNIT(s), "New main PID "PID_FMT" does not belong to service, accepting anyway since PID file is owned by root.", pidref.pid);
log_unit_debug(UNIT(s), "New main PID "PID_FMT" does not belong to service, accepting anyway since PID file is owned by "UID_FMT".",
pidref.pid, st.st_uid);
}
if (s->main_pid_known) {