...
Code Block | ||||
---|---|---|---|---|
| ||||
error_status_t _RemoteActivation( /* ... */, WCHAR *pwszObjectName, ... ) { *phr = GetServerPath( pwszObjectName, &pwszObjectName); /* ... */ } HRESULT GetServerPath( WCHAR *pwszPath, WCHAR **pwszServerPath ){ WCHAR *pwszFinalPath = pwszPath; WCHAR wszMachineName[MAX_COMPUTERNAME_LENGTH_FQDN+1]; hr = GetMachineName(pwszPath, wszMachineName); *pwszServerPath = pwszFinalPath; } HRESULT GetMachineName( WCHAR *pwszPath, WCHAR wszMachineName[MAX_COMPUTERNAME_LENGTH_FQDN+1]) { pwszServerName = wszMachineName; LPWSTR pwszTemp = pwszPath + 2; while ( *pwszTemp != L'\\' ) *pwszServerName++ = *pwszTemp++; /* ... */ } |
...
Noncompliant Code Example (Using Past the End Index)
Similarly Similar to the dereferencing-past-the-end-pointer error, the function insert_in_table()
in this noncompliant code example uses an otherwise valid index to attempt to store a value in an element just past the end of an array.
...
Code Block | ||||
---|---|---|---|---|
| ||||
static const size_t COLS = 5;
static const size_t ROWS = 7;
static int matrix[ROWS][COLS];
void init_matrix(int x) {
for (size_t i = 0; i < COLS; i++) {
for (size_t j = 0; j < ROWS; j++) {
matrix[i][j] = x;
}
}
}
|
...
Code Block | ||||
---|---|---|---|---|
| ||||
static const size_t COLS = 5;
static const size_t ROWS = 7;
static int matrix[ROWS][COLS];
void init_matrix(int x) {
for (size_t i = 0; i < ROWS; i++) {
for (size_t j = 0; j < COLS; j++) {
matrix[i][j] = x;
}
}
}
|
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> struct S { size_t len; char buf[]; /* Flexible array member */ }; const char *find(const struct S *s, int c) { const char *first = s->buf; const char *last = s->buf + s->len; while (first != last) { /* Avoid incrementing here */ if (*++first == (unsigned char)c) { return first; } } return NULL; } void g(void) { struct S *s = (struct S *)malloc(sizeof(struct S)); if (s == NULL) { /* handle error */ } s->len = 0; find(s, 'a'); } |
Noncompliant Code Example (
...
Null Pointer Arithmetic)
The following noncompliant code example is similar to a vulnerability in an Adobe Flash player Player vulnerability that was first exploited in 2008. (See http://www.iss.net/threats/289. html for more information). This code allocates a block of memory, and initializes it with some data. The data does not belong at the beginning of the block, which is left uninitialized. Instead, it is placed offset
bytes within the block. The function ensures that the data fits within the allocated block.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> char* init_block(size_t block_size, size_t offset, char * data, size_t data_size) { char* buffer = malloc(block_size); if (data_size > block_size || block_size - data_size > offset) { /* data won't fit in buffer, handle error */ } memcpy( buffer + offset, data, data_size); return buffer; } |
This function fails to check if the allocation succeeds. If ; a violation of ERR33-C. Detect and handle standard library errors. If the allocation fails, then malloc()
returns a null pointer. The call to memcpy()
does not dereference this pointer, but instead performs pointer arithmetic on it and tries adds this pointer to offset
and attempts to write to through the resulting pointer. Because a null pointer does not point into to a valid memoryobject, the results are undefined.
By not checking if malloc()
succeeds, this code also violates ERR33-C. Detect and handle standard library errors.
An attacker that can use supply the arguments to this function can exploit it to write to execute arbitrary memory. They pass a large value to block_size
, such as SIZE_MAX
...such a large size usually causes code. This can be accomplished by providing a sufficiently large value for block_size
to cause malloc()
to fail . They then convert an address of memory they wish to overwrite to a size_t
integer, and pass it as the offset
parameter. They then set data
and data_size
to refer correctly to memory containing the data they wish and return a null pointer. The offset
argument will then serve as the destination address to the call to memcpy()
. The data
and data_size
arguments can provide the address and length of the address respectively that the the attacker wishes to write into the memory indicated referenced by offset
. Consequently, the call to memcpy()
happily writes the memory of their choice.
...
can overwrite an address with an attacker supplied address; typically resulting in arbitrary code execution.
Compliant Solution (Null Pointer Arithmetic)
This compliant solution also checks ensures that the call to malloc()
succeeds.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> char* init_block(size_t block_size, size_t offset, char* data, size_t data_size) { char* buffer = malloc(block_size); if (NULL == buffer) { /* handle error */ } if (data_size > block_size || block_size - data_size > offset) { /* data won't fit in buffer, handle error */ } memcpy( buffer + offset, data, data_size); return buffer; } |
...