2020-06-30 12:50:28 +02:00
include::../description.adoc[]
2020-12-21 15:38:52 +01:00
== Noncompliant Code Example
2020-06-30 14:49:38 +02:00
2021-01-27 13:42:22 +01:00
A "check function" (for instance ``++access++``, ``++stat++`` ... in this case ``++access++`` to verify the existence of a file) is used, followed by a "use function" (``++open++``, ``++fopen++`` ...) to write data inside a non existing file. These two consecutive calls create a TOCTOU race condition:
2020-06-30 14:49:38 +02:00
----
#include <stdio.h>
2020-12-21 15:38:52 +01:00
void fopen_with_toctou(const char *file) {
if (access(file, F_OK) == -1 && errno == ENOENT) {
2020-06-30 14:49:38 +02:00
// the file doesn't exist
// it is now created in order to write some data inside
2020-12-21 15:38:52 +01:00
FILE *f = fopen(file, "w"); // Noncompliant: a race condition window exist from access() call to fopen() call calls
2020-06-30 14:49:38 +02:00
if (NULL == f) {
/* Handle error */
}
if (fclose(f) == EOF) {
/* Handle error */
}
}
}
----
2020-06-30 12:50:28 +02:00
== Compliant Solution
2021-01-27 13:42:22 +01:00
If the file already exists on the disk, ``++fopen++`` with ``++x++`` mode will fail:
2020-06-30 14:49:38 +02:00
2020-06-30 12:50:28 +02:00
----
#include <stdio.h>
void open_without_toctou(const char *file) {
FILE *f = fopen(file, "wx"); // Compliant
if (NULL == f) {
/* Handle error */
}
/* Write to file */
if (fclose(f) == EOF) {
/* Handle error */
}
}
----
A more generic solution is to use "file descriptors":
2020-06-30 14:49:38 +02:00
2020-06-30 12:50:28 +02:00
----
void open_without_toctou(const char *file) {
int fd = open(file, O_CREAT | O_EXCL | O_WRONLY);
if (-1 != fd) {
FILE *f = fdopen(fd, "w"); // Compliant
}
}
----
include::../see.adoc[]
2021-06-02 20:44:38 +02:00
ifdef::rspecator-view[]
== Comments And Links
(visible only on this page)
include::../comments-and-links.adoc[]
endif::rspecator-view[]