예제 #1
0
bool arch_prepareParent(honggfuzz_t * hfuzz)
{
    if (!hfuzz->pid) {
        return true;
    }
#define MAX_THREAD_IN_TASK 4096
    int tasks[MAX_THREAD_IN_TASK + 1];
    tasks[MAX_THREAD_IN_TASK] = 0;
    if (!arch_listThreads(tasks, MAX_THREAD_IN_TASK, hfuzz->pid)) {
        LOGMSG(l_ERROR, "Couldn't read thread list for pid '%d'", hfuzz->pid);
        return false;
    }

    for (int i = 0; i < MAX_THREAD_IN_TASK && tasks[i]; i++) {
        if (ptrace(PT_ATTACH, tasks[i], NULL, NULL) == -1) {
            LOGMSG_P(l_ERROR, "Couldn't ptrace() ATTACH to pid: %d", tasks[i]);
            return false;
        }

        int status;
        while (waitpid(tasks[i], &status, WUNTRACED | __WALL) != tasks[i]) ;

        if (ptrace(PT_CONTINUE, tasks[i], NULL, NULL) == -1) {
            LOGMSG_P(l_ERROR, "Couldn't ptrace() CONTINUE pid: %d", tasks[i]);
            ptrace(PT_DETACH, tasks[i], 0, SIGCONT);
            return false;
        }

        LOGMSG(l_INFO, "Successfully attached to pid/tid: %d", tasks[i]);
    }
    return true;
}
예제 #2
0
bool arch_ptraceAttach(pid_t pid)
{
#define MAX_THREAD_IN_TASK 4096
    int tasks[MAX_THREAD_IN_TASK + 1];
    tasks[MAX_THREAD_IN_TASK] = 0;
    if (!arch_listThreads(tasks, MAX_THREAD_IN_TASK, pid)) {
        LOGMSG(l_ERROR, "Couldn't read thread list for pid '%d'", pid);
        return false;
    }

    for (int i = 0; i < MAX_THREAD_IN_TASK && tasks[i]; i++) {
        if (ptrace
            (PTRACE_SEIZE, tasks[i], NULL,
             PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXIT) ==
            -1) {
            LOGMSG_P(l_ERROR, "Couldn't ptrace(PTRACE_SEIZE) to pid: %d", tasks[i]);
            return false;
        }
        LOGMSG(l_DEBUG, "Successfully attached to pid/tid: %d", tasks[i]);
    }
    for (int i = 0; i < MAX_THREAD_IN_TASK && tasks[i]; i++) {
        ptrace(PT_CONTINUE, tasks[i], NULL, NULL);
    }
    return true;
}
예제 #3
0
static bool arch_bfdInit(pid_t pid, bfd_t * bfdParams)
{
    char fname[PATH_MAX];
    snprintf(fname, sizeof(fname), "/proc/%d/exe", pid);
    if ((bfdParams->bfdh = bfd_openr(fname, 0)) == NULL) {
        LOGMSG(l_ERROR, "bfd_openr(%s) failed", fname);
        return false;
    }

    if (!bfd_check_format(bfdParams->bfdh, bfd_object)) {
        LOGMSG(l_ERROR, "bfd_check_format() failed");
        return false;
    }

    int storage_needed = bfd_get_symtab_upper_bound(bfdParams->bfdh);
    if (storage_needed <= 0) {
        LOGMSG(l_ERROR, "bfd_get_symtab_upper_bound() returned '%d'", storage_needed);
        return false;
    }

    if ((bfdParams->syms = (asymbol **) malloc(storage_needed)) == NULL) {
        LOGMSG_P(l_ERROR, "malloc(%d) failed", storage_needed);
        return false;
    }
    bfd_canonicalize_symtab(bfdParams->bfdh, bfdParams->syms);

    if ((bfdParams->section = bfd_get_section_by_name(bfdParams->bfdh, ".text")) == NULL) {
        LOGMSG(l_ERROR, "bfd_get_section_by_name('.text') failed");
        return false;
    }

    return true;
}
예제 #4
0
static bool arch_listThreads(int tasks[], size_t thrSz, int pid)
{
    size_t count = 0;
    char path[512];
    snprintf(path, sizeof(path), "/proc/%d/task", pid);
    DIR *dir = opendir(path);
    if (!dir) {
        LOGMSG_P(l_ERROR, "Couldn't open dir '%s'", path);
        return false;
    }

    for (;;) {
        struct dirent de, *res;
        if (readdir_r(dir, &de, &res) > 0) {
            LOGMSG_P(l_ERROR, "Couldn't read contents of '%s'", path);
            closedir(dir);
            return false;
        }

        if (res == NULL) {
            break;
        }

        pid_t pid = (pid_t) strtol(res->d_name, (char **)NULL, 10);
        if (pid == 0) {
            LOGMSG(l_DEBUG, "The following dir entry couldn't be converted to pid_t '%s'",
                   res->d_name);
            continue;
        }

        tasks[count++] = pid;
        LOGMSG(l_DEBUG, "Added pid '%d' from '%s/%s'", pid, path, res->d_name);

        if (count >= thrSz) {
            break;
        }
    }
    closedir(dir);
    LOGMSG_P(l_DEBUG, "Total number of threads in pid '%d': '%d'", pid, count);
    tasks[count + 1] = 0;
    if (count < 1) {
        return false;
    }
    return true;
}
예제 #5
0
파일: arch.c 프로젝트: zhuyue1314/honggfuzz
void arch_reapChild(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
{
    timer_t timerid;
    if (arch_setTimer(&timerid) == false) {
        LOGMSG(l_FATAL, "Couldn't set timer");
    }

    int perfFd[3];
    if (hfuzz->pid == 0) {
        int status;
        pid_t pid = wait4(fuzzer->pid, &status, __WNOTHREAD | __WALL | WUNTRACED, NULL);
        if (pid != pid) {
            LOGMSG(l_FATAL, "wait4() =! pid (%d)", fuzzer->pid);
        }
        if (!WIFSTOPPED(status)) {
            LOGMSG(l_FATAL, "PID '%d' is not in a stopped state", fuzzer->pid);
        }
        if (arch_ptraceAttach(fuzzer->pid) == false) {
            LOGMSG(l_FATAL, "Couldn't attach to pid %d", fuzzer->pid);
        }
        if (arch_perfEnable(fuzzer->pid, hfuzz, perfFd) == false) {
            LOGMSG(l_FATAL, "Couldn't enable perf counters for pid %d", fuzzer->pid);
        }
        arch_ptraceAnalyze(hfuzz, status, fuzzer->pid, fuzzer);
    }

    for (;;) {
        int status;
        pid_t pid = wait3(&status, __WNOTHREAD | __WALL | WUNTRACED, NULL);

        LOGMSG(l_DEBUG, "PID '%d' returned with status '%d'", pid, status);

        if (pid == -1 && errno == EINTR) {
            arch_checkTimeLimit(hfuzz, fuzzer);
            continue;
        }
        if (pid == -1 && errno == ECHILD) {
            if (hfuzz->pid == 0) {
                arch_perfAnalyze(hfuzz, fuzzer, perfFd);
            }
            LOGMSG(l_DEBUG, "No more processes to track");
            arch_removeTimer(&timerid);
            return;
        }
        if (pid == -1) {
            LOGMSG_P(l_FATAL, "wait3() failed");
        }

        if (hfuzz->pid == 0) {
            uint64_t tmp = arch_ptraceGetCustomPerf(hfuzz, pid);
            if (tmp != 0ULL) {
                fuzzer->branchCnt[3] = tmp;
            }
            arch_ptraceAnalyze(hfuzz, status, pid, fuzzer);
        }
    }
}
예제 #6
0
/*
 * Returns true if a process exited (so, presumably, we can delete an input
 * file)
 */
static bool arch_analyzePtrace(honggfuzz_t * hfuzz, pid_t pid, int status)
{
    /*
     * It's our child which fuzzess our process (that we had attached to) finished
     */
    int idx = HF_SLOT(hfuzz, pid);
    if (hfuzz->pid && idx != -1) {
        if (WIFEXITED(status) || WIFSIGNALED(status)) {
            LOGMSG_P(l_DEBUG, "Process pid: %d finished");
            return true;
        } else {
            return false;
        }
    }

    /*
     * If it's an uninteresting signal (even SIGTRAP), let it run and relay the
     * signal (if not SIGTRAP)
     */
    if (WIFSTOPPED(status) && !arch_sigs[WSTOPSIG(status)].important) {
        int sig = WSTOPSIG(status) == SIGTRAP ? 0 : WSTOPSIG(status);
        ptrace(PT_CONTINUE, pid, 0, sig);
        return false;
    }

    /*
     * If it's an interesting signal, save the testcase, and detach
     * the tracer (relay the signal as well)
     */
    if (WIFSTOPPED(status) && arch_sigs[WSTOPSIG(status)].important) {
        arch_savePtraceData(hfuzz, pid, status);
        ptrace(PT_CONTINUE, pid, 0, WSTOPSIG(status));
        return false;
    }

    /*
     * Resumed by delivery of SIGCONT
     */
    if (WIFCONTINUED(status)) {
        return false;
    }

    /*
     * Process exited
     */
    if (WIFEXITED(status) || WIFSIGNALED(status)) {
        if (hfuzz->pid && pid == hfuzz->pid) {
            LOGMSG(l_WARN, "Monitored process PID: %d finished", pid);
            exit(EXIT_SUCCESS);
        }
        return true;
    }

    abort();                    /* NOTREACHED */
    return true;
}
예제 #7
0
static bool arch_enablePtrace(honggfuzz_t * hfuzz)
{
    // We're fuzzing an external process, so just return true
    if (hfuzz->pid) {
        return true;
    }

    if (ptrace(PT_TRACE_ME, 0, 0, 0) == -1) {
        LOGMSG_P(l_FATAL, "Couldn't attach ptrace to pid %d", getpid());
        return false;
    }

    return true;
}
예제 #8
0
static void fuzz_runNext(honggfuzz_t * hfuzz)
{
    int i = HF_SLOT(hfuzz, 0);

    fuzz_getFileName(hfuzz, hfuzz->fuzzers[i].fileName);

    pid_t pid = fork();

    if (pid == -1) {
        LOGMSG_P(l_FATAL, "Couldn't fork");
        exit(EXIT_FAILURE);
    }

    if (!pid) {
        /*
         *  We've forked, other pid's might have the same rnd seeds now,
         *  reinitialize it
         */
        util_rndInit();

        hfuzz->fuzzers[i].pid = getpid();

        if (hfuzz->externalCommand != NULL) {
            if (!fuzz_prepareFileExternally(hfuzz, hfuzz->fuzzers[i].fileName)) {
                exit(EXIT_FAILURE);
            }
        } else {
            if (!fuzz_prepareFile(hfuzz, hfuzz->fuzzers[i].fileName)) {
                exit(EXIT_FAILURE);
            }
        }

        /*
         * Ok, kill the parent
         */
        if (!arch_launchChild(hfuzz, hfuzz->fuzzers[i].fileName)) {
            kill(getppid(), SIGTERM);
            exit(EXIT_FAILURE);
        }
    }

    hfuzz->threadsCnt++;
    hfuzz->fuzzers[i].pid = pid;

    LOGMSG(l_INFO, "Launched new process, pid: %d, (%d/%d)", pid,
           hfuzz->threadsCnt, hfuzz->threadsMax);
    return;
}
예제 #9
0
bool util_redirectStdin(char *inputFile)
{
    int fd = open(inputFile, O_RDONLY);

    if (fd == -1) {
        LOGMSG_P(l_ERROR, "Couldn't open '%s'", inputFile);
        return false;
    }

    dup2(fd, 0);
    if (fd != 0) {
        close(fd);
    }

    return true;
}
예제 #10
0
void util_nullifyStdio(void)
{
    int fd = open("/dev/null", O_RDWR);

    if (fd == -1) {
        LOGMSG_P(l_ERROR, "Couldn't open '/dev/null'");
        return;
    }

    dup2(fd, 0);
    dup2(fd, 1);
    dup2(fd, 2);

    if (fd > 2) {
        close(fd);
    }

    return;
}
예제 #11
0
static size_t arch_getProcMem(pid_t pid, uint8_t * buf, size_t len, void *pc)
{
    /*
     * len must be aligned to the sizeof(long)
     */
    int cnt = len / sizeof(long);
    size_t memsz = 0;

    for (int x = 0; x < cnt; x++) {
        uint8_t *addr = (uint8_t *) pc + (int)(x * sizeof(long));
        long ret = ptrace(PT_READ_D, pid, addr, NULL);

        if (errno != 0) {
            LOGMSG_P(l_WARN, "Couldn't PT_READ_D on pid %d, addr: %p", pid, addr);
            break;
        }

        memsz += sizeof(long);
        memcpy(&buf[x * sizeof(long)], &ret, sizeof(long));
    }
    return memsz;
}
예제 #12
0
static bool fuzz_prepareFile(honggfuzz_t * hfuzz, char *fileName)
{
    int rnd_index = util_rndGet(0, hfuzz->fileCnt - 1);
    off_t fileSz;
    int srcfd;

    uint8_t *buf = files_mapFileToRead(hfuzz->files[rnd_index], &fileSz, &srcfd);
    if (buf == NULL) {
        LOGMSG(l_ERROR, "Couldn't open and map '%s' in R/O mode", hfuzz->files[rnd_index]);
        return false;
    }

    LOGMSG(l_DEBUG, "Mmaped '%s' in R/O mode, size: %d", hfuzz->files[rnd_index], fileSz);

    int dstfd = open(fileName, O_CREAT | O_EXCL | O_RDWR, 0644);
    if (dstfd == -1) {
        LOGMSG_P(l_ERROR, "Couldn't create a temporary file '%s' in the current directory",
                 fileName);
        munmap(buf, fileSz);
        close(srcfd);
        return false;
    }

    fuzz_mangleContent(hfuzz, buf, fileSz);

    if (!files_writeToFd(dstfd, buf, fileSz)) {
        munmap(buf, fileSz);
        close(srcfd);
        close(dstfd);
        return false;
    }

    munmap(buf, fileSz);
    close(srcfd);
    close(dstfd);
    return true;
}
예제 #13
0
static size_t arch_getProcMem(pid_t pid, uint8_t * buf, size_t len, REG_TYPE pc)
{
    /*
     * Let's try process_vm_readv first
     */
    const struct iovec local_iov = {
        .iov_base = buf,
        .iov_len = len,
    };
    const struct iovec remote_iov = {
        .iov_base = (void *)(uintptr_t) pc,
        .iov_len = len,
    };
    if (process_vm_readv(pid, &local_iov, 1, &remote_iov, 1, 0) == (ssize_t) len) {
        return len;
    }
    // Debug if failed since it shouldn't happen very often
    LOGMSG_P(l_DEBUG, "process_vm_readv() failed");

    /*
     * Ok, let's do it via ptrace() then.
     * len must be aligned to the sizeof(long)
     */
    int cnt = len / sizeof(long);
    size_t memsz = 0;

    for (int x = 0; x < cnt; x++) {
        uint8_t *addr = (uint8_t *) (uintptr_t) pc + (int)(x * sizeof(long));
        long ret = ptrace(PT_READ_D, pid, addr, NULL);

        if (errno != 0) {
            LOGMSG_P(l_WARN, "Couldn't PT_READ_D on pid %d, addr: %p", pid, addr);
            break;
        }

        memsz += sizeof(long);
        memcpy(&buf[x * sizeof(long)], &ret, sizeof(long));
    }
    return memsz;
}

// Non i386 / x86_64 ISA fail build due to unused pid argument
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
uint64_t arch_ptraceGetCustomPerf(honggfuzz_t * hfuzz, pid_t pid)
{
    if ((hfuzz->dynFileMethod & _HF_DYNFILE_CUSTOM) == 0) {
        return 0ULL;
    }
#if defined(__i386__) || defined(__x86_64__)
    HEADERS_STRUCT regs;
    struct iovec pt_iov = {
        .iov_base = &regs,
        .iov_len = sizeof(regs),
    };

    if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &pt_iov) == -1L) {
        LOGMSG_P(l_DEBUG, "ptrace(PTRACE_GETREGSET) failed");

        // If PTRACE_GETREGSET fails, try PTRACE_GETREGS if available
#if PTRACE_GETREGS_AVAILABLE
        if (ptrace(PTRACE_GETREGS, pid, 0, &regs)) {
            LOGMSG_P(l_DEBUG, "ptrace(PTRACE_GETREGS) failed");
            LOGMSG(l_WARN, "ptrace PTRACE_GETREGSET & PTRACE_GETREGS failed to"
                   " extract target registers");
            return 0ULL;
        }
#else
        return 0ULL;
#endif
    }

    /*
     * 32-bit
     */
    if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
        struct user_regs_struct_32 *r32 = (struct user_regs_struct_32 *)&regs;
        return (uint64_t) r32->gs;
    }

    /*
     * 64-bit
     */
    if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
        struct user_regs_struct_64 *r64 = (struct user_regs_struct_64 *)&regs;
        return (uint64_t) r64->gs_base;
    }

    LOGMSG(l_WARN, "Unknown registers structure size: '%d'", pt_iov.iov_len);
