"Fossies" - the Fresh Open Source Software Archive

Member "honggfuzz-2.2/linux/arch.c" (23 Apr 2020, 12816 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 "arch.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 - architecture dependent code (LINUX)
    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 "arch.h"
   25 
   26 #include <ctype.h>
   27 #include <dlfcn.h>
   28 #include <errno.h>
   29 #include <fcntl.h>
   30 #include <inttypes.h>
   31 #include <locale.h>
   32 #include <setjmp.h>
   33 #include <signal.h>
   34 #include <stdio.h>
   35 #include <stdlib.h>
   36 #include <string.h>
   37 #include <sys/cdefs.h>
   38 #include <sys/personality.h>
   39 #include <sys/prctl.h>
   40 #include <sys/syscall.h>
   41 #include <sys/time.h>
   42 #include <sys/types.h>
   43 #include <sys/user.h>
   44 #include <sys/utsname.h>
   45 #include <sys/wait.h>
   46 #include <time.h>
   47 #include <unistd.h>
   48 
   49 #include "fuzz.h"
   50 #include "libhfcommon/common.h"
   51 #include "libhfcommon/files.h"
   52 #include "libhfcommon/log.h"
   53 #include "libhfcommon/ns.h"
   54 #include "libhfcommon/util.h"
   55 #include "linux/perf.h"
   56 #include "linux/trace.h"
   57 #include "sanitizers.h"
   58 #include "subproc.h"
   59 
   60 static uint8_t arch_clone_stack[128 * 1024] __attribute__((aligned(__BIGGEST_ALIGNMENT__)));
   61 static __thread jmp_buf env;
   62 
   63 HF_ATTR_NO_SANITIZE_ADDRESS
   64 HF_ATTR_NO_SANITIZE_MEMORY
   65 __attribute__((noreturn)) static int arch_cloneFunc(void* arg HF_ATTR_UNUSED) {
   66     longjmp(env, 1);
   67 }
   68 
   69 /* Avoid problem with caching of PID/TID in glibc */
   70 static pid_t arch_clone(uintptr_t flags) {
   71     if (flags & CLONE_VM) {
   72         LOG_E("Cannot use clone(flags & CLONE_VM)");
   73         return -1;
   74     }
   75 
   76     if (setjmp(env) == 0) {
   77         void* stack_mid = &arch_clone_stack[sizeof(arch_clone_stack) / 2];
   78         /* Parent */
   79         return clone(arch_cloneFunc, stack_mid, flags, NULL, NULL, NULL);
   80     }
   81     /* Child */
   82     return 0;
   83 }
   84 
   85 pid_t arch_fork(run_t* run) {
   86     pid_t pid = run->global->arch_linux.useClone ? arch_clone(CLONE_UNTRACED | SIGCHLD) : fork();
   87     if (pid == -1) {
   88         return pid;
   89     }
   90     if (pid == 0) {
   91         logMutexReset();
   92         if (prctl(PR_SET_PDEATHSIG, (unsigned long)SIGKILL, 0UL, 0UL, 0UL) == -1) {
   93             PLOG_W("prctl(PR_SET_PDEATHSIG, SIGKILL)");
   94         }
   95         return pid;
   96     }
   97     return pid;
   98 }
   99 
  100 bool arch_launchChild(run_t* run) {
  101     if ((run->global->arch_linux.cloneFlags & CLONE_NEWNET) && !nsIfaceUp("lo")) {
  102         LOG_W("Cannot bring interface 'lo' up");
  103     }
  104 
  105     /* Try to enable network namespacing if requested */
  106     if (run->global->arch_linux.useNetNs == HF_MAYBE) {
  107         if (unshare(CLONE_NEWUSER | CLONE_NEWNET) == -1) {
  108             PLOG_D("unshare((CLONE_NEWUSER|CLONE_NEWNS) failed");
  109         } else if (!nsIfaceUp("lo")) {
  110             LOG_E("Network namespacing enabled, but couldn't bring interface 'lo' up");
  111             return false;
  112         }
  113         LOG_D("Network namespacing enabled, and the 'lo' interface is set up");
  114     }
  115 
  116     /* Make it attach-able by ptrace() */
  117     if (prctl(PR_SET_DUMPABLE, 1UL, 0UL, 0UL, 0UL) == -1) {
  118         PLOG_E("prctl(PR_SET_DUMPABLE, 1)");
  119         return false;
  120     }
  121 
  122     /* Kill rocess which corrupts its own heap (with ABRT) */
  123     if (setenv("MALLOC_CHECK_", "7", 0) == -1) {
  124         PLOG_E("setenv(MALLOC_CHECK_=7) failed");
  125         return false;
  126     }
  127     if (setenv("MALLOC_PERTURB_", "85", 0) == -1) {
  128         PLOG_E("setenv(MALLOC_PERTURB_=85) failed");
  129         return false;
  130     }
  131 
  132     /* Increase our OOM score, so fuzzed processes die faster */
  133     if (!files_writeStrToFile("/proc/self/oom_score_adj", "+500", O_WRONLY)) {
  134         LOG_W("Couldn't increase our oom_score");
  135     }
  136 
  137     /*
  138      * Disable ASLR:
  139      * This might fail in Docker, as Docker blocks __NR_personality. Consequently
  140      * it's just a debug warning
  141      */
  142     if (run->global->arch_linux.disableRandomization &&
  143         syscall(__NR_personality, ADDR_NO_RANDOMIZE) == -1) {
  144         PLOG_D("personality(ADDR_NO_RANDOMIZE) failed");
  145     }
  146 
  147     /* Alarms persist across execve(), so disable them here */
  148     alarm(0);
  149 
  150     /* Wait for the ptrace to attach now */
  151     if (kill(syscall(__NR_getpid), SIGSTOP) == -1) {
  152         LOG_F("Couldn't stop itself");
  153     }
  154 #if defined(__NR_execveat)
  155     syscall(__NR_execveat, run->global->arch_linux.exeFd, "", run->args, environ, AT_EMPTY_PATH);
  156 #endif /* defined__NR_execveat) */
  157     execve(run->args[0], (char* const*)run->args, environ);
  158     int errno_cpy = errno;
  159     alarm(1);
  160 
  161     LOG_E("execve('%s', fd=%d): %s", run->args[0], run->global->arch_linux.exeFd,
  162         strerror(errno_cpy));
  163 
  164     return false;
  165 }
  166 
  167 static bool arch_attachToNewPid(run_t* run) {
  168     if (!arch_traceAttach(run)) {
  169         LOG_W("arch_traceAttach(pid=%d) failed", run->pid);
  170         return false;
  171     }
  172 
  173     return true;
  174 }
  175 
  176 void arch_prepareParentAfterFork(run_t* run) {
  177     /* Parent */
  178     if (run->global->exe.persistent) {
  179         const struct f_owner_ex fown = {
  180             .type = F_OWNER_TID,
  181             .pid = syscall(__NR_gettid),
  182         };
  183         if (fcntl(run->persistentSock, F_SETOWN_EX, &fown)) {
  184             PLOG_F("fcntl(%d, F_SETOWN_EX)", run->persistentSock);
  185         }
  186         if (fcntl(run->persistentSock, F_SETSIG, SIGIO) == -1) {
  187             PLOG_F("fcntl(%d, F_SETSIG, SIGIO)", run->persistentSock);
  188         }
  189         if (fcntl(run->persistentSock, F_SETFL, O_ASYNC) == -1) {
  190             PLOG_F("fcntl(%d, F_SETFL, O_ASYNC)", run->persistentSock);
  191         }
  192     }
  193 
  194     arch_perfClose(run);
  195     if (!arch_perfOpen(run)) {
  196         LOG_F("Couldn't open perf event for pid=%d", (int)run->pid);
  197     }
  198     if (!arch_attachToNewPid(run)) {
  199         LOG_F("Couldn't attach to pid=%d", (int)run->pid);
  200     }
  201 }
  202 
  203 void arch_prepareParent(run_t* run) {
  204     if (!arch_perfEnable(run)) {
  205         LOG_F("Couldn't enable perf counters for pid=%d", (int)run->pid);
  206     }
  207 }
  208 
  209 static bool arch_checkWait(run_t* run) {
  210     /* All queued wait events must be tested when SIGCHLD was delivered */
  211     for (;;) {
  212         int status;
  213         pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD | WNOHANG));
  214         if (pid == 0) {
  215             return false;
  216         }
  217         if (pid == -1 && errno == ECHILD) {
  218             LOG_D("No more processes to track");
  219             return true;
  220         }
  221         if (pid == -1) {
  222             PLOG_F("waitpid() failed");
  223         }
  224 
  225         char statusStr[4096];
  226         LOG_D("pid=%d returned with status: %s", pid,
  227             subproc_StatusToStr(status, statusStr, sizeof(statusStr)));
  228 
  229         arch_traceAnalyze(run, status, pid);
  230 
  231         if (pid == run->pid && (WIFEXITED(status) || WIFSIGNALED(status))) {
  232             if (run->global->exe.persistent) {
  233                 if (!fuzz_isTerminating()) {
  234                     LOG_W("Persistent mode: pid=%d exited with status: %s", (int)run->pid,
  235                         subproc_StatusToStr(status, statusStr, sizeof(statusStr)));
  236                 }
  237             }
  238             return true;
  239         }
  240     }
  241 }
  242 
  243 void arch_reapChild(run_t* run) {
  244     for (;;) {
  245         if (subproc_persistentModeStateMachine(run)) {
  246             break;
  247         }
  248 
  249         subproc_checkTimeLimit(run);
  250         subproc_checkTermination(run);
  251 
  252         const struct timespec ts = {
  253             .tv_sec = 0ULL,
  254             .tv_nsec = (1000ULL * 1000ULL * 100ULL),
  255         };
  256         /* Return with SIGIO, SIGCHLD */
  257         int sig = sigtimedwait(&run->global->exe.waitSigSet, NULL, &ts /* 0.1s */);
  258         if (sig == -1 && (errno != EAGAIN && errno != EINTR)) {
  259             PLOG_F("sigwaitinfo(SIGIO|SIGCHLD)");
  260         }
  261 
  262         if (sig != SIGIO && arch_checkWait(run)) {
  263             run->pid = 0;
  264             break;
  265         }
  266         if (run->global->socketFuzzer.enabled) {
  267             // Do not wait for new events
  268             break;
  269         }
  270     }
  271 
  272     arch_perfAnalyze(run);
  273 }
  274 
  275 bool arch_archInit(honggfuzz_t* hfuzz) {
  276     /* Make %'d work */
  277     setlocale(LC_NUMERIC, "en_US.UTF-8");
  278 
  279     if (access(hfuzz->exe.cmdline[0], X_OK) == -1) {
  280         PLOG_E("File '%s' doesn't seem to be executable", hfuzz->exe.cmdline[0]);
  281         return false;
  282     }
  283     if ((hfuzz->arch_linux.exeFd =
  284                 TEMP_FAILURE_RETRY(open(hfuzz->exe.cmdline[0], O_RDONLY | O_CLOEXEC))) == -1) {
  285         PLOG_E("Cannot open the executable binary: %s)", hfuzz->exe.cmdline[0]);
  286         return false;
  287     }
  288 
  289     for (;;) {
  290         __attribute__((weak)) const char* gnu_get_libc_version(void);
  291         if (!gnu_get_libc_version) {
  292             LOG_W("Unknown libc implementation. Using clone() instead of fork()");
  293             break;
  294         }
  295         const char* gversion = gnu_get_libc_version();
  296         int major, minor;
  297         if (sscanf(gversion, "%d.%d", &major, &minor) != 2) {
  298             LOG_W("Unknown glibc version:'%s'. Using clone() instead of fork()", gversion);
  299             break;
  300         }
  301         if ((major < 2) || (major == 2 && minor < 23)) {
  302             LOG_W("Your glibc version:'%s' will most likely result in malloc()-related "
  303                   "deadlocks. Min. version 2.24 (Or, Ubuntu's 2.23-0ubuntu6) suggested. "
  304                   "See https://sourceware.org/bugzilla/show_bug.cgi?id=19431 for explanation. "
  305                   "Using clone() instead of fork()",
  306                 gversion);
  307             break;
  308         }
  309         LOG_D("Glibc version:'%s', OK", gversion);
  310         hfuzz->arch_linux.useClone = false;
  311         break;
  312     }
  313 
  314     if (hfuzz->feedback.dynFileMethod != _HF_DYNFILE_NONE) {
  315         unsigned long major = 0, minor = 0;
  316         char* p = NULL;
  317 
  318         /*
  319          * Check that Linux kernel is compatible
  320          *
  321          * Compatibility list:
  322          *  1) Perf exclude_callchain_kernel requires kernel >= 3.7
  323          *     TODO: Runtime logic to disable it for unsupported kernels
  324          *           if it doesn't affect perf counters processing
  325          *  2) If 'PERF_TYPE_HARDWARE' is not supported by kernel, ENOENT
  326          *     is returned from perf_event_open(). Unfortunately, no reliable
  327          *     way to detect it here. libperf exports some list functions,
  328          *     although small guarantees it's installed. Maybe a more targeted
  329          *     message at perf_event_open() error handling will help.
  330          *  3) Intel's PT and new Intel BTS format require kernel >= 4.1
  331          */
  332         unsigned long checkMajor = 3, checkMinor = 7;
  333         if ((hfuzz->feedback.dynFileMethod & _HF_DYNFILE_BTS_EDGE) ||
  334             (hfuzz->feedback.dynFileMethod & _HF_DYNFILE_IPT_BLOCK)) {
  335             checkMajor = 4;
  336             checkMinor = 1;
  337         }
  338 
  339         struct utsname uts;
  340         if (uname(&uts) == -1) {
  341             PLOG_F("uname() failed");
  342             return false;
  343         }
  344 
  345         p = uts.release;
  346         major = strtoul(p, &p, 10);
  347         if (*p++ != '.') {
  348             LOG_F("Unsupported kernel version (%s)", uts.release);
  349             return false;
  350         }
  351 
  352         minor = strtoul(p, &p, 10);
  353         if ((major < checkMajor) || ((major == checkMajor) && (minor < checkMinor))) {
  354             LOG_E("Kernel version '%s' not supporting chosen perf method", uts.release);
  355             return false;
  356         }
  357 
  358         if (!arch_perfInit(hfuzz)) {
  359             return false;
  360         }
  361     }
  362 #if defined(__ANDROID__) && defined(__arm__) && defined(OPENSSL_ARMCAP_ABI)
  363     /*
  364      * For ARM kernels running Android API <= 21, if fuzzing target links to
  365      * libcrypto (OpenSSL), OPENSSL_cpuid_setup initialization is triggering a
  366      * SIGILL/ILLOPC at armv7_tick() due to  "mrrc p15, #1, r0, r1, c14)" instruction.
  367      * Setups using BoringSSL (API >= 22) are not affected.
  368      */
  369     if (setenv("OPENSSL_armcap", OPENSSL_ARMCAP_ABI, 1) == -1) {
  370         PLOG_E("setenv(OPENSSL_armcap) failed");
  371         return false;
  372     }
  373 #endif
  374 
  375     /* Updates the important signal array based on input args */
  376     arch_traceSignalsInit(hfuzz);
  377 
  378     if (hfuzz->arch_linux.cloneFlags && unshare(hfuzz->arch_linux.cloneFlags) == -1) {
  379         LOG_E("unshare(%tx)", hfuzz->arch_linux.cloneFlags);
  380         return false;
  381     }
  382 
  383     return true;
  384 }
  385 
  386 bool arch_archThreadInit(run_t* run) {
  387     run->arch_linux.perfMmapBuf = NULL;
  388     run->arch_linux.perfMmapAux = NULL;
  389     run->arch_linux.cpuInstrFd = -1;
  390     run->arch_linux.cpuBranchFd = -1;
  391     run->arch_linux.cpuIptBtsFd = -1;
  392 
  393     if (prctl(PR_SET_CHILD_SUBREAPER, 1UL, 0UL, 0UL, 0UL) == -1) {
  394         PLOG_W("prctl(PR_SET_CHILD_SUBREAPER, 1)");
  395     }
  396 
  397     return true;
  398 }