diff options
Diffstat (limited to 'en_US.ISO8859-1/books/developers-handbook/secure/chapter.sgml')
-rw-r--r-- | en_US.ISO8859-1/books/developers-handbook/secure/chapter.sgml | 525 |
1 files changed, 0 insertions, 525 deletions
diff --git a/en_US.ISO8859-1/books/developers-handbook/secure/chapter.sgml b/en_US.ISO8859-1/books/developers-handbook/secure/chapter.sgml deleted file mode 100644 index bc15b992ac..0000000000 --- a/en_US.ISO8859-1/books/developers-handbook/secure/chapter.sgml +++ /dev/null @@ -1,525 +0,0 @@ -<!-- - The FreeBSD Documentation Project - - $FreeBSD$ ---> - - <chapter id="secure"> - <chapterinfo> - <authorgroup> - <author> - <firstname>Murray</firstname> - <surname>Stockely</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"> - <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 FreeBSD-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> |