#endif                          /* defined(__i386__) || defined(__x86_64__) */

    return 0ULL;
}

#pragma GCC diagnostic pop      /* ignored "-Wunused-parameter" */

static size_t arch_getPC(pid_t pid, REG_TYPE * pc, REG_TYPE * status_reg)
{
    HEADERS_STRUCT regs;
    struct iovec pt_iov = {
        .iov_base = &regs,
        .iov_len = sizeof(regs),
    };

    if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &pt_iov) == -1L) {
        LOGMSG_P(l_DEBUG, "ptrace(PTRACE_GETREGSET) failed");

        // If PTRACE_GETREGSET fails, try PTRACE_GETREGS if available
#if PTRACE_GETREGS_AVAILABLE
        if (ptrace(PTRACE_GETREGS, pid, 0, &regs)) {
            LOGMSG_P(l_DEBUG, "ptrace(PTRACE_GETREGS) failed");
            LOGMSG(l_WARN, "ptrace PTRACE_GETREGSET & PTRACE_GETREGS failed to"
                   " extract target registers");
            return 0;
        }
#else
        return 0;
#endif
    }
#if defined(__i386__) || defined(__x86_64__)
    /*
     * 32-bit
     */
    if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
        struct user_regs_struct_32 *r32 = (struct user_regs_struct_32 *)&regs;
        *pc = r32->eip;
        *status_reg = r32->eflags;
        return pt_iov.iov_len;
    }

    /*
     * 64-bit
     */
    if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
        struct user_regs_struct_64 *r64 = (struct user_regs_struct_64 *)&regs;
        *pc = r64->ip;
        *status_reg = r64->flags;
        return pt_iov.iov_len;
    }
    LOGMSG(l_WARN, "Unknown registers structure size: '%d'", pt_iov.iov_len);
    return 0;
