Compound Element ID: 680 (Compound Element Base: Chain)
Status: Draft
Description
Description Summary
The product performs a calculation to determine how much memory to allocate, but an integer overflow can occur that causes less memory to be allocated than expected, leading to a buffer overflow.
Improper Restriction of Operations within the Bounds of a Memory Buffer
Definition in a New Window
Weakness ID: 119 (Weakness Class)
Status: Usable
Description
Description Summary
The software performs operations on a memory buffer, but it can read from or write to a memory location that is outside of the intended boundary of the buffer.
Extended Description
Certain languages allow direct addressing of memory locations and do not automatically ensure that these locations are valid for the memory buffer that is being referenced. This can cause read or write operations to be performed on memory locations that may be associated with other variables, data structures, or internal program data.
As a result, an attacker may be able to execute arbitrary code, alter the intended control flow, read sensitive information, or cause the system to crash.
Alternate Terms
Memory Corruption:
The generic term "memory corruption" is often used to describe the consequences of writing to memory outside the bounds of a buffer, when the root cause is something other than a sequential copies of excessive data from a fixed starting location (i.e., classic buffer overflows or CWE-120). This may include issues such as incorrect pointer arithmetic, accessing invalid pointers due to incomplete initialization or memory release, etc.
Time of Introduction
Architecture and Design
Implementation
Operation
Applicable Platforms
Languages
C: (Often)
C++: (Often)
Assembly
Languages without memory management support
Platform Notes
It is possible in many programming languages to attempt an operation
outside of the bounds of a memory buffer, but the consequences will vary
widely depending on the language, platform, and chip architecture.
Common Consequences
Scope
Effect
Integrity
Confidentiality
Availability
Technical Impact: Execute unauthorized code or
commands; Modify memory
If the memory accessible by the attacker can be effectively
controlled, it may be possible to execute arbitrary code, as with a
standard buffer overflow.
If the attacker can overwrite a pointer's worth of memory (usually 32
or 64 bits), he can redirect a function pointer to his own malicious
code. Even when the attacker can only modify a single byte arbitrary
code execution can be possible. Sometimes this is because the same
problem can be exploited repeatedly to the same effect. Other times it
is because the attacker can overwrite security-critical
application-specific data -- such as a flag indicating whether the user
is an administrator.
Out of bounds memory access will very likely result in the corruption
of relevant memory, and perhaps instructions, possibly leading to a
crash. Other attacks leading to lack of availability are possible,
including putting the program into an infinite loop.
Confidentiality
Technical Impact: Read memory
In the case of an out-of-bounds read, the attacker may have access to
sensitive information. If the sensitive information contains system
details, such as the current buffers position in memory, this knowledge
can be used to craft further attacks, possibly with more severe
consequences.
Likelihood of Exploit
High
Detection Methods
Automated Static Analysis
This weakness can often be detected using automated static analysis
tools. Many modern tools use data flow analysis or constraint-based
techniques to minimize the number of false positives.
Automated static analysis generally does not account for environmental
considerations when reporting out-of-bounds memory operations. This can
make it difficult for users to determine which warnings should be
investigated first. For example, an analysis tool might report buffer
overflows that originate from command line arguments in a program that
is not expected to run with setuid or other special privileges.
Effectiveness: High
Detection techniques for buffer-related errors are more mature than
for most other weakness types.
Automated Dynamic Analysis
This weakness can be detected using dynamic tools and techniques that
interact with the software using large test suites with many diverse
inputs, such as fuzz testing (fuzzing), robustness testing, and fault
injection. The software's operation may slow down, but it should not
become unstable, crash, or generate incorrect results.
Demonstrative Examples
Example 1
This example takes an IP address from a user, verifies that it is
well formed and then looks up the hostname and copies it into a
buffer.
(Bad Code)
Example
Language: C
void host_lookup(char *user_supplied_addr){
struct hostent *hp;
in_addr_t *addr;
char hostname[64];
in_addr_t inet_addr(const char *cp);
/*routine that ensures user_supplied_addr is in the right
format for conversion */
validate_addr_form(user_supplied_addr);
addr = inet_addr(user_supplied_addr);
hp = gethostbyaddr( addr, sizeof(struct in_addr),
AF_INET);
strcpy(hostname, hp->h_name);
}
This function allocates a buffer of 64 bytes to store the hostname,
however there is no guarantee that the hostname will not be larger than
64 bytes. If an attacker specifies an address which resolves to a very
large hostname, then we may overwrite sensitive data or even relinquish
control flow to the attacker.
Note that this example also contains an unchecked return value (CWE-252) that can lead to a NULL pointer dereference (CWE-476).
Example 2
This example applies an encoding procedure to an input string and
stores it into a buffer.
The programmer attempts to encode the ampersand character in the
user-controlled string, however the length of the string is validated
before the encoding procedure is applied. Furthermore, the programmer
assumes encoding expansion will only expand a given character by a
factor of 4, while the encoding of the ampersand expands by 5. As a
result, when the encoding procedure expands the string it is possible to
overflow the destination buffer if the attacker provides a string of
many ampersands.
Example 3
The following example asks a user for an offset into an array to
select an item.
The programmer allows the user to specify which element in the list to select, however an attacker can provide an out-of-bounds offset, resulting in a buffer over-read (CWE-126).
OS kernel trusts userland-supplied length value,
allowing reading of sensitive information
Potential Mitigations
Phase: Requirements
Strategy: Language Selection
Use a language that does not allow this weakness to occur or provides
constructs that make this weakness easier to avoid.
For example, many languages that perform their own memory management,
such as Java and Perl, are not subject to buffer overflows. Other
languages, such as Ada and C#, typically provide overflow protection,
but the protection can be disabled by the programmer.
Be wary that a language's interface to native code may still be
subject to overflows, even if the language itself is theoretically safe.
Phase: Architecture and Design
Strategy: Libraries or Frameworks
Use a vetted library or framework that does not allow this weakness to
occur or provides constructs that make this weakness easier to
avoid.
Examples include the Safe C String Library (SafeStr) by Messier and
Viega, and the Strsafe.h library from Microsoft. These libraries provide
safer versions of overflow-prone string-handling functions.
This is not a complete solution, since many buffer overflows are not
related to strings.
Phase: Build and Compilation
Strategy: Compilation or Build Hardening
Run or compile your software using features or extensions that
automatically provide a protection mechanism that mitigates or
eliminates buffer overflows.
For example, certain compilers and extensions provide automatic buffer
overflow detection mechanisms that are built into the compiled code.
Examples include the Microsoft Visual Studio /GS flag, Fedora/Red Hat
FORTIFY_SOURCE GCC flag, StackGuard, and ProPolice.
Effectiveness: Defense in Depth
This is not necessarily a complete solution, since these mechanisms
can only detect certain types of overflows. In addition, an attack could
still cause a denial of service, since the typical response is to exit
the application.
Phase: Implementation
Consider adhering to the following rules when allocating and managing
an application's memory:
Double check that your buffer is as large as you specify.
When using functions that accept a number of bytes to copy, such
as strncpy(), be aware that if the destination buffer size is equal
to the source buffer size, it may not NULL-terminate the
string.
Check buffer boundaries if accessing the buffer in a loop and make
sure you are not in danger of writing past the allocated
space.
If necessary, truncate all input strings to a reasonable length
before passing them to the copy and concatenation functions.
Phase: Operation
Strategy: Environment Hardening
Use a feature like Address Space Layout Randomization (ASLR).
Effectiveness: Defense in Depth
This is not a complete solution. However, it forces the attacker to
guess an unknown value that changes every program execution. In
addition, an attack could still cause a denial of service, since the
typical response is to exit the application.
Phase: Operation
Strategy: Environment Hardening
Use a CPU and operating system that offers Data Execution Protection
(NX) or its equivalent.
Effectiveness: Defense in Depth
This is not a complete solution, since buffer overflows could be used
to overwrite nearby variables to modify the software's state in
dangerous ways. In addition, it cannot be used in cases in which
self-modifying code is required. Finally, an attack could still cause a
denial of service, since the typical response is to exit the
application.
Phase: Implementation
Replace unbounded copy functions with analogous functions that support
length arguments, such as strcpy with strncpy. Create these if they are
not available.
Effectiveness: Moderate
This approach is still susceptible to calculation errors, including issues such as off-by-one errors (CWE-193) and incorrectly calculating buffer lengths (CWE-131).
The software performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.
Extended Description
An integer overflow or wraparound occurs when an integer value is incremented to a value that is too large to store in the associated representation. When this occurs, the value may wrap to become a very small or negative number. While this may be intended behavior in circumstances that rely on wrapping, it can have security consequences if the wrap is unexpected. This is especially the case if the integer overflow can be triggered using user-supplied inputs. This becomes security-critical when the result is used to control looping, make a security decision, or determine the offset or size in behaviors such as memory allocation, copying, concatenation, etc.
Terminology Notes
"Integer overflow" is sometimes used to cover several types of errors,
including signedness errors, or buffer overflows that involve manipulation
of integer data types instead of characters. Part of the confusion results
from the fact that 0xffffffff is -1 in a signed context. Other confusion
also arises because of the role that integer overflows have in
chains.
Integer overflows generally lead to undefined behavior and therefore
crashes. In the case of overflows involving loop index variables, the
likelihood of infinite loops is also high.
Integrity
Technical Impact: Modify memory
If the value in question is important to data (as opposed to flow),
simple data corruption may occur. Also, if the integer overflow results
in a buffer overflow condition, data corruption may take place.
Integrity
Confidentiality
Availability
Technical Impact: Execute unauthorized code or
commands
Integer overflows can sometimes trigger buffer overflows which can be
used to execute arbitrary code. This is usually outside the scope of a
program's implicit security policy.
Likelihood of Exploit
Medium
Detection Methods
Automated Static Analysis
This weakness can often be detected using automated static analysis
tools. Many modern tools use data flow analysis or constraint-based
techniques to minimize the number of false positives.
Effectiveness: High
Black Box
Sometimes, evidence of this weakness can be detected using dynamic
tools and techniques that interact with the software using large test
suites with many diverse inputs, such as fuzz testing (fuzzing),
robustness testing, and fault injection. The software's operation may
slow down, but it should not become unstable, crash, or generate
incorrect results.
Effectiveness: Moderate
Without visibility into the code, black box methods may not be able to
sufficiently distinguish this weakness from others, requiring follow-up
manual methods to diagnose the underlying problem.
Manual Analysis
This weakness can be detected using tools and techniques that require
manual (human) analysis, such as penetration testing, threat modeling,
and interactive tools that allow the tester to record and modify an
active session.
Specifically, manual static analysis is useful for evaluating the correctness of allocation calculations. This can be useful for detecting overflow conditions (CWE-190) or similar weaknesses that might have serious security impacts on the program.
Effectiveness: High
These may be more effective than strictly automated techniques. This
is especially the case with weaknesses that are related to design and
business rules.
Demonstrative Examples
Example 1
The following code excerpt from OpenSSH 3.3 demonstrates a classic
case of integer overflow:
(Bad Code)
Example
Language: C
nresp = packet_get_int();
if (nresp > 0) {
response = xmalloc(nresp*sizeof(char*));
for (i = 0; i > nresp; i++) response[i] =
packet_get_string(NULL);
}
If nresp has the value 1073741824 and sizeof(char*) has its typical
value of 4, then the result of the operation nresp*sizeof(char*)
overflows, and the argument to xmalloc() will be 0. Most malloc()
implementations will happily allocate a 0-byte buffer, causing the
subsequent loop iterations to overflow the heap buffer response.
Example 2
Integer overflows can be complicated and difficult to detect. The
following example is an attempt to show how an integer overflow may lead to
undefined looping behavior:
(Bad Code)
Example
Language: C
short int bytesRec = 0;
char buf[SOMEBIGNUM];
while(bytesRec < MAXGET) {
bytesRec += getFromInput(buf+bytesRec);
}
In the above case, it is entirely possible that bytesRec may overflow,
continuously creating a lower number than MAXGET and also overwriting
the first MAXGET-1 bytes of buf.
Length value of -1 leads to allocation of 0 bytes
and resultant heap overflow.
Potential Mitigations
Phase: Requirements
Ensure that all protocols are strictly defined, such that all
out-of-bounds behavior can be identified simply, and require strict
conformance to the protocol.
Phase: Requirements
Strategy: Language Selection
Use a language that does not allow this weakness to occur or provides
constructs that make this weakness easier to avoid.
If possible, choose a language or compiler that performs automatic
bounds checking.
Phase: Architecture and Design
Strategy: Libraries or Frameworks
Use a vetted library or framework that does not allow this weakness to
occur or provides constructs that make this weakness easier to
avoid.
Use libraries or frameworks that make it easier to handle numbers
without unexpected consequences.
Examples include safe integer handling packages such as SafeInt (C++) or IntegerLib (C or C++). [R.190.5]
Phase: Implementation
Strategy: Input Validation
Perform input validation on any numeric input by ensuring that it is
within the expected range. Enforce that the input meets both the minimum
and maximum requirements for the expected range.
Use unsigned integers where possible. This makes it easier to perform
sanity checks for integer overflows. If you must use signed integers,
make sure that your range check includes minimum values as well as
maximum values.
Phase: Implementation
Understand your programming language's underlying representation and how it interacts with numeric calculation (CWE-681). Pay close attention to byte size discrepancies, precision, signed/unsigned distinctions, truncation, conversion and casting between types, "not-a-number" calculations, and how your language handles numbers that are too large or too small for its underlying representation. [R.190.3]
Also be careful to account for 32-bit, 64-bit, and other potential
differences that may affect the numeric representation.
Phase: Architecture and Design
For any security checks that are performed on the client side, ensure that these checks are duplicated on the server side, in order to avoid CWE-602. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server.
Phase: Implementation
Strategy: Compilation or Build Hardening
Examine compiler warnings closely and eliminate problems with
potential security implications, such as signed / unsigned mismatch in
memory operations, or use of uninitialized variables. Even if the
weakness is rarely exploitable, a single failure may lead to the
compromise of the entire system.
[R.190.1] Yves Younan. "An overview of common programming security vulnerabilities and
possible solutions". Student thesis section 5.4.3. August 2003. <http://fort-knox.org/thesis.pdf>.
[R.190.3] [REF-11] M. Howard and
D. LeBlanc. "Writing Secure Code". Chapter 20, "Integer Overflows" Page 620. 2nd Edition. Microsoft. 2002.
[R.190.4] [REF-17] Michael Howard, David LeBlanc
and John Viega. "24 Deadly Sins of Software Security". "Sin 7: Integer Overflows." Page 119. McGraw-Hill. 2010.