International * Contact  * Sitemap  * Links  * Register Software
Search  
 SUSE - simply change

Home Users

 Novell
  | Home  |  | Overview  |  | Products  |  | Support  |  | Downloads  |  | Distributors & Resellers  |
  SUSE LINUX Support   Online Help   License information   Security   Feedback
  Printable page

Security-specific Programming Errors (Part 3)

Thomas Biege

Table of Contents Temporary Files

Besides memory overflow, errors in the manner in which temporary files are handled are the most common reason for security problems.

Generally, temporary files are created in directories that can be written to by everybody. (In Unix: /tmp, /var/tmp). To prevent files in public directories from being deleted, Unix, for example, sets a filesystem flag (chmod o+t /tmp), which means that users can only remove their own files from the directory. The flag does not offer protection for subdirectories. In other words, if the subdirectory can be written to by everybody, then everything in the directory can be modified, too. The t flag therefore has to be set explicitly for every directory. The directory /tmp/soffice.tmp, which is created by StarOffice, is a good example of this error.

Besides illegal deletion of files, there is also the risk of confidential files being exposed to prying eyes (e.g., with older versions of Acrobat Reader and WordPerfect) and race conditions or link attacks. The following non-atomic and insecure code segments are often used to create temporary files:

Wrong:

[...]
FILE *tmp_datei;
[...]

tmp_datei = tmpfile();
[...]

or:

[...]
char *tmp_name;
int tmpfd;

tmp_name = tmpnam(NULL);

if( (tmpfd = open(tmp_name, O_RDWR | O_CREAT)) < 0) 
      [EXIT]
unlink(tmp_name);
/*
** remove the filename so that the file is not left on the
** file system when the program code completes or when
** the file descriptor is closed.
*/
[...]

Both file creation methods are insecure as they are non-atomic and follow symbolic links. In the second example, it is not the tmpnam(3) function that is responsible for the security risk, but the subsequent open(2) command. Functions like tmpnam(3), tempnam(3) or mktemp(3) only ensure that the file name does not exist at the time when it is called. But between the creation of the name and opening the file, an attacker can create a link with exactly the same name and open(2) follows the link (this is known as a race condition).

Right:

[...]
int tmpfd;
[...]

if( (tmpfd = mkstemp("/tmp/MyTempFile.XXXXXX")) < 0)
     [Exit]

fchmod(tmpfd, 0600);
[...]

Mkstemp(3) creates a unique name and opens it in a secure manner. Unfortunately, the disadvantage of this solution is that mkstemp(3) is not part of the POSIX standard (BSD4.3) and old versions set the access rights to 0666, which means that anybody can write to the file and read from it. To create code that is both secure and portable, open(2) must be used and invoked with the right parameters.

[...]
int tmp_fd;
FILE *tmp_stream;
char tmp_name;
[...]

if((tmp_name = tmpnam(NULL)) == NULL)
    [Exit]

if((tmp_fd = open(tmp_name, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0)
{
     fprintf(stderr, "Possible link attack detected!\n");
     exit(-1);
}

/*

** We want to use the stream-I/O functions in stdio.h
**  
*/
if( (tmp_stream = fdopen(tmp_fd, "rw")) < 0)
     [Exit]
[...]
Format Bugs

The so-called format(ing) bug is another type of bug that leads to security problems. This bug was only discovered recently and has been lying dormant and unnoticed in a lot of software packages for several years.

The bug affects any program that passes data from an untrusted source to functions with variable parameter length as a format string. (In other words, all printf(3)-type functions).

Wrong:

 
[...]  
snprintf(buf, sizeof(buf), UntrustedUserDataBuffer); 
[...]

Right:

[...]
snprintf(buf, sizeof(buf), "%s", UntrustedUserDataBuffer);
[...]

Of course, it is also possible to use strncat(3) or similar.

To better understand the bug, you need to know how the variable number of parameters is handled in C.

The variable parameter number is simply defined with three dots ("...") in the function declaration.

For example:

 
int my_sprintf(char *buffer, char
*format_string, ...);

The function processes the unknown number of arguments with the macros va_start(3), va_arg(3) and va_end(3), which are defined in stdarg.h.

For example:

int my_sprintf(char *buffer, char *format_string, ...)
{
     va_list arg_ptr;        /* argument pointer */
     short ShortValue;
     [...]

     va_start(arg_ptr, format_string);
     /*
     ** set arg_ptr to first optional
     ** argument.
     */
     [...]

     while(format_string != NULL)
     {
     [...]

          ShortValue = va_arg(arg_ptr, short);
          /* va_arg() returns the short value */
          [...]

          ++format_string;
          /* next character in the format string */

     }
     va_end(arg_ptr);
     [...]
}

In order to gain access to the next optional parameter, va_arg(3) simply works its way backward up the stack (addresses are decremented). If the attacker has the chance to define the format string himself, he can specify format tags within the format string even when there are no format variables around.

For example:

[...]
#define MAX_BUF 1024;
[...]

char Buffer[MAX_BUF];
char UntrustedUserDataBuffer[MAX_BUF];
[...]

getDataFromNetwork(UntrustedUserDataBuffer, MAX_BUF);
[...]

my_sprintf(Buffer, UntrustedUserDataBuffer);
/*
** UntrustedUserDataBuffer contains, for example,
** "Good night! %s %p %p %s %p"
** There is no format variable for the format tags!
*/
[...]

Even if there are no format variables, va_arg(3) simply goes up the stack to get the values for the placeholders. The stack frames of other functions are also searched, of course. For this reason, the attacker can not only cause the program to crash, but he can also read confidential/valuable information, change the value of local variables or even execute code by manipulating function pointers, jump addresses or saved IP values. To make changes within the process memory, the format variable "%n" is required. With its help, the (not real) position is written in the format string at a specific address, which is specified by a format variable.

Format bugs can be avoided as follows:

my_sprintf(Buffer, "%s", UntrustedUserDataBuffer);

This prevents the format tags from being parsed yet again.

Further Information

* Reseller
* Reviews
* Support Database
* Hardware Database
* Education Program

Quick Links

* Security
* Support Portal
* Mailing Lists
* Feedback
* SUSE LINUX eNewsletter

Subscribe now!

Get the Live DVD and Run Linux in Seconds!

SUSE LINUX 9.1 Personal Live CD

Want a hassle-free way to try Linux? Download SUSE LINUX Professional 9.2 Live DVD. It runs completely from your DVD drive. No need to install anything.

 This server is powered by NPS.
Linux is a registered trademark of Linus Torvalds.
Last changed: 26.09.2003 09:39 MET DST by webmaster@suse.de