288 lines
No EOL
8.4 KiB
Text
288 lines
No EOL
8.4 KiB
Text
|
|
:experimental:
|
|
include::entities.adoc[]
|
|
|
|
[[sect-Defensive_Coding-C-Libc]]
|
|
==== The C Standard Library
|
|
|
|
Parts of the C standard library (and the UNIX and GNU extensions)
|
|
are difficult to use, so you should avoid them.
|
|
|
|
Please check the applicable documentation before using the
|
|
recommended replacements. Many of these functions allocate
|
|
buffers using `malloc` which your code must
|
|
deallocate explicitly using `free`.
|
|
|
|
[[sect-Defensive_Coding-C-Absolutely-Banned]]
|
|
===== Absolutely Banned Interfaces
|
|
|
|
The functions listed below must not be used because they are
|
|
almost always unsafe. Use the indicated replacements instead.
|
|
|
|
* `gets`
|
|
⟶ `fgets`
|
|
|
|
* `getwd`
|
|
⟶ `getcwd`
|
|
or `get_current_dir_name`
|
|
|
|
* `readdir_r` ⟶ `readdir`
|
|
|
|
* `realpath` (with a non-NULL second parameter)
|
|
⟶ `realpath` with NULL as the second parameter,
|
|
or `canonicalize_file_name`
|
|
|
|
The constants listed below must not be used, either. Instead,
|
|
code must allocate memory dynamically and use interfaces with
|
|
length checking.
|
|
|
|
* `NAME_MAX` (limit not actually enforced by
|
|
the kernel)
|
|
|
|
* `PATH_MAX` (limit not actually enforced by
|
|
the kernel)
|
|
|
|
* `_PC_NAME_MAX` (This limit, returned by the
|
|
`pathconf` function, is not enforced by
|
|
the kernel.)
|
|
|
|
* `_PC_PATH_MAX` (This limit, returned by the
|
|
`pathconf` function, is not enforced by
|
|
the kernel.)
|
|
|
|
The following structure members must not be used.
|
|
|
|
* `f_namemax` in `struct
|
|
statvfs` (limit not actually enforced by the kernel,
|
|
see `_PC_NAME_MAX` above)
|
|
|
|
[[sect-Defensive_Coding-C-Avoid]]
|
|
===== Functions to Avoid
|
|
|
|
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 `asprintf` or
|
|
`vasprintf`. (For non-GNU targets, these
|
|
functions are available from Gnulib.) In some cases, the
|
|
`snprintf` function might be a suitable
|
|
replacement, see <<sect-Defensive_Coding-C-String-Functions-Length>>.
|
|
|
|
* `sprintf`
|
|
|
|
* `strcat`
|
|
|
|
* `strcpy`
|
|
|
|
* `vsprintf`
|
|
|
|
Use the indicated replacements for the functions below.
|
|
|
|
* `alloca` ⟶
|
|
`malloc` and `free`
|
|
(see <<sect-Defensive_Coding-C-Allocators-alloca>>)
|
|
|
|
* `putenv` ⟶
|
|
explicit `envp` argument in process creation
|
|
(see <<sect-Defensive_Coding-Tasks-Processes-environ>>)
|
|
|
|
* `setenv` ⟶
|
|
explicit `envp` argument in process creation
|
|
(see <<sect-Defensive_Coding-Tasks-Processes-environ>>)
|
|
|
|
* `strdupa` ⟶
|
|
`strdup` and `free`
|
|
(see <<sect-Defensive_Coding-C-Allocators-alloca>>)
|
|
|
|
* `strndupa` ⟶
|
|
`strndup` and `free`
|
|
(see <<sect-Defensive_Coding-C-Allocators-alloca>>)
|
|
|
|
* `system` ⟶
|
|
`posix_spawn`
|
|
or `fork`pass:attributes[{blank}]/pass:attributes[{blank}]`execve`pass:attributes[{blank}]/
|
|
(see <<sect-Defensive_Coding-Tasks-Processes-execve>>)
|
|
|
|
* `unsetenv` ⟶
|
|
explicit `envp` argument in process creation
|
|
(see <<sect-Defensive_Coding-Tasks-Processes-environ>>)
|
|
|
|
[[sect-Defensive_Coding-C-String-Functions-Length]]
|
|
===== String Functions with Explicit Length Arguments
|
|
|
|
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.
|
|
|
|
[[sect-Defensive_Coding-C-Libc-snprintf]]
|
|
====== `snprintf`
|
|
|
|
The `snprintf` function provides a way to
|
|
construct a string in a statically-sized buffer. (If the buffer
|
|
size is allocated on the heap, consider use
|
|
`asprintf` instead.)
|
|
|
|
[subs="quotes"]
|
|
----
|
|
include::snippets/C-String-Functions-snprintf.adoc[]
|
|
|
|
----
|
|
|
|
The second argument to the `snprintf` 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 `snprintf`.
|
|
|
|
In particular, `snprintf` is not well-suited
|
|
to constructing a string iteratively, by appending to an
|
|
existing buffer. `snprintf` returns one of
|
|
two values, `-1` on errors, or the number of
|
|
characters which *would have been written to the
|
|
buffer if the buffer were large enough*. This means
|
|
that adding the result of `snprintf` 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. <<ex-Defensive_Coding-C-String-Functions-snprintf-incremental>>
|
|
works because `end -current > 0` is a loop
|
|
invariant. After the loop, the result string is in the
|
|
`buf` variable.
|
|
|
|
[[ex-Defensive_Coding-C-String-Functions-snprintf-incremental]]
|
|
.Repeatedly writing to a buffer using `snprintf`
|
|
====
|
|
|
|
[subs="quotes"]
|
|
----
|
|
include::snippets/C-String-Functions-snprintf-incremental.adoc[]
|
|
|
|
----
|
|
|
|
====
|
|
|
|
If you want to avoid the call to `strlen`
|
|
for performance reasons, you have to check for a negative
|
|
return value from `snprintf` 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 `snprintf`. However, this
|
|
optimization is rarely worthwhile.
|
|
|
|
Note that it is not permitted to use the same buffer both as
|
|
the destination and as a source argument.
|
|
|
|
[[sect-Defensive_Coding-C-Libc-vsnprintf]]
|
|
====== `vsnprintf` and Format Strings
|
|
|
|
If you use `vsnprintf` (or
|
|
`vasprintf` or even
|
|
`snprintf`) with a format string which is
|
|
not a constant, but a function argument, it is important to
|
|
annotate the function with a `format`
|
|
function attribute, so that GCC can warn about misuse of your
|
|
function (see <<ex-Defensive_Coding-C-String-Functions-format-Attribute>>).
|
|
|
|
[[ex-Defensive_Coding-C-String-Functions-format-Attribute]]
|
|
.The `format` function attribute
|
|
====
|
|
|
|
[subs="quotes"]
|
|
----
|
|
include::snippets/C-String-Functions-format.adoc[]
|
|
|
|
----
|
|
|
|
====
|
|
|
|
[[sect-Defensive_Coding-C-Libc-strncpy]]
|
|
====== `strncpy`
|
|
|
|
The `strncpy` function does not ensure that
|
|
the target buffer is null-terminated. A common idiom for
|
|
ensuring NUL termination is:
|
|
|
|
[subs="quotes"]
|
|
----
|
|
include::snippets/C-String-Functions-strncpy.adoc[]
|
|
|
|
----
|
|
|
|
Another approach uses the `strncat`
|
|
function for this purpose:
|
|
|
|
[subs="quotes"]
|
|
----
|
|
include::snippets/C-String-Functions-strncat-as-strncpy.adoc[]
|
|
|
|
----
|
|
|
|
[[sect-Defensive_Coding-C-Libc-strncat]]
|
|
====== `strncat`
|
|
|
|
The length argument of the `strncat`
|
|
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 `strncat`
|
|
call, plus one. Consequently, this function is rarely
|
|
appropriate for performing a length-checked string operation,
|
|
with the notable exception of the `strcpy`
|
|
emulation described in <<sect-Defensive_Coding-C-Libc-strncpy>>.
|
|
|
|
To implement a length-checked string append, you can use an
|
|
approach similar to <<ex-Defensive_Coding-C-String-Functions-snprintf-incremental>>:
|
|
|
|
[subs="quotes"]
|
|
----
|
|
include::snippets/C-String-Functions-strncat-emulation.adoc[]
|
|
|
|
----
|
|
|
|
In many cases, including this one, the string concatenation
|
|
can be avoided by combining everything into a single format
|
|
string:
|
|
|
|
[subs="quotes"]
|
|
----
|
|
include::snippets/C-String-Functions-strncat-merged.adoc[]
|
|
|
|
----
|
|
|
|
But you should must not dynamically construct format strings
|
|
to avoid concatenation because this would prevent GCC from
|
|
type-checking the argument lists.
|
|
|
|
It is not possible to use format strings like
|
|
`"%s%s"` to implement concatenation, unless
|
|
you use separate buffers. `snprintf` does
|
|
not support overlapping source and target strings.
|
|
|
|
====== `strlcpy` and
|
|
`strlcat`
|
|
|
|
Some systems support `strlcpy` and
|
|
`strlcat` functions which behave this way,
|
|
but these functions are not part of GNU libc.
|
|
`strlcpy` is often replaced with
|
|
`snprintf` with a `"%s"`
|
|
format string. See <<sect-Defensive_Coding-C-Libc-strncpy>> for a caveat
|
|
related to the `snprintf` return value.
|
|
|
|
To emulate `strlcat`, use the approach
|
|
described in <<sect-Defensive_Coding-C-Libc-strncat>>.
|
|
|
|
====== ISO C11 Annex K *pass:attributes[{blank}]`_s` functions
|
|
|
|
ISO C11 adds another set of length-checking functions, but GNU
|
|
libc currently does not implement them.
|
|
|
|
====== Other `strn`pass:attributes[{blank}]* and
|
|
`stpn`pass:attributes[{blank}]* functions
|
|
|
|
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. |