Hi,
hope you're doing well.
I've tried to figure out how to deal with the TOCTOUs, found by Coverity
Scan, https://scan.coverity.com/projects/freenginx.
So, I've created a PoC for that: it uses *at family functions (conforming
to POSIX.1-2008), such as mkdirat(2) and openat(2).
I do believe it's possible to fix TOCTOU issues similarly, but before
I start my work on that I'd like to hear your thoughts.
Thank you.
--
Sergey A. Osokin
#include <sys/syscall.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int dfdp, dfd, fd;
char *dirname = "foo";
char *filename = "bar.baz";
if ((dfdp = open("/home/osa/src/freenginx", O_EXCL | O_DIRECTORY | O_NOFOLLOW)) == -1) {
perror("parent dir open()");
exit(1);
}
umask((mode_t)022);
if ((dfd = mkdirat(dfdp, dirname, 0700)) == -1) {
perror("mkdirat() failed");
}
if ((dfd = openat(dfdp, dirname, O_EXCL | O_DIRECTORY | O_NOFOLLOW)) == -1) {
perror("openat() directory failed");
exit(1);
}
if ((fd = openat(dfd, filename, O_CREAT | O_RDWR | O_TRUNC, 0600)) == -1) {
perror("openat() file failed");
if (fd == -1) {
switch (errno) {
case EEXIST:
fprintf(stderr, "Error: The file %s already exists.\n", filename);
break;
case EBADF:
fprintf(stderr, "Error: Invalid directory file descriptor provided.\n");
break;
case EACCES:
fprintf(stderr, "Error: Permission denied in the target directory.\n");
break;
case ENOTDIR:
fprintf(stderr, "Error: The file descriptor provided is not a directory.\n");
break;
default:
fprintf(stderr, "Unexpected error creating '%s': %s\n",
filename, strerror(errno));
}
exit(1);
}
}
printf("Successfully created %s file with FD: %d\n", filename, fd);
close(fd);
return 0;
}