From 1cb2e4a6af50dfb8f5641966b5d42afc85a70c15 Mon Sep 17 00:00:00 2001 From: Kevin Willford Date: Wed, 28 Nov 2018 09:43:37 -0700 Subject: [PATCH 1/2] run-command: allow child to close all parent file descriptors When starting a child process using fork() all file descriptors of the parent are inherited by the child process. This can cause deadlocks in git when the following happens. 1. Start a child process - this opens pipes in the parent process in order for the parent to read/write data to the child. The child process dups the end of the pipes to stdin/stdout/stderr. 2. Parent does some work that starts another child process - this process will get the open pipes that the parent is using to communicate with the first child process. 3. Parent writes to the first child through pipe and closes it. 4. Parent reads from the first child through pipe while the second child process is still running. 5. Parent is deadlocked on the read because although the first child is done and pipes were closed, the second child has the file descriptors to the pipes for the first child which are still open. Since the parent might not know that it is spawning a child process, all possible file descriptors will to be closed on exec if flag is set. --- run-command.c | 6 ++++++ run-command.h | 1 + 2 files changed, 7 insertions(+) diff --git a/run-command.c b/run-command.c index 1c5a6c224ecf43..b46ed2546ebb67 100644 --- a/run-command.c +++ b/run-command.c @@ -716,6 +716,7 @@ int start_command(struct child_process *cmd) { int notify_pipe[2]; int null_fd = -1; + int fd; char **childenv; struct argv_array argv = ARGV_ARRAY_INIT; struct child_err cerr; @@ -795,6 +796,11 @@ int start_command(struct child_process *cmd) if (cmd->dir && chdir(cmd->dir)) child_die(CHILD_ERR_CHDIR); + if (cmd->close_parent_file_descriptors) { + for (fd = 3; fd < 256; ++fd) + set_cloexec(fd); + } + /* * restore default signal handlers here, in case * we catch a signal right before execve below diff --git a/run-command.h b/run-command.h index e71ddd65afe5e1..e0295f56caffb2 100644 --- a/run-command.h +++ b/run-command.h @@ -49,6 +49,7 @@ struct child_process { unsigned use_shell:1; unsigned clean_on_exit:1; unsigned wait_after_clean:1; + unsigned close_parent_file_descriptors:1; void (*clean_on_exit_handler)(struct child_process *process); void *clean_on_exit_handler_cbdata; }; From c6d16341551eb77081e5b417085f779b187135b6 Mon Sep 17 00:00:00 2001 From: Kevin Willford Date: Thu, 29 Nov 2018 10:25:35 -0700 Subject: [PATCH 2/2] sub-process: turn on the close_parent_file_descriptors flag --- sub-process.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sub-process.c b/sub-process.c index 3f4af935557c5e..22446fdee0c4b2 100644 --- a/sub-process.c +++ b/sub-process.c @@ -87,6 +87,7 @@ int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, co process->in = -1; process->out = -1; process->clean_on_exit = 1; + process->close_parent_file_descriptors = 1; process->clean_on_exit_handler = subprocess_exit_handler; process->trace2_child_class = "subprocess";