|
|
YOUR FEEDBACK
Did you read today's front page stories & breaking news?
SYS-CON.TV |
TOP LINKS YOU MUST CLICK ON Interviews
"Secure Coding in C and C++" A Linux.SYS-CON.com Interview With Robert Seacord
An interview with Robert Seacord, senior vulnerability analyst at CERT
By: Ibrahim Haddad
Dec. 24, 2005 02:15 PM
Digg This!
Page 2 of 2
« previous page
Finally sprintf() is a triple threat. Incautious use of this function can result in a buffer overflow vulnerability if, for example, an attacker provides a string argument for the user variable below that exceeds 495 bytes (512 bytes - 16 character bytes - 1 null byte):
1. char buffer[512]; Secondly, because the sprintf() function accepts a formatted output function that accepts a format string and variable number of arguments, it's subject to format string exploits. Third, if you Google for sprintf() on the Internet you can usually find some code that looks like this code (that I found in the first link I selected) from the Linux kernel mailing list at http://lkml.org/:
int i; So what's wrong with this code? Well, sprintf() can (and will) return -1 on error conditions such as an encoding error. In this case, the count variable, already at zero, can be decremented further - almost always with unexpected results. While this particular error isn't commonly associated with software vulnerabilities, it can easily lead to abnormal program termination. LWM: Does gcc or Visual Studio produce more secure executables? How do you assess this? RCS: In general both compilers are constrained by conformance to C language standards such as ISO/IEC 9899. In some places, Microsoft intentionally disregards strict conformance to improve security, for example, by disallowing the %n conversion specifiers for formatted input/output functions in the 2005 version of Visual C++. I think the most interesting area for differentiation from a security perspective is in each implementation's handling of integers. In a perfect world, C and C++ compilers would identify the potential for exceptional conditions to occur at runtime and provide a mechanism (such as an exception, trap, or signal handler) for applications to handle these events. Unfortunately, the world we live in is far from perfect. The Visual C++ .NET 2003 compiler generates a compiler warning (C4244) when an integer value is assigned to a smaller integer type. At warning level 1, a warning is issued if a value of type __int64 is assigned to a variable of type unsigned int. At warning level 3 and 4, a "possible loss of data" warning is issued if an integer type is converted to a smaller integer type. For example, the assignment in the following example is flagged at warning level 4:
// C4244.cpp Visual C++ .NET 2003 also provides runtime error checks that are enabled by the /RTC flag. The /RTCc compiler flag, in particular, provides a similar function to compiler warning C4244 by reporting when a value assigned to a smaller data type results in a loss of data. Visual C++ also includes a runtime_checks pragma that disables or restores the /RTC settings, but it doesn't include flags for catching other runtime errors such as overflows. Visual C++ 2005 adds the ability to catch overflows in operator::new (and is on by default). Runtime error checks aren't valid in a release (optimized) build for performance reasons. The gcc and g++ compilers include an -ftrapv compiler option that provides limited support for detecting signed integer exceptions at runtime. According to the gcc man page, this option "generates traps for signed overflow on addition, subtraction, and multiplication operations." In practice, this means that the gcc compiler generates calls to existing library functions rather than generating assembler instructions to perform these arithmetic operations on signed integers. These are enforced at runtime even when optimization is enabled. If you use this feature, make sure you use gcc version 3.4 or later because the checks implemented by the runtime system before this version don't adequately detect all overflows and shouldn't be relied on to do so. Neither compiler passes an argument or byte count on calls to variadic functions implemented using the ANSI stdargs, although it's permitted by the C99 specification and would make variadic functions such as the formatted input/output functions more secure. LWM: Are there any security issues that are unique to Linux/gcc? How can they be overcome? Are there any solutions in sight? RCS: Data pointers are used in C and C++ to refer to dynamically allocated structures, call-by-reference function arguments, arrays, and other data structures. An attacker can modify these data pointers (when exploiting a buffer overflow vulnerability, for example). If a pointer is subsequently used as a target for an assignment, an attacker can control the address to modify other memory locations with a technique known as an arbitrary memory write. Most Linux implementations contain a large number of suitable targets for arbitrary memory writes - addresses that can be overwritten and then used to transfer control to attacker-injected code (or existing code selected by the attacker). Linux uses the executable and linking format (ELF) that uses a global offset table (GOT). The GOT contains the absolute addresses of functions in the executable. An attacker can overwrite a GOT entry for a function with the shellcode address using an arbitrary memory write. A similar problem exists when an attacker overwrites function pointers directly. The GCC compiler generates a .dtors section in an easily identifiable location that contains destructor functions that are invoked following execution of the main C program. These functions can be overwritten and used to transfer control to arbitrary code even when the destructor functions aren't used in the program! Arbitrary memory writes can easily defeat canary-based protection schemes. Write-protecting targets is difficult because of the number of targets and because there's a requirement to modify many of these targets (for example, function pointers) at runtime. Buffer overflows occurring in any memory segment can be exploited to execute arbitrary code, so moving variables from the stack to the data segment or heap isn't a solution. The best approach to preventing pointer subterfuge resulting from buffer overflows is to eliminate possible buffer overflow conditions. One way to limit the exposure from some of these targets is to reduce the privileges of potentially vulnerable processes. OpenBSD, for example, enforces a policy called "W xor X" or "W^X" that requires that no part of the process memory address space is both writable and executable. If implemented on Linux systems, this policy could eliminate some (but not all) targets of arbitrary memory write. LWM: Are there any other sources of information on secure coding in C/C++ on Linux? RCS: In addition to my book Secure Coding in C and C++, you should also check out Secure Programming for Linux and Unix HOWTO-Creating Secure Software from David Wheeler online at www.dwheeler.com/secure-programs. SIDEBAR
About the Book Page 2 of 2 « previous page
LATEST LINUX STORIES
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
|
SYS-CON FEATURED WHITEPAPERS MOST READ THIS WEEK |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||