#endif                          /* defined(__i386__) || defined(__x86_64__) */

#if defined(__arm__) || defined(__aarch64__)
    /*
     * 32-bit
     */
    if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
        struct user_regs_struct_32 *r32 = (struct user_regs_struct_32 *)&regs;
#ifdef __ANDROID__
        *pc = r32->ARM_pc;
        *status_reg = r32->ARM_cpsr;
#else
        *pc = r32->uregs[ARM_pc];
        *status_reg = r32->uregs[ARM_cpsr];
#endif
        return pt_iov.iov_len;
    }

    /*
     * 64-bit
     */
    if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
        struct user_regs_struct_64 *r64 = (struct user_regs_struct_64 *)&regs;
        *pc = r64->pc;
        *status_reg = r64->pstate;
        return pt_iov.iov_len;
    }
    LOGMSG(l_WARN, "Unknown registers structure size: '%d'", pt_iov.iov_len);
    return 0;
#endif                          /* defined(__arm__) || defined(__aarch64__) */

#if defined(__powerpc64__) || defined(__powerpc__)
    /*
     * 32-bit
     */
    if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
        struct user_regs_struct_32 *r32 = (struct user_regs_struct_32 *)&regs;
        *pc = r32->nip;
        return pt_iov.iov_len;
    }

    /*
     * 64-bit
     */
    if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
        struct user_regs_struct_64 *r64 = (struct user_regs_struct_64 *)&regs;
        *pc = r64->nip;
        return pt_iov.iov_len;
    }

    LOGMSG(l_WARN, "Unknown registers structure size: '%d'", pt_iov.iov_len);
    return 0;
