diff options
Diffstat (limited to 'libhfcommon')
-rw-r--r-- | libhfcommon/common.h | 54 | ||||
-rw-r--r-- | libhfcommon/files.c | 421 | ||||
-rw-r--r-- | libhfcommon/files.h | 67 | ||||
-rw-r--r-- | libhfcommon/log.c | 160 | ||||
-rw-r--r-- | libhfcommon/log.h | 92 | ||||
-rw-r--r-- | libhfcommon/ns.c | 127 | ||||
-rw-r--r-- | libhfcommon/ns.h | 38 | ||||
-rw-r--r-- | libhfcommon/util.c | 647 | ||||
-rw-r--r-- | libhfcommon/util.h | 125 |
9 files changed, 1731 insertions, 0 deletions
diff --git a/libhfcommon/common.h b/libhfcommon/common.h new file mode 100644 index 00000000..6423548c --- /dev/null +++ b/libhfcommon/common.h @@ -0,0 +1,54 @@ +/* + * + * honggfuzz - core macros and helpers + * ----------------------------------------- + * + * Author: Robert Swiecki <swiecki@google.com> + * + * Copyright 2010-2017 by Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + * + */ + +#ifndef _HF_COMMON_H_ +#define _HF_COMMON_H_ + +#include <stdlib.h> +#include <unistd.h> + +#ifndef UNUSED +#define UNUSED __attribute__((unused)) +#endif /* ifndef UNUSED */ + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x) / sizeof(*x)) +#endif /* ifndef ARRAYSIZE */ + +/* Memory barriers */ +#define rmb() __asm__ __volatile__("" ::: "memory") +#define wmb() __sync_synchronize() + +/* TEMP_FAILURE_RETRY, but for all OSes */ +#ifndef TEMP_FAILURE_RETRY +#define TEMP_FAILURE_RETRY(exp) \ + ({ \ + typeof(exp) _rc; \ + do { \ + _rc = (exp); \ + } while (_rc == -1 && errno == EINTR); \ + _rc; \ + }) +#endif /* ifndef TEMP_FAILURE_RETRY */ + +#endif /* ifndef _HF_COMMON_H_ */ diff --git a/libhfcommon/files.c b/libhfcommon/files.c new file mode 100644 index 00000000..7dab9920 --- /dev/null +++ b/libhfcommon/files.c @@ -0,0 +1,421 @@ +/* + * + * honggfuzz - file operations + * ----------------------------------------- + * + * Author: Robert Swiecki <swiecki@google.com> + * + * Copyright 2010-2015 by Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + * + */ + +#include "libhfcommon/files.h" + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/socket.h> +#include <sys/stat.h> +#if defined(_HF_ARCH_LINUX) +#include <sys/syscall.h> +#endif /* defined(_HF_ARCH_LINUX) */ +#include <sys/types.h> +#include <unistd.h> + +#include "libhfcommon/common.h" +#include "libhfcommon/log.h" +#include "libhfcommon/util.h" + +ssize_t files_readFileToBufMax(char* fileName, uint8_t* buf, size_t fileMaxSz) { + int fd = open(fileName, O_RDONLY | O_CLOEXEC); + if (fd == -1) { + PLOG_W("Couldn't open '%s' for R/O", fileName); + return -1; + } + + ssize_t readSz = files_readFromFd(fd, buf, fileMaxSz); + if (readSz < 0) { + LOG_W("Couldn't read '%s' to a buf", fileName); + } + close(fd); + + LOG_D("Read '%zu' bytes from '%s'", readSz, fileName); + return readSz; +} + +bool files_writeBufToFile(const char* fileName, const uint8_t* buf, size_t fileSz, int flags) { + int fd = open(fileName, flags, 0644); + if (fd == -1) { + PLOG_W("Couldn't open '%s' for R/W", fileName); + return false; + } + + bool ret = files_writeToFd(fd, buf, fileSz); + if (ret == false) { + PLOG_W("Couldn't write '%zu' bytes to file '%s' (fd='%d')", fileSz, fileName, fd); + unlink(fileName); + } else { + LOG_D("Written '%zu' bytes to '%s'", fileSz, fileName); + } + + close(fd); + return ret; +} + +bool files_writeToFd(int fd, const uint8_t* buf, size_t fileSz) { + size_t writtenSz = 0; + while (writtenSz < fileSz) { + ssize_t sz = write(fd, &buf[writtenSz], fileSz - writtenSz); + if (sz < 0 && errno == EINTR) continue; + + if (sz < 0) return false; + + writtenSz += sz; + } + return true; +} + +bool files_writeStrToFd(int fd, const char* str) { + return files_writeToFd(fd, (const uint8_t*)str, strlen(str)); +} + +ssize_t files_readFromFd(int fd, uint8_t* buf, size_t fileSz) { + size_t readSz = 0; + while (readSz < fileSz) { + ssize_t sz = read(fd, &buf[readSz], fileSz - readSz); + if (sz < 0 && errno == EINTR) continue; + + if (sz == 0) break; + + if (sz < 0) return -1; + + readSz += sz; + } + return (ssize_t)readSz; +} + +bool files_exists(const char* fileName) { return (access(fileName, F_OK) != -1); } + +bool files_writePatternToFd(int fd, off_t size, unsigned char p) { + void* buf = malloc(size); + if (!buf) { + PLOG_W("Couldn't allocate memory"); + return false; + } + + memset(buf, p, (size_t)size); + int ret = files_writeToFd(fd, buf, size); + free(buf); + + return ret; +} + +bool files_sendToSocketNB(int fd, const uint8_t* buf, size_t fileSz) { + size_t writtenSz = 0; + while (writtenSz < fileSz) { + ssize_t sz = send(fd, &buf[writtenSz], fileSz - writtenSz, MSG_DONTWAIT); + if (sz < 0 && errno == EINTR) continue; + + if (sz < 0) return false; + + writtenSz += sz; + } + return true; +} + +bool files_sendToSocket(int fd, const uint8_t* buf, size_t fileSz) { + int sendFlags = 0; +#ifdef _HF_ARCH_DARWIN + sendFlags |= SO_NOSIGPIPE; +#else + sendFlags |= MSG_NOSIGNAL; +#endif + + size_t writtenSz = 0; + while (writtenSz < fileSz) { + ssize_t sz = send(fd, &buf[writtenSz], fileSz - writtenSz, sendFlags); + if (sz < 0 && errno == EINTR) continue; + + if (sz < 0) return false; + + writtenSz += sz; + } + return true; +} + +const char* files_basename(const char* path) { + const char* base = strrchr(path, '/'); + return base ? base + 1 : path; +} + +/* + * dstExists argument can be used by caller for cases where existing destination + * file requires special handling (e.g. save unique crashes) + */ +bool files_copyFile(const char* source, const char* destination, bool* dstExists, bool try_link) { + if (dstExists) { + *dstExists = false; + } + + if (try_link) { + if (link(source, destination) == 0) { + return true; + } else { + if (errno == EEXIST) { + // Should kick-in before MAC, so avoid the hassle + if (dstExists) *dstExists = true; + return false; + } else { + PLOG_D("Couldn't link '%s' as '%s'", source, destination); + /* + * Don't fail yet as we might have a running env which doesn't allow + * hardlinks (e.g. SELinux) + */ + } + } + } + // Now try with a verbose POSIX alternative + int inFD, outFD, dstOpenFlags; + mode_t dstFilePerms; + + // O_EXCL is important for saving unique crashes + dstOpenFlags = O_CREAT | O_WRONLY | O_CLOEXEC | O_EXCL; + dstFilePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + + inFD = open(source, O_RDONLY | O_CLOEXEC); + if (inFD == -1) { + PLOG_D("Couldn't open '%s' source", source); + return false; + } + + struct stat inSt; + if (fstat(inFD, &inSt) == -1) { + PLOG_W("Couldn't fstat(fd='%d' fileName='%s')", inFD, source); + close(inFD); + return false; + } + + outFD = open(destination, dstOpenFlags, dstFilePerms); + if (outFD == -1) { + if (errno == EEXIST) { + if (dstExists) *dstExists = true; + } + PLOG_D("Couldn't open '%s' destination", destination); + close(inFD); + return false; + } + + uint8_t* inFileBuf = malloc(inSt.st_size); + if (!inFileBuf) { + PLOG_W("malloc(%zu) failed", (size_t)inSt.st_size); + close(inFD); + close(outFD); + return false; + } + + ssize_t readSz = files_readFromFd(inFD, inFileBuf, (size_t)inSt.st_size); + if (readSz < 0) { + PLOG_W("Couldn't read '%s' to a buf", source); + free(inFileBuf); + close(inFD); + close(outFD); + return false; + } + + if (files_writeToFd(outFD, inFileBuf, readSz) == false) { + PLOG_W("Couldn't write '%zu' bytes to file '%s' (fd='%d')", (size_t)readSz, destination, + outFD); + unlink(destination); + free(inFileBuf); + close(inFD); + close(outFD); + return false; + } + + free(inFileBuf); + close(inFD); + close(outFD); + return true; +} + +/* + * Reads symbols from src file (one per line) and append them to filterList. The + * total number of added symbols is returned. + * + * Simple wildcard strings are also supported (e.g. mem*) + */ +size_t files_parseSymbolFilter(const char* srcFile, char*** filterList) { + FILE* f = fopen(srcFile, "rb"); + if (f == NULL) { + PLOG_W("Couldn't open '%s' - R/O mode", srcFile); + return 0; + } + + char* lineptr = NULL; + size_t symbolsRead = 0, n = 0; + for (;;) { + if (getline(&lineptr, &n, f) == -1) { + break; + } + + if (strlen(lineptr) < 3) { + LOG_F("Input symbol '%s' too short (strlen < 3)", lineptr); + symbolsRead = 0; + break; + } + if ((*filterList = (char**)util_Realloc( + *filterList, (symbolsRead + 1) * sizeof((*filterList)[0]))) == NULL) { + PLOG_W("realloc failed (sz=%zu)", (symbolsRead + 1) * sizeof((*filterList)[0])); + symbolsRead = 0; + break; + } + (*filterList)[symbolsRead] = malloc(strlen(lineptr)); + if (!(*filterList)[symbolsRead]) { + PLOG_E("malloc(%zu) failed", strlen(lineptr)); + symbolsRead = 0; + break; + } + strncpy((*filterList)[symbolsRead], lineptr, strlen(lineptr)); + symbolsRead++; + } + + LOG_I("%zu filter symbols added to list", symbolsRead); + fclose(f); + free(lineptr); + return symbolsRead; +} + +uint8_t* files_mapFile(const char* fileName, off_t* fileSz, int* fd, bool isWritable) { + int mmapProt = PROT_READ; + if (isWritable) { + mmapProt |= PROT_WRITE; + } + + if ((*fd = open(fileName, O_RDONLY)) == -1) { + PLOG_W("Couldn't open() '%s' file in R/O mode", fileName); + return NULL; + } + + struct stat st; + if (fstat(*fd, &st) == -1) { + PLOG_W("Couldn't stat() the '%s' file", fileName); + close(*fd); + return NULL; + } + + uint8_t* buf; + if ((buf = mmap(NULL, st.st_size, mmapProt, MAP_PRIVATE, *fd, 0)) == MAP_FAILED) { + PLOG_W("Couldn't mmap() the '%s' file", fileName); + close(*fd); + return NULL; + } + + *fileSz = st.st_size; + return buf; +} + +uint8_t* files_mapFileShared(const char* fileName, off_t* fileSz, int* fd) { + if ((*fd = open(fileName, O_RDONLY)) == -1) { + PLOG_W("Couldn't open() '%s' file in R/O mode", fileName); + return NULL; + } + + struct stat st; + if (fstat(*fd, &st) == -1) { + PLOG_W("Couldn't stat() the '%s' file", fileName); + close(*fd); + return NULL; + } + + uint8_t* buf; + if ((buf = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, *fd, 0)) == MAP_FAILED) { + PLOG_W("Couldn't mmap() the '%s' file", fileName); + close(*fd); + return NULL; + } + + *fileSz = st.st_size; + return buf; +} + +void* files_mapSharedMem(size_t sz, int* fd, const char* dir) { + *fd = -1; +#if defined(_HF_ARCH_LINUX) && defined(__NR_memfd_create) +#if !defined(MFD_CLOEXEC) /* It's not defined as we didn't include sys/memfd.h, but it's \ + present with some Linux distros only */ +#define MFD_CLOEXEC 0x0001U +#endif /* !defined(MFD_CLOEXEC) */ + *fd = syscall(__NR_memfd_create, "honggfuzz", (uintptr_t)MFD_CLOEXEC); +#endif /* defined(_HF_ARCH_LINUX) && defined(__NR_memfd_create) */ + if (*fd == -1) { + char template[PATH_MAX]; + snprintf(template, sizeof(template), "%s/hfuzz.XXXXXX", dir); + if ((*fd = mkstemp(template)) == -1) { + PLOG_W("mkstemp('%s')", template); + return MAP_FAILED; + } + unlink(template); + } + if (ftruncate(*fd, sz) == -1) { + PLOG_W("ftruncate(%d, %zu)", *fd, sz); + close(*fd); + *fd = -1; + return MAP_FAILED; + } + void* ret = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0); + if (ret == MAP_FAILED) { + PLOG_W("mmap(sz=%zu, fd=%d)", sz, *fd); + *fd = -1; + close(*fd); + return MAP_FAILED; + } + return ret; +} + +bool files_readPidFromFile(const char* fileName, pid_t* pidPtr) { + FILE* fPID = fopen(fileName, "rbe"); + if (fPID == NULL) { + PLOG_W("Couldn't open '%s' - R/O mode", fileName); + return false; + } + + char* lineptr = NULL; + size_t lineSz = 0; + ssize_t ret = getline(&lineptr, &lineSz, fPID); + fclose(fPID); + if (ret == -1) { + if (lineSz == 0) { + LOG_W("Empty PID file (%s)", fileName); + fclose(fPID); + free(lineptr); + return false; + } + } + + *pidPtr = atoi(lineptr); + free(lineptr); + if (*pidPtr < 1) { + LOG_W("Invalid PID read from '%s' file", fileName); + return false; + } + + return true; +} diff --git a/libhfcommon/files.h b/libhfcommon/files.h new file mode 100644 index 00000000..674941fc --- /dev/null +++ b/libhfcommon/files.h @@ -0,0 +1,67 @@ +/* + * + * honggfuzz - file operations + * ----------------------------------------- + * + * Author: Robert Swiecki <swiecki@google.com> + * + * Copyright 2010-2015 by Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + * + */ + +#ifndef _HF_COMMON_FILES_H_ +#define _HF_COMMON_FILES_H_ + +#include "common.h" + +#include <stdbool.h> +#include <stdint.h> +#include <unistd.h> + +extern ssize_t files_readFileToBufMax(char* fileName, uint8_t* buf, size_t fileMaxSz); + +extern bool files_writeBufToFile( + const char* fileName, const uint8_t* buf, size_t fileSz, int flags); + +extern bool files_writeToFd(int fd, const uint8_t* buf, size_t fileSz); + +extern bool files_writeStrToFd(int fd, const char* str); + +extern ssize_t files_readFromFd(int fd, uint8_t* buf, size_t fileSz); + +extern bool files_writePatternToFd(int fd, off_t size, unsigned char p); + +bool files_sendToSocketNB(int fd, const uint8_t* buf, size_t fileSz); + +bool files_sendToSocket(int fd, const uint8_t* buf, size_t fileSz); + +extern bool files_exists(const char* fileName); + +extern const char* files_basename(const char* path); + +extern bool files_copyFile( + const char* source, const char* destination, bool* dstExists, bool try_link); + +extern uint8_t* files_mapFile(const char* fileName, off_t* fileSz, int* fd, bool isWritable); + +extern uint8_t* files_mapFileShared(const char* fileName, off_t* fileSz, int* fd); + +extern void* files_mapSharedMem(size_t sz, int* fd, const char* dir); + +extern bool files_readPidFromFile(const char* fileName, pid_t* pidPtr); + +extern size_t files_parseSymbolFilter(const char* inFIle, char*** filterList); + +#endif /* ifndef HF_COMMON_FILES */ diff --git a/libhfcommon/log.c b/libhfcommon/log.c new file mode 100644 index 00000000..2e627728 --- /dev/null +++ b/libhfcommon/log.c @@ -0,0 +1,160 @@ +/* + + nsjail - logging + ----------------------------------------- + + Copyright 2014 Google Inc. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +#include "libhfcommon/log.h" + +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <limits.h> +#include <pthread.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +#include "libhfcommon/common.h" +#include "libhfcommon/util.h" + +#if defined(_HF_ARCH_LINUX) +#include <sys/syscall.h> +#define __hf_pid() (pid_t) syscall(__NR_gettid) +#else /* defined(_HF_ARCH_LINUX) */ +#define __hf_pid() getpid() +#endif /* defined(_HF_ARCH_LINUX) */ + +static int log_fd = STDERR_FILENO; +static bool log_fd_isatty = false; +enum llevel_t log_level = INFO; +static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER; + +__attribute__((constructor)) static void log_init(void) { + log_level = INFO; + log_fd = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 0); + if (log_fd == -1) { + log_fd = STDERR_FILENO; + } + log_fd_isatty = isatty(log_fd); +} + +/* + * Log to stderr by default. Use a dup()d fd, because in the future we'll associate the + * connection socket with fd (0, 1, 2). + */ +bool logInitLogFile(const char* logfile, enum llevel_t ll) { + log_level = ll; + + if (logfile == NULL) { + return true; + } + + log_fd = open(logfile, O_CREAT | O_RDWR | O_TRUNC, 0640); + if (log_fd == -1) { + log_fd = STDERR_FILENO; + PLOG_E("Couldn't open logfile open('%s')", logfile); + return false; + } + log_fd_isatty = (isatty(log_fd) == 1 ? true : false); + return true; +} + +void logLog(enum llevel_t ll, const char* fn, int ln, bool perr, const char* fmt, ...) { + char strerr[512]; + if (perr == true) { + snprintf(strerr, sizeof(strerr), "%s", strerror(errno)); + } + struct ll_t { + const char* descr; + const char* prefix; + const bool print_funcline; + const bool print_time; + }; + static const struct ll_t logLevels[] = { + {"F", "\033[7;35m", true, true}, + {"E", "\033[1;31m", true, true}, + {"W", "\033[0;33m", true, true}, + {"I", "\033[1m", false, false}, + {"D", "\033[0;4m", true, true}, + {"HR", "\033[0m", false, false}, + {"HB", "\033[1m", false, false}, + }; + + time_t ltstamp = time(NULL); + struct tm utctime; + localtime_r(<stamp, &utctime); + char timestr[32]; + if (strftime(timestr, sizeof(timestr) - 1, "%FT%T%z", &utctime) == 0) { + timestr[0] = '\0'; + } + + /* Start printing logs */ + { + MX_LOCK(&log_mutex); + + if (log_fd_isatty) { + dprintf(log_fd, "%s", logLevels[ll].prefix); + } + if (logLevels[ll].print_time) { + dprintf(log_fd, "[%s][%s][%d] ", timestr, logLevels[ll].descr, __hf_pid()); + } + if (logLevels[ll].print_funcline) { + dprintf(log_fd, "%s():%d ", fn, ln); + } + + va_list args; + va_start(args, fmt); + vdprintf(log_fd, fmt, args); + va_end(args); + + if (perr == true) { + dprintf(log_fd, ": %s", strerr); + } + if (log_fd_isatty) { + dprintf(log_fd, "\033[0m"); + } + dprintf(log_fd, "\n"); + + MX_UNLOCK(&log_mutex); + } + /* End printing logs */ + + if (ll == FATAL) { + exit(1); + } +} + +void logStop(int sig) { LOG_I("Server stops due to fatal signal (%d) caught. Exiting", sig); } + +void logRedirectLogFD(int fd) { log_fd = fd; } + +void logDirectlyToFD(const char* msg) { dprintf(log_fd, "%s", msg); } + +pthread_mutex_t* logMutexGet(void) { return &log_mutex; } + +void logMutexReset(void) { pthread_mutex_init(&log_mutex, NULL); } + +bool logIsTTY(void) { return log_fd_isatty; } + +int logFd(void) { return log_fd; } diff --git a/libhfcommon/log.h b/libhfcommon/log.h new file mode 100644 index 00000000..a6c8706d --- /dev/null +++ b/libhfcommon/log.h @@ -0,0 +1,92 @@ +/* + * + * honggfuzz - logging + * ----------------------------------------- + * + * Copyright 2014 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _HF_COMMON_LOG_H_ +#define _HF_COMMON_LOG_H_ + +#include <pthread.h> +#include <stdbool.h> + +enum llevel_t { FATAL = 0, ERROR, WARNING, INFO, DEBUG, HELP, HELP_BOLD }; + +extern enum llevel_t log_level; + +#define LOG_HELP(...) logLog(HELP, __FUNCTION__, __LINE__, false, __VA_ARGS__); +#define LOG_HELP_BOLD(...) logLog(HELP_BOLD, __FUNCTION__, __LINE__, false, __VA_ARGS__); + +#define LOG_D(...) \ + if (log_level >= DEBUG) { \ + logLog(DEBUG, __FUNCTION__, __LINE__, false, __VA_ARGS__); \ + } +#define LOG_I(...) \ + if (log_level >= INFO) { \ + logLog(INFO, __FUNCTION__, __LINE__, false, __VA_ARGS__); \ + } +#define LOG_W(...) \ + if (log_level >= WARNING) { \ + logLog(WARNING, __FUNCTION__, __LINE__, false, __VA_ARGS__); \ + } +#define LOG_E(...) \ + if (log_level >= ERROR) { \ + logLog(ERROR, __FUNCTION__, __LINE__, false, __VA_ARGS__); \ + } +#define LOG_F(...) \ + if (log_level >= FATAL) { \ + logLog(FATAL, __FUNCTION__, __LINE__, false, __VA_ARGS__); \ + } + +#define PLOG_D(...) \ + if (log_level >= DEBUG) { \ + logLog(DEBUG, __FUNCTION__, __LINE__, true, __VA_ARGS__); \ + } +#define PLOG_I(...) \ + if (log_level >= INFO) { \ + logLog(INFO, __FUNCTION__, __LINE__, true, __VA_ARGS__); \ + } +#define PLOG_W(...) \ + if (log_level >= WARNING) { \ + logLog(WARNING, __FUNCTION__, __LINE__, true, __VA_ARGS__); \ + } +#define PLOG_E(...) \ + if (log_level >= ERROR) { \ + logLog(ERROR, __FUNCTION__, __LINE__, true, __VA_ARGS__); \ + } +#define PLOG_F(...) \ + if (log_level >= FATAL) { \ + logLog(FATAL, __FUNCTION__, __LINE__, true, __VA_ARGS__); \ + } + +extern bool logInitLogFile(const char* logfile, enum llevel_t ll); + +extern void logLog(enum llevel_t ll, const char* fn, int ln, bool perr, const char* fmt, ...) + __attribute__((format(printf, 5, 6))); + +extern void logStop(int sig); + +extern bool logIsTTY(void); + +extern int logFd(void); + +extern pthread_mutex_t* logMutexGet(void); + +void logMutexReset(void); + +#endif /* ifndef _HF_COMMON_LOG_H_ */ diff --git a/libhfcommon/ns.c b/libhfcommon/ns.c new file mode 100644 index 00000000..25c25f90 --- /dev/null +++ b/libhfcommon/ns.c @@ -0,0 +1,127 @@ +/* + * + * honggfuzz - namespace-related utilities + * ----------------------------------------- + * + * Author: Robert Swiecki <swiecki@google.com> + * + * Copyright 2017 by Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + * + */ + +#include "libhfcommon/ns.h" + +#include "libhfcommon/common.h" +#include "libhfcommon/files.h" +#include "libhfcommon/log.h" + +#if defined(_HF_ARCH_LINUX) + +#include <arpa/inet.h> +#include <fcntl.h> +#include <net/if.h> +#include <sched.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/mount.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> + +bool nsEnter(uintptr_t cloneFlags) { + pid_t current_uid = getuid(); + gid_t current_gid = getgid(); + + if (unshare(cloneFlags) == -1) { + PLOG_E("unshare(0x%tx)", cloneFlags); + return false; + } + + const char* deny_str = "deny"; + if (files_writeBufToFile("/proc/self/setgroups", (const uint8_t*)deny_str, strlen(deny_str), + O_WRONLY) == false) { + PLOG_E("Couldn't write to /proc/self/setgroups"); + return false; + } + + char gid_map[4096]; + snprintf(gid_map, sizeof(gid_map), "%d %d 1", (int)current_gid, (int)current_gid); + if (files_writeBufToFile( + "/proc/self/gid_map", (const uint8_t*)gid_map, strlen(gid_map), O_WRONLY) == false) { + PLOG_E("Couldn't write to /proc/self/gid_map"); + return false; + } + + char uid_map[4096]; + snprintf(uid_map, sizeof(uid_map), "%d %d 1", (int)current_uid, (int)current_uid); + if (files_writeBufToFile( + "/proc/self/uid_map", (const uint8_t*)uid_map, strlen(uid_map), O_WRONLY) == false) { + PLOG_E("Couldn't write to /proc/self/uid_map"); + return false; + } + + if (setresgid(current_gid, current_gid, current_gid) == -1) { + PLOG_E("setresgid(%d)", (int)current_gid); + return false; + } + if (setresuid(current_uid, current_uid, current_uid) == -1) { + PLOG_E("setresuid(%d)", (int)current_uid); + return false; + } + + return true; +} + +bool nsIfaceUp(const char* ifacename) { + int sock = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_IP); + if (sock == -1) { + PLOG_E("socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP)"); + return false; + } + + struct ifreq ifr; + memset(&ifr, '\0', sizeof(ifr)); + snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", ifacename); + + if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) { + PLOG_E("ioctl(iface='%s', SIOCGIFFLAGS, IFF_UP)", ifacename); + close(sock); + return false; + } + + ifr.ifr_flags |= (IFF_UP | IFF_RUNNING); + + if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) { + PLOG_E("ioctl(iface='%s', SIOCGIFFLAGS, IFF_UP)", ifacename); + close(sock); + return false; + } + + close(sock); + return true; +} + +bool nsMountTmpfs(const char* dst) { + if (mount(NULL, dst, "tmpfs", 0, NULL) == -1) { + PLOG_E("mount(dst='%s', tmpfs)", dst); + return false; + } + return true; +} + +#endif /* defined(_HF_ARCH_LINUX) */ diff --git a/libhfcommon/ns.h b/libhfcommon/ns.h new file mode 100644 index 00000000..882f7547 --- /dev/null +++ b/libhfcommon/ns.h @@ -0,0 +1,38 @@ +/* + * + * honggfuzz - namespace related utils + * ----------------------------------------- + * + * Author: Robert Swiecki <swiecki@google.com> + * + * Copyright 2017 by Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + * + */ + +#ifndef _HF_NS_H_ +#define _HF_NS_H_ + +#if defined(_HF_ARCH_LINUX) + +#include <inttypes.h> +#include <stdbool.h> + +bool nsEnter(uintptr_t cloneFlags); +bool nsIfaceUp(const char* ifacename); +bool nsMountTmpfs(const char* dst); + +#endif /* defined(_HF_ARCH_LINUX) */ + +#endif diff --git a/libhfcommon/util.c b/libhfcommon/util.c new file mode 100644 index 00000000..5745a4b2 --- /dev/null +++ b/libhfcommon/util.c @@ -0,0 +1,647 @@ +/* + * + * honggfuzz - utilities + * ----------------------------------------- + * + * Author: Robert Swiecki <swiecki@google.com> + * + * Copyright 2010-2015 by Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + * + */ + +#include "libhfcommon/util.h" + +#include <ctype.h> +#include <fcntl.h> +#include <inttypes.h> +#include <math.h> +#include <pthread.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +#include "libhfcommon/common.h" +#include "libhfcommon/files.h" +#include "libhfcommon/log.h" + +void* util_Malloc(size_t sz) { + void* p = malloc(sz); + if (p == NULL) { + LOG_F("malloc(size='%zu')", sz); + } + return p; +} + +void* util_Calloc(size_t sz) { + void* p = util_Malloc(sz); + memset(p, '\0', sz); + return p; +} + +extern void* util_Realloc(void* ptr, size_t sz) { + void* ret = realloc(ptr, sz); + if (ret == NULL) { + PLOG_W("realloc(%p, %zu)", ptr, sz); + free(ptr); + return NULL; + } + return ret; +} + +void* util_MMap(size_t sz) { + void* p = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (p == MAP_FAILED) { + LOG_F("mmap(size='%zu')", sz); + } + return p; +} + +char* util_StrDup(const char* s) { + char* ret = strdup(s); + if (ret == NULL) { + LOG_F("strdup(size=%zu)", strlen(s)); + } + return ret; +} + +static __thread pthread_once_t rndThreadOnce = PTHREAD_ONCE_INIT; +static __thread uint64_t rndState[2]; + +static void util_rndInitThread(void) { + int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); + if (fd == -1) { + PLOG_F("Couldn't open /dev/urandom for reading"); + } + if (files_readFromFd(fd, (uint8_t*)rndState, sizeof(rndState)) != sizeof(rndState)) { + PLOG_F("Couldn't read '%zu' bytes from /dev/urandom", sizeof(rndState)); + } + close(fd); +} + +/* + * xoroshiro128plus by David Blackman and Sebastiano Vigna + */ +static inline uint64_t util_RotL(const uint64_t x, int k) { return (x << k) | (x >> (64 - k)); } + +static inline uint64_t util_InternalRnd64(void) { + const uint64_t s0 = rndState[0]; + uint64_t s1 = rndState[1]; + const uint64_t result = s0 + s1; + s1 ^= s0; + rndState[0] = util_RotL(s0, 55) ^ s1 ^ (s1 << 14); + rndState[1] = util_RotL(s1, 36); + + return result; +} + +uint64_t util_rnd64(void) { + pthread_once(&rndThreadOnce, util_rndInitThread); + return util_InternalRnd64(); +} + +uint64_t util_rndGet(uint64_t min, uint64_t max) { + if (min > max) { + LOG_F("min:%" PRIu64 " > max:%" PRIu64, min, max); + } + + if (max == UINT64_MAX) { + return util_rnd64(); + } + + return ((util_rnd64() % (max - min + 1)) + min); +} + +void util_rndBuf(uint8_t* buf, size_t sz) { + pthread_once(&rndThreadOnce, util_rndInitThread); + if (sz == 0) { + return; + } + for (size_t i = 0; i < sz; i++) { + buf[i] = (uint8_t)util_InternalRnd64(); + } +} + +/* + * Function has variable length stack size, although already we know it's invoked + * with relatively small sizes (max is _HF_REPORT_SIZE), thus safe to silent warning. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wframe-larger-than=" +int util_vssnprintf(char* str, size_t size, const char* format, va_list ap) { + char buf1[size]; + char buf2[size]; + + strncpy(buf1, str, size); + + vsnprintf(buf2, size, format, ap); + + return snprintf(str, size, "%s%s", buf1, buf2); +} + +int util_ssnprintf(char* str, size_t size, const char* format, ...) { + char buf1[size]; + char buf2[size]; + + snprintf(buf1, sizeof(buf1), "%s", str); + + va_list args; + va_start(args, format); + vsnprintf(buf2, size, format, args); + va_end(args); + + return snprintf(str, size, "%s%s", buf1, buf2); +} + +#pragma GCC diagnostic pop /* EOF diagnostic ignored "-Wstack-usage=" */ + +void util_getLocalTime(const char* fmt, char* buf, size_t len, time_t tm) { + struct tm ltime; + localtime_r(&tm, <ime); + if (strftime(buf, len, fmt, <ime) < 1) { + snprintf(buf, len, "[date fetch error]"); + } +} + +void util_nullifyStdio(void) { + int fd = open("/dev/null", O_RDWR); + + if (fd == -1) { + PLOG_E("Couldn't open '/dev/null'"); + return; + } + + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + + if (fd > 2) { + close(fd); + } +} + +bool util_redirectStdin(const char* inputFile) { + int fd = open(inputFile, O_RDONLY); + + if (fd == -1) { + PLOG_W("Couldn't open '%s'", inputFile); + return false; + } + + dup2(fd, 0); + if (fd != 0) { + close(fd); + } + + return true; +} + +/* + * This is not a cryptographically secure hash + */ +uint64_t util_hash(const char* buf, size_t len) { + uint64_t ret = 0; + + for (size_t i = 0; i < len; i++) { + ret += buf[i]; + ret += (ret << 10); + ret ^= (ret >> 6); + } + + return ret; +} + +int64_t util_timeNowMillis(void) { + struct timeval tv; + if (gettimeofday(&tv, NULL) == -1) { + PLOG_F("gettimeofday()"); + } + + return (((int64_t)tv.tv_sec * 1000LL) + ((int64_t)tv.tv_usec / 1000LL)); +} + +uint64_t util_getUINT32(const uint8_t* buf) { + uint32_t r; + memcpy(&r, buf, sizeof(r)); + return (uint64_t)r; +} + +uint64_t util_getUINT64(const uint8_t* buf) { + uint64_t r; + memcpy(&r, buf, sizeof(r)); + return r; +} + +void util_mutexLock(pthread_mutex_t* mutex, const char* func, int line) { + if (pthread_mutex_lock(mutex)) { + PLOG_F("%s():%d pthread_mutex_lock(%p)", func, line, (void*)mutex); + } +} + +void util_mutexUnlock(pthread_mutex_t* mutex, const char* func, int line) { + if (pthread_mutex_unlock(mutex)) { + PLOG_F("%s():%d pthread_mutex_unlock(%p)", func, line, (void*)mutex); + } +} + +void util_mutexRWLockRead(pthread_rwlock_t* mutex, const char* func, int line) { + if (pthread_rwlock_rdlock(mutex)) { + PLOG_F("%s():%d pthread_rwlock_rdlock(%p)", func, line, (void*)mutex); + } +} + +void util_mutexRWLockWrite(pthread_rwlock_t* mutex, const char* func, int line) { + if (pthread_rwlock_wrlock(mutex)) { + PLOG_F("%s():%d pthread_rwlock_wrlock(%p)", func, line, (void*)mutex); + } +} + +void util_mutexRWUnlock(pthread_rwlock_t* mutex, const char* func, int line) { + if (pthread_rwlock_unlock(mutex)) { + PLOG_F("%s():%d pthread_rwlock_unlock(%p)", func, line, (void*)mutex); + } +} + +int64_t fastArray64Search(uint64_t* array, size_t arraySz, uint64_t key) { + size_t low = 0; + size_t high = arraySz - 1; + size_t mid; + + while (array[high] != array[low] && key >= array[low] && key <= array[high]) { + mid = low + (key - array[low]) * ((high - low) / (array[high] - array[low])); + + if (array[mid] < key) { + low = mid + 1; + } else if (key < array[mid]) { + high = mid - 1; + } else { + return mid; + } + } + + if (key == array[low]) { + return low; + } else { + return -1; + } +} + +bool util_isANumber(const char* s) { + if (!isdigit(s[0])) { + return false; + } + for (int i = 0; s[i]; s++) { + if (!isdigit(s[i]) && s[i] != 'x') { + return false; + } + } + return true; +} + +size_t util_decodeCString(char* s) { + size_t len = strlen(s); + size_t o = 0; + for (size_t i = 0; s[i] != '\0' && s[i] != '"' && i < len; i++, o++) { + switch (s[i]) { + case '\\': { + i++; + if (i >= len) { + continue; + } + switch (s[i]) { + case 'a': + s[o] = '\a'; + break; + case 'r': + s[o] = '\r'; + break; + case 'n': + s[o] = '\n'; + break; + case 't': + s[o] = '\t'; + break; + case '0': + s[o] = '\0'; + break; + case 'x': { + /* Yup, this can overflow */ + char hex[] = {s[i + 1], s[i + 2], 0}; + s[o] = strtoul(hex, NULL, 16); + i += 2; + break; + } + default: + s[o] = s[i]; + break; + } + break; + } + default: { + s[o] = s[i]; + break; + } + } + } + s[o] = '\0'; + return o; +} + +/* ISO 3309 CRC-64 Poly table */ +static const uint64_t util_CRC64ISOPoly[] = { + 0x0000000000000000ULL, + 0x01B0000000000000ULL, + 0x0360000000000000ULL, + 0x02D0000000000000ULL, + 0x06C0000000000000ULL, + 0x0770000000000000ULL, + 0x05A0000000000000ULL, + 0x0410000000000000ULL, + 0x0D80000000000000ULL, + 0x0C30000000000000ULL, + 0x0EE0000000000000ULL, + 0x0F50000000000000ULL, + 0x0B40000000000000ULL, + 0x0AF0000000000000ULL, + 0x0820000000000000ULL, + 0x0990000000000000ULL, + 0x1B00000000000000ULL, + 0x1AB0000000000000ULL, + 0x1860000000000000ULL, + 0x19D0000000000000ULL, + 0x1DC0000000000000ULL, + 0x1C70000000000000ULL, + 0x1EA0000000000000ULL, + 0x1F10000000000000ULL, + 0x1680000000000000ULL, + 0x1730000000000000ULL, + 0x15E0000000000000ULL, + 0x1450000000000000ULL, + 0x1040000000000000ULL, + 0x11F0000000000000ULL, + 0x1320000000000000ULL, + 0x1290000000000000ULL, + 0x3600000000000000ULL, + 0x37B0000000000000ULL, + 0x3560000000000000ULL, + 0x34D0000000000000ULL, + 0x30C0000000000000ULL, + 0x3170000000000000ULL, + 0x33A0000000000000ULL, + 0x3210000000000000ULL, + 0x3B80000000000000ULL, + 0x3A30000000000000ULL, + 0x38E0000000000000ULL, + 0x3950000000000000ULL, + 0x3D40000000000000ULL, + 0x3CF0000000000000ULL, + 0x3E20000000000000ULL, + 0x3F90000000000000ULL, + 0x2D00000000000000ULL, + 0x2CB0000000000000ULL, + 0x2E60000000000000ULL, + 0x2FD0000000000000ULL, + 0x2BC0000000000000ULL, + 0x2A70000000000000ULL, + 0x28A0000000000000ULL, + 0x2910000000000000ULL, + 0x2080000000000000ULL, + 0x2130000000000000ULL, + 0x23E0000000000000ULL, + 0x2250000000000000ULL, + 0x2640000000000000ULL, + 0x27F0000000000000ULL, + 0x2520000000000000ULL, + 0x2490000000000000ULL, + 0x6C00000000000000ULL, + 0x6DB0000000000000ULL, + 0x6F60000000000000ULL, + 0x6ED0000000000000ULL, + 0x6AC0000000000000ULL, + 0x6B70000000000000ULL, + 0x69A0000000000000ULL, + 0x6810000000000000ULL, + 0x6180000000000000ULL, + 0x6030000000000000ULL, + 0x62E0000000000000ULL, + 0x6350000000000000ULL, + 0x6740000000000000ULL, + 0x66F0000000000000ULL, + 0x6420000000000000ULL, + 0x6590000000000000ULL, + 0x7700000000000000ULL, + 0x76B0000000000000ULL, + 0x7460000000000000ULL, + 0x75D0000000000000ULL, + 0x71C0000000000000ULL, + 0x7070000000000000ULL, + 0x72A0000000000000ULL, + 0x7310000000000000ULL, + 0x7A80000000000000ULL, + 0x7B30000000000000ULL, + 0x79E0000000000000ULL, + 0x7850000000000000ULL, + 0x7C40000000000000ULL, + 0x7DF0000000000000ULL, + 0x7F20000000000000ULL, + 0x7E90000000000000ULL, + 0x5A00000000000000ULL, + 0x5BB0000000000000ULL, + 0x5960000000000000ULL, + 0x58D0000000000000ULL, + 0x5CC0000000000000ULL, + 0x5D70000000000000ULL, + 0x5FA0000000000000ULL, + 0x5E10000000000000ULL, + 0x5780000000000000ULL, + 0x5630000000000000ULL, + 0x54E0000000000000ULL, + 0x5550000000000000ULL, + 0x5140000000000000ULL, + 0x50F0000000000000ULL, + 0x5220000000000000ULL, + 0x5390000000000000ULL, + 0x4100000000000000ULL, + 0x40B0000000000000ULL, + 0x4260000000000000ULL, + 0x43D0000000000000ULL, + 0x47C0000000000000ULL, + 0x4670000000000000ULL, + 0x44A0000000000000ULL, + 0x4510000000000000ULL, + 0x4C80000000000000ULL, + 0x4D30000000000000ULL, + 0x4FE0000000000000ULL, + 0x4E50000000000000ULL, + 0x4A40000000000000ULL, + 0x4BF0000000000000ULL, + 0x4920000000000000ULL, + 0x4890000000000000ULL, + 0xD800000000000000ULL, + 0xD9B0000000000000ULL, + 0xDB60000000000000ULL, + 0xDAD0000000000000ULL, + 0xDEC0000000000000ULL, + 0xDF70000000000000ULL, + 0xDDA0000000000000ULL, + 0xDC10000000000000ULL, + 0xD580000000000000ULL, + 0xD430000000000000ULL, + 0xD6E0000000000000ULL, + 0xD750000000000000ULL, + 0xD340000000000000ULL, + 0xD2F0000000000000ULL, + 0xD020000000000000ULL, + 0xD190000000000000ULL, + 0xC300000000000000ULL, + 0xC2B0000000000000ULL, + 0xC060000000000000ULL, + 0xC1D0000000000000ULL, + 0xC5C0000000000000ULL, + 0xC470000000000000ULL, + 0xC6A0000000000000ULL, + 0xC710000000000000ULL, + 0xCE80000000000000ULL, + 0xCF30000000000000ULL, + 0xCDE0000000000000ULL, + 0xCC50000000000000ULL, + 0xC840000000000000ULL, + 0xC9F0000000000000ULL, + 0xCB20000000000000ULL, + 0xCA90000000000000ULL, + 0xEE00000000000000ULL, + 0xEFB0000000000000ULL, + 0xED60000000000000ULL, + 0xECD0000000000000ULL, + 0xE8C0000000000000ULL, + 0xE970000000000000ULL, + 0xEBA0000000000000ULL, + 0xEA10000000000000ULL, + 0xE380000000000000ULL, + 0xE230000000000000ULL, + 0xE0E0000000000000ULL, + 0xE150000000000000ULL, + 0xE540000000000000ULL, + 0xE4F0000000000000ULL, + 0xE620000000000000ULL, + 0xE790000000000000ULL, + 0xF500000000000000ULL, + 0xF4B0000000000000ULL, + 0xF660000000000000ULL, + 0xF7D0000000000000ULL, + 0xF3C0000000000000ULL, + 0xF270000000000000ULL, + 0xF0A0000000000000ULL, + 0xF110000000000000ULL, + 0xF880000000000000ULL, + 0xF930000000000000ULL, + 0xFBE0000000000000ULL, + 0xFA50000000000000ULL, + 0xFE40000000000000ULL, + 0xFFF0000000000000ULL, + 0xFD20000000000000ULL, + 0xFC90000000000000ULL, + 0xB400000000000000ULL, + 0xB5B0000000000000ULL, + 0xB760000000000000ULL, + 0xB6D0000000000000ULL, + 0xB2C0000000000000ULL, + 0xB370000000000000ULL, + 0xB1A0000000000000ULL, + 0xB010000000000000ULL, + 0xB980000000000000ULL, + 0xB830000000000000ULL, + 0xBAE0000000000000ULL, + 0xBB50000000000000ULL, + 0xBF40000000000000ULL, + 0xBEF0000000000000ULL, + 0xBC20000000000000ULL, + 0xBD90000000000000ULL, + 0xAF00000000000000ULL, + 0xAEB0000000000000ULL, + 0xAC60000000000000ULL, + 0xADD0000000000000ULL, + 0xA9C0000000000000ULL, + 0xA870000000000000ULL, + 0xAAA0000000000000ULL, + 0xAB10000000000000ULL, + 0xA280000000000000ULL, + 0xA330000000000000ULL, + 0xA1E0000000000000ULL, + 0xA050000000000000ULL, + 0xA440000000000000ULL, + 0xA5F0000000000000ULL, + 0xA720000000000000ULL, + 0xA690000000000000ULL, + 0x8200000000000000ULL, + 0x83B0000000000000ULL, + 0x8160000000000000ULL, + 0x80D0000000000000ULL, + 0x84C0000000000000ULL, + 0x8570000000000000ULL, + 0x87A0000000000000ULL, + 0x8610000000000000ULL, + 0x8F80000000000000ULL, + 0x8E30000000000000ULL, + 0x8CE0000000000000ULL, + 0x8D50000000000000ULL, + 0x8940000000000000ULL, + 0x88F0000000000000ULL, + 0x8A20000000000000ULL, + 0x8B90000000000000ULL, + 0x9900000000000000ULL, + 0x98B0000000000000ULL, + 0x9A60000000000000ULL, + 0x9BD0000000000000ULL, + 0x9FC0000000000000ULL, + 0x9E70000000000000ULL, + 0x9CA0000000000000ULL, + 0x9D10000000000000ULL, + 0x9480000000000000ULL, + 0x9530000000000000ULL, + 0x97E0000000000000ULL, + 0x9650000000000000ULL, + 0x9240000000000000ULL, + 0x93F0000000000000ULL, + 0x9120000000000000ULL, + 0x9090000000000000ULL, +}; + +uint64_t util_CRC64(const uint8_t* buf, size_t len) { + uint64_t res = 0ULL; + + for (size_t i = 0; i < len; i++) { + res = util_CRC64ISOPoly[(uint8_t)res ^ buf[i]] ^ (res >> 8); + } + + return res; +} + +uint64_t util_CRC64Rev(const uint8_t* buf, size_t len) { + uint64_t res = 0ULL; + + for (ssize_t i = (ssize_t)len - 1; i >= 0; i--) { + res = util_CRC64ISOPoly[(uint8_t)res ^ buf[i]] ^ (res >> 8); + } + + return res; +} diff --git a/libhfcommon/util.h b/libhfcommon/util.h new file mode 100644 index 00000000..26fe6e66 --- /dev/null +++ b/libhfcommon/util.h @@ -0,0 +1,125 @@ +/* + * + * honggfuzz - utilities + * ----------------------------------------- + * + * Author: Robert Swiecki <swiecki@google.com> + * + * Copyright 2010-2015 by Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + * + */ + +#ifndef _HF_COMMON_UTIL_H_ +#define _HF_COMMON_UTIL_H_ + +#include <pthread.h> +#include <stdarg.h> +#ifdef __clang__ +#include <stdatomic.h> +#endif +#include <stdbool.h> +#include <stdint.h> +#include <time.h> + +#define MX_LOCK(m) util_mutexLock(m, __func__, __LINE__) +#define MX_UNLOCK(m) util_mutexUnlock(m, __func__, __LINE__) +#define MX_RWLOCK_READ(m) util_mutexRWLockRead(m, __func__, __LINE__) +#define MX_RWLOCK_WRITE(m) util_mutexRWLockWrite(m, __func__, __LINE__) +#define MX_RWLOCK_UNLOCK(m) util_mutexRWUnlock(m, __func__, __LINE__) + +/* Atomics */ +#define ATOMIC_GET(x) __atomic_load_n(&(x), __ATOMIC_SEQ_CST) +#define ATOMIC_SET(x, y) __atomic_store_n(&(x), y, __ATOMIC_SEQ_CST) +#define ATOMIC_CLEAR(x) __atomic_store_n(&(x), 0, __ATOMIC_SEQ_CST) +#define ATOMIC_XCHG(x, y) __atomic_exchange_n(&(x), y, __ATOMIC_SEQ_CST) + +#define ATOMIC_PRE_INC(x) __atomic_add_fetch(&(x), 1, __ATOMIC_SEQ_CST) +#define ATOMIC_POST_INC(x) __atomic_fetch_add(&(x), 1, __ATOMIC_SEQ_CST) + +#define ATOMIC_PRE_DEC(x) __atomic_sub_fetch(&(x), 1, __ATOMIC_SEQ_CST) +#define ATOMIC_POST_DEC(x) __atomic_fetch_sub(&(x), 1, __ATOMIC_SEQ_CST) + +#define ATOMIC_PRE_ADD(x, y) __atomic_add_fetch(&(x), y, __ATOMIC_SEQ_CST) +#define ATOMIC_POST_ADD(x, y) __atomic_fetch_add(&(x), y, __ATOMIC_SEQ_CST) + +#define ATOMIC_PRE_SUB(x, y) __atomic_sub_fetch(&(x), y, __ATOMIC_SEQ_CST) +#define ATOMIC_POST_SUB(x, y) __atomic_fetch_sub(&(x), y, __ATOMIC_SEQ_CST) + +#define ATOMIC_PRE_AND(x, y) __atomic_and_fetch(&(x), y, __ATOMIC_SEQ_CST) +#define ATOMIC_POST_AND(x, y) __atomic_fetch_and(&(x), y, __ATOMIC_SEQ_CST) + +#define ATOMIC_PRE_OR(x, y) __atomic_or_fetch(&(x), y, __ATOMIC_SEQ_CST) +#define ATOMIC_POST_OR(x, y) __atomic_fetch_or(&(x), y, __ATOMIC_SEQ_CST) + +#define ATOMIC_PRE_INC_RELAXED(x) __atomic_add_fetch(&(x), 1, __ATOMIC_RELAXED) +#define ATOMIC_POST_OR_RELAXED(x, y) __atomic_fetch_or(&(x), y, __ATOMIC_RELAXED) + +__attribute__((always_inline)) static inline uint8_t ATOMIC_BTS(uint8_t* addr, size_t offset) { + uint8_t oldbit; + addr += (offset / 8); + oldbit = ATOMIC_POST_OR_RELAXED(*addr, ((uint8_t)1U << (offset % 8))); + return oldbit; +} + +extern void* util_Malloc(size_t sz); + +extern void* util_Calloc(size_t sz); + +extern void* util_MMap(size_t sz); + +extern void* util_Realloc(void* ptr, size_t sz); + +extern char* util_StrDup(const char* s); + +extern uint64_t util_rndGet(uint64_t min, uint64_t max); + +extern void util_rndBuf(uint8_t* buf, size_t sz); + +extern uint64_t util_rnd64(void); + +extern int util_ssnprintf(char* str, size_t size, const char* format, ...); + +extern int util_vssnprintf(char* str, size_t size, const char* format, va_list ap); + +extern void util_getLocalTime(const char* fmt, char* buf, size_t len, time_t tm); + +extern void util_nullifyStdio(void); + +extern bool util_redirectStdin(const char* inputFile); + +extern uint64_t util_hash(const char* buf, size_t len); + +extern int64_t util_timeNowMillis(void); + +extern uint64_t util_getUINT32(const uint8_t* buf); +extern uint64_t util_getUINT64(const uint8_t* buf); + +extern void util_mutexLock(pthread_mutex_t* mutex, const char* func, int line); +extern void util_mutexUnlock(pthread_mutex_t* mutex, const char* func, int line); + +extern void util_mutexRWLockRead(pthread_rwlock_t* mutex, const char* func, int line); +extern void util_mutexRWLockWrite(pthread_rwlock_t* mutex, const char* func, int line); +extern void util_mutexRWUnlock(pthread_rwlock_t* mutex, const char* func, int line); + +extern int64_t fastArray64Search(uint64_t* array, size_t arraySz, uint64_t key); + +extern bool util_isANumber(const char* s); + +extern size_t util_decodeCString(char* s); + +extern uint64_t util_CRC64(const uint8_t* buf, size_t len); +extern uint64_t util_CRC64Rev(const uint8_t* buf, size_t len); + +#endif /* ifndef _HF_COMMON_UTIL_H_ */ |