mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 07:03:38 +00:00
launch: Close file descriptors after fork (RHBZ#1123007).
This refactors existing code to close file descriptors in the recovery
process, and also adds code to close file descriptors between the
fork() and exec() of QEMU or User-Mode Linux.
The reason is to avoid leaking main process file descriptors where the
main process (or other libraries in the main process) are not setting
O_CLOEXEC at all or not setting it atomically. Python is a particular
culprit.
See also this OpenStack Nova bug report:
https://bugs.launchpad.net/nova/+bug/1313477
Thanks: Qin Zhao for identifying and characterizing the problem in Nova.
This is version 2 of this commit. This commit is identical to the
reverted commit 115fcc3432 except that
we don't close stderr.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/* libguestfs
|
||||
* Copyright (C) 2013 Red Hat Inc.
|
||||
* Copyright (C) 2013-2014 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -164,4 +164,18 @@ extern GUESTFS_DLL_PUBLIC int guestfs___add_libvirt_dom (guestfs_h *g, virDomain
|
||||
# define program_name "libguestfs"
|
||||
#endif
|
||||
|
||||
/* Close all file descriptors matching the condition. */
|
||||
#define close_file_descriptors(cond) do { \
|
||||
int max_fd = sysconf (_SC_OPEN_MAX); \
|
||||
int fd; \
|
||||
if (max_fd == -1) \
|
||||
max_fd = 1024; \
|
||||
if (max_fd > 65536) \
|
||||
max_fd = 65536; /* bound the amount of work we do here */ \
|
||||
for (fd = 0; fd < max_fd; ++fd) { \
|
||||
if (cond) \
|
||||
close (fd); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* GUESTFS_INTERNAL_FRONTEND_H_ */
|
||||
|
||||
@@ -717,6 +717,13 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
|
||||
goto dup_failed;
|
||||
|
||||
close (sv[1]);
|
||||
|
||||
/* Close any other file descriptors that we don't want to pass
|
||||
* to qemu. This prevents file descriptors which didn't have
|
||||
* O_CLOEXEC set properly from leaking into the subprocess. See
|
||||
* RHBZ#1123007.
|
||||
*/
|
||||
close_file_descriptors (fd > 2);
|
||||
}
|
||||
|
||||
/* Dump the command line (after setting up stderr above). */
|
||||
@@ -747,7 +754,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
|
||||
if (g->recovery_proc) {
|
||||
r = fork ();
|
||||
if (r == 0) {
|
||||
int i, fd, max_fd;
|
||||
int i;
|
||||
struct sigaction sa;
|
||||
pid_t qemu_pid = data->pid;
|
||||
pid_t parent_pid = getppid ();
|
||||
@@ -767,13 +774,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
|
||||
/* Close all other file descriptors. This ensures that we don't
|
||||
* hold open (eg) pipes from the parent process.
|
||||
*/
|
||||
max_fd = sysconf (_SC_OPEN_MAX);
|
||||
if (max_fd == -1)
|
||||
max_fd = 1024;
|
||||
if (max_fd > 65536)
|
||||
max_fd = 65536; /* bound the amount of work we do here */
|
||||
for (fd = 0; fd < max_fd; ++fd)
|
||||
close (fd);
|
||||
close_file_descriptors (1);
|
||||
|
||||
/* It would be nice to be able to put this in the same process
|
||||
* group as qemu (ie. setpgid (0, qemu_pid)). However this is
|
||||
|
||||
@@ -333,6 +333,9 @@ launch_uml (guestfs_h *g, void *datav, const char *arg)
|
||||
goto dup_failed;
|
||||
|
||||
close (csv[1]);
|
||||
|
||||
/* RHBZ#1123007 */
|
||||
close_file_descriptors (fd > 2 && fd != dsv[1]);
|
||||
}
|
||||
|
||||
/* Dump the command line (after setting up stderr above). */
|
||||
@@ -360,7 +363,7 @@ launch_uml (guestfs_h *g, void *datav, const char *arg)
|
||||
if (g->recovery_proc) {
|
||||
r = fork ();
|
||||
if (r == 0) {
|
||||
int i, fd, max_fd;
|
||||
int i;
|
||||
struct sigaction sa;
|
||||
pid_t vmlinux_pid = data->pid;
|
||||
pid_t parent_pid = getppid ();
|
||||
@@ -380,13 +383,7 @@ launch_uml (guestfs_h *g, void *datav, const char *arg)
|
||||
/* Close all other file descriptors. This ensures that we don't
|
||||
* hold open (eg) pipes from the parent process.
|
||||
*/
|
||||
max_fd = sysconf (_SC_OPEN_MAX);
|
||||
if (max_fd == -1)
|
||||
max_fd = 1024;
|
||||
if (max_fd > 65536)
|
||||
max_fd = 65536; /* bound the amount of work we do here */
|
||||
for (fd = 0; fd < max_fd; ++fd)
|
||||
close (fd);
|
||||
close_file_descriptors (1);
|
||||
|
||||
/* It would be nice to be able to put this in the same process
|
||||
* group as vmlinux (ie. setpgid (0, vmlinux_pid)). However
|
||||
|
||||
Reference in New Issue
Block a user