defensive-coding-guide/_preview/fedora/master/en-US/tasks/Tasks-Descriptors.html
Brian (bex) Exelbierd 2e8934be40 Converted to AsciiBinder
This required moving files around in the repository and shifting
from a master.adoc structure to _topic_map.yml, etc.

README and Makefile modified slightly to reflect new build process
2018-02-08 13:08:40 +01:00

497 lines
No EOL
23 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>Defensive Coding Guide | Defensive Coding Guide | Specific Programming Tasks | File Descriptor Management</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<!-- Overpass Font -->
<link rel="stylesheet" href="https://overpass-30e2.kxcdn.com/overpass.css">
<link href="../../../master/_stylesheets/asciibinder.css" rel="stylesheet" />
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<link href="../../../master/_images/favicon32x32.png" rel="shortcut icon" type="text/css">
<!--[if IE]><link rel="shortcut icon" href="../../../master/_images/favicon.ico"><![endif]-->
<meta content="AsciiBinder" name="application-name">
</head>
<body>
<div class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="https://docs.fedoraproject.org/"><img alt="Fedora Documentation" src="../../../master/_images/fedora.svg"></a>
</div>
</div>
</div>
<div class="container">
<p class="toggle-nav visible-xs pull-left">
<button class="btn btn-default btn-sm" type="button" data-toggle="offcanvas">Toggle nav</button>
</p>
<ol class="breadcrumb">
<li class="sitename">
<a href="../../../index.html">Home</a>
</li>
<li class="hidden-xs active">
<a href="../../en-US/index.html">Defensive Coding Guide </a>
</li>
<li class="hidden-xs active">
<a href="../../en-US/index.html">Defensive Coding Guide</a>
</li>
<li class="hidden-xs active"><a href="../../en-US/tasks/Tasks-Library_Design.html">Specific Programming Tasks</a></li>
<li class="hidden-xs active">
File Descriptor Management
</li>
</ol>
<div class="row row-offcanvas row-offcanvas-left">
<div class="col-xs-8 col-sm-3 col-md-3 sidebar sidebar-offcanvas">
<ul class="nav nav-sidebar">
<li class="nav-header">
<a class="" href="#" data-toggle="collapse" data-target="#topicGroup0">
<span id="tgSpan0" class="fa fa-angle-down"></span>Defensive Coding Guide
</a>
<ul id="topicGroup0" class="collapse in list-unstyled">
<li><a class="" href="../../en-US/index.html">Book Information</a></li>
<li class="nav-header">
<a class="" href="#" data-toggle="collapse" data-target="#topicSubGroup-0-1">
<span id="sgSpan-0-1" class="fa fa-caret-right"></span>&nbsp;Programming Languages
</a>
<ul id="topicSubGroup-0-1" class="nav-tertiary list-unstyled collapse">
<li><a class="" href="../../en-US/programming-languages/C.html">The C Programming Language</a></li>
<li><a class="" href="../../en-US/programming-languages/CXX.html">The C++ Programming&nbsp;Language</a></li>
<li><a class="" href="../../en-US/programming-languages/Java.html">The Java Programming Language</a></li>
<li><a class="" href="../../en-US/programming-languages/Python.html">The Python Programming Language</a></li>
<li><a class="" href="../../en-US/programming-languages/Shell.html">Shell Programming and bash</a></li>
<li><a class="" href="../../en-US/programming-languages/Go.html">The Go Programming Language</a></li>
<li><a class="" href="../../en-US/programming-languages/Vala.html">The Vala Programming Language</a></li>
</ul>
</li>
<li class="nav-header">
<a class="" href="#" data-toggle="collapse" data-target="#topicSubGroup-0-2">
<span id="sgSpan-0-2" class="fa fa-caret-down"></span>&nbsp;Specific Programming Tasks
</a>
<ul id="topicSubGroup-0-2" class="nav-tertiary list-unstyled collapse in">
<li><a class="" href="../../en-US/tasks/Tasks-Library_Design.html">Library Design</a></li>
<li><a class=" active" href="../../en-US/tasks/Tasks-Descriptors.html">File Descriptor Management</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-File_System.html">File System Manipulation</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Temporary_Files.html">Temporary Files</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Processes.html">Processes</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Serialization.html">Serialization and Deserialization</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Cryptography.html">Cryptography</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Packaging.html">RPM Packaging</a></li>
</ul>
</li>
<li class="nav-header">
<a class="" href="#" data-toggle="collapse" data-target="#topicSubGroup-0-3">
<span id="sgSpan-0-3" class="fa fa-caret-right"></span>&nbsp;Implementing Security Features
</a>
<ul id="topicSubGroup-0-3" class="nav-tertiary list-unstyled collapse">
<li><a class="" href="../../en-US/features/Features-Authentication.html">Authentication and Authorization</a></li>
<li><a class="" href="../../en-US/features/Features-TLS.html">Transport Layer Security (TLS)</a></li>
<li><a class="" href="../../en-US/features/Features-HSM.html">Hardware Security Modules and Smart Cards</a></li>
</ul>
</li>
<li><a class="" href="../../en-US/Revision_History.html">Revision History</a></li>
</ul>
</li>
</ul>
</div>
<div class="col-xs-12 col-sm-9 col-md-9 main">
<div class="page-header">
<h2>File Descriptor Management</h2>
</div>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>File descriptors underlie all input/output mechanisms offered by
the system. They are used to implementation the <code>FILE
*</code>-based functions found in
<code>&lt;stdio.h&gt;</code>, and all the file and network
communication facilities provided by the Python and Java
environments are eventually implemented in them.</p>
</div>
<div class="paragraph">
<p>File descriptors are small, non-negative integers in userspace,
and are backed on the kernel side with complicated data structures
which can sometimes grow very large.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="closing-descriptors"><a class="anchor" href="#closing-descriptors"></a>Closing Descriptors</h2>
<div class="sectionbody">
<div class="paragraph">
<p>If a descriptor is no longer used by a program and is not closed
explicitly, its number cannot be reused (which is problematic in
itself, see <a href="#sect-Defensive_Coding-Tasks-Descriptors-Limit">Dealing with the <code>select</code> Limit</a>), and
the kernel resources are not freed. Therefore, it is important
to close all descriptors at the earliest point in time
possible, but not earlier.</p>
</div>
<div class="sect2">
<h3 id="error-handling-during-descriptor-close"><a class="anchor" href="#error-handling-during-descriptor-close"></a>Error Handling during Descriptor Close</h3>
<div class="paragraph">
<p>The <code>close</code> system call is always
successful in the sense that the passed file descriptor is
never valid after the function has been called. However,
<code>close</code> still can return an error, for
example if there was a file system failure. But this error is
not very useful because the absence of an error does not mean
that all caches have been emptied and previous writes have
been made durable. Programs which need such guarantees must
open files with <code>O_SYNC</code> or use
<code>fsync</code> or <code>fdatasync</code>, and
may also have to <code>fsync</code> the directory
containing the file.</p>
</div>
</div>
<div class="sect2">
<h3 id="closing-descriptors-and-race-conditions"><a class="anchor" href="#closing-descriptors-and-race-conditions"></a>Closing Descriptors and Race Conditions</h3>
<div class="paragraph">
<p>Unlike process IDs, which are recycle only gradually, the
kernel always allocates the lowest unused file descriptor when
a new descriptor is created. This means that in a
multi-threaded program which constantly opens and closes file
descriptors, descriptors are reused very quickly. Unless
descriptor closing and other operations on the same file
descriptor are synchronized (typically, using a mutex), there
will be race conditons and I/O operations will be applied to
the wrong file descriptor.</p>
</div>
<div class="paragraph">
<p>Sometimes, it is necessary to close a file descriptor
concurrently, while another thread might be about to use it in
a system call. In order to support this, a program needs to
create a single special file descriptor, one on which all I/O
operations fail. One way to achieve this is to use
<code>socketpair</code>, close one of the descriptors,
and call <code>shutdown(fd, SHUTRDWR)</code> on the
other.</p>
</div>
<div class="paragraph">
<p>When a descriptor is closed concurrently, the program does not
call <code>close</code> on the descriptor. Instead it
program uses <code>dup2</code> to replace the
descriptor to be closed with the dummy descriptor created
earlier. This way, the kernel will not reuse the descriptor,
but it will carry out all other steps associated with calling
a descriptor (for instance, if the descriptor refers to a
stream socket, the peer will be notified).</p>
</div>
<div class="paragraph">
<p>This is just a sketch, and many details are missing.
Additional data structures are needed to determine when it is
safe to really close the descriptor, and proper locking is
required for that.</p>
</div>
</div>
<div class="sect2">
<h3 id="lingering-state-after-close"><a class="anchor" href="#lingering-state-after-close"></a>Lingering State after Close</h3>
<div class="paragraph">
<p>By default, closing a stream socket returns immediately, and
the kernel will try to send the data in the background. This
means that it is impossible to implement accurate accounting
of network-related resource utilization from userspace.</p>
</div>
<div class="paragraph">
<p>The <code>SO_LINGER</code> socket option alters the
behavior of <code>close</code>, so that it will return
only after the lingering data has been processed, either by
sending it to the peer successfully, or by discarding it after
the configured timeout. However, there is no interface which
could perform this operation in the background, so a separate
userspace thread is needed for each <code>close</code>
call, causing scalability issues.</p>
</div>
<div class="paragraph">
<p>Currently, there is no application-level countermeasure which
applies universally. Mitigation is possible with
<strong class="application">iptables</strong> (the
<code>connlimit</code> match type in particular) and
specialized filtering devices for denial-of-service network
traffic.</p>
</div>
<div class="paragraph">
<p>These problems are not related to the
<code>TIME_WAIT</code> state commonly seen in
<strong class="application">netstat</strong> output. The kernel
automatically expires such sockets if necessary.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="sect-Defensive_Coding-Tasks-Descriptors-Child_Processes"><a class="anchor" href="#sect-Defensive_Coding-Tasks-Descriptors-Child_Processes"></a>Preventing File Descriptor Leaks to Child Processes</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Child processes created with <code>fork</code> share
the initial set of file descriptors with their parent
process. By default, file descriptors are also preserved if
a new process image is created with <code>execve</code>
(or any of the other functions such as <code>system</code>
or <code>posix_spawn</code>).</p>
</div>
<div class="paragraph">
<p>Usually, this behavior is not desirable. There are two ways to
turn it off, that is, to prevent new process images from
inheriting the file descriptors in the parent process:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Set the close-on-exec flag on all newly created file
descriptors. Traditionally, this flag is controlled by the
<code>FD_CLOEXEC</code> flag, using
<code>F_GETFD</code> and <code>F_SETFD</code>
operations of the <code>fcntl</code> function.</p>
<div class="paragraph">
<p>However, in a multi-threaded process, there is a race
condition: a subprocess could have been created between the
time the descriptor was created and the
<code>FD_CLOEXEC</code> was set. Therefore, many system
calls which create descriptors (such as
<code>open</code> and <code>openat</code>)
now accept the <code>O_CLOEXEC</code> flag
(<code>SOCK_CLOEXEC</code> for
<code>socket</code> and
<code>socketpair</code>), which cause the
<code>FD_CLOEXEC</code> flag to be set for the file
descriptor in an atomic fashion. In addition, a few new
systems calls were introduced, such as
<code>pipe2</code> and <code>dup3</code>.</p>
</div>
<div class="paragraph">
<p>The downside of this approach is that every descriptor needs
to receive special treatment at the time of creation,
otherwise it is not completely effective.</p>
</div>
</li>
<li>
<p>After calling <code>fork</code>, but before creating
a new process image with <code>execve</code>, all
file descriptors which the child process will not need are
closed.</p>
<div class="paragraph">
<p>Traditionally, this was implemented as a loop over file
descriptors ranging from <code>3</code> to
<code>255</code> and later <code>1023</code>.
But this is only an approximation because it is possible to
create file descriptors outside this range easily (see <a href="#sect-Defensive_Coding-Tasks-Descriptors-Limit">Dealing with the <code>select</code> Limit</a>).
Another approach reads <code>/proc/self/fd</code>
and closes the unexpected descriptors listed there, but this
approach is much slower.</p>
</div>
</li>
</ul>
</div>
<div class="paragraph">
<p>At present, environments which care about file descriptor
leakage implement the second approach. OpenJDK 6 and 7
are among them.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="sect-Defensive_Coding-Tasks-Descriptors-Limit"><a class="anchor" href="#sect-Defensive_Coding-Tasks-Descriptors-Limit"></a>Dealing with the <code>select</code> Limit</h2>
<div class="sectionbody">
<div class="paragraph">
<p>By default, a user is allowed to open only 1024 files in a
single process, but the system administrator can easily change
this limit (which is necessary for busy network servers).
However, there is another restriction which is more difficult to
overcome.</p>
</div>
<div class="paragraph">
<p>The <code>select</code> function only supports a
maximum of <code>FD_SETSIZE</code> file descriptors
(that is, the maximum permitted value for a file descriptor
is <code>FD_SETSIZE - 1</code>, usually 1023.) If a
process opens many files, descriptors may exceed such
limits. It is impossible to query such descriptors using
<code>select</code>.</p>
</div>
<div class="paragraph">
<p>If a library which creates many file descriptors is used in
the same process as a library which uses
<code>select</code>, at least one of them needs to
be changed.
Calls to <code>select</code> can be replaced with
calls to <code>poll</code> or another event handling
mechanism. Replacing the <code>select</code> function
is the recommended approach.</p>
</div>
<div class="paragraph">
<p>Alternatively, the library with high descriptor usage can
relocate descriptors above the <code>FD_SETSIZE</code>
limit using the following procedure.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Create the file descriptor <code>fd</code> as
usual, preferably with the <code>O_CLOEXEC</code>
flag.</p>
</li>
<li>
<p>Before doing anything else with the descriptor
<code>fd</code>, invoke:</p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre> int newfd = fcntl(fd, F_DUPFD_CLOEXEC, (long)FD_SETSIZE);</pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>Check that <code>newfd</code> result is
non-negative, otherwise close <code>fd</code> and
report an error, and return.</p>
</li>
<li>
<p>Close <code>fd</code> and continue to use
<code>newfd</code>.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The new descriptor has been allocated above the
<code>FD_SETSIZE</code>. Even though this algorithm
is racy in the sense that the <code>FD_SETSIZE</code>
first descriptors could fill up, a very high degree of
physical parallelism is required before this becomes a problem.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="bottom" class="text-muted py-3" >
<div class="foot">
<div class="container">
<div class="row footerlinks">
<div class="col-sm-3 col-xs-6 widget">
<h3 class="widget-title">About</h3>
<div class="widget-body">
<dl>
<dd><a href="https://fedoraproject.org/wiki/Overview">About Fedora</a></dd>
<dd><a href="https://getfedora.org/en/sponsors">Sponsors</a></dd>
<dd><a href="https://fedoramagazine.org">Fedora Magazine</a></dd>
<dd><a href="https://fedoraproject.org/wiki/Legal:Main#Legal">Legal</a></dd>
</dl>
<ul class="list-inline">
<li>
<a href="https://www.facebook.com/TheFedoraProject" class="btn-social btn-outline"><i class="fa fa-fw fa-facebook"></i></a>
</li>
<li>
<a href="https://plus.google.com/112917221531140868607" class="btn-social btn-outline"><i class="fa fa-fw fa-google-plus"></i></a>
</li>
<li>
<a href="https://twitter.com/fedora" class="btn-social btn-outline"><i class="fa fa-fw fa-twitter"></i></a>
</li>
</ul>
</div>
</div>
<div class="col-sm-3 col-xs-6 widget">
<h3 class="widget-title uppercase">Download</h3>
<div class="widget-body">
<dl>
<dd><a href="https://getfedora.org/en/workstation/download">Get Fedora Workstation</a></dd>
<dd><a href="https://getfedora.org/en/server/download">Get Fedora Server</a></dd>
<dd><a href="https://getfedora.org/en/atomic/download">Get Fedora Atomic</a></dd>
<dd><a href="https://spins.fedoraproject.org">Fedora Spins</a></dd>
<dd><a href="https://labs.fedoraproject.org">Fedora Labs</a></dd>
<dd><a href="https://arm.fedoraproject.org">Fedora ARM<span class="sup">&reg;</span></a></dd>
<dd><a href="https://alt.fedoraproject.org/">Alternative Downloads</a></dd>
</dl>
</div>
</div>
<div class="col-sm-3 col-xs-6 widget">
<h3 class="widget-title">Support</h3>
<div class="widget-body">
<dl>
<dd><a href="https://fedoraproject.org/wiki/Communicating_and_getting_help">Get Help</a></dd>
<dd><a href="https://ask.fedoraproject.org/">Ask Fedora</a></dd>
<dd><a href="https://fedoraproject.org/wiki/Common_F27_bugs">Common Bugs</a></dd>
<dd><a href="https://developer.fedoraproject.org/">Fedora Developer Portal</a></dd>
<dd><a href="https://docs.fedoraproject.org/f27/install-guide/index.html">Installation Guide</a></dd>
</dl>
</div>
</div>
<div class="col-sm-3 col-xs-6 widget">
<h3 class="widget-title">Join</h3>
<div class="widget-body">
<dl>
<dd><a href="https://fedoraproject.org/wiki/Join">Join Fedora</a></dd>
<dd><a href="http://fedoraplanet.org">Planet Fedora</a></dd>
<dd><a href="https://fedoraproject.org/wiki/SIGs">Fedora SIGs</a></dd>
<dd><a href="https://admin.fedoraproject.org/accounts/">Fedora Account System</a></dd>
<dd><a href="https://fedoracommunity.org/">Fedora Community</a></dd>
</dl>
</div>
</div>
</div> <!-- /row of widgets -->
<div class="row">
<div class="col-md-2">
<div class="widget-body">
<a href="https://www.redhat.com/"><img class="rh-logo" src="../../../master/_images/redhat-logo.png" alt="Red Hat Logo" /></a>
</div>
</div>
<div class="col-md-7">
<div class="widget-body">
<p class="sponsor">Fedora is sponsored by Red Hat.</p>
<p class="sponsor"><a href="https://www.redhat.com/en/technologies/linux-platforms/articles/relationship-between-fedora-and-rhel">Learn more about the relationship between Red Hat and Fedora &raquo;</a></p>
<p class="copy">&copy; 2017 Red Hat, Inc. and others. Please send any comments or corrections to the <a href="https://pagure.io/fedora-docs/docs-fp-o">documentation team</a></p>
</div>
</div>
</div> <!-- /row of widgets -->
</div>
</div>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="../../../master/_javascripts/bootstrap-offcanvas.js" type="text/javascript"></script>
<script type="text/javascript">
/*<![CDATA[*/
$(document).ready(function() {
$("[id^='topicGroup']").on('show.bs.collapse', function (event) {
if (!($(event.target).attr('id').match(/^topicSubGroup/))) {
$(this).parent().find("[id^='tgSpan']").toggleClass("fa-angle-right fa-angle-down");
}
});
$("[id^='topicGroup']").on('hide.bs.collapse', function (event) {
if (!($(event.target).attr('id').match(/^topicSubGroup/))) {
$(this).parent().find("[id^='tgSpan']").toggleClass("fa-angle-right fa-angle-down");
}
});
$("[id^='topicSubGroup']").on('show.bs.collapse', function () {
$(this).parent().find("[id^='sgSpan']").toggleClass("fa-caret-right fa-caret-down");
});
$("[id^='topicSubGroup']").on('hide.bs.collapse', function () {
$(this).parent().find("[id^='sgSpan']").toggleClass("fa-caret-right fa-caret-down");
});
});
/*]]>*/
</script>
</body>
</html>