defensive-coding-guide/en-US/C-Libc.xml
2017-10-23 14:46:34 +00:00

352 lines
14 KiB
XML

<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
]>
<section id="sect-Defensive_Coding-C-Libc">
<title>The C Standard Library</title>
<para>
Parts of the C standard library (and the UNIX and GNU extensions)
are difficult to use, so you should avoid them.
</para>
<para>
Please check the applicable documentation before using the
recommended replacements. Many of these functions allocate
buffers using <function>malloc</function> which your code must
deallocate explicitly using <function>free</function>.
</para>
<section id="sect-Defensive_Coding-C-Absolutely-Banned">
<title>Absolutely Banned Interfaces</title>
<para>
The functions listed below must not be used because they are
almost always unsafe. Use the indicated replacements instead.
</para>
<itemizedlist>
<listitem><para><function>gets</function>
<function>fgets</function></para></listitem>
<listitem><para><function>getwd</function>
<function>getcwd</function>
or <function>get_current_dir_name</function></para></listitem>
<listitem>
<para>
<function>readdir_r</function><function>readdir</function>
<!-- It is quite complicated to allocate a properly-sized
buffer for use with readdir_r, and readdir provides
sufficient thread safety guarantees. -->
<!-- ??? Add File_System cross-reference -->
</para>
</listitem>
<listitem>
<para>
<function>realpath</function> (with a non-NULL second parameter)
<function>realpath</function> with NULL as the second parameter,
or <function>canonicalize_file_name</function>
<!-- It is complicated to allocate a properly-sized buffer
for use with realpath. -->
<!-- ??? Add File_System cross-reference -->
</para>
</listitem>
</itemizedlist>
<para>
The constants listed below must not be used, either. Instead,
code must allocate memory dynamically and use interfaces with
length checking.
</para>
<itemizedlist>
<listitem>
<para>
<literal>NAME_MAX</literal> (limit not actually enforced by
the kernel)
</para>
</listitem>
<listitem>
<para>
<literal>PATH_MAX</literal> (limit not actually enforced by
the kernel)
</para>
</listitem>
<listitem>
<para>
<literal>_PC_NAME_MAX</literal> (This limit, returned by the
<function>pathconf</function> function, is not enforced by
the kernel.)
</para>
</listitem>
<listitem>
<para>
<literal>_PC_PATH_MAX</literal> (This limit, returned by the
<function>pathconf</function> function, is not enforced by
the kernel.)
</para>
</listitem>
</itemizedlist>
<para>
The following structure members must not be used.
</para>
<itemizedlist>
<listitem>
<para>
<literal>f_namemax</literal> in <literal>struct
statvfs</literal> (limit not actually enforced by the kernel,
see <literal>_PC_NAME_MAX</literal> above)
</para>
</listitem>
</itemizedlist>
</section>
<section id="sect-Defensive_Coding-C-Avoid">
<title>Functions to Avoid</title>
<para>
The following string manipulation functions can be used securely
in principle, but their use should be avoided because they are
difficult to use correctly. Calls to these functions can be
replaced with <function>asprintf</function> or
<function>vasprintf</function>. (For non-GNU targets, these
functions are available from Gnulib.) In some cases, the
<function>snprintf</function> function might be a suitable
replacement, see <xref
linkend="sect-Defensive_Coding-C-String-Functions-Length"/>.
</para>
<itemizedlist>
<listitem><para><function>sprintf</function></para></listitem>
<listitem><para><function>strcat</function></para></listitem>
<listitem><para><function>strcpy</function></para></listitem>
<listitem><para><function>vsprintf</function></para></listitem>
</itemizedlist>
<para>
Use the indicated replacements for the functions below.
</para>
<itemizedlist>
<listitem>
<para>
<function>alloca</function>
<function>malloc</function> and <function>free</function>
(see <xref linkend="sect-Defensive_Coding-C-Allocators-alloca"/>)
</para>
</listitem>
<listitem>
<para>
<function>putenv</function>
explicit <varname>envp</varname> argument in process creation
(see <xref linkend="sect-Defensive_Coding-Tasks-Processes-environ"/>)
</para>
</listitem>
<listitem>
<para>
<function>setenv</function>
explicit <varname>envp</varname> argument in process creation
(see <xref linkend="sect-Defensive_Coding-Tasks-Processes-environ"/>)
</para>
</listitem>
<listitem>
<para>
<function>strdupa</function>
<function>strdup</function> and <function>free</function>
(see <xref linkend="sect-Defensive_Coding-C-Allocators-alloca"/>)
</para>
</listitem>
<listitem>
<para>
<function>strndupa</function>
<function>strndup</function> and <function>free</function>
(see <xref linkend="sect-Defensive_Coding-C-Allocators-alloca"/>)
</para>
</listitem>
<listitem>
<para>
<function>system</function>
<function>posix_spawn</function>
or <function>fork</function>/<function>execve</function>/
(see <xref linkend="sect-Defensive_Coding-Tasks-Processes-execve"/>)
</para>
</listitem>
<listitem>
<para>
<function>unsetenv</function>
explicit <varname>envp</varname> argument in process creation
(see <xref linkend="sect-Defensive_Coding-Tasks-Processes-environ"/>)
</para>
</listitem>
</itemizedlist>
</section>
<section id="sect-Defensive_Coding-C-String-Functions-Length">
<title>String Functions with Explicit Length Arguments</title>
<para>
The C run-time library provides string manipulation functions
which not just look for NUL characters for string termination,
but also honor explicit lengths provided by the caller.
However, these functions evolved over a long period of time, and
the lengths mean different things depending on the function.
</para>
<section id="sect-Defensive_Coding-C-Libc-snprintf">
<title><literal>snprintf</literal></title>
<para>
The <function>snprintf</function> function provides a way to
construct a string in a statically-sized buffer. (If the buffer
size is allocated on the heap, consider use
<function>asprintf</function> instead.)
</para>
<informalexample>
<xi:include href="snippets/C-String-Functions-snprintf.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
</informalexample>
<para>
The second argument to the <function>snprintf</function> call
should always be the size of the buffer in the first argument
(which should be a character array). Elaborate pointer and
length arithmetic can introduce errors and nullify the
security benefits of <function>snprintf</function>.
</para>
<para>
In particular, <literal>snprintf</literal> is not well-suited
to constructing a string iteratively, by appending to an
existing buffer. <function>snprintf</function> returns one of
two values, <literal>-1</literal> on errors, or the number of
characters which <emphasis>would have been written to the
buffer if the buffer were large enough</emphasis>. This means
that adding the result of <function>snprintf</function> to the
buffer pointer to skip over the characters just written is
incorrect and risky. However, as long as the length argument
is not zero, the buffer will remain null-terminated. <xref
linkend="ex-Defensive_Coding-C-String-Functions-snprintf-incremental"/>
works because <literal>end -current &gt; 0</literal> is a loop
invariant. After the loop, the result string is in the
<varname>buf</varname> variable.
</para>
<example id="ex-Defensive_Coding-C-String-Functions-snprintf-incremental">
<title>Repeatedly writing to a buffer using <function>snprintf</function></title>
<xi:include href="snippets/C-String-Functions-snprintf-incremental.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
</example>
<para>
If you want to avoid the call to <function>strlen</function>
for performance reasons, you have to check for a negative
return value from <function>snprintf</function> and also check
if the return value is equal to the specified buffer length or
larger. Only if neither condition applies, you may advance
the pointer to the start of the write buffer by the number
return by <function>snprintf</function>. However, this
optimization is rarely worthwhile.
</para>
<para>
Note that it is not permitted to use the same buffer both as
the destination and as a source argument.
</para>
</section>
<section id="sect-Defensive_Coding-C-Libc-vsnprintf">
<title><literal>vsnprintf</literal> and Format Strings</title>
<para>
If you use <function>vsnprintf</function> (or
<function>vasprintf</function> or even
<function>snprintf</function>) with a format string which is
not a constant, but a function argument, it is important to
annotate the function with a <literal>format</literal>
function attribute, so that GCC can warn about misuse of your
function (see <xref
linkend="ex-Defensive_Coding-C-String-Functions-format-Attribute"/>).
</para>
<example id="ex-Defensive_Coding-C-String-Functions-format-Attribute">
<title>The <literal>format</literal> function attribute</title>
<xi:include href="snippets/C-String-Functions-format.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
</example>
</section>
<section id="sect-Defensive_Coding-C-Libc-strncpy">
<title><function>strncpy</function></title>
<para>
The <function>strncpy</function> function does not ensure that
the target buffer is null-terminated. A common idiom for
ensuring NUL termination is:
</para>
<informalexample>
<xi:include href="snippets/C-String-Functions-strncpy.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
</informalexample>
<para>
Another approach uses the <function>strncat</function>
function for this purpose:
</para>
<informalexample>
<xi:include href="snippets/C-String-Functions-strncat-as-strncpy.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
</informalexample>
</section>
<section id="sect-Defensive_Coding-C-Libc-strncat">
<title><function>strncat</function></title>
<para>
The length argument of the <function>strncat</function>
function specifies the maximum number of characters copied
from the source buffer, excluding the terminating NUL
character. This means that the required number of bytes in
the destination buffer is the length of the original string,
plus the length argument in the <function>strncat</function>
call, plus one. Consequently, this function is rarely
appropriate for performing a length-checked string operation,
with the notable exception of the <function>strcpy</function>
emulation described in <xref
linkend="sect-Defensive_Coding-C-Libc-strncpy"/>.
</para>
<para>
To implement a length-checked string append, you can use an
approach similar to <xref
linkend="ex-Defensive_Coding-C-String-Functions-snprintf-incremental"/>:
</para>
<informalexample>
<xi:include href="snippets/C-String-Functions-strncat-emulation.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
</informalexample>
<para>
In many cases, including this one, the string concatenation
can be avoided by combining everything into a single format
string:
</para>
<informalexample>
<xi:include href="snippets/C-String-Functions-strncat-merged.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
</informalexample>
<para>
But you should must not dynamically construct format strings
to avoid concatenation because this would prevent GCC from
type-checking the argument lists.
</para>
<para>
It is not possible to use format strings like
<literal>"%s%s"</literal> to implement concatenation, unless
you use separate buffers. <function>snprintf</function> does
not support overlapping source and target strings.
</para>
</section>
<section>
<title><function>strlcpy</function> and
<function>strlcat</function></title>
<para>
Some systems support <function>strlcpy</function> and
<function>strlcat</function> functions which behave this way,
but these functions are not part of GNU libc.
<function>strlcpy</function> is often replaced with
<function>snprintf</function> with a <literal>"%s"</literal>
format string. See <xref
linkend="sect-Defensive_Coding-C-Libc-strncpy"/> for a caveat
related to the <function>snprintf</function> return value.
</para>
<para>
To emulate <function>strlcat</function>, use the approach
described in <xref
linkend="sect-Defensive_Coding-C-Libc-strncat"/>.
</para>
</section>
<section>
<title>ISO C11 Annex K *<function>_s</function> functions</title>
<para>
ISO C11 adds another set of length-checking functions, but GNU
libc currently does not implement them.
</para>
</section>
<section>
<title>Other <function>strn</function>* and
<function>stpn</function>* functions</title>
<para>
GNU libc contains additional functions with different variants
of length checking. Consult the documentation before using
them to find out what the length actually means.
</para>
</section>
</section>
</section>