From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Josselin Poiret via "Bug reports for GUILE, GNU's Ubiquitous Extension Language" Newsgroups: gmane.lisp.guile.bugs Subject: bug#52835: [PATCH v3] Fix child spawning closing standard fds prematurely Date: Mon, 7 Feb 2022 17:55:43 +0100 Message-ID: <20220207165543.12723-1-dev@jpoiret.xyz> References: <87lf04fxqo.fsf@jpoiret.xyz> Reply-To: Josselin Poiret Mime-Version: 1.0 Content-Transfer-Encoding: 8bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="16992"; mail-complaints-to="usenet@ciao.gmane.io" Cc: 52835@debbugs.gnu.org To: Josselin Poiret , Timothy Sample Original-X-From: bug-guile-bounces+guile-bugs=m.gmane-mx.org@gnu.org Mon Feb 07 18:29:16 2022 Return-path: Envelope-to: guile-bugs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nH7pE-0004FU-CO for guile-bugs@m.gmane-mx.org; Mon, 07 Feb 2022 18:29:16 +0100 Original-Received: from localhost ([::1]:55878 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nH7pD-0000Jb-74 for guile-bugs@m.gmane-mx.org; Mon, 07 Feb 2022 12:29:15 -0500 Original-Received: from eggs.gnu.org ([209.51.188.92]:57280) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nH7J4-0003q7-JK for bug-guile@gnu.org; Mon, 07 Feb 2022 11:56:02 -0500 Original-Received: from debbugs.gnu.org ([209.51.188.43]:49707) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nH7J4-0000ss-7V for bug-guile@gnu.org; Mon, 07 Feb 2022 11:56:02 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nH7J4-0003Ux-3V for bug-guile@gnu.org; Mon, 07 Feb 2022 11:56:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Josselin Poiret Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Mon, 07 Feb 2022 16:56:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 52835 X-GNU-PR-Package: guile X-GNU-PR-Keywords: patch Original-Received: via spool by 52835-submit@debbugs.gnu.org id=B52835.164425295513434 (code B ref 52835); Mon, 07 Feb 2022 16:56:02 +0000 Original-Received: (at 52835) by debbugs.gnu.org; 7 Feb 2022 16:55:55 +0000 Original-Received: from localhost ([127.0.0.1]:43604 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nH7Ix-0003Ub-0I for submit@debbugs.gnu.org; Mon, 07 Feb 2022 11:55:55 -0500 Original-Received: from jpoiret.xyz ([206.189.101.64]:46344) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nH7Iu-0003US-VQ for 52835@debbugs.gnu.org; Mon, 07 Feb 2022 11:55:53 -0500 Original-Received: from authenticated-user (jpoiret.xyz [206.189.101.64]) by jpoiret.xyz (Postfix) with ESMTPA id C26641851ED; Mon, 7 Feb 2022 16:55:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jpoiret.xyz; s=dkim; t=1644252951; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=4kVbElNHtrKjq7eNd+6kpfceo5oRwkjPZqJ+p/QF4mA=; b=fmN3PGoIbN5c8mk+QF90EI4KgzT+tB+bRk6bmu84G89qQPb849DGegQ8d+HX8/5l/mvQi5 eEoRLwO8PYeYq+qB/brA1BuT05yOACxY6YCDg4xVjH8LODL0hEcruIQBhRAtt5sqOtORpJ B+axU7KgC+GxDip3G0EKluYnlI9vaObqZI7rAEVAfzzVlZD+gV/T/pRJ2Z/qhn0d8wm94t NYuTNwvU/mNha8Ser9frSKk+xCa1sAEHpZ+1jnbMpG0xd1FjHdoEIQFlrO+0556JzMLZcU 7SbedKWSNo3/3P+beSROvh7AwyLaJ081Jnavbm8RESbw9/a82LAGy4iC2eFUyw== In-Reply-To: <87lf04fxqo.fsf@jpoiret.xyz> Authentication-Results: jpoiret.xyz; auth=pass smtp.auth=jpoiret@jpoiret.xyz smtp.mailfrom=dev@jpoiret.xyz X-Spamd-Bar: ++++ X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-guile@gnu.org List-Id: "Bug reports for GUILE, GNU's Ubiquitous Extension Language" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-guile-bounces+guile-bugs=m.gmane-mx.org@gnu.org Original-Sender: "bug-guile" Xref: news.gmane.io gmane.lisp.guile.bugs:10243 Archived-At: * libguile/posix.c (renumber_file_descriptor): Refactor it as dup_handle_error. (dup_handle_error, dup2_handle_error): New functions that wrap around dup and dup2 by retrying on EINTR or EBUSY, as well as erroring out on other errors. (start_child): Close standard file descriptors only after all of them have been dup2'd. --- Hello, This is a new version of the fix that should now handle possible dup/dup2 errors properly. Best, Josselin libguile/posix.c | 82 +++++++++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/libguile/posix.c b/libguile/posix.c index 3ab12b99e..dc3080b3c 100644 --- a/libguile/posix.c +++ b/libguile/posix.c @@ -1280,14 +1280,14 @@ SCM_DEFINE (scm_fork, "primitive-fork", 0, 0, 0, #endif /* HAVE_FORK */ #ifdef HAVE_FORK -/* 'renumber_file_descriptor' is a helper function for 'start_child' - below, and is specialized for that particular environment where it - doesn't make sense to report errors via exceptions. It uses dup(2) - to duplicate the file descriptor FD, closes the original FD, and - returns the new descriptor. If dup(2) fails, print an error message - to ERR and abort. */ +/* 'dup_handle_error' is a helper function for 'start_child' below, and + is specialized for that particular environment where it doesn't make + sense to report errors via exceptions. It uses dup(2) to duplicate + the file descriptor FD, does *not* close the original FD, and returns + the new descriptor. If dup(2) fails, print an error message to ERR + and abort. */ static int -renumber_file_descriptor (int fd, int err) +dup_handle_error (int fd, int err) { int new_fd; @@ -1304,7 +1304,33 @@ renumber_file_descriptor (int fd, int err) _exit (127); /* Use exit status 127, as with other exec errors. */ } - close (fd); + return new_fd; +} + +/* 'dup2_handle_error' is a helper function for 'start_child' below, and + is specialized for that particular environment where it doesn't make + sense to report errors via exceptions. It uses dup2(2) to duplicate + the file descriptor FD, does *not* close the original FD, and returns + the new descriptor. If dup2(2) fails, print an error message to ERR + and abort. */ +static int +dup2_handle_error (int fd, int to, int err) +{ + int new_fd; + + do + new_fd = dup2 (fd, to); + while (new_fd == -1 && (errno == EINTR || errno == EBUSY)); + + if (new_fd == -1) + { + /* At this point we are in the child process before exec. We + cannot safely raise an exception in this environment. */ + const char *msg = strerror (errno); + fprintf (fdopen (err, "a"), "start_child: dup failed: %s\n", msg); + _exit (127); /* Use exit status 127, as with other exec errors. */ + } + return new_fd; } #endif /* HAVE_FORK */ @@ -1357,27 +1383,25 @@ start_child (const char *exec_file, char **exec_argv, if (err == -1) err = open ("/dev/null", O_WRONLY); - if (in > 0) - { - if (out == 0) - out = renumber_file_descriptor (out, err); - if (err == 0) - err = renumber_file_descriptor (err, err); - do dup2 (in, 0); while (errno == EINTR); - close (in); - } - if (out > 1) - { - if (err == 1) - err = renumber_file_descriptor (err, err); - do dup2 (out, 1); while (errno == EINTR); - close (out); - } - if (err > 2) - { - do dup2 (err, 2); while (errno == EINTR); - close (err); - } + /* Dup each non-yet-dup2'd fd that's in the way to the next available fd, + so that we can safely dup2 to 0/1/2 without potentially overwriting + in/out/err. Note that dup2 doesn't do anything if its arguments are + equal. */ + if (out == 0) + out = dup_handle_error (out, err); + if (err == 0) + err = dup_handle_error (err, err); + dup2_handle_error (in, 0, err); + + if (err == 1) + err = dup_handle_error (err, err); + dup2_handle_error (out, 1, err); + + dup2_handle_error (err, 2, err); + + if (in > 2) close (in); + if (out > 2) close (out); + if (err > 2) close (err); execvp (exec_file, exec_argv); -- 2.34.0