Secure Programming for Linux and Unix HOWTO | ||
---|---|---|
<<< Previous | Next >>> |
Undoubtedly there are all sorts of languages in the world, yet none of them is without meaning. | |
1 Corinthians 14:10 (NIV) |
There are many language-specific security issues. Many of them can be summarized as follows:
Turn on all relevant warnings and protection mechanisms available to you where practical. For compiled languages, this includes both compile-time mechanisms and run-time mechanisms. In general, security-relevant programs should compile cleanly with all warnings turned on.
Avoid dangerous and deprecated operations in the language. By ``dangerous'', I mean operations which are difficult to use correctly.
Ensure that the languages' infrastructure (e.g., run-time library) is available and secured.
Languages that automatically garbage-collect strings should be especially careful to immediately erase secret data (in particular secret keys and passwords).
Know precisely the semantics of the operations that you are using. Look up each operation's semantics in its documentation. Do not ignore return values unless you're sure they cannot be relevant. Don't ignore the difference between ``signed'' and ``unsigned'' values. This is particularly difficult in languages which don't support exceptions, like C, but that's the way it goes.
One of the biggest security problems with C and C++ programs is buffer overflow; see the chapter called Avoid Buffer Overflow for more information. C has the additional weakness of not supporting exceptions, which makes it easy to write programs that ignore critical error situations.
One complication in C and C++ is that the character type ``char'' can be signed or unsigned (depending on the compiler and machine). When a signed char with its high bit set is saved in an integer, the result will be a negative number; in some cases this can be exploitable. In general, use ``unsigned char'' instead of char or signed char for buffers, pointers, and casts when dealing with character data that may have values greater than 127 (0x7f).
C and C++ are by definition rather lax in their type-checking support, but there's no need to be lax in your code. Turn on as many compiler warnings as you can and change the code to cleanly compile with them, and strictly use ANSI prototypes in separate header (.h) files to ensure that all function calls use the correct types. For C or C++ compilations using gcc, use at least the following as compilation flags (which turn on a host of warning messages) and try to eliminate all warnings (note that -O2 is used since some warnings can only be detected by the data flow analysis performed at higher optimization levels):
gcc -Wall -Wpointer-arith -Wstrict-prototypes -O2 |
Many C/C++ compilers can detect inaccurate format strings. For example, gcc can warn about inaccurate format strings for functions you create if you use its __attribute__() facility (a C extension) to mark such functions, and you can use that facility without making your code non-portable. Here is an example of what you'd put in your header (.h) file:
/* in header.h */ #ifndef __GNUC__ # define __attribute__(x) /*nothing*/ #endif extern void logprintf(const char *format, ...) __attribute__((format(printf,1,2))); extern void logprintva(const char *format, va_list args) __attribute__((format(printf,1,0))); |
Where you can, use ``enum'' to define enumerated values (and not just a ``char'' or ``int'' with special values). This is particularly useful for values in switch statements, where the compiler can be used to determine if all legal values have been covered.
<<< Previous | Home | Next >>> |
Prevent Include/Configuration File Access | Perl |