[ previous ] [ Contents ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ A ] [ B ] [ C ] [ D ] [ E ] [ F ] [ G ] [ H ] [ next ]


Securing Debian Manual
Chapter 9 - Developer's Best Practices for OS Security


This chapter introduces some best secure coding practices for developers writing Debian packages. If you are really interested in secure coding I recommend you read David Wheeler's Secure Programming for Linux and Unix HOWTO and Secure Coding: Principles and Practices by Mark G. Graff and Kenneth R. van Wyk (O'Reilly, 2003).


9.1 Best practices for security review and design

Developers that are packaging software should make a best effort to ensure that the installation of the software, or its use, does not introduce security risks to either the system it is installed on or its users.

In order to do so, they should make their best to review the source code of the package and detect any flaws that might introduce security bugs before releasing the software or distributing a new version. It is acknowledged that the cost of fixing bugs grows for different stages of its development, so it is easier (and cheaper) to fix bugs when designing than when the software has been deployed and is in maintenance mode (some studies say that the cost in this later phase is sixty times higher). Although there are some tools that try to automatically detect these flaws, developers should strive to learn about the different kind of security flaws in order to understand them and be able to spot them in the code they (or others) have written.

The programming bugs which lead to security bugs typically include: buffer overflows, format string overflows, heap overflows and integer overflows (in C/C++ programs), temporary symlink race conditions (in scripts), directory traversal and command injection (in servers) and cross-site scripting, and SQL injection bugs (in the case of web-oriented applications). For a more complete information on security bugs review Fortify's Taxonomy of Software Security Errors.

Some of these issues might not be easy to spot unless you are an expert in the programming language the software uses, but some security problems are easy to detect and fix. For example, finding temporary race conditions due to misuse of temporary directories can easily be done just by running grep -r "/tmp/" .. Those calls can be reviewed and replace the hardcoded filenames using temporary directories to calls to either mktemp or tempfile in shell scripts, File::Temp(3perl) in Perl scripts, or tmpfile(3) in C/C++.

There are a set of tools available to assist to the security code review phase. These include rats, flawfinder and pscan. For more information, read the list of tools used by the Debian Security Audit Team.

When packaging software developers have to make sure that they follow common security principles, including:

If you have to do any of the above make sure the programs that might run with higher privileges have been audited for security bugs. If you are unsure, or need help, contact the Debian Security Audit team. In the case of setuid/setgid binaries, follow the Debian policy section regarding permissions and owners

For more information, specific to secure programming, make sure you read (or point your upstream to) Secure Programming for Linux and Unix HOWTO and the Build Security In portal.


9.2 Creating users and groups for software daemons

If your software runs a daemon that does not need root privileges, you need to create a user for it. There are two kind of Debian users that can be used by packages: static uids (assigned by base-passwd, for a list of static users in Debian see Operating system users and groups, Section 12.1.12) and dynamic uids in the range assigned to system users.

In the first case, you need to ask for a user or group id to the base-passwd. Once the user is available there the package needs to be distributed including a proper versioned depends to the base-passwd package.

In the second case, you need to create the system user either in the preinst or in the postinst and make the package depend on adduser (>= 3.11).

The following example code creates the user and group the daemon will run as when the package is installed or upgraded:

