Bug 197751
Summary: | select() doesn't report EBADF for closed fd's >= 256 (or >= 64 if ptraced) | ||
---|---|---|---|
Product: | IO/Storage | Reporter: | Zack Weinberg (zackw) |
Component: | Other | Assignee: | io_other |
Status: | NEW --- | ||
Severity: | normal | CC: | felix.ramold |
Priority: | P1 | ||
Hardware: | Intel | ||
OS: | Linux | ||
Kernel Version: | 4.13 | Subsystem: | |
Regression: | No | Bisected commit-id: | |
Attachments: |
test program
test program using poll() instead of select() does not show the problem |
Description
Zack Weinberg
2017-11-03 16:35:41 UTC
Created attachment 260499 [details]
test program using poll() instead of select() does not show the problem
This additional test program indicates this is a problem specific to select(); poll() will correctly return 1 with revents set to POLLNVAL for every file descriptor from 3 up to whatever the RLIMIT_NOFILE cap is.
A Stack Overflow commenter pointed out that the 256 .vs. 64 thing isn't about ptrace at all; rather, an interactive 'bash' process holds file descriptor 255 open on the terminal, therefore the kernel allocates space for 256 file descriptors in its directly forked children. But if one of those children calls execve, and then the new process image calls fork without opening any high-numbered fd's (which is what happens in either the strace or gdb scenario), the grandchild will only get the minimum 64-entry fd table. The threshold for the bug is the size of the currently-allocated fd table. To demonstrate that this is indeed the issue, let the compiled first test program be 'a.out' and then run these perl one-liners: # the threshold drops to 64 with any intermediate process; ptrace isn't involved $ perl -le 'if (fork() == 0) { exec "./a.out" } else { wait; exit $?>>8 }'; echo $? fd 64: select timed out 1 # if the intermediate process opens a sufficiently high-numbered fd, # the bug doesn't manifest $ perl -le 'use POSIX "dup2"; dup2(0, 1023); if (fork() == 0) { exec "./a.out" } else { wait; exit $?>>8 }'; echo $? 0 (Additional important detail: the fd 255 held open by bash is in close-on-exec mode.) |