libct/nsenter: fix logging race in nsexec

As reported in issue 3119, there is a race in nsexec logging
that can lead to garbled json received by log forwarder, which
complains about it with a "failed to decode" error.

This happens because dprintf (used since the very beginning of nsexec
logging introduced in commit ba3cabf932) relies on multiple write(2)
calls, and with additional logging added by 64bb59f592 a race is
possible between runc init parent and its children.

The fix is to prepare a string and write it using a single call to
write(2).

[v2: NULLify json on error from asprintf]

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 2bab4a56f1)
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
Kir Kolyshkin
2021-07-29 14:28:18 -07:00
parent 0b77b2d1d5
commit 7cf1952fcb
+9 -2
View File
@@ -142,7 +142,7 @@ int setns(int fd, int nstype)
static void write_log(const char *level, const char *format, ...)
{
char *message = NULL, *stage = NULL;
char *message = NULL, *stage = NULL, *json = NULL;
va_list args;
int ret;
@@ -164,11 +164,18 @@ static void write_log(const char *level, const char *format, ...)
if (ret < 0)
goto out;
dprintf(logfd, "{\"level\":\"%s\", \"msg\": \"%s[%d]: %s\"}\n", level, stage, getpid(), message);
ret = asprintf(&json, "{\"level\":\"%s\", \"msg\": \"%s[%d]: %s\"}\n", level, stage, getpid(), message);
if (ret < 0) {
json = NULL;
goto out;
}
write(logfd, json, ret);
out:
free(message);
free(stage);
free(json);
}
/* XXX: This is ugly. */