<!--
     The FreeBSD Documentation Project

     $FreeBSD$
-->

    <chapter id="secure">
      <chapterinfo>
	<authorgroup>
	  <author>
	    <firstname>Murray</firstname>
	    <surname>Stokely</surname>
	    <contrib>Contributed by </contrib>
	  </author>
	</authorgroup>
      </chapterinfo>

      <title>Secure Programming</title>
      
      <sect1 id="secure-synopsis"><title>Synopsis</title>
 
      <para>This chapter describes some of the security issues that
      have plagued &unix; programmers for decades and some of the new
      tools available to help programmers avoid writing exploitable
      code.</para>
      </sect1>

      <sect1 id="secure-philosophy"><title>Secure Design
      Methodology</title>

      <para>Writing secure applications takes a very scrutinous and
      pessimistic outlook on life.  Applications should be run with
      the principle of <quote>least privilege</quote> so that no
      process is ever running with more than the bare minimum access
      that it needs to accomplish its function.  Previously tested
      code should be reused whenever possible to avoid common
      mistakes that others may have already fixed.</para>

      <para>One of the pitfalls of the &unix; environment is how easy it
      is to make assumptions about the sanity of the environment.
      Applications should never trust user input (in all its forms),
      system resources, inter-process communication, or the timing of
      events.  &unix; processes do not execute synchronously so logical
      operations are rarely atomic.</para>
      </sect1>

      <sect1 id="secure-bufferov"><title>Buffer Overflows</title> 

      <para>Buffer Overflows have been around since the very
      beginnings of the Von-Neuman <xref linkend="COD"> architecture.

      <indexterm><primary>buffer overflow</primary></indexterm> 
      <indexterm><primary>Von-Neuman</primary></indexterm>

      They first gained widespread notoriety in 1988 with the Morris
      Internet worm.  Unfortunately, the same basic attack remains

      <indexterm><primary>Morris Internet worm</primary></indexterm>

      effective today.  Of the 17 CERT security advisories of 1999, 10

      <indexterm>
        <primary>CERT</primary><secondary>security advisories</secondary>
      </indexterm>

      of them were directly caused by buffer-overflow software bugs.
      By far the most common type of buffer overflow attack is based
      on corrupting the stack.</para>

      <indexterm><primary>stack</primary></indexterm> 
      <indexterm><primary>arguments</primary></indexterm> 

      <para>Most modern computer systems use a stack to pass arguments
      to procedures and to store local variables.  A stack is a last
      in first out (LIFO) buffer in the high memory area of a process
      image.  When a program invokes a function a new "stack frame" is
   
      <indexterm><primary>LIFO</primary></indexterm>
      <indexterm>
        <primary>process image</primary>
	  <secondary>stack pointer</secondary>
      </indexterm>

      created.  This stack frame consists of the arguments passed to
      the function as well as a dynamic amount of local variable
      space.  The "stack pointer" is a register that holds the current

      <indexterm><primary>stack frame</primary></indexterm>
      <indexterm><primary>stack pointer</primary></indexterm>

      location of the top of the stack.  Since this value is
      constantly changing as new values are pushed onto the top of the
      stack, many implementations also provide a "frame pointer" that
      is located near the beginning of a stack frame so that local
      variables can more easily be addressed relative to this
      value. <xref linkend="COD"> The return address for function

      <indexterm><primary>frame pointer</primary></indexterm> 
      <indexterm>
        <primary>process image</primary>
        <secondary>frame pointer</secondary>
      </indexterm>
      <indexterm><primary>return address</primary></indexterm> 
      <indexterm><primary>stack-overflow</primary></indexterm>

      calls is also stored on the stack, and this is the cause of
      stack-overflow exploits since overflowing a local variable in a
      function can overwrite the return address of that function,
      potentially allowing a malicious user to execute any code he or
      she wants.</para>

      <para>Although stack-based attacks are by far the most common,
      it would also be possible to overrun the stack with a heap-based
      (malloc/free) attack.</para>

      <para>The C programming language does not perform automatic
      bounds checking on arrays or pointers as many other languages
      do.  In addition, the standard C library is filled with a
      handful of very dangerous functions.</para>

      <informaltable frame="none" pgwide="1">
        <tgroup cols=2>
          <tbody>
          <row><entry><function>strcpy</function>(char *dest, const char
          *src)</entry>
          <entry><simpara>May overflow the dest buffer</simpara></entry>
          </row>

          <row><entry><function>strcat</function>(char *dest, const char
          *src)</entry>
          <entry><simpara>May overflow the dest buffer</simpara></entry>
          </row>

          <row><entry><function>getwd</function>(char *buf)</entry>
          <entry><simpara>May overflow the buf buffer</simpara></entry>
          </row>

          <row><entry><function>gets</function>(char *s)</entry>
          <entry><simpara>May overflow the s buffer</simpara></entry>
          </row>

          <row><entry><function>[vf]scanf</function>(const char *format,
          ...)</entry>
          <entry><simpara>May overflow its arguments.</simpara></entry>
          </row>

          <row><entry><function>realpath</function>(char *path, char
          resolved_path[])</entry>
          <entry><simpara>May overflow the path buffer</simpara></entry>
          </row>

          <row><entry><function>[v]sprintf</function>(char *str, const char
          *format, ...)</entry>
          <entry><simpara>May overflow the str buffer.</simpara></entry>
          </row>
          </tbody>
        </tgroup>
      </informaltable>

      <sect2><title>Example Buffer Overflow</title>

      <para>The following example code contains a buffer overflow
      designed to overwrite the return address and skip the
      instruction immediately following the function call.  (Inspired
      by <xref linkend="Phrack">)</para>

