defensive-coding-guide/_preview/fedora/master/en-US/tasks/Tasks-File_System.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

548 lines
No EOL
26 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 System Manipulation</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 System Manipulation
</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="" href="../../en-US/tasks/Tasks-Descriptors.html">File Descriptor Management</a></li>
<li><a class=" active" 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 System Manipulation</h2>
</div>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>In this chapter, we discuss general file system manipulation, with
a focus on access files and directories to which an other,
potentially untrusted user has write access.</p>
</div>
<div class="paragraph">
<p>Temporary files are covered in their own chapter, <a href="#chap-Defensive_Coding-Tasks-Temporary_Files">[chap-Defensive_Coding-Tasks-Temporary_Files]</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="sect-Defensive_Coding-Tasks-File_System-Unowned"><a class="anchor" href="#sect-Defensive_Coding-Tasks-File_System-Unowned"></a>Working with Files and Directories Owned by Other Users</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Sometimes, it is necessary to operate on files and directories
owned by other (potentially untrusted) users. For example, a
system administrator could remove the home directory of a user,
or a package manager could update a file in a directory which is
owned by an application-specific user. This differs from
accessing the file system as a specific user; see
<a href="#sect-Defensive_Coding-Tasks-File_System-Foreign">Accessing the File System as a Different User</a>.</p>
</div>
<div class="paragraph">
<p>Accessing files across trust boundaries faces several
challenges, particularly if an entire directory tree is being
traversed:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Another user might add file names to a writable directory at
any time. This can interfere with file creation and the
order of names returned by <code>readdir</code>.</p>
</li>
<li>
<p>Merely opening and closing a file can have side effects.
For instance, an automounter can be triggered, or a tape
device rewound. Opening a file on a local file system can
block indefinitely, due to mandatory file locking, unless
the <code>O_NONBLOCK</code> flag is specified.</p>
</li>
<li>
<p>Hard links and symbolic links can redirect the effect of
file system operations in unexpected ways. The
<code>O_NOFOLLOW</code> and
<code>AT_SYMLINK_NOFOLLOW</code> variants of system
calls only affected final path name component.</p>
</li>
<li>
<p>The structure of a directory tree can change. For example,
the parent directory of what used to be a subdirectory
within the directory tree being processed could suddenly
point outside that directory tree.</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>Files should always be created with the
<code>O_CREAT</code> and <code>O_EXCL</code> flags,
so that creating the file will fail if it already exists. This
guards against the unexpected appearance of file names, either
due to creation of a new file, or hard-linking of an existing
file. In multi-threaded programs, rather than manipulating the
umask, create the files with mode <code>000</code> if
possible, and adjust it afterwards with
<code>fchmod</code>.</p>
</div>
<div class="paragraph">
<p>To avoid issues related to symbolic links and directory tree
restructuring, the “<code>at</code>” variants of system
calls have to be used (that is, functions like
<code>openat</code>, <code>fchownat</code>,
<code>fchmodat</code>, and
<code>unlinkat</code>, together with
<code>O_NOFOLLOW</code> or
<code>AT_SYMLINK_NOFOLLOW</code>). Path names passed to
these functions must have just a single component (that is,
without a slash). When descending, the descriptors of parent
directories must be kept open. The missing
<code>opendirat</code> function can be emulated with
<code>openat</code> (with an
<code>O_DIRECTORY</code> flag, to avoid opening special
files with side effects), followed by
<code>fdopendir</code>.</p>
</div>
<div class="paragraph">
<p>If the “<code>at</code>” functions are not available, it
is possible to emulate them by changing the current directory.
(Obviously, this only works if the process is not multi-threaded.)
<code>fchdir</code> has to be used to change the current
directory, and the descriptors of the parent directories have to
be kept open, just as with the “<code>at</code>”-based
approach. <code>chdir("&#8230;&#8203;")</code> is unsafe because it
might ascend outside the intended directory tree.</p>
</div>
<div class="paragraph">
<p>This “<code>at</code>” function emulation is currently
required when manipulating extended attributes. In this case,
the <code>lsetxattr</code> function can be used, with a
relative path name consisting of a single component. This also
applies to SELinux contexts and the
<code>lsetfilecon</code> function.</p>
</div>
<div class="paragraph">
<p>Currently, it is not possible to avoid opening special files
<strong>and</strong> changes to files with hard links if the
directory containing them is owned by an untrusted user.
(Device nodes can be hard-linked, just as regular files.)
<code>fchmodat</code> and <code>fchownat</code>
affect files whose link count is greater than one. But opening
the files, checking that the link count is one with
<code>fstat</code>, and using
<code>fchmod</code> and <code>fchown</code> on
the file descriptor may have unwanted side effects, due to item
2 above. When creating directories, it is therefore important
to change the ownership and permissions only after it has been
fully created. Until that point, file names are stable, and no
files with unexpected hard links can be introduced.</p>
</div>
<div class="paragraph">
<p>Similarly, when just reading a directory owned by an untrusted
user, it is currently impossible to reliably avoid opening
special files.</p>
</div>
<div class="paragraph">
<p>There is no workaround against the instability of the file list
returned by <code>readdir</code>. Concurrent
modification of the directory can result in a list of files
being returned which never actually existed on disk.</p>
</div>
<div class="paragraph">
<p>Hard links and symbolic links can be safely deleted using
<code>unlinkat</code> without further checks because
deletion only affects the name within the directory tree being
processed.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="sect-Defensive_Coding-Tasks-File_System-Foreign"><a class="anchor" href="#sect-Defensive_Coding-Tasks-File_System-Foreign"></a>Accessing the File System as a Different User</h2>
<div class="sectionbody">
<div class="paragraph">
<p>This section deals with access to the file system as a specific
user. This is different from accessing files and directories owned by a
different, potentially untrusted user; see <a href="#sect-Defensive_Coding-Tasks-File_System-Foreign">Accessing the File System as a Different User</a>.</p>
</div>
<div class="paragraph">
<p>One approach is to spawn a child process which runs under the
target user and group IDs (both effective and real IDs). Note
that this child process can block indefinitely, even when
processing regular files only. For example, a special FUSE file
system could cause the process to hang in uninterruptible sleep
inside a <code>stat</code> system call.</p>
</div>
<div class="paragraph">
<p>An existing process could change its user and group ID using
<code>setfsuid</code> and <code>setfsgid</code>.
(These functions are preferred over <code>seteuid</code>
and <code>setegid</code> because they do not allow the
impersonated user to send signals to the process.) These
functions are not thread safe. In multi-threaded processes,
these operations need to be performed in a single-threaded child
process. Unexpected blocking may occur as well.</p>
</div>
<div class="paragraph">
<p>It is not recommended to try to reimplement the kernel
permission checks in user space because the required checks are
complex. It is also very difficult to avoid race conditions
during path name resolution.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="sect-Defensive_Coding-Tasks-File_System-Limits"><a class="anchor" href="#sect-Defensive_Coding-Tasks-File_System-Limits"></a>File System Limits</h2>
<div class="sectionbody">
<div class="paragraph">
<p>For historical reasons, there are preprocessor constants such as
<code>PATH_MAX</code>, <code>NAME_MAX</code>.
However, on most systems, the length of canonical path names
(absolute path names with all symbolic links resolved, as
returned by <code>realpath</code> or
<code>canonicalize_file_name</code>) can exceed
<code>PATH_MAX</code> bytes, and individual file name
components can be longer than <code>NAME_MAX</code>. This
is also true of the <code>_PC_PATH_MAX</code> and
<code>_PC_NAME_MAX</code> values returned by
<code>pathconf</code>, and the
<code>f_namemax</code> member of <code>struct
statvfs</code>. Therefore, these constants should not be
used. This is also reason why the
<code>readdir_r</code> should never be used (instead,
use <code>readdir</code>).</p>
</div>
<div class="paragraph">
<p>You should not write code in a way that assumes that there is an
upper limit on the number of subdirectories of a directory, the
number of regular files in a directory, or the link count of an
inode.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="sect-Defensive_Coding-Tasks-File_System-Features"><a class="anchor" href="#sect-Defensive_Coding-Tasks-File_System-Features"></a>File system features</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Not all file systems support all features. This makes it very
difficult to write general-purpose tools for copying files. For
example, a copy operation intending to preserve file permissions
will generally fail when copying to a FAT file system.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Some file systems are case-insensitive. Most should be
case-preserving, though.</p>
</li>
<li>
<p>Name length limits vary greatly, from eight to thousands of
bytes. Path length limits differ as well. Most systems
impose an upper bound on path names passed to the kernel,
but using relative path names, it is possible to create and
access files whose absolute path name is essentially of
unbounded length.</p>
</li>
<li>
<p>Some file systems do not store names as fairly unrestricted
byte sequences, as it has been traditionally the case on GNU
systems. This means that some byte sequences (outside the
POSIX safe character set) are not valid names. Conversely,
names of existing files may not be representable as byte
sequences, and the files are thus inaccessible on GNU
systems. Some file systems perform Unicode canonicalization
on file names. These file systems preserve case, but
reading the name of a just-created file using
<code>readdir</code> might still result in a
different byte sequence.</p>
</li>
<li>
<p>Permissions and owners are not universally supported (and
SUID/SGID bits may not be available). For example, FAT file
systems assign ownership based on a mount option, and
generally mark all files as executable. Any attempt to
change permissions would result in an error.</p>
</li>
<li>
<p>Non-regular files (device nodes, FIFOs) are not generally
available.</p>
</li>
<li>
<p>Only on some file systems, files can have holes, that is,
not all of their contents is backed by disk storage.</p>
</li>
<li>
<p><code>ioctl</code> support (even fairly generic
functionality such as <code>FIEMAP</code> for
discovering physical file layout and holes) is
file-system-specific.</p>
</li>
<li>
<p>Not all file systems support extended attributes, ACLs and
SELinux metadata. Size and naming restriction on extended
attributes vary.</p>
</li>
<li>
<p>Hard links may not be supported at all (FAT) or only within
the same directory (AFS). Symbolic links may not be
available, either. Reflinks (hard links with copy-on-write
semantics) are still very rare. Recent systems restrict
creation of hard links to users which own the target file or
have read/write access to it, but older systems do not.</p>
</li>
<li>
<p>Renaming (or moving) files using <code>rename</code>
can fail (even when <code>stat</code> indicates that
the source and target directories are located on the same
file system). This system call should work if the old and
new paths are located in the same directory, though.</p>
</li>
<li>
<p>Locking semantics vary among file systems. This affects
advisory and mandatory locks. For example, some network
file systems do not allow deleting files which are opened by
any process.</p>
</li>
<li>
<p>Resolution of time stamps varies from two seconds to
nanoseconds. Not all time stamps are available on all file
systems. File creation time (<strong>birth
time</strong>) is not exposed over the
<code>stat</code>/<code>fstat</code>
interface, even if stored by the file system.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="sect-Defensive_Coding-Tasks-File_System-Free_Space"><a class="anchor" href="#sect-Defensive_Coding-Tasks-File_System-Free_Space"></a>Checking Free Space</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <code>statvfs</code> and
<code>fstatvfs</code> functions allow programs to
examine the number of available blocks and inodes, through the
members <code>f_bfree</code>, <code>f_bavail</code>,
<code>f_ffree</code>, and <code>f_favail</code> of
<code>struct statvfs</code>. Some file systems return
fictional values in the <code>f_ffree</code> and
<code>f_favail</code> fields, so the only reliable way to
discover if the file system still has space for a file is to try
to create it. The <code>f_bfree</code> field should be
reasonably accurate, though.</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>