C99 defines the fwrite()
function as follows [ISO/IEC 9899:1999]:
size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
The
fwrite()
function shall write, from the array pointed to byptr
, up tonitems
elements whose size is specified bysize
, to the stream pointed to bystream
. For each object,size
calls shall be made to thefputc()
function, taking the values (in order) from an array of unsigned char exactly overlaying the object. The file-position indicator for the stream (if defined) shall be advanced by the number of bytes successfully written. If an error occurs, the resulting value of the file-position indicator for the stream is unspecified.
The definition does not state that the fwrite()
function will stop copying characters into the file if a null character is encountered. Therefore, when writing a null-terminated byte string to a file using the fwrite()
function, always use the length of the string plus 1 (to account for the null character) as the nitems
parameter.
Noncompliant Code Example
In this noncompliant code example, the size of the buffer is stored in size1
, but size2
number of characters are written in to the file. If size2
is greater than size1
, write()
will not stop copying characters at the null character.
#include <stdio.h> char *buffer = NULL; size_t size1, size2; FILE *filedes; /* * Assume size1 and size2 are appropriately initialized */ filedes = fopen("out.txt", "w+"); if (filedes == NULL) { /* Handle error */ } buffer = (char *)calloc( 1, size1); if (buffer == NULL) { /* Handle error */ } fwrite(buffer, 1, size2, filedes); free(buffer); buffer = NULL; fclose(filedes);
Compliant Solution
This compliant solution ensures that the correct number of characters are written to the file.
char *buffer = NULL; size_t size1, size2; FILE *filedes; /* * Assume size1 is appropriately initialized */ filedes = fopen("out.txt", "w+"); if (filedes == NULL){ /* Handle error */ } buffer = (char *)calloc( 1, size1); if (buffer == NULL) { /* Handle error */ } /* * Accept characters in to the buffer * Check for buffer overflow */ size2 = strlen(buffer) + 1; fwrite(buffer, 1, size2, filedes); free(buffer); buffer = NULL; fclose(filedes);
Risk Assessment
Failure to follow the recommendation could result in a non-null-terminated string being written to a file. This will create problems when the program tries to read it back as a null-terminated byte string.
Recommendation |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
FIO18-C |
Medium |
Probable |
Medium |
P8 |
L2 |
Related Guidelines
CERT C++ Secure Coding Standard: FIO18-CPP. Never expect write() to terminate the writing process at a null character
ISO/IEC 9899:1999 Section 7.19.8.2, "The fwrite function"
Bibliography
http://www.opengroup.org/onlinepubs/009695399/functions/fwrite.html
09. Input Output (FIO) FIO19-C. Do not use fseek() and ftell() to compute the size of a file