From 0736d4e1a31d5cf04fb6cb4b73b6e0a70b13df45 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 8 Feb 2016 18:08:46 +0100 Subject: [PATCH] If stdin/stdout aren't open on startup, open them to /dev/null 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 --- strace.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/strace.c b/strace.c index 35a04237..90c64e34 100644 --- 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. */ -- 2.40.0