Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Section 7.21.9.2 of the C standard Standard [ISO/IEC 9899:2011] specifies the following behavior for fseek() when opening a binary file in binary mode:

...

Seeking to the end of a binary stream in binary mode with fseek() is not meaningfully supported and , as a result, is not a recommended method for computing the size of a file.

Section 7.21.9.4 of the C standard Standard [ISO/IEC 9899:2011] specifies the following behavior for ftell() when opening a text file in text mode:

...

POSIX [Open Group 2008] provides several guarantees that the problems described in the C standard Standard do not occur on POSIX systems.

...

This indicates that the file position indicator, and consequently the file size, is directly based on the number of bytes actually written to a file.

...

Code Block
bgColor#FFCCCC
langc
FILE *fp;
long file_size;
char *buffer;

fp = fopen("foo.bin", "rb");
if (fp == NULL) {
  /* Handle Errorerror */
}

if (fseek(fp, 0 , SEEK_END) != 0) {
  /* Handle Errorerror */
}

file_size = ftell(fp);
if (file_size == -1) {
  /* Handle Errorerror */
}

buffer = (char*)malloc(file_size);
if (buffer == NULL) {
  /* Handle Errorerror */
}

/* ... */ 

Compliant Solution (POSIX ftello())

If the code needs to handle large files, it is preferable to use fseeko() and ftello() because, for some implementations, they can handle larger file offsets than fseek() and ftell().  If they are used, the file_size variable should have type off_t to avoid the possibility of overflow when assigning the return value of ftello() to it.   This solution works only works with regular files.

Code Block
bgColor#CCCCFF
langc
FILE* fp;
int fd;
off_t file_size;
char *buffer;
struct stat st;
  
fd = open("foo.bin", O_RDONLY);
if (fd == -1) {
  /* Handle Errorerror */
}

fp = fdopen(fd, "r");
if (fp == NULL) {
  /* Handle Errorerror */
}

/* Ensure that the file is a regular file */
if ((fstat(fd, &st) != 0) || (!S_ISREG(st.st_mode))) {
  /* Handle Errorerror */
}
 
if (fseeko(fp, 0 , SEEK_END) != 0) {
  /* Handle Errorerror */
}
  
file_size = ftello(fp);
if (file_size == -1) {
  /* Handle Errorerror */
}
 
buffer = (char*)malloc(file_size);
if (buffer == NULL) {
  /* Handle Errorerror */
}

/* ... */ 

Compliant Solution (POSIX fstat())

This compliant solution uses the size provided by the POSIX fstat() function, rather than by fseek() and ftell(), to obtain the size of the binary file.   This solution works only works with regular files.

Code Block
bgColor#CCCCFF
langc
off_t file_size;
char *buffer;
struct stat stbuf;
int fd;
 
fd = open("foo.bin", O_RDONLY);
if (fd == -1) {
  /* Handle Errorerror */
}
 
if ((fstat(fd, &stbuf) != 0) || (!S_ISREG(stbuf.st_mode))) {
  /* Handle Errorerror */
}
 
file_size = stbuf.st_size;
 
buffer = (char*)malloc(file_size);
if (buffer == NULL) {
  /* Handle Errorerror */
}

/* ... */ 

Compliant Solution (Windows)

...

Code Block
bgColor#CCCCFF
langc
int fd;
long file_size;
char *buffer;

_sopen_s(&fd, "foo.bin", _O_RDONLY, _SH_DENYRW, _S_IREAD);
if (fd == -1) {
  /* Handle Errorerror */
}

file_size = _filelength(fd);
if (file_size == -1) {
  /* Handle Errorerror */
}

buffer = (char*)malloc(file_size);
if (buffer == NULL) {
  /* Handle Errorerror */
}

/* ... */ 

Noncompliant Code Example (Text File)

...

Code Block
bgColor#FFCCCC
langc
FILE *fp;
long file_size;
char *buffer;

fp = fopen("foo.txt", "r");
if (fp == NULL) {
  /* Handle Errorerror */
}

if (fseek(fp, 0 , SEEK_END) != 0) {
  /* Handle Errorerror */
}

file_size = ftell(fp);
if (file_size == -1) {
  /* Handle Errorerror */
}

buffer = (char*)malloc(file_size);
if (buffer == NULL) {
  /* Handle Errorerror */
}

/* ... */ 

However, the file position indicator returned by ftell() with a file opened in text mode is useful only useful in calls to fseek(). As such, the value of file_size may not necessarily be a meaningful measure of the number of characters in the file, and consequently, the amount of memory allocated may be incorrect, leading to a potential vulnerability.

...

Understanding the difference between text mode and binary mode with file streams is critical when working with functions that operate on them. Setting the file position indicator to end-of-file with fseek() has undefined behavior for a binary stream. In addition, the return value of ftell() for streams opened in text mode is useful only in calls to fseek(), not for determining file sizes or for any other use. As such, fstat(), or other platform-equivalent functions , should be used to determine the size of a file.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

FIO19-C

low

unlikely

medium

P2

L3

...

Bibliography

...

]Section 7.21.

...

3, "

...

Files"

...


Section 7.21.

...

9.2, "

...

The fseek Function"
Section 7.21.9.4, "The ftell

...

Function"

Bibliography