4

Not sure why this is happening. I have a test service logging some arbitrary text to stdout every 10 seconds. Here is my service file /etc/systemd/system/samplego.service:

[Unit]
Description=Sample go app
After=network.target

[Service]
SyslogIdentifier=my-samplego
ExecStart=/opt/samplego/samplego
Restart=on-failure

[Install]
WantedBy=multi-user.target 

This works well and I can see these log lines using journalctl.

However if I change a setting in /etc/systemd/journald.conf e.g. forwardtosyslog=yes. Then issue systemctl restart systemd-journald - my app stops logging and I can't see updates in journalctl -f until issue systemctl restart samplego. Do you have to restart all services after a journald restart?

12

One of the major innovations of daemontools in the middle 1990s was the idea of reliable logging. The dæmon supervisor ran two dæmons, the main dæmon and a log dæmon. It opened a pipe before invoking either, passing the write end of the pipe as the main dæmon process' standard output and the read end of the pipe as the log dæmon process' standard input. It also itself kept open file descriptors to both ends of the pipe. So if the log dæmon died, or was terminated, and then restarted, log data written into the pipe would be preserved and available to be read and logged by the freshly restarted instance of the log dæmon, because the pipe would not get closed.

The systemd designers did not learn from this design.

systemd arranges for spawned service processes, where configured, to have their standard outputs sent over a socket to a journal process. But rather than, as in the daemontools case, opening a pipe and arranging for each process to inherit the appropriate end of the pipe, systemd uses an AF_LOCAL stream socket at /run/systemd/journal/stdout. Main processes connect as clients; the log process listens as a server.

This means that the data connection has client-server socket semantics rather than inherited pipe semantics. If the server dies, the connection goes away. All buffered log data are lost, and all further data written by the main dæmon go to a closed socket and are lost. (This is partly why systemd has an IgnoreSIGPIPE setting that defaults to true. Writing log output to a closed socket also causes the kernel to attempt to kill the dæmon that is writing the log.)

So if you kill the systemd-journald process, process exit closes the socket connections to all of the dæmon processes whose outputs it is logging, and all further output from them is lost. There is no way to recover from this and reconnect the main process' outputs to the log process. One has to restart all of the main processes, so that systemd re-opens a new client connection to the (newly minted) log server.

The systemd people made a bodge to work around this in 2016. It involved adding the ability for processes to push arbitrary open file descriptors of their own choosing into process #1, and pull them later. systemd-journald does this with the server-end connections to the clients that it is logging, so that they remain open over a restart of the logging dæmon itself.

The problem with this mechanism is that it needs a lot more work to make it secure, and the systemd people do not have a good track record when it comes to designing things to be secure, as events this year alone have demonstrated. It needs a lot more work because who can push what and how many open file descriptors into process #1 and for how long needs to be access controlled and limited. Otherwise there is a wealth of possible exploits. (In the daemontools design, the service manager process itself is what opens the file descriptors, so it has absolute control over what file descriptors it is keeping open for child processes. It cannot be tricked, abused, or flooded.)

In Laurent Bercot's s6, s6-svscan does the usual daemontools thing with the pipe between the main and log services. It also has a mechanism for keeping arbitrary file descriptors open. This is not done by code running with superuser privileges inside the service manager in process #1, as in systemd. It is done by a wholly unprivileged process that runs separately from the service manager.

Further reading

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.