<programlisting>#include <sgmltag>stdio.h</sgmltag>

void manipulate(char *buffer) {
  char newbuffer[80];
  strcpy(newbuffer,buffer);
}

int main() {
  char ch,buffer[4096];
  int i=0;

  while ((buffer[i++] = getchar()) != '\n') {};
  
  i=1;
  manipulate(buffer);
  i=2;
  printf("The value of i is : %d\n",i);
  return 0;
}</programlisting>

      <para>Let us examine what the memory image of this process would
      look like if we were to input 160 spaces into our little program
      before hitting return.</para> 

      <para>[XXX figure here!]</para>

      <para>Obviously more malicious input can be devised to execute
      actual compiled instructions (such as exec(/bin/sh)).</para>
      </sect2>

      <sect2><title>Avoiding Buffer Overflows</title>

      <para>The most straightforward solution to the problem of
      stack-overflows is to always use length restricted memory and
      string copy functions.  <function>strncpy</function> and
      <function>strncat</function> are part of the standard C library.

      <indexterm>
        <primary>string copy functions</primary>
	  <secondary>strncpy</secondary>
      </indexterm>      
      <indexterm>
        <primary>string copy functions</primary>
	  <secondary>strncat</secondary>
      </indexterm>      

      These functions accept a length value as a parameter which
      should be no larger than the size of the destination buffer.
      These functions will then copy up to `length' bytes from the
      source to the destination.  However there are a number of
      problems with these functions.  Neither function guarantees NUL
      termination if the size of the input buffer is as large as the

      <indexterm><primary>NUL termination</primary></indexterm>

      destination.  The length parameter is also used inconsistently
      between strncpy and strncat so it is easy for programmers to get
      confused as to their proper usage.  There is also a significant
      performance loss compared to <function>strcpy</function> when
      copying a short string into a large buffer since
      <function>strncpy</function> NUL fills up the size
      specified.</para>

      <para>In OpenBSD, another memory copy implementation has been

      <indexterm><primary>OpenBSD</primary></indexterm>

      created to get around these problem.  The
      <function>strlcpy</function> and <function>strlcat</function>
      functions guarantee that they will always null terminate the
      destination string when given a non-zero length argument.  For
      more information about these functions see <xref
      linkend="OpenBSD">.  The OpenBSD <function>strlcpy</function> and
      <function>strlcat</function> instructions have been in FreeBSD
      since 3.3.</para>

      <indexterm>
        <primary>string copy functions</primary>
	  <secondary>strlcpy</secondary>
      </indexterm>

      <indexterm>
	<primary>string copy functions</primary>
          <secondary>strlcat</secondary>
      </indexterm>

        <sect3><title>Compiler based run-time bounds checking</title>

	<indexterm><primary>bounds checking</primary>
	<secondary>compiler-based</secondary></indexterm>

        <para>Unfortunately there is still a very large assortment of
        code in public use which blindly copies memory around without
        using any of the bounded copy routines we just discussed.
        Fortunately, there is another solution.  Several compiler
        add-ons and libraries exist to do Run-time bounds checking in
        C/C++.</para> 

	<indexterm><primary>StackGuard</primary></indexterm> 
	<indexterm><primary>gcc</primary></indexterm>  

        <para>StackGuard is one such add-on that is implemented as a
        small patch to the gcc code generator.  From the <ulink
          url="http://immunix.org/stackguard.html">StackGuard
          website</ulink>:

        <blockquote><para>"StackGuard detects and defeats stack
        smashing attacks by protecting the return address on the stack
        from being altered.  StackGuard places a "canary" word next to
        the return address when a function is called.  If the canary
        word has been altered when the function returns, then a stack
        smashing attack has been attempted, and the program responds
        by emitting an intruder alert into syslog, and then
        halts."</para></blockquote> 

        <blockquote><para>"StackGuard is implemented as a small patch
        to the gcc code generator, specifically the function_prolog()
        and function_epilog() routines.  function_prolog() has been
        enhanced to lay down canaries on the stack when functions
        start, and function_epilog() checks canary integrity when the
        function exits.  Any attempt at corrupting the return address
        is thus detected before the function
        returns."</para></blockquote>
        </para>

        <indexterm><primary>buffer overflow</primary></indexterm>

        <para>Recompiling your application with StackGuard is an
        effective means of stopping most buffer-overflow attacks, but
        it can still be compromised.</para>

        </sect3>

        <sect3><title>Library based run-time bounds checking</title>

  	<indexterm>
	  <primary>bounds checking</primary>
	  <secondary>library-based</secondary>
	</indexterm>

        <para>Compiler-based mechanisms are completely useless for
        binary-only software for which you cannot recompile.  For
        these situations there are a number of libraries which
        re-implement the unsafe functions of the C-library
        (<function>strcpy</function>, <function>fscanf</function>,
        <function>getwd</function>, etc..) and ensure that these
        functions can never write past the stack pointer.</para>

        <itemizedlist>
        <listitem><simpara>libsafe</simpara></listitem>
        <listitem><simpara>libverify</simpara></listitem>
        <listitem><simpara>libparanoia</simpara></listitem>
        </itemizedlist>

	<para>Unfortunately these library-based defenses have a number
        of shortcomings.  These libraries only protect against a very
        small set of security related issues and they neglect to fix
        the actual problem.  These defenses may fail if the
        application was compiled with -fomit-frame-pointer.  Also, the
        LD_PRELOAD and LD_LIBRARY_PATH environment variables can be
        overwritten/unset by the user.</para>
        </sect3>

        </sect2>
      </sect1>

      <sect1 id="secure-setuid"><title>SetUID issues</title>

      <indexterm><primary>seteuid</primary></indexterm>

      <para>There are at least 6 different IDs associated with any
      given process.  Because of this you have to be very careful with
      the access that your process has at any given time.  In
      particular, all seteuid applications should give up their
      privileges as soon as it is no longer required.</para>

      <indexterm>
        <primary>user IDs</primary>
          <secondary>real user ID</secondary>
      </indexterm>
      <indexterm>
        <primary>user IDs</primary>
          <secondary>effective user ID</secondary>
      </indexterm>

      <para>The real user ID can only be changed by a superuser
      process.  The <application>login</application> program sets this
      when a user initially logs in and it is seldom changed.</para>

      <para>The effective user ID is set by the
      <function>exec()</function> functions if a program has its
      seteuid bit set.  An application can call
      <function>seteuid()</function> at any time to set the effective
      user ID to either the real user ID or the saved set-user-ID.
      When the effective user ID is set by <function>exec()</function>
      functions, the previous value is saved in the saved set-user-ID.</para>

      </sect1>

      <sect1 id="secure-chroot"><title>Limiting your program's environment</title>

      <indexterm><primary>chroot()</primary></indexterm>

      <para>The traditional method of restricting a process
      is with the <function>chroot()</function> system call.  This
      system call changes the root directory from which all other
      paths are referenced for a process and any child processes.  For
      this call to succeed the process must have execute (search)
      permission on the directory being referenced.  The new
      environment does not actually take effect until you
      <function>chdir()</function> into your new environment.  It
      should also be noted that a process can easily break out of a
      chroot environment if it has root privilege.  This could be
      accomplished by creating device nodes to read kernel memory,
      attaching a debugger to a process outside of the jail, or in
      many other creative ways.</para>
      
      <para>The behavior of the <function>chroot()</function> system
      call can be controlled somewhat with the
      kern.chroot_allow_open_directories <command>sysctl</command>
      variable.  When this value is set to 0,
      <function>chroot()</function> will fail with EPERM if there are
      any directories open.  If set to the default value of 1, then
      <function>chroot()</function> will fail with EPERM if there are
      any directories open and the process is already subject to a
      <function>chroot()</function> call.  For any other value, the
      check for open directories will be bypassed completely.</para>

      <sect2><title>FreeBSD's jail functionality</title>

      <indexterm><primary>jail</primary></indexterm>

      <para>The concept of a Jail extends upon the
      <function>chroot()</function> by limiting the powers of the
      superuser to create a true `virtual server'.  Once a prison is
      set up all network communication must take place through the
      specified IP address, and the power of "root privilege" in this
      jail is severely constrained.</para>

      <para>While in a prison, any tests of superuser power within the
      kernel using the <function>suser()</function> call will fail.
      However, some calls to <function>suser()</function> have been
      changed to a new interface <function>suser_xxx()</function>.
      This function is responsible for recognizing or denying access
      to superuser power for imprisoned processes.</para>

      <para>A superuser process within a jailed environment has the
      power to:</para>

      <itemizedlist>
      <listitem><simpara>Manipulate credential with
        <function>setuid</function>, <function>seteuid</function>,
        <function>setgid</function>, <function>setegid</function>,
        <function>setgroups</function>, <function>setreuid</function>,
        <function>setregid</function>, <function>setlogin</function></simpara></listitem>
      <listitem><simpara>Set resource limits with <function>setrlimit</function></simpara></listitem>
      <listitem><simpara>Modify some sysctl nodes
        (kern.hostname)</simpara></listitem>
      <listitem><simpara><function>chroot()</function></simpara></listitem>
      <listitem><simpara>Set flags on a vnode:
        <function>chflags</function>,
        <function>fchflags</function></simpara></listitem>
      <listitem><simpara>Set attributes of a vnode such as file
        permission, owner, group, size, access time, and modification
        time.</simpara></listitem>
      <listitem><simpara>Bind to privileged ports in the Internet
        domain (ports < 1024)</simpara></listitem>
      </itemizedlist>

      <para><function>Jail</function> is a very useful tool for
      running applications in a secure environment but it does have
      some shortcomings.  Currently, the IPC mechanisms have not been
      converted to the <function>suser_xxx</function> so applications
      such as MySQL cannot be run within a jail.  Superuser access
      may have a very limited meaning within a jail, but there is
      no way to specify exactly what "very limited" means.</para>
      </sect2>

      <sect2><title>&posix;.1e Process Capabilities</title>

      <indexterm><primary>POSIX.1e Process Capabilities</primary></indexterm>
      <indexterm><primary>TrustedBSD</primary></indexterm>

      <para>&posix; has released a working draft that adds event
      auditing, access control lists, fine grained privileges,
      information labeling, and mandatory access control.</para>
      <para>This is a work in progress and is the focus of the <ulink
      url="http://www.trustedbsd.org/">TrustedBSD</ulink> project.  Some
      of the initial work has been committed to &os.current; 
      (cap_set_proc(3)).</para>

      </sect2>

      </sect1>

      <sect1 id="secure-trust"><title>Trust</title>

      <para>An application should never assume that anything about the
      users environment is sane.  This includes (but is certainly not
      limited to): user input, signals, environment variables,
      resources, IPC, mmaps, the filesystem working directory, file
      descriptors, the # of open files, etc.</para>

      <indexterm><primary>positive filtering</primary></indexterm>
      <indexterm><primary>data validation</primary></indexterm>

      <para>You should never assume that you can catch all forms of
      invalid input that a user might supply.  Instead, your
      application should use positive filtering to only allow a
      specific subset of inputs that you deem safe.  Improper data
      validation has been the cause of many exploits, especially with
      CGI scripts on the world wide web.  For filenames you need to be
      extra careful about paths ("../", "/"), symbolic links, and
      shell escape characters.</para>

      <indexterm><primary>Perl Taint mode</primary></indexterm>

      <para>Perl has a really cool feature called "Taint" mode which
      can be used to prevent scripts from using data derived outside
      the program in an unsafe way.  This mode will check command line
      arguments, environment variables, locale information, the
      results of certain syscalls (<function>readdir()</function>,
      <function>readlink()</function>,
      <function>getpwxxx()</function>, and all file input.</para>

      </sect1>

      <sect1 id="secure-race-conditions">
      <title>Race Conditions</title>

      <para>A race condition is anomalous behavior caused by the
      unexpected dependence on the relative timing of events.  In
      other words, a programmer incorrectly assumed that a particular
      event would always happen before another.</para>

      <indexterm><primary>race conditions</primary>
      <secondary>signals</secondary></indexterm>

      <indexterm><primary>race conditions</primary>
      <secondary>access checks</secondary></indexterm>

      <indexterm><primary>race conditions</primary>
      <secondary>file opens</secondary></indexterm>

      <para>Some of the common causes of race conditions are signals,
      access checks, and file opens.  Signals are asynchronous events
      by nature so special care must be taken in dealing with them.
      Checking access with <function>access(2)</function> then
      <function>open(2)</function> is clearly non-atomic.  Users can
      move files in between the two calls.  Instead, privileged
      applications should <function>seteuid()</function> and then call
      <function>open()</function> directly.  Along the same lines, an
      application should always set a proper umask before
      <function>open()</function> to obviate the need for spurious
      <function>chmod()</function> calls.</para>

      </sect1>

     </chapter>
