View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0000141 | 1003.1(2008)/Issue 7 | System Interfaces | public | 2009-09-02 15:42 | 2013-04-16 13:06 |
Reporter | eblake | Assigned To | ajosey | ||
Priority | normal | Severity | Objection | Type | Omission |
Status | Closed | Resolution | Accepted As Marked | ||
Name | Eric Blake | ||||
Organization | N/A | ||||
User Reference | ebb.O_NONBLOCK | ||||
Section | open | ||||
Page Number | 1380 | ||||
Line Number | 45239 | ||||
Interp Status | Approved | ||||
Final Accepted Text | 0000141:0000232 | ||||
Summary | 0000141: O_NONBLOCK flag to open | ||||
Description | The current specification of the O_NONBLOCK flag to open and openat has some holes. Older versions of the Linux kernel lacked (or silently ignored) O_DIRECTORY. Therefore, it is common to see code similar to: #ifndef O_DIRECTORY # define O_DIRECTORY 0 #endif #ifndef O_CLOEXEC # define O_CLOEXEC 0 #endif int fd = open (name, O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK | O_CLOEXEC); if (!O_DIRECTORY && 0 <= fd) { /* Prove that fd is indeed a directory. */ struct stat st; if (fstat (fd, &st) == -1 || !S_ISDIR (st.st_mode)) { close (fd); errno = ENOTDIR; fd = -1; } } The idea is that if the user can't atomically guarantee that a directory will be opened, at least they can guarantee that they won't change a controlling terminal or block on a FIFO, and can use followup checks to simulate O_DIRECTORY with minimal semantic difference. For an example of this, which goes one step further in also using O_NOFOLLOW to avoid symlink-to-directory, see http://git.savannah.gnu.org/cgit/gnulib.git/tree/lib/chdir-safer.c From the POSIX perspective, the use of O_NOCTTY is safe albeit redundant - files that name directories (either a directory, or a symlink-to-directory) are mutually exclusive from terminal devices, so if name describes a directory, O_NOCTTY is silently ignored (line 45222) and open succeeds; if name is a terminal device, then O_DIRECTORY causes failure (line 45209), so the controlling terminal cannot change. And for the older non-POSIX kernels, the user has added a safety valve to prevent changing the controlling terminal until they can verify that the intent of opening a directory was met. But for O_NONBLOCK, there is a problem. For the non-POSIX case, the user has tried to add a safety valve that if name is a FIFO rather than a directory, the application will not block (avoiding a delay or even deadlock at reaching the subsequent fstat to reject the non-directory). However, according to POSIX, the use of O_NONBLOCK is unspecified on a directory, so it is conceivable that an implementation could choose to use the unspecified behavior umbrella by making open fail if name does not support non-blocking mode, rendering the combination O_DIRECTORY|O_NONBLOCK useless for a strictly compliant application (it would either fail because a non-directory was specified, or because a directory does not support non-blocking mode). Thankfully, there are no known existing implementations of open that fail if O_NONBLOCK is specified on a file that does not support non-blocking mode, although it is not clear whether a subsequent fcntl(F_GETFL) will see O_NONBLOCK. Furthermore, fcntl has no restrictions on using F_SETFL to enable O_NONBLOCK for any type of file descriptor. So, while it is currently unspecified what happens when using O_NONBLOCK to open a directory or a regular file, there appears to be no restriction on setting it later. Even if a user tries to avoid unspecified behavior associated with O_NONBLOCK by only using open(O_NONBLOCK) if they have previously stat()ed name and seen that it is a FIFO, there is an inherent data race where name can be changed to a non-FIFO between the stat() and the open(); thus it is impossible to for open(O_NONBLOCK) to ensure that it is avoiding unspecified behavior, based on the current specification. It would be nicer if the specification of O_NONBLOCK were tightened such that it is well-defined as never causing an error, similar to O_NOCTTY or O_TTY_INIT, while still leaving implementations the flexibility of ignoring the flag on file descriptors where non-blocking is not supported. That way, O_NONBLOCK can safely be used with O_DIRECTORY, and applications need not worry about triggering unspecified behavior due to a race between stat() and open(). | ||||
Desired Action | At line 26904 (fcntl F_GETFL), add a sentence: If filedes does not support non-blocking operations, it is unspecified whether the O_NONBLOCK flag will be ignored. At line 45239 (open O_NONBLOCK), change: Otherwise, the behavior of O_NONBLOCK is unspecified. to: Otherwise, the O_NONBLOCK flag shall not cause an error, but it is unspecified whether the file status flags will include the O_NONBLOCK flag. | ||||
Tags | tc1-2008 |
|
A small change to the code would avoid the unspecified behaviour in the standard: oflags = O_RDONLY; #ifdef O_DIRECTORY oflags |= O_DIRECTORY; #else oflags |= O_NONBLOCK | O_NOCTTY; #endif #ifdef O_CLOEXEC oflags |= O_CLOEXEC; #endif int fd = open (name, oflags); #ifndef O_DIRECTORY if (0 <= fd) { /* Prove that fd is indeed a directory. */ ... } #endif Since the standard requires O_DIRECTORY to be defined, with this code O_NONBLOCK will only be used on a directory on non-conforming systems (including systems that conform to older revisions of POSIX, but a change to the current standard would not affect them). Nevertheless, I believe there is a case for changing the standard here. The reason is that when an application calls open() on an existing file, it cannot be certain what file type the file will have at the time of the open. (The best it can do is stat() the file beforehand, but as Eric points out this would create a race condition whereby the file could change between the stat() and the open().) Thus an application that is expecting to open a FIFO, and calls open() with O_NONBLOCK set, could end up opening a regular file or a directory instead, and has no way of preventing this from happening. The standard should specify the behaviour sufficiently for applications to be able to detect this situation. |
|
The proposed text has a typo; the sentence to be added to fcntl belongs at line 26910 F_SETFL (not 26904 F_GETFL). |
|
Interpretation response ------------------------ The standard does not speak to this issue, and as such no conformance distinction can be made between alternative implementations based on this. This is being referred to the sponsor Rationale: ------------- None. Notes to the Editor (not part of this interpretation): ------------------------------------------------------- Make the change At page 807 line 26910 (fcntl F_SETFL), add a sentence: If fildes does not support non-blocking operations, it is unspecified whether the O_NONBLOCK flag will be ignored. At line 45239 (open O_NONBLOCK), change: Otherwise, the behavior of O_NONBLOCK is unspecified. to: Otherwise, the O_NONBLOCK flag shall not cause an error, but it is unspecified whether the file status flags will include the O_NONBLOCK flag. |
Date Modified | Username | Field | Change |
---|---|---|---|
2009-09-02 15:42 | eblake | New Issue | |
2009-09-02 15:42 | eblake | Status | New => Under Review |
2009-09-02 15:42 | eblake | Assigned To | => ajosey |
2009-09-02 15:42 | eblake | Name | => Eric Blake |
2009-09-02 15:42 | eblake | Organization | => N/A |
2009-09-02 15:42 | eblake | User Reference | => ebb.O_NONBLOCK |
2009-09-02 15:42 | eblake | Section | => open |
2009-09-02 15:42 | eblake | Page Number | => 1380 |
2009-09-02 15:42 | eblake | Line Number | => 45239 |
2009-09-03 10:09 | geoffclare | Note Added: 0000213 | |
2009-09-03 22:37 | eblake | Note Added: 0000216 | |
2009-09-17 15:52 | nick | Note Added: 0000232 | |
2009-09-17 15:54 | nick | Interp Status | => --- |
2009-09-17 15:54 | nick | Status | Under Review => Interpretation Required |
2009-09-17 15:54 | nick | Resolution | Open => Accepted As Marked |
2009-09-17 15:55 | nick | Note Edited: 0000232 | |
2009-09-17 15:55 | nick | Final Accepted Text | => Bugnote: 232 |
2009-09-17 15:56 | nick | Interp Status | --- => Pending |
2009-09-17 15:56 | nick | Final Accepted Text | Bugnote: 232 => 0000141:0000232 |
2009-09-17 15:56 | nick | Note Edited: 0000232 | |
2009-09-17 16:00 | ajosey | Note Edited: 0000232 | |
2009-11-07 07:34 | ajosey | Note Edited: 0000232 | |
2009-11-07 07:34 | ajosey | Interp Status | Pending => Proposed |
2009-12-07 16:56 | ajosey | Interp Status | Proposed => Approved |
2010-09-21 11:13 | geoffclare | Tag Attached: tc1-2008 | |
2013-02-14 16:46 | eblake | Relationship added | related to 0000658 |
2013-04-16 13:06 | ajosey | Status | Interpretation Required => Closed |