...
Code Block |
---|
|
size_t utf8_to_ucs(wchar_t *ucs, size_t n, const char *utf8) {
setlocale(LC_CTYPE, "en_US.UTF-8");
return mbstowcs(ucs, utf8, n);
}
|
...
Code Block |
---|
|
size_t utf8_to_ucs(wchar_t *ucs, size_t n, const char *utf8) {
const char *save;
save = setlocale(LC_CTYPE, "en_US.UTF-8");
if (NULL == save) {
/* Propagate error to caller */
return (size_t)-1;
}
n = mbstowcs(ucs, utf8, n);
if (NULL == setlocale(LC_CTYPE, save))
n = -1;
return n;
}
|
...
Code Block |
---|
|
volatile sig_atomic_t interrupted;
void handle_interrupt(int signo) {
interrupted = 1;
}
int f() {
int result = 0;
signal(SIGINT, handle_interrupt);
while (0 == result && 0 == interrupted) {
/* Perform a lengthy computation */
}
/* Indicate success or failure */
return interrupted ? -1 : result;
}
|
...
Code Block |
---|
|
volatile sig_atomic_t interrupted;
void handle_interrupt(int signo) {
interrupted = 1;
}
int f() {
int result = 0;
void (*saved_handler)(int);
saved_handler = signal(SIGINT, handle_interrupt);
if (SIG_ERR == saved_handler) {
/* Indicate failure */
return -1;
}
while (0 == result && 0 == interrupted) {
/* Perform a lengthy computation */
}
if (SIG_ERR == signal(SIGINT, saved_handler))
return -1;
/* Indicate success or failure */
return interrupted ? -1 : result;
}
|
...
In this noncompliant code example, temp_num
, tmp2
, andnum_of_records
are under the control of a malicious user. The attacker can easily cause malloc()
to fail by providing a large value for num_of_records
.
Code Block |
---|
|
signal_info * start = malloc(num_of_records * sizeof(signal_info));
signal_info * point = (signal_info *)start;
point = start + temp_num - 1;
memcpy(point->sig_desc, tmp2, strlen(tmp2));
/* ... */ |
When malloc()
fails, it returns a null pointer that is assigned to start
. If start
is a null, an attacker can provide a value for temp_num
that when scaled by the the sizeof signal_info
references a writable address to which control is eventually transferred. The contents of the string referenced by tmp2
can then be used to overwrite the address resulting in an arbitrary code execution vulnerability.
Compliant Solution (malloc()
)
To correct this error, ensure the pointer returned by malloc()
is not null. This also ensures compliance with rule MEM32-C. Detect and handle memory allocation errors.
Code Block |
---|
|
signal_info * start = malloc(num_of_records * sizeof(signal_info));
if (start == NULL) {
/* Handle Allocation Error */
}
signal_info * point = (signal_info *)start;
point = start + temp_num - 1;
memcpy(point->sig_desc, tmp2, strlen(tmp2));
/* ... */
|
Noncompliant Code Example (malloc()
)
In this noncompliant code example, input_string
is copied into dynamically allocated memory referenced by str
. However, the result of malloc()
is not checked before str
is referenced. Consequently, if malloc()
fails, the program has undefined behavior. (See undefined behavior 103 in Annex J.) In practice, this typically leads to an abnormal termination of the process, thus providing an opportunity for a denial-of-service attack. In some cases, it may be the source of other vulnerabilities, as well. (See the #Related Vulnerabilities section.)
...
Code Block |
---|
|
void f(char *input_string) {
size_t size = strlen(input_string) + 1;
char *str = (char *)malloc(size);
strcpy(str, input_string);
/* ... */
}
|
Compliant Solution (malloc()
)
The malloc()
function, as well as the other memory allocation functions, returns either a null pointer or a pointer to the allocated space. Always test the returned pointer to ensure it is not NULL
before referencing the pointer. Handle the error condition appropriately when the returned pointer is NULL
. When recovery from the allocation failure isn't possible, propagate the failure to the caller.
Code Block |
---|
|
int f(char *input_string) {
size_t size = strlen(input_string) + 1;
char *str = (char *)malloc(size);
if (str == NULL) {
/* Handle allocation failure and return error status */
return -1;
}
strcpy(str, input_string);
/* ... */
free(str);
return 0;
}
|
...