From: Denys Vlasenko Date: Mon, 8 Feb 2016 13:52:32 +0000 (+0100) Subject: Close stdin/out after child is forked X-Git-Tag: v4.12~589 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c9f85b38766a0e14f4f035f6d702fe57b6b9110c;p=strace Close stdin/out after child is forked Testcase: { sleep 1; yes | head -n99999; } | strace -o/dev/null sh -c 'exec <&-; sleep 9' The writer (head) will be able to perform writes to write end of the pipe. With strace call removed, head will immediately get SIGPIPE. This change fixes this: now writer immediately gets SIGPIPE with strace too. * strace.c (startup_child): Close stdin/out and reopen them to /dev/null. Signed-off-by: Denys Vlasenko --- diff --git a/strace.c b/strace.c index 614b85f9..35a04237 100644 --- a/strace.c +++ b/strace.c @@ -1353,6 +1353,27 @@ startup_child(char **argv) * to create a genuine separate stack and execute on it. */ } + /* + * A case where straced process is part of a pipe: + * { sleep 1; yes | head -n99999; } | strace -o/dev/null sh -c 'exec <&-; sleep 9' + * If strace won't close its fd#0, closing it in tracee is not enough: + * the pipe is still open, it has a reader. Thus, "head" will not get its + * SIGPIPE at once, on the first write. + * + * Preventing it by closing strace's stdin/out. + * (Don't leave fds 0 and 1 closed, this is bad practice: future opens + * 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 '/'"); + dup2(0, 1); +#if 0 + /* A good idea too, but we sometimes need to print error messages */ + if (shared_log != stderr) + dup2(0, 2); +#endif } #if USE_SEIZE