service: tell service processes that the fdstore is available via an env var

This commit is contained in:
Lennart Poettering 2023-04-05 15:48:31 +02:00
parent f643ca1767
commit 75b29fda71
5 changed files with 54 additions and 33 deletions

View file

@ -238,25 +238,29 @@
<varlistentry>
<term>FDSTORE=1</term>
<listitem><para>Stores additional file descriptors in the service manager. File descriptors sent this way will
be maintained per-service by the service manager and will later be handed back using the usual file descriptor
passing logic at the next invocation of the service (e.g. when it is restarted), see
<citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>. This is
useful for implementing services that can restart after an explicit request or a crash without losing
state. Any open sockets and other file descriptors which should not be closed during the restart may be stored
this way. Application state can either be serialized to a file in <filename>/run/</filename>, or better, stored
in a <citerefentry><refentrytitle>memfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry> memory
file descriptor. Note that the service manager will accept messages for a service only if its
<listitem><para>Stores additional file descriptors in the service manager. File descriptors sent this
way will be maintained per-service by the service manager and will later be handed back using the
usual file descriptor passing logic at the next invocation of the service (e.g. when it is
restarted), see
<citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
This is useful for implementing services that can restart after an explicit request or a crash
without losing state. Any open sockets and other file descriptors which should not be closed during
the restart may be stored this way. Application state can either be serialized to a file in
<filename>/run/</filename>, or better, stored in a
<citerefentry><refentrytitle>memfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry>
memory file descriptor. Note that the service manager will accept messages for a service only if its
<varname>FileDescriptorStoreMax=</varname> setting is non-zero (defaults to zero, see
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>). If
<varname>FDPOLL=0</varname> is not set and the file descriptors sent are pollable (see
<citerefentry><refentrytitle>epoll_ctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>), then any
<constant>EPOLLHUP</constant> or <constant>EPOLLERR</constant> event seen on them will result in their
automatic removal from the store. Multiple arrays of file descriptors may be sent in separate messages, in
which case the arrays are combined. Note that the service manager removes duplicate (pointing to the same
object) file descriptors before passing them to the service. When a service is stopped, its file descriptor
store is discarded and all file descriptors in it are closed. Use <function>sd_pid_notify_with_fds()</function>
to send messages with <literal>FDSTORE=1</literal>, see below.</para></listitem>
<citerefentry><refentrytitle>epoll_ctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>), then
any <constant>EPOLLHUP</constant> or <constant>EPOLLERR</constant> event seen on them will result in
their automatic removal from the store. Multiple arrays of file descriptors may be sent in separate
messages, in which case the arrays are combined. Note that the service manager removes duplicate
(pointing to the same object) file descriptors before passing them to the service. When a service is
stopped, its file descriptor store is discarded and all file descriptors in it are closed. Use
<function>sd_pid_notify_with_fds()</function> to send messages with <literal>FDSTORE=1</literal>, see
below. The service manager will set the <varname>$FDSTORE</varname> environment variable for services
that have the file descriptor store enabled.</para></listitem>
</varlistentry>
<varlistentry>
@ -348,19 +352,14 @@
<function>sd_notify()</function> and
<function>sd_notifyf()</function>.</para>
<para><function>sd_pid_notify_with_fds()</function> is similar to
<function>sd_pid_notify()</function> but takes an additional array
of file descriptors. These file descriptors are sent along the
notification message to the service manager. This is particularly
useful for sending <literal>FDSTORE=1</literal> messages, as
described above. The additional arguments are a pointer to the
file descriptor array plus the number of file descriptors in the
array. If the number of file descriptors is passed as 0, the call
is fully equivalent to <function>sd_pid_notify()</function>, i.e.
no file descriptors are passed. Note that sending file descriptors
to the service manager on messages that do not expect them (i.e.
without <literal>FDSTORE=1</literal>) they are immediately closed
on reception.</para>
<para><function>sd_pid_notify_with_fds()</function> is similar to <function>sd_pid_notify()</function>
but takes an additional array of file descriptors. These file descriptors are sent along the notification
message to the service manager. This is particularly useful for sending <literal>FDSTORE=1</literal>
messages, as described above. The additional arguments are a pointer to the file descriptor array plus
the number of file descriptors in the array. If the number of file descriptors is passed as 0, the call
is fully equivalent to <function>sd_pid_notify()</function>, i.e. no file descriptors are passed. Note
that file descriptors sent to the service manager on a message without <literal>FDSTORE=1</literal> are
immediately closed on reception.</para>
<para><function>sd_notify_barrier()</function> allows the caller to
synchronize against reception of previously sent notification messages

View file

@ -3476,8 +3476,7 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
<varlistentry>
<term><varname>$NOTIFY_SOCKET</varname></term>
<listitem><para>The socket
<function>sd_notify()</function> talks to. See
<listitem><para>The socket <function>sd_notify()</function> talks to. See
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para></listitem>
</varlistentry>
@ -3799,6 +3798,19 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
convey.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>$FDSTORE</varname></term>
<listitem><para>If the file descriptor store is enabled for a service
(i.e. <varname>FileDescriptorStoreMax=</varname> is set to a non-zero value, see
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details), this environment variable will be set to the maximum number of permitted entries, as
per the setting. Applications may check this environment variable before sending file descriptors
to the service manager via <function>sd_pid_notify_with_fds()</function> (see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> for
details).</para></listitem>
</varlistentry>
</variablelist>
<para>For system services, when <varname>PAMName=</varname> is enabled and <command>pam_systemd</command> is part

View file

@ -1089,7 +1089,12 @@
allow unprivileged clients to query the list of currently open file descriptors of a
service. Sensitive data may hence be safely placed inside the referenced files, but should not be
attached to the metadata (e.g. included in filenames) of the stored file
descriptors.</para></listitem>
descriptors.</para>
<para>If this option is set to a non-zero value the <varname>$FDSTORE</varname> environment variable
will be set for processes invoked for this service. See
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details.</para></listitem>
</varlistentry>
<varlistentry>

View file

@ -1677,7 +1677,7 @@ static int service_spawn_internal(
if (r < 0)
return r;
our_env = new0(char*, 12);
our_env = new0(char*, 13);
if (!our_env)
return -ENOMEM;
@ -1686,6 +1686,10 @@ static int service_spawn_internal(
return -ENOMEM;
exec_params.notify_socket = UNIT(s)->manager->notify_socket;
if (s->n_fd_store_max > 0)
if (asprintf(our_env + n_env++, "FDSTORE=%u", s->n_fd_store_max) < 0)
return -ENOMEM;
}
if (s->main_pid > 0)

View file

@ -53,6 +53,7 @@ cat >> "$MYSCRIPT" <<'EOF'
#!/usr/bin/env bash
set -eux
set -o pipefail
test "$FDSTORE" -eq 7
N="/tmp/$RANDOM"
echo $RANDOM > "$N"
systemd-notify --fd=4 --fdname=quux --pid=parent 4< "$N"