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;
}

Reply via email to