Merge branch 'master' of git+ssh://git.fedorahosted.org/git/secure-coding

This commit is contained in:
Eric Christensen 2014-05-28 11:00:16 -04:00
commit 8341df782d
10 changed files with 348 additions and 4 deletions

View file

@ -9,7 +9,7 @@ build: build-src build-manual
build-snippets:
mkdir -p en-US/snippets
python scripts/split-snippets.py . \
src/*.c src/*.cpp src/*.java src/*.py
src/*.c src/*.cpp src/*.java src/*.py src/*.go
build-manual: build-snippets
publican build --formats=html,epub,pdf --langs=en-US

View file

@ -29,7 +29,7 @@
realloc(ptr, size);</literal> is wrong because the memory
pointed to by <literal>ptr</literal> leaks in case of an error.
</para>
<section>
<section id="sect-Defensive_Coding-C-Use-After-Free">
<title>Use-after-free errors</title>
<para>
After <function>free</function>, the pointer is invalid.
@ -140,7 +140,7 @@
</para>
</section>
<section>
<section id="sect-Defensive_Coding-C-Allocators-Custom">
<title>Custom memory allocators</title>
<para>
Custom memory allocates come in two forms: replacements for
@ -176,7 +176,8 @@
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
is poor, and external fragmentation increases the overall
memory usage.
</para>
</listitem>
</itemizedlist>

View file

@ -8,6 +8,8 @@
<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="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>
@ -18,6 +20,7 @@
<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>

View file

@ -185,6 +185,17 @@
For instance, a verification failure in <command>openssl
verify</command> result in an exit status of zero.
</para>
<para>
OpenSSL command-line commands, such as <command>openssl
genrsa</command>, do not ensure that physical entropy is used
for key generation—they obtain entropy from
<filename>/dev/urandom</filename> and other sources, but not
from <filename>/dev/random</filename>. This can result in
weak keys if the system lacks a proper entropy source (e.g., a
virtual machine with solid state storage). Depending on local
policies, keys generated by these OpenSSL tools should not be
used in high-value, critical functions.
</para>
<para>
The OpenSSL server and client applications (<command>openssl
s_client</command> and <command>openssl s_server</command>)

View file

@ -0,0 +1,90 @@
<?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 and 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>
</chapter>

View file

@ -0,0 +1,131 @@
<?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.
</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 &amp;&amp; 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}) %{tlskey}
%ghost %attr(0644,%{tlsuser},%{tlsuser}) %{tlscert}
</programlisting>
</example>
<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 &amp;&amp; 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}) %{tlskey}
%ghost %attr(0644,%{root},%{root}) %{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>
</chapter>

View 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>

View file

@ -4,5 +4,6 @@
/TLS-Client-OpenSSL
/XML-Parser-Expat
/XML-Parser-Qt
/Go-Error_Handling
*.class
*.o

View file

@ -0,0 +1,48 @@
package main
import "io"
//+ Go Error_Handling-Regular
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
}
//-
//+ Go Error_Handling-IO
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
}
//-
func main() {
}

View file

@ -2,10 +2,12 @@
CC = gcc
CXX = g++
GCCGO = gccgo
CWARNFLAGS = -Wall -W -Wno-unused-parameter -Werror=implicit-function-declaration
CXXWARNFLAGS = -Wall -W
CFLAGS = -std=gnu99 -O2 $(CWARNFLAGS) -g
CXXFLAGS = -std=c++03 -O2 $(CXXWARNFLAGS) -g
GOFLAGS = -O2 -Wall -W
LDFLAGS = -g
# List files which should only be compiled for syntax checking.
@ -41,6 +43,7 @@ compile_and_link += XML-Parser-Expat
LIBS_XML-Parser-Expat = -lexpat
compile_and_link += XML-Parser-Qt
LIBS_XML-Parser-Qt = -lQtCore -lQtXml
compile_and_link += Go-Error_Handling
# Define preprocessor symbols if certain functions exist.
CHECK_FUNCTION = crypto/X509_check_host/-DHAVE_X509_CHECK_HOST \
@ -68,6 +71,9 @@ src/%.class: src/%.java
src/%: src/%.o
$(CXX) $(LDFLAGS) $^ -o $@ $(LIBS_$(notdir $@))
src/%: src/%.go
$(GCCGO) $(GOFLAGS) $(LDFLAGS) -o $@ $^
src/TLS-Client-GNUTLS: src/tcp_connect.o
src/TLS-Client-OpenSSL: src/tcp_connect.o src/x509_check_host.o
src/TLS-Client-NSS: src/tcp_connect.o