1
0
mirror of https://github.com/systemd/systemd synced 2025-11-19 08:44:44 +01:00

Compare commits

...

2 Commits

Author SHA1 Message Date
Ryan Brue
e80c5eb6e6 man: Clarify usage of /usr/share/factory/ in programs
As discussed in this thread:
https://github.com/redhat-performance/tuned/issues/798#issuecomment-3197697654

/usr/share/factory/ is not intended to be read from by programs,
but the wording in the FHS can be misread to think that programs
should be using /usr/share/factory/ as the vendor supplied configuration
directory rather than something like /usr/lib/foo/ or /usr/share/foo/.

This commit points developers to the UAPI configuration spec for how to
make their programs hermetic /usr/ compatible.

Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>
2025-10-22 11:07:23 +02:00
Daniel Foster
c7a444a9c1 tree-wide: extend $LISTEN_FDS protocol with $LISTEN_PIDFDID
Although extremely unlikely, there is a race present in solely checking the
$LISTEN_PID environment variable, due to PID recycling. Fix that by introducing
$LISTEN_PIDFDID, which contains the 64-bit ID of a pidfd for the child process
that is not subject to recycling.
2025-10-22 09:34:14 +02:00
17 changed files with 130 additions and 25 deletions

4
TODO
View File

@ -529,8 +529,8 @@ Features:
be established on top of dm-crypt or dm-verity devices, or an allowlist of
file systems (which should probably include vfat, for compat with the ESP)
* $LISTEN_PID, $SYSTEMD_EXECPID env vars that the service manager sets should
be augmented with $LISTEN_PIDFDID, and $SYSTEMD_EXECPIDFD (and similar for
* $SYSTEMD_EXECPID that the service manager sets should
be augmented with $SYSTEMD_EXECPIDFD (and similar for
other env vars we might send).
* port copy.c over to use LabelOps for all labelling.

View File

@ -65,9 +65,9 @@ string of choice, which may be used to identify the fd later.
Whenever the service is restarted the fds in its fdstore will be passed to the
new instance following the same protocol as for socket activation fds. i.e. the
`$LISTEN_FDS`, `$LISTEN_PIDS`, `$LISTEN_FDNAMES` environment variables will be
set (the latter will be populated from the `FDNAME=…` field mentioned
above). See
`$LISTEN_FDS`, `$LISTEN_PID`, `$LISTEN_PIDFDID`, and `$LISTEN_FDNAMES`
environment variables will be set (the latter will be populated from the
`FDNAME=…` field mentioned above). See
[`sd_listen_fds()`](https://www.freedesktop.org/software/systemd/man/sd_listen_fds.html)
for details on receiving such fds in a service. (Note that the name set in
`FDNAME=…` does not need to be unique, which is useful when operating with

View File

@ -230,7 +230,9 @@
<listitem><para>Repository for vendor-supplied default configuration files. This directory should be
populated with pristine vendor versions of all configuration files that may be placed in
<filename>/etc/</filename>. This is useful to compare the local configuration of a system with vendor
defaults and to populate the local configuration with defaults.</para></listitem>
defaults and to populate the local configuration with defaults. Software should not read configuration
settings directly from <filename>/usr/share/factory/</filename>. Those files will be copied to
other locations if appropriate, and should only be read from there.</para></listitem>
</varlistentry>
<varlistentry>
@ -239,7 +241,9 @@
<listitem><para>Similar to
<filename>/usr/share/factory/etc/</filename>, but for vendor
versions of files in the variable, persistent data directory
<filename>/var/</filename>.</para></listitem>
<filename>/var/</filename>. The same recommendations as for
<filename>/usr/share/factory/etc/</filename> apply here.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -93,10 +93,10 @@
<para>If the <parameter>unset_environment</parameter> parameter is
non-zero, <function>sd_listen_fds()</function> will unset the
<varname>$LISTEN_FDS</varname>, <varname>$LISTEN_PID</varname> and
<varname>$LISTEN_FDNAMES</varname> environment variables before
returning (regardless of whether the function call itself
succeeded or not). Further calls to
<varname>$LISTEN_FDS</varname>, <varname>$LISTEN_PID</varname>,
<varname>$LISTEN_PIDFDID</varname>, and <varname>$LISTEN_FDNAMES</varname>
environment variables before returning (regardless of whether the function
call itself succeeded or not). Further calls to
<function>sd_listen_fds()</function> will then return zero, but the
variables are no longer inherited by child processes.</para>
@ -175,8 +175,9 @@
<para>On failure, these calls returns a negative errno-style error
code. If
<varname>$LISTEN_FDS</varname>/<varname>$LISTEN_PID</varname> was
not set or was not correctly set for this daemon and hence no file
descriptors were received, 0 is returned. Otherwise, the number of
not set, or one of those variables or <varname>$LISTEN_PIDFDID</varname>
was not correctly set for this daemon, no file
descriptors were received and 0 is returned. Otherwise, the number of
file descriptors passed is returned. The application may find them
starting with file descriptor SD_LISTEN_FDS_START, i.e. file
descriptor 3.</para>
@ -190,7 +191,10 @@
<para>Internally, <function>sd_listen_fds()</function> checks
whether the <varname>$LISTEN_PID</varname> environment variable
equals the daemon PID. If not, it returns immediately. Otherwise,
equals the daemon PID. If not, it returns immediately. Since version 259,
if the <varname>$LISTEN_PIDFDID</varname> environment variable is set,
it also checks whether it matches the inode of this process' pidfd.
If both of these checks pass,
it parses the number passed in the <varname>$LISTEN_FDS</varname>
environment variable, then sets the FD_CLOEXEC flag for the parsed
number of file descriptors starting from SD_LISTEN_FDS_START.
@ -209,6 +213,7 @@
<variablelist class='environment-variables'>
<varlistentry>
<term><varname>$LISTEN_PID</varname></term>
<term><varname>$LISTEN_PIDFDID</varname></term>
<term><varname>$LISTEN_FDS</varname></term>
<term><varname>$LISTEN_FDNAMES</varname></term>

View File

@ -157,6 +157,7 @@
<varlistentry>
<term><varname>$LISTEN_FDS</varname></term>
<term><varname>$LISTEN_PID</varname></term>
<term><varname>$LISTEN_PIDFDID</varname></term>
<term><varname>$LISTEN_FDNAMES</varname></term>
<listitem><para>See

View File

@ -4207,6 +4207,7 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
<varlistentry>
<term><varname>$LISTEN_FDS</varname></term>
<term><varname>$LISTEN_PID</varname></term>
<term><varname>$LISTEN_PIDFDID</varname></term>
<term><varname>$LISTEN_FDNAMES</varname></term>
<listitem><para>Information about file descriptors passed to a

View File

@ -720,6 +720,7 @@
<varlistentry>
<term><varname>$LISTEN_PID</varname></term>
<term><varname>$LISTEN_PIDFDID</varname></term>
<term><varname>$LISTEN_FDS</varname></term>
<term><varname>$LISTEN_FDNAMES</varname></term>

View File

@ -59,6 +59,7 @@
#include "osc-context.h"
#include "pam-util.h"
#include "path-util.h"
#include "pidfd-util.h"
#include "pidref.h"
#include "proc-cmdline.h"
#include "process-util.h"
@ -2014,7 +2015,7 @@ static int build_environment(
assert(cgroup_context);
assert(ret);
#define N_ENV_VARS 19
#define N_ENV_VARS 20
our_env = new0(char*, N_ENV_VARS + _EXEC_DIRECTORY_TYPE_MAX + 1);
if (!our_env)
return -ENOMEM;
@ -2026,6 +2027,13 @@ static int build_environment(
return -ENOMEM;
our_env[n_env++] = x;
uint64_t pidfdid;
if (pidfd_get_inode_id_self_cached(&pidfdid) >= 0) {
if (asprintf(&x, "LISTEN_PIDFDID=%"PRIu64, pidfdid) < 0)
return -ENOMEM;
our_env[n_env++] = x;
}
if (asprintf(&x, "LISTEN_FDS=%zu", n_fds) < 0)
return -ENOMEM;
our_env[n_env++] = x;

View File

@ -623,6 +623,7 @@ static char** sanitize_environment(char **l) {
"LISTEN_FDNAMES",
"LISTEN_FDS",
"LISTEN_PID",
"LISTEN_PIDFDID",
"LOGS_DIRECTORY",
"LOG_NAMESPACE",
"MAINPID",

View File

@ -35,6 +35,7 @@ static void unsetenv_listen(bool unset_environment) {
return;
assert_se(unsetenv("LISTEN_PID") == 0);
assert_se(unsetenv("LISTEN_PIDFDID") == 0);
assert_se(unsetenv("LISTEN_FDS") == 0);
assert_se(unsetenv("LISTEN_FDNAMES") == 0);
}
@ -60,6 +61,23 @@ _public_ int sd_listen_fds(int unset_environment) {
goto finish;
}
e = getenv("LISTEN_PIDFDID");
if (e) {
uint64_t own_pidfdid, pidfdid;
r = safe_atou64(e, &pidfdid);
if (r < 0)
goto finish;
if (pidfd_get_inode_id_self_cached(&own_pidfdid) >= 0) {
/* Is this *really* for us? */
if (pidfdid != own_pidfdid) {
r = 0;
goto finish;
}
}
}
e = getenv("LISTEN_FDS");
if (!e) {
r = 0;

View File

@ -24,6 +24,7 @@
#include "log.h"
#include "mkdir.h"
#include "path-util.h"
#include "pidfd-util.h"
#include "process-util.h"
#include "socket-util.h"
#include "string-table.h"
@ -266,6 +267,18 @@ _public_ int sd_varlink_connect_exec(sd_varlink **ret, const char *_command, cha
xsprintf(spid, PID_FMT, pid);
uint64_t pidfdid;
if (pidfd_get_inode_id_self_cached(&pidfdid) >= 0) {
char spidfdid[DECIMAL_STR_MAX(uint64_t)+1];
xsprintf(spidfdid, "%" PRIu64, pidfdid);
if (setenv("LISTEN_PIDFDID", spidfdid, /* override= */ true) < 0) {
log_debug_errno(errno,
"Failed to set environment variable 'LISTEN_PIDFDID': %m");
_exit(EXIT_FAILURE);
}
}
STRV_FOREACH_PAIR(a, b, setenv_list) {
if (setenv(*a, *b, /* override= */ true) < 0) {
log_debug_errno(errno, "Failed to set environment variable '%s': %m", *a);

View File

@ -14,6 +14,7 @@
#include "format-util.h"
#include "log.h"
#include "mountfsd-manager.h"
#include "pidfd-util.h"
#include "process-util.h"
#include "set.h"
#include "signal-util.h"
@ -165,6 +166,17 @@ static int start_one_worker(Manager *m) {
_exit(EXIT_FAILURE);
}
uint64_t pidfdid;
if (pidfd_get_inode_id_self_cached(&pidfdid) >= 0) {
char pidfdids[DECIMAL_STR_MAX(uint64_t)];
xsprintf(pidfdids, "%" PRIu64, pidfdid);
if (setenv("LISTEN_PIDFDID", pidfdids, 1) < 0) {
log_error_errno(errno, "Failed to set $LISTEN_PIDFDID: %m");
_exit(EXIT_FAILURE);
}
}
if (setenv("LISTEN_FDS", "1", 1) < 0) {
log_error_errno(errno, "Failed to set $LISTEN_FDS: %m");
_exit(EXIT_FAILURE);

View File

@ -20,6 +20,7 @@
#include "mkdir.h"
#include "nsresourced-manager.h"
#include "parse-util.h"
#include "pidfd-util.h"
#include "process-util.h"
#include "recurse-dir.h"
#include "set.h"
@ -201,6 +202,17 @@ static int start_one_worker(Manager *m) {
_exit(EXIT_FAILURE);
}
uint64_t pidfdid;
if (pidfd_get_inode_id_self_cached(&pidfdid) >= 0) {
char pidfdids[DECIMAL_STR_MAX(uint64_t)];
xsprintf(pidfdids, "%" PRIu64, pidfdid);
if (setenv("LISTEN_PIDFDID", pidfdids, 1) < 0) {
log_error_errno(errno, "Failed to set $LISTEN_PIDFDID: %m");
_exit(EXIT_FAILURE);
}
}
if (setenv("LISTEN_FDS", "1", 1) < 0) {
log_error_errno(errno, "Failed to set $LISTEN_FDS: %m");
_exit(EXIT_FAILURE);

View File

@ -17,6 +17,7 @@
#include "format-util.h"
#include "log.h"
#include "main-func.h"
#include "pidfd-util.h"
#include "pretty-print.h"
#include "process-util.h"
#include "socket-netlink.h"
@ -186,6 +187,13 @@ static int exec_process(char * const *argv, int start_fd, size_t n_fds) {
if (r < 0)
return r;
uint64_t pidfdid;
if (pidfd_get_inode_id_self_cached(&pidfdid) >= 0) {
r = strv_extendf(&envp, "LISTEN_PIDFDID=%" PRIu64, pidfdid);
if (r < 0)
return r;
}
if (arg_fdnames) {
_cleanup_free_ char *names = NULL;
size_t len;

View File

@ -55,16 +55,16 @@ _SD_BEGIN_DECLARATIONS;
/*
Returns how many file descriptors have been passed, or a negative
errno code on failure. Optionally, removes the $LISTEN_FDS and
$LISTEN_PID file descriptors from the environment (recommended, but
problematic in threaded environments). If r is the return value of
this function you'll find the file descriptors passed as fds
SD_LISTEN_FDS_START to SD_LISTEN_FDS_START+r-1. Returns a negative
errno style error code on failure. This function call ensures that
the FD_CLOEXEC flag is set for the passed file descriptors, to make
sure they are not passed on to child processes. If FD_CLOEXEC shall
not be set, the caller needs to unset it after this call for all file
descriptors that are used.
errno code on failure. Optionally, removes the $LISTEN_FDS,
$LISTEN_PID, $LISTEN_PIDFDID, and $LISTEN_FDNAMES variables from the
environment (recommended, but problematic in threaded environments).
If r is the return value of this function you'll find the file
descriptors passed as fds SD_LISTEN_FDS_START to
SD_LISTEN_FDS_START+r-1. Returns a negative errno style error code on
failure. This function call ensures that the FD_CLOEXEC flag is set
for the passed file descriptors, to make sure they are not passed on
to child processes. If FD_CLOEXEC shall not be set, the caller needs
to unset it after this call for all file descriptors that are used.
See sd_listen_fds(3) for more information.
*/

View File

@ -15,6 +15,7 @@
#include "fs-util.h"
#include "log.h"
#include "mkdir.h"
#include "pidfd-util.h"
#include "process-util.h"
#include "set.h"
#include "signal-util.h"
@ -181,6 +182,15 @@ static int start_one_worker(Manager *m) {
_exit(EXIT_FAILURE);
}
uint64_t pidfdid;
if (pidfd_get_inode_id_self_cached(&pidfdid) >= 0) {
r = setenvf("LISTEN_PIDFDID", true, "%" PRIu64, pidfdid);
if (r < 0) {
log_error_errno(r, "Failed to set $LISTEN_PIDFDID: %m");
_exit(EXIT_FAILURE);
}
}
if (setenv("LISTEN_FDS", "1", 1) < 0) {
log_error_errno(errno, "Failed to set $LISTEN_FDS: %m");
_exit(EXIT_FAILURE);

View File

@ -20,6 +20,7 @@
#include "pager.h"
#include "parse-argument.h"
#include "parse-util.h"
#include "pidfd-util.h"
#include "pretty-print.h"
#include "process-util.h"
#include "string-util.h"
@ -876,9 +877,19 @@ static int verb_call(int argc, char *argv[], void *userdata) {
log_error_errno(r, "Failed to set $LISTEN_PID environment variable: %m");
_exit(EXIT_FAILURE);
}
uint64_t pidfdid;
if (pidfd_get_inode_id_self_cached(&pidfdid) >= 0) {
r = setenvf("LISTEN_PIDFDID", /* overwrite= */ true, "%" PRIu64, pidfdid);
if (r < 0) {
log_error_errno(r, "Failed to set $LISTEN_PIDFDID environment variable: %m");
_exit(EXIT_FAILURE);
}
}
} else {
(void) unsetenv("LISTEN_FDS");
(void) unsetenv("LISTEN_PID");
(void) unsetenv("LISTEN_PIDFDID");
}
(void) unsetenv("LISTEN_FDNAMES");