157 lines
4.4 KiB
Plaintext
157 lines
4.4 KiB
Plaintext
Passing invalid arguments to standard C library functions for handling I/O streams results in undefined behavior.
|
|
|
|
== Why is this an issue?
|
|
|
|
The standard C library includes a number of functions for handling I/O streams.
|
|
These functions put certain constraints on the values of their parameters.
|
|
The constraints include the following:
|
|
|
|
* The value for the ``++FILE*++``-typed parameter may _not_ be ``++NULL++``
|
|
* The third argument of ``++fseek++`` must be either of ``++SEEK_SET++``, ``++SEEK_END++``, or ``++SEEK_CUR++``
|
|
|
|
Failing to pass correctly constrained parameters renders them invalid and will result in undefined behavior.
|
|
|
|
[source,cpp]
|
|
----
|
|
#include <stdio.h>
|
|
|
|
size_t get_file_size() {
|
|
FILE *f = fopen("example_file.txt", "r");
|
|
// `f` may be NULL if `fopen` fails.
|
|
fseek(f, 0L, SEEK_END); // Leads to undefined behavior, if `f` is NULL.
|
|
size_t size = ftell(f); // Leads to undefined behavior, if `f` is NULL.
|
|
fclose(f);
|
|
return size;
|
|
}
|
|
----
|
|
|
|
|
|
== What is the potential impact?
|
|
|
|
Using the standard C library's functions for handling I/O streams with invalid arguments leads to *undefined behavior*.
|
|
|
|
When a program comprises undefined behavior, the compiler no longer needs to adhere to the language standard, and the program has no meaning assigned to it.
|
|
|
|
Due to the resulting NULL pointer dereferences in the C library functions, the application might just crash, but in the worst case, the application may appear to execute correctly, while losing data or producing incorrect results.
|
|
|
|
Besides affecting the application's availability, NULL pointer dereferences may lead to code execution, in rare circumstances.
|
|
If NULL is equivalent to the 0x0 memory address that can be accessed by privileged code, writing and reading memory is possible, which compromises the integrity and confidentiality of the application.
|
|
|
|
|
|
== How to fix it
|
|
|
|
Ensure that the ``++FILE*++``-typed pointer parameters passed to the standard C library's I/O stream handling functions are non-``++NULL++`` and also any other parameters such as the third argument of ``++fseek++`` carry appropriate values, namely any of ``++SEEK_SET++``, ``++SEEK_END++``, or ``++SEEK_CUR++``.
|
|
|
|
|
|
=== Code examples
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,cpp,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
int process_file(const char *fname) {
|
|
FILE *f = fopen(fname, "r");
|
|
fseek(f, 0L, SEEK_END);
|
|
size_t size = ftell(f);
|
|
rewind(f);
|
|
char *buf = (char *)malloc(size);
|
|
// Read file into buffer ...
|
|
fclose(f);
|
|
// Process buffer ...
|
|
free(buf);
|
|
return 0;
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,cpp,diff-id=1,diff-type=compliant]
|
|
----
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
int process_file(const char *fname) {
|
|
FILE *f = fopen(fname, "r");
|
|
if (!f) {
|
|
printf("Could not open file!\n");
|
|
return 1;
|
|
}
|
|
fseek(f, 0L, SEEK_END);
|
|
size_t size = ftell(f);
|
|
rewind(f);
|
|
char *buf = (char *)malloc(size);
|
|
// Read file into buffer ...
|
|
fclose(f);
|
|
// Process buffer ...
|
|
free(buf);
|
|
return 0;
|
|
}
|
|
----
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,cpp,diff-id=2,diff-type=noncompliant]
|
|
----
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
void process_tmp_file() {
|
|
FILE *f = tmpfile();
|
|
size_t pos_indicator = ftell(f); // Noncompliant: `f` could be NULL.
|
|
fseek(f, 0L, 3); // Noncompliant: 3rd argument should either be SEEK_SET, SEEK_CUR or SEEK_END.
|
|
// Further file processing ...
|
|
fclose(f);
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,cpp,diff-id=2,diff-type=compliant]
|
|
----
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
int process_tmp_file() {
|
|
FILE *f = tmpfile();
|
|
if (!f) {
|
|
printf("Could not create temporary file!\n");
|
|
return 1;
|
|
}
|
|
size_t pos_indicator = ftell(f); // Compliant: `f` cannot be NULL here.
|
|
fseek(f, 0L, SEEK_END); // Compliant: 3rd argument is now a valid value.
|
|
// Further file processing ...
|
|
fclose(f);
|
|
return 0;
|
|
}
|
|
----
|
|
|
|
|
|
== Resources
|
|
|
|
=== Standards
|
|
|
|
* CWE - https://cwe.mitre.org/data/definitions/476[CWE-476 NULL Pointer Dereference]
|
|
|
|
=== Related rules
|
|
|
|
* S3807 ensures that appropriate arguments are passed to C standard library functions
|
|
* S5488 ensures that appropriate arguments are passed to UNIX/POSIX functions
|
|
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
'''
|
|
== Comments And Links
|
|
(visible only on this page)
|
|
|
|
=== is related to: S2095
|
|
|
|
=== is related to: S3588
|
|
|
|
=== on 22 Oct 2019, 16:20:15 Loïc Joly wrote:
|
|
\[~amelie.renard] I heavily reworded this one, can you validate please?
|
|
|
|
endif::env-github,rspecator-view[]
|