#endif                          /* defined(__powerpc64__) || defined(__powerpc__) */

    LOGMSG(l_DEBUG, "Unknown/unsupported CPU architecture");
    return 0;
}

static void arch_getInstrStr(pid_t pid, REG_TYPE * pc, char *instr)
{
    /*
     * We need a value aligned to 8
     * which is sizeof(long) on 64bit CPU archs (on most of them, I hope;)
     */
    uint8_t buf[MAX_INSTR_SZ];
    size_t memsz;
    REG_TYPE status_reg = 0;

    snprintf(instr, _HF_INSTR_SZ, "%s", "[UNKNOWN]");

    size_t pcRegSz = arch_getPC(pid, pc, &status_reg);
    if (!pcRegSz) {
        LOGMSG(l_WARN, "Current architecture not supported for disassembly");
        return;
    }

    if ((memsz = arch_getProcMem(pid, buf, sizeof(buf), *pc)) == 0) {
        snprintf(instr, _HF_INSTR_SZ, "%s", "[NOT_MMAPED]");
        return;
    }
#if !defined(__ANDROID__)
    arch_bfdDisasm(pid, buf, memsz, instr);
#else
    cs_arch arch;
    cs_mode mode;
#if defined(__arm__) || defined(__aarch64__)
    arch = (pcRegSz == sizeof(struct user_regs_struct_64)) ? CS_ARCH_ARM64 : CS_ARCH_ARM;
    if (arch == CS_ARCH_ARM) {
        mode = (status_reg & 0x20) ? CS_MODE_THUMB : CS_MODE_ARM;
    } else {
        mode = CS_MODE_ARM;
    }
#elif defined(__i386__) || defined(__x86_64__)
    arch = CS_ARCH_X86;
    mode = (pcRegSz == sizeof(struct user_regs_struct_64)) ? CS_MODE_64 : CS_MODE_32;
#else
    LOGMSG(l_ERROR, "Unknown/unsupported Android CPU architecture");
#endif

    csh handle;
    cs_err err = cs_open(arch, mode, &handle);
    if (err != CS_ERR_OK) {
        LOGMSG(l_WARN, "Capstone initialization failed: '%s'", cs_strerror(err));
        return;
    }

    cs_insn *insn;
    size_t count = cs_disasm(handle, buf, sizeof(buf), *pc, 0, &insn);

    if (count < 1) {
        LOGMSG(l_WARN, "Couldn't disassemble the assembler instructions' stream: '%s'",
               cs_strerror(cs_errno(handle)));
        cs_close(&handle);
        return;
    }

    snprintf(instr, _HF_INSTR_SZ, "%s %s", insn[0].mnemonic, insn[0].op_str);
    cs_free(insn, count);
    cs_close(&handle);
#endif

    for (int x = 0; instr[x] && x < _HF_INSTR_SZ; x++) {
        if (instr[x] == '/' || instr[x] == '\\' || isspace(instr[x])
            || !isprint(instr[x])) {
            instr[x] = '_';
        }
    }

    return;
}

static void
arch_ptraceGenerateReport(pid_t pid, fuzzer_t * fuzzer, funcs_t * funcs,
                          size_t funcCnt, siginfo_t * si, const char *instr)
{
    fuzzer->report[0] = '\0';
    util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "ORIG_FNAME: %s\n",
                   fuzzer->origFileName);
    util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "FUZZ_FNAME: %s\n", fuzzer->fileName);
    util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "PID: %d\n", pid);
    util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "SIGNAL: %s (%d)\n",
                   arch_sigs[si->si_signo].descr, si->si_signo);
    util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "FAULT ADDRESS: %p\n", si->si_addr);
    util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "INSTRUCTION: %s\n", instr);
    util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "STACK:\n");
    for (size_t i = 0; i < funcCnt; i++) {
#ifdef __HF_USE_CAPSTONE__
        util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), " <" REG_PD REG_PM "> ",
                       (REG_TYPE) (long)funcs[i].pc, funcs[i].func, funcs[i].line);
        if (funcs[i].func[0] != '\0')
            util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "[%s + 0x%x]\n",
                           funcs[i].func, funcs[i].line);
        else
            util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "[]\n");
#else
        util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), " <" REG_PD REG_PM "> [%s():%u]\n",
                       (REG_TYPE) (long)funcs[i].pc, funcs[i].func, funcs[i].line);
#endif
    }

// libunwind is not working for 32bit targets in 64bit systems
#if defined(__aarch64__)
    if (funcCnt == 0) {
        util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), " !ERROR: If 32bit fuzz target"
                       " in aarch64 system, try ARM 32bit build\n");
    }
