...
This indicates that the file position indicator, and consequently file size, is directly based on the number of bytes actually written to a file.
Noncompliant Code Example (Binary File)
This code example attempts to open a binary file in binary mode and use fseek() and ftell() to obtain the file size. This code is noncompliant on systems that do not provide the same guarantees as POSIX. On these systems, setting the file position indicator to the end of the file using fseek() is not guaranteed to work for a binary stream, and consequently, the amount of memory allocated may be incorrect, leading to a potential vulnerability.
| Code Block | ||||
|---|---|---|---|---|
| ||||
FILE *fp;
long file_size;
char *buffer;
fp = fopen("foo.bin", "rb");
if (fp == NULL) {
/* Handle Error */
}
if (fseek(fp, 0 , SEEK_END) != 0) {
/* Handle Error */
}
file_size = ftell(fp);
if (file_size == -1) {
/* Handle Error */
}
buffer = (char*)malloc(file_size);
if (buffer == NULL) {
/* Handle Error */
}
/* ... */
|
Compliant Solution (POSIX)
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 only works with regular files.
| Code Block | ||||
|---|---|---|---|---|
| ||||
FILE *fp;
off_t file_size;
char *buffer;
struct stat st;
fd = open("foo.bin", O_RDONLY);
if (fd == -1) {
/* Handle Error */
}
/* Ensure that the file is a regular file */
if ((fstat(fd, &st) != 0) || (!S_ISREG(st.st_mode))) {
/* Handle Error */
}
if (fseeko(fp, 0 , SEEK_END) != 0) {
/* Handle Error */
}
file_size = ftello(fp);
if (file_size == -1) {
/* Handle Error */
}
buffer = (char*)malloc(file_size);
if (buffer == NULL) {
/* Handle Error */
}
/* ... */
|
Compliant Solution (POSIX fstat())
This compliant solution uses the POSIX fstat() function, rather than fseek() and ftell(), to obtain the size of the binary file. This solution only works with regular files.
| Code Block | ||||
|---|---|---|---|---|
| ||||
FILE *fp;
off_t file_size;
char *buffer;
struct stat stbuf;
int fd;
fd = open("foo.bin", O_RDONLY);
if (fd == -1) {
/* Handle Error */
}
if ((fstat(fd, &st) != 0) || (!S_ISREG(st.st_mode))) {
/* Handle Error */
}
file_size = stbuf.st_size;
buffer = (char*)malloc(file_size);
if (buffer == NULL) {
/* Handle Error */
}
/* ... */
|
Compliant Solution (Windows)
This compliant solution uses the Windows _filelength() function to determine the size of the file.
| Code Block | ||||
|---|---|---|---|---|
| ||||
int fd;
long file_size;
char *buffer;
_sopen_s(&fd, "foo.bin", _O_RDONLY, _SH_DENYRW, _S_IREAD);
if (fd == -1) {
/* Handle Error */
}
file_size = _filelength(fd);
if (file_size == -1) {
/* Handle Error */
}
buffer = (char*)malloc(file_size);
if (buffer == NULL) {
/* Handle Error */
}
/* ... */
|
Noncompliant Code Example (Text File)
This noncompliant code example attempts to open a text file in text mode and use fseek() and ftell() to obtain the file size.
...
Again, this indicates that the return value of ftell() for streams opened in text mode is useful only in calls to fseek() and should not be used for any other purpose.
Compliant Solution (Windows)
The compliant solution used for binary files on Windows can also be used for text files.
Compliant Solution (POSIX)
Because binary files are treated the same as text files in POSIX, you can use either compliant solution for determining the size of a binary file under POSIX to determine the size of a text file as well.
Risk Assessment
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 |
Related Guidelines
ISO/IEC 9899:2011 Section 7.21.9.2, "The fseek function", Section 7.21.3, "Files," and Section 7.21.9.4, "The ftell function"
Bibliography
[MSDN] "ftell"
...