Home | History | Annotate | Download | only in honggfuzz
      1 /*
      2  *
      3  * honggfuzz - file operations
      4  * -----------------------------------------
      5  *
      6  * Author: Robert Swiecki <swiecki (at) google.com>
      7  *
      8  * Copyright 2010-2015 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 "input.h"
     25 
     26 #include <dirent.h>
     27 #include <errno.h>
     28 #include <fcntl.h>
     29 #include <inttypes.h>
     30 #include <stdint.h>
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <string.h>
     34 #include <sys/mman.h>
     35 #include <sys/socket.h>
     36 #include <sys/stat.h>
     37 #include <sys/types.h>
     38 #include <unistd.h>
     39 
     40 #include "libcommon/common.h"
     41 #include "libcommon/files.h"
     42 
     43 #if defined(_HF_ARCH_LINUX)
     44 #include <sys/syscall.h>
     45 #if defined(__NR_memfd_create)
     46 #include <linux/memfd.h>
     47 #endif /* defined(__NR_memfd_create) */
     48 #endif /* defined(_HF_ARCH_LINUX) */
     49 
     50 #include "libcommon/log.h"
     51 #include "libcommon/util.h"
     52 
     53 static bool input_getDirStatsAndRewind(honggfuzz_t* hfuzz) {
     54     rewinddir(hfuzz->io.inputDirPtr);
     55 
     56     size_t maxSize = 0U;
     57     size_t fileCnt = 0U;
     58     for (;;) {
     59         errno = 0;
     60         struct dirent* entry = readdir(hfuzz->io.inputDirPtr);
     61         if (entry == NULL && errno == EINTR) {
     62             continue;
     63         }
     64         if (entry == NULL && errno != 0) {
     65             PLOG_W("readdir('%s')", hfuzz->io.inputDir);
     66             return false;
     67         }
     68         if (entry == NULL) {
     69             break;
     70         }
     71 
     72         char fname[PATH_MAX];
     73         snprintf(fname, sizeof(fname), "%s/%s", hfuzz->io.inputDir, entry->d_name);
     74         LOG_D("Analyzing file '%s'", fname);
     75 
     76         struct stat st;
     77         if (stat(fname, &st) == -1) {
     78             LOG_W("Couldn't stat() the '%s' file", fname);
     79             continue;
     80         }
     81         if (!S_ISREG(st.st_mode)) {
     82             LOG_D("'%s' is not a regular file, skipping", fname);
     83             continue;
     84         }
     85         if (hfuzz->maxFileSz != 0UL && st.st_size > (off_t)hfuzz->maxFileSz) {
     86             LOG_W("File '%s' is bigger than maximal defined file size (-F): %" PRId64 " > %" PRId64,
     87                 fname, (int64_t)st.st_size, (int64_t)hfuzz->maxFileSz);
     88         }
     89         if ((size_t)st.st_size > maxSize) {
     90             maxSize = st.st_size;
     91         }
     92         fileCnt++;
     93     }
     94 
     95     ATOMIC_SET(hfuzz->io.fileCnt, fileCnt);
     96     if (hfuzz->maxFileSz == 0U) {
     97         if (maxSize < 8192) {
     98             hfuzz->maxFileSz = 8192;
     99         } else {
    100             hfuzz->maxFileSz = maxSize;
    101         }
    102     }
    103     if (hfuzz->persistent && hfuzz->maxFileSz > (1024U * 128)) {
    104         LOG_D("Persistent mode enabled, lowering maximum input size to 128KiB");
    105         hfuzz->maxFileSz = 1024U * 128;
    106     }
    107 
    108     if (hfuzz->io.fileCnt == 0U) {
    109         LOG_W("No usable files in the input directory '%s'", hfuzz->io.inputDir);
    110         return false;
    111     }
    112 
    113     LOG_D("Re-read the '%s', maxFileSz:%zu, number of usable files:%zu", hfuzz->io.inputDir,
    114         hfuzz->maxFileSz, hfuzz->io.fileCnt);
    115 
    116     rewinddir(hfuzz->io.inputDirPtr);
    117 
    118     return true;
    119 }
    120 
    121 bool input_getNext(run_t* run, char* fname, bool rewind) {
    122     static pthread_mutex_t input_mutex = PTHREAD_MUTEX_INITIALIZER;
    123     MX_SCOPED_LOCK(&input_mutex);
    124 
    125     if (run->global->io.fileCnt == 0U) {
    126         return false;
    127     }
    128 
    129     for (;;) {
    130         errno = 0;
    131         struct dirent* entry = readdir(run->global->io.inputDirPtr);
    132         if (entry == NULL && errno == EINTR) {
    133             continue;
    134         }
    135         if (entry == NULL && errno != 0) {
    136             PLOG_W("readdir_r('%s')", run->global->io.inputDir);
    137             return false;
    138         }
    139         if (entry == NULL && rewind == false) {
    140             return false;
    141         }
    142         if (entry == NULL && rewind == true) {
    143             if (input_getDirStatsAndRewind(run->global) == false) {
    144                 LOG_E("input_getDirStatsAndRewind('%s')", run->global->io.inputDir);
    145                 return false;
    146             }
    147             continue;
    148         }
    149 
    150         snprintf(fname, PATH_MAX, "%s/%s", run->global->io.inputDir, entry->d_name);
    151 
    152         struct stat st;
    153         if (stat(fname, &st) == -1) {
    154             LOG_W("Couldn't stat() the '%s' file", fname);
    155             continue;
    156         }
    157         if (!S_ISREG(st.st_mode)) {
    158             LOG_D("'%s' is not a regular file, skipping", fname);
    159             continue;
    160         }
    161         return true;
    162     }
    163 }
    164 
    165 bool input_init(honggfuzz_t* hfuzz) {
    166     hfuzz->io.fileCnt = 0U;
    167 
    168     if (!hfuzz->io.inputDir) {
    169         LOG_W("No input file/dir specified");
    170         return false;
    171     }
    172 
    173     int dir_fd = open(hfuzz->io.inputDir, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
    174     if (dir_fd == -1) {
    175         PLOG_W("open('%s', O_DIRECTORY|O_RDONLY|O_CLOEXEC)", hfuzz->io.inputDir);
    176         return false;
    177     }
    178     if ((hfuzz->io.inputDirPtr = fdopendir(dir_fd)) == NULL) {
    179         close(dir_fd);
    180         PLOG_W("opendir('%s')", hfuzz->io.inputDir);
    181         return false;
    182     }
    183     if (input_getDirStatsAndRewind(hfuzz) == false) {
    184         hfuzz->io.fileCnt = 0U;
    185         LOG_W("input_getDirStatsAndRewind('%s')", hfuzz->io.inputDir);
    186         return false;
    187     }
    188 
    189     return true;
    190 }
    191 
    192 bool input_parseDictionary(honggfuzz_t* hfuzz) {
    193     FILE* fDict = fopen(hfuzz->dictionaryFile, "rb");
    194     if (fDict == NULL) {
    195         PLOG_W("Couldn't open '%s' - R/O mode", hfuzz->dictionaryFile);
    196         return false;
    197     }
    198     defer { fclose(fDict); };
    199 
    200     char* lineptr = NULL;
    201     size_t n = 0;
    202     defer { free(lineptr); };
    203     for (;;) {
    204         ssize_t len = getdelim(&lineptr, &n, '\n', fDict);
    205         if (len == -1) {
    206             break;
    207         }
    208         if (len > 1 && lineptr[len - 1] == '\n') {
    209             lineptr[len - 1] = '\0';
    210             len--;
    211         }
    212         if (lineptr[0] == '#') {
    213             continue;
    214         }
    215         if (lineptr[0] == '\n') {
    216             continue;
    217         }
    218         if (lineptr[0] == '\0') {
    219             continue;
    220         }
    221         char bufn[1025] = {0};
    222         char bufv[1025] = {0};
    223         if (sscanf(lineptr, "\"%1024s", bufv) != 1 &&
    224             sscanf(lineptr, "%1024[^=]=\"%1024s", bufn, bufv) != 2) {
    225             LOG_W("Incorrect dictionary entry: '%s'. Skipping", lineptr);
    226             continue;
    227         }
    228 
    229         char* s = util_StrDup(bufv);
    230         struct strings_t* str = (struct strings_t*)util_Malloc(sizeof(struct strings_t));
    231         str->len = util_decodeCString(s);
    232         str->s = s;
    233         hfuzz->dictionaryCnt += 1;
    234         TAILQ_INSERT_TAIL(&hfuzz->dictq, str, pointers);
    235 
    236         LOG_D("Dictionary: loaded word: '%s' (len=%zu)", str->s, str->len);
    237     }
    238     LOG_I("Loaded %zu words from the dictionary", hfuzz->dictionaryCnt);
    239     return true;
    240 }
    241 
    242 bool input_parseBlacklist(honggfuzz_t* hfuzz) {
    243     FILE* fBl = fopen(hfuzz->blacklistFile, "rb");
    244     if (fBl == NULL) {
    245         PLOG_W("Couldn't open '%s' - R/O mode", hfuzz->blacklistFile);
    246         return false;
    247     }
    248     defer { fclose(fBl); };
    249 
    250     char* lineptr = NULL;
    251     /* lineptr can be NULL, but it's fine for free() */
    252     defer { free(lineptr); };
    253     size_t n = 0;
    254     for (;;) {
    255         if (getline(&lineptr, &n, fBl) == -1) {
    256             break;
    257         }
    258 
    259         if ((hfuzz->blacklist = util_Realloc(hfuzz->blacklist,
    260                  (hfuzz->blacklistCnt + 1) * sizeof(hfuzz->blacklist[0]))) == NULL) {
    261             PLOG_W(
    262                 "realloc failed (sz=%zu)", (hfuzz->blacklistCnt + 1) * sizeof(hfuzz->blacklist[0]));
    263             return false;
    264         }
    265 
    266         hfuzz->blacklist[hfuzz->blacklistCnt] = strtoull(lineptr, 0, 16);
    267         LOG_D("Blacklist: loaded %'" PRIu64 "'", hfuzz->blacklist[hfuzz->blacklistCnt]);
    268 
    269         // Verify entries are sorted so we can use interpolation search
    270         if (hfuzz->blacklistCnt > 1) {
    271             if (hfuzz->blacklist[hfuzz->blacklistCnt - 1] > hfuzz->blacklist[hfuzz->blacklistCnt]) {
    272                 LOG_F(
    273                     "Blacklist file not sorted. Use 'tools/createStackBlacklist.sh' to sort "
    274                     "records");
    275                 return false;
    276             }
    277         }
    278         hfuzz->blacklistCnt += 1;
    279     }
    280 
    281     if (hfuzz->blacklistCnt > 0) {
    282         LOG_I("Loaded %zu stack hash(es) from the blacklist file", hfuzz->blacklistCnt);
    283     } else {
    284         LOG_F("Empty stack hashes blacklist file '%s'", hfuzz->blacklistFile);
    285     }
    286     return true;
    287 }
    288