#endif

    return;
}
예제 #14
0
static bool fuzz_prepareFileExternally(honggfuzz_t * hfuzz, char *fileName)
{
    int rnd_index = util_rndGet(0, hfuzz->fileCnt - 1);
    off_t fileSz;
    int srcfd;

    int dstfd = open(fileName, O_CREAT | O_EXCL | O_RDWR, 0644);
    if (dstfd == -1) {
        LOGMSG_P(l_ERROR, "Couldn't create a temporary file '%s' in the current directory",
                 fileName);
        return false;
    }

    LOGMSG(l_DEBUG, "Created '%f' as an input file", fileName);

    if (hfuzz->inputFile) {
        uint8_t *buf = files_mapFileToRead(hfuzz->files[rnd_index], &fileSz, &srcfd);
        if (buf == NULL) {
            LOGMSG(l_ERROR, "Couldn't open and map '%s' in R/O mode", hfuzz->files[rnd_index]);
            close(dstfd);
            return false;
        }

        LOGMSG(l_DEBUG, "Mmaped '%s' in R/O mode, size: %d", hfuzz->files[rnd_index], fileSz);

        bool ret = files_writeToFd(dstfd, buf, fileSz);
        munmap(buf, fileSz);
        close(srcfd);

        if (!ret) {
            close(dstfd);
            return false;
        }
    }

    close(dstfd);

    pid_t pid = fork();
    if (pid == -1) {
        LOGMSG_P(l_ERROR, "Couldn't fork");
        return false;
    }

    if (!pid) {
        /*
         * child does the external file modifications
         */
        execl(hfuzz->externalCommand, hfuzz->externalCommand, fileName, NULL);
        LOGMSG_P(l_FATAL, "Couldn't execute '%s %s'", hfuzz->externalCommand, fileName);
        return false;
    } else {
        /*
         * parent waits until child is done fuzzing the input file
         */

        int childStatus;
        pid_t terminatedPid;
        do {
            terminatedPid = wait(&childStatus);
        } while (terminatedPid != pid);

        if (WIFEXITED(childStatus)) {
            LOGMSG(l_DEBUG, "External command exited with status %d", WEXITSTATUS(childStatus));
            return true;
        } else if (WIFSIGNALED(childStatus)) {
            LOGMSG(l_ERROR, "External command terminated  with signal %d", WTERMSIG(childStatus));
            return false;
        }
        LOGMSG(l_FATAL, "External command terminated abnormally, status: %d", childStatus);
        return false;
    }

    abort();                    /* NOTREACHED */
}
예제 #15
0
int main(int argc, char **argv)
{
    int c;
    int ll = l_INFO;
    honggfuzz_t hfuzz;

    hfuzz.inputFile = NULL;
    hfuzz.nullifyStdio = false;
    hfuzz.fuzzStdin = false;
    hfuzz.saveUnique = false;
    hfuzz.fileExtn = "fuzz";
    hfuzz.flipRate = 0.001f;
    hfuzz.flipMode = 'B';
    hfuzz.fuzzStart = 0;
    hfuzz.fuzzEnd = UINT_MAX;
    hfuzz.externalCommand = NULL;
    hfuzz.tmOut = 3;
    hfuzz.ignoreAddr = (void *)0UL;
    hfuzz.threadsMax = 5;
    hfuzz.asLimit = 0UL;
    hfuzz.cmdline = NULL;
    hfuzz.pid = 0;

    hfuzz.files = NULL;
    hfuzz.threadsCnt = 0;

    printf(AB PROG_NAME " version " PROG_VERSION "\n" PROG_AUTHORS AC "\n");
    if (argc < 2) {
        usage();
        exit(EXIT_SUCCESS);
    }

    for (;;) {
        c = getopt(argc, argv, "hqsuf:d:e:r:m:c:t:a:n:l:p:b:w:");
        if (c < 0)
            break;

        switch (c) {
        case 'f':
            hfuzz.inputFile = optarg;
            break;
        case 'h':
            usage();
            break;
        case 'q':
            hfuzz.nullifyStdio = true;
            break;
        case 's':
            hfuzz.fuzzStdin = true;
            break;
        case 'u':
            hfuzz.saveUnique = true;
            break;
        case 'd':
            ll = atoi(optarg);
            break;
        case 'e':
            hfuzz.fileExtn = optarg;
            break;
        case 'r':
            hfuzz.flipRate = atof(optarg);
            break;
        case 'm':
            hfuzz.flipMode = optarg[0];
            break;
        case 'c':
            hfuzz.externalCommand = optarg;
            break;
        case 't':
            hfuzz.tmOut = atol(optarg);
            break;
        case 'a':
            hfuzz.ignoreAddr = (void *)atol(optarg);
            break;
        case 'n':
            hfuzz.threadsMax = atol(optarg);
            break;
        case 'l':
            hfuzz.asLimit = strtoul(optarg, NULL, 10);
            break;
        case 'p':
            hfuzz.pid = atoi(optarg);
            break;
        case 'b':
            hfuzz.fuzzStart = strtoul(optarg, NULL, 10);
            break;
        case 'w':
            hfuzz.fuzzEnd = strtoul(optarg, NULL, 10);
            break;
        default:
            break;
        }
    }
    hfuzz.cmdline = &argv[optind];

    util_rndInit();
    log_setMinLevel(ll);

    if (!hfuzz.cmdline[0]) {
        LOGMSG(l_FATAL, "Please specify binary to fuzz");
        usage();
    }

    if (!hfuzz.fuzzStdin && !checkFor_FILE_PLACEHOLDER(hfuzz.cmdline)) {
        LOGMSG(l_FATAL,
               "You must specify '" FILE_PLACEHOLDER
               "' when the -s (stdin fuzzing) option is not set");
        usage();
    }

    if (hfuzz.pid) {
        LOGMSG(l_INFO, "External PID specified, concurrency disabled");
        hfuzz.threadsMax = 1;
    }

    if (strchr(hfuzz.fileExtn, '/')) {
        LOGMSG(l_FATAL, "The file extension contains the '/' character: '%s'", hfuzz.fileExtn);
        usage();
    }

    if (hfuzz.fuzzStart > hfuzz.fuzzEnd || hfuzz.fuzzStart == hfuzz.fuzzEnd) {
        LOGMSG(l_FATAL, "Invalid mangle fuzz area file offsets");
        usage();
    }

    LOGMSG(l_INFO,
           "debugLevel: %d, inputFile '%s', nullifyStdio: %d, fuzzStdin: %d, saveUnique: %d, flipRate: %lf, "
           "flipMode: '%c', externalCommand: '%s', tmOut: %ld, threadsMax: %ld, fileExtn '%s', ignoreAddr: %p, "
           "memoryLimit: %lu (MiB), fuzzExe: '%s', fuzzedPid: %d",
           ll, hfuzz.inputFile, hfuzz.nullifyStdio ? 1 : 0,
           hfuzz.fuzzStdin ? 1 : 0, hfuzz.saveUnique ? 1 : 0, hfuzz.flipRate, hfuzz.flipMode,
           hfuzz.externalCommand == NULL ? "NULL" : hfuzz.externalCommand, hfuzz.tmOut,
           hfuzz.threadsMax, hfuzz.fileExtn, hfuzz.ignoreAddr, hfuzz.asLimit, hfuzz.cmdline[0],
           hfuzz.pid);

    if (!(hfuzz.fuzzers = malloc(sizeof(hfuzz.fuzzers[0]) * hfuzz.threadsMax))) {
        LOGMSG_P(l_FATAL, "Couldn't allocate memory");
        exit(EXIT_FAILURE);
    }
    memset(hfuzz.fuzzers, '\0', sizeof(hfuzz.fuzzers[0]) * hfuzz.threadsMax);

    if (!files_init(&hfuzz)) {
        LOGMSG(l_FATAL, "Couldn't load input files");
        exit(EXIT_FAILURE);
    }

    /*
     * So far so good
     */
    fuzz_main(&hfuzz);

    abort();                    /* NOTREACHED */
    return EXIT_SUCCESS;
}
예제 #16
0
static void arch_savePtraceData(honggfuzz_t * hfuzz, pid_t pid, int status)
{
    void *pc = NULL;

    char instr[MAX_OP_STRING] = "[UNKNOWN]";
    siginfo_t si;

    if (ptrace(PT_GETSIGINFO, pid, 0, &si) == -1) {
        LOGMSG_P(l_WARN, "Couldn't get siginfo for pid %d", pid);
        return;
    }

    struct user_regs_struct regs;
    if (ptrace(PT_GETREGS, pid, NULL, &regs) == -1) {
        LOGMSG(l_ERROR, "Couldn't get CPU registers");
    }
#ifdef __i386__
    pc = (void *)regs.eip;
    arch_getX86InstrStr(pid, instr, pc);
#endif                          /* __i386__ */
#ifdef __x86_64__
    pc = (void *)regs.rip;
    arch_getX86InstrStr(pid, instr, pc);
#endif                          /* __x86_64__ */

    LOGMSG(l_DEBUG,
           "Pid: %d, signo: %d, errno: %d, code: %d, addr: %p, pc: %p, instr: '%s'",
           pid, si.si_signo, si.si_errno, si.si_code, si.si_addr, pc, instr);

    int idx = HF_SLOT(hfuzz, pid);

    // If we're checkign state of an external process, then the idx is 0 (cause
    // there's no concurrency)
    if (hfuzz->pid) {
        idx = 0;
    }

    if (si.si_addr < hfuzz->ignoreAddr) {
        LOGMSG(l_INFO,
               "'%s' is interesting (%s), but the si.si_addr is %p (below %p), skipping",
               hfuzz->fuzzers[idx].fileName, arch_sigs[si.si_signo].descr, si.si_addr,
               hfuzz->ignoreAddr);
        return;
    }

    char newname[PATH_MAX];
    if (hfuzz->saveUnique) {
        snprintf(newname, sizeof(newname),
                 "%s.PC.%p.CODE.%d.ADDR.%p.INSTR.%s.%s.%s",
                 arch_sigs[si.si_signo].descr, pc, si.si_code, si.si_addr, instr,
                 hfuzz->fuzzers[idx].origFileName, hfuzz->fileExtn);
    } else {
        char localtmstr[PATH_MAX];
        util_getLocalTime("%F.%H.%M.%S", localtmstr, sizeof(localtmstr));
        snprintf(newname, sizeof(newname), "%s.PC.%p.CODE.%d.ADDR.%p.INSTR.%s.%s.%d.%s.%s",
                 arch_sigs[si.si_signo].descr, pc, si.si_code, si.si_addr, instr, localtmstr, pid,
                 hfuzz->fuzzers[idx].origFileName, hfuzz->fileExtn);
    }

    if (link(hfuzz->fuzzers[idx].fileName, newname) == 0) {
        LOGMSG(l_INFO, "Ok, that's interesting, saved '%s' as '%s'",
               hfuzz->fuzzers[idx].fileName, newname);
    } else {
        if (errno == EEXIST) {
            LOGMSG(l_INFO, "It seems that '%s' already exists, skipping", newname);
        } else {
            LOGMSG_P(l_ERROR, "Couldn't link '%s' to '%s'", hfuzz->fuzzers[idx].fileName, newname);
        }
    }
}
예제 #17
0
bool arch_launchChild(honggfuzz_t * hfuzz, char *fileName)
{
    if (!arch_enablePtrace(hfuzz)) {
        return false;
    }
#ifdef __linux__
#include <sys/prctl.h>
#include <sys/personality.h>
    /*
     * Kill a process (with ABRT) which corrupts its own heap
     */
    if (setenv("MALLOC_CHECK_", "3", 1) == -1) {
        LOGMSG_P(l_ERROR, "setenv(MALLOC_CHECK_=3) failed");
        return false;
    }

    /*
     * Kill the children when fuzzer dies (e.g. due to Ctrl+C)
     */
    if (prctl(PR_SET_PDEATHSIG, (long)SIGKILL, 0L, 0L, 0L) == -1) {
        LOGMSG_P(l_ERROR, "prctl(PR_SET_PDEATHSIG, SIGKILL) failed");
        return false;
    }

    /*
     * Disable ASLR
     */
    if (personality(ADDR_NO_RANDOMIZE) == -1) {
        LOGMSG_P(l_ERROR, "personality(ADDR_NO_RANDOMIZE) failed");
        return false;
    }
#endif                          /* __linux__ */

#define ARGS_MAX 512
    char *args[ARGS_MAX + 2];

    int x;
    char *pCurArg = NULL;
    char argData[PATH_MAX] = { 0 };

    for (x = 0; x < ARGS_MAX && hfuzz->cmdline[x]; x++) {
        pCurArg = hfuzz->cmdline[x];
        if (!hfuzz->fuzzStdin && strcmp(pCurArg, FILE_PLACEHOLDER) == 0) {
            args[x] = fileName;
        } else if (!hfuzz->fuzzStdin && strstr(pCurArg, CON_FILE_PLACEHOLDER) != NULL) {
            const char *off = strstr(hfuzz->cmdline[x], CON_FILE_PLACEHOLDER);
            snprintf(argData, PATH_MAX, "%.*s=%s", (off - pCurArg), pCurArg, fileName);
            args[x] = argData;
        } else {
            args[x] = hfuzz->cmdline[x];
        }
    }

    args[x++] = NULL;

    LOGMSG(l_DEBUG, "Launching '%s' on file '%s'", args[0], fileName);

    /*
     * Set timeout (prof), real timeout (2*prof), and rlimit_cpu (2*prof)
     */
    if (hfuzz->tmOut) {
        struct itimerval it;

        /*
         * The hfuzz->tmOut is real CPU usage time...
         */
        it.it_value.tv_sec = hfuzz->tmOut;
        it.it_value.tv_usec = 0;
        it.it_interval.tv_sec = 0;
        it.it_interval.tv_usec = 0;
        if (setitimer(ITIMER_PROF, &it, NULL) == -1) {
            LOGMSG_P(l_ERROR, "Couldn't set the ITIMER_PROF timer");
            return false;
        }

        /*
         * ...so, if a process sleeps, this one should
         * trigger a signal...
         */
        it.it_value.tv_sec = hfuzz->tmOut * 2UL;
        it.it_value.tv_usec = 0;
        it.it_interval.tv_sec = 0;
        it.it_interval.tv_usec = 0;
        if (setitimer(ITIMER_REAL, &it, NULL) == -1) {
            LOGMSG_P(l_ERROR, "Couldn't set the ITIMER_REAL timer");
            return false;
        }

        /*
         * ..if a process sleeps and catches SIGPROF/SIGALRM
         * rlimits won't help either
         */
        struct rlimit rl;

        rl.rlim_cur = hfuzz->tmOut * 2;
        rl.rlim_max = hfuzz->tmOut * 2;
        if (setrlimit(RLIMIT_CPU, &rl) == -1) {
            LOGMSG_P(l_ERROR, "Couldn't enforce the RLIMIT_CPU resource limit");
            return false;
        }
    }

    /*
     * The address space limit. If big enough - roughly the size of RAM used
     */
    if (hfuzz->asLimit) {
        struct rlimit rl;

        rl.rlim_cur = hfuzz->asLimit * 1024UL * 1024UL;
        rl.rlim_max = hfuzz->asLimit * 1024UL * 1024UL;
        if (setrlimit(RLIMIT_AS, &rl) == -1) {
            LOGMSG_P(l_DEBUG, "Couldn't encforce the RLIMIT_AS resource limit, ignoring");
        }
    }

    if (hfuzz->nullifyStdio) {
        util_nullifyStdio();
    }

    if (hfuzz->fuzzStdin) {
        /* Uglyyyyyy ;) */
        if (!util_redirectStdin(fileName)) {
            return false;
        }
    }

    execvp(args[0], args);

    util_recoverStdio();
    LOGMSG(l_FATAL, "Failed to create new '%s' process", args[0]);
    return false;
}
예제 #18
0
bool arch_launchChild(honggfuzz_t * hfuzz, char *fileName)
{
    /*
     * Kill a process which corrupts its own heap (with ABRT)
     */
    if (setenv("MALLOC_CHECK_", "3", 1) == -1) {
        LOGMSG_P(l_ERROR, "setenv(MALLOC_CHECK_=3) failed");
        return false;
    }

    /*
     * Tell asan to ignore SEGVs
     */
    if (setenv
        ("ASAN_OPTIONS",
         "allow_user_segv_handler=1:handle_segv=0:abort_on_error=1:allocator_may_return_null=1",
         1) == -1) {
        LOGMSG_P(l_ERROR, "setenv(ASAN_OPTIONS) failed");
        return false;
    }

    /*
     * Kill the children when fuzzer dies (e.g. due to Ctrl+C)
     */
    if (prctl(PR_SET_PDEATHSIG, (long)SIGKILL, 0L, 0L, 0L) == -1) {
        LOGMSG_P(l_ERROR, "prctl(PR_SET_PDEATHSIG, SIGKILL) failed");
        return false;
    }

    /*
     * Disable ASLR
     */
    if (personality(ADDR_NO_RANDOMIZE) == -1) {
        LOGMSG_P(l_ERROR, "personality(ADDR_NO_RANDOMIZE) failed");
        return false;
    }
#define ARGS_MAX 512
    char *args[ARGS_MAX + 2];

    int x;

    for (x = 0; x < ARGS_MAX && hfuzz->cmdline[x]; x++) {
        if (!hfuzz->fuzzStdin && strcmp(hfuzz->cmdline[x], _HF_FILE_PLACEHOLDER) == 0) {
            args[x] = fileName;
        } else {
            args[x] = hfuzz->cmdline[x];
        }
    }

    args[x++] = NULL;

    LOGMSG(l_DEBUG, "Launching '%s' on file '%s'", args[0], fileName);

    /*
     * Set timeout (prof), real timeout (2*prof), and rlimit_cpu (2*prof)
     */
    if (hfuzz->tmOut) {
        /* 
         * Set the CPU rlimit to twice the value of the time-out
         */
        struct rlimit rl = {
            .rlim_cur = hfuzz->tmOut * 2,
            .rlim_max = hfuzz->tmOut * 2,
        };
        if (setrlimit(RLIMIT_CPU, &rl) == -1) {
            LOGMSG_P(l_ERROR, "Couldn't enforce the RLIMIT_CPU resource limit");
            return false;
        }
    }

    /*
     * The address space limit. If big enough - roughly the size of RAM used
     */
    if (hfuzz->asLimit) {
        struct rlimit rl = {
            .rlim_cur = hfuzz->asLimit * 1024UL * 1024UL,
            .rlim_max = hfuzz->asLimit * 1024UL * 1024UL,
        };
        if (setrlimit(RLIMIT_AS, &rl) == -1) {
            LOGMSG_P(l_DEBUG, "Couldn't encforce the RLIMIT_AS resource limit, ignoring");
        }
    }

    for (size_t i = 0; i < ARRAYSIZE(hfuzz->envs) && hfuzz->envs[i]; i++) {
        putenv(hfuzz->envs[i]);
    }

    if (hfuzz->nullifyStdio) {
        util_nullifyStdio();
    }

    if (hfuzz->fuzzStdin) {
        /*
         * Uglyyyyyy ;)
         */
        if (!util_redirectStdin(fileName)) {
            return false;
        }
    }
    /*
     * Wait for the ptrace to attach
     */
    syscall(__NR_tkill, syscall(__NR_gettid), SIGSTOP);
    execvp(args[0], args);

    util_recoverStdio();
    LOGMSG(l_FATAL, "Failed to create new '%s' process", args[0]);
    return false;
}

