257 lines
9.9 KiB
XML
257 lines
9.9 KiB
XML
<?xml version='1.0' encoding='utf-8' ?>
|
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
|
]>
|
|
<chapter id="chap-Defensive_Coding-Tasks-Temporary_Files">
|
|
<title>Temporary Files</title>
|
|
<para>
|
|
In this chapter, we describe how to create temporary files and
|
|
directories, how to remove them, and how to work with programs
|
|
which do not create files in ways that are safe with a shared
|
|
directory for temporary files. General file system manipulation
|
|
is treated in a separate chapter, <xref
|
|
linkend="chap-Defensive_Coding-Tasks-File_System"/>.
|
|
</para>
|
|
<para>
|
|
Secure creation of temporary files has four different aspects.
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
The location of the directory for temporary files must be
|
|
obtained in a secure manner (that is, untrusted environment
|
|
variables must be ignored, see <xref
|
|
linkend="sect-Defensive_Coding-Tasks-secure_getenv"/>).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
A new file must be created. Reusing an existing file must be
|
|
avoided (the <filename class="directory">/tmp</filename> race
|
|
condition). This is tricky because traditionally, system-wide
|
|
temporary directories shared by all users are used.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The file must be created in a way that makes it impossible for
|
|
other users to open it.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The descriptor for the temporary file should not leak to
|
|
subprocesses.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
All functions mentioned below will take care of these aspects.
|
|
</para>
|
|
<para>
|
|
Traditionally, temporary files are often used to reduce memory
|
|
usage of programs. More and more systems use RAM-based file
|
|
systems such as <literal>tmpfs</literal> for storing temporary
|
|
files, to increase performance and decrease wear on Flash storage.
|
|
As a result, spooling data to temporary files does not result in
|
|
any memory savings, and the related complexity can be avoided if
|
|
the data is kept in process memory.
|
|
</para>
|
|
|
|
<section id="chap-Defensive_Coding-Tasks-Temporary_Files-Location">
|
|
<title>Obtaining the Location of Temporary Directory</title>
|
|
<para>
|
|
Some functions below need the location of a directory which
|
|
stores temporary files. For C/C++ programs, use the following
|
|
steps to obtain that directory:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
Use <function>secure_getenv</function> to obtain the value
|
|
of the <literal>TMPDIR</literal> environment variable. If
|
|
it is set, convert the path to a fully-resolved absolute
|
|
path, using <literal>realpath(path, NULL)</literal>. Check
|
|
if the new path refers to a directory and is writeable. In
|
|
this case, use it as the temporary directory.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Fall back to <filename class="directory">/tmp</filename>.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
In Python, you can use the <varname>tempfile.tempdir</varname>
|
|
variable.
|
|
</para>
|
|
<para>
|
|
Java does not support SUID/SGID programs, so you can use the
|
|
<function>java.lang.System.getenv(String)</function> method to
|
|
obtain the value of the <literal>TMPDIR</literal> environment
|
|
variable, and follow the two steps described above. (Java's
|
|
default directory selection does not honor
|
|
<literal>TMPDIR</literal>.)
|
|
</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Named Temporary Files</title>
|
|
<para>
|
|
The <function>mkostemp</function> function creates a named
|
|
temporary file. You should specify the
|
|
<literal>O_CLOEXEC</literal> flag to avoid file descriptor leaks
|
|
to subprocesses. (Applications which do not use multiple threads
|
|
can also use <function>mkstemp</function>, but libraries should
|
|
use <function>mkostemp</function>.) For determining the
|
|
directory part of the file name pattern, see <xref
|
|
linkend="chap-Defensive_Coding-Tasks-Temporary_Files-Location"/>.
|
|
</para>
|
|
<para>
|
|
The file is not removed automatically. It is not safe to rename
|
|
or delete the file before processing, or transform the name in
|
|
any way (for example, by adding a file extension). If you need
|
|
multiple temporary files, call <function>mkostemp</function>
|
|
multiple times. Do not create additional file names derived
|
|
from the name provided by a previous
|
|
<function>mkostemp</function> call. However, it is safe to close
|
|
the descriptor returned by <function>mkostemp</function> and
|
|
reopen the file using the generated name.
|
|
</para>
|
|
<para>
|
|
The Python class <literal>tempfile.NamedTemporaryFile</literal>
|
|
provides similar functionality, except that the file is deleted
|
|
automatically by default. Note that you may have to use the
|
|
<literal>file</literal> attribute to obtain the actual file
|
|
object because some programming interfaces cannot deal with
|
|
file-like objects. The C function <function>mkostemp</function>
|
|
is also available as <function>tempfile.mkstemp</function>.
|
|
</para>
|
|
<para>
|
|
In Java, you can use the
|
|
<function>java.io.File.createTempFile(String, String,
|
|
File)</function> function, using the temporary file location
|
|
determined according to <xref
|
|
linkend="chap-Defensive_Coding-Tasks-Temporary_Files-Location"/>.
|
|
Do not use <function>java.io.File.deleteOnExit()</function> to
|
|
delete temporary files, and do not register a shutdown hook for
|
|
each temporary file you create. In both cases, the deletion
|
|
hint cannot be removed from the system if you delete the
|
|
temporary file prior to termination of the VM, causing a memory
|
|
leak.
|
|
</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Temporary Files without Names</title>
|
|
<para>
|
|
The <function>tmpfile</function> function creates a temporary
|
|
file and immediately deletes it, while keeping the file open.
|
|
As a result, the file lacks a name and its space is deallocated
|
|
as soon as the file descriptor is closed (including the implicit
|
|
close when the process terminates). This avoids cluttering the
|
|
temporary directory with orphaned files.
|
|
</para>
|
|
<para>
|
|
Alternatively, if the maximum size of the temporary file is
|
|
known beforehand, the <function>fmemopen</function> function can
|
|
be used to create a <literal>FILE *</literal> object which is
|
|
backed by memory.
|
|
</para>
|
|
<para>
|
|
In Python, unnamed temporary files are provided by the
|
|
<literal>tempfile.TemporaryFile</literal> class, and the
|
|
<literal>tempfile.SpooledTemporaryFile</literal> class provides
|
|
a way to avoid creation of small temporary files.
|
|
</para>
|
|
<para>
|
|
Java does not support unnamed temporary files.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="chap-Defensive_Coding-Tasks-Temporary_Directory">
|
|
<title>Temporary Directories</title>
|
|
<para>
|
|
The <function>mkdtemp</function> function can be used to create
|
|
a temporary directory. (For determining the directory part of
|
|
the file name pattern, see <xref
|
|
linkend="chap-Defensive_Coding-Tasks-Temporary_Files-Location"/>.)
|
|
The directory is not automatically removed. In Python, this
|
|
function is available as <function>tempfile.mkdtemp</function>.
|
|
In Java 7, temporary directories can be created using the
|
|
<function>java.nio.file.Files.createTempDirectory(Path, String,
|
|
FileAttribute...)</function> function.
|
|
</para>
|
|
<para>
|
|
When creating files in the temporary directory, use
|
|
automatically generated names, e.g., derived from a sequential
|
|
counter. Files with externally provided names could be picked
|
|
up in unexpected contexts, and crafted names could actually
|
|
point outside of the tempoary directory (due to
|
|
<emphasis>directory traversal</emphasis>).
|
|
</para>
|
|
<para>
|
|
Removing a directory tree in a completely safe manner is
|
|
complicated. Unless there are overriding performance concerns,
|
|
the <application>rm</application> program should be used, with
|
|
the <option>-rf</option> and <option>--</option> options.
|
|
</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Compensating for Unsafe File Creation</title>
|
|
<para>
|
|
There are two ways to make a function or program which excepts a
|
|
file name safe for use with temporary files. See
|
|
<xref linkend="sect-Defensive_Coding-Tasks-Processes-Creation"/>,
|
|
for details on subprocess creation.
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
Create a temporary directory and place the file there. If
|
|
possible, run the program in a subprocess which uses the
|
|
temporary directory as its current directory, with a
|
|
restricted environment.
|
|
Use generated names for all files in that temporary
|
|
directory. (See <xref
|
|
linkend="chap-Defensive_Coding-Tasks-Temporary_Directory"/>.)
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Create the temporary file and pass the generated file name
|
|
to the function or program. This only works if the function
|
|
or program can cope with a zero-length existing file. It is
|
|
safe only under additional assumptions:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
The function or program must not create additional files
|
|
whose name is derived from the specified file name or
|
|
are otherwise predictable.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The function or program must not delete the file before
|
|
processing it.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
It must not access any existing files in the same
|
|
directory.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
It is often difficult to check whether these additional
|
|
assumptions are matched, therefore this approach is not
|
|
recommended.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
</chapter>
|