commit:     a3ff1534945c3898332b2481c9fd355dfbd56e1f
Author:     Mike Frysinger <vapier <AT> gentoo <DOT> org>
AuthorDate: Sat Jun 23 18:52:51 2012 +0000
Commit:     Mike Frysinger <vapier <AT> gentoo <DOT> org>
CommitDate: Sat Jun 23 18:52:51 2012 +0000
URL:        https://gitweb.gentoo.org/proj/sandbox.git/commit/?id=a3ff1534

libsandbox: clean up open file handles in parent tracing process

Currently, if a non-static app sets up a pipe (with cloexec enabled) and
executes a static app, the handle to that pipe is left open in the parent
process.  This causes trouble when the parent is waiting for that to be
closed immediately.

Since none of the fds in the forked parent process matter to us, we can
just go ahead and clean up all fds before we start tracing the child.

URL: http://bugs.gentoo.org/364877
Reported-by: Victor Stinner <victor.stinner <AT> haypocalc.com>
Signed-off-by: Mike Frysinger <vapier <AT> gentoo.org>

 libsandbox/trace.c           |  3 +-
 libsbutil/sb_close.c         | 26 +++++++++++-
 libsbutil/sbutil.h           |  1 +
 tests/Makefile.am            |  2 +
 tests/pipe-fork_static_tst.c | 18 +++++++++
 tests/pipe-fork_tst.c        | 95 ++++++++++++++++++++++++++++++++++++++++++++
 tests/script-9.sh            |  5 +++
 tests/script.at              |  1 +
 8 files changed, 149 insertions(+), 2 deletions(-)

diff --git a/libsandbox/trace.c b/libsandbox/trace.c
index 32ad2d6..dfbab18 100644
--- a/libsandbox/trace.c
+++ b/libsandbox/trace.c
@@ -504,8 +504,9 @@ void trace_main(const char *filename, char *const argv[])
                /* Not all kernel versions support this, so ignore return */
                ptrace(PTRACE_SETOPTIONS, trace_pid, NULL, (void 
*)PTRACE_O_TRACESYSGOOD);
 #endif
+               sb_close_all_fds();
                trace_loop();
-               return;
+               sb_ebort("ISE: child should have quit, as should we\n");
        }
 
        sb_debug("child setting up ...");

diff --git a/libsbutil/sb_close.c b/libsbutil/sb_close.c
index 17a4560..5379197 100644
--- a/libsbutil/sb_close.c
+++ b/libsbutil/sb_close.c
@@ -3,7 +3,7 @@
  *
  * IO functions.
  *
- * Copyright 1999-2008 Gentoo Foundation
+ * Copyright 1999-2012 Gentoo Foundation
  * Licensed under the GPL-2
  */
 
@@ -29,3 +29,27 @@ int sb_close(int fd)
 
        return res;
 }
+
+/* Quickly close all the open fds (good for daemonization) */
+void sb_close_all_fds(void)
+{
+       DIR *dirp;
+       struct dirent *de;
+       int dfd, fd;
+       const char *fd_dir = sb_get_fd_dir();
+
+       dirp = opendir(fd_dir);
+       if (!dirp)
+               sb_ebort("could not process %s\n", fd_dir);
+       dfd = dirfd(dirp);
+
+       while ((de = readdir(dirp)) != NULL) {
+               if (de->d_name[0] == '.')
+                       continue;
+               fd = atoi(de->d_name);
+               if (fd != dfd)
+                       close(fd);
+       }
+
+       closedir(dirp);
+}

diff --git a/libsbutil/sbutil.h b/libsbutil/sbutil.h
index 02b88cb..479734b 100644
--- a/libsbutil/sbutil.h
+++ b/libsbutil/sbutil.h
@@ -97,6 +97,7 @@ int sb_open(const char *path, int flags, mode_t mode);
 size_t sb_read(int fd, void *buf, size_t count);
 size_t sb_write(int fd, const void *buf, size_t count);
 int sb_close(int fd);
+void sb_close_all_fds(void);
 int sb_copy_file_to_fd(const char *file, int ofd);
 
 /* Reliable output */

diff --git a/tests/Makefile.am b/tests/Makefile.am
index cd8f9c2..1d32e2e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -72,6 +72,8 @@ check_PROGRAMS = \
        \
        getcwd-gnulib_tst \
        libsigsegv_tst \
