...
Code Block |
---|
|
char dest[ARRAY_SIZE];
char src[ARRAY_SIZE];
size_t i;
/* ... */
for (i=0; src[i] && (i < sizeof(dest)-1); i++) {
dest[i] = src[i];
}
dest[i] = '\0';
/* ... */
|
Noncompliant Code Example (argv
) (strcpy()
)
Arguments read from the command line are stored in process memory. The function main()
, called at program startup, is typically declared as follows when the program accepts command-line arguments:
...
Code Block |
---|
|
int main(int argc, char *argv[]) {
/* ... */
char prog_name[128];
strcpy(prog_name, argv[0]);
/* ... */
}
|
Compliant Solution (argv
) (strcpy()
)
Wiki Markup |
---|
The {{strlen()}} function can be used to determine the length of the strings referenced by {{argv\[0\]}} through {{argv\[argc-1\]}} so that adequate memory can be dynamically allocated: |
...
The memcpy()
function differs from strcpy_s()
in that it never returns an error. The memcpy()
function returns a pointer to the destination string (that is, its first argument). However, memcpy()
does not validate that the destination pointer has enough space for the memory being copied, and cannot be used if the source and destination strings overlap.
Compliant Solution (argv
)
If an argument is not going to be modified or concatenated, there is no reason to make a copy of the string. Not copying a string is the best way to prevent a buffer overflow, and is also the most efficient solution.
...
Code Block |
---|
|
/* ... */
char buff[256];
char *editor = getenv("EDITOR");
if (editor == NULL) {
/* EDITOR environment variable not set */
} else {
strcpy(buff, editor);
}
/* ... */
|
Compliant Solution (getenv()
)
Environmental variables are loaded into process memory when the program is loaded. As a result, the length of these null-terminated byte strings can be determined by calling the strlen()
function and the resulting length used to allocate adequate dynamic memory:
Code Block |
---|
|
/* ... */
char *buff;
char *editor = getenv("EDITOR");
if (editor == NULL) {
/* EDITOR environment variable not set */
} else {
size_t len = strlen(editor)+1;
buff = (char *)malloc(len);
if (buff == NULL) {
/* Handle malloc() Error */
}
memcpy(buff, editor, len);
}
/* ... */
|
Noncompliant Code Example (sprintf()
)
In this example, name
refers to an external string; it could have originated from user input, or from the file system, or from the network. The program constructs a filename from the string in preparation for opening the file.
Code Block |
---|
|
char* name; /* initialized externally */
char filename[128];
sprintf( filename, "%s.txt", name);
/* open filename * /
|
However, since the sprintf
function makes no guarantees regarding the length of the string generated, a sufficiently-long string in name
could generate a buffer overflow.
Compliant Solution (sprintf()
)
The buffer overflow can be prevented by providing a precision length to the %s
specifier. The value 123 ensures that filename can contain the first 123 characters of name
, the ".txt" extension, and the null terminator.
Code Block |
---|
|
char* name; /* initialized externally */
char filename[128];
sprintf( filename, "%.123s.txt", name);
/* open filename * /
|
Compliant Solution (snprintf()
)
A more general solution is to use the snprintf()
function.
Code Block |
---|
|
char* name; /* initialized externally */
char filename[128];
snprintf( filename, sizeof( filename), "%s.txt", name);
/* open filename * /
|
Risk Assessment
Copying NTBS data to a buffer that is too small to hold that data results in a buffer overflow. Attackers can exploit this condition to execute arbitrary code with the permissions of the vulnerable process.
...