From 53fabd4b86e15869e13fb762686d674c64294385 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 16 Mar 2017 16:29:45 +0100 Subject: qemu-ga: obey LISTEN_PID when using systemd socket activation qemu-ga's socket activation support was not obeying the LISTEN_PID environment variable, which avoids that a process uses a socket-activation file descriptor meant for its parent. Mess can for example ensue if a process forks a children before consuming the socket-activation file descriptor and therefore setting O_CLOEXEC on it. Luckily, qemu-nbd also got socket activation code, and its copy does support LISTEN_PID. Some extra fixups are needed to ensure that the code can be used for both, but that's what this patch does. The main change is to replace get_listen_fds's "consume" argument with the FIRST_SOCKET_ACTIVATION_FD macro from the qemu-nbd code. Cc: "Richard W.M. Jones" Cc: Stefan Hajnoczi Reviewed-by: Daniel P. Berrange Signed-off-by: Paolo Bonzini --- util/systemd.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 util/systemd.c (limited to 'util/systemd.c') diff --git a/util/systemd.c b/util/systemd.c new file mode 100644 index 0000000000..d22e86c707 --- /dev/null +++ b/util/systemd.c @@ -0,0 +1,77 @@ +/* + * systemd socket activation support + * + * Copyright 2017 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Richard W.M. Jones + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/systemd.h" +#include "qemu/cutils.h" +#include "qemu/error-report.h" + +#ifndef _WIN32 +unsigned int check_socket_activation(void) +{ + const char *s; + unsigned long pid; + unsigned long nr_fds; + unsigned int i; + int fd; + int err; + + s = getenv("LISTEN_PID"); + if (s == NULL) { + return 0; + } + err = qemu_strtoul(s, NULL, 10, &pid); + if (err) { + return 0; + } + if (pid != getpid()) { + return 0; + } + + s = getenv("LISTEN_FDS"); + if (s == NULL) { + return 0; + } + err = qemu_strtoul(s, NULL, 10, &nr_fds); + if (err) { + return 0; + } + assert(nr_fds <= UINT_MAX); + + /* So these are not passed to any child processes we might start. */ + unsetenv("LISTEN_FDS"); + unsetenv("LISTEN_PID"); + + /* So the file descriptors don't leak into child processes. */ + for (i = 0; i < nr_fds; ++i) { + fd = FIRST_SOCKET_ACTIVATION_FD + i; + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { + /* If we cannot set FD_CLOEXEC then it probably means the file + * descriptor is invalid, so socket activation has gone wrong + * and we should exit. + */ + error_report("Socket activation failed: " + "invalid file descriptor fd = %d: %m", + fd); + exit(EXIT_FAILURE); + } + } + + return (unsigned int) nr_fds; +} + +#else /* !_WIN32 */ +unsigned int check_socket_activation(void) +{ + return 0; +} +#endif -- cgit v1.2.3