journal: refresh cached credentials of stdout streams

journald assumes that getsockopt(SO_PEERCRED) correctly identifies the
process on the remote end of the socket. However, this is incorrect
according to man 7 socket:

    The returned  credentials  are  those that were in effect at the
    time of the call to connect(2) or socketpair(2).

This becomes a problem when a new process inherits the stdout stream
from a parent. First, log messages from the child process will
be attributed to the parent. Second, the struct ucred used by journald
becomes invalid as soon as the parent exits. Further sendmsg calls then
fail with ENOENT. Logs for the child process then vanish from the journal.

Fix this by using recvmsg on the stdout stream, and refreshing the cached
struct ucred if SCM_CREDENTIALS indicate a new process.

Fixes #13708
This commit is contained in:
Lorenz Bauer
2019-11-05 10:41:03 +01:00
committed by Zbigniew Jędrzejewski-Szmek
parent d7d31692bf
commit 09d0b46ab6
2 changed files with 63 additions and 2 deletions
+16
View File
@@ -74,6 +74,22 @@ cmp /expected /output
{ journalctl -ball -b -m 2>&1 || :; } | head -1 > /output
cmp /expected /output
# https://github.com/systemd/systemd/issues/13708
ID=$(systemd-id128 new)
systemd-cat -t "$ID" bash -c 'echo parent; (echo child) & wait' &
PID=$!
wait %%
journalctl --sync
# We can drop this grep when https://github.com/systemd/systemd/issues/13937
# has a fix.
journalctl -b -o export -t "$ID" --output-fields=_PID | grep '^_PID=' >/output
[[ `grep -c . /output` -eq 2 ]]
grep -q "^_PID=$PID" /output
grep -vq "^_PID=$PID" /output
# Add new tests before here, the journald restarts below
# may make tests flappy.
# Don't lose streams on restart
systemctl start forever-print-hola
sleep 3