[...] case "$1" in install|upgrade) # If the package has default file it could be sourced, so that # the local admin can overwrite the defaults [ -f "/etc/default/packagename" ] && . /etc/default/packagename # Sane defaults: [ -z "$SERVER_HOME" ] && SERVER_HOME=server_dir [ -z "$SERVER_USER" ] && SERVER_USER=server_user [ -z "$SERVER_NAME" ] && SERVER_NAME="Server description" [ -z "$SERVER_GROUP" ] && SERVER_GROUP=server_group # Groups that the user will be added to, if undefined, then none. ADDGROUP="" # create user to avoid running server as root # 1. create group if not existing if ! getent group | grep -q "^$SERVER_GROUP:" ; then echo -n "Adding group $SERVER_GROUP.." addgroup --quiet --system $SERVER_GROUP 2>/dev/null ||true echo "..done" fi # 2. create homedir if not existing test -d $SERVER_HOME || mkdir $SERVER_HOME # 3. create user if not existing if ! getent passwd | grep -q "^$SERVER_USER:"; then echo -n "Adding system user $SERVER_USER.." adduser --quiet \ --system \ --ingroup $SERVER_GROUP \ --no-create-home \ --disabled-password \ $SERVER_USER 2>/dev/null || true echo "..done" fi # 4. adjust passwd entry usermod -c "$SERVER_NAME" \ -d $SERVER_HOME \ -g $SERVER_GROUP \ $SERVER_USER # 5. adjust file and directory permissions if ! dpkg-statoverride --list $SERVER_HOME >/dev/null then chown -R $SERVER_USER:adm $SERVER_HOME chmod u=rwx,g=rxs,o= $SERVER_HOME fi # 6. Add the user to the ADDGROUP group if test -n $ADDGROUP then if ! groups $SERVER_USER | cut -d: -f2 | \ grep -qw $ADDGROUP; then adduser $SERVER_USER $ADDGROUP fi fi ;; configure) [...]

You have to make sure that the init.d script file:

If the package creates the system user it can remove it when it is purged in its postrm. This has some drawbacks, however. For example, files created by it will be orphaned and might be taken over by a new system user in the future if it is assigned the same uid[63]. Consequently, removing system users on purge is not yet mandatory and depends on the package needs. If unsure, this action could be handled by asking the administrator for the prefered action when the package is installed (i.e. through debconf).

The following example code[64] removes the user and groups created before only, and only if, the uid is in the range of dynamic assigned system uids and the gid is belongs to a system group:

case "$1" in purge) [...] # find first and last SYSTEM_UID numbers for LINE in `grep SYSTEM_UID /etc/adduser.conf | grep -v "^#"`; do case $LINE in FIRST_SYSTEM_UID*) FIST_SYSTEM_UID=`echo $LINE | cut -f2 -d '='` ;; LAST_SYSTEM_UID*) LAST_SYSTEM_UID=`echo $LINE | cut -f2 -d '='` ;; *) ;; esac done # Remove system account if necessary CREATEDUSER="server_user" if [ -n "$FIST_SYSTEM_UID" ] && [ -n "$LAST_SYSTEM_UID" ]; then if USERID=`getent passwd $CREATEDUSER | cut -f 3 -d ':'`; then if [ -n "$USERID" ]; then if [ "$FIST_SYSTEM_UID" -le "$USERID" ] && \ [ "$USERID" -le "$LAST_SYSTEM_UID" ]; then echo -n "Removing $CREATEDUSER system user.." deluser --quiet $CREATEDUSER || true echo "..done" fi fi fi fi # Remove system group if necessary CREATEDGROUP=server_group FIRST_USER_GID=`grep ^USERS_GID /etc/adduser.conf | cut -f2 -d '='` if [ -n "$FIST_USER_GID" ] then if GROUPGID=`getent group $CREATEDGROUP | cut -f 3 -d ':'`; then if [ -n "$GROUPGID" ]; then if [ "$FIST_USER_GID" -gt "$GROUPGID" ]; then echo -n "Removing $CREATEDGROUP group.." delgroup --only-if-empty $CREATEDGROUP || true echo "..done" fi fi fi fi [...]

Running programs with a user with limited privileges makes sure that any security issue will not be able to damage the full system. It also follows the principle of least privilege. Also consider you can limit privileges in programs through other mechanisms besides running as non-root[65]. For more information, read the Minimize Privileges chapter of the Secure Programming for Linux and Unix HOWTO book.


[ previous ] [ Contents ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ A ] [ B ] [ C ] [ D ] [ E ] [ F ] [ G ] [ H ] [ next ]


Securing Debian Manual

Version: 3.13, Mon, 10 Nov 2008 23:32:30 +0000

Javier Fernández-Sanguino Peña jfs@debian.org
Authors, Section 1.1