Weaknesses Addressed by the CERT C Secure Coding Standard
Definition in a New Window
View ID: 734 (View: Graph)
Status: Incomplete
View Data
View Objective
CWE entries in this view (graph) are fully or partially eliminated by
following the CERT C Secure Coding Standard. Since not all rules map to specific
weaknesses, this view is incomplete.
View Metrics
CWEs in this view
Total CWEs
Total
103
out of
791
Views
0
out of
22
Categories
15
out of
106
Weaknesses
86
out of
651
Compound_Elements
2
out of
12
View Audience
Stakeholder
Description
Developers
By following the CERT C Secure Coding Standard, developers will be
able to fully or partially prevent the weaknesses that are identified in
this view. In addition, developers can use a CWE coverage graph to
determine which weaknesses are not directly addressed by the standard,
which will help identify and resolve remaining gaps in training, tool
acquisition, or other approaches for reducing weaknesses.
Software Customers
If a software developer claims to be following the CERT C Secure
Coding standard, then customers can search for the weaknesses in this
view in order to formulate independent evidence of that claim.
Educators
Educators can use this view in multiple ways. For example, if there is
a focus on teaching weaknesses, the educator could link them to the
relevant Secure Coding Standard.
Weaknesses Addressed by the CERT C Secure Coding Standard (primary)734
Relationship Notes
The relationships in this view were determined based on specific
statements within the rules from the standard. Not all rules have direct
relationships to individual weaknesses, although they likely have chaining
relationships in specific circumstances.
References
"The CERT C Secure Coding Standard". Addison-Wesley Professional. 2008-10-14.
The accidental addition of a data-structure sentinel can cause
serious programming logic problems.
Extended Description
Data-structure sentinels are often used to mark the structure of data. A
common example of this is the null character at the end of strings or a
special sentinel to mark the end of a linked list. It is dangerous to allow
this type of control data to be easily accessible. Therefore, it is
important to protect from the addition or modification of sentinels.
Time of Introduction
Architecture and Design
Implementation
Applicable Platforms
Languages
C
C++
Common Consequences
Scope
Effect
Availability
Generally this error will cause the data structure to not work
properly by truncating the data.
Likelihood of Exploit
High to Very High
Demonstrative Examples
Example 1
The following example assigns some character values to a list of
characters and prints them each individually, and then as a string. The
third character value is intended to be an integer taken from user input and
converted to an int.
The first print statement will print each character separated by a
space. However, if a non-integer is read from stdin by getc, then atoi
will not make a conversion and return 0. When foo is printed as a
string, the 0 at character foo[2] will act as a NULL terminator and
foo[3] will never be printed.
Potential Mitigations
Phase
Description
Implementation
Architecture and Design
Encapsulate the user from interacting with data sentinels. Validate
user input to verify that sentinels are not present.
Implementation
Proper error checking can reduce the risk of inadvertently introducing
sentinel values into data. For example, if a parsing function fails or
encounters an error, it might return a value that is the same as the
sentinel.
Requirements
Use a language or compiler that performs automatic bounds
checking.
Architecture and Design
Use an abstraction library to abstract away risky APIs. This is not a
complete solution.
Build and Compilation
Compiler-based canary mechanisms such as StackGuard, ProPolice, and
Microsoft Visual Studio /GS flag. Unless this provides automatic bounds
checking, it is not a complete solution.
Operation
Use OS-level preventative functionality. This is not a complete
solution.
The software does not sufficiently delimit the arguments being
passed to a component in another control sphere, allowing alternate arguments to
be provided, leading to potentially security-relevant
changes.
Argument injection vulnerability in TellMe 1.2 and
earlier allows remote attackers to modify command line arguments for the
Whois program and obtain sensitive information via "--" style options in the
q Host parameter.
Beagle before 0.2.5 can produce certain insecure
command lines to launch external helper applications while indexing, which
allows attackers to execute arbitrary commands. NOTE: it is not immediately
clear whether this issue involves argument injection, shell metacharacters,
or other issues.
Argument injection vulnerability in Internet
Explorer 6 for Windows XP SP2 allows user-assisted remote attackers to
modify command line arguments to an invoked mail client via " (double quote)
characters in a mailto: scheme handler, as demonstrated by launching
Microsoft Outlook with an arbitrary filename as an attachment. NOTE: it is
not clear whether this issue is implementation-specific or a problem in the
Microsoft API.
Argument injection vulnerability in Mozilla
Firefox 1.0.6 allows user-assisted remote attackers to modify command line
arguments to an invoked mail client via " (double quote) characters in a
mailto: scheme handler, as demonstrated by launching Microsoft Outlook with
an arbitrary filename as an attachment. NOTE: it is not clear whether this
issue is implementation-specific or a problem in the Microsoft
API.
Argument injection vulnerability in Avant Browser
10.1 Build 17 allows user-assisted remote attackers to modify command line
arguments to an invoked mail client via " (double quote) characters in a
mailto: scheme handler, as demonstrated by launching Microsoft Outlook with
an arbitrary filename as an attachment. NOTE: it is not clear whether this
issue is implementation-specific or a problem in the Microsoft
API.
Argument injection vulnerability in the URI
handler in Skype 2.0.*.104 and 2.5.*.0 through 2.5.*.78 for Windows allows
remote authorized attackers to download arbitrary files via a URL that
contains certain command-line switches.
Argument injection vulnerability in WinSCP 3.8.1
build 328 allows remote attackers to upload or download arbitrary files via
encoded spaces and double-quote characters in a scp or sftp
URI.
Argument injection vulnerability in the Windows
Object Packager (packager.exe) in Microsoft Windows XP SP1 and SP2 and
Server 2003 SP1 and earlier allows remote user-assisted attackers to execute
arbitrary commands via a crafted file with a "/" (slash) character in the
filename of the Command Line property, followed by a valid file extension,
which causes the command before the slash to be executed, aka "Object
Packager Dialogue Spoofing Vulnerability."
Argument injection vulnerability in HyperAccess
8.4 allows user-assisted remote attackers to execute arbitrary vbscript and
commands via the /r option in a telnet:// URI, which is configured to use
hawin32.exe.
Argument injection vulnerability in the telnet
daemon (in.telnetd) in Solaris 10 and 11 (SunOS 5.10 and 5.11) misinterprets
certain client "-f" sequences as valid requests for the login program to
skip authentication, which allows remote attackers to log into certain
accounts, as demonstrated by the bin account.
Language interpreter's mail function accepts
another argument that is concatenated to a string used in a dangerous
popen() call. Since there is no sanitization against this argument, both OS
Command Injection (CWE-78) and Argument Injection (CWE-88) are
possible.
Potential Mitigations
Phase
Description
Avoid using user-controlled input in command arguments.
Assume all input is malicious. Use an appropriate combination of black
lists and white lists to ensure only valid and expected input is
processed by the system.
Weakness Ordinalities
Ordinality
Description
Primary
(where the
weakness exists independent of other weaknesses)
At one layer of abstraction, this can overlap other weaknesses that have
whitespace problems, e.g. injection of javascript into attributes of HTML
tags.
Affected Resources
System Process
Causal Nature
Explicit
Taxonomy Mappings
Mapped Taxonomy Name
Node ID
Fit
Mapped Node Name
PLOVER
Argument Injection or Modification
CERT C Secure Coding
ENV03-C
Sanitize the environment when invoking external
programs
CERT C Secure Coding
ENV04-C
Do not call system() if you do not need a command
processor
Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')
Definition in a New Window
Compound Element ID: 120 (Compound Element Base: Composite)
Status: Incomplete
Description
Description Summary
The program copies an input buffer to an output buffer without
verifying that the size of the input buffer is less than the size of the output
buffer, leading to a buffer overflow.
Extended Description
A buffer overflow condition exists when a program attempts to put more
data in a buffer than it can hold, or when a program attempts to put data in
a memory area outside of the boundaries of a buffer. The simplest type of
error, and the most common cause of buffer overflows, is the "classic" case
in which the program copies the buffer without checking its length at all.
Other variants exist, but the existence of a classic overflow strongly
suggests that the programmer is not considering even the most basic of
security protections.
Alternate Terms
buffer overrun:
Some prominent vendors and researchers use the term "buffer overrun,"
but most people use "buffer overflow."
Unbounded Transfer
Terminology Notes
Many issues that are now called "buffer overflows" are substantively
different than the "classic" overflow, including entirely different bug
types that rely on overflow exploit techniques, such as integer signedness
errors, integer overflows, and format string bugs. This imprecise
terminology can make it difficult to determine which variant is being
reported.
Time of Introduction
Architecture and Design
Implementation
Applicable Platforms
Languages
C
C++
Common Consequences
Scope
Effect
Availability
Buffer overflows generally lead to crashes. Other attacks leading to
lack of availability are possible, including putting the program into an
infinite loop.
Integrity
Buffer overflows often can be used to execute arbitrary code, which is
usually outside the scope of a program's implicit security
policy.
Integrity
When the consequence is arbitrary code execution, this can often be
used to subvert any other security service.
By replacing a valid cookie value with an
extremely long string of characters, an attacker may overflow the
application's buffers.
Potential Mitigations
Phase
Description
Architecture and Design
Use an abstraction library to abstract away risky APIs. Examples
include the Safe C String Library (SafeStr) by Viega, and the Strsafe.h
library from Microsoft. This is not a complete solution, since many
buffer overflows are not related to strings.
Architecture and Design
Use the <strsafe.h> library. This library has buffer
overflow safe functions that will help with the detection of buffer
overflows.
Build and Compilation
Use automatic buffer overflow detection mechanisms that are offered by
certain compilers or compiler extensions. Examples include StackGuard,
ProPolice and the Microsoft Visual Studio /GS flag. This is not
necessarily a complete solution, since these canary-based mechanisms
only detect certain types of overflows. In addition, the result is still
a denial of service, since the typical response is to exit the
application.
Implementation
Programmers should adhere to the following rules when allocating and
managing their applications 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 calling this function in a loop and
make sure you are not in danger of writing past the allocated space.
Truncate all input strings to a reasonable length before passing them to
the copy and concatenation functions
Operation
Use a feature like Address Space Layout Randomization (ASLR). This is
not a complete solution. However, it forces the attacker to guess an
unknown value that changes every program execution.
Operation
Use a CPU and operating system that offers Data Execution Protection
(NX) or its equivalent. 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.
Build and Compilation
Operation
Most mitigating technologies at the compiler or OS level to date
address only a subset of buffer overflow problems and rarely provide
complete protection against even that subset. It is good practice to
implement strategies to increase the workload of an attacker, such as
leaving the attacker to guess an unknown value that changes every
program execution.
Weakness Ordinalities
Ordinality
Description
Resultant
(where the
weakness is typically related to the presence of some other
weaknesses)
Primary
(where the
weakness exists independent of other weaknesses)
At the code level, stack-based and heap-based overflows do not differ
significantly, so there usually is not a need to distinguish them. From the
attacker perspective, they can be quite different, since different
techniques are required to exploit them.
Affected Resources
Memory
Functional Areas
Memory Management
Causal Nature
Explicit
Taxonomy Mappings
Mapped Taxonomy Name
Node ID
Fit
Mapped Node Name
PLOVER
Unbounded Transfer ('classic overflow')
7 Pernicious Kingdoms
Buffer Overflow
CLASP
Buffer overflow
OWASP Top Ten 2004
A1
CWE More Specific
Unvalidated Input
OWASP Top Ten 2004
A5
CWE More Specific
Buffer Overflows
CERT C Secure Coding
STR35-C
Do not copy data from an unbounded source to a fixed-length
array
A weakness where the code path includes a Buffer Write Operation such
that:
1. the expected size of the buffer is greater than the actual size of
the buffer where expected size is equal to the sum of the size of the
data item and the position in the buffer
Where Buffer Write Operation is a statement that writes a data item of a
certain size into a buffer at a certain position and at a certain
index
CERT C Secure Coding Section 01 - Preprocessor (PRE)
Definition in a New Window
Category ID: 735 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the
preprocessor section of the CERT C Secure Coding Standard. Since not all rules
map to specific weaknesses, this category may be incomplete.
CERT C Secure Coding Section 02 - Declarations and Initialization (DCL)
Definition in a New Window
Category ID: 736 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the
declarations and initialization section of the CERT C Secure Coding Standard.
Since not all rules map to specific weaknesses, this category may be incomplete.
CERT C Secure Coding Section 03 - Expressions (EXP)
Definition in a New Window
Category ID: 737 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the
expressions section of the CERT C Secure Coding Standard. Since not all rules
map to specific weaknesses, this category may be incomplete.
Weaknesses in this category are related to rules in the
integers section of the CERT C Secure Coding Standard. Since not all rules map
to specific weaknesses, this category may be incomplete.
CERT C Secure Coding Section 05 - Floating Point (FLP)
Definition in a New Window
Category ID: 739 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the
floating point section of the CERT C Secure Coding Standard. Since not all rules
map to specific weaknesses, this category may be incomplete.
Weaknesses in this category are related to rules in the arrays
section of the CERT C Secure Coding Standard. Since not all rules map to
specific weaknesses, this category may be incomplete.
CERT C Secure Coding Section 07 - Characters and Strings (STR)
Definition in a New Window
Category ID: 741 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the
characters and strings section of the CERT C Secure Coding Standard. Since not
all rules map to specific weaknesses, this category may be incomplete.
CERT C Secure Coding Section 08 - Memory Management (MEM)
Definition in a New Window
Category ID: 742 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the memory
management section of the CERT C Secure Coding Standard. Since not all rules map
to specific weaknesses, this category may be incomplete.
CERT C Secure Coding Section 09 - Input Output (FIO)
Definition in a New Window
Category ID: 743 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the
input/output section of the CERT C Secure Coding Standard. Since not all rules
map to specific weaknesses, this category may be incomplete.
CERT C Secure Coding Section 10 - Environment (ENV)
Definition in a New Window
Category ID: 744 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the
environment section of the CERT C Secure Coding Standard. Since not all rules
map to specific weaknesses, this category may be incomplete.
Weaknesses in this category are related to rules in the signals
section of the CERT C Secure Coding Standard. Since not all rules map to
specific weaknesses, this category may be incomplete.
CERT C Secure Coding Section 12 - Error Handling (ERR)
Definition in a New Window
Category ID: 746 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the error
handling section of the CERT C Secure Coding Standard. Since not all rules map
to specific weaknesses, this category may be incomplete.
CERT C Secure Coding Section 49 - Miscellaneous (MSC)
Definition in a New Window
Category ID: 747 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the
miscellaneous section of the CERT C Secure Coding Standard. Since not all rules
map to specific weaknesses, this category may be incomplete.
Weaknesses in this category are related to rules in the POSIX
section of the CERT C Secure Coding Standard. Since not all rules map to
specific weaknesses, this category may be incomplete.
Sensitive memory is cleared according to the source code, but
compiler optimizations leave the memory untouched when it is not read from
again, aka "dead store removal."
Extended Description
This compiler optimization error occurs when:
1. Secret data are stored in memory.
2. The secret data are scrubbed from memory by overwriting its
contents.
3. The source code is compiled using an optimizing compiler, which
identifies and removes the function that overwrites the contents as a
dead store because the memory is not used subsequently.
Time of Introduction
Implementation
Build and Compilation
Applicable Platforms
Languages
C
C++
Detection Factors
Black Box:
This specific weakness is impossible to detect using black box
methods. While an analyst could examine memory to see that it has not
been scrubbed, an analysis of the executable would not be successful.
This is because the compiler has already removed the relevant code. Only
the source code shows whether the programmer intended to clear the
memory or not, so this weakness is indistinguishable from others.
White Box:
This weakness is only detectable using white box methods (see black
box detection factor). Careful analysis is required to determine if the
code is likely to be removed by the compiler.
Demonstrative Examples
Example 1
The following code reads a password from the user, uses the password
to connect to a back-end mainframe and then attempts to scrub the password
from memory using memset().
(Bad Code)
C
void GetData(char *MFAddr) {
char pwd[64];
if (GetPasswordFromUser(pwd, sizeof(pwd))) {
if (ConnectToMainframe(MFAddr, pwd)) {
// Interaction with mainframe
}
}
memset(pwd, 0, sizeof(pwd));
}
The code in the example will behave correctly if it is executed
verbatim, but if the code is compiled using an optimizing compiler, such
as Microsoft Visual C++ .NET or GCC 3.x, then the call to memset() will
be removed as a dead store because the buffer pwd is not used after its
value is overwritten [18]. Because the buffer pwd contains a sensitive
value, the application may be vulnerable to attack if the data are left
memory resident. If attackers are able to access the correct region of
memory, they may use the recovered password to gain control of the
system. It is common practice to overwrite sensitive data manipulated in
memory, such as passwords or cryptographic keys, in order to prevent
attackers from learning system secrets. However, with the advent of
optimizing compilers, programs do not always behave as their source code
alone would suggest. In the example, the compiler interprets the call to
memset() as dead code because the memory being written to is not
subsequently used, despite the fact that there is clearly a security
motivation for the operation to occur. The problem here is that many
compilers, and in fact many programming languages, do not take this and
other security concerns into consideration in their efforts to improve
efficiency. Attackers typically exploit this type of vulnerability by
using a core dump or runtime mechanism to access the memory used by a
particular application and recover the secret information. Once an
attacker has access to the secret information, it is relatively
straightforward to further exploit the system and possibly compromise
other resources with which the application interacts.
Potential Mitigations
Phase
Description
Implementation
Store the sensitive data in a "volatile" memory location if
available.
Build and Compilation
If possible, configure your compiler so that it does not remove dead
stores.
Architecture and Design
Where possible, encrypt sensitive data that are used by a software
system.
Creation of Temporary File in Directory with Incorrect Permissions
Definition in a New Window
Weakness ID: 379 (Weakness Base)
Status: Incomplete
Description
Description Summary
The software creates a temporary file in a directory whose
permissions allow unintended actors to determine the file's existence or
otherwise access that file.
Extended Description
On some operating systems, the fact that the temporary file exists may be
apparent to any user with sufficient privileges to access that directory.
Since the file is visible, the application that is using the temporary file
could be known. If one has access to list the processes on the system, the
attacker has gained information about what the user is doing at that time.
By correlating this with the applications the user is running, an attacker
could potentially discover what a user's actions are. From this, higher
levels of security could be breached.
Time of Introduction
Architecture and Design
Implementation
Applicable Platforms
Languages
All
Common Consequences
Scope
Effect
Confidentiality
Since the file is visible and the application which is using the temp
file could be known, the attacker has gained information about what the
user is doing at that time.
Likelihood of Exploit
Low
Demonstrative Examples
Example 1
(Bad Code)
C and C++
FILE *stream; char tempstring[] = "String to be written";
if( (stream = tmpfile()) == NULL ) {
perror("Could not open new temporary file\n");
return (-1);
}
/* write data to tmp file */
/* ... */
_rmtmp();
In cygwin and some older unixes one can ls /tmp and see that this temp
file exists.
The software contains dead code, which can never be
executed.
Extended Description
Dead code is source code that can never be executed in a running program.
The surrounding code makes it impossible for a section of code to ever be
executed.
Time of Introduction
Implementation
Common Consequences
Scope
Effect
Other
Dead code can lead to confusion during code maintenance and result in
unrepaired vulnerabilities.
Demonstrative Examples
Example 1
The condition for the second if statement is impossible to satisfy.
It requires that the variables be non-null, while on the only path where s
can be assigned a non-null value there is a return statement.
(Bad Code)
C++
String s = null;
if (b) {
s = "Yes";
return;
}
if (s != null) {
Dead();
}
Example 2
In the following class, two private methods call each other, but
since neither one is ever invoked from anywhere else, they are both dead
code.
(Bad Code)
Java
public class DoubleDead {
private void doTweedledee() {
doTweedledumb();
}
private void doTweedledumb() {
doTweedledee();
}
public static void main(String[] args) {
System.out.println("running DoubleDead");
}
}
(In this case it is a good thing that the methods are dead: invoking
either one would cause an infinite loop.)
Example 3
The field named glue is not used in the following class. The author
of the class has accidentally put quotes around the field name, transforming
it into a string constant.
(Bad Code)
Java
public class Dead {
String glue;
public String getGlue() {
return "glue";
}
}
Potential Mitigations
Phase
Description
Remove dead code before deploying the application.
This weakness typically occurs when an unexpected value is provided to the
product, or if an error occurs that is not properly detected. It frequently
occurs in calculations involving physical dimensions such as size, length,
width, and height.
Time of Introduction
Implementation
Common Consequences
Scope
Effect
Availability
A Divide by Zero results in a crash.
Likelihood of Exploit
Medium
Demonstrative Examples
Example 1
The following Java example contains a function to compute an average
but does not validate that the input value used as the denominator is not
zero. This will create an exception for attempting to divide by zero. If
this error is not handled by Java exception handling, unexpected results can
occur.
(Bad Code)
Java
public int computeAverageResponseTime (int totalTime, int
numRequests) {
return totalTime / numRequests;
}
By validating the input value used as the denominator the following
code will ensure that a divide by zero error will not cause unexpected
results. The following Java code example will validate the input value,
output an error message, and throw an exception.
(Good Code)
public int computeAverageResponseTime (int totalTime, int
numRequests) throws ArithmeticException {
if (numRequests == 0) {
System.out.println("Division by zero attempted!");
throw ArithmeticException;
}
return totalTime / numRequests;
}
Example 2
The following C/C++ example contains a function that divides two
numeric values without verifying that the input value used as the
denominator is not zero. This will create an error for attempting to divide
by zero, if this error is not caught by the error handling capabilities of
the language, unexpected results can occur.
(Bad Code)
C and C++
double divide(double x, double y){
return x/y;
}
By validating the input value used as the denominator the following
code will ensure that a divide by zero error will not cause unexpected
results. If the method is called and a zero is passed as the second
argument a DivideByZero error will be thrown and should be caught by the
calling block with an output message indicating the error.
The following C# example contains a function that divides two
numeric values without verifying that the input value used as the
denominator is not zero. This will create an error for attempting to divide
by zero, if this error is not caught by the error handling capabilities of
the language, unexpected results can occur.
(Bad Code)
C#
int Division(int x, int y){
return (x / y);
}
The method can be modified to raise, catch and handle the
DivideByZeroException if the input value used as the denominator is
zero.
(Good Code)
int SafeDivision(int x, int y){
try{
return (x / y);
}
catch (System.DivideByZeroException dbz){
System.Console.WriteLine("Division by zero
attempted!");
The product calls free() twice on the same memory address,
potentially leading to modification of unexpected memory
locations.
Extended Description
When a program calls free() twice with the same argument, the program's
memory management data structures become corrupted. This corruption can
cause the program to crash or, in some circumstances, cause two later calls
to malloc() to return the same pointer. If malloc() returns the same value
twice and the program later gives the attacker control over the data that is
written into this doubly-allocated memory, the program becomes vulnerable to
a buffer overflow attack.
Alternate Terms
Double-free
Time of Introduction
Architecture and Design
Implementation
Applicable Platforms
Languages
C
C++
Common Consequences
Scope
Effect
Access Control
Doubly freeing memory may result in a write-what-where condition,
allowing an attacker to execute arbitrary code.
Likelihood of Exploit
Low to Medium
Demonstrative Examples
Example 1
The following code shows a simple example of a double free
vulnerability.
(Bad Code)
C
char* ptr = (char*)malloc (SIZE);
...
if (abrt) {
free(ptr);
}
...
free(ptr);
Double free vulnerabilities have two common (and sometimes
overlapping) causes:
Error conditions and other exceptional circumstances
Confusion over which part of the program is responsible for
freeing the memory
Although some double free vulnerabilities are not much more
complicated than the previous example, most are spread out across
hundreds of lines of code or even different files. Programmers seem
particularly susceptible to freeing global variables more than
once.
Example 2
While contrived, this code should be exploitable on Linux
distributions which do not ship with heap-chunk check summing turned
on.
Choose a language that provides automatic memory management.
Implementation
Ensure that each allocation is freed only once. After freeing a chunk,
set the pointer to NULL to ensure the pointer cannot be freed again. In
complicated error conditions, be sure that clean-up routines respect the
state of allocation properly. If the language is object oriented, ensure
that object destructors delete each chunk of memory only once.
Implementation
Use a static analysis tool to find double free instances.
This is usually resultant from another weakness, such as an unhandled
error or race condition between threads. It could also be primary to
weaknesses such as buffer overflows.
Affected Resources
Memory
Taxonomy Mappings
Mapped Taxonomy Name
Node ID
Fit
Mapped Node Name
PLOVER
DFREE - Double-Free Vulnerability
7 Pernicious Kingdoms
Double Free
CLASP
Doubly freeing memory
CERT C Secure Coding
MEM00-C
Allocate and free memory in the same module, at the same level
of abstraction
CERT C Secure Coding
MEM01-C
Store a new value in pointers immediately after
free()
CERT C Secure Coding
MEM31-C
Free dynamically allocated memory exactly
once
White Box Definitions
A weakness where code path has:
1. start statement that relinquishes a dynamically allocated memory
resource
2. end statement that relinquishes the dynamically allocated memory
resource
Maintenance Notes
It could be argued that Double Free would be most appropriately located as
a child of "Use after Free", but "Use" and "Release" are considered to be
distinct operations within vulnerability theory, therefore this is more
accurately "Release of a Resource after Expiration or Release", which
doesn't exist yet.
Content History
Submissions
Submission Date
Submitter
Organization
Source
PLOVER
Externally Mined
Modifications
Modification Date
Modifier
Organization
Source
2008-07-01
Eric Dalci
Cigital
External
updated Potential Mitigations,
Time of Introduction
2008-08-01
KDM Analytics
External
added/updated white box definitions
2008-09-08
CWE Content Team
MITRE
Internal
updated Applicable Platforms, Common Consequences,
Description, Maintenance Notes, Relationships, Other Notes,
Relationship Notes, Taxonomy Mappings
Duplicate keys in associative lists can lead to non-unique keys
being mistaken for an error.
Extended Description
A duplicate key entry -- if the alist is designed properly -- could be
used as a constant time replace function. However, duplicate key entries
could be inserted by mistake. Because of this ambiguity, duplicate key
entries in an association list are not recommended and should not be
allowed.
Time of Introduction
Architecture and Design
Implementation
Applicable Platforms
Languages
C
C++
Java
.NET
Likelihood of Exploit
Low
Demonstrative Examples
Example 1
The following code adds data to a list and then attempts to sort the
data.
(Bad Code)
alist = []
while (foo()): #now assume there is a string data with a key
basename
queue.append(basename,data)
queue.sort()
Since basename is not necessarily unique, this may not sort how one
would like it to be.
Potential Mitigations
Phase
Description
Architecture and Design
Use a hash table instead of an alist.
Architecture and Design
Use an alist which checks the uniqueness of hash keys with each entry
before inserting the entry.
This weakness is probably closely associated with other issues related to
doubling, such as CWE-462 (duplicate key in alist) or CWE-102 (Struts
duplicate validation forms). It's usually a case of an API contract
violation (CWE-227).
Relevant Properties
Uniqueness
Taxonomy Mappings
Mapped Taxonomy Name
Node ID
Fit
Mapped Node Name
CERT C Secure Coding
FIO31-C
Do not simultaneously open the same file multiple
times
The software contains an expression that will always evaluate
to false.
Time of Introduction
Implementation
Applicable Platforms
Languages
All
Demonstrative Examples
Example 1
In the following Java example the updateUserAccountOrder() method
used within an e-business product ordering/inventory application will
validate the product number that was ordered and the user account number. If
they are valid, the method will update the product inventory, the user
account, and the user order appropriately.
(Bad Code)
Java
public void updateUserAccountOrder(String productNumber, String
accountNumber) {
boolean isValidProduct = false;
boolean isValidAccount = false;
if (validProductNumber(productNumber)) {
isValidProduct = true;
updateInventory(productNumber);
}
else {
return;
}
if (validAccountNumber(accountNumber)) {
isValidProduct = true;
updateAccount(accountNumber, productNumber);
}
if (isValidProduct && isValidAccount) {
updateAccountOrder(accountNumber, productNumber);
}
}
However, the method never sets the isValidAccount variable after
initializing it to false so the isValidProduct is mistakenly used twice.
The result is that the expression "isValidProduct &&
isValidAccount" will always evaluate to false, so the
updateAccountOrder() method will never be invoked. This will create
serious problems with the product ordering application since the user
account and inventory databases will be updated but the order will not
be updated.
This can be easily corrected by updating the appropriate
variable.
(Good Code)
...
if (validAccountNumber(accountNumber)) {
isValidAccount = true;
updateAccount(accountNumber, productNumber);
}
...
Example 2
In the following example, the hasReadWriteAccess method uses bit
masks and bit operators to determine if a user has read and write privileges
for a particular process. The variable mask is defined as a bit mask from
the BIT_READ and BIT_WRITE constants that have been defined. The variable
mask is used within the predicate of the hasReadWriteAccess method to
determine if the userMask input parameter has the read and write bits set.
(Bad Code)
#define BIT_READ 0x0001 // 00000001
#define BIT_WRITE 0x0010 // 00010000
unsigned int mask = BIT_READ & BIT_WRITE; /* intended to
use "|" */
// using "&", mask = 00000000
// using "|", mask = 00010001
// determine if user has read and write access
int hasReadWriteAccess(unsigned int userMask) {
// if the userMask has read and write bits set
// then return 1 (true)
if (userMask & mask) {
return 1;
}
// otherwise return 0 (false)
return 0;
}
However the bit operator used to initialize the mask variable is the
AND operator rather than the intended OR operator (CWE-480), this
resulted in the variable mask being set to 0. As a result, the if
statement will always evaluate to false and never get executed.
The use of bit masks, bit operators and bitwise operations on
variables can be difficult. If possible, try to use frameworks or
libraries that provide appropriate functionality and abstract the
implementation.
Example 3
In the following example, the updateInventory method used within an
e-business inventory application will update the inventory for a particular
product. This method includes an if statement with an expression that will
always evaluate to false. This is a common practice in C/C++ to introduce
debugging statements quickly by simply changing the expression to evaluate
to true and then removing those debugging statements by changing expression
to evaluate to false. This is also a common practice for disabling features
no longer needed.
(Bad Code)
int updateInventory(char* productNumber, int numberOfItems)
{
int initCount = getProductCount(productNumber);
int updatedCount = initCount + numberOfItems;
int updated = updateProductCount(updatedCount);
// if statement for debugging purposes only
if (1 == 0) {
char productName[128];
productName = getProductName(productNumber);
printf("product %s initially has %d items in inventory
\n", productName, initCount);
printf("adding %d items to inventory for %s \n",
numberOfItems, productName);
if (updated == 0) {
printf("Inventory updated for product %s to %d items
\n", productName, updatedCount);
}
else {
printf("Inventory not updated for product: %s \n",
productName);
}
}
return updated;
}
Using this practice for introducing debugging statements or disabling
features creates dead code that can cause problems during code
maintenance and potentially introduce vulnerabilities. To avoid using
expressions that evaluate to false for debugging purposes a logging API
or debugging API should be used for the output of debugging
messages.
Potential Mitigations
Phase
Description
Testing
Use Static Analysis tools to spot such conditions.
The software contains an expression that will always evaluate
to true.
Time of Introduction
Implementation
Applicable Platforms
Languages
All
Demonstrative Examples
Example 1
In the following Java example the updateInventory() method used
within an e-business product ordering/inventory application will check if
the input product number is in the store or in the warehouse. If the product
is found, the method will update the store or warehouse database as well as
the aggregate product database. If the product is not found, the method
intends to do some special processing without updating any database.
(Bad Code)
Java
public void updateInventory(String productNumber) {
boolean isProductAvailable = false;
boolean isDelayed = false;
if (productInStore(productNumber)) {
isProductAvailable = true;
updateInStoreDatabase(productNumber);
}
else if (productInWarehouse(productNumber)) {
isProductAvailable = true;
updateInWarehouseDatabase(productNumber);
}
else {
isProductAvailable = true;
}
if ( isProductAvailable ) {
updateProductDatabase(productNumber);
}
else if ( isDelayed ) {
/* Warn customer about delay before order processing
*/
...
}
}
However, the method never sets the isDelayed variable and instead will
always update the isProductAvailable variable to true. The result is
that the predicate testing the isProductAvailable boolean will always
evaluate to true and therefore always update the product database.
Further, since the isDelayed variable is initialized to false and never
changed, the expression always evaluates to false and the customer will
never be warned of a delay on their product.
Potential Mitigations
Phase
Description
Testing
Use Static Analysis tools to spot such conditions.
Failure to Clear Heap Memory Before Release ('Heap Inspection')
Definition in a New Window
Weakness ID: 244 (Weakness Variant)
Status: Draft
Description
Description Summary
Using realloc() to resize buffers that store sensitive
information can leave the sensitive information exposed to attack, because it is
not removed from memory.
Extended Description
When sensitive data such as a password or an encryption key is not removed
from memory, it could be exposed to an attacker using a "heap inspection"
attack that reads the sensitive data using memory dumps or other methods.
The realloc() function is commonly used to increase the size of a block of
allocated memory. This operation often requires copying the contents of the
old memory block into a new and larger block. This operation leaves the
contents of the original block intact but inaccessible to the program,
preventing the program from being able to scrub sensitive data from memory.
If an attacker can later examine the contents of a memory dump, the
sensitive data could be exposed.
Time of Introduction
Implementation
Applicable Platforms
Languages
C
C++
Common Consequences
Scope
Effect
Confidentiality
Be careful using vfork() and fork() in security sensitive code. The
process state will not be cleaned up and will contain traces of data
from past use.
Demonstrative Examples
Example 1
The following code calls realloc() on a buffer containing sensitive
data:
There is an attempt to scrub the sensitive data from memory, but
realloc() is used, so a copy of the data can still be exposed in the
memory originally allocated for cleartext_buffer.
Failure to Constrain 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.
Time of Introduction
Architecture and Design
Implementation
Operation
Applicable Platforms
Languages
C: (Often)
C++: (Often)
All
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
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.
Availability
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
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
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)
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_supply_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.
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
Description
Requirements
Use a language with features that can automatically mitigate or
eliminate buffer overflows.
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.
Architecture and Design
Use languages, libraries, or frameworks that make it easier to manage
buffers without exceeding their boundaries.
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.
Build and Compilation
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.
This is not necessarily a complete solution, since these mechanisms
can only detect certain types of overflows. In addition, a buffer
overflow attack can still cause a denial of service, since the typical
response is to exit the application.
Implementation
Programmers should adhere to the following rules when allocating and
managing their 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 calling this function 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.
Testing
Use automated static analysis tools that target this type of weakness.
Many modern techniques use data flow analysis to minimize the number of
false positives. This is not a perfect solution, since 100% accuracy and
coverage are not feasible.
Testing
Use 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.
Operation
Use a feature like Address Space Layout Randomization (ASLR). This is
not a complete solution. However, it forces the attacker to guess an
unknown value that changes every program execution.
Operation
Use a CPU and operating system that offers Data Execution Protection
(NX) or its equivalent. 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.
The software does not properly handle when an input contains
Unicode encoding.
Time of Introduction
Implementation
Applicable Platforms
Languages
All
Demonstrative Examples
Example 1
Windows provides the MultiByteToWideChar(), WideCharToMultiByte(),
UnicodeToBytes(), and BytesToUnicode() functions to convert between
arbitrary multibyte (usually ANSI) character strings and Unicode (wide
character) strings. The size arguments to these functions are specified in
different units, (one in bytes, the other in characters) making their use
prone to error.
In a multibyte character string, each character occupies a varying
number of bytes, and therefore the size of such strings is most easily
specified as a total number of bytes. In Unicode, however, characters
are always a fixed size, and string lengths are typically given by the
number of characters they contain. Mistakenly specifying the wrong units
in a size argument can lead to a buffer overflow.
The following function takes a username specified as a multibyte
string and a pointer to a structure for user information and populates
the structure with information about the specified user. Since Windows
authentication uses Unicode for usernames, the username argument is
first converted from a multibyte string to a Unicode string.
This function incorrectly passes the size of unicodeUser in bytes
instead of characters. The call to MultiByteToWideChar() can therefore
write up to (UNLEN+1)*sizeof(WCHAR) wide characters, or
(UNLEN+1)*sizeof(WCHAR)*sizeof(WCHAR) bytes, to the unicodeUser array,
which has only (UNLEN+1)*sizeof(WCHAR) bytes allocated.
If the username string contains more than UNLEN characters, the call
to MultiByteToWideChar() will overflow the buffer unicodeUser.
Avoid making decisions based on names of resources (e.g. files) if
those resources can have alternate names.
Architecture and Design
Assume all input is malicious. Use a standard input validation
mechanism to validate all input for length, type, syntax, and business
rules before accepting the data to be displayed or stored. Use an
"accept known good" validation strategy.
Use and specify a strong output encoding (such as ISO 8859-1 or UTF
8).
Do not rely exclusively on blacklist validation to detect malicious
input or to encode output. There are too many variants to encode a
character; you're likely to miss some variants.
Inputs should be decoded and canonicalized to the application's
current internal representation before being validated. Make sure that
your application does not decode the same input twice. Such errors could
be used to bypass whitelist schemes by introducing dangerous inputs
after they have been checked.
The code does not function according to its published
specifications, potentially leading to incorrect usage.
Extended Description
When providing functionality to an external party, it is important that
the software behaves in accordance with the details specified. Failing to
document requirements or nuances can result in unintended behaviors for the
caller, possibly leading to an exploitable state.