CWE-121¶
Stack-based Buffer Overflow. [Improper-Control-Of-A-Resource-Through-Its-Lifetime]
Required inputs: IR, StaticSemanticAnalysis
Background Details Demonstrative Examples
Background Details Demonstrative Examples
Example 1
While buffer overflow examples can be rather complex, it is possible to have very simple, yet still exploitable, stack-based buffer overflows:
Example Language:C
#define BUFSIZE 256
int main(int argc, char **argv) {
char buf[BUFSIZE];
strcpy(buf, argv[1]);
}
The buffer size is fixed, but there is no guarantee the string in argv[1] will not exceed this size and cause an overflow.
Example 2
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.
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 the function 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).
Excerpts from CWE [https://cwe.mitre.org], Copyright (C) 2006-2026, the MITRE Corporation. See section 9.4. "3rd-Party Licenses" in the documentation for full details.Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
arithmetic_out_of_bounds |
Pointer arithmetic on {node0} might create pointer outside array bounds of {name0} |
None |
False |
out_of_bounds |
Access into array is out of bounds |
None |
False |
possible_indirect_out_of_bounds |
Pointer-indirect access through {node0} might be out of bounds accessing {name0} |
None |
False |
possible_out_of_bounds |
Access into array might be out of bounds |
None |
False |
possible_write_beyond_argument |
Call to {} might result in a write access beyond the bounds of argument {}, since argument {} might be too large. |
None |
False |
undereferenced_arithmetic_out_of_bounds |
Pointer arithmetic on {node0} might create pointer one past the end of {name0} (but not dereferenced) |
None |
False |
undereferenced_out_of_bounds |
Access is one past the end of the array (but not dereferenced) |
None |
False |
undereferenced_possible_indirect_out_of_bounds |
Pointer-indirect access through {node0} might be one past the end accessing {name0} (but not dereferenced) |
None |
False |
undereferenced_possible_out_of_bounds |
Access might be one past the end of the array (but not dereferenced) |
None |
False |
Options¶
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
abstract_interpretation_out_of_bounds¶
abstract_interpretation_out_of_bounds : bool = False
concat_operations¶
concat_operations
Names of buffer-concatenating functions being relevant as call targets for this check, with the position of the argument pointing to the destination buffer, and the position of the argument that references the buffer that should be appended at the end of the destination buffer.Type: dict[bauhaus.analysis.config.QualifiedName, typing.Tuple[int, int]]
Default:
{ 'strcat': (0, 1) }
copy_operations¶
copy_operations
Names of buffer copy functions being relevant as call targets for this check, with the position of the destination argument and the source argument of the buffer copy operation.Type: dict[bauhaus.analysis.config.QualifiedName, typing.Tuple[int, int]]
Default:
{ 'strcpy': (0, 1) }
delimiter_of_arguments¶
delimiter_of_arguments
Names of functions being relevant as call targets for this check, with the position of parameters whose referenced buffers should be checked for being properly terminated by a null terminator.Type: dict[bauhaus.analysis.config.QualifiedName, set[int]]
Default:
{ 'strcat': {0, 1}, 'strchr': {0}, 'strcmp': {0, 1}, 'strcoll': {0, 1}, 'strcpy': {1}, 'strcspn': {0, 1}, 'strlen': {0}, 'strpbrk': {0, 1}, 'strrchr': {0}, 'strspn': {0, 1}, 'strstr': {0, 1}, 'strtok': {0, 1} }
exclude_very_high_indices¶
exclude_very_high_indices : bool = True
exclude_warnings_for_unknown_arguments¶
exclude_warnings_for_unknown_arguments : bool = False
ignore_calls_in_functions¶
ignore_calls_in_functions : set[bauhaus.analysis.config.QualifiedName] = set()
report_unbounded_arrays¶
report_unbounded_arrays : bool = False
extern char buf[];.
report_undereferenced_one_past_the_end¶
report_undereferenced_one_past_the_end : bool = False
report_unknown_index¶
report_unknown_index : bool = False