static void arch_sigFunc(int signo, siginfo_t * si, void *dummy)
{
    if (signo != SIGALRM) {
        LOGMSG(l_ERROR, "Signal != SIGALRM (%d)", signo);
    }
    return;
    if (si == NULL) {
        return;
    }
    if (dummy == NULL) {
        return;
    }
}

static void arch_removeTimer(timer_t * timerid)
{
    timer_delete(*timerid);
}

static bool arch_setTimer(timer_t * timerid)
{
    struct sigevent sevp = {
        .sigev_value.sival_ptr = timerid,
        .sigev_signo = SIGALRM,
        .sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL,
        ._sigev_un._tid = syscall(__NR_gettid),
    };
    if (timer_create(CLOCK_REALTIME, &sevp, timerid) == -1) {
        LOGMSG_P(l_ERROR, "timer_create(CLOCK_REALTIME) failed");
        return false;
    }
    /* 
     * Kick in every 200ms, starting with the next second
     */
    const struct itimerspec ts = {
        .it_value = {.tv_sec = 1,.tv_nsec = 0},
        .it_interval = {.tv_sec = 0,.tv_nsec = 200000000,},
    };
    if (timer_settime(*timerid, 0, &ts, NULL) == -1) {
        LOGMSG_P(l_ERROR, "timer_settime() failed");
        timer_delete(*timerid);
        return false;
    }
    sigset_t smask;
    sigemptyset(&smask);
    struct sigaction sa = {
        .sa_handler = NULL,
        .sa_sigaction = arch_sigFunc,
        .sa_mask = smask,
        .sa_flags = SA_SIGINFO,
        .sa_restorer = NULL,
    };
    if (sigaction(SIGALRM, &sa, NULL) == -1) {
        LOGMSG_P(l_ERROR, "sigaciton(SIGALRM) failed");
        return false;
    }

    return true;
}

