From 828db443b2a7380f3a0033488cb0522db5ae1116 Mon Sep 17 00:00:00 2001 From: henri Date: Wed, 25 Feb 2015 16:36:42 +0000 Subject: [PATCH] Fixed a TOCTOU race in mmapfile() Let open() fail in case of a missing file, then use fstat on the returned file descriptor to get the actual file size. Reported by Camille Mougey. --- CHANGELOG | 3 +++ utils.cc | 28 ++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6a6a3d27c..38e3b849a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,8 @@ # Nmap Changelog ($Id$); -*-text-*- +o Fixed a benign TOCTOU race between stat() and open() in mmapfile(). + Reported by Camille Mougey. [Henri Doreau] + o Reduce CPU consumption when using nsock poll engine with no registered FD, by actually calling Poll() for the time until timeout, instead of directly returning zero and entering the loop again. [Henri Doreau] diff --git a/utils.cc b/utils.cc index 2a9a36a41..c0f060d9c 100644 --- a/utils.cc +++ b/utils.cc @@ -584,16 +584,28 @@ int cpe_get_part(const char *cpe) { } +#ifndef WIN32 +static int open2mmap_flags(int open_flags) +{ + switch (open_flags) { + case O_RDONLY: return PROT_READ; + case O_RDWR: return PROT_READ | PROT_WRITE; + case O_WRONLY: return PROT_WRITE; + default: + return -1; + } +} + /* mmap() an entire file into the address space. Returns a pointer to the beginning of the file. The mmap'ed length is returned inside the length parameter. If there is a problem, NULL is returned, the value of length is undefined, and errno is set to something appropriate. The user is responsible for doing an munmap(ptr, length) when finished with it. openflags should be O_RDONLY or O_RDWR, or O_WRONLY. */ -#ifndef WIN32 char *mmapfile(char *fname, int *length, int openflags) { struct stat st; int fd; + int mmap_flags; char *fileptr; if (!length || !fname) { @@ -603,8 +615,9 @@ char *mmapfile(char *fname, int *length, int openflags) { *length = -1; - if (stat(fname, &st) == -1) { - errno = ENOENT; + mmap_flags = open2mmap_flags(openflags); + if (mmap_flags == -1) { + errno = EINVAL; return NULL; } @@ -613,9 +626,12 @@ char *mmapfile(char *fname, int *length, int openflags) { return NULL; } - fileptr = (char *)mmap(0, st.st_size, (openflags == O_RDONLY) ? PROT_READ : - (openflags == O_RDWR) ? (PROT_READ | PROT_WRITE) - : PROT_WRITE, MAP_SHARED, fd, 0); + if (fstat(fd, &st) == -1) { + close(fd); + return NULL; + } + + fileptr = (char *)mmap(0, st.st_size, mmap_flags, MAP_SHARED, fd, 0); close(fd);