"Fossies" - the Fresh Open Source Software Archive

Member "honggfuzz-2.2/libhfcommon/files.c" (23 Apr 2020, 14684 Bytes) of package /linux/privat/honggfuzz-2.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "files.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.1_vs_2.2.

    1 /*
    2  *
    3  * honggfuzz - file operations
    4  * -----------------------------------------
    5  *
    6  * Author: Robert Swiecki <swiecki@google.com>
    7  *
    8  * Copyright 2010-2018 by Google Inc. All Rights Reserved.
    9  *
   10  * Licensed under the Apache License, Version 2.0 (the "License"); you may
   11  * not use this file except in compliance with the License. You may obtain
   12  * a copy of the License at
   13  *
   14  * http://www.apache.org/licenses/LICENSE-2.0
   15  *
   16  * Unless required by applicable law or agreed to in writing, software
   17  * distributed under the License is distributed on an "AS IS" BASIS,
   18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
   19  * implied. See the License for the specific language governing
   20  * permissions and limitations under the License.
   21  *
   22  */
   23 
   24 #include "libhfcommon/files.h"
   25 
   26 #include <arpa/inet.h>
   27 #include <dirent.h>
   28 #include <errno.h>
   29 #include <fcntl.h>
   30 #include <inttypes.h>
   31 #include <limits.h>
   32 #if defined(_HF_ARCH_LINUX)
   33 #include <linux/memfd.h>
   34 #endif /* defined(_HF_ARCH_LINUX) */
   35 #include <netinet/in.h>
   36 #include <netinet/ip.h>
   37 #include <stddef.h>
   38 #include <stdint.h>
   39 #include <stdio.h>
   40 #include <stdlib.h>
   41 #include <string.h>
   42 #include <sys/mman.h>
   43 #include <sys/socket.h>
   44 #include <sys/stat.h>
   45 #include <sys/un.h>
   46 #if defined(_HF_ARCH_LINUX)
   47 #include <sys/syscall.h>
   48 #endif /* defined(_HF_ARCH_LINUX) */
   49 #include <sys/time.h>
   50 #include <sys/types.h>
   51 #include <unistd.h>
   52 
   53 #include "libhfcommon/common.h"
   54 #include "libhfcommon/log.h"
   55 #include "libhfcommon/util.h"
   56 
   57 ssize_t files_readFileToBufMax(const char* fname, uint8_t* buf, size_t fileMaxSz) {
   58     int fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
   59     if (fd == -1) {
   60         PLOG_W("Couldn't open '%s' for R/O", fname);
   61         return -1;
   62     }
   63 
   64     ssize_t readSz = files_readFromFd(fd, buf, fileMaxSz);
   65     if (readSz < 0) {
   66         LOG_W("Couldn't read '%s' to a buf", fname);
   67     }
   68     close(fd);
   69 
   70     LOG_D("Read %zu bytes (%zu requested) from '%s'", (size_t)readSz, fileMaxSz, fname);
   71     return readSz;
   72 }
   73 
   74 bool files_writeBufToFile(const char* fname, const uint8_t* buf, size_t fileSz, int flags) {
   75     int fd = TEMP_FAILURE_RETRY(open(fname, flags, 0644));
   76     if (fd == -1) {
   77         PLOG_W("Couldn't create/open '%s' for R/W", fname);
   78         return false;
   79     }
   80 
   81     bool ret = files_writeToFd(fd, buf, fileSz);
   82     if (ret == false) {
   83         PLOG_W("Couldn't write '%zu' bytes to file '%s' (fd='%d')", fileSz, fname, fd);
   84         unlink(fname);
   85     } else {
   86         LOG_D("Written '%zu' bytes to '%s'", fileSz, fname);
   87     }
   88 
   89     close(fd);
   90     return ret;
   91 }
   92 
   93 bool files_writeStrToFile(const char* fname, const char* str, int flags) {
   94     return files_writeBufToFile(fname, (uint8_t*)str, strlen(str), flags);
   95 }
   96 
   97 int files_writeBufToTmpFile(const char* dir, const uint8_t* buf, size_t fileSz, int flags) {
   98     char template[PATH_MAX];
   99     snprintf(template, sizeof(template), "%s/hfuzz.XXXXXX", dir);
  100     int fd = mkostemp(template, flags);
  101     if (fd == -1) {
  102         PLOG_W("mkostemp('%s') failed", template);
  103         return -1;
  104     }
  105     if (unlink(template) == -1) {
  106         PLOG_W("unlink('%s')", template);
  107     }
  108     if (!files_writeToFd(fd, buf, fileSz)) {
  109         PLOG_W("Couldn't save data to the temporary file");
  110         close(fd);
  111         return -1;
  112     }
  113     if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
  114         PLOG_W("Couldn't rewind file '%s' fd=%d", template, fd);
  115         close(fd);
  116         return -1;
  117     }
  118     return fd;
  119 }
  120 
  121 bool files_writeToFd(int fd, const uint8_t* buf, size_t fileSz) {
  122     size_t writtenSz = 0;
  123     while (writtenSz < fileSz) {
  124         ssize_t sz = TEMP_FAILURE_RETRY(write(fd, &buf[writtenSz], fileSz - writtenSz));
  125         if (sz < 0) {
  126             return false;
  127         }
  128         writtenSz += sz;
  129     }
  130     return true;
  131 }
  132 
  133 bool files_writeStrToFd(int fd, const char* str) {
  134     return files_writeToFd(fd, (const uint8_t*)str, strlen(str));
  135 }
  136 
  137 ssize_t files_readFromFd(int fd, uint8_t* buf, size_t fileSz) {
  138     size_t readSz = 0;
  139     while (readSz < fileSz) {
  140         ssize_t sz = TEMP_FAILURE_RETRY(read(fd, &buf[readSz], fileSz - readSz));
  141         if (sz == 0) {
  142             break;
  143         }
  144         if (sz < 0) {
  145             return -1;
  146         }
  147         readSz += sz;
  148     }
  149     return (ssize_t)readSz;
  150 }
  151 
  152 ssize_t files_readFromFdSeek(int fd, uint8_t* buf, size_t fileSz, off_t off) {
  153     if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
  154         PLOG_W("lseek(fd=%d, %lld, SEEK_SET)", fd, (long long int)off);
  155         return -1;
  156     }
  157     return files_readFromFd(fd, buf, fileSz);
  158 }
  159 
  160 bool files_exists(const char* fname) {
  161     return (access(fname, F_OK) != -1);
  162 }
  163 
  164 bool files_writePatternToFd(int fd, off_t size, unsigned char p) {
  165     void* buf = malloc(size);
  166     if (!buf) {
  167         PLOG_W("Couldn't allocate memory");
  168         return false;
  169     }
  170 
  171     memset(buf, p, (size_t)size);
  172     int ret = files_writeToFd(fd, buf, size);
  173     free(buf);
  174 
  175     return ret;
  176 }
  177 
  178 bool files_sendToSocketNB(int fd, const uint8_t* buf, size_t fileSz) {
  179     size_t writtenSz = 0;
  180     while (writtenSz < fileSz) {
  181         ssize_t sz =
  182             TEMP_FAILURE_RETRY(send(fd, &buf[writtenSz], fileSz - writtenSz, MSG_DONTWAIT));
  183         if (sz < 0) {
  184             return false;
  185         }
  186         writtenSz += sz;
  187     }
  188     return true;
  189 }
  190 
  191 bool files_sendToSocket(int fd, const uint8_t* buf, size_t fileSz) {
  192     int sendFlags = 0;
  193 #ifdef _HF_ARCH_DARWIN
  194     sendFlags |= SO_NOSIGPIPE;
  195 #else
  196     sendFlags |= MSG_NOSIGNAL;
  197 #endif
  198 
  199     size_t writtenSz = 0;
  200     while (writtenSz < fileSz) {
  201         ssize_t sz = send(fd, &buf[writtenSz], fileSz - writtenSz, sendFlags);
  202         if (sz < 0 && errno == EINTR) continue;
  203 
  204         if (sz < 0) return false;
  205 
  206         writtenSz += sz;
  207     }
  208     return true;
  209 }
  210 
  211 const char* files_basename(const char* path) {
  212     const char* base = strrchr(path, '/');
  213     return base ? base + 1 : path;
  214 }
  215 
  216 /* Zero all bytes in the file */
  217 bool files_resetFile(int fd, size_t sz) {
  218 #if defined(_HF_ARCH_LINUX)
  219     if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, (off_t)0, (off_t)sz) != -1) {
  220         return true;
  221     }
  222     PLOG_W("fallocate(fd=%d, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, sz=%zu)", fd, sz);
  223 #endif /* defined(_HF_ARCH_LINUX) */
  224 
  225     /* Fallback mode */
  226     if (ftruncate(fd, (off_t)0) == -1) {
  227         PLOG_W("ftruncate(fd=%d, sz=0)", fd);
  228         return false;
  229     }
  230     if (ftruncate(fd, (off_t)sz) == -1) {
  231         PLOG_W("ftruncate(fd=%d, sz=%zu)", fd, sz);
  232         return false;
  233     }
  234     return true;
  235 }
  236 
  237 /*
  238  * Reads symbols from src file (one per line) and append them to filterList. The
  239  * total number of added symbols is returned.
  240  *
  241  * Simple wildcard strings are also supported (e.g. mem*)
  242  */
  243 size_t files_parseSymbolFilter(const char* srcFile, char*** filterList) {
  244     FILE* f = fopen(srcFile, "rb");
  245     if (f == NULL) {
  246         PLOG_W("Couldn't open '%s' - R/O mode", srcFile);
  247         return 0;
  248     }
  249 
  250     char* lineptr = NULL;
  251     size_t symbolsRead = 0, n = 0;
  252     for (;;) {
  253         if (getline(&lineptr, &n, f) == -1) {
  254             break;
  255         }
  256 
  257         if (strlen(lineptr) < 3) {
  258             LOG_F("Input symbol '%s' too short (strlen < 3)", lineptr);
  259             symbolsRead = 0;
  260             break;
  261         }
  262         if ((*filterList = (char**)util_Realloc(
  263                  *filterList, (symbolsRead + 1) * sizeof((*filterList)[0]))) == NULL) {
  264             PLOG_W("realloc failed (sz=%zu)", (symbolsRead + 1) * sizeof((*filterList)[0]));
  265             symbolsRead = 0;
  266             break;
  267         }
  268         (*filterList)[symbolsRead] = malloc(strlen(lineptr));
  269         if (!(*filterList)[symbolsRead]) {
  270             PLOG_E("malloc(%zu) failed", strlen(lineptr));
  271             symbolsRead = 0;
  272             break;
  273         }
  274         snprintf((*filterList)[symbolsRead], strlen(lineptr), "%s", lineptr);
  275         symbolsRead++;
  276     }
  277 
  278     LOG_I("%zu filter symbols added to list", symbolsRead);
  279     fclose(f);
  280     free(lineptr);
  281     return symbolsRead;
  282 }
  283 
  284 uint8_t* files_mapFile(const char* fname, off_t* fileSz, int* fd, bool isWritable) {
  285     int mmapProt = PROT_READ;
  286     if (isWritable) {
  287         mmapProt |= PROT_WRITE;
  288     }
  289 
  290     if ((*fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY))) == -1) {
  291         PLOG_W("Couldn't open() '%s' file in R/O mode", fname);
  292         return NULL;
  293     }
  294 
  295     struct stat st;
  296     if (fstat(*fd, &st) == -1) {
  297         PLOG_W("Couldn't stat() the '%s' file", fname);
  298         close(*fd);
  299         return NULL;
  300     }
  301 
  302     uint8_t* buf;
  303     if ((buf = mmap(NULL, st.st_size, mmapProt, MAP_PRIVATE, *fd, 0)) == MAP_FAILED) {
  304         PLOG_W("Couldn't mmap() the '%s' file", fname);
  305         close(*fd);
  306         return NULL;
  307     }
  308 
  309     *fileSz = st.st_size;
  310     return buf;
  311 }
  312 
  313 /* mmap flags for various OSs, when mmap'ing a temporary file or a shared mem */
  314 int files_getTmpMapFlags(int flag, bool nocore) {
  315 #if defined(MAP_NOSYNC)
  316     /*
  317      * Some kind of bug in FreeBSD kernel. Without this flag, the shm_open() memory will cause a lot
  318      * of troubles to the calling process when mmap()'d
  319      */
  320     flag |= MAP_NOSYNC;
  321 #endif /* defined(MAP_NOSYNC) */
  322 #if defined(MAP_HASSEMAPHORE)
  323     /* Our shared/mmap'd pages can have mutexes in them */
  324     flag |= MAP_HASSEMAPHORE;
  325 #endif /* defined(MAP_HASSEMAPHORE) */
  326     if (nocore) {
  327 #if defined(MAP_CONCEAL)
  328         flag |= MAP_CONCEAL;
  329 #endif /* defined(MAP_CONCEAL) */
  330 #if defined(MAP_NOCORE)
  331         flag |= MAP_NOCORE;
  332 #endif /* defined(MAP_NOCORE) */
  333     }
  334     return flag;
  335 }
  336 
  337 int files_createSharedMem(size_t sz, const char* name, bool exportmap) {
  338     int fd = -1;
  339 
  340     if (exportmap) {
  341         char path[PATH_MAX];
  342         snprintf(path, sizeof(path), "./%s", name);
  343         if ((fd = open(path, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0644)) == -1) {
  344             PLOG_W("open('%s')", path);
  345             return -1;
  346         }
  347     }
  348 
  349 #if defined(_HF_ARCH_LINUX)
  350     if (fd == -1) {
  351         fd = syscall(__NR_memfd_create, name, (uintptr_t)(MFD_CLOEXEC));
  352     }
  353 #endif /* defined(_HF_ARCH_LINUX) */
  354 
  355 /* SHM_ANON is available with some *BSD OSes */
  356 #if defined(SHM_ANON)
  357     if (fd == -1) {
  358         if ((fd = shm_open(SHM_ANON, O_RDWR, 0600)) == -1) {
  359             PLOG_W("shm_open(SHM_ANON, O_RDWR, 0600)");
  360         }
  361     }
  362 #endif /* defined(SHM_ANON) */
  363 
  364 /* Use regular shm_open */
  365 #if !defined(_HF_ARCH_DARWIN) && !defined(__ANDROID__)
  366     /* shm objects under MacOSX are 'a-typical' */
  367     if (fd == -1) {
  368         char tmpname[PATH_MAX];
  369         struct timeval tv;
  370         gettimeofday(&tv, NULL);
  371         snprintf(tmpname, sizeof(tmpname), "/%s%lx%lx%d", name, (unsigned long)tv.tv_sec,
  372             (unsigned long)tv.tv_usec, (int)getpid());
  373         if ((fd = shm_open(tmpname, O_RDWR | O_CREAT | O_EXCL, 0600)) == -1) {
  374             PLOG_W("shm_open('%s', O_RDWR|O_CREAT|O_EXCL, 0600)", tmpname);
  375         } else {
  376             shm_unlink(tmpname);
  377         }
  378     }
  379 #endif /* !defined(_HF_ARCH_DARWIN) && !defined(__ANDROID__) */
  380 
  381     /* As the last resort, create a file in /tmp */
  382     if (fd == -1) {
  383         char template[PATH_MAX];
  384         snprintf(template, sizeof(template), "/tmp/%s.XXXXXX", name);
  385         if ((fd = mkostemp(template, O_CLOEXEC)) == -1) {
  386             PLOG_W("mkstemp('%s')", template);
  387             return -1;
  388         }
  389         unlink(template);
  390     }
  391 
  392     if (TEMP_FAILURE_RETRY(ftruncate(fd, sz)) == -1) {
  393         PLOG_W("ftruncate(%d, %zu)", fd, sz);
  394         close(fd);
  395         return -1;
  396     }
  397 
  398     return fd;
  399 }
  400 
  401 void* files_mapSharedMem(size_t sz, int* fd, const char* name, bool nocore, bool exportmap) {
  402     *fd = files_createSharedMem(sz, name, exportmap);
  403     if (*fd == -1) {
  404         return NULL;
  405     }
  406 
  407     int mflags = files_getTmpMapFlags(MAP_SHARED, /* nocore= */ true);
  408     void* ret = mmap(NULL, sz, PROT_READ | PROT_WRITE, mflags, *fd, 0);
  409     if (ret == MAP_FAILED) {
  410         PLOG_W("mmap(sz=%zu, fd=%d)", sz, *fd);
  411         *fd = -1;
  412         close(*fd);
  413         return NULL;
  414     }
  415     if (posix_madvise(ret, sz, POSIX_MADV_RANDOM) == -1) {
  416         PLOG_W("posix_madvise(sz=%zu, POSIX_MADV_RANDOM)", sz);
  417     }
  418     if (nocore) {
  419 #if defined(MADV_DONTDUMP)
  420         if (madvise(ret, sz, MADV_DONTDUMP) == -1) {
  421             PLOG_W("madvise(sz=%zu, MADV_DONTDUMP)", sz);
  422         }
  423 #endif /* defined(MADV_DONTDUMP) */
  424 #if defined(MADV_NOCORE)
  425         if (madvise(ret, sz, MADV_NOCORE) == -1) {
  426             PLOG_W("madvise(sz=%zu, MADV_NOCORE)", sz);
  427         }
  428 #endif /* defined(MADV_NOCORE) */
  429     }
  430     return ret;
  431 }
  432 
  433 sa_family_t files_sockFamily(int sock) {
  434     struct sockaddr addr;
  435     socklen_t addrlen = sizeof(addr);
  436 
  437     if (getsockname(sock, &addr, &addrlen) == -1) {
  438         PLOG_W("getsockname(sock=%d)", sock);
  439         return AF_UNSPEC;
  440     }
  441 
  442     return addr.sa_family;
  443 }
  444 
  445 const char* files_sockAddrToStr(const struct sockaddr* sa, const socklen_t len) {
  446     static __thread char str[4096];
  447 
  448     if (sa->sa_family == AF_INET) {
  449         struct sockaddr_in* sin = (struct sockaddr_in*)sa;
  450         if (inet_ntop(sin->sin_family, &sin->sin_addr.s_addr, str, sizeof(str))) {
  451             util_ssnprintf(str, sizeof(str), "/%hd", ntohs(sin->sin_port));
  452         } else {
  453             snprintf(str, sizeof(str), "IPv4 addr conversion failed");
  454         }
  455         return str;
  456     }
  457     if (sa->sa_family == AF_INET6) {
  458         struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
  459         if (inet_ntop(sin6->sin6_family, sin6->sin6_addr.s6_addr, str, sizeof(str))) {
  460             util_ssnprintf(str, sizeof(str), "/%hd", ntohs(sin6->sin6_port));
  461         } else {
  462             snprintf(str, sizeof(str), "IPv6 addr conversion failed");
  463         }
  464         return str;
  465     }
  466 
  467     if (sa->sa_family == AF_UNIX) {
  468         if ((size_t)len <= offsetof(struct sockaddr_un, sun_path)) {
  469             snprintf(str, sizeof(str), "unix:<struct too short at %u bytes>", (unsigned)len);
  470             return str;
  471         }
  472 
  473         struct sockaddr_un* sun = (struct sockaddr_un*)sa;
  474         int pathlen;
  475 
  476         if (sun->sun_path[0] == '\0') {
  477             /* Abstract socket
  478              *
  479              * TODO: Handle null bytes in sun->sun_path (they have no
  480              * special significance unlike in C char arrays, see unix(7))
  481              */
  482             pathlen = strnlen(&sun->sun_path[1], len - offsetof(struct sockaddr_un, sun_path) - 1);
  483 
  484             snprintf(str, sizeof(str), "unix:abstract:%-*s", pathlen, &sun->sun_path[1]);
  485             return str;
  486         }
  487 
  488         pathlen = strnlen(sun->sun_path, len - offsetof(struct sockaddr_un, sun_path));
  489 
  490         snprintf(str, sizeof(str), "unix:%-*s", pathlen, sun->sun_path);
  491         return str;
  492     }
  493 
  494     snprintf(str, sizeof(str), "Unsupported sockaddr family=%d", (int)sa->sa_family);
  495     return str;
  496 }