static void arch_checkTimeLimit(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
{
    int64_t curMillis = util_timeNowMillis();
    int64_t diffMillis = curMillis - fuzzer->timeStartedMillis;
    if (diffMillis > (hfuzz->tmOut * 1000)) {
        LOGMSG(l_WARN, "PID %d took too much time (limit %ld s). Sending SIGKILL",
               fuzzer->pid, hfuzz->tmOut);
        kill(fuzzer->pid, SIGKILL);
    }
}
예제 #19
0
static bool fuzz_prepareFileExternally(honggfuzz_t * hfuzz, fuzzer_t * fuzzer, int rnd_index)
{
    int dstfd = open(fuzzer->fileName, O_CREAT | O_EXCL | O_RDWR, 0644);
    if (dstfd == -1) {
        LOGMSG_P(l_ERROR, "Couldn't create a temporary file '%s' in the current directory",
                 fuzzer->fileName);
        return false;
    }

    LOGMSG(l_DEBUG, "Created '%f' as an input file", fuzzer->fileName);

    if (hfuzz->inputFile) {
        size_t fileSz =
            files_readFileToBufMax(hfuzz->files[rnd_index], fuzzer->dynamicFile, hfuzz->maxFileSz);
        if (fileSz == 0UL) {
            LOGMSG(l_ERROR, "Couldn't read '%s'", hfuzz->files[rnd_index]);
            unlink(fuzzer->fileName);
            return false;
        }

        if (files_writeToFd(dstfd, fuzzer->dynamicFile, fileSz) == false) {
            close(dstfd);
            unlink(fuzzer->fileName);
            return false;
        }
    }

    close(dstfd);

    pid_t pid = fork();
    if (pid == -1) {
        LOGMSG_P(l_ERROR, "Couldn't vfork");
        return false;
    }

    if (!pid) {
        /*
         * child performs the external file modifications
         */
        execl(hfuzz->externalCommand, hfuzz->externalCommand, fuzzer->fileName, NULL);
        LOGMSG_P(l_FATAL, "Couldn't execute '%s %s'", hfuzz->externalCommand, fuzzer->fileName);
        return false;
    }

    /*
     * parent waits until child is done fuzzing the input file
     */
    int childStatus;
    int flags = 0;
#if defined(__WNOTHREAD)
    flags |= __WNOTHREAD;
#endif                          /* defined(__WNOTHREAD) */
    while (wait4(pid, &childStatus, flags, NULL) != pid) ;
    if (WIFEXITED(childStatus)) {
        LOGMSG(l_DEBUG, "External command exited with status %d", WEXITSTATUS(childStatus));
        return true;
    }
    if (WIFSIGNALED(childStatus)) {
        LOGMSG(l_ERROR, "External command terminated with signal %d", WTERMSIG(childStatus));
        return false;
    }
    LOGMSG(l_FATAL, "External command terminated abnormally, status: %d", childStatus);
    return false;

    abort();                    /* NOTREACHED */
}
예제 #20
0
static void arch_ptraceSaveData(honggfuzz_t * hfuzz, pid_t pid, fuzzer_t * fuzzer)
{
    __sync_fetch_and_add(&hfuzz->crashesCnt, 1UL);
    REG_TYPE pc = 0;

    char instr[_HF_INSTR_SZ] = "\x00";
    siginfo_t si;
    bzero(&si, sizeof(si));

    if (ptrace(PT_GETSIGINFO, pid, 0, &si) == -1) {
        LOGMSG_P(l_WARN, "Couldn't get siginfo for pid %d", pid);
    }

    arch_getInstrStr(pid, &pc, instr);

    LOGMSG(l_DEBUG,
           "Pid: %d, signo: %d, errno: %d, code: %d, addr: %p, pc: %"
           REG_PM ", instr: '%s'", pid, si.si_signo, si.si_errno, si.si_code, si.si_addr, pc,
           instr);

    if (si.si_addr < hfuzz->ignoreAddr) {
        LOGMSG(l_INFO,
               "'%s' is interesting (%s), but the si.si_addr is %p (below %p), skipping",
               fuzzer->fileName, arch_sigs[si.si_signo].descr, si.si_addr, hfuzz->ignoreAddr);
        return;
    }

    char newname[PATH_MAX];
    if (hfuzz->saveUnique) {
        snprintf(newname, sizeof(newname),
                 "%s.PC.%" REG_PM ".CODE.%d.ADDR.%p.INSTR.%s.%s",
                 arch_sigs[si.si_signo].descr, pc, si.si_code, si.si_addr, instr, hfuzz->fileExtn);
    } else {
        char localtmstr[PATH_MAX];
        util_getLocalTime("%F.%H:%M:%S", localtmstr, sizeof(localtmstr), time(NULL));
        snprintf(newname, sizeof(newname),
                 "%s.PC.%" REG_PM ".CODE.%d.ADDR.%p.INSTR.%s.%s.%d.%s",
                 arch_sigs[si.si_signo].descr, pc, si.si_code, si.si_addr,
                 instr, localtmstr, pid, hfuzz->fileExtn);
    }

    if (link(fuzzer->fileName, newname) == 0) {
        LOGMSG(l_INFO, "Ok, that's interesting, saved '%s' as '%s'", fuzzer->fileName, newname);
    } else {
        if (errno == EEXIST) {
            LOGMSG(l_INFO, "It seems that '%s' already exists, skipping", newname);
            // Don't bother unwinding & generating reports for duplicate crashes
            return;
        } else {
            LOGMSG_P(l_ERROR, "Couldn't link '%s' to '%s'", fuzzer->fileName, newname);
        }
    }

    funcs_t funcs[_HF_MAX_FUNCS] = {
        [0 ... (_HF_MAX_FUNCS - 1)].pc = NULL,
        [0 ... (_HF_MAX_FUNCS - 1)].line = 0,
        [0 ... (_HF_MAX_FUNCS - 1)].func = {'\0'}
        ,
    };

#if !defined(__ANDROID__)
    size_t funcCnt = arch_unwindStack(pid, funcs);
    arch_bfdResolveSyms(pid, funcs, funcCnt);
#else
    size_t funcCnt = arch_unwindStack(pid, funcs);
#endif

    arch_ptraceGenerateReport(pid, fuzzer, funcs, funcCnt, &si, instr);
}