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 <dvlasenk@redhat.com>
This commit is contained in:
Denys Vlasenko
2016-02-08 14:52:32 +01:00
parent 7469e252fa
commit c9f85b3876

View File

@ -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