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" <rjones@redhat.com> Cc: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
		
			
				
	
	
		
			78 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			78 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * systemd socket activation support
 | |
|  *
 | |
|  * Copyright 2017 Red Hat, Inc. and/or its affiliates
 | |
|  *
 | |
|  * Authors:
 | |
|  *  Richard W.M. Jones <rjones@redhat.com>
 | |
|  *
 | |
|  * 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
 |