Merge branch 'master' of git+ssh://git.fedorahosted.org/git/secure-coding
This commit is contained in:
commit
8341df782d
10 changed files with 348 additions and 4 deletions
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>)
|
||||
|
|
90
defensive-coding/en-US/Go.xml
Normal file
90
defensive-coding/en-US/Go.xml
Normal 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>
|
131
defensive-coding/en-US/Tasks-Packaging.xml
Normal file
131
defensive-coding/en-US/Tasks-Packaging.xml
Normal 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 && 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 && 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>
|
53
defensive-coding/en-US/Vala.xml
Normal file
53
defensive-coding/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>
|
1
defensive-coding/src/.gitignore
vendored
1
defensive-coding/src/.gitignore
vendored
|
@ -4,5 +4,6 @@
|
|||
/TLS-Client-OpenSSL
|
||||
/XML-Parser-Expat
|
||||
/XML-Parser-Qt
|
||||
/Go-Error_Handling
|
||||
*.class
|
||||
*.o
|
||||
|
|
48
defensive-coding/src/Go-Error_Handling.go
Normal file
48
defensive-coding/src/Go-Error_Handling.go
Normal 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() {
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue