]> granicus.if.org Git - strace/commitdiff
If stdin/stdout aren't open on startup, open them to /dev/null
authorDenys Vlasenko <dvlasenk@redhat.com>
Mon, 8 Feb 2016 17:08:46 +0000 (18:08 +0100)
committerDenys Vlasenko <dvlasenk@redhat.com>
Mon, 8 Feb 2016 17:17:38 +0000 (18:17 +0100)
Otherwise, -oLOGFILE may end up using one of them. This conflicts
with the previous change, which closes stdin/out in strace.

* strace.c (init): If fcntl(F_GETFD) fails on stdin or stdout,
sanitize them: open /dev/null and dup it until fds 0,1,2
are all used up.

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
strace.c

index 35a04237c1510f47689307417cb842b0f2595344..90c64e34addec626c23b47c1096a59cf41420b9c 100644 (file)
--- a/strace.c
+++ b/strace.c
@@ -1184,6 +1184,16 @@ exec_or_die(void)
        perror_msg_and_die("exec");
 }
 
+static int open_dev_null(void)
+{
+       int fd = open("/dev/null", O_RDWR);
+       if (fd < 0) /* /dev not populated? Give me _something_... */
+               fd = open("/", O_RDWR);
+       if (fd < 0) /* shouldn't happen... */
+               perror_msg_and_die("Can't open '/'");
+       return fd;
+}
+
 static void
 startup_child(char **argv)
 {
@@ -1365,9 +1375,7 @@ startup_child(char **argv)
         * will reuse them, unexpectedly making a newly opened object "stdin").
         */
        close(0);
-       if (open("/dev/null", O_RDWR) != 0) /* /dev not populated? */
-               if (open("/", O_RDONLY) != 0) /* shouldn't happen... */
-                       perror_msg_and_die("Can't open '/'");
+       open_dev_null(); /* opens to fd#0 */
        dup2(0, 1);
 #if 0
        /* A good idea too, but we sometimes need to print error messages */
@@ -1715,6 +1723,25 @@ init(int argc, char *argv[])
                error_msg("ptrace_setoptions = %#x", ptrace_setoptions);
        test_ptrace_seize();
 
+       if (fcntl(0, F_GETFD) == -1 || fcntl(1, F_GETFD) == -1) {
+               /*
+                * Something weird with our stdin and/or stdout -
+                * for example, may be not open? In this case,
+                * ensure that none of the future opens uses them.
+                *
+                * This was seen in the wild when /proc/sys/kernel/core_pattern
+                * was set to "|/bin/strace -o/tmp/LOG PROG":
+                * kernel runs coredump helper with fd#0 open but fd#1 closed (!),
+                * therefore LOG gets opened to fd#1, and fd#1 is closed by
+                * "don't hold up stdin/out open" code soon after.
+                */
+               int fd = open_dev_null();
+               while (fd >= 0 && fd < 2)
+                       fd = dup(fd);
+               if (fd > 2)
+                       close(fd);
+       }
+
        /* Check if they want to redirect the output. */
        if (outfname) {
                /* See if they want to pipe the output. */