Anonymous | Login | 2024-12-03 18:28 UTC |
Main | My View | View Issues | Change Log | Docs |
Viewing Issue Simple Details [ Jump to Notes ] | [ Issue History ] [ Print ] | ||||||
ID | Category | Severity | Type | Date Submitted | Last Update | ||
0000149 | [1003.1(2008)/Issue 7] System Interfaces | Editorial | Enhancement Request | 2009-09-17 06:41 | 2013-04-16 13:06 | ||
Reporter | tahonermann | View Status | public | ||||
Assigned To | ajosey | ||||||
Priority | normal | Resolution | Accepted As Marked | ||||
Status | Closed | ||||||
Name | Tom Honermann | ||||||
Organization | Oracle | ||||||
User Reference | |||||||
Section | fdwalk | ||||||
Page Number | N/A | ||||||
Line Number | N/A | ||||||
Interp Status | --- | ||||||
Final Accepted Text | Note: 0000648 | ||||||
Summary | 0000149: Add fdwalk system interface | ||||||
Description |
Code similar to the following is often used before calling one of the 'exec' family of functions to limit open file descriptors for the new process image. Many programs rely on this behavior for security reasons and to avoid exceeding limits on the number of open files.int fdesc; struct rlimit rl; /* Retrieve the soft limit for the maximum number of open files */ getrlimit(RLIMIT_NOFILE, &rl); /* Set all file descriptors except stdin, stdout, and stderr to close-on-exec */ for(fdesc=3; fdesc < rl.rlim_cur; ++fdesc) { int old_flags = fcntl(fdesc, F_GETFD, 0); if(old_flags >= 0) fcntl(fdesc, F_SETFD, old_flags | FD_CLOEXEC); } The above code functions properly but negatively impacts performance when running with a high soft limit. Consider a soft limit of 256 - at least 253 system calls to 'fcntl' will be made before calling one of the 'exec' functions to replace the process image. Solaris includes a function named 'fdwalk' which can be used to achieve the same results as the above code with much less overhead. See the Solaris man page for more information: http://docs.sun.com/app/docs/doc/816-5168/fdwalk-3c?a=view. [^] Sample code to achieve the same results as the code above follows. static int fdwalk_close_on_exec(void *unused, int fd) { if (fd >= 3) { int old_flags = fcntl(fd, F_GETFD, 0); if(old_flags >= 0) fcntl(fd, F_SETFD, old_flags | FD_CLOEXEC); } return (0); } ... fdwalk(fdwalk_close_on_exec, NULL); Use of 'fdwalk' is more efficient since 'fcntl' is only called for file descriptors that are actually open. |
||||||
Desired Action | Add fdwalk to the system interface section of the next standard. | ||||||
Tags | tc1-2008 | ||||||
Attached Files | |||||||
|
Relationships | ||||||||||||||||
|
Notes | |
(0000238) msbrown (manager) 2009-09-24 15:45 |
The rules for introducing new material into the standard are provided in austin-112r3 (http://www.opengroup.org/austin/docs/austin_112r3.txt). [^] [^] The material introduced must have a copyright release from the original owner. The text needs to be fully formed ... the exact words you would propose being added to the standard. |
(0000648) eblake (manager) 2011-01-13 16:17 edited on: 2011-01-13 16:59 |
This was discussed again during the 16 Dec 2010 meeting. Group consensus was that closefrom( ) cannot be standardized, because the standard explicitly permits the creation of file descriptors that are essential to the implementation (for example, posix_trace_* functionality is often implemented in terms of an inherited fd), and arbitrarily closing all file descriptors beyond a certain value could break the trace and render the application potentially non-conforming. There is no point in standardizing something while declaring that it cannot be portably used (but implementations like BSD can continue to provide it as an extension, as is true of any other non-standardized interface). The group also discussed that since fdwalk( ) has a callback function that operates in user-space, it is necessarily non-atomic. It is possible that closefrom() can be implemented in an atomic manner if it is not based on top of fdwalk( ). Meanwhile, because fdwalk( ) allows for discrimination on which file descriptors to close, it is possible that fdwalk( ) might be usable in a manner that does not invalidate implementation-specific file descriptors, so a future revision of the standard may indeed add fdwalk( ), although no one in the meeting was willing to draft a proposal for fdwalk( ) at this time (again, implementations like Solaris can continue to provide it as an extension). Another suggestion was made for adding a new fcntl( ) command, fcntl(fd,FD_NEXT,flags), which returns the next open file descriptor after fd that satisfies the conditions of flags (where flags could request the next fd in general, the next fd open for reading, the next fd open for writing, etc.). It has the same limitations as fdwalk( ) in being non-atomic, but is more efficient than iterating through every possible file descriptor value and checking to see if that value maps to an open file. However, unlike closefrom( ) and fdwalk( ), it lacks prior implementation practice at this time. A similar request for adding a command to the posix_spawn_file_actions namespace for closing all file descriptors beyond a certain range has the same drawbacks as calling closefrom( ) after fork( ). As a side note, it was mentioned that behavior differs on whether a posix_spawn_file_actions_addclose( ) that closes an already closed file descriptor should make posix_spawn( ) fail or should be ignored as a no-op, and 0000370 was raised to address that point; meanwhile, an application can use an extra posix_spawn_file_actions_adddup2( ) to guarantee that a file descriptor will not be already closed, but with the same risk of non-compliant behavior if doing so overwrites a file descriptor that must be inherited into the child for compliant behavior. Revisiting the original complaint: multi-threaded applications are already aware of the security implications of leaking unintended file descriptors to a child process. The race is possible when one thread creates a file descriptor, then another thread calls fork( ) and exec( ) before the first can use fcntl( ) to mark the file descriptor as close-on-exec. Since the second thread cannot know which file descriptors might have suffered from this race, a common approach has been to try and close all unknown file descriptors after the fork( ) and before the exec( ), rather than relying on the cloexec flag. But as pointed out above, closing a file descriptor that might be in use by the application leads to non-conforming results. Instead, if the standard were to provide ways to guarantee that file descriptors are atomically created as close-on-exec, then it is possible to write conforming software that need not iterate over file descriptors after fork( ), because there is no longer a close-on-exec race that could leak unintended file descriptors, and by avoiding the iteration altogether, there is no longer a risk of accidentally closing a file descriptor essential to the implementation. Therefore, the rest of this proposal seeks to document the problem with closing arbitrary file descriptors, and a new bugid will be opened to propose standardizing some recent interfaces and interface extensions first appearing in Linux (new interfaces such as pipe2( ), accept4( ), mkostemps( ), ..., and extensions like fopen(,"we")) to guarantee the atomic creation of file descriptors with the cloexec bit already set, as was already done in the standard with O_CLOEXEC in open( ) and F_DUPFD_CLOEXEC in fcntl( ). See also 0000368 for a related proposal to require CLOEXEC on hidden descriptors. Make the following changes in TC1: At line 22962 [XSH close APPLICATION USAGE], add a paragraph: Implementations may use file descriptors that must be inherited into child processes for the child process to remain conforming, such as for message catalog or tracing purposes. Therefore, an application that calls close( ) on an arbitrary integer risks non-conforming behavior, and close( ) can only portably be used on file descriptor values that the application has obtained through explicit actions, as well as the three file descriptors corresponding to the standard file streams. In multi-threaded parent applications, the practice of calling close( ) in a loop after fork( ) and before an exec call in order to avoid a race condition of leaking an unintended file descriptor into a child process, is therefore unsafe, and the race should instead be combatted by opening all file descriptors with the FD_CLOEXEC bit set unless the file descriptor is intended to be inherited across exec. also, at line 22968 [RATIONALE], add a new paragraph: The standard developers rejected a proposal to add closefrom( ) to the standard. Because the standard permits implementations to use inherited file descriptors as a means of providing a conforming environment for the child process, it is not possible to standardize an interface that closes arbitrary file descriptors above a certain value while still guaranteeing a conforming environment. At line 24917 [XSH dup2 APPLICATION USAGE], change: The dup( ) and dup2( ) functions are redundant. Their services are also provided by the fcntl( ) function. They have been included in this volume of POSIX.1-2008 primarily for historical reasons, since many existing applications use them. to: The dup( ) function is redundant. Its services are also provided by the fcntl( ) function. It has been included in this volume of POSIX.1-2008 primarily for historical reasons, since many existing applications use it. On the other hand, the dup2( ) function provides unique services, as no other interface is able to atomically replace an existing file descriptor. also, add a paragraph after line 24926: Implementations may use file descriptors that must be inherited into child processes for the child process to remain conforming, such as for message catalog or tracing purposes. Therefore, an application that calls dup2( ) with an arbitrary integer for filedes2 risks non-conforming behavior, and dup2( ) can only portably be used to overwrite file descriptor values that the application has obtained through explicit actions, or for the three file descriptors corresponding to the standard file streams. In order to avoid a race condition of leaking an unintended file descriptor into a child process, an application should consider opening all file descriptors with the FD_CLOEXEC bit set unless the file descriptor is intended to be inherited across exec. At line 46906 [XSH posix_spawn_file_actions_addclose], add a paragraph: Implementations may use file descriptors that must be inherited into child processes for the child process to remain conforming, such as for message catalog or tracing purposes. Therefore, an application that calls posix_spawn_file_actions_addclose( ) with an arbitrary integer risks non-conforming behavior, and this function can only portably be used to close file descriptor values that the application has obtained through explicit actions, or for the three file descriptors corresponding to the standard file streams. In order to avoid a race condition of leaking an unintended file descriptor into a child process, an application should consider opening all file descriptors with the FD_CLOEXEC bit set unless the file descriptor is intended to be inherited across exec. At line 46997 [XSH posix_spawn_file_actions_adddup2], add a paragraph: Implementations may use file descriptors that must be inherited into child processes for the child process to remain conforming, such as for message catalog or tracing purposes. Therefore, an application that calls posix_spawn_file_actions_adddup2( ) with an arbitrary integer for newfiledes risks non-conforming behavior, and this function can only portably be used to overwrite file descriptor values that the application has obtained through explicit actions, or for the three file descriptors corresponding to the standard file streams. In order to avoid a race condition of leaking an unintended file descriptor into a child process, an application should consider opening all file descriptors with the FD_CLOEXEC bit set unless the file descriptor is intended to be inherited across exec. |
(0000652) eblake (manager) 2011-01-20 16:38 |
An interesting point to note is that with POSIX 2008, the definition of OPEN_MAX was changed (see 0000371) to be the current cap on file descriptor creation, but not necessarily on already-open descriptors. Thus, iterating over file descriptors from 0 to OPEN_MAX may miss descriptors that were created prior to a sysconf() call that reduced OPEN_MAX. This argues that maybe the next revision of the standard should consider adding fcntl(fd, F_NEXT), which would return the next open file descriptor > fd (or -1 if fd is the maximum), and where the result can be greater than OPEN_MAX, in order to assist in determining which file descriptors exist in a more reliable manner than just iterating up to OPEN_MAX. |
Issue History | |||
Date Modified | Username | Field | Change |
2009-09-17 06:41 | tahonermann | New Issue | |
2009-09-17 06:41 | tahonermann | Status | New => Under Review |
2009-09-17 06:41 | tahonermann | Assigned To | => ajosey |
2009-09-17 06:41 | tahonermann | Name | => Tom Honermann |
2009-09-17 06:41 | tahonermann | Organization | => Oracle |
2009-09-17 06:41 | tahonermann | Section | => fdwalk |
2009-09-17 06:41 | tahonermann | Page Number | => N/A |
2009-09-17 06:41 | tahonermann | Line Number | => N/A |
2009-09-17 06:57 | tahonermann | Issue Monitored: tahonermann | |
2009-09-24 15:45 | msbrown | Note Added: 0000238 | |
2009-09-24 15:46 | msbrown | Interp Status | => --- |
2009-09-24 15:46 | msbrown | Status | Under Review => Resolved |
2009-09-24 15:46 | msbrown | Resolution | Open => Future Enhancement |
2010-09-09 15:49 | geoffclare | Tag Attached: issue8 | |
2011-01-13 16:17 | eblake | Note Added: 0000648 | |
2011-01-13 16:21 | eblake | Note Edited: 0000648 | |
2011-01-13 16:24 | eblake | Status | Resolved => Under Review |
2011-01-13 16:24 | eblake | Resolution | Future Enhancement => Reopened |
2011-01-13 16:36 | eblake | Note Edited: 0000648 | |
2011-01-13 16:47 | msbrown | Relationship added | related to 0000368 |
2011-01-13 16:49 | eblake | Note Edited: 0000648 | |
2011-01-13 16:57 | msbrown | Status | Under Review => Resolved |
2011-01-13 16:57 | msbrown | Resolution | Reopened => Accepted |
2011-01-13 16:57 | msbrown | Final Accepted Text | => Note: 0000648 |
2011-01-13 16:57 | msbrown | Resolution | Accepted => Accepted As Marked |
2011-01-13 16:58 | Don Cragun | Tag Detached: issue8 | |
2011-01-13 16:59 | Don Cragun | Note Edited: 0000648 | |
2011-01-13 17:01 | geoffclare | Tag Attached: tc1-2008 | |
2011-01-13 17:05 | Don Cragun | Relationship added | related to 0000370 |
2011-01-20 16:38 | eblake | Note Added: 0000652 | |
2011-04-20 17:03 | eblake | Relationship added | related to 0000411 |
2013-04-16 13:06 | ajosey | Status | Resolved => Closed |
Mantis 1.1.6[^] Copyright © 2000 - 2008 Mantis Group |