Removed non-Defensive Coding Guide bits and promoted source to root
This commit is contained in:
parent
9eb72b454b
commit
9dc8a003e5
402 changed files with 0 additions and 2049 deletions
17
en-US/Author_Group.xml
Normal file
17
en-US/Author_Group.xml
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE authorgroup PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!ENTITY % BOOK_ENTITIES SYSTEM "Defensive_Coding.ent">
|
||||
%BOOK_ENTITIES;
|
||||
]>
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Florian</firstname>
|
||||
<surname>Weimer</surname>
|
||||
<affiliation>
|
||||
<orgname>Red Hat</orgname>
|
||||
<orgdiv>Product Security Team</orgdiv>
|
||||
</affiliation>
|
||||
<email>fweimer@redhat.com</email>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
29
en-US/Book_Info.xml
Normal file
29
en-US/Book_Info.xml
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?xml version='1.0' encoding='UTF-8' ?>
|
||||
<!DOCTYPE bookinfo PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<bookinfo id="book-Defensive_Coding">
|
||||
<title>Defensive Coding</title>
|
||||
<subtitle>A Guide to Improving Software Security</subtitle>
|
||||
<edition>1</edition>
|
||||
<pubsnumber>1</pubsnumber>
|
||||
<productname>Fedora Security Team</productname>
|
||||
<productnumber></productnumber>
|
||||
<abstract>
|
||||
<para>
|
||||
This document provides guidelines for improving software
|
||||
security through secure coding. It covers common
|
||||
programming languages and libraries, and focuses on
|
||||
concrete recommendations.
|
||||
</para>
|
||||
</abstract>
|
||||
<corpauthor>
|
||||
<inlinemediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Common_Content/images/title_logo.svg" format="SVG" />
|
||||
</imageobject>
|
||||
</inlinemediaobject>
|
||||
</corpauthor>
|
||||
<xi:include href="Common_Content/Legal_Notice.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Author_Group.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</bookinfo>
|
||||
|
209
en-US/C-Allocators.xml
Normal file
209
en-US/C-Allocators.xml
Normal file
|
@ -0,0 +1,209 @@
|
|||
<?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-Allocators">
|
||||
<title>Memory allocators</title>
|
||||
|
||||
<section>
|
||||
<title><function>malloc</function> and related functions</title>
|
||||
<para>
|
||||
The C library interfaces for memory allocation are provided by
|
||||
<function>malloc</function>, <function>free</function> and
|
||||
<function>realloc</function>, and the
|
||||
<function>calloc</function> function. In addition to these
|
||||
generic functions, there are derived functions such as
|
||||
<function>strdup</function> which perform allocation using
|
||||
<function>malloc</function> internally, but do not return
|
||||
untyped heap memory (which could be used for any object).
|
||||
</para>
|
||||
<para>
|
||||
The C compiler knows about these functions and can use their
|
||||
expected behavior for optimizations. For instance, the compiler
|
||||
assumes that an existing pointer (or a pointer derived from an
|
||||
existing pointer by arithmetic) will not point into the memory
|
||||
area returned by <function>malloc</function>.
|
||||
</para>
|
||||
<para>
|
||||
If the allocation fails, <function>realloc</function> does not
|
||||
free the old pointer. Therefore, the idiom <literal>ptr =
|
||||
realloc(ptr, size);</literal> is wrong because the memory
|
||||
pointed to by <literal>ptr</literal> leaks in case of an error.
|
||||
</para>
|
||||
<section id="sect-Defensive_Coding-C-Use-After-Free">
|
||||
<title>Use-after-free errors</title>
|
||||
<para>
|
||||
After <function>free</function>, the pointer is invalid.
|
||||
Further pointer dereferences are not allowed (and are usually
|
||||
detected by <application>valgrind</application>). Less obvious
|
||||
is that any <emphasis>use</emphasis> of the old pointer value is
|
||||
not allowed, either. In particular, comparisons with any other
|
||||
pointer (or the null pointer) are undefined according to the C
|
||||
standard.
|
||||
</para>
|
||||
<para>
|
||||
The same rules apply to <function>realloc</function> if the
|
||||
memory area cannot be enlarged in-place. For instance, the
|
||||
compiler may assume that a comparison between the old and new
|
||||
pointer will always return false, so it is impossible to detect
|
||||
movement this way.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Handling memory allocation errors</title>
|
||||
<para>
|
||||
Recovering from out-of-memory errors is often difficult or even
|
||||
impossible. In these cases, <function>malloc</function> and
|
||||
other allocation functions return a null pointer. Dereferencing
|
||||
this pointer lead to a crash. Such dereferences can even be
|
||||
exploitable for code execution if the dereference is combined
|
||||
with an array subscript.
|
||||
</para>
|
||||
<para>
|
||||
In general, if you cannot check all allocation calls and
|
||||
handle failure, you should abort the program on allocation
|
||||
failure, and not rely on the null pointer dereference to
|
||||
terminate the process. See
|
||||
<xref
|
||||
linkend="sect-Defensive_Coding-Tasks-Serialization-Decoders"/>
|
||||
for related memory allocation concerns.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-C-Allocators-alloca">
|
||||
<title><function>alloca</function> and other forms of stack-based
|
||||
allocation</title>
|
||||
<para>
|
||||
Allocation on the stack is risky because stack overflow checking
|
||||
is implicit. There is a guard page at the end of the memory
|
||||
area reserved for the stack. If the program attempts to read
|
||||
from or write to this guard page, a <literal>SIGSEGV</literal>
|
||||
signal is generated and the program typically terminates.
|
||||
</para>
|
||||
<para>
|
||||
This is sufficient for detecting typical stack overflow
|
||||
situations such as unbounded recursion, but it fails when the
|
||||
stack grows in increments larger than the size of the guard
|
||||
page. In this case, it is possible that the stack pointer ends
|
||||
up pointing into a memory area which has been allocated for a
|
||||
different purposes. Such misbehavior can be exploitable.
|
||||
</para>
|
||||
<para>
|
||||
A common source for large stack growth are calls to
|
||||
<function>alloca</function> and related functions such as
|
||||
<function>strdupa</function>. These functions should be avoided
|
||||
because of the lack of error checking. (They can be used safely
|
||||
if the allocated size is less than the page size (typically,
|
||||
4096 bytes), but this case is relatively rare.) Additionally,
|
||||
relying on <function>alloca</function> makes it more difficult
|
||||
to reorgnize the code because it is not allowed to use the
|
||||
pointer after the function calling <function>alloca</function>
|
||||
has returned, even if this function has been inlined into its
|
||||
caller.
|
||||
</para>
|
||||
<para>
|
||||
Similar concerns apply to <emphasis>variable-length
|
||||
arrays</emphasis> (VLAs), a feature of the C99 standard which
|
||||
started as a GNU extension. For large objects exceeding the
|
||||
page size, there is no error checking, either.
|
||||
</para>
|
||||
<para>
|
||||
In both cases, negative or very large sizes can trigger a
|
||||
stack-pointer wraparound, and the stack pointer and end up
|
||||
pointing into caller stack frames, which is fatal and can be
|
||||
exploitable.
|
||||
</para>
|
||||
<para>
|
||||
If you want to use <function>alloca</function> or VLAs for
|
||||
performance reasons, consider using a small on-stack array (less
|
||||
than the page size, large enough to fulfill most requests). If
|
||||
the requested size is small enough, use the on-stack array.
|
||||
Otherwise, call <function>malloc</function>. When exiting the
|
||||
function, check if <function>malloc</function> had been called,
|
||||
and free the buffer as needed.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-C-Allocators-Arrays">
|
||||
<title>Array allocation</title>
|
||||
<para>
|
||||
When allocating arrays, it is important to check for overflows.
|
||||
The <function>calloc</function> function performs such checks.
|
||||
</para>
|
||||
<para>
|
||||
If <function>malloc</function> or <function>realloc</function>
|
||||
is used, the size check must be written manually. For instance,
|
||||
to allocate an array of <literal>n</literal> elements of type
|
||||
<literal>T</literal>, check that the requested size is not
|
||||
greater than <literal>((size_t) -1) / sizeof(T)</literal>. See
|
||||
<xref linkend="sect-Defensive_Coding-C-Arithmetic"/>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-C-Allocators-Custom">
|
||||
<title>Custom memory allocators</title>
|
||||
<para>
|
||||
Custom memory allocates come in two forms: replacements for
|
||||
<function>malloc</function>, and completely different interfaces
|
||||
for memory management. Both approaches can reduce the
|
||||
effectiveness of <application>valgrind</application> and similar
|
||||
tools, and the heap corruption detection provided by GNU libc, so
|
||||
they should be avoided.
|
||||
</para>
|
||||
<para>
|
||||
Memory allocators are difficult to write and contain many
|
||||
performance and security pitfalls.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
When computing array sizes or rounding up allocation
|
||||
requests (to the next allocation granularity, or for
|
||||
alignment purposes), checks for arithmetic overflow are
|
||||
required.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Size computations for array allocations need overflow
|
||||
checking. See <xref
|
||||
linkend="sect-Defensive_Coding-C-Allocators-Arrays"/>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
It can be difficult to beat well-tuned general-purpose
|
||||
allocators. In micro-benchmarks, pool allocators can show
|
||||
huge wins, and size-specific pools can reduce internal
|
||||
fragmentation. But often, utilization of individual pools
|
||||
is poor, and external fragmentation increases the overall
|
||||
memory usage.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Conservative garbage collection</title>
|
||||
<para>
|
||||
Garbage collection can be an alternative to explicit memory
|
||||
management using <function>malloc</function> and
|
||||
<function>free</function>. The Boehm-Dehmers-Weiser allocator
|
||||
can be used from C programs, with minimal type annotations.
|
||||
Performance is competitive with <function>malloc</function> on
|
||||
64-bit architectures, especially for multi-threaded programs.
|
||||
The stop-the-world pauses may be problematic for some real-time
|
||||
applications, though.
|
||||
</para>
|
||||
<para>
|
||||
However, using a conservative garbage collector may reduce
|
||||
opertunities for code reduce because once one library in a
|
||||
program uses garbage collection, the whole process memory needs
|
||||
to be subject to it, so that no pointers are missed. The
|
||||
Boehm-Dehmers-Weiser collector also reserves certain signals for
|
||||
internal use, so it is not fully transparent to the rest of the
|
||||
program.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
221
en-US/C-Language.xml
Normal file
221
en-US/C-Language.xml
Normal file
|
@ -0,0 +1,221 @@
|
|||
<?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-Language">
|
||||
<title>The core language</title>
|
||||
<para>
|
||||
C provides no memory safety. Most recommendations in this section
|
||||
deal with this aspect of the language.
|
||||
</para>
|
||||
|
||||
<section id="sect-Defensive_Coding-C-Undefined">
|
||||
<title>Undefined behavior</title>
|
||||
<para>
|
||||
Some C constructs are defined to be undefined by the C standard.
|
||||
This does not only mean that the standard does not describe
|
||||
what happens when the construct is executed. It also allows
|
||||
optimizing compilers such as GCC to assume that this particular
|
||||
construct is never reached. In some cases, this has caused
|
||||
GCC to optimize security checks away. (This is not a flaw in GCC
|
||||
or the C language. But C certainly has some areas which are more
|
||||
difficult to use than others.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Common sources of undefined behavior are:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem><para>out-of-bounds array accesses</para></listitem>
|
||||
<listitem><para>null pointer dereferences</para></listitem>
|
||||
<listitem><para>overflow in signed integer arithmetic</para></listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-C-Pointers">
|
||||
<title>Recommendations for pointers and array handling</title>
|
||||
<para>
|
||||
Always keep track of the size of the array you are working with.
|
||||
Often, code is more obviously correct when you keep a pointer
|
||||
past the last element of the array, and calculate the number of
|
||||
remaining elements by substracting the current position from
|
||||
that pointer. The alternative, updating a separate variable
|
||||
every time when the position is advanced, is usually less
|
||||
obviously correct.
|
||||
</para>
|
||||
<para>
|
||||
<xref linkend="ex-Defensive_Coding-C-Pointers-remaining"/>
|
||||
shows how to extract Pascal-style strings from a character
|
||||
buffer. The two pointers kept for length checks are
|
||||
<varname>inend</varname> and <varname>outend</varname>.
|
||||
<varname>inp</varname> and <varname>outp</varname> are the
|
||||
respective positions.
|
||||
The number of input bytes is checked using the expression
|
||||
<literal>len > (size_t)(inend - inp)</literal>.
|
||||
The cast silences a compiler warning;
|
||||
<varname>inend</varname> is always larger than
|
||||
<varname>inp</varname>.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-C-Pointers-remaining">
|
||||
<title>Array processing in C</title>
|
||||
<xi:include href="snippets/C-Pointers-remaining.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
It is important that the length checks always have the form
|
||||
<literal>len > (size_t)(inend - inp)</literal>, where
|
||||
<varname>len</varname> is a variable of type
|
||||
<type>size_t</type> which denotes the <emphasis>total</emphasis>
|
||||
number of bytes which are about to be read or written next. In
|
||||
general, it is not safe to fold multiple such checks into one,
|
||||
as in <literal>len1 + len2 > (size_t)(inend - inp)</literal>,
|
||||
because the expression on the left can overflow or wrap around
|
||||
(see <xref linkend="sect-Defensive_Coding-C-Arithmetic"/>), and it
|
||||
no longer reflects the number of bytes to be processed.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-C-Arithmetic">
|
||||
<title>Recommendations for integer arithmetic</title>
|
||||
<para>
|
||||
Overflow in signed integer arithmetic is undefined. This means
|
||||
that it is not possible to check for overflow after it happened,
|
||||
see <xref linkend="ex-Defensive_Coding-C-Arithmetic-bad"/>.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-C-Arithmetic-bad">
|
||||
<title>Incorrect overflow detection in C</title>
|
||||
<xi:include href="snippets/C-Arithmetic-add.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
The following approaches can be used to check for overflow,
|
||||
without actually causing it.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Use a wider type to perform the calculation, check that the
|
||||
result is within bounds, and convert the result to the
|
||||
original type. All intermediate results must be checked in
|
||||
this way.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Perform the calculation in the corresponding unsigned type
|
||||
and use bit fiddling to detect the overflow.
|
||||
<xref linkend="ex-Defensive_Coding-C-Arithmetic-add_unsigned"/>
|
||||
shows how to perform an overflow check for unsigned integer
|
||||
addition. For three or more terms, all the intermediate
|
||||
additions have to be checked in this way.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<example id="ex-Defensive_Coding-C-Arithmetic-add_unsigned">
|
||||
<title>Overflow checking for unsigned addition</title>
|
||||
<xi:include href="snippets/C-Arithmetic-add_unsigned.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Compute bounds for acceptable input values which are known
|
||||
to avoid overflow, and reject other values. This is the
|
||||
preferred way for overflow checking on multiplications,
|
||||
see <xref linkend="ex-Defensive_Coding-C-Arithmetic-mult"/>.
|
||||
<!-- This approach can result in bogus compiler warnings
|
||||
with signed types:
|
||||
http://gcc.gnu.org/bugzilla/post_bug.cgi -->
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<example id="ex-Defensive_Coding-C-Arithmetic-mult">
|
||||
<title>Overflow checking for unsigned multiplication</title>
|
||||
<xi:include href="snippets/C-Arithmetic-mult.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
Basic arithmetic operations are commutative, so for bounds checks,
|
||||
there are two different but mathematically equivalent
|
||||
expressions. Sometimes, one of the expressions results in
|
||||
better code because parts of it can be reduced to a constant.
|
||||
This applies to overflow checks for multiplication <literal>a *
|
||||
b</literal> involving a constant <literal>a</literal>, where the
|
||||
expression is reduced to <literal>b > C</literal> for some
|
||||
constant <literal>C</literal> determined at compile time. The
|
||||
other expression, <literal>b && a > ((unsigned)-1) /
|
||||
b</literal>, is more difficult to optimize at compile time.
|
||||
</para>
|
||||
<para>
|
||||
When a value is converted to a signed integer, GCC always
|
||||
chooses the result based on 2's complement arithmetic. This GCC
|
||||
extension (which is also implemented by other compilers) helps a
|
||||
lot when implementing overflow checks.
|
||||
</para>
|
||||
<para>
|
||||
Sometimes, it is necessary to compare unsigned and signed
|
||||
integer variables. This results in a compiler warning,
|
||||
<emphasis>comparison between signed and unsigned integer
|
||||
expressions</emphasis>, because the comparison often gives
|
||||
unexpected results for negative values. When adding a cast,
|
||||
make sure that negative values are covered properly. If the
|
||||
bound is unsigned and the checked quantity is signed, you should
|
||||
cast the checked quantity to an unsigned type as least as wide
|
||||
as either operand type. As a result, negative values will fail
|
||||
the bounds check. (You can still check for negative values
|
||||
separately for clarity, and the compiler will optimize away this
|
||||
redundant check.)
|
||||
</para>
|
||||
<para>
|
||||
Legacy code should be compiled with the <option>-fwrapv</option>
|
||||
GCC option. As a result, GCC will provide 2's complement
|
||||
semantics for integer arithmetic, including defined behavior on
|
||||
integer overflow.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-C-Globals">
|
||||
<title>Global variables</title>
|
||||
<para>
|
||||
Global variables should be avoided because they usually lead to
|
||||
thread safety hazards. In any case, they should be declared
|
||||
<literal>static</literal>, so that access is restricted to a
|
||||
single translation unit.
|
||||
</para>
|
||||
<para>
|
||||
Global constants are not a problem, but declaring them can be
|
||||
tricky. <xref linkend="ex-Defensive_Coding-C-Globals-String_Array"/>
|
||||
shows how to declare a constant array of constant strings.
|
||||
The second <literal>const</literal> is needed to make the
|
||||
array constant, and not just the strings. It must be placed
|
||||
after the <literal>*</literal>, and not before it.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-C-Globals-String_Array">
|
||||
<title>Declaring a constant array of constant strings</title>
|
||||
<xi:include href="snippets/C-Globals-String_Array.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
Sometimes, static variables local to functions are used as a
|
||||
replacement for proper memory management. Unlike non-static
|
||||
local variables, it is possible to return a pointer to static
|
||||
local variables to the caller. But such variables are
|
||||
well-hidden, but effectively global (just as static variables at
|
||||
file scope). It is difficult to add thread safety afterwards if
|
||||
such interfaces are used. Merely dropping the
|
||||
<literal>static</literal> keyword in such cases leads to
|
||||
undefined behavior.
|
||||
</para>
|
||||
<para>
|
||||
Another source for static local variables is a desire to reduce
|
||||
stack space usage on embedded platforms, where the stack may
|
||||
span only a few hundred bytes. If this is the only reason why
|
||||
the <literal>static</literal> keyword is used, it can just be
|
||||
dropped, unless the object is very large (larger than
|
||||
128 kilobytes on 32 bit platforms). In the latter case, it is
|
||||
recommended to allocate the object using
|
||||
<literal>malloc</literal>, to obtain proper array checking, for
|
||||
the same reasons outlined in <xref
|
||||
linkend="sect-Defensive_Coding-C-Allocators-alloca"/>.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
352
en-US/C-Libc.xml
Normal file
352
en-US/C-Libc.xml
Normal file
|
@ -0,0 +1,352 @@
|
|||
<?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 shoud 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 NUL-terminated. <xref
|
||||
linkend="ex-Defensive_Coding-C-String-Functions-snprintf-incremental"/>
|
||||
works because <literal>end -current > 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 NUL-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>
|
70
en-US/C-Other.xml
Normal file
70
en-US/C-Other.xml
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?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-Other">
|
||||
<title>Other C-related topics</title>
|
||||
<section id="sect-Defensive_Coding-C-Wrapper-Functions">
|
||||
<title>Wrapper functions</title>
|
||||
<para>
|
||||
Some libraries provide wrappers for standard library functions.
|
||||
Common cases include allocation functions such as
|
||||
<function>xmalloc</function> which abort the process on
|
||||
allocation failure (instead of returning a
|
||||
<literal>NULL</literal> pointer), or alternatives to relatively
|
||||
recent library additions such as <function>snprintf</function>
|
||||
(along with implementations for systems which lack them).
|
||||
</para>
|
||||
<para>
|
||||
In general, such wrappers are a bad idea, particularly if they
|
||||
are not implemented as inline functions or preprocessor macros.
|
||||
The compiler lacks knowledge of such wrappers outside the
|
||||
translation unit which defines them, which means that some
|
||||
optimizations and security checks are not performed. Adding
|
||||
<literal>__attribute__</literal> annotations to function
|
||||
declarations can remedy this to some extent, but these
|
||||
annotations have to be maintained carefully for feature parity
|
||||
with the standard implementation.
|
||||
</para>
|
||||
<para>
|
||||
At the minimum, you should apply these attributes:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
If you wrap function which accepts are GCC-recognized format
|
||||
string (for example, a <function>printf</function>-style
|
||||
function used for logging), you should add a suitable
|
||||
<literal>format</literal> attribute, as in <xref
|
||||
linkend="ex-Defensive_Coding-C-String-Functions-format-Attribute"/>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
If you wrap a function which carries a
|
||||
<literal>warn_unused_result</literal> attribute and you
|
||||
propagate its return value, your wrapper should be declared
|
||||
with <literal>warn_unused_result</literal> as well.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Duplicating the buffer length checks based on the
|
||||
<function>__builtin_object_size</function> GCC builtin is
|
||||
desirable if the wrapper processes arrays. (This
|
||||
functionality is used by the
|
||||
<literal>-D_FORTIFY_SOURCE=2</literal> checks to guard
|
||||
against static buffer overflows.) However, designing
|
||||
appropriate interfaces and implementing the checks may not
|
||||
be entirely straightforward.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
For other attributes (such as <literal>malloc</literal>),
|
||||
careful analysis and comparison with the compiler documentation
|
||||
is required to check if propagating the attribute is
|
||||
appropriate. Incorrectly applied attributes can result in
|
||||
undesired behavioral changes in the compiled code.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
12
en-US/C.xml
Normal file
12
en-US/C.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?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-C">
|
||||
<title>The C Programming Language</title>
|
||||
|
||||
<xi:include href="C-Language.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="C-Libc.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="C-Allocators.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="C-Other.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</chapter>
|
||||
|
188
en-US/CXX-Language.xml
Normal file
188
en-US/CXX-Language.xml
Normal file
|
@ -0,0 +1,188 @@
|
|||
<?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-CXX-Language">
|
||||
<title>The core language</title>
|
||||
<para>
|
||||
C++ includes a large subset of the C language. As far as the C
|
||||
subset is used, the recommendations in <xref
|
||||
linkend="chap-Defensive_Coding-C"/> apply.
|
||||
</para>
|
||||
|
||||
<section>
|
||||
<title>Array allocation with <literal>operator new[]</literal></title>
|
||||
<para>
|
||||
For very large values of <literal>n</literal>, an expression
|
||||
like <literal>new T[n]</literal> can return a pointer to a heap
|
||||
region which is too small. In other words, not all array
|
||||
elements are actually backed with heap memory reserved to the
|
||||
array. Current GCC versions generate code that performs a
|
||||
computation of the form <literal>sizeof(T) * size_t(n) +
|
||||
cookie_size</literal>, where <literal>cookie_size</literal> is
|
||||
currently at most 8. This computation can overflow, and GCC
|
||||
versions prior to 4.8 generated code which did not detect this.
|
||||
(Fedora 18 was the first release which fixed this in GCC.)
|
||||
</para>
|
||||
<para>
|
||||
The <literal>std::vector</literal> template can be used instead
|
||||
an explicit array allocation. (The GCC implementation detects
|
||||
overflow internally.)
|
||||
</para>
|
||||
<para>
|
||||
If there is no alternative to <literal>operator new[]</literal>
|
||||
and the sources will be compiled with older GCC versions, code
|
||||
which allocates arrays with a variable length must check for
|
||||
overflow manually. For the <literal>new T[n]</literal> example,
|
||||
the size check could be <literal>n || (n > 0 && n >
|
||||
(size_t(-1) - 8) / sizeof(T))</literal>. (See <xref
|
||||
linkend="sect-Defensive_Coding-C-Arithmetic"/>.) If there are
|
||||
additional dimensions (which must be constants according to the
|
||||
C++ standard), these should be included as factors in the
|
||||
divisor.
|
||||
</para>
|
||||
<para>
|
||||
These countermeasures prevent out-of-bounds writes and potential
|
||||
code execution. Very large memory allocations can still lead to
|
||||
a denial of service. <xref
|
||||
linkend="sect-Defensive_Coding-Tasks-Serialization-Decoders"/>
|
||||
contains suggestions for mitigating this problem when processing
|
||||
untrusted data.
|
||||
</para>
|
||||
<para>
|
||||
See <xref linkend="sect-Defensive_Coding-C-Allocators-Arrays"/>
|
||||
for array allocation advice for C-style memory allocation.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Overloading</title>
|
||||
<para>
|
||||
Do not overload functions with versions that have different
|
||||
security characteristics. For instance, do not implement a
|
||||
function <function>strcat</function> which works on
|
||||
<type>std::string</type> arguments. Similarly, do not name
|
||||
methods after such functions.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>ABI compatibility and preparing for security updates</title>
|
||||
<para>
|
||||
A stable binary interface (ABI) is vastly preferred for security
|
||||
updates. Without a stable ABI, all reverse dependencies need
|
||||
recompiling, which can be a lot of work and could even be
|
||||
impossible in some cases. Ideally, a security update only
|
||||
updates a single dynamic shared object, and is picked up
|
||||
automatically after restarting affected processes.
|
||||
</para>
|
||||
<para>
|
||||
Outside of extremely performance-critical code, you should
|
||||
ensure that a wide range of changes is possible without breaking
|
||||
ABI. Some very basic guidelines are:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Avoid inline functions.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the pointer-to-implementation idiom.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Try to avoid templates. Use them if the increased type
|
||||
safety provides a benefit to the programmer.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Move security-critical code out of templated code, so that
|
||||
it can be patched in a central place if necessary.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
The KDE project publishes a document with more extensive
|
||||
guidelines on ABI-preserving changes to C++ code, <ulink
|
||||
url="http://techbase.kde.org/Policies/Binary_Compatibility_Issues_With_C++">Policies/Binary
|
||||
Compatibility Issues With C++</ulink>
|
||||
(<emphasis>d-pointer</emphasis> refers to the
|
||||
pointer-to-implementation idiom).
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-CXX-Language-CXX11">
|
||||
<title>C++0X and C++11 support</title>
|
||||
<para>
|
||||
GCC offers different language compatibility modes:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<option>-std=c++98</option> for the original 1998 C++
|
||||
standard
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<option>-std=c++03</option> for the 1998 standard with the
|
||||
changes from the TR1 technical report
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<option>-std=c++11</option> for the 2011 C++ standard. This
|
||||
option should not be used.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<option>-std=c++0x</option> for several different versions
|
||||
of C++11 support in development, depending on the GCC
|
||||
version. This option should not be used.
|
||||
<!-- There were two incompatibilies before GCC 4.7.2
|
||||
(std::list and std::pair), but link C++98 and C++11
|
||||
code is still unsupported, although it currently has
|
||||
some chance of working by accident. -->
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
For each of these flags, there are variants which also enable
|
||||
GNU extensions (mostly language features also found in C99 or
|
||||
C11): <option>-std=gnu++98</option>,
|
||||
<option>-std=gnu++03</option>, <option>-std=gnu++11</option>.
|
||||
Again, <option>-std=gnu++11</option> should not be used.
|
||||
</para>
|
||||
<para>
|
||||
If you enable C++11 support, the ABI of the standard C++ library
|
||||
<literal>libstdc++</literal> will change in subtle ways.
|
||||
Currently, no C++ libraries are compiled in C++11 mode, so if
|
||||
you compile your code in C++11 mode, it will be incompatible
|
||||
with the rest of the system. Unfortunately, this is also the
|
||||
case if you do not use any C++11 features. Currently, there is
|
||||
no safe way to enable C++11 mode (except for freestanding
|
||||
applications).
|
||||
</para>
|
||||
<para>
|
||||
The meaning of C++0X mode changed from GCC release to GCC
|
||||
release. Earlier versions were still ABI-compatible with C++98
|
||||
mode, but in the most recent versions, switching to C++0X mode
|
||||
activates C++11 support, with its compatibility problems.
|
||||
</para>
|
||||
<para>
|
||||
Some C++11 features (or approximations thereof) are available
|
||||
with TR1 support, that is, with <option>-std=c++03</option> or
|
||||
<option>-std=gnu++03</option> and in the
|
||||
<literal><tr1/*></literal> header files. This includes
|
||||
<literal>std::tr1::shared_ptr</literal> (from
|
||||
<literal><tr1/memory></literal>) and
|
||||
<literal>std::tr1::function</literal> (from
|
||||
<literal><tr1/functional></literal>). For other C++11
|
||||
features, the Boost C++ library contains replacements.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
202
en-US/CXX-Std.xml
Normal file
202
en-US/CXX-Std.xml
Normal file
|
@ -0,0 +1,202 @@
|
|||
<?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-CXX-Std">
|
||||
<title>The C++ standard library</title>
|
||||
<para>
|
||||
The C++ standard library includes most of its C counterpart
|
||||
by reference, see <xref linkend="sect-Defensive_Coding-C-Libc"/>.
|
||||
</para>
|
||||
<section id="sect-Defensive_Coding-CXX-Std-Functions">
|
||||
<title>Functions that are difficult to use</title>
|
||||
<para>
|
||||
This section collects functions and function templates which are
|
||||
part of the standard library and are difficult to use.
|
||||
</para>
|
||||
<section id="sect-Defensive_Coding-CXX-Std-Functions-Unpaired_Iterators">
|
||||
<title>Unpaired iterators</title>
|
||||
<para>
|
||||
Functions which use output operators or iterators which do not
|
||||
come in pairs (denoting ranges) cannot perform iterator range
|
||||
checking.
|
||||
(See <xref linkend="sect-Defensive_Coding-CXX-Std-Iterators"/>)
|
||||
Function templates which involve output iterators are
|
||||
particularly dangerous:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem><para><function>std::copy</function></para></listitem>
|
||||
<listitem><para><function>std::copy_backward</function></para></listitem>
|
||||
<listitem><para><function>std::copy_if</function></para></listitem>
|
||||
<listitem><para><function>std::move</function> (three-argument variant)</para></listitem>
|
||||
<listitem><para><function>std::move_backward</function></para></listitem>
|
||||
<listitem><para><function>std::partition_copy_if</function></para></listitem>
|
||||
<listitem><para><function>std::remove_copy</function></para></listitem>
|
||||
<listitem><para><function>std::remove_copy_if</function></para></listitem>
|
||||
<listitem><para><function>std::replace_copy</function></para></listitem>
|
||||
<listitem><para><function>std::replace_copy_if</function></para></listitem>
|
||||
<listitem><para><function>std::swap_ranges</function></para></listitem>
|
||||
<listitem><para><function>std::transform</function></para></listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
In addition, <function>std::copy_n</function>,
|
||||
<function>std::fill_n</function> and
|
||||
<function>std::generate_n</function> do not perform iterator
|
||||
checking, either, but there is an explicit count which has to be
|
||||
supplied by the caller, as opposed to an implicit length
|
||||
indicator in the form of a pair of forward iterators.
|
||||
</para>
|
||||
<para>
|
||||
These output-iterator-expecting functions should only be used
|
||||
with unlimited-range output iterators, such as iterators
|
||||
obtained with the <function>std::back_inserter</function>
|
||||
function.
|
||||
</para>
|
||||
<para>
|
||||
Other functions use single input or forward iterators, which can
|
||||
read beyond the end of the input range if the caller is not careful:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem><para><function>std::equal</function></para></listitem>
|
||||
<listitem><para><function>std::is_permutation</function></para></listitem>
|
||||
<listitem><para><function>std::mismatch</function></para></listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-CXX-Std-String">
|
||||
<title>String handling with <literal>std::string</literal></title>
|
||||
<para>
|
||||
The <literal>std::string</literal> class provides a convenient
|
||||
way to handle strings. Unlike C strings,
|
||||
<literal>std::string</literal> objects have an explicit length
|
||||
(and can contain embedded NUL characters), and storage for its
|
||||
characters is managed automatically. This section discusses
|
||||
<literal>std::string</literal>, but these observations also
|
||||
apply to other instances of the
|
||||
<literal>std::basic_string</literal> template.
|
||||
</para>
|
||||
<para>
|
||||
The pointer returned by the <function>data()</function> member
|
||||
function does not necessarily point to a NUL-terminated string.
|
||||
To obtain a C-compatible string pointer, use
|
||||
<function>c_str()</function> instead, which adds the NUL
|
||||
terminator.
|
||||
</para>
|
||||
<para>
|
||||
The pointers returned by the <function>data()</function> and
|
||||
<function>c_str()</function> functions and iterators are only
|
||||
valid until certain events happen. It is required that the
|
||||
exact <literal>std::string</literal> object still exists (even
|
||||
if it was initially created as a copy of another string object).
|
||||
Pointers and iterators are also invalidated when non-const
|
||||
member functions are called, or functions with a non-const
|
||||
reference parameter. The behavior of the GCC implementation
|
||||
deviates from that required by the C++ standard if multiple
|
||||
threads are present. In general, only the first call to a
|
||||
non-const member function after a structural modification of the
|
||||
string (such as appending a character) is invalidating, but this
|
||||
also applies to member function such as the non-const version of
|
||||
<function>begin()</function>, in violation of the C++ standard.
|
||||
</para>
|
||||
<para>
|
||||
Particular care is necessary when invoking the
|
||||
<function>c_str()</function> member function on a temporary
|
||||
object. This is convenient for calling C functions, but the
|
||||
pointer will turn invalid as soon as the temporary object is
|
||||
destroyed, which generally happens when the outermost expression
|
||||
enclosing the expression on which <function>c_str()</function>
|
||||
is called completes evaluation. Passing the result of
|
||||
<function>c_str()</function> to a function which does not store
|
||||
or otherwise leak that pointer is safe, though.
|
||||
</para>
|
||||
<para>
|
||||
Like with <literal>std::vector</literal> and
|
||||
<literal>std::array</literal>, subscribing with
|
||||
<literal>operator[]</literal> does not perform bounds checks.
|
||||
Use the <function>at(size_type)</function> member function
|
||||
instead. See <xref
|
||||
linkend="sect-Defensive_Coding-CXX-Std-Subscript"/>.
|
||||
Furthermore, accessing the terminating NUL character using
|
||||
<literal>operator[]</literal> is not possible. (In some
|
||||
implementations, the <literal>c_str()</literal> member function
|
||||
writes the NUL character on demand.)
|
||||
</para>
|
||||
<para>
|
||||
Never write to the pointers returned by
|
||||
<function>data()</function> or <function>c_str()</function>
|
||||
after casting away <literal>const</literal>. If you need a
|
||||
C-style writable string, use a
|
||||
<literal>std::vector<char></literal> object and its
|
||||
<function>data()</function> member function. In this case, you
|
||||
have to explicitly add the terminating NUL character.
|
||||
</para>
|
||||
<para>
|
||||
GCC's implementation of <literal>std::string</literal> is
|
||||
currently based on reference counting. It is expected that a
|
||||
future version will remove the reference counting, due to
|
||||
performance and conformance issues. As a result, code that
|
||||
implicitly assumes sharing by holding to pointers or iterators
|
||||
for too long will break, resulting in run-time crashes or worse.
|
||||
On the other hand, non-const iterator-returning functions will
|
||||
no longer give other threads an opportunity for invalidating
|
||||
existing iterators and pointers because iterator invalidation
|
||||
does not depend on sharing of the internal character array
|
||||
object anymore.
|
||||
</para>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-CXX-Std-Subscript">
|
||||
<title>Containers and <literal>operator[]</literal></title>
|
||||
<para>
|
||||
Many sequence containers similar to <literal>std::vector</literal>
|
||||
provide both <literal>operator[](size_type)</literal> and a
|
||||
member function <literal>at(size_type)</literal>. This applies
|
||||
to <literal>std::vector</literal> itself,
|
||||
<literal>std::array</literal>, <literal>std::string</literal>
|
||||
and other instances of <literal>std::basic_string</literal>.
|
||||
</para>
|
||||
<para>
|
||||
<literal>operator[](size_type)</literal> is not required by the
|
||||
standard to perform bounds checking (and the implementation in
|
||||
GCC does not). In contrast, <literal>at(size_type)</literal>
|
||||
must perform such a check. Therefore, in code which is not
|
||||
performance-critical, you should prefer
|
||||
<literal>at(size_type)</literal> over
|
||||
<literal>operator[](size_type)</literal>, even though it is
|
||||
slightly more verbose.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>front()</literal> and <literal>back()</literal>
|
||||
member functions are undefined if a vector object is empty. You
|
||||
can use <literal>vec.at(0)</literal> and
|
||||
<literal>vec.at(vec.size() - 1)</literal> as checked
|
||||
replacements. For an empty vector, <literal>data()</literal> is
|
||||
defined; it returns an arbitrary pointer, but not necessarily
|
||||
the NULL pointer.
|
||||
</para>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-CXX-Std-Iterators">
|
||||
<title>Iterators</title>
|
||||
<para>
|
||||
Iterators do not perform any bounds checking. Therefore, all
|
||||
functions that work on iterators should accept them in pairs,
|
||||
denoting a range, and make sure that iterators are not moved
|
||||
outside that range. For forward iterators and bidirectional
|
||||
iterators, you need to check for equality before moving the
|
||||
first or last iterator in the range. For random-access
|
||||
iterators, you need to compute the difference before adding or
|
||||
subtracting an offset. It is not possible to perform the
|
||||
operation and check for an invalid operator afterwards.
|
||||
</para>
|
||||
<para>
|
||||
Output iterators cannot be compared for equality. Therefore, it
|
||||
is impossible to write code that detects that it has been
|
||||
supplied an output area that is too small, and their use should
|
||||
be avoided.
|
||||
</para>
|
||||
<para>
|
||||
These issues make some of the standard library functions
|
||||
difficult to use correctly, see <xref
|
||||
linkend="sect-Defensive_Coding-CXX-Std-Functions-Unpaired_Iterators"/>.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
10
en-US/CXX.xml
Normal file
10
en-US/CXX.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?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-CXX">
|
||||
<title>The C++ Programming Language</title>
|
||||
|
||||
<xi:include href="CXX-Language.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="CXX-Std.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</chapter>
|
||||
|
2
en-US/Defensive_Coding.ent
Normal file
2
en-US/Defensive_Coding.ent
Normal file
|
@ -0,0 +1,2 @@
|
|||
<!ENTITY YEAR "2012-2014">
|
||||
<!ENTITY HOLDER "Red Hat, Inc">
|
32
en-US/Defensive_Coding.xml
Normal file
32
en-US/Defensive_Coding.xml
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<book>
|
||||
<xi:include href="Book_Info.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<part>
|
||||
<title>Programming Languages</title>
|
||||
<xi:include href="C.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="CXX.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Java.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Python.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Shell.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Go.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Vala.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</part>
|
||||
<part>
|
||||
<title>Specific Programming Tasks</title>
|
||||
<xi:include href="Tasks-Library_Design.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Tasks-Descriptors.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Tasks-File_System.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Tasks-Temporary_Files.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Tasks-Processes.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Tasks-Serialization.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Tasks-Cryptography.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Tasks-Packaging.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</part>
|
||||
<part>
|
||||
<title>Implementing Security Features</title>
|
||||
<xi:include href="Features-Authentication.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Features-TLS.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</part>
|
||||
<xi:include href="Revision_History.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</book>
|
189
en-US/Features-Authentication.xml
Normal file
189
en-US/Features-Authentication.xml
Normal file
|
@ -0,0 +1,189 @@
|
|||
<?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-Authentication">
|
||||
<title>Authentication and Authorization</title>
|
||||
|
||||
<section id="sect-Defensive_Coding-Authentication-Server">
|
||||
<title>Authenticating servers</title>
|
||||
<para>
|
||||
When connecting to a server, a client has to make sure that it
|
||||
is actually talking to the server it expects. There are two
|
||||
different aspects, securing the network path, and making sure
|
||||
that the expected user runs the process on the target host.
|
||||
There are several ways to ensure that:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
The server uses a TLS certificate which is valid according
|
||||
to the web browser public key infrastructure, and the client
|
||||
verifies the certificate and the host name.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The server uses a TLS certificate which is expectedby the
|
||||
client (perhaps it is stored in a configuration file read by
|
||||
the client). In this case, no host name checking is
|
||||
required.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
On Linux, UNIX domain sockets (of the
|
||||
<literal>PF_UNIX</literal> protocol family, sometimes called
|
||||
<literal>PF_LOCAL</literal>) are restricted by file system
|
||||
permissions. If the server socket path is not
|
||||
world-writable, the server identity cannot be spoofed by
|
||||
local users.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Port numbers less than 1024 (<emphasis>trusted
|
||||
ports</emphasis>) can only be used by
|
||||
<literal>root</literal>, so if a UDP or TCP server is
|
||||
running on the local host and it uses a trusted port, its
|
||||
identity is assured. (Not all operating systems enforce the
|
||||
trusted ports concept, and the network might not be trusted,
|
||||
so it is only useful on the local system.)
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
TLS (<xref linkend="chap-Defensive_Coding-TLS"/>) is the
|
||||
recommended way for securing connections over untrusted
|
||||
networks.
|
||||
</para>
|
||||
<para>
|
||||
If the server port number is 1024 is higher, a local user can
|
||||
impersonate the process by binding to this socket, perhaps after
|
||||
crashing the real server by exploiting a denial-of-service
|
||||
vulnerability.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Authentication-Host_based">
|
||||
<title>Host-based authentication</title>
|
||||
<para>
|
||||
Host-based authentication uses access control lists (ACLs) to
|
||||
accept or deny requests from clients. Thsis authentication
|
||||
method comes in two flavors: IP-based (or, more generally,
|
||||
address-based) and name-based (with the name coming from DNS or
|
||||
<filename>/etc/hosts</filename>). IP-based ACLs often use
|
||||
prefix notation to extend access to entire subnets. Name-based
|
||||
ACLs sometimes use wildcards for adding groups of hosts (from
|
||||
entire DNS subtrees). (In the SSH context, host-based
|
||||
authentication means something completely different and is not
|
||||
covered in this section.)
|
||||
</para>
|
||||
<para>
|
||||
Host-based authentication trust the network and may not offer
|
||||
sufficient granularity, so it has to be considered a weak form
|
||||
of authentication. On the other hand, IP-based authentication
|
||||
can be made extremely robust and can be applied very early in
|
||||
input processing, so it offers an opportunity for significantly
|
||||
reducing the number of potential attackers for many services.
|
||||
</para>
|
||||
<para>
|
||||
The names returned by <function>gethostbyaddr</function> and
|
||||
<function>getnameinfo</function> functions cannot be trusted.
|
||||
(DNS PTR records can be set to arbitrary values, not just names
|
||||
belong to the address owner.) If these names are used for ACL
|
||||
matching, a forward lookup using
|
||||
<function>gethostbyaddr</function> or
|
||||
<function>getaddrinfo</function> has to be performed. The name
|
||||
is only valid if the original address is found among the results
|
||||
of the forward lookup (<emphasis>double-reverse
|
||||
lookup</emphasis>).
|
||||
</para>
|
||||
<para>
|
||||
An empty ACL should deny all access (deny-by-default). If empty
|
||||
ACLs permits all access, configuring any access list must switch
|
||||
to deny-by-default for all unconfigured protocols, in both
|
||||
name-based and address-based variants.
|
||||
</para>
|
||||
<para>
|
||||
Similarly, if an address or name is not matched by the list, it
|
||||
should be denied. However, many implementations behave
|
||||
differently, so the actual behavior must be documented properly.
|
||||
</para>
|
||||
<para>
|
||||
IPv6 addresses can embed IPv4 addresses. There is no
|
||||
universally correct way to deal with this ambiguity. The
|
||||
behavior of the ACL implementation should be documented.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Authentication-UNIX_Domain">
|
||||
<title>UNIX domain socket authentication</title>
|
||||
<para>
|
||||
UNIX domain sockets (with address family
|
||||
<literal>AF_UNIX</literal> or <literal>AF_LOCAL</literal>) are
|
||||
restricted to the local host and offer a special authentication
|
||||
mechanism: credentials passing.
|
||||
</para>
|
||||
<para>
|
||||
Nowadays, most systems support the
|
||||
<literal>SO_PEERCRED</literal> (Linux) or
|
||||
<literal>LOCAL_PEERCRED</literal> (FreeBSD) socket options, or
|
||||
the <function>getpeereid</function> (other BSDs, MacOS X).
|
||||
These interfaces provide direct access to the (effective) user
|
||||
ID on the other end of a domain socket connect, without
|
||||
cooperation from the other end.
|
||||
</para>
|
||||
<para>
|
||||
Historically, credentials passing was implemented using
|
||||
ancillary data in the <function>sendmsg</function> and
|
||||
<function>recvmsg</function> functions. On some systems, only
|
||||
credentials data that the peer has explicitly sent can be
|
||||
received, and the kernel checks the data for correctness on the
|
||||
sending side. This means that both peers need to deal with
|
||||
ancillary data. Compared to that, the modern interfaces are
|
||||
easier to use. Both sets of interfaces vary considerably among
|
||||
UNIX-like systems, unfortunately.
|
||||
</para>
|
||||
<para>
|
||||
If you want to authenticate based on supplementary groups, you
|
||||
should obtain the user ID using one of these methods, and look
|
||||
up the list of supplementary groups using
|
||||
<function>getpwuid</function> (or
|
||||
<function>getpwuid_r</function>) and
|
||||
<function>getgrouplist</function>. Using the PID and
|
||||
information from <filename>/proc/PID/status</filename> is prone
|
||||
to race conditions and insecure.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Authentication-Netlink">
|
||||
<title><literal>AF_NETLINK</literal> authentication of origin</title>
|
||||
<!-- ??? kernel change may make this obsolete:
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=851968 -->
|
||||
<para>
|
||||
Netlink messages are used as a high-performance data transfer
|
||||
mechanism between the kernel and the userspace. Traditionally,
|
||||
they are used to exchange information related to the network
|
||||
statck, such as routing table entries.
|
||||
</para>
|
||||
<para>
|
||||
When processing Netlink messages from the kernel, it is
|
||||
important to check that these messages actually originate from
|
||||
the kernel, by checking that the port ID (or PID) field
|
||||
<literal>nl_pid</literal> in the <literal>sockaddr_nl</literal>
|
||||
structure is <literal>0</literal>. (This structure can be
|
||||
obtained using <function>recvfrom</function> or
|
||||
<function>recvmsg</function>, it is different from the
|
||||
<literal>nlmsghdr</literal> structure.) The kernel does not
|
||||
prevent other processes from sending unicast Netlink messages,
|
||||
but the <literal>nl_pid</literal> field in the sender's socket
|
||||
address will be non-zero in such cases.
|
||||
</para>
|
||||
<para>
|
||||
Applications should not use <literal>AF_NETLINK</literal>
|
||||
sockets as an IPC mechanism among processes, but prefer UNIX
|
||||
domain sockets for this tasks.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
1013
en-US/Features-TLS.xml
Normal file
1013
en-US/Features-TLS.xml
Normal file
File diff suppressed because it is too large
Load diff
110
en-US/Go.xml
Normal file
110
en-US/Go.xml
Normal file
|
@ -0,0 +1,110 @@
|
|||
<?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-Go">
|
||||
<title>The Go Programming Language</title>
|
||||
<para>
|
||||
This chapter contains language-specific recommendations for Go.
|
||||
</para>
|
||||
<section id="chap-Defensive_Coding-Go-Memory_Safety">
|
||||
<title>Memory safety</title>
|
||||
<para>
|
||||
Go provides memory safety, but only if the program is not executed
|
||||
in parallel (that is, <envar>GOMAXPROCS</envar> is not larger than
|
||||
<literal>1</literal>). The reason is that interface values and
|
||||
slices consist of multiple words are not updated atomically.
|
||||
Another thread of execution can observe an inconsistent pairing
|
||||
between type information and stored value (for interfaces) or
|
||||
pointer and length (for slices), and such inconsistency can lead
|
||||
to a memory safety violation.
|
||||
</para>
|
||||
<para>
|
||||
Code which does not run in parallel and does not use the
|
||||
<literal>unsafe</literal> package (or other packages which expose
|
||||
unsafe constructs) is memory-safe. For example, invalid casts and
|
||||
out-of-range subscripting cause panics at run time.
|
||||
</para>
|
||||
<para>
|
||||
Keep in mind that finalization can introduce parallelism because
|
||||
finalizers are executed concurrently, potentially interleaved with
|
||||
the rest of the program.
|
||||
</para>
|
||||
</section>
|
||||
<section id="chap-Defensive_Coding-Go-Error_Handling">
|
||||
<title>Error handling</title>
|
||||
<para>
|
||||
Only a few common operations (such as pointer dereference, integer
|
||||
division, array subscripting) trigger exceptions in Go, called
|
||||
<emphasis>panics</emphasis>. Most interfaces in the standard
|
||||
library use a separate return value of type
|
||||
<literal>error</literal> to signal error.
|
||||
</para>
|
||||
<para>
|
||||
Not checking error return values can lead to incorrect operation
|
||||
and data loss (especially in the case of writes, using interfaces
|
||||
such as <literal>io.Writer</literal>).
|
||||
</para>
|
||||
<para>
|
||||
The correct way to check error return values depends on the
|
||||
function or method being called. In the majority of cases, the
|
||||
first step after calling a function should be an error check
|
||||
against the <literal>nil</literal> value, handling any encountered
|
||||
error. See <xref
|
||||
linkend="ex-Defensive_Coding-Go-Error_Handling-Regular"/> for
|
||||
details.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Go-Error_Handling-Regular">
|
||||
<title>Regular error handling in Go</title>
|
||||
<xi:include href="snippets/Go-Error_Handling-Regular.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
However, with <literal>io.Reader</literal>,
|
||||
<literal>io.ReaderAt</literal> and related interfaces, it is
|
||||
necessary to check for a non-zero number of read bytes first, as
|
||||
shown in <xref
|
||||
linkend="ex-Defensive_Coding-Go-Error_Handling-IO"/>. If this
|
||||
pattern is not followed, data loss may occur. This is due to the
|
||||
fact that the <literal>io.Reader</literal> interface permits
|
||||
returning both data and an error at the same time.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Go-Error_Handling-IO">
|
||||
<title>Read error handling in Go</title>
|
||||
<xi:include href="snippets/Go-Error_Handling-IO.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
</section>
|
||||
<section id="chap-Defensive_Coding-Go-Garbage_Collector">
|
||||
<title>Garbage Collector</title>
|
||||
<para>
|
||||
Older Go releases (before Go 1.3) use a conservative garbage
|
||||
collector without blacklisting. This means that data blobs can
|
||||
cause retention of unrelated data structures because the data is
|
||||
conservatively interpreted as pointers. This phenomenon can be
|
||||
triggered accidentally on 32-bit architectures and is more likely
|
||||
to occur if the heap grows larger. On 64-bit architectures, it
|
||||
may be possible to trigger it deliberately—it is unlikely to occur
|
||||
spontaneously.
|
||||
</para>
|
||||
</section>
|
||||
<section id="chap-Defensive_Coding-Go-Marshaling">
|
||||
<title>Marshaling and unmarshaling</title>
|
||||
<para>
|
||||
Several packages in the <literal>encoding</literal> hierarchy
|
||||
provide support for serialization and deserialization. The usual
|
||||
caveats apply (see
|
||||
<xref linkend="chap-Defensive_Coding-Tasks-Serialization"/>).
|
||||
</para>
|
||||
<para>
|
||||
As an additional precaution, the <function>Unmarshal</function>
|
||||
and <function>Decode</function> functions should only be used with
|
||||
fresh values in the <literal>interface{}</literal> argument. This
|
||||
is due to the way defaults for missing values are implemented:
|
||||
During deserialization, missing value do not result in an error,
|
||||
but the original value is preserved. Using a fresh value (with
|
||||
suitable default values if necessary) ensures that data from a
|
||||
previous deserialization operation does not leak into the current
|
||||
one. This is especially relevant when structs are deserialized.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
291
en-US/Java-Language.xml
Normal file
291
en-US/Java-Language.xml
Normal file
|
@ -0,0 +1,291 @@
|
|||
<?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-Java-Language">
|
||||
<title>The core language</title>
|
||||
<para>
|
||||
Implementations of the Java programming language provide strong
|
||||
memory safety, even in the presence of data races in concurrent
|
||||
code. This prevents a large range of security vulnerabilities
|
||||
from occurring, unless certain low-level features are used; see
|
||||
<xref linkend="sect-Defensive_Coding-Java-LowLevel"/>.
|
||||
</para>
|
||||
|
||||
<section id="sect-Defensive_Coding-Java-Language-ReadArray">
|
||||
<title>Inceasing robustness when reading arrays</title>
|
||||
<para>
|
||||
External data formats often include arrays, and the data is
|
||||
stored as an integer indicating the number of array elements,
|
||||
followed by this number of elements in the file or protocol data
|
||||
unit. This length specified can be much larger than what is
|
||||
actually available in the data source.
|
||||
</para>
|
||||
<para>
|
||||
To avoid allocating extremely large amounts of data, you can
|
||||
allocate a small array initially and grow it as you read more
|
||||
data, implementing an exponential growth policy. See the
|
||||
<function>readBytes(InputStream, int)</function> function in
|
||||
<xref linkend="ex-Defensive_Coding-Java-Language-ReadArray"/>.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Java-Language-ReadArray">
|
||||
<title>Incrementally reading a byte array</title>
|
||||
<xi:include href="snippets/Java-Language-ReadArray.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
When reading data into arrays, hash maps or hash sets, use the
|
||||
default constructor and do not specify a size hint. You can
|
||||
simply add the elements to the collection as you read them.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Java-Language-Resources">
|
||||
<title>Resource management</title>
|
||||
<para>
|
||||
Unlike C++, Java does not offer destructors which can deallocate
|
||||
resources in a predictable fashion. All resource management has
|
||||
to be manual, at the usage site. (Finalizers are generally not
|
||||
usable for resource management, especially in high-performance
|
||||
code; see <xref
|
||||
linkend="sect-Defensive_Coding-Java-Language-Finalizers"/>.)
|
||||
</para>
|
||||
<para>
|
||||
The first option is the
|
||||
<literal>try</literal>-<literal>finally</literal> construct, as
|
||||
shown in <xref linkend="ex-Defensive_Coding-Java-Language-Finally"/>.
|
||||
The code in the <literal>finally</literal> block should be as short as
|
||||
possible and should not throw any exceptions.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Java-Language-Finally">
|
||||
<title>Resource management with a
|
||||
<literal>try</literal>-<literal>finally</literal> block</title>
|
||||
<xi:include href="snippets/Java-Finally.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
Note that the resource allocation happens
|
||||
<emphasis>outside</emphasis> the <literal>try</literal> block,
|
||||
and that there is no <literal>null</literal> check in the
|
||||
<literal>finally</literal> block. (Both are common artifacts
|
||||
stemming from IDE code templates.)
|
||||
</para>
|
||||
<para>
|
||||
If the resource object is created freshly and implements the
|
||||
<literal>java.lang.AutoCloseable</literal> interface, the code
|
||||
in <xref
|
||||
linkend="ex-Defensive_Coding-Java-Language-TryWithResource"/> can be
|
||||
used instead. The Java compiler will automatically insert the
|
||||
<function>close()</function> method call in a synthetic
|
||||
<literal>finally</literal> block.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Java-Language-TryWithResource">
|
||||
<title>Resource management using the
|
||||
<literal>try</literal>-with-resource construct</title>
|
||||
<xi:include href="snippets/Java-TryWithResource.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
To be compatible with the <literal>try</literal>-with-resource
|
||||
construct, new classes should name the resource deallocation
|
||||
method <function>close()</function>, and implement the
|
||||
<literal>AutoCloseable</literal> interface (the latter breaking
|
||||
backwards compatibility with Java 6). However, using the
|
||||
<literal>try</literal>-with-resource construct with objects that
|
||||
are not freshly allocated is at best awkward, and an explicit
|
||||
<literal>finally</literal> block is usually the better approach.
|
||||
</para>
|
||||
<para>
|
||||
In general, it is best to design the programming interface in
|
||||
such a way that resource deallocation methods like
|
||||
<function>close()</function> cannot throw any (checked or
|
||||
unchecked) exceptions, but this should not be a reason to ignore
|
||||
any actual error conditions.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Java-Language-Finalizers">
|
||||
<title>Finalizers</title>
|
||||
<para>
|
||||
Finalizers can be used a last-resort approach to free resources
|
||||
which would otherwise leak. Finalization is unpredictable,
|
||||
costly, and there can be a considerable delay between the last
|
||||
reference to an object going away and the execution of the
|
||||
finalizer. Generally, manual resource management is required;
|
||||
see <xref linkend="sect-Defensive_Coding-Java-Language-Resources"/>.
|
||||
</para>
|
||||
<para>
|
||||
Finalizers should be very short and should only deallocate
|
||||
native or other external resources held directly by the object
|
||||
being finalized. In general, they must use synchronization:
|
||||
Finalization necessarily happens on a separate thread because it is
|
||||
inherently concurrent. There can be multiple finalization
|
||||
threads, and despite each object being finalized at most once,
|
||||
the finalizer must not assume that it has exclusive access to
|
||||
the object being finalized (in the <literal>this</literal>
|
||||
pointer).
|
||||
</para>
|
||||
<para>
|
||||
Finalizers should not deallocate resources held by other
|
||||
objects, especially if those objects have finalizers on their
|
||||
own. In particular, it is a very bad idea to define a finalizer
|
||||
just to invoke the resource deallocation method of another object,
|
||||
or overwrite some pointer fields.
|
||||
</para>
|
||||
<para>
|
||||
Finalizers are not guaranteed to run at all. For instance, the
|
||||
virtual machine (or the machine underneath) might crash,
|
||||
preventing their execution.
|
||||
</para>
|
||||
<para>
|
||||
Objects with finalizers are garbage-collected much later than
|
||||
objects without them, so using finalizers to zero out key
|
||||
material (to reduce its undecrypted lifetime in memory) may have
|
||||
the opposite effect, keeping objects around for much longer and
|
||||
prevent them from being overwritten in the normal course of
|
||||
program execution.
|
||||
</para>
|
||||
<para>
|
||||
For the same reason, code which allocates objects with
|
||||
finalizers at a high rate will eventually fail (likely with a
|
||||
<literal>java.lang.OutOfMemoryError</literal> exception) because
|
||||
the virtual machine has finite resources for keeping track of
|
||||
objects pending finalization. To deal with that, it may be
|
||||
necessary to recycle objects with finalizers.
|
||||
</para>
|
||||
<para>
|
||||
The remarks in this section apply to finalizers which are
|
||||
implemented by overriding the <function>finalize()</function>
|
||||
method, and to custom finalization using reference queues.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Java-Language-Exceptions">
|
||||
<title>Recovering from exceptions and errors</title>
|
||||
<para>
|
||||
Java exceptions come in three kinds, all ultimately deriving
|
||||
from <literal>java.lang.Throwable</literal>:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Run-time exceptions</emphasis> do not have to be
|
||||
declared explicitly and can be explicitly thrown from any
|
||||
code, by calling code which throws them, or by triggering an
|
||||
error condition at run time, like division by zero, or an
|
||||
attempt at an out-of-bounds array access. These exceptions
|
||||
derive from from the
|
||||
<literal>java.lang.RuntimeException</literal> class (perhaps
|
||||
indirectly).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Checked exceptions</emphasis> have to be declared
|
||||
explicitly by functions that throw or propagate them. They
|
||||
are similar to run-time exceptions in other regards, except
|
||||
that there is no language construct to throw them (except
|
||||
the <literal>throw</literal> statement itself). Checked
|
||||
exceptions are only present at the Java language level and
|
||||
are only enforced at compile time. At run time, the virtual
|
||||
machine does not know about them and permits throwing
|
||||
exceptions from any code. Checked exceptions must derive
|
||||
(perhaps indirectly) from the
|
||||
<literal>java.lang.Exception</literal> class, but not from
|
||||
<literal>java.lang.RuntimeException</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Errors</emphasis> are exceptions which typically
|
||||
reflect serious error conditions. They can be thrown at any
|
||||
point in the program, and do not have to be declared (unlike
|
||||
checked exceptions). In general, it is not possible to
|
||||
recover from such errors; more on that below, in <xref
|
||||
linkend="sect-Defensive_Coding-Java-Language-Exceptions-Errors"/>.
|
||||
Error classes derive (perhaps indirectly) from
|
||||
<literal>java.lang.Error</literal>, or from
|
||||
<literal>java.lang.Throwable</literal>, but not from
|
||||
<literal>java.lang.Exception</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
The general expection is that run-time errors are avoided by
|
||||
careful programming (e.g., not dividing by zero). Checked
|
||||
exception are expected to be caught as they happen (e.g., when
|
||||
an input file is unexpectedly missing). Errors are impossible
|
||||
to predict and can happen at any point and reflect that
|
||||
something went wrong beyond all expectations.
|
||||
</para>
|
||||
|
||||
<section id="sect-Defensive_Coding-Java-Language-Exceptions-Errors">
|
||||
<title>The difficulty of catching errors</title>
|
||||
<para>
|
||||
Errors (that is, exceptions which do not (indirectly) derive
|
||||
from <literal>java.lang.Exception</literal>), have the
|
||||
peculiar property that catching them is problematic. There
|
||||
are several reasons for this:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
The error reflects a failed consistenty check, for example,
|
||||
<literal>java.lang.AssertionError</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The error can happen at any point, resulting in
|
||||
inconsistencies due to half-updated objects. Examples are
|
||||
<literal>java.lang.ThreadDeath</literal>,
|
||||
<literal>java.lang.OutOfMemoryError</literal> and
|
||||
<literal>java.lang.StackOverflowError</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The error indicates that virtual machine failed to provide
|
||||
some semantic guarantees by the Java programming language.
|
||||
<literal>java.lang.ExceptionInInitializerError</literal>
|
||||
is an example—it can leave behind a half-initialized
|
||||
class.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
In general, if an error is thrown, the virtual machine should
|
||||
be restarted as soon as possible because it is in an
|
||||
inconsistent state. Continuing running as before can have
|
||||
unexpected consequences. However, there are legitimate
|
||||
reasons for catching errors because not doing so leads to even
|
||||
greater problems.
|
||||
</para>
|
||||
<para>
|
||||
Code should be written in a way that avoids triggering errors.
|
||||
See <xref linkend="sect-Defensive_Coding-Java-Language-ReadArray"/>
|
||||
for an example.
|
||||
</para>
|
||||
<para>
|
||||
It is usually necessary to log errors. Otherwise, no trace of
|
||||
the problem might be left anywhere, making it very difficult
|
||||
to diagnose realted failures. Consequently, if you catch
|
||||
<literal>java.lang.Exception</literal> to log and suppress all
|
||||
unexpected exceptions (for example, in a request dispatching
|
||||
loop), you should consider switching to
|
||||
<literal>java.lang.Throwable</literal> instead, to also cover
|
||||
errors.
|
||||
</para>
|
||||
<para>
|
||||
The other reason mainly applies to such request dispatching
|
||||
loops: If you do not catch errors, the loop stops looping,
|
||||
resulting in a denial of service.
|
||||
</para>
|
||||
<para>
|
||||
However, if possible, catching errors should be coupled with a
|
||||
way to signal the requirement of a virtual machine restart.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
157
en-US/Java-LowLevel.xml
Normal file
157
en-US/Java-LowLevel.xml
Normal file
|
@ -0,0 +1,157 @@
|
|||
<?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-Java-LowLevel">
|
||||
<title>Low-level features of the virtual machine</title>
|
||||
|
||||
<section id="sect-Defensive_Coding-Java-Reflection">
|
||||
<title><literal>Reflection and private parts</literal></title>
|
||||
<para>
|
||||
The <function>setAccessible(boolean)</function> method of the
|
||||
<literal>java.lang.reflect.AccessibleObject</literal> class
|
||||
allows a program to disable language-defined access rules for
|
||||
specific constructors, methods, or fields. Once the access
|
||||
checks are disabled, any code can use the
|
||||
<literal>java.lang.reflect.Constructor</literal>,
|
||||
<literal>java.lang.reflect.Method</literal>, or
|
||||
<literal>java.lang.reflect.Field</literal> object to access the
|
||||
underlying Java entity, without further permission checks. This
|
||||
breaks encapsulation and can undermine the stability of the
|
||||
virtual machine. (In contrast, without using the
|
||||
<function>setAccessible(boolean)</function> method, this should
|
||||
not happen because all the language-defined checks still apply.)
|
||||
</para>
|
||||
<para>
|
||||
This feature should be avoided if possible.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Java-JNI">
|
||||
<title>Java Native Interface (JNI)</title>
|
||||
<para>
|
||||
The Java Native Interface allows calling from Java code
|
||||
functions specifically written for this purpose, usually in C or
|
||||
C++.
|
||||
</para>
|
||||
<para>
|
||||
The transition between the Java world and the C world is not
|
||||
fully type-checked, and the C code can easily break the Java
|
||||
virtual machine semantics. Therefore, extra care is needed when
|
||||
using this functionality.
|
||||
</para>
|
||||
<para>
|
||||
To provide a moderate amount of type safety, it is recommended
|
||||
to recreate the class-specific header file using
|
||||
<application>javah</application> during the build process,
|
||||
include it in the implementation, and use the
|
||||
<option>-Wmissing-declarations</option> option.
|
||||
</para>
|
||||
<para>
|
||||
Ideally, the required data is directly passed to static JNI
|
||||
methods and returned from them, and the code and the C side does
|
||||
not have to deal with accessing Java fields (or even methods).
|
||||
</para>
|
||||
<para>
|
||||
When using <function>GetPrimitiveArrayCritical</function> or
|
||||
<function>GetStringCritical</function>, make sure that you only
|
||||
perform very little processing between the get and release
|
||||
operations. Do not access the file system or the network, and
|
||||
not perform locking, because that might introduce blocking.
|
||||
When processing large strings or arrays, consider splitting the
|
||||
computation into multiple sub-chunks, so that you do not prevent
|
||||
the JVM from reaching a safepoint for extended periods of time.
|
||||
</para>
|
||||
<para>
|
||||
If necessary, you can use the Java <literal>long</literal> type
|
||||
to store a C pointer in a field of a Java class. On the C side,
|
||||
when casting between the <literal>jlong</literal> value and the
|
||||
pointer on the C side,
|
||||
</para>
|
||||
<para>
|
||||
You should not try to perform pointer arithmetic on the Java
|
||||
side (that is, you should treat pointer-carrying
|
||||
<literal>long</literal> values as opaque). When passing a slice
|
||||
of an array to the native code, follow the Java convention and
|
||||
pass it as the base array, the integer offset of the start of
|
||||
the slice, and the integer length of the slice. On the native
|
||||
side, check the offset/length combination against the actual
|
||||
array length, and use the offset to compute the pointer to the
|
||||
beginning of the array.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Java-JNI-Pointers">
|
||||
<title>Array length checking in JNI code</title>
|
||||
<xi:include href="snippets/Java-JNI-Pointers.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
In any case, classes referring to native resources must be
|
||||
declared <literal>final</literal>, and must not be serializeable
|
||||
or cloneable. Initialization and mutation of the state used by
|
||||
the native side must be controlled carefully. Otherwise, it
|
||||
might be possible to create an object with inconsistent native
|
||||
state which results in a crash (or worse) when used (or perhaps
|
||||
only finalized) later. If you need both Java inheritance and
|
||||
native resources, you should consider moving the native state to
|
||||
a separate class, and only keep a reference to objects of that
|
||||
class. This way, cloning and serialization issues can be
|
||||
avoided in most cases.
|
||||
</para>
|
||||
<para>
|
||||
If there are native resources associated with an object, the
|
||||
class should have an explicit resource deallocation method
|
||||
(<xref
|
||||
linkend="sect-Defensive_Coding-Java-Language-Resources"/>) and a
|
||||
finalizer (<xref
|
||||
linkend="sect-Defensive_Coding-Java-Language-Finalizers"/>) as a
|
||||
last resort. The need for finalization means that a minimum
|
||||
amount of synchronization is needed. Code on the native side
|
||||
should check that the object is not in a closed/freed state.
|
||||
</para>
|
||||
<para>
|
||||
Many JNI functions create local references. By default, these
|
||||
persist until the JNI-implemented method returns. If you create
|
||||
many such references (e.g., in a loop), you may have to free
|
||||
them using <function>DeleteLocalRef</function>, or start using
|
||||
<function>PushLocalFrame</function> and
|
||||
<function>PopLocalFrame</function>. Global references must be
|
||||
deallocated with <function>DeleteGlobalRef</function>, otherwise
|
||||
there will be a memory leak, just as with
|
||||
<function>malloc</function> and <function>free</function>.
|
||||
</para>
|
||||
<para>
|
||||
When throwing exceptions using <function>Throw</function> or
|
||||
<function>ThrowNew</function>, be aware that these functions
|
||||
return regularly. You have to return control manually to the
|
||||
JVM.
|
||||
</para>
|
||||
<para>
|
||||
Technically, the <literal>JNIEnv</literal> pointer is not
|
||||
necessarily constant during the lifetime of your JNI module.
|
||||
Storing it in a global variable is therefore incorrect.
|
||||
Particularly if you are dealing with callbacks, you may have to
|
||||
store the pointer in a thread-local variable (defined with
|
||||
<literal>__thread</literal>). It is, however, best to avoid the
|
||||
complexity of calling back into Java code.
|
||||
</para>
|
||||
<para>
|
||||
Keep in mind that C/C++ and Java are different languages,
|
||||
despite very similar syntax for expressions. The Java memory
|
||||
model is much more strict than the C or C++ memory models, and
|
||||
native code needs more synchronization, usually using JVM
|
||||
facilities or POSIX threads mutexes. Integer overflow in Java
|
||||
is defined, but in C/C++ it is not (for the
|
||||
<literal>jint</literal> and <literal>jlong</literal> types).
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Java-MiscUnsafe">
|
||||
<title><literal>sun.misc.Unsafe</literal></title>
|
||||
<para>
|
||||
The <literal>sun.misc.Unsafe</literal> class is unportable and
|
||||
contains many functions explicitly designed to break Java memory
|
||||
safety (for performance and debugging). If possible, avoid
|
||||
using this class.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
292
en-US/Java-SecurityManager.xml
Normal file
292
en-US/Java-SecurityManager.xml
Normal file
|
@ -0,0 +1,292 @@
|
|||
<?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-Java-SecurityManager">
|
||||
<title>Interacting with the security manager</title>
|
||||
<para>
|
||||
The Java platform is largely implemented in the Java language
|
||||
itself. Therefore, within the same JVM, code runs which is part
|
||||
of the Java installation and which is trusted, but there might
|
||||
also be code which comes from untrusted sources and is restricted
|
||||
by the Java sandbox (to varying degrees). The <emphasis>security
|
||||
manager</emphasis> draws a line between fully trusted, partially
|
||||
trusted and untrusted code.
|
||||
</para>
|
||||
<para>
|
||||
The type safety and accessibility checks provided by the Java
|
||||
language and JVM would be sufficient to implement a sandbox.
|
||||
However, only some Java APIs employ such a capabilities-based
|
||||
approach. (The Java SE library contains many public classes with
|
||||
public constructors which can break any security policy, such as
|
||||
<literal>java.io.FileOutputStream</literal>.) Instead, critical
|
||||
functionality is protected by <emphasis>stack
|
||||
inspection</emphasis>: At a security check, the stack is walked
|
||||
from top (most-nested) to bottom. The security check fails if a
|
||||
stack frame for a method is encountered whose class lacks the
|
||||
permission which the security check requires.
|
||||
</para>
|
||||
<para>
|
||||
This simple approach would not allow untrusted code (which lacks
|
||||
certain permissions) to call into trusted code while the latter
|
||||
retains trust. Such trust transitions are desirable because they
|
||||
enable Java as an implementation language for most parts of the
|
||||
Java platform, including security-relevant code. Therefore, there
|
||||
is a mechanism to mark certain stack frames as trusted (<xref
|
||||
linkend="sect-Defensive_Coding-Java-SecurityManager-Privileged"/>).
|
||||
</para>
|
||||
<para>
|
||||
In theory, it is possible to run a Java virtual machine with a
|
||||
security manager that acts very differently from this approach,
|
||||
but a lot of code expects behavior very close to the platform
|
||||
default (including many classes which are part of the OpenJDK
|
||||
implementation).
|
||||
</para>
|
||||
|
||||
<section id="sect-Defensive_Coding-Java-SecurityManager-Compatible">
|
||||
<title>Security manager compatibility</title>
|
||||
<para>
|
||||
A lot of code can run without any additional permissions at all,
|
||||
with little changes. The following guidelines should help to
|
||||
increase compatibility with a restrictive security manager.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
When retrieving system properties using
|
||||
<function>System.getProperty(String)</function> or similar
|
||||
methods, catch <literal>SecurityException</literal>
|
||||
exceptions and treat the property as unset.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Avoid unnecessary file system or network access.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Avoid explicit class loading. Access to a suitable class
|
||||
loader might not be available when executing as untrusted
|
||||
code.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
If the functionality you are implementing absolutely requires
|
||||
privileged access and this functionality has to be used from
|
||||
untrusted code (hopefully in a restricted and secure manner),
|
||||
see <xref
|
||||
linkend="sect-Defensive_Coding-Java-SecurityManager-Privileged"/>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Java-SecurityManager-Activate">
|
||||
<title>Activating the security manager</title>
|
||||
<para>
|
||||
The usual command to launch a Java application,
|
||||
<command>java</command>, does not activate the security manager.
|
||||
Therefore, the virtual machine does not enforce any sandboxing
|
||||
restrictions, even if explicitly requested by the code (for
|
||||
example, as described in <xref
|
||||
linkend="sect-Defensive_Coding-Java-SecurityManager-Unprivileged"/>).
|
||||
</para>
|
||||
<para>
|
||||
The <option>-Djava.security.manager</option> option activates
|
||||
the security manager, with the fairly restrictive default
|
||||
policy. With a very permissive policy, most Java code will run
|
||||
unchanged. Assuming the policy in <xref
|
||||
linkend="ex-Defensive_Coding-Java-SecurityManager-GrantAll"/>
|
||||
has been saved in a file <filename>grant-all.policy</filename>,
|
||||
this policy can be activated using the option
|
||||
<option>-Djava.security.policy=grant-all.policy</option> (in
|
||||
addition to the <option>-Djava.security.manager</option>
|
||||
option).
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Java-SecurityManager-GrantAll">
|
||||
<title>Most permissve OpenJDK policy file</title>
|
||||
<programlisting>
|
||||
grant {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
</programlisting>
|
||||
</example>
|
||||
<para>
|
||||
With this most permissive policy, the security manager is still
|
||||
active, and explicit requests to drop privileges will be
|
||||
honored.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Java-SecurityManager-Unprivileged">
|
||||
<title>Reducing trust in code</title>
|
||||
<para>
|
||||
<xref linkend="ex-Defensive_Coding-Java-SecurityManager-Unprivileged"/>
|
||||
shows how to run a piece code of with reduced privileges.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Java-SecurityManager-Unprivileged">
|
||||
<title>Using the security manager to run code with reduced
|
||||
privileges</title>
|
||||
<xi:include href="snippets/Java-SecurityManager-Unprivileged.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
The example above does not add any additional permissions to the
|
||||
<literal>permissions</literal> object. If such permissions are
|
||||
necessary, code like the following (which grants read permission
|
||||
on all files in the current directory) can be used:
|
||||
</para>
|
||||
<informalexample>
|
||||
<xi:include href="snippets/Java-SecurityManager-CurrentDirectory.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</informalexample>
|
||||
<important>
|
||||
<para>
|
||||
Calls to the
|
||||
<function>java.security.AccessController.doPrivileged()</function>
|
||||
methods do not enforce any additional restriction if no
|
||||
security manager has been set. Except for a few special
|
||||
exceptions, the restrictions no longer apply if the
|
||||
<function>doPrivileged()</function> has returned, even to
|
||||
objects created by the code which ran with reduced privileges.
|
||||
(This applies to object finalization in particular.)
|
||||
</para>
|
||||
<para>
|
||||
The example code above does not prevent the called code from
|
||||
calling the
|
||||
<function>java.security.AccessController.doPrivileged()</function>
|
||||
methods. This mechanism should be considered an additional
|
||||
safety net, but it still can be used to prevent unexpected
|
||||
behavior of trusted code. As long as the executed code is not
|
||||
dynamic and came with the original application or library, the
|
||||
sandbox is fairly effective.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>context</literal> argument in <xref
|
||||
linkend="ex-Defensive_Coding-Java-SecurityManager-Unprivileged"/>
|
||||
is extremely important—otherwise, this code would increase
|
||||
privileges instead of reducing them.
|
||||
</para>
|
||||
</important>
|
||||
<para>
|
||||
For activating the security manager, see <xref
|
||||
linkend="sect-Defensive_Coding-Java-SecurityManager-Activate"/>.
|
||||
Unfortunately, this affects the virtual machine as a whole, so
|
||||
it is not possible to do this from a library.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Java-SecurityManager-Privileged">
|
||||
<title>Re-gaining privileges</title>
|
||||
<para>
|
||||
Ordinarily, when trusted code is called from untrusted code, it
|
||||
loses its privileges (because of the untrusted stack frames
|
||||
visible to stack inspection). The
|
||||
<function>java.security.AccessController.doPrivileged()</function>
|
||||
family of methods provides a controlled backdoor from untrusted
|
||||
to trusted code.
|
||||
</para>
|
||||
<important>
|
||||
<para>
|
||||
By design, this feature can undermine the Java security model
|
||||
and the sandbox. It has to be used very carefully. Most
|
||||
sandbox vulnerabilities can be traced back to its misuse.
|
||||
</para>
|
||||
</important>
|
||||
<para>
|
||||
In essence, the <function>doPrivileged()</function> methods
|
||||
cause the stack inspection to end at their call site. Untrusted
|
||||
code further down the call stack becomes invisible to security
|
||||
checks.
|
||||
</para>
|
||||
<para>
|
||||
The following operations are common and safe to perform with
|
||||
elevated privileges.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Reading custom system properties with fixed names,
|
||||
especially if the value is not propagated to untrusted code.
|
||||
(File system paths including installation paths, host names
|
||||
and user names are sometimes considered private information
|
||||
and need to be protected.)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Reading from the file system at fixed paths, either
|
||||
determined at compile time or by a system property. Again,
|
||||
leaking the file contents to the caller can be problematic.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Accessing network resources under a fixed address, name or
|
||||
URL, derived from a system property or configuration file,
|
||||
information leaks not withstanding.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
<xref linkend="ex-Defensive_Coding-Java-SecurityManager-Privileged"/>
|
||||
shows how to request additional privileges.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Java-SecurityManager-Privileged">
|
||||
<title>Using the security manager to run code with increased
|
||||
privileges</title>
|
||||
<xi:include href="snippets/Java-SecurityManager-Privileged.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
Obviously, this only works if the class containing the call to
|
||||
<function>doPrivileged()</function> is marked trusted (usually
|
||||
because it is loaded from a trusted class loader).
|
||||
</para>
|
||||
<para>
|
||||
When writing code that runs with elevated privileges, make sure
|
||||
that you follow the rules below.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Make the privileged code as small as possible. Perform as
|
||||
many computations as possible before and after the
|
||||
privileged code section, even if it means that you have to
|
||||
define a new class to pass the data around.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Make sure that you either control the inputs to the
|
||||
privileged code, or that the inputs are harmless and cannot
|
||||
affect security properties of the privileged code.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Data that is returned from or written by the privileged code
|
||||
must either be restricted (that is, it cannot be accessed by
|
||||
untrusted code), or must be harmless. Otherwise, privacy
|
||||
leaks or information disclosures which affect security
|
||||
properties can be the result.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
If the code calls back into untrusted code at a later stage (or
|
||||
performs other actions under control from the untrusted caller),
|
||||
you must obtain the original security context and restore it
|
||||
before performing the callback, as in <xref
|
||||
linkend="ex-Defensive_Coding-Java-SecurityManager-Callback"/>.
|
||||
(In this example, it would be much better to move the callback
|
||||
invocation out of the privileged code section, of course.)
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Java-SecurityManager-Callback">
|
||||
<title>Restoring privileges when invoking callbacks</title>
|
||||
<xi:include href="snippets/Java-SecurityManager-Callback.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
11
en-US/Java.xml
Normal file
11
en-US/Java.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?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-Java">
|
||||
<title>The Java Programming Language</title>
|
||||
|
||||
<xi:include href="Java-Language.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Java-LowLevel.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Java-SecurityManager.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</chapter>
|
||||
|
74
en-US/Python.xml
Normal file
74
en-US/Python.xml
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?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" [
|
||||
]>
|
||||
<chapter id="chap-Defensive_Coding-Python">
|
||||
<title>The Python Programming Language</title>
|
||||
<para>
|
||||
Python provides memory safety by default, so low-level security
|
||||
vulnerabilities are rare and typically needs fixing the Python
|
||||
interpreter or standard library itself.
|
||||
</para>
|
||||
<para>
|
||||
Other sections with Python-specific advice include:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<xref linkend="chap-Defensive_Coding-Tasks-Temporary_Files"/>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<xref linkend="sect-Defensive_Coding-Tasks-Processes-Creation"/>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<xref linkend="chap-Defensive_Coding-Tasks-Serialization"/>, in
|
||||
particular <xref linkend="sect-Defensive_Coding-Tasks-Serialization-Library"/>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<xref linkend="sect-Defensive_Coding-Tasks-Cryptography-Randomness"/>
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<section>
|
||||
<title>Dangerous standard library features</title>
|
||||
<para>
|
||||
Some areas of the standard library, notably the
|
||||
<literal>ctypes</literal> module, do not provide memory safety
|
||||
guarantees comparable to the rest of Python. If such
|
||||
functionality is used, the advice in <xref
|
||||
linkend="sect-Defensive_Coding-C-Language"/> should be followed.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Run-time compilation and code generation</title>
|
||||
<para>
|
||||
The following Python functions and statements related to code
|
||||
execution should be avoided:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem><para><function>compile</function></para></listitem>
|
||||
<listitem><para><function>eval</function></para></listitem>
|
||||
<listitem><para><literal>exec</literal></para></listitem>
|
||||
<listitem><para><function>execfile</function></para></listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
If you need to parse integers or floating point values, use the
|
||||
<function>int</function> and <function>float</function>
|
||||
functions instead of <function>eval</function>. Sandboxing
|
||||
untrusted Python code does not work reliably.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Sandboxing</title>
|
||||
<para>
|
||||
The <literal>rexec</literal> Python module cannot safely sandbox
|
||||
untrusted code and should not be used. The standard CPython
|
||||
implementation is not suitable for sandboxing.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
96
en-US/Revision_History.xml
Normal file
96
en-US/Revision_History.xml
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE appendix PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!ENTITY % BOOK_ENTITIES SYSTEM "Defensive_Coding.ent">
|
||||
%BOOK_ENTITIES;
|
||||
]>
|
||||
<appendix id="appe-Defensive_Coding-Revision_History">
|
||||
<title>Revision History</title>
|
||||
<simpara>
|
||||
<revhistory>
|
||||
<revision>
|
||||
<revnumber>1.3-1</revnumber>
|
||||
<date>Mon Oct 13 2014</date>
|
||||
<author>
|
||||
<firstname>Florian</firstname>
|
||||
<surname>Weimer</surname>
|
||||
<email>fweimer@redhat.com</email>
|
||||
</author>
|
||||
<revdescription>
|
||||
<simplelist>
|
||||
<member>Go: Mention default value handling in deserialization</member>
|
||||
<member>Shell: New chapter</member>
|
||||
</simplelist>
|
||||
</revdescription>
|
||||
</revision>
|
||||
<revision>
|
||||
<revnumber>1.2-1</revnumber>
|
||||
<date>Wed Jul 16 2014</date>
|
||||
<author>
|
||||
<firstname>Florian</firstname>
|
||||
<surname>Weimer</surname>
|
||||
<email>fweimer@redhat.com</email>
|
||||
</author>
|
||||
<revdescription>
|
||||
<simplelist>
|
||||
<member>C: Corrected the <function>strncat</function> example</member>
|
||||
<member>C: Mention mixed signed/unsigned comparisons</member>
|
||||
<member>C: Unsigned overflow checking example</member>
|
||||
<member>C++: <literal>operator new[]</literal> has been fixed in GCC</member>
|
||||
<member>C++: Additional material on <literal>std::string</literal>, iterators</member>
|
||||
<member>OpenSSL: Mention <command>openssl genrsa</command> entropy issue</member>
|
||||
<member>Packaging: X.509 key generation</member>
|
||||
<member>Go, Vala: Add short chapters</member>
|
||||
<member>Serialization: Notes on fragmentation and reassembly</member>
|
||||
</simplelist>
|
||||
</revdescription>
|
||||
</revision>
|
||||
<revision>
|
||||
<revnumber>1.1-1</revnumber>
|
||||
<date>Tue Aug 27 2013</date>
|
||||
<author>
|
||||
<firstname>Eric</firstname>
|
||||
<surname>Christensen</surname>
|
||||
<email>sparks@redhat.com</email>
|
||||
</author>
|
||||
<revdescription>
|
||||
<simplelist>
|
||||
<member>Add a chapter which covers some Java topics.</member>
|
||||
<member>Deserialization: Warn about Java's java.beans.XMLDecoder.</member>
|
||||
<member>C: Correct the advice on array allocation
|
||||
(<ulink url="https://bugzilla.redhat.com/show_bug.cgi?id=995595">bug 995595</ulink>).</member>
|
||||
<member>C: Add material on global variables.</member>
|
||||
</simplelist>
|
||||
</revdescription>
|
||||
</revision>
|
||||
<revision>
|
||||
<revnumber>1.0-1</revnumber>
|
||||
<date>Thu May 09 2013</date>
|
||||
<author>
|
||||
<firstname>Eric</firstname>
|
||||
<surname>Christensen</surname>
|
||||
<email>sparks@redhat.com</email>
|
||||
</author>
|
||||
<revdescription>
|
||||
<simplelist>
|
||||
<member>Added more C and C++ examples.</member>
|
||||
<member>TLS Client NSS: Rely on NSS 3.14 cipher suite defaults.</member>
|
||||
</simplelist>
|
||||
</revdescription>
|
||||
</revision>
|
||||
<revision>
|
||||
<revnumber>0-1</revnumber>
|
||||
<date>Thu Mar 7 2013</date>
|
||||
<author>
|
||||
<firstname>Eric</firstname>
|
||||
<surname>Christensen</surname>
|
||||
<email>sparks@redhat.com</email>
|
||||
</author>
|
||||
<revdescription>
|
||||
<simplelist>
|
||||
<member>Initial publication.</member>
|
||||
</simplelist>
|
||||
</revdescription>
|
||||
</revision>
|
||||
</revhistory>
|
||||
</simpara>
|
||||
</appendix>
|
454
en-US/Shell.xml
Normal file
454
en-US/Shell.xml
Normal file
|
@ -0,0 +1,454 @@
|
|||
<?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-Shell">
|
||||
<title>Shell Programming and <application>bash</application></title>
|
||||
<para>
|
||||
This chapter contains advice about shell programming, specifically
|
||||
in <application>bash</application>. Most of the advice will apply
|
||||
to scripts written for other shells because extensions such as
|
||||
integer or array variables have been implemented there as well, with
|
||||
comparable syntax.
|
||||
</para>
|
||||
<section id="sect-Defensive_Coding-Shell-Alternatives">
|
||||
<title>Consider alternatives</title>
|
||||
<para>
|
||||
Once a shell script is so complex that advice in this chapter
|
||||
applies, it is time to step back and consider the question: Is
|
||||
there a more suitable implementation language available?
|
||||
</para>
|
||||
<para>
|
||||
For example, Python with its <literal>subprocess</literal> module
|
||||
can be used to write scripts which are almost as concise as shell
|
||||
scripts when it comes to invoking external programs, and Python
|
||||
offers richer data structures, with less arcane syntax and more
|
||||
consistent behavior.
|
||||
</para>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-Shell-Language">
|
||||
<title>Shell language features</title>
|
||||
<para>
|
||||
The following sections cover subtleties concerning the shell
|
||||
programming languages. They have been written with the
|
||||
<application>bash</application> shell in mind, but some of these
|
||||
features apply to other shells as well.
|
||||
</para>
|
||||
<para>
|
||||
Some of the features described may seem like implementation defects,
|
||||
but these features have been replicated across multiple independent
|
||||
implementations, so they now have to be considered part of the shell
|
||||
programming language.
|
||||
</para>
|
||||
<section id="sect-Defensive_Coding-Shell-Parameter_Expansion">
|
||||
<title>Parameter expansion</title>
|
||||
<para>
|
||||
The mechanism by which named shell variables and parameters are
|
||||
expanded is called <emphasis>parameter expansion</emphasis>. The
|
||||
most basic syntax is
|
||||
“<literal>$</literal><emphasis>variable</emphasis>” or
|
||||
“<literal>${</literal><emphasis>variable</emphasis><literal>}</literal>”.
|
||||
</para>
|
||||
<para>
|
||||
In almost all cases, a parameter expansion should be enclosed in
|
||||
double quotation marks <literal>"</literal>…<literal>"</literal>.
|
||||
</para>
|
||||
<informalexample>
|
||||
<programlisting language="Bash">
|
||||
external-program "$arg1" "$arg2"
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
<para>
|
||||
If the double quotation marks are omitted, the value of the
|
||||
variable will be split according to the current value of the
|
||||
<envar>IFS</envar> variable. This may allow the injection of
|
||||
additional options which are then processed by
|
||||
<literal>external-program</literal>.
|
||||
</para>
|
||||
<para>
|
||||
Parameter expansion can use special syntax for specific features,
|
||||
such as substituting defaults or performing string or array
|
||||
operations. These constructs should not be used because they can
|
||||
trigger arithmetic evaluation, which can result in code execution.
|
||||
See <xref linkend="sect-Defensive_Coding-Shell-Arithmetic"/>.
|
||||
</para>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-Shell-Double_Expansion">
|
||||
<title>Double expansion</title>
|
||||
<para>
|
||||
<emphasis>Double expansion</emphasis> occurs when, during the
|
||||
expansion of a shell variable, not just the variable is expanded,
|
||||
replacing it by its value, but the <emphasis>value</emphasis> of
|
||||
the variable is itself is expanded as well. This can trigger
|
||||
arbitrary code execution, unless the value of the variable is
|
||||
verified against a restrictive pattern.
|
||||
</para>
|
||||
<para>
|
||||
The evaluation process is in fact recursive, so a self-referential
|
||||
expression can cause an out-of-memory condition and a shell crash.
|
||||
</para>
|
||||
<para>
|
||||
Double expansion may seem like as a defect, but it is implemented
|
||||
by many shells, and has to be considered an integral part of the
|
||||
shell programming language. However, it does make writing robust
|
||||
shell scripts difficult.
|
||||
</para>
|
||||
<para>
|
||||
Double expansion can be requested explicitly with the
|
||||
<literal>eval</literal> built-in command, or by invoking a
|
||||
subshell with “<literal>bash -c</literal>”. These constructs
|
||||
should not be used.
|
||||
</para>
|
||||
<para>
|
||||
The following sections give examples of places where implicit
|
||||
double expansion occurs.
|
||||
</para>
|
||||
<section id="sect-Defensive_Coding-Shell-Arithmetic">
|
||||
<title>Arithmetic evaluation</title>
|
||||
<para>
|
||||
<emphasis>Arithmetic evaluation</emphasis> is a process by which
|
||||
the shell computes the integer value of an expression specified
|
||||
as a string. It is highly problematic for two reasons: It
|
||||
triggers double expansion (see <xref
|
||||
linkend="sect-Defensive_Coding-Shell-Double_Expansion"/>), and the
|
||||
language of arithmetic expressions is not self-contained. Some
|
||||
constructs in arithmetic expressions (notably array subscripts)
|
||||
provide a trapdoor from the restricted language of arithmetic
|
||||
expressions to the full shell language, thus paving the way
|
||||
towards arbitrary code execution. Due to double expansion,
|
||||
input which is (indirectly) referenced from an arithmetic
|
||||
expression can trigger execution of arbitrary code, which is
|
||||
potentially harmful.
|
||||
</para>
|
||||
<para>
|
||||
Arithmetic evaluation is triggered by the follow constructs:
|
||||
</para>
|
||||
<!-- The list was constructed by looking at the bash sources and
|
||||
search for the string "expand_". -->
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>expression</emphasis> in
|
||||
“<literal>$((</literal><emphasis>expression</emphasis><literal>))</literal>”
|
||||
is evaluated. This construct is called <emphasis>arithmetic
|
||||
expansion</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
“<literal>$[</literal><emphasis>expression</emphasis><literal>]</literal>”
|
||||
is a deprecated syntax with the same effect.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The arguments to the <literal>let</literal> shell built-in
|
||||
are evaluated.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
“<literal>((</literal><emphasis>expression</emphasis><literal>))</literal>”
|
||||
is an alternative syntax for “<literal>let
|
||||
</literal><emphasis>expression</emphasis>”.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Conditional expressions surrounded by
|
||||
“<literal>[[</literal>…<literal>]]</literal>” can trigger
|
||||
arithmetic evaluation if certain operators such as
|
||||
<literal>-eq</literal> are used. (The
|
||||
<literal>test</literal> built-in does not perform arithmetic
|
||||
evaluation, even with integer operators such as
|
||||
<literal>-eq</literal>.)
|
||||
</para>
|
||||
<para>
|
||||
The conditional expression
|
||||
“<literal>[[ $</literal><emphasis>variable</emphasis><literal> =~ </literal><emphasis>regexp</emphasis><literal> ]]</literal>”
|
||||
can be used for input validation, assuming that
|
||||
<emphasis>regexp</emphasis> is a constant regular
|
||||
expression.
|
||||
See <xref linkend="sect-Defensive_Coding-Shell-Input_Validation"/>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Certain parameter expansions, for example
|
||||
“<literal>${</literal><emphasis>variable</emphasis><literal>[</literal><emphasis>expression</emphasis><literal>]}</literal>”
|
||||
(array indexing) or
|
||||
“<literal>${</literal><emphasis>variable</emphasis><literal>:</literal><emphasis>expression</emphasis><literal>}</literal>”
|
||||
(string slicing), trigger arithmetic evaluation of
|
||||
<emphasis>expression</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Assignment to array elements using
|
||||
“<emphasis>array_variable</emphasis><literal>[</literal><emphasis>subscript</emphasis><literal>]=</literal><emphasis>expression</emphasis>”
|
||||
triggers evaluation of <emphasis>subscript</emphasis>, but
|
||||
not <emphasis>expression</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The expressions in the arithmetic <literal>for</literal>
|
||||
command,
|
||||
“<literal>for ((</literal><emphasis>expression1</emphasis><literal>; </literal><emphasis>expression2</emphasis><literal>; </literal><emphasis>expression3</emphasis><literal>)); do </literal><emphasis>commands</emphasis><literal>; done</literal>”
|
||||
are evaluated. This does not apply to the regular
|
||||
for command,
|
||||
“<literal>for </literal><emphasis>variable</emphasis><literal> in </literal><emphasis>list</emphasis><literal>; do </literal><emphasis>commands</emphasis><literal>; done</literal>”.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<important>
|
||||
<para>
|
||||
Depending on the <application>bash</application> version, the
|
||||
above list may be incomplete.
|
||||
</para>
|
||||
<para>
|
||||
If faced with a situation where using such shell features
|
||||
appears necessary, see <xref
|
||||
linkend="sect-Defensive_Coding-Shell-Alternatives"/>.
|
||||
</para>
|
||||
</important>
|
||||
<para>
|
||||
If it is impossible to avoid shell arithmetic on untrusted
|
||||
inputs, refer to <xref
|
||||
linkend="sect-Defensive_Coding-Shell-Input_Validation"/>.
|
||||
</para>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-Shell-Types">
|
||||
<title>Type declarations</title>
|
||||
<para>
|
||||
<application>bash</application> supports explicit type
|
||||
declarations for shell variables:
|
||||
</para>
|
||||
<informalexample>
|
||||
<programlisting language="Bash">
|
||||
declare -i integer_variable
|
||||
declare -a array_variable
|
||||
declare -A assoc_array_variable
|
||||
|
||||
typeset -i integer_variable
|
||||
typeset -a array_variable
|
||||
typeset -A assoc_array_variable
|
||||
|
||||
local -i integer_variable
|
||||
local -a array_variable
|
||||
local -A assoc_array_variable
|
||||
|
||||
readonly -i integer_variable
|
||||
readonly -a array_variable
|
||||
readonly -A assoc_array_variable
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
<para>
|
||||
Variables can also be declared as arrays by assigning them an
|
||||
array expression, as in:
|
||||
</para>
|
||||
<informalexample>
|
||||
<programlisting language="Bash">
|
||||
array_variable=(1 2 3 4)
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
<para>
|
||||
Some built-ins (such as <literal>mapfile</literal>) can
|
||||
implicitly create array variables.
|
||||
</para>
|
||||
<para>
|
||||
Such type declarations should not be used because assignment to
|
||||
such variables (independent of the concrete syntax used for the
|
||||
assignment) triggers arithmetic expansion (and thus double
|
||||
expansion) of the right-hand side of the assignment operation.
|
||||
See <xref linkend="sect-Defensive_Coding-Shell-Arithmetic"/>.
|
||||
</para>
|
||||
<para>
|
||||
Shell scripts which use integer or array variables should be
|
||||
rewritten in another, more suitable language. Se <xref
|
||||
linkend="sect-Defensive_Coding-Shell-Alternatives"/>.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-Shell-Obscure">
|
||||
<title>Other obscurities</title>
|
||||
<para>
|
||||
Obscure shell language features should not be used. Examples are:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Exported functions (<literal>export -f</literal> or
|
||||
<literal>declare -f</literal>).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Function names which are not valid variable names, such as
|
||||
“<literal>module::function</literal>”.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The possibility to override built-ins or external commands
|
||||
with shell functions.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Changing the value of the <envar>IFS</envar> variable to
|
||||
tokenize strings.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-Shell-Invoke">
|
||||
<title>Invoking external commands</title>
|
||||
<para>
|
||||
When passing shell variables as single command line arguments,
|
||||
they should always be surrounded by double quotes. See
|
||||
<xref linkend="sect-Defensive_Coding-Shell-Parameter_Expansion"/>.
|
||||
</para>
|
||||
<para>
|
||||
Care is required when passing untrusted values as positional
|
||||
parameters to external commands. If the value starts with a hyphen
|
||||
“<literal>-</literal>”, it may be interpreted by the external
|
||||
command as an option. Depending on the external program, a
|
||||
“<literal>--</literal>” argument stops option processing and treats
|
||||
all following arguments as positional parameters. (Double quotes
|
||||
are completely invisible to the command being invoked, so they do
|
||||
not prevent variable values from being interpreted as options.)
|
||||
</para>
|
||||
<para>
|
||||
Cleaning the environment before invoking child processes is
|
||||
difficult to implement in script. <application>bash</application>
|
||||
keeps a hidden list of environment variables which do not correspond
|
||||
to shell variables, and unsetting them from within a
|
||||
<application>bash</application> script is not possible. To reset
|
||||
the environment, a script can re-run itself under the “<literal>env
|
||||
-i</literal>” command with an additional parameter which indicates
|
||||
the environment has been cleared and suppresses a further
|
||||
self-execution. Alternatively, individual commands can be executed
|
||||
with “<literal>env -i</literal>”.
|
||||
</para>
|
||||
<important>
|
||||
<para>
|
||||
Completely isolation from its original execution environment
|
||||
(which is required when the script is executed after a trust
|
||||
transition, e.g., triggered by the SUID mechanism) is impossible
|
||||
to achieve from within the shell script itself. Instead, the
|
||||
invoking process has to clear the process environment (except for
|
||||
few trusted variables) before running the shell script.
|
||||
</para>
|
||||
</important>
|
||||
<para>
|
||||
Checking for failures in executed external commands is recommended.
|
||||
If no elaborate error recovery is needed, invoking “<literal>set
|
||||
-e</literal>” may be sufficient. This causes the script to stop on
|
||||
the first failed command. However, failures in pipes
|
||||
(“<literal>command1 | command2</literal>”) are only detected for the
|
||||
last command in the pipe, errors in previous commands are ignored.
|
||||
This can be changed by invoking “<literal>set -o pipefail</literal>”.
|
||||
Due to architectural limitations, only the process that spawned
|
||||
the entire pipe can check for failures in individual commands;
|
||||
it is not possible for a process to tell if the process feeding
|
||||
data (or the process consuming data) exited normally or with
|
||||
an error.
|
||||
</para>
|
||||
<para>
|
||||
See <xref linkend="sect-Defensive_Coding-Tasks-Processes-Creation"/>
|
||||
for additional details on creating child processes.
|
||||
</para>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-Shell-Temporary_Files">
|
||||
<title>Temporary files</title>
|
||||
<para>
|
||||
Temporary files should be created with the
|
||||
<literal>mktemp</literal> command, and temporary directories with
|
||||
“<literal>mktemp -d</literal>”.
|
||||
</para>
|
||||
<para>
|
||||
To clean up temporary files and directories, write a clean-up
|
||||
shell function and register it as a trap handler, as shown in
|
||||
<xref linkend="ex-Defensive_Coding-Tasks-Temporary_Files"/>.
|
||||
Using a separate function avoids issues with proper quoting of
|
||||
variables.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Tasks-Temporary_Files">
|
||||
<title>Creating and cleaning up temporary files</title>
|
||||
<informalexample>
|
||||
<programlisting language="Bash">
|
||||
tmpfile="$(mktemp)"
|
||||
|
||||
cleanup () {
|
||||
rm -f -- "$tmpfile"
|
||||
}
|
||||
|
||||
trap cleanup 0
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
</example>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-Shell-Input_Validation">
|
||||
<title>Performing input validation</title>
|
||||
<para>
|
||||
In some cases, input validation cannot be avoided. For example,
|
||||
if arithmetic evaluation is absolutely required, it is imperative
|
||||
to check that input values are, in fact, integers. See <xref
|
||||
linkend="sect-Defensive_Coding-Shell-Arithmetic"/>.
|
||||
</para>
|
||||
<para>
|
||||
<xref linkend="ex-Defensive_Coding-Shell-Input_Validation"/>
|
||||
shows a construct which can be used to check if a string
|
||||
“<literal>$value</literal>” is an integer. This construct is
|
||||
specific to <application>bash</application> and not portable to
|
||||
POSIX shells.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Shell-Input_Validation">
|
||||
<title>Input validation in <application>bash</application></title>
|
||||
<xi:include href="snippets/Shell-Input_Validation.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
Using <literal>case</literal> statements for input validation is
|
||||
also possible and supported by other (POSIX) shells, but the
|
||||
pattern language is more restrictive, and it can be difficult to
|
||||
write suitable patterns.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>expr</literal> external command can give misleading
|
||||
results (e.g., if the value being checked contains operators
|
||||
itself) and should not be used.
|
||||
</para>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-Shell-Edit_Guard">
|
||||
<title>Guarding shell scripts against changes</title>
|
||||
<para>
|
||||
<application>bash</application> only reads a shell script up to
|
||||
the point it is needed for executed the next command. This means
|
||||
that if script is overwritten while it is running, execution can
|
||||
jump to a random part of the script, depending on what is modified
|
||||
in the script and how the file offsets change as a result. (This
|
||||
behavior is needed to support self-extracting shell archives whose
|
||||
script part is followed by a stream of bytes which does not follow
|
||||
the shell language syntax.)
|
||||
</para>
|
||||
<para>
|
||||
Therefore, long-running scripts should be guarded against
|
||||
concurrent modification by putting as much of the program logic
|
||||
into a <literal>main</literal> function, and invoking the
|
||||
<literal>main</literal> function at the end of the script, using
|
||||
this syntax:
|
||||
</para>
|
||||
<informalexample>
|
||||
<programlisting language="Bash">
|
||||
main "$@" ; exit $?
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
<para>
|
||||
This construct ensures that <application>bash</application> will
|
||||
stop execution after the <literal>main</literal> function, instead
|
||||
of opening the script file and trying to read more commands.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
111
en-US/Tasks-Cryptography.xml
Normal file
111
en-US/Tasks-Cryptography.xml
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?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-Cryptography">
|
||||
<title>Cryptography</title>
|
||||
|
||||
<section>
|
||||
<title>Primitives</title>
|
||||
<para>
|
||||
Choosing from the following cryptographic primitives is
|
||||
recommended:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem><para>RSA with 2048 bit keys and OAEP</para></listitem>
|
||||
<listitem><para>AES-128 in CBC mode</para></listitem>
|
||||
<listitem><para>SHA-256</para></listitem>
|
||||
<listitem><para>HMAC-SHA-256</para></listitem>
|
||||
<listitem><para>HMAC-SHA-1</para></listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
Other cryptographic algorithms can be used if they are required
|
||||
for interoperability with existing software:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem><para>RSA with key sizes larger than 1024
|
||||
and legacy padding</para></listitem>
|
||||
<listitem><para>AES-192</para></listitem>
|
||||
<listitem><para>AES-256</para></listitem>
|
||||
<listitem><para>3DES (triple DES, with two or three 56 bit keys)</para></listitem>
|
||||
<listitem><para>RC4 (but very, very strongly discouraged)</para></listitem>
|
||||
<listitem><para>SHA-1</para></listitem>
|
||||
<listitem><para>HMAC-MD5</para></listitem>
|
||||
</itemizedlist>
|
||||
<important>
|
||||
<title>Important</title>
|
||||
<para>
|
||||
These primitives are difficult to use in a secure way. Custom
|
||||
implementation of security protocols should be avoided. For
|
||||
protecting confidentiality and integrity of network
|
||||
transmissions, TLS should be used (<xref
|
||||
linkend="chap-Defensive_Coding-TLS"/>).
|
||||
</para>
|
||||
</important>
|
||||
<!-- TODO: More algorithms are available in the NIST documents
|
||||
linked from: http://wiki.brq.redhat.com/SecurityTechnologies/FIPS -->
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title id="sect-Defensive_Coding-Tasks-Cryptography-Randomness">Randomness</title>
|
||||
<para>
|
||||
The following facilities can be used to generate unpredictable
|
||||
and non-repeating values. When these functions are used without
|
||||
special safeguards, each individual random value should be at
|
||||
least 12 bytes long.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><function>PK11_GenerateRandom</function> in the NSS library
|
||||
(usable for high data rates)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><function>RAND_bytes</function> in the OpenSSL library
|
||||
(usable for high data rates)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><function>gnutls_rnd</function> in GNUTLS, with
|
||||
<literal>GNUTLS_RND_RANDOM</literal> as the first argument
|
||||
(usable for high data rates)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><type>java.security.SecureRandom</type> in Java
|
||||
(usable for high data rates)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><function>os.urandom</function> in Python</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Reading from the <filename>/dev/urandom</filename>
|
||||
character device</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
All these functions should be non-blocking, and they should not
|
||||
wait until physical randomness becomes available. (Some
|
||||
cryptography providers for Java can cause
|
||||
<type>java.security.SecureRandom</type> to block, however.)
|
||||
Those functions which do not obtain all bits directly from
|
||||
<filename>/dev/urandom</filename> are suitable for high data
|
||||
rates because they do not deplete the system-wide entropy pool.
|
||||
</para>
|
||||
<important>
|
||||
<title>Difficult to use API</title>
|
||||
<para>
|
||||
Both <function>RAND_bytes</function> and
|
||||
<function>PK11_GenerateRandom</function> have three-state
|
||||
return values (with conflicting meanings). Careful error
|
||||
checking is required. Please review the documentation when
|
||||
using these functions.
|
||||
</para>
|
||||
</important>
|
||||
<para>
|
||||
Other sources of randomness should be considered predictable.
|
||||
</para>
|
||||
<para>
|
||||
Generating randomness for cryptographic keys in long-term use
|
||||
may need different steps and is best left to cryptographic
|
||||
libraries.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
267
en-US/Tasks-Descriptors.xml
Normal file
267
en-US/Tasks-Descriptors.xml
Normal file
|
@ -0,0 +1,267 @@
|
|||
<?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="sect-Defensive_Coding-Tasks-Descriptors">
|
||||
<title>File Descriptor Management</title>
|
||||
<para>
|
||||
File descriptors underlie all input/output mechanisms offered by
|
||||
the system. They are used to implementation the <literal>FILE
|
||||
*</literal>-based functions found in
|
||||
<literal><stdio.h></literal>, and all the file and network
|
||||
communication facilities provided by the Python and Java
|
||||
environments are eventually implemented in them.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<section>
|
||||
<title>Closing descriptors</title>
|
||||
<para>
|
||||
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 <xref
|
||||
linkend="sect-Defensive_Coding-Tasks-Descriptors-Limit"/>), and
|
||||
the kernel resources are not freed. Therefore, it is important
|
||||
to close all descriptors at the earlierst point in time
|
||||
possible, but not earlier.
|
||||
</para>
|
||||
<section>
|
||||
<title>Error handling during descriptor close</title>
|
||||
<para>
|
||||
The <function>close</function> system call is always
|
||||
successful in the sense that the passed file descriptor is
|
||||
never valid after the function has been called. However,
|
||||
<function>close</function> 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 <literal>O_SYNC</literal> or use
|
||||
<literal>fsync</literal> or <literal>fdatasync</literal>, and
|
||||
may also have to <literal>fsync</literal> the directory
|
||||
containing the file.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Closing descriptors and race conditions</title>
|
||||
<para>
|
||||
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 coniditons and I/O operations will be applied to
|
||||
the wrong file descriptor.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
<function>socketpair</function>, close one of the descriptors,
|
||||
and call <literal>shutdown(fd, SHUTRDWR)</literal> on the
|
||||
other.
|
||||
</para>
|
||||
<para>
|
||||
When a descriptor is closed concurrently, the program does not
|
||||
call <function>close</function> on the descriptor. Instead it
|
||||
program uses <function>dup2</function> 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).
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Lingering state after close</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>SO_LINGER</literal> socket option alters the
|
||||
behavior of <function>close</function>, 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 <function>close</function>
|
||||
call, causing scalability issues.
|
||||
</para>
|
||||
<para>
|
||||
Currently, there is no application-level countermeasure which
|
||||
applies universally. Mitigation is possible with
|
||||
<application>iptables</application> (the
|
||||
<literal>connlimit</literal> match type in particular) and
|
||||
specialized filtering devices for denial-of-service network
|
||||
traffic.
|
||||
</para>
|
||||
<para>
|
||||
These problems are not related to the
|
||||
<literal>TIME_WAIT</literal> state commonly seen in
|
||||
<application>netstat</application> output. The kernel
|
||||
automatically expires such sockets if necessary.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Descriptors-Child_Processes">
|
||||
<title>Preventing file descriptor leaks to child processes</title>
|
||||
<para>
|
||||
Child processes created with <function>fork</function> 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 <function>execve</function>
|
||||
(or any of the other functions such as <function>system</function>
|
||||
or <function>posix_spawn</function>).
|
||||
</para>
|
||||
<para>
|
||||
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:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Set the close-on-exec flag on all newly created file
|
||||
descriptors. Traditionally, this flag is controlled by the
|
||||
<literal>FD_CLOEXEC</literal> flag, using
|
||||
<literal>F_GETFD</literal> and <literal>F_SETFD</literal>
|
||||
operations of the <function>fcntl</function> function.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
<literal>FD_CLOEXEC</literal> was set. Therefore, many system
|
||||
calls which create descriptors (such as
|
||||
<function>open</function> and <function>openat</function>)
|
||||
now accept the <function>O_CLOEXEC</function> flag
|
||||
(<function>SOCK_CLOEXEC</function> for
|
||||
<function>socket</function> and
|
||||
<function>socketpair</function>), which cause the
|
||||
<literal>FD_CLOEXEC</literal> flag to be set for the file
|
||||
descriptor in an atomic fashion. In addition, a few new
|
||||
systems calls were introduced, such as
|
||||
<function>pipe2</function> and <function>dup3</function>.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
After calling <function>fork</function>, but before creating
|
||||
a new process image with <function>execve</function>, all
|
||||
file descriptors which the child process will not need are
|
||||
closed.
|
||||
</para>
|
||||
<para>
|
||||
Traditionally, this was implemented as a loop over file
|
||||
descriptors ranging from <literal>3</literal> to
|
||||
<literal>255</literal> and later <literal>1023</literal>.
|
||||
But this is only an approximatio because it is possible to
|
||||
create file descriptors outside this range easily (see <xref
|
||||
linkend="sect-Defensive_Coding-Tasks-Descriptors-Limit"/>).
|
||||
Another approach reads <filename>/proc/self/fd</filename>
|
||||
and closes the unexpected descriptors listed there, but this
|
||||
approach is much slower.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
At present, environments which care about file descriptor
|
||||
leakage implement the second approach. OpenJDK 6 and 7
|
||||
are among them.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Descriptors-Limit">
|
||||
<title>Dealing with the <function>select</function> limit</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
The <function>select</function> function only supports a
|
||||
maximum of <literal>FD_SETSIZE</literal> file descriptors
|
||||
(that is, the maximum permitted value for a file descriptor
|
||||
is <literal>FD_SETSIZE - 1</literal>, usually 1023.) If a
|
||||
process opens many files, descriptors may exceed such
|
||||
limits. It is impossible to query such descriptors using
|
||||
<function>select</function>.
|
||||
</para>
|
||||
<para>
|
||||
If a library which creates many file descriptors is used in
|
||||
the same process as a library which uses
|
||||
<function>select</function>, at least one of them needs to
|
||||
be changed. <!-- ??? refer to event-driven programming -->
|
||||
Calls to <function>select</function> can be replaced with
|
||||
calls to <function>poll</function> or another event handling
|
||||
mechanism. Replacing the <function>select</function> function
|
||||
is the recommended approach.
|
||||
</para>
|
||||
<para>
|
||||
Alternatively, the library with high descriptor usage can
|
||||
relocate descriptors above the <literal>FD_SETSIZE</literal>
|
||||
limit using the following procedure.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Create the file descriptor <literal>fd</literal> as
|
||||
usual, preferably with the <literal>O_CLOEXEC</literal>
|
||||
flag.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Before doing anything else with the descriptor
|
||||
<literal>fd</literal>, invoke:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
int newfd = fcntl(fd, F_DUPFD_CLOEXEC, (long)FD_SETSIZE);
|
||||
</programlisting>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Check that <literal>newfd</literal> result is
|
||||
non-negative, otherwise close <literal>fd</literal> and
|
||||
report an error, and return.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Close <literal>fd</literal> and continue to use
|
||||
<literal>newfd</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
The new descriptor has been allocated above the
|
||||
<literal>FD_SETSIZE</literal>. Even though this algorithm
|
||||
is racy in the sense that the <literal>FD_SETSIZE</literal>
|
||||
first descriptors could fill up, a very high degree of
|
||||
physical parallelism is required before this becomes a problem.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
339
en-US/Tasks-File_System.xml
Normal file
339
en-US/Tasks-File_System.xml
Normal file
|
@ -0,0 +1,339 @@
|
|||
<?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-File_System">
|
||||
<title>File system manipulation</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
Temporary files are covered in their own chapter, <xref
|
||||
linkend="chap-Defensive_Coding-Tasks-Temporary_Files"/>.
|
||||
</para>
|
||||
<section id="sect-Defensive_Coding-Tasks-File_System-Unowned">
|
||||
<title>Working with files and directories owned by other users</title>
|
||||
<para>
|
||||
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
|
||||
<xref linkend="sect-Defensive_Coding-Tasks-File_System-Foreign"/>.
|
||||
</para>
|
||||
<para>
|
||||
Accessing files across trust boundaries faces several
|
||||
challenges, particularly if an entire directory tree is being
|
||||
traversed:
|
||||
</para>
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
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 <function>readdir</function>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
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 <literal>O_NONBLOCK</literal> flag is specified.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Hard links and symbolic links can redirect the effect of
|
||||
file system operations in unexpected ways. The
|
||||
<literal>O_NOFOLLOW</literal> and
|
||||
<literal>AT_SYMLINK_NOFOLLOW</literal> variants of system
|
||||
calls only affected final path name component.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<para>
|
||||
Files should always be created with the
|
||||
<literal>O_CREAT</literal> and <literal>O_EXCL</literal> 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 <literal>000</literal> if
|
||||
possible, and adjust it afterwards with
|
||||
<function>fchmod</function>.
|
||||
</para>
|
||||
<para>
|
||||
To avoid issues related to symbolic links and directory tree
|
||||
restructuring, the “<literal>at</literal>” variants of system
|
||||
calls have to be used (that is, functions like
|
||||
<function>openat</function>, <function>fchownat</function>,
|
||||
<function>fchmodat</function>, and
|
||||
<function>unlinkat</function>, together with
|
||||
<literal>O_NOFOLLOW</literal> or
|
||||
<literal>AT_SYMLINK_NOFOLLOW</literal>). 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
|
||||
<literal>opendirat</literal> function can be emulated with
|
||||
<literal>openat</literal> (with an
|
||||
<literal>O_DIRECTORY</literal> flag, to avoid opening special
|
||||
files with side effects), followed by
|
||||
<literal>fdopendir</literal>.
|
||||
</para>
|
||||
<para>
|
||||
If the “<literal>at</literal>” 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.)
|
||||
<function>fchdir</function> 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 “<literal>at</literal>”-based
|
||||
approach. <literal>chdir("...")</literal> is unsafe because it
|
||||
might ascend outside the intended directory tree.
|
||||
</para>
|
||||
<para>
|
||||
This “<literal>at</literal>” function emulation is currently
|
||||
required when manipulating extended attributes. In this case,
|
||||
the <function>lsetxattr</function> function can be used, with a
|
||||
relative path name consisting of a single component. This also
|
||||
applies to SELinux contexts and the
|
||||
<function>lsetfilecon</function> function.
|
||||
</para>
|
||||
<para>
|
||||
Currently, it is not possible to avoid opening special files
|
||||
<emphasis>and</emphasis> 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.)
|
||||
<function>fchmodat</function> and <function>fchownat</function>
|
||||
affect files whose link count is greater than one. But opening
|
||||
the files, checking that the link count is one with
|
||||
<function>fstat</function>, and using
|
||||
<function>fchmod</function> and <function>fchown</function> 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.
|
||||
</para>
|
||||
<para>
|
||||
Similarly, when just reading a directory owned by an untrusted
|
||||
user, it is currently impossible to reliably avoid opening
|
||||
special files.
|
||||
</para>
|
||||
<para>
|
||||
There is no workaround against the instability of the file list
|
||||
returned by <function>readdir</function>. Concurrent
|
||||
modification of the directory can result in a list of files
|
||||
being returned which never actually existed on disk.
|
||||
</para>
|
||||
<para>
|
||||
Hard links and symbolic links can be safely deleted using
|
||||
<function>unlinkat</function> without further checks because
|
||||
deletion only affects the name within the directory tree being
|
||||
processed.
|
||||
</para>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-Tasks-File_System-Foreign">
|
||||
<title>Accessing the file system as a different user</title>
|
||||
<para>
|
||||
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 <xref
|
||||
linkend="sect-Defensive_Coding-Tasks-File_System-Foreign"/>.
|
||||
</para>
|
||||
<para>
|
||||
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 <function>stat</function> system call.
|
||||
</para>
|
||||
<para>
|
||||
An existing process could change its user and group ID using
|
||||
<function>setfsuid</function> and <function>setfsgid</function>.
|
||||
(These functions are preferred over <function>seteuid</function>
|
||||
and <function>setegid</function> 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.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-Tasks-File_System-Limits">
|
||||
<title>File system limits</title>
|
||||
<para>
|
||||
For historical reasons, there are preprocessor constants such as
|
||||
<literal>PATH_MAX</literal>, <literal>NAME_MAX</literal>.
|
||||
However, on most systems, the length of canonical path names
|
||||
(absolute path names with all symbolic links resolved, as
|
||||
returned by <function>realpath</function> or
|
||||
<function>canonicalize_file_name</function>) can exceed
|
||||
<literal>PATH_MAX</literal> bytes, and individual file name
|
||||
components can be longer than <literal>NAME_MAX</literal>. This
|
||||
is also true of the <literal>_PC_PATH_MAX</literal> and
|
||||
<literal>_PC_NAME_MAX</literal> values returned by
|
||||
<function>pathconf</function>, and the
|
||||
<literal>f_namemax</literal> member of <literal>struct
|
||||
statvfs</literal>. Therefore, these constants should not be
|
||||
used. This is also reason why the
|
||||
<function>readdir_r</function> should never be used (instead,
|
||||
use <function>readdir</function>).
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-Tasks-File_System-Features">
|
||||
<title>File system features</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Some file systems are case-insensitive. Most should be
|
||||
case-preserving, though.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
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
|
||||
<function>readdir</function> might still result in a
|
||||
different byte sequence.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Non-regular files (device nodes, FIFOs) are not generally
|
||||
available.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Only on some file systems, files can have holes, that is,
|
||||
not all of their contents is backed by disk storage.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>ioctl</function> support (even fairly generic
|
||||
functionality such as <literal>FIEMAP</literal> for
|
||||
discovering physical file layout and holes) is
|
||||
file-system-specific.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Not all file systems support extended attributes, ACLs and
|
||||
SELinux metadata. Size and naming restriction on extended
|
||||
attributes vary.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Renaming (or moving) files using <function>rename</function>
|
||||
can fail (even when <function>stat</function> 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.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Resolution of time stamps varies from two seconds to
|
||||
nanoseconds. Not all time stamps are available on all file
|
||||
systems. File creation time (<emphasis>birth
|
||||
time</emphasis>) is not exposed over the
|
||||
<function>stat</function>/<function>fstat</function>
|
||||
interface, even if stored by the file system.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-Tasks-File_System-Free_Space">
|
||||
<title>Checking free space</title>
|
||||
<para>
|
||||
The <function>statvfs</function> and
|
||||
<function>fstatvfs</function> functions allow programs to
|
||||
examine the number of available blocks and inodes, through the
|
||||
members <literal>f_bfree</literal>, <literal>f_bavail</literal>,
|
||||
<literal>f_ffree</literal>, and <literal>f_favail</literal> of
|
||||
<literal>struct statvfs</literal>. Some file systems return
|
||||
fictional values in the <literal>f_ffree</literal> and
|
||||
<literal>f_favail</literal> 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 <literal>f_bfree</literal> field should be
|
||||
reasonably accurate, though.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
195
en-US/Tasks-Library_Design.xml
Normal file
195
en-US/Tasks-Library_Design.xml
Normal file
|
@ -0,0 +1,195 @@
|
|||
<?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-Library_Design">
|
||||
<title>Library Design</title>
|
||||
<para>
|
||||
Throught this section, the term <emphasis>client code</emphasis>
|
||||
refers to applications and other libraries using the library.
|
||||
</para>
|
||||
|
||||
<section>
|
||||
<title>State management</title>
|
||||
<para>
|
||||
</para>
|
||||
<section>
|
||||
<title>Global state</title>
|
||||
<para>
|
||||
Global state should be avoided.
|
||||
</para>
|
||||
<para>
|
||||
If this is impossible, the global state must be protected with
|
||||
a lock. For C/C++, you can use the
|
||||
<function>pthread_mutex_lock</function>
|
||||
and <function>pthread_mutex_unlock</function>
|
||||
functions without linking against <literal>-lpthread</literal>
|
||||
because the system provides stubs for non-threaded processes.
|
||||
</para>
|
||||
<para>
|
||||
For compatibility with <function>fork</function>, these locks
|
||||
should be acquired and released in helpers registered with
|
||||
<function>pthread_atfork</function>. This function is not
|
||||
available without <literal>-lpthread</literal>, so you need to
|
||||
use <function>dlsym</function> or a weak symbol to obtain its
|
||||
address.
|
||||
</para>
|
||||
<para>
|
||||
If you need <function>fork</function> protection for other
|
||||
reasons, you should store the process ID and compare it to the
|
||||
value returned by <function>getpid</function> each time you
|
||||
access the global state. (<function>getpid</function> is not
|
||||
implemented as a system call and is fast.) If the value
|
||||
changes, you know that you have to re-create the state object.
|
||||
(This needs to be combined with locking, of course.)
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Handles</title>
|
||||
<para>
|
||||
Library state should be kept behind a curtain. Client code
|
||||
should receive only a handle. In C, the handle can be a
|
||||
pointer to an incomplete <literal>struct</literal>. In C++,
|
||||
the handle can be a pointer to an abstract base class, or it
|
||||
can be hidden using the pointer-to-implementation idiom.
|
||||
</para>
|
||||
<para>
|
||||
The library should provide functions for creating and
|
||||
destroying handles. (In C++, it is possible to use virtual
|
||||
destructors for the latter.) Consistency between creation and
|
||||
destruction of handles is strongly recommended: If the client
|
||||
code created a handle, it is the responsibility of the client
|
||||
code to destroy it. (This is not always possible or
|
||||
convenient, so sometimes, a transfer of ownership has to
|
||||
happen.)
|
||||
</para>
|
||||
<para>
|
||||
Using handles ensures that it is possible to change the way
|
||||
the library represents state in a way that is transparent to
|
||||
client code. This is important to facilitate security updates
|
||||
and many other code changes.
|
||||
</para>
|
||||
<para>
|
||||
It is not always necessary to protect state behind a handle
|
||||
with a lock. This depends on the level of thread safety
|
||||
the library provides.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Object orientation</title>
|
||||
<para>
|
||||
Classes should be either designed as base classes, or it should
|
||||
be impossible to use them as base classes (like
|
||||
<literal>final</literal> classes in Java). Classes which are
|
||||
not designed for inheritance and are used as base classes
|
||||
nevertheless create potential maintenance hazards because it is
|
||||
difficult to predict how client code will react when calls to
|
||||
virtual methods are added, reordered or removed.
|
||||
</para>
|
||||
<para>
|
||||
Virtual member functions can be used as callbacks. See
|
||||
<xref linkend="sect-Defensive_Coding-Tasks-Library_Design-Callbacks"/>
|
||||
for some of the challenges involved.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Library_Design-Callbacks">
|
||||
<title>Callbacks</title>
|
||||
<para>
|
||||
Higher-order code is difficult to analyze for humans and
|
||||
computers alike, so it should be avoided. Often, an
|
||||
iterator-based interface (a library function which is called
|
||||
repeatedly by client code and returns a stream of events) leads
|
||||
to a better design which is easier to document and use.
|
||||
</para>
|
||||
<para>
|
||||
If callbacks are unavoidable, some guidelines for them follow.
|
||||
</para>
|
||||
<para>
|
||||
In modern C++ code, <literal>std::function</literal> objects
|
||||
should be used for callbacks.
|
||||
</para>
|
||||
<para>
|
||||
In older C++ code and in C code, all callbacks must have an
|
||||
additional closure parameter of type <literal>void *</literal>,
|
||||
the value of which can be specified by client code. If
|
||||
possible, the value of the closure parameter should be provided
|
||||
by client code at the same time a specific callback is
|
||||
registered (or specified as a function argument). If a single
|
||||
closure parameter is shared by multiple callbacks, flexibility
|
||||
is greatly reduced, and conflicts between different pieces of
|
||||
client code using the same library object could be unresolvable.
|
||||
In some cases, it makes sense to provide a de-registration
|
||||
callback which can be used to destroy the closure parameter when
|
||||
the callback is no longer used.
|
||||
</para>
|
||||
<para>
|
||||
Callbacks can throw exceptions or call
|
||||
<function>longjmp</function>. If possible, all library objects
|
||||
should remain in a valid state. (All further operations on them
|
||||
can fail, but it should be possible to deallocate them without
|
||||
causing resource leaks.)
|
||||
</para>
|
||||
<para>
|
||||
The presence of callbacks raises the question if functions
|
||||
provided by the library are <emphasis>reentrant</emphasis>.
|
||||
Unless a library was designed for such use, bad things will
|
||||
happen if a callback function uses functions in the same library
|
||||
(particularly if they are invoked on the same objects and
|
||||
manipulate the same state). When the callback is invoked, the
|
||||
library can be in an inconsistent state. Reentrant functions
|
||||
are more difficult to write than thread-safe functions (by
|
||||
definition, simple locking would immediately lead to deadlocks).
|
||||
It is also difficult to decide what to do when destruction of an
|
||||
object which is currently processing a callback is requested.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Process attributes</title>
|
||||
<para>
|
||||
Several attributes are global and affect all code in the
|
||||
process, not just the library that manipulates them.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
environment variables
|
||||
(see <xref linkend="sect-Defensive_Coding-Tasks-secure_getenv"/>)
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
umask
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
user IDs, group IDs and capabilities
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
current working directory
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
signal handlers, signal masks and signal delivery
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
file locks (especially <function>fcntl</function> locks
|
||||
behave in surprising ways, not just in a multi-threaded
|
||||
environment)
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
Library code should avoid manipulating these global process
|
||||
attributes. It should not rely on environment variables, umask,
|
||||
the current working directory and signal masks because these
|
||||
attributes can be inherted from an untrusted source.
|
||||
</para>
|
||||
<para>
|
||||
In addition, there are obvious process-wide aspects such as the
|
||||
virtual memory layout, the set of open files and dynamic shared
|
||||
objects, but with the exception of shared objects, these can be
|
||||
manipulated in a relatively isolated way.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
||||
|
5
en-US/Tasks-Locking.xml
Normal file
5
en-US/Tasks-Locking.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?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="sect-Defensive_Coding-Tasks-Locking">
|
||||
</chapter>
|
175
en-US/Tasks-Packaging.xml
Normal file
175
en-US/Tasks-Packaging.xml
Normal file
|
@ -0,0 +1,175 @@
|
|||
<?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-Packaging">
|
||||
<title>RPM packaging</title>
|
||||
<para>
|
||||
This chapter deals with security-related concerns around RPM
|
||||
packaging. It has to be read in conjunction with
|
||||
distribution-specific packaging guidelines.
|
||||
</para>
|
||||
<section id="sect-Defensive_Coding-Tasks-Packaging-Certificates">
|
||||
<title>Generating X.509 self-signed certificates during
|
||||
installation</title>
|
||||
<para>
|
||||
Some applications need X.509 certificates for authentication
|
||||
purposes. For example, a single private/public key pair could
|
||||
be used to define cluster membership, enabling authentication
|
||||
and encryption of all intra-cluster communication. (Lack of
|
||||
certification from a CA matters less in such a context.) For
|
||||
such use, generating the key pair at package installation time
|
||||
when preparing system images for use in the cluster is
|
||||
reasonable. For other use cases, it is necessary to generate
|
||||
the key pair before the service is started for the first time,
|
||||
see <xref linkend="sect-Defensive_Coding-Tasks-Packaging-Certificates-Service"/>.
|
||||
</para>
|
||||
<important>
|
||||
<para>
|
||||
The way the key is generated may not be suitable for key
|
||||
material of critical value. (<command>openssl
|
||||
genrsa</command> uses, but does not require, entropy from a
|
||||
physical source of randomness, among other things.) Such keys
|
||||
should be stored in a hardware security module if possible,
|
||||
and generated from random bits reserved for this purpose
|
||||
derived from a non-deterministic physical source.
|
||||
</para>
|
||||
</important>
|
||||
<para>
|
||||
In the spec file, we define two RPM variables which contain the
|
||||
names of the files used to store the private and public key, and
|
||||
the user name for the service:
|
||||
</para>
|
||||
<informalexample>
|
||||
<programlisting language="RPM Spec">
|
||||
# Name of the user owning the file with the private key
|
||||
%define tlsuser %{name}
|
||||
# Name of the directory which contains the key and certificate files
|
||||
%define tlsdir %{_sysconfdir}/%{name}
|
||||
%define tlskey %{tlsdir}/%{name}.key
|
||||
%define tlscert %{tlsdir}/%{name}.crt
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
<para>
|
||||
These variables likely need adjustment based on the needs of the
|
||||
package.
|
||||
</para>
|
||||
<para>
|
||||
Typically, the file with the private key needs to be owned by
|
||||
the system user which needs to read it,
|
||||
<literal>%{tlsuser}</literal> (not <literal>root</literal>). In
|
||||
order to avoid races, if the <emphasis>directory</emphasis>
|
||||
<literal>%{tlsdir}</literal> is <emphasis>owned by the services
|
||||
user</emphasis>, you should use the code in <xref
|
||||
linkend="ex-Defensive_Coding-Packaging-Certificates-Owned"/>.
|
||||
The invocation of <application>su</application> with the
|
||||
<option>-s /bin/bash</option> argument is necessary in case the
|
||||
login shell for the user has been disabled.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Packaging-Certificates-Owned">
|
||||
<title>Creating a key pair in a user-owned directory</title>
|
||||
<programlisting language="Bash">
|
||||
%post
|
||||
if [ $1 -eq 1 ] ; then
|
||||
if ! test -e %{tlskey} ; then
|
||||
su -s /bin/bash \
|
||||
-c "umask 077 && openssl genrsa -out %{tlskey} 2048 2>/dev/null" \
|
||||
%{tlsuser}
|
||||
fi
|
||||
if ! test -e %{tlscert} ; then
|
||||
cn="Automatically generated certificate for the %{tlsuser} service"
|
||||
req_args="-key %{tlskey} -out %{tlscert} -days 7305 -subj \"/CN=$cn/\""
|
||||
su -s /bin/bash \
|
||||
-c "openssl req -new -x509 -extensions usr_cert $req_args" \
|
||||
%{tlsuser}
|
||||
fi
|
||||
fi
|
||||
|
||||
%files
|
||||
%dir %attr(0755,%{tlsuser},%{tlsuser]) %{tlsdir}
|
||||
%ghost %attr(0600,%{tlsuser},%{tlsuser}) %config(noreplace) %{tlskey}
|
||||
%ghost %attr(0644,%{tlsuser},%{tlsuser}) %config(noreplace) %{tlscert}
|
||||
</programlisting>
|
||||
</example>
|
||||
<para>
|
||||
The files containing the key material are marked as ghost
|
||||
configuration files. This ensures that they are tracked in the
|
||||
RPM database as associated with the package, but RPM will not
|
||||
create them when the package is installed and not verify their
|
||||
contents (the <literal>%ghost</literal>), or delete the files
|
||||
when the package is uninstalled (the
|
||||
<literal>%config(noreplace)</literal> part).
|
||||
</para>
|
||||
<para>
|
||||
If the <emphasis>directory</emphasis>
|
||||
<literal>%{tlsdir}</literal> <emphasis>is owned by</emphasis>
|
||||
<literal>root</literal>, use the code in <xref
|
||||
linkend="ex-Defensive_Coding-Packaging-Certificates-Unowned"/>.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Packaging-Certificates-Unowned">
|
||||
<title>Creating a key pair in a <literal>root</literal>-owned directory</title>
|
||||
<programlisting language="Bash">
|
||||
%post
|
||||
if [ $1 -eq 1 ] ; then
|
||||
if ! test -e %{tlskey} ; then
|
||||
(umask 077 && openssl genrsa -out %{tlskey} 2048 2>/dev/null)
|
||||
chown %{tlsuser} %{tlskey}
|
||||
fi
|
||||
if ! test -e %{tlscert} ; then
|
||||
cn="Automatically generated certificate for the %{tlsuser} service"
|
||||
openssl req -new -x509 -extensions usr_cert \
|
||||
-key %{tlskey} -out %{tlscert} -days 7305 -subj "/CN=$cn/"
|
||||
fi
|
||||
fi
|
||||
|
||||
%files
|
||||
%dir %attr(0755,root,root]) %{tlsdir}
|
||||
%ghost %attr(0600,%{tlsuser},%{tlsuser}) %config(noreplace) %{tlskey}
|
||||
%ghost %attr(0644,root,root) %config(noreplace) %{tlscert}
|
||||
</programlisting>
|
||||
</example>
|
||||
<para>
|
||||
In order for this to work, the package which generates the keys
|
||||
must require the <application>openssl</application> package. If
|
||||
the user which owns the key file is generated by a different
|
||||
package, the package generating the certificate must specify a
|
||||
<literal>Requires(pre):</literal> on the package which creates
|
||||
the user. This ensures that the user account will exist when it
|
||||
is needed for the <application>su</application> or
|
||||
<application>chmod</application> invocation.
|
||||
</para>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-Tasks-Packaging-Certificates-Service">
|
||||
<title>Generating X.509 self-signed certificates before service
|
||||
start</title>
|
||||
<para>
|
||||
An alternative way to automatically provide an X.509 key pair is
|
||||
to create it just before the service is started for the first
|
||||
time. This ensures that installation images which are created
|
||||
from installed RPM packages receive different key material.
|
||||
Creating the key pair at package installation time (see <xref
|
||||
linkend="sect-Defensive_Coding-Tasks-Packaging-Certificates"/>)
|
||||
would put the key into the image, which may or may not make
|
||||
sense.
|
||||
</para>
|
||||
<important>
|
||||
<para>
|
||||
The caveats about the way the key is generated in <xref
|
||||
linkend="sect-Defensive_Coding-Tasks-Packaging-Certificates"/>
|
||||
apply to this procedure as well.
|
||||
</para>
|
||||
</important>
|
||||
<para>
|
||||
Generating key material before service start may happen very
|
||||
early during boot, when the kernel randomness pool has not yet
|
||||
been initialized. Currently, the only way to check for the
|
||||
initialization is to look for the kernel message
|
||||
<literal>random: nonblocking pool is initialized</literal>. In
|
||||
theory, it is also possible to read from
|
||||
<filename>/dev/random</filename> while generating the key
|
||||
material (instead of <filename>/dev/urandom</filename>), but
|
||||
this can block not just during the boot process, but also much
|
||||
later at run time, and generally results in a poor user
|
||||
experience.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
483
en-US/Tasks-Processes.xml
Normal file
483
en-US/Tasks-Processes.xml
Normal file
|
@ -0,0 +1,483 @@
|
|||
<?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="sect-Defensive_Coding-Tasks-Processes">
|
||||
<title>Processes</title>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Processes-Creation">
|
||||
<title>Safe process creation</title>
|
||||
<para>
|
||||
This section describes how to create new child processes in a
|
||||
safe manner. In addition to the concerns addressed below, there
|
||||
is the possibility of file descriptor leaks, see <xref
|
||||
linkend="sect-Defensive_Coding-Tasks-Descriptors-Child_Processes"/>.
|
||||
</para>
|
||||
<section>
|
||||
<title>Obtaining the program path and the command line
|
||||
template</title>
|
||||
<para>
|
||||
The name and path to the program being invoked should be
|
||||
hard-coded or controlled by a static configuration file stored
|
||||
at a fixed location (at an file system absolute path). The
|
||||
same applies to the template for generating the command line.
|
||||
</para>
|
||||
<para>
|
||||
The configured program name should be an absolute path. If it
|
||||
is a relative path, the contents of the <envar>PATH</envar>
|
||||
must be obtained in a secure manner (see <xref
|
||||
linkend="sect-Defensive_Coding-Tasks-secure_getenv"/>).
|
||||
If the <envar>PATH</envar> variable is not set or untrusted,
|
||||
the safe default <literal>/bin:/usr/bin</literal> must be
|
||||
used.
|
||||
</para>
|
||||
<para>
|
||||
If too much flexibility is provided here, it may allow
|
||||
invocation of arbitrary programs without proper authorization.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Processes-execve">
|
||||
<title>Bypassing the shell</title>
|
||||
<para>
|
||||
Child processes should be created without involving the system
|
||||
shell.
|
||||
</para>
|
||||
<para>
|
||||
For C/C++, <function>system</function> should not be used.
|
||||
The <function>posix_spawn</function> function can be used
|
||||
instead, or a combination <function>fork</function> and
|
||||
<function>execve</function>. (In some cases, it may be
|
||||
preferable to use <function>vfork</function> or the
|
||||
Linux-specific <function>clone</function> system call instead
|
||||
of <function>fork</function>.)
|
||||
</para>
|
||||
<para>
|
||||
In Python, the <literal>subprocess</literal> module bypasses
|
||||
the shell by default (when the <literal>shell</literal>
|
||||
keyword argument is not set to true).
|
||||
<function>os.system</function> should not be used.
|
||||
</para>
|
||||
<para>
|
||||
The Java class <type>java.lang.ProcessBuilder</type> can be
|
||||
used to create subprocesses without interference from the
|
||||
system shell.
|
||||
</para>
|
||||
<important>
|
||||
<title>Portability notice</title>
|
||||
<para>
|
||||
On Windows, there is no argument vector, only a single
|
||||
argument string. Each application is responsible for parsing
|
||||
this string into an argument vector. There is considerable
|
||||
variance among the quoting style recognized by applications.
|
||||
Some of them expand shell wildcards, others do not. Extensive
|
||||
application-specific testing is required to make this secure.
|
||||
</para>
|
||||
</important>
|
||||
<para>
|
||||
Note that some common applications (notably
|
||||
<application>ssh</application>) unconditionally introduce the
|
||||
use of a shell, even if invoked directly without a shell. It is
|
||||
difficult to use these applications in a secure manner. In this
|
||||
case, untrusted data should be supplied by other means. For
|
||||
example, standard input could be used, instead of the command
|
||||
line.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Processes-environ">
|
||||
<title>Specifying the process environment</title>
|
||||
<para>
|
||||
Child processes should be created with a minimal set of
|
||||
environment variables. This is absolutely essential if there
|
||||
is a trust transition involved, either when the parent process
|
||||
was created, or during the creation of the child process.
|
||||
</para>
|
||||
<para>
|
||||
In C/C++, the environment should be constructed as an array of
|
||||
strings and passed as the <varname>envp</varname> argument to
|
||||
<function>posix_spawn</function> or <function>execve</function>.
|
||||
The functions <function>setenv</function>,
|
||||
<function>unsetenv</function> and <function>putenv</function>
|
||||
should not be used. They are not thread-safe and suffer from
|
||||
memory leaks.
|
||||
</para>
|
||||
<para>
|
||||
Python programs need to specify a <literal>dict</literal> for
|
||||
the the <varname>env</varname> argument of the
|
||||
<function>subprocess.Popen</function> constructor.
|
||||
The Java class <literal>java.lang.ProcessBuilder</literal>
|
||||
provides a <function>environment()</function> method,
|
||||
which returns a map that can be manipulated.
|
||||
</para>
|
||||
<para>
|
||||
The following list provides guidelines for selecting the set
|
||||
of environment variables passed to the child process.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<envar>PATH</envar> should be initialized to
|
||||
<literal>/bin:/usr/bin</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<envar>USER</envar> and <envar>HOME</envar> can be inhereted
|
||||
from the parent process environment, or they can be
|
||||
initialized from the <literal>pwent</literal> structure
|
||||
for the user. <!-- ??? refer to dropping privileges -->
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The <envar>DISPLAY</envar> and <envar>XAUTHORITY</envar>
|
||||
variables should be passed to the subprocess if it is an X
|
||||
program. Note that this will typically not work across trust
|
||||
boundaries because <envar>XAUTHORITY</envar> refers to a file
|
||||
with <literal>0600</literal> permissions.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The location-related environment variables
|
||||
<envar>LANG</envar>, <envar>LANGUAGE</envar>,
|
||||
<envar>LC_ADDRESS</envar>, <envar>LC_ALL</envar>,
|
||||
<envar>LC_COLLATE</envar>, <envar>LC_CTYPE</envar>,
|
||||
<envar>LC_IDENTIFICATION</envar>,
|
||||
<envar>LC_MEASUREMENT</envar>, <envar>LC_MESSAGES</envar>,
|
||||
<envar>LC_MONETARY</envar>, <envar>LC_NAME</envar>,
|
||||
<envar>LC_NUMERIC</envar>, <envar>LC_PAPER</envar>,
|
||||
<envar>LC_TELEPHONE</envar> and <envar>LC_TIME</envar>
|
||||
can be passed to the subprocess if present.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The called process may need application-specific
|
||||
environment variables, for example for passing passwords.
|
||||
(See <xref
|
||||
linkend="sect-Defensive_Coding-Tasks-Processes-Command_Line_Visibility"/>.)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
All other environment variables should be dropped. Names
|
||||
for new environment variables should not be accepted from
|
||||
untrusted sources.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Robust argument list processing</title>
|
||||
<para>
|
||||
When invoking a program, it is sometimes necessary to include
|
||||
data from untrusted sources. Such data should be checked
|
||||
against embedded <literal>NUL</literal> characters because the
|
||||
system APIs will silently truncate argument strings at the first
|
||||
<literal>NUL</literal> character.
|
||||
</para>
|
||||
<para>
|
||||
The following recommendations assume that the program being
|
||||
invoked uses GNU-style option processing using
|
||||
<function>getopt_long</function>. This convention is widely
|
||||
used, but it is just that, and individual programs might
|
||||
interpret a command line in a different way.
|
||||
</para>
|
||||
<para>
|
||||
If the untrusted data has to go into an option, use the
|
||||
<literal>--option-name=VALUE</literal> syntax, placing the
|
||||
option and its value into the same command line argument.
|
||||
This avoids any potential confusion if the data starts with
|
||||
<literal>-</literal>.
|
||||
</para>
|
||||
<para>
|
||||
For positional arguments, terminate the option list with a
|
||||
single <option>--</option> marker after the last option, and
|
||||
include the data at the right position. The
|
||||
<option>--</option> marker terminates option processing, and
|
||||
the data will not be treated as an option even if it starts
|
||||
with a dash.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Processes-Command_Line_Visibility">
|
||||
<title>Passing secrets to subprocesses</title>
|
||||
<para>
|
||||
The command line (the name of the program and its argument) of
|
||||
a running process is traditionally available to all local
|
||||
users. The called program can overwrite this information, but
|
||||
only after it has run for a bit of time, during which the
|
||||
information may have been read by other processes. However,
|
||||
on Linux, the process environment is restricted to the user
|
||||
who runs the process. Therefore, if you need a convenient way
|
||||
to pass a password to a child process, use an environment
|
||||
variable, and not a command line argument. (See <xref
|
||||
linkend="sect-Defensive_Coding-Tasks-Processes-environ"/>.)
|
||||
</para>
|
||||
<important>
|
||||
<title>Portability notice</title>
|
||||
<para>
|
||||
On some UNIX-like systems (notably Solaris), environment
|
||||
variables can be read by any system user, just like command
|
||||
lines.
|
||||
</para>
|
||||
</important>
|
||||
<para>
|
||||
If the environment-based approach cannot be used due to
|
||||
portability concerns, the data can be passed on standard
|
||||
input. Some programs (notably <application>gpg</application>)
|
||||
use special file descriptors whose numbers are specified on
|
||||
the command line. Temporary files are an option as well, but
|
||||
they might give digital forensics access to sensitive data
|
||||
(such as passphrases) because it is difficult to safely delete
|
||||
them in all cases.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Handling child process termination</title>
|
||||
<para>
|
||||
When child processes terminate, the parent process is signalled.
|
||||
A stub of the terminated processes (a
|
||||
<emphasis>zombie</emphasis>, shown as
|
||||
<literal><defunct></literal> by
|
||||
<application>ps</application>) is kept around until the status
|
||||
information is collected (<emphasis>reaped</emphasis>) by the
|
||||
parent process. Over the years, several interfaces for this
|
||||
have been invented:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
The parent process calls <function>wait</function>,
|
||||
<function>waitpid</function>, <function>waitid</function>,
|
||||
<function>wait3</function> or <function>wait4</function>,
|
||||
without specifying a process ID. This will deliver any
|
||||
matching process ID. This approach is typically used from
|
||||
within event loops.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The parent process calls <function>waitpid</function>,
|
||||
<function>waitid</function>, or <function>wait4</function>,
|
||||
with a specific process ID. Only data for the specific
|
||||
process ID is returned. This is typically used in code
|
||||
which spawns a single subprocess in a synchronous manner.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The parent process installs a handler for the
|
||||
<literal>SIGCHLD</literal> signal, using
|
||||
<function>sigaction</function>, and specifies to the
|
||||
<literal>SA_NOCLDWAIT</literal> flag.
|
||||
This approach could be used by event loops as well.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
None of these approaches can be used to wait for child process
|
||||
terminated in a completely thread-safe manner. The parent
|
||||
process might execute an event loop in another thread, which
|
||||
could pick up the termination signal. This means that libraries
|
||||
typically cannot make free use of child processes (for example,
|
||||
to run problematic code with reduced privileges in a separate
|
||||
address space).
|
||||
</para>
|
||||
<para>
|
||||
At the moment, the parent process should explicitly wait for
|
||||
termination of the child process using
|
||||
<function>waitpid</function> or <function>waitid</function>,
|
||||
and hope that the status is not collected by an event loop
|
||||
first.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title><literal>SUID</literal>/<literal>SGID</literal>
|
||||
processes</title>
|
||||
<!-- ??? need to document real vs effective UID -->
|
||||
<para>
|
||||
Programs can be marked in the file system to indicate to the
|
||||
kernel that a trust transition should happen if the program is
|
||||
run. The <literal>SUID</literal> file permission bit indicates
|
||||
that an executable should run with the effective user ID equal
|
||||
to the owner of the executable file. Similarly, with the
|
||||
<literal>SGID</literal> bit, the effective group ID is set to
|
||||
the group of the executable file.
|
||||
</para>
|
||||
<para>
|
||||
Linux supports <emphasis>fscaps</emphasis>, which can grant
|
||||
additional capabilities to a process in a finer-grained manner.
|
||||
Additional mechanisms can be provided by loadable security
|
||||
modules.
|
||||
</para>
|
||||
<para>
|
||||
When such a trust transition has happened, the process runs in a
|
||||
potentially hostile environment. Additional care is necessary
|
||||
not to rely on any untrusted information. These concerns also
|
||||
apply to libraries which can be linked into such processes.
|
||||
</para>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-secure_getenv">
|
||||
<title>Accessing environment variables</title>
|
||||
<para>
|
||||
The following steps are required so that a program does not
|
||||
accidentally pick up untrusted data from environment
|
||||
variables.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Compile your C/C++ sources with <literal>-D_GNU_SOURCE</literal>.
|
||||
The Autoconf macro <literal>AC_GNU_SOURCE</literal> ensures this.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Check for the presence of the <function>secure_getenv</function>
|
||||
and <function>__secure_getenv</function> function. The Autoconf
|
||||
directive <literal>AC_CHECK_FUNCS([__secure_getenv secure_getenv])</literal>
|
||||
performs these checks.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Arrange for a proper definition of the
|
||||
<function>secure_getenv</function> function. See <xref
|
||||
linkend="ex-Defensive_Coding-Tasks-secure_getenv"/>.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Use <function>secure_getenv</function> instead of
|
||||
<function>getenv</function> to obtain the value of critical
|
||||
environment variables. <function>secure_getenv</function>
|
||||
will pretend the variable has not bee set if the process
|
||||
environment is not trusted.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
Critical environment variables are debugging flags,
|
||||
configuration file locations, plug-in and log file locations,
|
||||
and anything else that might be used to bypass security
|
||||
restrictions or cause a privileged process to behave in an
|
||||
unexpected way.
|
||||
</para>
|
||||
<para>
|
||||
Either the <function>secure_getenv</function> function or the
|
||||
<function>__secure_getenv</function> is available from GNU libc.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Tasks-secure_getenv">
|
||||
<title>Obtaining a definition for <function>secure_getenv</function></title>
|
||||
<programlisting language="C">
|
||||
<![CDATA[
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef HAVE_SECURE_GETENV
|
||||
# ifdef HAVE__SECURE_GETENV
|
||||
# define secure_getenv __secure_getenv
|
||||
# else
|
||||
# error neither secure_getenv nor __secure_getenv are available
|
||||
# endif
|
||||
#endif
|
||||
]]>
|
||||
</programlisting>
|
||||
</example>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Processes-Daemons">
|
||||
<title>Daemons</title>
|
||||
<para>
|
||||
Background processes providing system services
|
||||
(<emphasis>daemons</emphasis>) need to decouple themselves from
|
||||
the controlling terminal and the parent process environment:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Fork.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
In the child process, call <function>setsid</function>. The
|
||||
parent process can simply exit (using
|
||||
<function>_exit</function>, to avoid running clean-up
|
||||
actions twice).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
In the child process, fork again. Processing continues in
|
||||
the child process. Again, the parent process should just
|
||||
exit.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Replace the descriptors 0, 1, 2 with a descriptor for
|
||||
<filename>/dev/null</filename>. Logging should be
|
||||
redirected to <application>syslog</application>.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
Older instructions for creating daemon processes recommended a
|
||||
call to <literal>umask(0)</literal>. This is risky because it
|
||||
often leads to world-writable files and directories, resulting
|
||||
in security vulnerabilities such as arbitrary process
|
||||
termination by untrusted local users, or log file truncation.
|
||||
If the <emphasis>umask</emphasis> needs setting, a restrictive
|
||||
value such as <literal>027</literal> or <literal>077</literal>
|
||||
is recommended.
|
||||
</para>
|
||||
<para>
|
||||
Other aspects of the process environment may have to changed as
|
||||
well (environment variables, signal handler disposition).
|
||||
</para>
|
||||
<para>
|
||||
It is increasingly common that server processes do not run as
|
||||
background processes, but as regular foreground process under a
|
||||
supervising master process (such as
|
||||
<application>systemd</application>). Server processes should
|
||||
offer a command line option which disables forking and
|
||||
replacement of the standard output and standard error streams.
|
||||
Such an option is also useful for debugging.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Semantics of command line arguments</title>
|
||||
<!-- ??? This applies in two ways, safely calling an other process
|
||||
and support for being called safely. Also need to address
|
||||
untrusted current directory on USB sticks. -->
|
||||
<para>
|
||||
After process creation and option processing, it is up to the
|
||||
child process to interpret the arguments. Arguments can be
|
||||
file names, host names, or URLs, and many other things. URLs
|
||||
can refer to the local network, some server on the Internet,
|
||||
or to the local file system. Some applications even accept
|
||||
arbitrary code in arguments (for example,
|
||||
<application>python</application> with the
|
||||
<option>-c</option> option).
|
||||
</para>
|
||||
<para>
|
||||
Similar concerns apply to environment variables, the contents
|
||||
of the current directory and its subdirectories.
|
||||
<!-- ??? refer to section on temporary directories -->
|
||||
</para>
|
||||
<para>
|
||||
Consequently, careful analysis is required if it is safe to
|
||||
pass untrusted data to another program.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Processes-Fork-Parallel">
|
||||
<title><function>fork</function> as a primitive for parallelism</title>
|
||||
<para>
|
||||
A call to <function>fork</function> which is not immediately
|
||||
followed by a call to <function>execve</function> (perhaps after
|
||||
rearranging and closing file descriptors) is typically unsafe,
|
||||
especially from a library which does not control the state of
|
||||
the entire process. Such use of <function>fork</function>
|
||||
should be replaced with proper child processes or threads.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
604
en-US/Tasks-Serialization.xml
Normal file
604
en-US/Tasks-Serialization.xml
Normal file
|
@ -0,0 +1,604 @@
|
|||
<?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-Serialization">
|
||||
<title>Serialization and Deserialization</title>
|
||||
<para>
|
||||
Protocol decoders and file format parsers are often the
|
||||
most-exposed part of an application because they are exposed with
|
||||
little or no user interaction and before any authentication and
|
||||
security checks are made. They are also difficult to write
|
||||
robustly in languages which are not memory-safe.
|
||||
</para>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Serialization-Decoders">
|
||||
<title>Recommendations for manually written decoders</title>
|
||||
<para>
|
||||
For C and C++, the advice in <xref
|
||||
linkend="sect-Defensive_Coding-C-Pointers"/> applies. In
|
||||
addition, avoid non-character pointers directly into input
|
||||
buffers. Pointer misalignment causes crashes on some
|
||||
architectures.
|
||||
</para>
|
||||
<para>
|
||||
When reading variable-sized objects, do not allocate large
|
||||
amounts of data solely based on the value of a size field. If
|
||||
possible, grow the data structure as more data is read from the
|
||||
source, and stop when no data is available. This helps to avoid
|
||||
denial-of-service attacks where little amounts of input data
|
||||
results in enormous memory allocations during decoding.
|
||||
Alternatively, you can impose reasonable bounds on memory
|
||||
allocations, but some protocols do not permit this.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Protocol design</title>
|
||||
<para>
|
||||
Binary formats with explicit length fields are more difficult to
|
||||
parse robustly than those where the length of dynamically-sized
|
||||
elements is derived from sentinel values. A protocol which does
|
||||
not use length fields and can be written in printable ASCII
|
||||
characters simplifies testing and debugging. However, binary
|
||||
protocols with length fields may be more efficient to parse.
|
||||
</para>
|
||||
<para>
|
||||
In new datagram-oriented protocols, unique numbers such as
|
||||
sequence numbers or identifiers for fragment reassembly (see
|
||||
<xref
|
||||
linkend="sect-Defensive_Coding-Tasks-Serialization-Fragmentation"/>)
|
||||
should be at least 64 bits large, and really should not be
|
||||
smaller than 32 bits in size. Protocols should not permit
|
||||
fragments with overlapping contents.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Serialization-Fragmentation">
|
||||
<title>Fragmentation</title>
|
||||
<para>
|
||||
Some serialization formats use frames or protocol data units
|
||||
(PDUs) on lower levels which are smaller than the PDUs on higher
|
||||
levels. With such an architecture, higher-level PDUs may have
|
||||
to be <emphasis>fragmented</emphasis> into smaller frames during
|
||||
serialization, and frames may need
|
||||
<emphasis>reassembly</emphasis> into large PDUs during
|
||||
deserialization.
|
||||
</para>
|
||||
<para>
|
||||
Serialization formats may use conceptually similar structures
|
||||
for completely different purposes, for example storing multiple
|
||||
layers and color channels in a single image file.
|
||||
</para>
|
||||
<para>
|
||||
When fragmenting PDUs, establish a reasonable lower bound for
|
||||
the size of individual fragments (as large as possible—limits as
|
||||
low as one or even zero can add substantial overhead). Avoid
|
||||
fragmentation if at all possible, and try to obtain the maximum
|
||||
acceptable fragment length from a trusted data source.
|
||||
</para>
|
||||
<para>
|
||||
When implementing reassembly, consider the following aspects.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Avoid allocating significant amount of resources without
|
||||
proper authentication. Allocate memory for the unfragmented
|
||||
PDU as more and more and fragments are encountered, and not
|
||||
based on the initially advertised unfragmented PDU size,
|
||||
unless there is a sufficiently low limit on the unfragmented
|
||||
PDU size, so that over-allocation cannot lead to performance
|
||||
problems.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Reassembly queues on top of datagram-oriented transports
|
||||
should be bounded, both in the combined size of the arrived
|
||||
partial PDUs waiting for reassembly, and the total number of
|
||||
partially reassembled fragments. The latter limit helps to
|
||||
reduce the risk of accidental reassembly of unrelated
|
||||
fragments, as it can happen with small fragment IDs (see
|
||||
<xref linkend="sect-Defensive_Coding-Tasks-Serialization-Fragmentation-ID"/>).
|
||||
It also guards to some extent against deliberate injection of fragments,
|
||||
by guessing fragment IDs.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Carefully keep track of which bytes in the unfragmented PDU
|
||||
have been covered by fragments so far. If message
|
||||
reordering is a concern, the most straightforward data
|
||||
structure for this is an array of bits, with one bit for
|
||||
every byte (or other atomic unit) in the unfragmented PDU.
|
||||
Complete reassembly can be determined by increasing a
|
||||
counter of set bits in the bit array as the bit array is
|
||||
updated, taking overlapping fragments into consideration.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Reject overlapping fragments (that is, multiple fragments
|
||||
which provide data at the same offset of the PDU being
|
||||
fragmented), unless the protocol explicitly requires
|
||||
accepting overlapping fragments. The bit array used for
|
||||
tracking already arrived bytes can be used for this purpose.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Check for conflicting values of unfragmented PDU lengths (if
|
||||
this length information is part of every fragment) and
|
||||
reject fragments which are inconsistent.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Validate fragment lengths and offsets of individual
|
||||
fragments against the unfragmented PDU length (if they are
|
||||
present). Check that the last byte in the fragment does not
|
||||
lie after the end of the unfragmented PDU. Avoid integer
|
||||
overflows in these computations (see <xref
|
||||
linkend="sect-Defensive_Coding-C-Arithmetic"/>).
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<section id="sect-Defensive_Coding-Tasks-Serialization-Fragmentation-ID">
|
||||
<title>Fragment IDs</title>
|
||||
<para>
|
||||
If the underlying transport is datagram-oriented (so that PDUs
|
||||
can be reordered, duplicated or be lost, like with UDP),
|
||||
fragment reassembly needs to take into account endpoint
|
||||
addresses of the communication channel, and there has to be
|
||||
some sort of fragment ID which identifies the individual
|
||||
fragments as part of a larger PDU. In addition, the
|
||||
fragmentation protocol will typically involve fragment offsets
|
||||
and fragment lengths, as mentioned above.
|
||||
</para>
|
||||
<para>
|
||||
If the transport may be subject to blind PDU injection (again,
|
||||
like UDP), the fragment ID must be generated randomly. If the
|
||||
fragment ID is 64 bit or larger (strongly recommended), it can
|
||||
be generated in a completely random fashion for most traffic
|
||||
volumes. If it is less than 64 bits large (so that accidental
|
||||
collisions can happen if a lot of PDUs are transmitted), the
|
||||
fragment ID should be incremented sequentially from a starting
|
||||
value. The starting value should be derived using a HMAC-like
|
||||
construction from the endpoint addresses, using a long-lived
|
||||
random key. This construction ensures that despite the
|
||||
limited range of the ID, accidental collisions are as unlikely
|
||||
as possible. (This will not work reliable with really short
|
||||
fragment IDs, such as the 16 bit IDs used by the Internet
|
||||
Protocol.)
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title id="sect-Defensive_Coding-Tasks-Serialization-Library">Library
|
||||
support for deserialization</title>
|
||||
<para>
|
||||
For some languages, generic libraries are available which allow
|
||||
to serialize and deserialize user-defined objects. The
|
||||
deserialization part comes in one of two flavors, depending on
|
||||
the library. The first kind uses type information in the data
|
||||
stream to control which objects are instantiated. The second
|
||||
kind uses type definitions supplied by the programmer. The
|
||||
first one allows arbitrary object instantiation, the second one
|
||||
generally does not.
|
||||
</para>
|
||||
<para>
|
||||
The following serialization frameworks are in the first category,
|
||||
are known to be unsafe, and must not be used for untrusted data:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Python's <package>pickle</package> and <package>cPickle</package>
|
||||
modules, and wrappers such as <package>shelve</package>
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Perl's <package>Storable</package> package
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Java serialization (<type>java.io.ObjectInputStream</type>),
|
||||
even if encoded in other formats (as with
|
||||
<type>java.beans.XMLDecoder</type>)
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
PHP serialization (<function>unserialize</function>)
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Most implementations of YAML
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
When using a type-directed deserialization format where the
|
||||
types of the deserialized objects are specified by the
|
||||
programmer, make sure that the objects which can be instantiated
|
||||
cannot perform any destructive actions in their destructors,
|
||||
even when the data members have been manipulated.
|
||||
</para>
|
||||
<para>
|
||||
In general, JSON decoders do not suffer from this problem. But
|
||||
you must not use the <function>eval</function> function to parse
|
||||
JSON objects in Javascript; even with the regular expression
|
||||
filter from RFC 4627, there are still information leaks
|
||||
remaining. JSON-based formats can still turn out risky if they
|
||||
serve as an encoding form for any if the serialization
|
||||
frameworks listed above.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Serialization-XML">
|
||||
<title>XML serialization</title>
|
||||
<para>
|
||||
</para>
|
||||
<section id="sect-Defensive_Coding-Tasks-Serialization-XML-External">
|
||||
<title>External references</title>
|
||||
<para>
|
||||
XML documents can contain external references. They can occur
|
||||
in various places.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
In the DTD declaration in the header of an XML document:
|
||||
</para>
|
||||
<informalexample>
|
||||
<programlisting language="XML">
|
||||
<![CDATA[<!DOCTYPE html PUBLIC
|
||||
"-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">]]>
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
In a namespace declaration:
|
||||
</para>
|
||||
<informalexample>
|
||||
<programlisting language="XML">
|
||||
<![CDATA[<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">]]>
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
In an entity defintion:
|
||||
</para>
|
||||
<informalexample>
|
||||
<programlisting language="XML">
|
||||
<![CDATA[<!ENTITY sys SYSTEM "http://www.example.com/ent.xml">
|
||||
<!ENTITY pub PUBLIC "-//Example//Public Entity//EN"
|
||||
"http://www.example.com/pub-ent.xml">]]>
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
In a notation:
|
||||
</para>
|
||||
<informalexample>
|
||||
<programlisting language="XML">
|
||||
<![CDATA[<!NOTATION not SYSTEM "../not.xml">]]>
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
Originally, these external references were intended as unique
|
||||
identifiers, but by many XML implementations, they are used
|
||||
for locating the data for the referenced element. This causes
|
||||
unwanted network traffic, and may disclose file system
|
||||
contents or otherwise unreachable network resources, so this
|
||||
functionality should be disabled.
|
||||
</para>
|
||||
<para>
|
||||
Depending on the XML library, external referenced might be
|
||||
processed not just when parsing XML, but also when generating
|
||||
it.
|
||||
</para>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-Tasks-Serialization-XML-Entities">
|
||||
<title>Entity expansion</title>
|
||||
<para>
|
||||
When external DTD processing is disabled, an internal DTD
|
||||
subset can still contain entity definitions. Entity
|
||||
declarations can reference other entities. Some XML libraries
|
||||
expand entities automatically, and this processing cannot be
|
||||
switched off in some places (such as attribute values or
|
||||
content models). Without limits on the entity nesting level,
|
||||
this expansion results in data which can grow exponentially in
|
||||
length with size of the input. (If there is a limit on the
|
||||
nesting level, the growth is still polynomial, unless further
|
||||
limits are imposed.)
|
||||
</para>
|
||||
<para>
|
||||
Consequently, the processing internal DTD subsets should be
|
||||
disabled if possible, and only trusted DTDs should be
|
||||
processed. If a particular XML application does not permit
|
||||
such restrictions, then application-specific limits are called
|
||||
for.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Serialization-XML-XInclude">
|
||||
<title>XInclude processing</title>
|
||||
<para>
|
||||
XInclude processing can reference file and network resources
|
||||
and include them into the document, much like external entity
|
||||
references. When parsing untrusted XML documents, XInclude
|
||||
processing should be truned off.
|
||||
</para>
|
||||
<para>
|
||||
XInclude processing is also fairly complex and may pull in
|
||||
support for the XPointer and XPath specifications,
|
||||
considerably increasing the amount of code required for XML
|
||||
processing.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Serialization-XML-Validation">
|
||||
<title>Algorithmic complexity of XML validation</title>
|
||||
<para>
|
||||
DTD-based XML validation uses regular expressions for content
|
||||
models. The XML specification requires that content models
|
||||
are deterministic, which means that efficient validation is
|
||||
possible. However, some implementations do not enforce
|
||||
determinism, and require exponential (or just polynomial)
|
||||
amount of space or time for validating some DTD/document
|
||||
combinations.
|
||||
</para>
|
||||
<para>
|
||||
XML schemas and RELAX NG (via the <literal>xsd:</literal>
|
||||
prefix) directly support textual regular expressions which are
|
||||
not required to be deterministic.
|
||||
</para>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-Tasks-Serialization-XML-Expat">
|
||||
<title>Using Expat for XML parsing</title>
|
||||
<para>
|
||||
By default, Expat does not try to resolve external IDs, so no
|
||||
steps are required to block them. However, internal entity
|
||||
declarations are processed. Installing a callback which stops
|
||||
parsing as soon as such entities are encountered disables
|
||||
them, see <xref
|
||||
linkend="ex-Defensive_Coding-Tasks-Serialization-XML-Expat-EntityDeclHandler"/>.
|
||||
Expat does not perform any validation, so there are no
|
||||
problems related to that.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Tasks-Serialization-XML-Expat-EntityDeclHandler">
|
||||
<title>Disabling XML entity processing with Expat</title>
|
||||
<xi:include href="snippets/Tasks-Serialization-XML-Expat-EntityDeclHandler.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
This handler must be installed when the
|
||||
<literal>XML_Parser</literal> object is created (<xref
|
||||
linkend="ex-Defensive_Coding-Tasks-Serialization-XML-Expat-Create"/>).
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Tasks-Serialization-XML-Expat-Create">
|
||||
<title>Creating an Expat XML parser</title>
|
||||
<xi:include href="snippets/Tasks-Serialization-XML-Expat-Create.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
It is also possible to reject internal DTD subsets altogeher,
|
||||
using a suitable
|
||||
<literal>XML_StartDoctypeDeclHandler</literal> handler
|
||||
installed with <function>XML_SetDoctypeDeclHandler</function>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Serialization-Qt">
|
||||
<title>Using Qt for XML parsing</title>
|
||||
<para>
|
||||
The XML component of Qt, QtXml, does not resolve external IDs
|
||||
by default, so it is not requred to prevent such resolution.
|
||||
Internal entities are processed, though. To change that, a
|
||||
custom <literal>QXmlDeclHandler</literal> and
|
||||
<literal>QXmlSimpleReader</literal> subclasses are needed. It
|
||||
is not possible to use the
|
||||
<function>QDomDocument::setContent(const QByteArray
|
||||
&)</function> convenience methods.
|
||||
</para>
|
||||
<para>
|
||||
<xref linkend="ex-Defensive_Coding-Tasks-Serialization-XML-Qt-NoEntityHandler"/>
|
||||
shows an entity handler which always returns errors, causing
|
||||
parsing to stop when encountering entity declarations.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Tasks-Serialization-XML-Qt-NoEntityHandler">
|
||||
<title>A QtXml entity handler which blocks entity processing</title>
|
||||
<xi:include href="snippets/Tasks-Serialization-XML-Qt-NoEntityHandler.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
This handler is used in the custom
|
||||
<literal>QXmlReader</literal> subclass in <xref
|
||||
linkend="ex-Defensive_Coding-Tasks-Serialization-XML-Qt-NoEntityReader"/>.
|
||||
Some parts of QtXml will call the
|
||||
<function>setDeclHandler(QXmlDeclHandler *)</function> method.
|
||||
Consequently, we prevent overriding our custom handler by
|
||||
providing a definition of this method which does nothing. In
|
||||
the constructor, we activate namespace processing; this part
|
||||
may need adjusting.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Tasks-Serialization-XML-Qt-NoEntityReader">
|
||||
<title>A QtXml XML reader which blocks entity processing</title>
|
||||
<xi:include href="snippets/Tasks-Serialization-XML-Qt-NoEntityReader.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
Our <literal>NoEntityReader</literal> class can be used with
|
||||
one of the overloaded
|
||||
<function>QDomDocument::setContent</function> methods.
|
||||
<xref linkend="ex-Defensive_Coding-Tasks-Serialization-XML-Qt-QDomDocument"/>
|
||||
shows how the <literal>buffer</literal> object (of type
|
||||
<literal>QByteArray</literal>) is wrapped as a
|
||||
<literal>QXmlInputSource</literal>. After calling the
|
||||
<function>setContent</function> method, you should check the
|
||||
return value and report any error.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Tasks-Serialization-XML-Qt-QDomDocument">
|
||||
<title>Parsing an XML document with QDomDocument, without entity expansion</title>
|
||||
<xi:include href="snippets/Tasks-Serialization-XML-Qt-QDomDocument.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Serialization-XML-OpenJDK_Parse">
|
||||
<title>Using OpenJDK for XML parsing and validation</title>
|
||||
<para>
|
||||
OpenJDK contains facilities for DOM-based, SAX-based, and
|
||||
StAX-based document parsing. Documents can be validated
|
||||
against DTDs or XML schemas.
|
||||
</para>
|
||||
<para>
|
||||
The approach taken to deal with entity expansion differs from
|
||||
the general recommendation in <xref
|
||||
linkend="sect-Defensive_Coding-Tasks-Serialization-XML-Entities"/>.
|
||||
We enable the the feature flag
|
||||
<literal>javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING</literal>,
|
||||
which enforces heuristic restrictions on the number of entity
|
||||
expansions. Note that this flag alone does not prevent
|
||||
resolution of external references (system IDs or public IDs),
|
||||
so it is slightly misnamed.
|
||||
</para>
|
||||
<para>
|
||||
In the following sections, we use helper classes to prevent
|
||||
external ID resolution.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Tasks-Serialization-XML-OpenJDK-NoEntityResolver">
|
||||
<title>Helper class to prevent DTD external entity resolution in OpenJDK</title>
|
||||
<xi:include href="snippets/Tasks-Serialization-XML-OpenJDK-NoEntityResolver.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<example id="ex-Defensive_Coding-Tasks-Serialization-XML-OpenJDK-NoResourceResolver">
|
||||
<title>Helper class to prevent schema resolution in
|
||||
OpenJDK</title>
|
||||
<xi:include href="snippets/Tasks-Serialization-XML-OpenJDK-NoResourceResolver.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
<xref linkend="ex-Defensive_Coding-Tasks-Serialization-XML-OpenJDK-Imports"/>
|
||||
shows the imports used by the examples.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Tasks-Serialization-XML-OpenJDK-Imports">
|
||||
<title>Java imports for OpenJDK XML parsing</title>
|
||||
<xi:include href="snippets/Tasks-Serialization-XML-OpenJDK-Imports.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<section id="sect-Defensive_Coding-Tasks-Serialization-XML-OpenJDK_Parse-DOM">
|
||||
<title>DOM-based XML parsing and DTD validation in OpenJDK</title>
|
||||
<para>
|
||||
This approach produces a
|
||||
<literal>org.w3c.dom.Document</literal> object from an input
|
||||
stream. <xref linkend="ex-Defensive_Coding-Tasks-Serialization-XML-OpenJDK_Parse-DOM"/>
|
||||
use the data from the <literal>java.io.InputStream</literal>
|
||||
instance in the <literal>inputStream</literal> variable.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Tasks-Serialization-XML-OpenJDK_Parse-DOM">
|
||||
<title>DOM-based XML parsing in OpenJDK</title>
|
||||
<xi:include href="snippets/Tasks-Serialization-XML-OpenJDK_Parse-DOM.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
External entity references are prohibited using the
|
||||
<literal>NoEntityResolver</literal> class in
|
||||
<xref linkend="ex-Defensive_Coding-Tasks-Serialization-XML-OpenJDK-NoEntityResolver"/>.
|
||||
Because external DTD references are prohibited, DTD validation
|
||||
(if enabled) will only happen against the internal DTD subset
|
||||
embedded in the XML document.
|
||||
</para>
|
||||
<para>
|
||||
To validate the document against an external DTD, use a
|
||||
<literal>javax.xml.transform.Transformer</literal> class to
|
||||
add the DTD reference to the document, and an entity
|
||||
resolver which whitelists this external reference.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Defensive_Coding-Tasks-Serialization-XML-OpenJDK_Parse-SAX">
|
||||
<title>XML Schema validation in OpenJDK</title>
|
||||
<para>
|
||||
<xref linkend="ex-Defensive_Coding-Tasks-Serialization-XML-OpenJDK_Parse-XMLSchema_SAX"/>
|
||||
shows how to validate a document against an XML Schema,
|
||||
using a SAX-based approach. The XML data is read from an
|
||||
<literal>java.io.InputStream</literal> in the
|
||||
<literal>inputStream</literal> variable.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Tasks-Serialization-XML-OpenJDK_Parse-XMLSchema_SAX">
|
||||
<title>SAX-based validation against an XML schema in
|
||||
OpenJDK</title>
|
||||
<xi:include href="snippets/Tasks-Serialization-XML-OpenJDK_Parse-XMLSchema_SAX.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
<para>
|
||||
The <literal>NoResourceResolver</literal> class is defined
|
||||
in <xref linkend="ex-Defensive_Coding-Tasks-Serialization-XML-OpenJDK-NoResourceResolver"/>.
|
||||
</para>
|
||||
<para>
|
||||
If you need to validate a document against an XML schema,
|
||||
use the code in <xref
|
||||
linkend="ex-Defensive_Coding-Tasks-Serialization-XML-OpenJDK_Parse-DOM"/>
|
||||
to create the document, but do not enable validation at this
|
||||
point. Then use
|
||||
<xref linkend="ex-Defensive_Coding-Tasks-Serialization-XML-OpenJDK_Parse-XMLSchema_DOM"/>
|
||||
to perform the schema-based validation on the
|
||||
<literal>org.w3c.dom.Document</literal> instance
|
||||
<literal>document</literal>.
|
||||
</para>
|
||||
<example id="ex-Defensive_Coding-Tasks-Serialization-XML-OpenJDK_Parse-XMLSchema_DOM">
|
||||
<title>Validation of a DOM document against an XML schema in
|
||||
OpenJDK</title>
|
||||
<xi:include href="snippets/Tasks-Serialization-XML-OpenJDK_Parse-XMLSchema_DOM.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</example>
|
||||
</section>
|
||||
<section id="sect-Defensive_Coding-Tasks-Serialization-XML-OpenJDK_Parse-Other">
|
||||
<title>Other XML parsers in OpenJDK</title>
|
||||
<para>
|
||||
OpenJDK contains additional XML parsing and processing
|
||||
facilities. Some of them are insecure.
|
||||
</para>
|
||||
<para>
|
||||
The class <type>java.beans.XMLDecoder</type> acts as a
|
||||
bridge between the Java object serialization format and XML.
|
||||
It is close to impossible to securely deserialize Java
|
||||
objects in this format from untrusted inputs, so its use is
|
||||
not recommended, as with the Java object serialization
|
||||
format itself. See <xref
|
||||
linkend="sect-Defensive_Coding-Tasks-Serialization-Library"/>.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Protocol Encoders</title>
|
||||
<para>
|
||||
For protocol encoders, you should write bytes to a buffer which
|
||||
grows as needed, using an exponential sizing policy. Explicit
|
||||
lengths can be patched in later, once they are known.
|
||||
Allocating the required number of bytes upfront typically
|
||||
requires separate code to compute the final size, which must be
|
||||
kept in sync with the actual encoding step, or vulnerabilities
|
||||
may result. In multi-threaded code, parts of the object being
|
||||
deserialized might change, so that the computed size is out of
|
||||
date.
|
||||
</para>
|
||||
<para>
|
||||
You should avoid copying data directly from a received packet
|
||||
during encoding, disregarding the format. Propagating malformed
|
||||
data could enable attacks on other recipients of that data.
|
||||
</para>
|
||||
<para>
|
||||
When using C or C++ and copying whole data structures directly
|
||||
into the output, make sure that you do not leak information in
|
||||
padding bytes between fields or at the end of the
|
||||
<literal>struct</literal>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
257
en-US/Tasks-Temporary_Files.xml
Normal file
257
en-US/Tasks-Temporary_Files.xml
Normal file
|
@ -0,0 +1,257 @@
|
|||
<?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>
|
53
en-US/Vala.xml
Normal file
53
en-US/Vala.xml
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?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" [
|
||||
]>
|
||||
<chapter id="chap-Defensive_Coding-Vala">
|
||||
<title>The Vala Programming Language</title>
|
||||
<para>
|
||||
Vala is a programming language mainly targeted at GNOME developers.
|
||||
</para>
|
||||
<para>
|
||||
Its syntax is inspired by C# (and thus, indirectly, by Java). But
|
||||
unlike C# and Java, Vala does not attempt to provide memory safety:
|
||||
Vala is compiled to C, and the C code is compiled with GCC using
|
||||
typical compiler flags. Basic operations like integer arithmetic
|
||||
are directly mapped to C constructs. As a results, the
|
||||
recommendations in <xref linkend="chap-Defensive_Coding-C"/> apply.
|
||||
</para>
|
||||
<para>
|
||||
In particular, the following Vala language constructs can result in
|
||||
undefined behavior at run time:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Integer arithmetic, as described in <xref
|
||||
linkend="sect-Defensive_Coding-C-Arithmetic"/>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Pointer arithmetic, string subscripting and the
|
||||
<literal>substring</literal> method on strings (the
|
||||
<literal>string</literal> class in the
|
||||
<literal>glib-2.0</literal> package) are not range-checked. It
|
||||
is the responsibility of the calling code to ensure that the
|
||||
arguments being passed are valid. This applies even to cases
|
||||
(like <literal>substring</literal>) where the implementation
|
||||
would have range information to check the validity of indexes.
|
||||
See <xref linkend="sect-Defensive_Coding-C-Pointers"/>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Similarly, Vala only performs garbage collection (through
|
||||
reference counting) for <literal>GObject</literal> values. For
|
||||
plain C pointers (such as strings), the programmer has to ensure
|
||||
that storage is deallocated once it is no longer needed (to
|
||||
avoid memory leaks), and that storage is not being deallocated
|
||||
while it is still being used (see <xref
|
||||
linkend="sect-Defensive_Coding-C-Use-After-Free"/>).
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</chapter>
|
2118
en-US/Web_Applications.xml.txt
Normal file
2118
en-US/Web_Applications.xml.txt
Normal file
File diff suppressed because it is too large
Load diff
3936
en-US/images/icon.svg
Normal file
3936
en-US/images/icon.svg
Normal file
File diff suppressed because it is too large
Load diff
After Width: | Height: | Size: 108 KiB |
4
en-US/schemas.xml
Normal file
4
en-US/schemas.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0"?>
|
||||
<locatingRules xmlns="http://thaiopensource.com/ns/locating-rules/1.0">
|
||||
<include rules="../schemas.xml"/>
|
||||
</locatingRules>
|
21
en-US/snippets/C-Arithmetic-add.xml
Normal file
21
en-US/snippets/C-Arithmetic-add.xml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
void report_overflow(void);
|
||||
|
||||
int
|
||||
add(int a, int b)
|
||||
{
|
||||
int result = a + b;
|
||||
if (a < 0 || b < 0) {
|
||||
return -1;
|
||||
}
|
||||
// The compiler can optimize away the following if statement.
|
||||
if (result < 0) {
|
||||
report_overflow();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
</programlisting>
|
17
en-US/snippets/C-Arithmetic-add_unsigned.xml
Normal file
17
en-US/snippets/C-Arithmetic-add_unsigned.xml
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
void report_overflow(void);
|
||||
|
||||
unsigned
|
||||
add_unsigned(unsigned a, unsigned b)
|
||||
{
|
||||
unsigned sum = a + b;
|
||||
if (sum < a) { // or sum < b
|
||||
report_overflow();
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
</programlisting>
|
14
en-US/snippets/C-Arithmetic-mult.xml
Normal file
14
en-US/snippets/C-Arithmetic-mult.xml
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
unsigned
|
||||
mul(unsigned a, unsigned b)
|
||||
{
|
||||
if (b && a > ((unsigned)-1) / b) {
|
||||
report_overflow();
|
||||
}
|
||||
return a * b;
|
||||
}
|
||||
</programlisting>
|
12
en-US/snippets/C-Globals-String_Array.xml
Normal file
12
en-US/snippets/C-Globals-String_Array.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
static const char *const string_list[] = {
|
||||
"first",
|
||||
"second",
|
||||
"third",
|
||||
NULL
|
||||
};
|
||||
</programlisting>
|
49
en-US/snippets/C-Pointers-remaining.xml
Normal file
49
en-US/snippets/C-Pointers-remaining.xml
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
ssize_t
|
||||
extract_strings(const char *in, size_t inlen, char **out, size_t outlen)
|
||||
{
|
||||
const char *inp = in;
|
||||
const char *inend = in + inlen;
|
||||
char **outp = out;
|
||||
char **outend = out + outlen;
|
||||
|
||||
while (inp != inend) {
|
||||
size_t len;
|
||||
char *s;
|
||||
if (outp == outend) {
|
||||
errno = ENOSPC;
|
||||
goto err;
|
||||
}
|
||||
len = (unsigned char)*inp;
|
||||
++inp;
|
||||
if (len > (size_t)(inend - inp)) {
|
||||
errno = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
s = malloc(len + 1);
|
||||
if (s == NULL) {
|
||||
goto err;
|
||||
}
|
||||
memcpy(s, inp, len);
|
||||
inp += len;
|
||||
s[len] = '\0';
|
||||
*outp = s;
|
||||
++outp;
|
||||
}
|
||||
return outp - out;
|
||||
err:
|
||||
{
|
||||
int errno_old = errno;
|
||||
while (out != outp) {
|
||||
free(*out);
|
||||
++out;
|
||||
}
|
||||
errno = errno_old;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
</programlisting>
|
18
en-US/snippets/C-String-Functions-format.xml
Normal file
18
en-US/snippets/C-String-Functions-format.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
void log_format(const char *format, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
void
|
||||
log_format(const char *format, ...)
|
||||
{
|
||||
char buf[1000];
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vsnprintf(buf, sizeof(buf), format, ap);
|
||||
va_end(ap);
|
||||
log_string(buf);
|
||||
}
|
||||
</programlisting>
|
14
en-US/snippets/C-String-Functions-snprintf-incremental.xml
Normal file
14
en-US/snippets/C-String-Functions-snprintf-incremental.xml
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
char buf[512];
|
||||
char *current = buf;
|
||||
const char *const end = buf + sizeof(buf);
|
||||
for (struct item *it = data; it->key; ++it) {
|
||||
snprintf(current, end - current, "%s%s=%d",
|
||||
current == buf ? "" : ", ", it->key, it->value);
|
||||
current += strlen(current);
|
||||
}
|
||||
</programlisting>
|
8
en-US/snippets/C-String-Functions-snprintf.xml
Normal file
8
en-US/snippets/C-String-Functions-snprintf.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
char fraction[30];
|
||||
snprintf(fraction, sizeof(fraction), "%d/%d", numerator, denominator);
|
||||
</programlisting>
|
8
en-US/snippets/C-String-Functions-strncat-as-strncpy.xml
Normal file
8
en-US/snippets/C-String-Functions-strncat-as-strncpy.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
buf[0] = '\0';
|
||||
strncat(buf, data, sizeof(buf) - 1);
|
||||
</programlisting>
|
9
en-US/snippets/C-String-Functions-strncat-emulation.xml
Normal file
9
en-US/snippets/C-String-Functions-strncat-emulation.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
char buf[10];
|
||||
snprintf(buf, sizeof(buf), "%s", prefix);
|
||||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s", data);
|
||||
</programlisting>
|
7
en-US/snippets/C-String-Functions-strncat-merged.xml
Normal file
7
en-US/snippets/C-String-Functions-strncat-merged.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
snprintf(buf, sizeof(buf), "%s%s", prefix, data);
|
||||
</programlisting>
|
9
en-US/snippets/C-String-Functions-strncpy.xml
Normal file
9
en-US/snippets/C-String-Functions-strncpy.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
char buf[10];
|
||||
strncpy(buf, data, sizeof(buf));
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
</programlisting>
|
50
en-US/snippets/Features-TLS-Client-GNUTLS-Connect.xml
Normal file
50
en-US/snippets/Features-TLS-Client-GNUTLS-Connect.xml
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
// Create the session object.
|
||||
gnutls_session_t session;
|
||||
ret = gnutls_init(&session, GNUTLS_CLIENT);
|
||||
if (ret != GNUTLS_E_SUCCESS) {
|
||||
fprintf(stderr, "error: gnutls_init: %s\n",
|
||||
gnutls_strerror(ret));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Configure the cipher preferences.
|
||||
const char *errptr = NULL;
|
||||
ret = gnutls_priority_set_direct(session, "NORMAL", &errptr);
|
||||
if (ret != GNUTLS_E_SUCCESS) {
|
||||
fprintf(stderr, "error: gnutls_priority_set_direct: %s\n"
|
||||
"error: at: \"%s\"\n", gnutls_strerror(ret), errptr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Install the trusted certificates.
|
||||
ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred);
|
||||
if (ret != GNUTLS_E_SUCCESS) {
|
||||
fprintf(stderr, "error: gnutls_credentials_set: %s\n",
|
||||
gnutls_strerror(ret));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Associate the socket with the session object and set the server
|
||||
// name.
|
||||
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t)(uintptr_t)sockfd);
|
||||
ret = gnutls_server_name_set(session, GNUTLS_NAME_DNS,
|
||||
host, strlen(host));
|
||||
if (ret != GNUTLS_E_SUCCESS) {
|
||||
fprintf(stderr, "error: gnutls_server_name_set: %s\n",
|
||||
gnutls_strerror(ret));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Establish the session.
|
||||
ret = gnutls_handshake(session);
|
||||
if (ret != GNUTLS_E_SUCCESS) {
|
||||
fprintf(stderr, "error: gnutls_handshake: %s\n",
|
||||
gnutls_strerror(ret));
|
||||
exit(1);
|
||||
}
|
||||
</programlisting>
|
29
en-US/snippets/Features-TLS-Client-GNUTLS-Credentials.xml
Normal file
29
en-US/snippets/Features-TLS-Client-GNUTLS-Credentials.xml
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
// Load the trusted CA certificates.
|
||||
gnutls_certificate_credentials_t cred = NULL;
|
||||
int ret = gnutls_certificate_allocate_credentials (&cred);
|
||||
if (ret != GNUTLS_E_SUCCESS) {
|
||||
fprintf(stderr, "error: gnutls_certificate_allocate_credentials: %s\n",
|
||||
gnutls_strerror(ret));
|
||||
exit(1);
|
||||
}
|
||||
// gnutls_certificate_set_x509_system_trust needs GNUTLS version 3.0
|
||||
// or newer, so we hard-code the path to the certificate store
|
||||
// instead.
|
||||
static const char ca_bundle[] = "/etc/ssl/certs/ca-bundle.crt";
|
||||
ret = gnutls_certificate_set_x509_trust_file
|
||||
(cred, ca_bundle, GNUTLS_X509_FMT_PEM);
|
||||
if (ret == 0) {
|
||||
fprintf(stderr, "error: no certificates found in: %s\n", ca_bundle);
|
||||
exit(1);
|
||||
}
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "error: gnutls_certificate_set_x509_trust_files(%s): %s\n",
|
||||
ca_bundle, gnutls_strerror(ret));
|
||||
exit(1);
|
||||
}
|
||||
</programlisting>
|
30
en-US/snippets/Features-TLS-Client-GNUTLS-Match.xml
Normal file
30
en-US/snippets/Features-TLS-Client-GNUTLS-Match.xml
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
// Match the peer certificate against the host name.
|
||||
// We can only obtain a set of DER-encoded certificates from the
|
||||
// session object, so we have to re-parse the peer certificate into
|
||||
// a certificate object.
|
||||
gnutls_x509_crt_t cert;
|
||||
ret = gnutls_x509_crt_init(&cert);
|
||||
if (ret != GNUTLS_E_SUCCESS) {
|
||||
fprintf(stderr, "error: gnutls_x509_crt_init: %s\n",
|
||||
gnutls_strerror(ret));
|
||||
exit(1);
|
||||
}
|
||||
// The peer certificate is the first certificate in the list.
|
||||
ret = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_DER);
|
||||
if (ret != GNUTLS_E_SUCCESS) {
|
||||
fprintf(stderr, "error: gnutls_x509_crt_import: %s\n",
|
||||
gnutls_strerror(ret));
|
||||
exit(1);
|
||||
}
|
||||
ret = gnutls_x509_crt_check_hostname(cert, host);
|
||||
if (ret == 0 && !certificate_host_name_override(certs[0], host)) {
|
||||
fprintf(stderr, "error: host name does not match certificate\n");
|
||||
exit(1);
|
||||
}
|
||||
gnutls_x509_crt_deinit(cert);
|
||||
</programlisting>
|
42
en-US/snippets/Features-TLS-Client-GNUTLS-Verify.xml
Normal file
42
en-US/snippets/Features-TLS-Client-GNUTLS-Verify.xml
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
// Obtain the server certificate chain. The server certificate
|
||||
// itself is stored in the first element of the array.
|
||||
unsigned certslen = 0;
|
||||
const gnutls_datum_t *const certs =
|
||||
gnutls_certificate_get_peers(session, &certslen);
|
||||
if (certs == NULL || certslen == 0) {
|
||||
fprintf(stderr, "error: could not obtain peer certificate\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Validate the certificate chain.
|
||||
unsigned status = (unsigned)-1;
|
||||
ret = gnutls_certificate_verify_peers2(session, &status);
|
||||
if (ret != GNUTLS_E_SUCCESS) {
|
||||
fprintf(stderr, "error: gnutls_certificate_verify_peers2: %s\n",
|
||||
gnutls_strerror(ret));
|
||||
exit(1);
|
||||
}
|
||||
if (status != 0 && !certificate_validity_override(certs[0])) {
|
||||
gnutls_datum_t msg;
|
||||
#if GNUTLS_VERSION_AT_LEAST_3_1_4
|
||||
int type = gnutls_certificate_type_get (session);
|
||||
ret = gnutls_certificate_verification_status_print(status, type, &out, 0);
|
||||
#else
|
||||
ret = -1;
|
||||
#endif
|
||||
if (ret == 0) {
|
||||
fprintf(stderr, "error: %s\n", msg.data);
|
||||
gnutls_free(msg.data);
|
||||
exit(1);
|
||||
} else {
|
||||
fprintf(stderr, "error: certificate validation failed with code 0x%x\n",
|
||||
status);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
</programlisting>
|
15
en-US/snippets/Features-TLS-Client-NSS-Close.xml
Normal file
15
en-US/snippets/Features-TLS-Client-NSS-Close.xml
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
// Send close_notify alert.
|
||||
if (PR_Shutdown(nspr, PR_SHUTDOWN_BOTH) != PR_SUCCESS) {
|
||||
const PRErrorCode err = PR_GetError();
|
||||
fprintf(stderr, "error: PR_Read error %d: %s\n",
|
||||
err, PR_ErrorToName(err));
|
||||
exit(1);
|
||||
}
|
||||
// Closes the underlying POSIX file descriptor, too.
|
||||
PR_Close(nspr);
|
||||
</programlisting>
|
80
en-US/snippets/Features-TLS-Client-NSS-Connect.xml
Normal file
80
en-US/snippets/Features-TLS-Client-NSS-Connect.xml
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
// Wrap the POSIX file descriptor. This is an internal NSPR
|
||||
// function, but it is very unlikely to change.
|
||||
PRFileDesc* nspr = PR_ImportTCPSocket(sockfd);
|
||||
sockfd = -1; // Has been taken over by NSPR.
|
||||
|
||||
// Add the SSL layer.
|
||||
{
|
||||
PRFileDesc *model = PR_NewTCPSocket();
|
||||
PRFileDesc *newfd = SSL_ImportFD(NULL, model);
|
||||
if (newfd == NULL) {
|
||||
const PRErrorCode err = PR_GetError();
|
||||
fprintf(stderr, "error: NSPR error code %d: %s\n",
|
||||
err, PR_ErrorToName(err));
|
||||
exit(1);
|
||||
}
|
||||
model = newfd;
|
||||
newfd = NULL;
|
||||
if (SSL_OptionSet(model, SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess) {
|
||||
const PRErrorCode err = PR_GetError();
|
||||
fprintf(stderr, "error: set SSL_ENABLE_SSL2 error %d: %s\n",
|
||||
err, PR_ErrorToName(err));
|
||||
exit(1);
|
||||
}
|
||||
if (SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, PR_FALSE) != SECSuccess) {
|
||||
const PRErrorCode err = PR_GetError();
|
||||
fprintf(stderr, "error: set SSL_V2_COMPATIBLE_HELLO error %d: %s\n",
|
||||
err, PR_ErrorToName(err));
|
||||
exit(1);
|
||||
}
|
||||
if (SSL_OptionSet(model, SSL_ENABLE_DEFLATE, PR_FALSE) != SECSuccess) {
|
||||
const PRErrorCode err = PR_GetError();
|
||||
fprintf(stderr, "error: set SSL_ENABLE_DEFLATE error %d: %s\n",
|
||||
err, PR_ErrorToName(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Allow overriding invalid certificate.
|
||||
if (SSL_BadCertHook(model, bad_certificate, (char *)host) != SECSuccess) {
|
||||
const PRErrorCode err = PR_GetError();
|
||||
fprintf(stderr, "error: SSL_BadCertHook error %d: %s\n",
|
||||
err, PR_ErrorToName(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
newfd = SSL_ImportFD(model, nspr);
|
||||
if (newfd == NULL) {
|
||||
const PRErrorCode err = PR_GetError();
|
||||
fprintf(stderr, "error: SSL_ImportFD error %d: %s\n",
|
||||
err, PR_ErrorToName(err));
|
||||
exit(1);
|
||||
}
|
||||
nspr = newfd;
|
||||
PR_Close(model);
|
||||
}
|
||||
|
||||
// Perform the handshake.
|
||||
if (SSL_ResetHandshake(nspr, PR_FALSE) != SECSuccess) {
|
||||
const PRErrorCode err = PR_GetError();
|
||||
fprintf(stderr, "error: SSL_ResetHandshake error %d: %s\n",
|
||||
err, PR_ErrorToName(err));
|
||||
exit(1);
|
||||
}
|
||||
if (SSL_SetURL(nspr, host) != SECSuccess) {
|
||||
const PRErrorCode err = PR_GetError();
|
||||
fprintf(stderr, "error: SSL_SetURL error %d: %s\n",
|
||||
err, PR_ErrorToName(err));
|
||||
exit(1);
|
||||
}
|
||||
if (SSL_ForceHandshake(nspr) != SECSuccess) {
|
||||
const PRErrorCode err = PR_GetError();
|
||||
fprintf(stderr, "error: SSL_ForceHandshake error %d: %s\n",
|
||||
err, PR_ErrorToName(err));
|
||||
exit(1);
|
||||
}
|
||||
</programlisting>
|
26
en-US/snippets/Features-TLS-Client-OpenJDK-Connect.xml
Normal file
26
en-US/snippets/Features-TLS-Client-OpenJDK-Connect.xml
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
// Create the socket and connect it at the TCP layer.
|
||||
SSLSocket socket = (SSLSocket) ctx.getSocketFactory()
|
||||
.createSocket(host, port);
|
||||
|
||||
// Disable the Nagle algorithm.
|
||||
socket.setTcpNoDelay(true);
|
||||
|
||||
// Adjust ciphers and protocols.
|
||||
socket.setSSLParameters(params);
|
||||
|
||||
// Perform the handshake.
|
||||
socket.startHandshake();
|
||||
|
||||
// Validate the host name. The match() method throws
|
||||
// CertificateException on failure.
|
||||
X509Certificate peer = (X509Certificate)
|
||||
socket.getSession().getPeerCertificates()[0];
|
||||
// This is the only way to perform host name checking on OpenJDK 6.
|
||||
HostnameChecker.getInstance(HostnameChecker.TYPE_TLS).match(
|
||||
host, peer);
|
||||
</programlisting>
|
26
en-US/snippets/Features-TLS-Client-OpenJDK-Context.xml
Normal file
26
en-US/snippets/Features-TLS-Client-OpenJDK-Context.xml
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
// Create the context. Specify the SunJSSE provider to avoid
|
||||
// picking up third-party providers. Try the TLS 1.2 provider
|
||||
// first, then fall back to TLS 1.0.
|
||||
SSLContext ctx;
|
||||
try {
|
||||
ctx = SSLContext.getInstance("TLSv1.2", "SunJSSE");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
try {
|
||||
ctx = SSLContext.getInstance("TLSv1", "SunJSSE");
|
||||
} catch (NoSuchAlgorithmException e1) {
|
||||
// The TLS 1.0 provider should always be available.
|
||||
throw new AssertionError(e1);
|
||||
} catch (NoSuchProviderException e1) {
|
||||
throw new AssertionError(e1);
|
||||
}
|
||||
} catch (NoSuchProviderException e) {
|
||||
// The SunJSSE provider should always be available.
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
ctx.init(null, null, null);
|
||||
</programlisting>
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
SSLContext ctx;
|
||||
try {
|
||||
ctx = SSLContext.getInstance("TLSv1.2", "SunJSSE");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
try {
|
||||
ctx = SSLContext.getInstance("TLSv1", "SunJSSE");
|
||||
} catch (NoSuchAlgorithmException e1) {
|
||||
throw new AssertionError(e1);
|
||||
} catch (NoSuchProviderException e1) {
|
||||
throw new AssertionError(e1);
|
||||
}
|
||||
} catch (NoSuchProviderException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
MyTrustManager tm = new MyTrustManager(certHash);
|
||||
ctx.init(null, new TrustManager[] {tm}, null);
|
||||
</programlisting>
|
7
en-US/snippets/Features-TLS-Client-OpenJDK-Hostname.xml
Normal file
7
en-US/snippets/Features-TLS-Client-OpenJDK-Hostname.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
params.setEndpointIdentificationAlgorithm("HTTPS");
|
||||
</programlisting>
|
18
en-US/snippets/Features-TLS-Client-OpenJDK-Import.xml
Normal file
18
en-US/snippets/Features-TLS-Client-OpenJDK-Import.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import sun.security.util.HostnameChecker;
|
||||
</programlisting>
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
public class MyTrustManager implements X509TrustManager {
|
||||
private final byte[] certHash;
|
||||
|
||||
public MyTrustManager(byte[] certHash) throws Exception {
|
||||
this.certHash = certHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType)
|
||||
throws CertificateException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain,
|
||||
String authType) throws CertificateException {
|
||||
byte[] digest = getCertificateDigest(chain[0]);
|
||||
String digestHex = formatHex(digest);
|
||||
|
||||
if (Arrays.equals(digest, certHash)) {
|
||||
System.err.println("info: accepting certificate: " + digestHex);
|
||||
} else {
|
||||
throw new CertificateException("certificate rejected: " +
|
||||
digestHex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
}
|
||||
</programlisting>
|
11
en-US/snippets/Features-TLS-Client-OpenJDK-Use.xml
Normal file
11
en-US/snippets/Features-TLS-Client-OpenJDK-Use.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
socket.getOutputStream().write("GET / HTTP/1.0\r\n\r\n"
|
||||
.getBytes(Charset.forName("UTF-8")));
|
||||
byte[] buffer = new byte[4096];
|
||||
int count = socket.getInputStream().read(buffer);
|
||||
System.out.write(buffer, 0, count);
|
||||
</programlisting>
|
71
en-US/snippets/Features-TLS-Client-OpenSSL-CTX.xml
Normal file
71
en-US/snippets/Features-TLS-Client-OpenSSL-CTX.xml
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
// Configure a client connection context. Send a hendshake for the
|
||||
// highest supported TLS version, and disable compression.
|
||||
const SSL_METHOD *const req_method = SSLv23_client_method();
|
||||
SSL_CTX *const ctx = SSL_CTX_new(req_method);
|
||||
if (ctx == NULL) {
|
||||
ERR_print_errors(bio_err);
|
||||
exit(1);
|
||||
}
|
||||
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION);
|
||||
|
||||
// Adjust the ciphers list based on a whitelist. First enable all
|
||||
// ciphers of at least medium strength, to get the list which is
|
||||
// compiled into OpenSSL.
|
||||
if (SSL_CTX_set_cipher_list(ctx, "HIGH:MEDIUM") != 1) {
|
||||
ERR_print_errors(bio_err);
|
||||
exit(1);
|
||||
}
|
||||
{
|
||||
// Create a dummy SSL session to obtain the cipher list.
|
||||
SSL *ssl = SSL_new(ctx);
|
||||
if (ssl == NULL) {
|
||||
ERR_print_errors(bio_err);
|
||||
exit(1);
|
||||
}
|
||||
STACK_OF(SSL_CIPHER) *active_ciphers = SSL_get_ciphers(ssl);
|
||||
if (active_ciphers == NULL) {
|
||||
ERR_print_errors(bio_err);
|
||||
exit(1);
|
||||
}
|
||||
// Whitelist of candidate ciphers.
|
||||
static const char *const candidates[] = {
|
||||
"AES128-GCM-SHA256", "AES128-SHA256", "AES256-SHA256", // strong ciphers
|
||||
"AES128-SHA", "AES256-SHA", // strong ciphers, also in older versions
|
||||
"RC4-SHA", "RC4-MD5", // backwards compatibility, supposed to be weak
|
||||
"DES-CBC3-SHA", "DES-CBC3-MD5", // more backwards compatibility
|
||||
NULL
|
||||
};
|
||||
// Actually selected ciphers.
|
||||
char ciphers[300];
|
||||
ciphers[0] = '\0';
|
||||
for (const char *const *c = candidates; *c; ++c) {
|
||||
for (int i = 0; i < sk_SSL_CIPHER_num(active_ciphers); ++i) {
|
||||
if (strcmp(SSL_CIPHER_get_name(sk_SSL_CIPHER_value(active_ciphers, i)),
|
||||
*c) == 0) {
|
||||
if (*ciphers) {
|
||||
strcat(ciphers, ":");
|
||||
}
|
||||
strcat(ciphers, *c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
SSL_free(ssl);
|
||||
// Apply final cipher list.
|
||||
if (SSL_CTX_set_cipher_list(ctx, ciphers) != 1) {
|
||||
ERR_print_errors(bio_err);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Load the set of trusted root certificates.
|
||||
if (!SSL_CTX_set_default_verify_paths(ctx)) {
|
||||
ERR_print_errors(bio_err);
|
||||
exit(1);
|
||||
}
|
||||
</programlisting>
|
55
en-US/snippets/Features-TLS-Client-OpenSSL-Connect.xml
Normal file
55
en-US/snippets/Features-TLS-Client-OpenSSL-Connect.xml
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
// Create the connection object.
|
||||
SSL *ssl = SSL_new(ctx);
|
||||
if (ssl == NULL) {
|
||||
ERR_print_errors(bio_err);
|
||||
exit(1);
|
||||
}
|
||||
SSL_set_fd(ssl, sockfd);
|
||||
|
||||
// Enable the ServerNameIndication extension
|
||||
if (!SSL_set_tlsext_host_name(ssl, host)) {
|
||||
ERR_print_errors(bio_err);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Perform the TLS handshake with the server.
|
||||
ret = SSL_connect(ssl);
|
||||
if (ret != 1) {
|
||||
// Error status can be 0 or negative.
|
||||
ssl_print_error_and_exit(ssl, "SSL_connect", ret);
|
||||
}
|
||||
|
||||
// Obtain the server certificate.
|
||||
X509 *peercert = SSL_get_peer_certificate(ssl);
|
||||
if (peercert == NULL) {
|
||||
fprintf(stderr, "peer certificate missing");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Check the certificate verification result. Allow an explicit
|
||||
// certificate validation override in case verification fails.
|
||||
int verifystatus = SSL_get_verify_result(ssl);
|
||||
if (verifystatus != X509_V_OK && !certificate_validity_override(peercert)) {
|
||||
fprintf(stderr, "SSL_connect: verify result: %s\n",
|
||||
X509_verify_cert_error_string(verifystatus));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Check if the server certificate matches the host name used to
|
||||
// establish the connection.
|
||||
// FIXME: Currently needs OpenSSL 1.1.
|
||||
if (X509_check_host(peercert, (const unsigned char *)host, strlen(host),
|
||||
0) != 1
|
||||
&& !certificate_host_name_override(peercert, host)) {
|
||||
fprintf(stderr, "SSL certificate does not match host name\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
X509_free(peercert);
|
||||
|
||||
</programlisting>
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
const char *const req = "GET / HTTP/1.0\r\n\r\n";
|
||||
if (SSL_write(ssl, req, strlen(req)) < 0) {
|
||||
ssl_print_error_and_exit(ssl, "SSL_write", ret);
|
||||
}
|
||||
char buf[4096];
|
||||
ret = SSL_read(ssl, buf, sizeof(buf));
|
||||
if (ret < 0) {
|
||||
ssl_print_error_and_exit(ssl, "SSL_read", ret);
|
||||
}
|
||||
</programlisting>
|
13
en-US/snippets/Features-TLS-Client-OpenSSL-Init.xml
Normal file
13
en-US/snippets/Features-TLS-Client-OpenSSL-Init.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
// The following call prints an error message and calls exit() if
|
||||
// the OpenSSL configuration file is unreadable.
|
||||
OPENSSL_config(NULL);
|
||||
// Provide human-readable error messages.
|
||||
SSL_load_error_strings();
|
||||
// Register ciphers.
|
||||
SSL_library_init();
|
||||
</programlisting>
|
14
en-US/snippets/Features-TLS-Client-Python-Connect.xml
Normal file
14
en-US/snippets/Features-TLS-Client-Python-Connect.xml
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Python">
|
||||
sock = ssl.wrap_socket(sock,
|
||||
ciphers="HIGH:-aNULL:-eNULL:-PSK:RC4-SHA:RC4-MD5",
|
||||
ssl_version=ssl.PROTOCOL_TLSv1,
|
||||
cert_reqs=ssl.CERT_REQUIRED,
|
||||
ca_certs='/etc/ssl/certs/ca-bundle.crt')
|
||||
# getpeercert() triggers the handshake as a side effect.
|
||||
if not check_host_name(sock.getpeercert(), host):
|
||||
raise IOError("peer certificate does not match host name")
|
||||
</programlisting>
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Python">
|
||||
def check_host_name(peercert, name):
|
||||
"""Simple certificate/host name checker. Returns True if the
|
||||
certificate matches, False otherwise. Does not support
|
||||
wildcards."""
|
||||
# Check that the peer has supplied a certificate.
|
||||
# None/{} is not acceptable.
|
||||
if not peercert:
|
||||
return False
|
||||
if peercert.has_key("subjectAltName"):
|
||||
for typ, val in peercert["subjectAltName"]:
|
||||
if typ == "DNS" and val == name:
|
||||
return True
|
||||
else:
|
||||
# Only check the subject DN if there is no subject alternative
|
||||
# name.
|
||||
cn = None
|
||||
for attr, val in peercert["subject"]:
|
||||
# Use most-specific (last) commonName attribute.
|
||||
if attr == "commonName":
|
||||
cn = val
|
||||
if cn is not None:
|
||||
return cn == name
|
||||
return False
|
||||
</programlisting>
|
7
en-US/snippets/Features-TLS-GNUTLS-Credentials-Close.xml
Normal file
7
en-US/snippets/Features-TLS-GNUTLS-Credentials-Close.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
gnutls_certificate_free_credentials(cred);
|
||||
</programlisting>
|
14
en-US/snippets/Features-TLS-GNUTLS-Disconnect.xml
Normal file
14
en-US/snippets/Features-TLS-GNUTLS-Disconnect.xml
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
// Initiate an orderly connection shutdown.
|
||||
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "error: gnutls_bye: %s\n", gnutls_strerror(ret));
|
||||
exit(1);
|
||||
}
|
||||
// Free the session object.
|
||||
gnutls_deinit(session);
|
||||
</programlisting>
|
7
en-US/snippets/Features-TLS-GNUTLS-Init.xml
Normal file
7
en-US/snippets/Features-TLS-GNUTLS-Init.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
gnutls_global_init();
|
||||
</programlisting>
|
18
en-US/snippets/Features-TLS-GNUTLS-Use.xml
Normal file
18
en-US/snippets/Features-TLS-GNUTLS-Use.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
char buf[4096];
|
||||
snprintf(buf, sizeof(buf), "GET / HTTP/1.0\r\nHost: %s\r\n\r\n", host);
|
||||
ret = gnutls_record_send(session, buf, strlen(buf));
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "error: gnutls_record_send: %s\n", gnutls_strerror(ret));
|
||||
exit(1);
|
||||
}
|
||||
ret = gnutls_record_recv(session, buf, sizeof(buf));
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "error: gnutls_record_recv: %s\n", gnutls_strerror(ret));
|
||||
exit(1);
|
||||
}
|
||||
</programlisting>
|
8
en-US/snippets/Features-TLS-NSS-Close.xml
Normal file
8
en-US/snippets/Features-TLS-NSS-Close.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
SECMOD_DestroyModule(module);
|
||||
NSS_ShutdownContext(ctx);
|
||||
</programlisting>
|
20
en-US/snippets/Features-TLS-NSS-Includes.xml
Normal file
20
en-US/snippets/Features-TLS-NSS-Includes.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
// NSPR include files
|
||||
#include <prerror.h>
|
||||
#include <prinit.h>
|
||||
|
||||
// NSS include files
|
||||
#include <nss.h>
|
||||
#include <pk11pub.h>
|
||||
#include <secmod.h>
|
||||
#include <ssl.h>
|
||||
#include <sslproto.h>
|
||||
|
||||
// Private API, no other way to turn a POSIX file descriptor into an
|
||||
// NSPR handle.
|
||||
NSPR_API(PRFileDesc*) PR_ImportTCPSocket(int);
|
||||
</programlisting>
|
63
en-US/snippets/Features-TLS-NSS-Init.xml
Normal file
63
en-US/snippets/Features-TLS-NSS-Init.xml
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
|
||||
NSSInitContext *const ctx =
|
||||
NSS_InitContext("sql:/etc/pki/nssdb", "", "", "", NULL,
|
||||
NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
|
||||
if (ctx == NULL) {
|
||||
const PRErrorCode err = PR_GetError();
|
||||
fprintf(stderr, "error: NSPR error code %d: %s\n",
|
||||
err, PR_ErrorToName(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Ciphers to enable.
|
||||
static const PRUint16 good_ciphers[] = {
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
SSL_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
SSL_NULL_WITH_NULL_NULL // sentinel
|
||||
};
|
||||
|
||||
// Check if the current policy allows any strong ciphers. If it
|
||||
// doesn't, set the cipher suite policy. This is not thread-safe
|
||||
// and has global impact. Consequently, we only do it if absolutely
|
||||
// necessary.
|
||||
int found_good_cipher = 0;
|
||||
for (const PRUint16 *p = good_ciphers; *p != SSL_NULL_WITH_NULL_NULL;
|
||||
++p) {
|
||||
PRInt32 policy;
|
||||
if (SSL_CipherPolicyGet(*p, &policy) != SECSuccess) {
|
||||
const PRErrorCode err = PR_GetError();
|
||||
fprintf(stderr, "error: policy for cipher %u: error %d: %s\n",
|
||||
(unsigned)*p, err, PR_ErrorToName(err));
|
||||
exit(1);
|
||||
}
|
||||
if (policy == SSL_ALLOWED) {
|
||||
fprintf(stderr, "info: found cipher %x\n", (unsigned)*p);
|
||||
found_good_cipher = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found_good_cipher) {
|
||||
if (NSS_SetDomesticPolicy() != SECSuccess) {
|
||||
const PRErrorCode err = PR_GetError();
|
||||
fprintf(stderr, "error: NSS_SetDomesticPolicy: error %d: %s\n",
|
||||
err, PR_ErrorToName(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the trusted certificate store.
|
||||
char module_name[] = "library=libnssckbi.so name=\"Root Certs\"";
|
||||
SECMODModule *module = SECMOD_LoadUserModule(module_name, NULL, PR_FALSE);
|
||||
if (module == NULL || !module->loaded) {
|
||||
const PRErrorCode err = PR_GetError();
|
||||
fprintf(stderr, "error: NSPR error code %d: %s\n",
|
||||
err, PR_ErrorToName(err));
|
||||
exit(1);
|
||||
}
|
||||
</programlisting>
|
22
en-US/snippets/Features-TLS-NSS-Use.xml
Normal file
22
en-US/snippets/Features-TLS-NSS-Use.xml
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
char buf[4096];
|
||||
snprintf(buf, sizeof(buf), "GET / HTTP/1.0\r\nHost: %s\r\n\r\n", host);
|
||||
PRInt32 ret = PR_Write(nspr, buf, strlen(buf));
|
||||
if (ret < 0) {
|
||||
const PRErrorCode err = PR_GetError();
|
||||
fprintf(stderr, "error: PR_Write error %d: %s\n",
|
||||
err, PR_ErrorToName(err));
|
||||
exit(1);
|
||||
}
|
||||
ret = PR_Read(nspr, buf, sizeof(buf));
|
||||
if (ret < 0) {
|
||||
const PRErrorCode err = PR_GetError();
|
||||
fprintf(stderr, "error: PR_Read error %d: %s\n",
|
||||
err, PR_ErrorToName(err));
|
||||
exit(1);
|
||||
}
|
||||
</programlisting>
|
12
en-US/snippets/Features-TLS-Nagle.xml
Normal file
12
en-US/snippets/Features-TLS-Nagle.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
const int val = 1;
|
||||
int ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
|
||||
if (ret < 0) {
|
||||
perror("setsockopt(TCP_NODELAY)");
|
||||
exit(1);
|
||||
}
|
||||
</programlisting>
|
27
en-US/snippets/Features-TLS-OpenJDK-Parameters.xml
Normal file
27
en-US/snippets/Features-TLS-OpenJDK-Parameters.xml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
// Prepare TLS parameters. These have to applied to every TLS
|
||||
// socket before the handshake is triggered.
|
||||
SSLParameters params = ctx.getDefaultSSLParameters();
|
||||
// Do not send an SSL-2.0-compatible Client Hello.
|
||||
ArrayList<String> protocols = new ArrayList<String>(
|
||||
Arrays.asList(params.getProtocols()));
|
||||
protocols.remove("SSLv2Hello");
|
||||
params.setProtocols(protocols.toArray(new String[protocols.size()]));
|
||||
// Adjust the supported ciphers.
|
||||
ArrayList<String> ciphers = new ArrayList<String>(
|
||||
Arrays.asList(params.getCipherSuites()));
|
||||
ciphers.retainAll(Arrays.asList(
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"SSL_RSA_WITH_RC4_128_SHA1",
|
||||
"SSL_RSA_WITH_RC4_128_MD5",
|
||||
"TLS_EMPTY_RENEGOTIATION_INFO_SCSV"));
|
||||
params.setCipherSuites(ciphers.toArray(new String[ciphers.size()]));
|
||||
</programlisting>
|
30
en-US/snippets/Features-TLS-OpenSSL-Connection-Close.xml
Normal file
30
en-US/snippets/Features-TLS-OpenSSL-Connection-Close.xml
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
// Send the close_notify alert.
|
||||
ret = SSL_shutdown(ssl);
|
||||
switch (ret) {
|
||||
case 1:
|
||||
// A close_notify alert has already been received.
|
||||
break;
|
||||
case 0:
|
||||
// Wait for the close_notify alert from the peer.
|
||||
ret = SSL_shutdown(ssl);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
fprintf(stderr, "info: second SSL_shutdown returned zero\n");
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
ssl_print_error_and_exit(ssl, "SSL_shutdown 2", ret);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ssl_print_error_and_exit(ssl, "SSL_shutdown 1", ret);
|
||||
}
|
||||
SSL_free(ssl);
|
||||
close(sockfd);
|
||||
</programlisting>
|
7
en-US/snippets/Features-TLS-OpenSSL-Context-Close.xml
Normal file
7
en-US/snippets/Features-TLS-OpenSSL-Context-Close.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
SSL_CTX_free(ctx);
|
||||
</programlisting>
|
31
en-US/snippets/Features-TLS-OpenSSL-Errors.xml
Normal file
31
en-US/snippets/Features-TLS-OpenSSL-Errors.xml
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
static void __attribute__((noreturn))
|
||||
ssl_print_error_and_exit(SSL *ssl, const char *op, int ret)
|
||||
{
|
||||
int subcode = SSL_get_error(ssl, ret);
|
||||
switch (subcode) {
|
||||
case SSL_ERROR_NONE:
|
||||
fprintf(stderr, "error: %s: no error to report\n", op);
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||
case SSL_ERROR_WANT_CONNECT:
|
||||
case SSL_ERROR_WANT_ACCEPT:
|
||||
fprintf(stderr, "error: %s: invalid blocking state %d\n", op, subcode);
|
||||
break;
|
||||
case SSL_ERROR_SSL:
|
||||
fprintf(stderr, "error: %s: TLS layer problem\n", op);
|
||||
case SSL_ERROR_SYSCALL:
|
||||
fprintf(stderr, "error: %s: system call failed: %s\n", op, strerror(errno));
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
fprintf(stderr, "error: %s: zero return\n", op);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
</programlisting>
|
7
en-US/snippets/Features-TLS-Python-Close.xml
Normal file
7
en-US/snippets/Features-TLS-Python-Close.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Python">
|
||||
sock.close()
|
||||
</programlisting>
|
8
en-US/snippets/Features-TLS-Python-Use.xml
Normal file
8
en-US/snippets/Features-TLS-Python-Use.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Python">
|
||||
sock.write("GET / HTTP/1.1\r\nHost: " + host + "\r\n\r\n")
|
||||
print sock.read()
|
||||
</programlisting>
|
25
en-US/snippets/Go-Error_Handling-IO.xml
Normal file
25
en-US/snippets/Go-Error_Handling-IO.xml
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
func IOError(r io.Reader, buf []byte, processor Processor,
|
||||
handler ErrorHandler) (message string, err error) {
|
||||
n, err := r.Read(buf)
|
||||
// First check for available data.
|
||||
if n > 0 {
|
||||
message, err = processor.Process(buf[0:n])
|
||||
// Regular error handling.
|
||||
if err != nil {
|
||||
handler.Handle(err)
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
// Then handle any error.
|
||||
if err != nil {
|
||||
handler.Handle(err)
|
||||
return "", err
|
||||
}
|
||||
return
|
||||
}
|
||||
</programlisting>
|
23
en-US/snippets/Go-Error_Handling-Regular.xml
Normal file
23
en-US/snippets/Go-Error_Handling-Regular.xml
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
type Processor interface {
|
||||
Process(buf []byte) (message string, err error)
|
||||
}
|
||||
|
||||
type ErrorHandler interface {
|
||||
Handle(err error)
|
||||
}
|
||||
|
||||
func RegularError(buf []byte, processor Processor,
|
||||
handler ErrorHandler) (message string, err error) {
|
||||
message, err = processor.Process(buf)
|
||||
if err != nil {
|
||||
handler.Handle(err)
|
||||
return "", err
|
||||
}
|
||||
return
|
||||
}
|
||||
</programlisting>
|
12
en-US/snippets/Java-Finally.xml
Normal file
12
en-US/snippets/Java-Finally.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
InputStream in = new BufferedInputStream(new FileInputStream(path));
|
||||
try {
|
||||
readFile(in);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
</programlisting>
|
36
en-US/snippets/Java-JNI-Pointers.xml
Normal file
36
en-US/snippets/Java-JNI-Pointers.xml
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
JNIEXPORT jint JNICALL Java_sum
|
||||
(JNIEnv *jEnv, jclass clazz, jbyteArray buffer, jint offset, jint length)
|
||||
{
|
||||
assert(sizeof(jint) == sizeof(unsigned));
|
||||
if (offset < 0 || length < 0) {
|
||||
(*jEnv)->ThrowNew(jEnv, arrayIndexOutOfBoundsExceptionClass,
|
||||
"negative offset/length");
|
||||
return 0;
|
||||
}
|
||||
unsigned uoffset = offset;
|
||||
unsigned ulength = length;
|
||||
// This cannot overflow because of the check above.
|
||||
unsigned totallength = uoffset + ulength;
|
||||
unsigned actuallength = (*jEnv)->GetArrayLength(jEnv, buffer);
|
||||
if (totallength > actuallength) {
|
||||
(*jEnv)->ThrowNew(jEnv, arrayIndexOutOfBoundsExceptionClass,
|
||||
"offset + length too large");
|
||||
return 0;
|
||||
}
|
||||
unsigned char *ptr = (*jEnv)->GetPrimitiveArrayCritical(jEnv, buffer, 0);
|
||||
if (ptr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
unsigned long long sum = 0;
|
||||
for (unsigned char *p = ptr + uoffset, *end = p + ulength; p != end; ++p) {
|
||||
sum += *p;
|
||||
}
|
||||
(*jEnv)->ReleasePrimitiveArrayCritical(jEnv, buffer, ptr, 0);
|
||||
return sum;
|
||||
}
|
||||
</programlisting>
|
39
en-US/snippets/Java-Language-ReadArray.xml
Normal file
39
en-US/snippets/Java-Language-ReadArray.xml
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
static byte[] readBytes(InputStream in, int length) throws IOException {
|
||||
final int startSize = 65536;
|
||||
byte[] b = new byte[Math.min(length, startSize)];
|
||||
int filled = 0;
|
||||
while (true) {
|
||||
int remaining = b.length - filled;
|
||||
readFully(in, b, filled, remaining);
|
||||
if (b.length == length) {
|
||||
break;
|
||||
}
|
||||
filled = b.length;
|
||||
if (length - b.length <= b.length) {
|
||||
// Allocate final length. Condition avoids overflow.
|
||||
b = Arrays.copyOf(b, length);
|
||||
} else {
|
||||
b = Arrays.copyOf(b, b.length * 2);
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
static void readFully(InputStream in,byte[] b, int off, int len)
|
||||
throws IOException {
|
||||
int startlen = len;
|
||||
while (len > 0) {
|
||||
int count = in.read(b, off, len);
|
||||
if (count < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
off += count;
|
||||
len -= count;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
40
en-US/snippets/Java-SecurityManager-Callback.xml
Normal file
40
en-US/snippets/Java-SecurityManager-Callback.xml
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
interface Callback<T> {
|
||||
T call(boolean flag);
|
||||
}
|
||||
|
||||
class CallbackInvoker<T> {
|
||||
private final AccessControlContext context;
|
||||
Callback<T> callback;
|
||||
|
||||
CallbackInvoker(Callback<T> callback) {
|
||||
context = AccessController.getContext();
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public T invoke() {
|
||||
// Obtain increased privileges.
|
||||
return AccessController.doPrivileged(new PrivilegedAction<T>() {
|
||||
@Override
|
||||
public T run() {
|
||||
// This operation would fail without
|
||||
// additional privileges.
|
||||
final boolean flag = Boolean.getBoolean("some.property");
|
||||
|
||||
// Restore the original privileges.
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<T>() {
|
||||
@Override
|
||||
public T run() {
|
||||
return callback.call(flag);
|
||||
}
|
||||
}, context);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
</programlisting>
|
8
en-US/snippets/Java-SecurityManager-CurrentDirectory.xml
Normal file
8
en-US/snippets/Java-SecurityManager-CurrentDirectory.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
permissions.add(new FilePermission(
|
||||
System.getProperty("user.dir") + "/-", "read"));
|
||||
</programlisting>
|
19
en-US/snippets/Java-SecurityManager-Privileged.xml
Normal file
19
en-US/snippets/Java-SecurityManager-Privileged.xml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
// This is expected to fail.
|
||||
try {
|
||||
System.out.println(System.getProperty("user.home"));
|
||||
} catch (SecurityException e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
// This should work.
|
||||
System.out.println(System.getProperty("user.home"));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
</programlisting>
|
28
en-US/snippets/Java-SecurityManager-Unprivileged.xml
Normal file
28
en-US/snippets/Java-SecurityManager-Unprivileged.xml
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
Permissions permissions = new Permissions();
|
||||
ProtectionDomain protectionDomain =
|
||||
new ProtectionDomain(null, permissions);
|
||||
AccessControlContext context = new AccessControlContext(
|
||||
new ProtectionDomain[] { protectionDomain });
|
||||
|
||||
// This is expected to succeed.
|
||||
try (FileInputStream in = new FileInputStream(path)) {
|
||||
System.out.format("FileInputStream: %s%n", in);
|
||||
}
|
||||
|
||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
|
||||
@Override
|
||||
public Void run() throws Exception {
|
||||
// This code runs with reduced privileges and is
|
||||
// expected to fail.
|
||||
try (FileInputStream in = new FileInputStream(path)) {
|
||||
System.out.format("FileInputStream: %s%n", in);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, context);
|
||||
</programlisting>
|
9
en-US/snippets/Java-TryWithResource.xml
Normal file
9
en-US/snippets/Java-TryWithResource.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
try (InputStream in = new BufferedInputStream(new FileInputStream(path))) {
|
||||
readFile(in);
|
||||
}
|
||||
</programlisting>
|
12
en-US/snippets/Shell-Input_Validation.xml
Normal file
12
en-US/snippets/Shell-Input_Validation.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Bash">
|
||||
if [[ $value =~ ^-?[0-9]+$ ]] ; then
|
||||
echo value is an integer
|
||||
else
|
||||
echo "value is not an integer" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
</programlisting>
|
17
en-US/snippets/Tasks-Serialization-XML-Expat-Create.xml
Normal file
17
en-US/snippets/Tasks-Serialization-XML-Expat-Create.xml
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
XML_Parser parser = XML_ParserCreate("UTF-8");
|
||||
if (parser == NULL) {
|
||||
fprintf(stderr, "XML_ParserCreate failed\n");
|
||||
close(fd);
|
||||
exit(1);
|
||||
}
|
||||
// EntityDeclHandler needs a reference to the parser to stop
|
||||
// parsing.
|
||||
XML_SetUserData(parser, parser);
|
||||
// Disable entity processing, to inhibit entity expansion.
|
||||
XML_SetEntityDeclHandler(parser, EntityDeclHandler);
|
||||
</programlisting>
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="C">
|
||||
// Stop the parser when an entity declaration is encountered.
|
||||
static void
|
||||
EntityDeclHandler(void *userData,
|
||||
const XML_Char *entityName, int is_parameter_entity,
|
||||
const XML_Char *value, int value_length,
|
||||
const XML_Char *base, const XML_Char *systemId,
|
||||
const XML_Char *publicId, const XML_Char *notationName)
|
||||
{
|
||||
XML_StopParser((XML_Parser)userData, XML_FALSE);
|
||||
}
|
||||
</programlisting>
|
22
en-US/snippets/Tasks-Serialization-XML-OpenJDK-Errors.xml
Normal file
22
en-US/snippets/Tasks-Serialization-XML-OpenJDK-Errors.xml
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
class Errors implements ErrorHandler {
|
||||
@Override
|
||||
public void warning(SAXParseException exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatalError(SAXParseException exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(SAXParseException exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
</programlisting>
|
27
en-US/snippets/Tasks-Serialization-XML-OpenJDK-Imports.xml
Normal file
27
en-US/snippets/Tasks-Serialization-XML-OpenJDK-Imports.xml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.sax.SAXSource;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
import javax.xml.validation.Validator;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.ls.LSInput;
|
||||
import org.w3c.dom.ls.LSResourceResolver;
|
||||
import org.xml.sax.EntityResolver;
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
import org.xml.sax.XMLReader;
|
||||
</programlisting>
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
class NoEntityResolver implements EntityResolver {
|
||||
@Override
|
||||
public InputSource resolveEntity(String publicId, String systemId)
|
||||
throws SAXException, IOException {
|
||||
// Throwing an exception stops validation.
|
||||
throw new IOException(String.format(
|
||||
"attempt to resolve \"%s\" \"%s\"", publicId, systemId));
|
||||
}
|
||||
}
|
||||
</programlisting>
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
class NoResourceResolver implements LSResourceResolver {
|
||||
@Override
|
||||
public LSInput resolveResource(String type, String namespaceURI,
|
||||
String publicId, String systemId, String baseURI) {
|
||||
// Throwing an exception stops validation.
|
||||
throw new RuntimeException(String.format(
|
||||
"resolution attempt: type=%s namespace=%s " +
|
||||
"publicId=%s systemId=%s baseURI=%s",
|
||||
type, namespaceURI, publicId, systemId, baseURI));
|
||||
}
|
||||
}
|
||||
</programlisting>
|
19
en-US/snippets/Tasks-Serialization-XML-OpenJDK_Parse-DOM.xml
Normal file
19
en-US/snippets/Tasks-Serialization-XML-OpenJDK_Parse-DOM.xml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
// Impose restrictions on the complexity of the DTD.
|
||||
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||
|
||||
// Turn on validation.
|
||||
// This step can be omitted if validation is not desired.
|
||||
factory.setValidating(true);
|
||||
|
||||
// Parse the document.
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
builder.setEntityResolver(new NoEntityResolver());
|
||||
builder.setErrorHandler(new Errors());
|
||||
Document document = builder.parse(inputStream);
|
||||
</programlisting>
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<!-- Automatically generated file. Do not edit. -->
|
||||
<programlisting language="Java">
|
||||
SchemaFactory factory = SchemaFactory.newInstance(
|
||||
XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||
|
||||
// This enables restrictions on schema complexity.
|
||||
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||
|
||||
// The following line prevents resource resolution
|
||||
// by the schema itself.
|
||||
factory.setResourceResolver(new NoResourceResolver());
|
||||
|
||||
Schema schema = factory.newSchema(schemaFile);
|
||||
|
||||
Validator validator = schema.newValidator();
|
||||
|
||||
// This prevents external resource resolution.
|
||||
validator.setResourceResolver(new NoResourceResolver());
|
||||
validator.validate(new DOMSource(document));
|
||||
</programlisting>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue