FreeBSD manual
download PDF document: sprog.7.pdf
SPROG(7) FreeBSD Miscellaneous Information Manual SPROG(7)
NAME
sprog - secure programming practices
DESCRIPTION
Security issues have crept into many systems over the years. This
document is a guide for programming practices that prevent these
problems.
Overview
Writing secure applications takes a very scrutinous and pessimistic
outlook. Applications should be run with the principle of "least
privilege" so that no process is ever running with more than the bare
minimum access it needs to accomplish its function. Previously tested
code should be reused whenever possible. Generally, anything beyond the
control of a program should never be trusted. This includes all forms of
user input, system resources, interprocess communication, and the timing
of events.
Buffer Overflows
One of the most common types of security problems is the buffer overflow.
In short, if a program is not careful with the data it receives, it may
be possible for this data to be written across memory, overwriting the
return address for a function call, and the program will be forced to run
code that does unfriendly things.
A good number of functions in the standard C library make it difficult or
even impossible to prevent buffer overflows when used. These include
fscanf(3), gets(3), getwd(3), realpath(3), scanf(3), sprintf(3),
strcat(3), strcpy(3), vscanf(3), and vsprintf(3).
Many other functions that deal with strings can also open up a potential
buffer overflow when not used carefully. For example, strncat(3) does
not go out of its way to provide NUL character termination. Of course,
the proper length must always be specified. Usage of strlcat(3) and
strlcpy(3) ensure that strings are null terminated and of the specified
length.
Functions that receive a string format must also be used carefully. It
is possible for a string to contain additional format specifiers, which
open up another possibility for a buffer overflow. Never pass a string
with untrusted data without using `%s'. Always use the proper secure
idiom:
function("%s", string);
There are mechanisms that provide a backstop for these problems at the
library and compiler levels, however, there is no substitute for simply
writing good code.
Set-user-ID Issues
In many cases, it may be necessary for a program to operate with an
increased set of permissions. Reasons for this include binding to
protected sockets, reading and writing certain files and directories, and
access to various resources. Using a setuid program is frequently the
solution. However, it is important that programs give up these
privileges as soon as possible. For example, if a program is binding to
a protected socket, it should give up its privileges as soon as it has
course, the process must have access to this path to begin with. The new
environment does not actually take effect until chdir(2) is called to
place the process into the new environment. Unfortunately, a process can
break out of this environment if root access is obtained.
Often, jail(2) can be used to create a more complete and enclosed
environment than chroot(2) can provide. A jail limits all processes
inside that environment, including processes with superuser privileges.
Fine grained privileges, as described by POSIX.1e extensions, are
currently a work in progress, and the focus of the TrustedBSD Project.
More information can be found at http://www.TrustedBSD.org/.
Trust
Programs should not make assumptions about the environment in which they
are running. This includes user input, signals, environment variables,
system resources, interprocess communications, and shared memory, amongst
other things that are beyond the control of the program. They should not
assume that all forms of invalid data can be detected either. Instead,
they should use positive filtering, and only allow a specific subset of
inputs that are known to be safe. This is the same logic that an
administrator should apply to a firewall, that is, deny by default and
specify what is to be accepted.
Race Conditions
A race condition is anomalous behavior caused by the relative timing of
events. Programs should not assume that a particular event will occur
before another. The most common causes of race conditions are signals,
access checks, and file reads. Signals are asynchronous by nature, so
special care must be taken while dealing with them. Attempting to check
access with sequential non-atomic operations is a very bad idea, as files
can be moved and changed at any given time. Instead of using a sequence
of access(2) and open(2), use seteuid(2) and then call open(2) directly.
Set umask(2) properly beforehand.
SEE ALSO
jail(2), setuid(2), strlcat(3), strlcpy(3)
AUTHORS
Eric Melville <eric@FreeBSD.org> originally wrote this document based on
a chapter of the FreeBSD Developer's Handbook written by Murray Stokely
<murray@FreeBSD.org>.
FreeBSD 14.2-RELEASE June 3, 2001 FreeBSD 14.2-RELEASE