+       pipe-fork_tst \
+       pipe-fork_static_tst \
        sb_printf_tst \
        sigsuspend-zsh_tst \
        sigsuspend-zsh_static_tst

diff --git a/tests/pipe-fork_static_tst.c b/tests/pipe-fork_static_tst.c
new file mode 100644
index 0000000..3f4839e
--- /dev/null
+++ b/tests/pipe-fork_static_tst.c
@@ -0,0 +1,18 @@
+/*
+https://bugs.gentoo.org/364877
+written by Victor Stinner <[email protected]>
+*/
+
+#include "headers.h"
+
+int main(int argc, char *argv[])
+{
+       const size_t n = 1024* 1024;
+       char *data;
+       alarm(10);
+       data = malloc(n);
+       memset(data, 'a', n);
+       if (write(1, data, n)) {}
+       free(data);
+       return 0;
+}

diff --git a/tests/pipe-fork_tst.c b/tests/pipe-fork_tst.c
new file mode 100644
index 0000000..72669bf
--- /dev/null
+++ b/tests/pipe-fork_tst.c
@@ -0,0 +1,95 @@
+/*
+https://bugs.gentoo.org/364877
+written by Victor Stinner <[email protected]>
+*/
+
+#include "headers.h"
+
+static void cloexec(int fd)
+{
+       int flags;
+
+       flags = fcntl(fd, F_GETFD);
+       if (flags == -1) {
+               perror("fcntl(F_GETFD)");
+               exit(1);
+       }
+       fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+}
+
+int main(int argc, char *argv[])
+{
+       int err;
+       pid_t child;
+       int outpipe[2];
+       int errpipe[2];
+       ssize_t n;
+       char buffer[4096];
+       char *dir = dirname(argv[0]);
+       char *argv0 = "pipe-fork_static_tst";
+       char *child_argv[] = {argv0, NULL};
+
+       if (dir)
+               if (chdir(dir)) {}
+
+       err = pipe(outpipe);
+       if (err) {
+               perror("open");
+               return 1;
+       }
+
+       err = pipe(errpipe);
+       if (err) {
+               perror("open");
+               return 1;
+       }
+       cloexec(errpipe[0]);
+       cloexec(errpipe[1]);
+
+       child = fork();
+       if (child < 0) {
+               perror("fork");
+               return 1;
+       }
+       if (child == 0) {
+               close(outpipe[0]);
+               close(errpipe[0]);
+
+               dup2(outpipe[1], 1);
+               execvp(argv0, child_argv);
+               execv(argv0, child_argv);
+
+               perror("execvp");
+               return 1;
+       } else {
+               close(outpipe[1]);
+               close(errpipe[1]);
+
+               printf("wait errpipe..."); fflush(stdout);
+               n = read(errpipe[0], buffer, sizeof(buffer));
+               if (n < 0) {
+                       perror("fcntl(F_GETFD)");
+                       return 1;
+               }
+               printf(" done ");
+
+               while (1) {
+                       n = read(outpipe[0], buffer, sizeof(buffer));
+                       if (n < 0) {
+                               perror("fcntl(F_GETFD)");
+                               return 1;
+                       }
+                       if (n == 0)
+                               break;
+               }
+
+               int status;
+               waitpid(child, &status, 0);
+               if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+                       printf("OK!");
+                       return 0;
+               }
+               printf("\nfailed! child status: %#x\n", status);
+               return 1;
+       }
+}

diff --git a/tests/script-9.sh b/tests/script-9.sh
new file mode 100755
index 0000000..dc21e64
--- /dev/null
+++ b/tests/script-9.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# verify tracing static apps with pipes #364877
+[ "${at_xfail}" = "yes" ] && exit 77 # see script-0
+
+pipe-fork_tst

diff --git a/tests/script.at b/tests/script.at
index 9e8e900..b095ce1 100644
--- a/tests/script.at
+++ b/tests/script.at
@@ -6,3 +6,4 @@ SB_CHECK(5)
 SB_CHECK(6,,,8)
 SB_CHECK(7)
 SB_CHECK(8)
+SB_CHECK(9, [wait errpipe... done OK!])

Reply via email to