├── rng ├── sse2rng.h ├── arc4random_uniform.h ├── arc4random_uniform.c ├── arc4random.h ├── sse2rng.c ├── arc4random.c └── chacha_private.h ├── README.md ├── xthread.cpp ├── hashheapallocator.hh ├── real.hh ├── Makefile ├── threadstruct.hh ├── real.cpp ├── errmsg.hh ├── mm.hh ├── hashfuncs.hh ├── slist.h ├── dlist.h ├── mylist.hh ├── bigheap.hh ├── list.hh ├── log.hh ├── xdefines.hh ├── xthread.hh ├── hashmap.hh ├── libguarder.cpp └── bibopheap.hh /rng/sse2rng.h: -------------------------------------------------------------------------------- 1 | void srand_sse( unsigned int seed ); 2 | void rand_sse( unsigned int* ); 3 | -------------------------------------------------------------------------------- /rng/arc4random_uniform.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | //#include "arc4random.h" 5 | 6 | extern uint32_t arc4random(void); 7 | extern void arc4random_buf(void *buf, size_t n); 8 | uint32_t arc4random_uniform(uint32_t upper_bound); 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Guarder 2 | 3 | #### Compilation 4 | Simply use `make clean; make` to compile the allocator. This will produce a DSO named `libguarder.so` which may then be linked to applications at compile-time using the `-rdynamic /path/to/libguarder.so` flag. 5 | 6 | To link to an existing, pre-compiled application, utilize the `LD_PRELOAD` environment variable when executing the program. For example: `$ LD_PRELOAD=/path/to/libguarder.so ./program-to-run`. 7 | -------------------------------------------------------------------------------- /xthread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file xthread.cpp: thread-related function implementation. 21 | * @author Tongping Liu 22 | * @author Sam Silvestro 23 | */ 24 | 25 | #include "xthread.hh" 26 | 27 | char * getThreadBuffer() { 28 | #ifdef CUSTOMIZED_STACK 29 | thread_t * current = xthread::getInstance().getThread(getThreadIndex(¤t)); 30 | #else 31 | thread_t * current = xthread::getInstance().getThread(); 32 | #endif 33 | return current->outputBuf; 34 | } 35 | -------------------------------------------------------------------------------- /hashheapallocator.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file hashheapallocator.hh: support functions allocate memory for hash table. 21 | * @author Tongping Liu 22 | * @author Sam Silvestro 23 | */ 24 | #ifndef __HASHHEAPALLOCATOR_HH__ 25 | #define __HASHHEAPALLOCATOR_HH__ 26 | 27 | #include "real.hh" 28 | 29 | class HeapAllocator { 30 | public: 31 | static void* allocate(size_t sz) { 32 | void* ptr = Real::malloc(sz); 33 | if(!ptr) { 34 | return NULL; 35 | } 36 | return ptr; 37 | } 38 | 39 | static void deallocate(void* ptr) { 40 | Real::free(ptr); 41 | ptr = NULL; 42 | } 43 | }; 44 | #endif 45 | -------------------------------------------------------------------------------- /real.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file real.hh: provides wrappers to glibc thread & memory functions. 21 | * @author Tongping Liu 22 | * @author Sam Silvestro 23 | */ 24 | #ifndef __REAL_HH_ 25 | #define __REAL_HH_ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #define DECLARE_WRAPPER(name) extern decltype(::name) * name; 33 | 34 | namespace Real { 35 | void initializer(); 36 | DECLARE_WRAPPER(free); 37 | // DECLARE_WRAPPER(calloc); 38 | DECLARE_WRAPPER(malloc); 39 | // DECLARE_WRAPPER(realloc); 40 | DECLARE_WRAPPER(pthread_create); 41 | DECLARE_WRAPPER(pthread_join); 42 | DECLARE_WRAPPER(pthread_kill); 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SRCS = real.cpp \ 2 | xthread.cpp \ 3 | libguarder.cpp 4 | 5 | INCS = bibopheap.hh \ 6 | bigheap.hh \ 7 | dlist.h \ 8 | hashfuncs.hh \ 9 | hashheapallocator.hh \ 10 | hashmap.hh \ 11 | list.hh \ 12 | log.hh \ 13 | mm.hh \ 14 | real.hh \ 15 | slist.h \ 16 | threadstruct.hh \ 17 | xdefines.hh \ 18 | xthread.hh 19 | 20 | DEPS = $(SRCS) $(INCS) 21 | 22 | CC = clang 23 | CXX = clang++ 24 | 25 | ifndef DEBUG_LEVEL 26 | DEBUG_LEVEL = 3 27 | endif 28 | 29 | CFLAGS += -O2 -Wall --std=c++11 -g -fno-omit-frame-pointer -DNDEBUG -DCUSTOMIZED_STACK -DENABLE_GUARDPAGE -DRANDOM_GUARD -DUSE_CANARY 30 | 31 | # NDEBUG overrules DEBUG_LEVEL macro in log.hh 32 | ifdef NDEBUG 33 | CFLAGS += -DNDEBUG 34 | endif 35 | #ifdef MANYBAGS 36 | #CFLAGS += -DMANYBAGS 37 | #endif 38 | 39 | INCLUDE_DIRS = -I. -I/usr/include/x86_64-linux-gnu/c++/4.8/ -I./rng 40 | LIBS := dl pthread 41 | 42 | ifdef ARC4RNG 43 | CFLAGS += -DARC4RNG 44 | SRCS += rng/arc4random.o rng/arc4random_uniform.o 45 | TARGETS = arc4random.o arc4random_uniform.o $(TARGETS) 46 | else 47 | CFLAGS += -DSSE2RNG -msse2 48 | SRCS += rng/sse2rng.c 49 | endif 50 | CFLAGS += -DUSE_GLOBAL_FREE_CACHE 51 | 52 | TARGETS = libguarder.so 53 | 54 | all: $(TARGETS) 55 | 56 | rng/arc4random.o: rng/arc4random.c 57 | clang -fPIC -O2 -DNDEBUG -I. -c rng/arc4random.c -o rng/arc4random.o 58 | 59 | rng/arc4random_uniform.o: rng/arc4random_uniform.c 60 | clang -fPIC -O2 -DNDEBUG -I. -c rng/arc4random_uniform.c -o rng/arc4random_uniform.o 61 | 62 | libguarder.so: $(DEPS) 63 | $(CXX) $(CFLAGS) $(INCLUDE_DIRS) -shared -fPIC $(SRCS) -o libguarder.so -ldl -lpthread -lrt 64 | 65 | clean: 66 | rm -f $(TARGETS) 67 | -------------------------------------------------------------------------------- /threadstruct.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file threadstruct.hh: internal per-thread structure. 21 | * @author Tongping Liu 22 | * @author Sam Silvestro 23 | */ 24 | #ifndef __THREADSTRUCT_HH__ 25 | #define __THREADSTRUCT_HH__ 26 | 27 | #include 28 | #include 29 | #include 30 | #include "xdefines.hh" 31 | 32 | extern "C" { 33 | typedef void * threadFunction(void *); 34 | typedef struct thread { 35 | // Whether the entry is available so that allocThreadIndex can use this one 36 | bool available; 37 | 38 | // Identifications 39 | pid_t tid; 40 | pthread_t pthreadt; 41 | int index; 42 | 43 | // Starting parameters 44 | threadFunction * startRoutine; 45 | void * startArg; 46 | 47 | // Printing buffer to avoid lock conflict. 48 | // fprintf will use a shared buffer and can't be used in signal handler 49 | char outputBuf[LOG_SIZE]; 50 | } thread_t; 51 | }; 52 | #endif 53 | -------------------------------------------------------------------------------- /rng/arc4random_uniform.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: arc4random_uniform.c,v 1.2 2015/09/13 08:31:47 guenther Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 2008, Damien Miller 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | extern uint32_t arc4random(void); 24 | 25 | /* 26 | * Calculate a uniformly distributed random number less than upper_bound 27 | * avoiding "modulo bias". 28 | * 29 | * Uniformity is achieved by generating new random numbers until the one 30 | * returned is outside the range [0, 2**32 % upper_bound). This 31 | * guarantees the selected random number will be inside 32 | * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) 33 | * after reduction modulo upper_bound. 34 | */ 35 | uint32_t 36 | arc4random_uniform(uint32_t upper_bound) 37 | { 38 | uint32_t r, min; 39 | 40 | if (upper_bound < 2) 41 | return 0; 42 | 43 | /* 2**32 % x == (2**32 - x) % x */ 44 | min = -upper_bound % upper_bound; 45 | 46 | /* 47 | * This could theoretically loop forever but each retry has 48 | * p > 0.5 (worst case, usually far better) of selecting a 49 | * number inside the range we need, so it should rarely need 50 | * to re-roll. 51 | */ 52 | for (;;) { 53 | r = arc4random(); 54 | if (r >= min) 55 | break; 56 | } 57 | 58 | return r % upper_bound; 59 | } 60 | -------------------------------------------------------------------------------- /real.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file real.cpp: provides wrappers to glibc thread & memory functions. 21 | * @author Tongping Liu 22 | * @author Sam Silvestro 23 | */ 24 | #include 25 | #include 26 | #include "real.hh" 27 | 28 | #define DEFINE_WRAPPER(name) decltype(::name) * name; 29 | #define INIT_WRAPPER(name, handle) name = (decltype(::name)*)dlsym(handle, #name); 30 | 31 | namespace Real { 32 | DEFINE_WRAPPER(free); 33 | // DEFINE_WRAPPER(calloc); 34 | DEFINE_WRAPPER(malloc); 35 | // DEFINE_WRAPPER(realloc); 36 | DEFINE_WRAPPER(pthread_create); 37 | DEFINE_WRAPPER(pthread_join); 38 | DEFINE_WRAPPER(pthread_kill); 39 | 40 | void initializer() { 41 | INIT_WRAPPER(free, RTLD_NEXT); 42 | // INIT_WRAPPER(calloc, RTLD_NEXT); 43 | INIT_WRAPPER(malloc, RTLD_NEXT); 44 | // INIT_WRAPPER(realloc, RTLD_NEXT); 45 | 46 | // FIXME about the flags 47 | void *pthread_handle = dlopen("libpthread.so.0", RTLD_NOW | RTLD_GLOBAL | RTLD_NOLOAD); 48 | INIT_WRAPPER(pthread_create, pthread_handle); 49 | INIT_WRAPPER(pthread_join, pthread_handle); 50 | INIT_WRAPPER(pthread_kill, pthread_handle); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /errmsg.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file errmsg.hh: prints callstack information. 21 | * @author Tongping Liu 22 | * @author Sam Silvestro 23 | */ 24 | #ifndef ERRMSG_H 25 | #define ERRMSG_H 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "xdefines.hh" 35 | #include "log.hh" 36 | 37 | #define PREV_INSTRUCTION_OFFSET 1 38 | #define FILENAMELENGTH 256 39 | 40 | void printCallStack(){ 41 | void* array[256]; 42 | int frames = backtrace(array, 256); 43 | 44 | char main_exe[FILENAMELENGTH]; 45 | readlink("/proc/self/exe", main_exe, FILENAMELENGTH); 46 | 47 | #ifdef CUSTOMIZED_STACK 48 | int threadIndex = getThreadIndex(&frames); 49 | #else 50 | int threadIndex = getThreadIndex(); 51 | #endif 52 | 53 | char buf[256]; 54 | for(int i = 0; i < frames; i++) { 55 | void* addr = (void*)((unsigned long)array[i] - PREV_INSTRUCTION_OFFSET); 56 | PRINT("\tThread %d: callstack frame %d: %p\t", threadIndex, i, addr); 57 | sprintf(buf, "addr2line -a -i -e %s %p", main_exe, addr); 58 | system(buf); 59 | } 60 | } 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /mm.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file mm.hh: memory mapping functions. 21 | * @author Tongping Liu 22 | * @author Sam Silvestro 23 | */ 24 | #ifndef __MM_HH__ 25 | #define __MM_HH__ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | class MM { 36 | public: 37 | #define ALIGN_TO_CACHELINE(size) (size % 64 == 0 ? size : (size + 64) / 64 * 64) 38 | 39 | static void mmapDeallocate(void* ptr, size_t sz) { munmap(ptr, sz); } 40 | 41 | static void* mmapAllocateShared(size_t sz, int fd = -1, void* startaddr = NULL) { 42 | return allocate(true, sz, fd, startaddr); 43 | } 44 | 45 | static void* mmapAllocatePrivate(size_t sz, void* startaddr = NULL, int fd = -1) { 46 | return allocate(false, sz, fd, startaddr); 47 | } 48 | 49 | private: 50 | static void* allocate(bool isShared, size_t sz, int fd, void* startaddr) { 51 | int protInfo = PROT_READ | PROT_WRITE; 52 | int sharedInfo = isShared ? MAP_SHARED : MAP_PRIVATE; 53 | sharedInfo |= ((fd == -1) ? MAP_ANONYMOUS : 0); 54 | sharedInfo |= ((startaddr != (void*)0) ? MAP_FIXED : 0); 55 | sharedInfo |= MAP_NORESERVE; 56 | 57 | void* ptr = mmap(startaddr, sz, protInfo, sharedInfo, fd, 0); 58 | if(ptr == MAP_FAILED) { 59 | FATAL("Couldn't do mmap (%s) : startaddr %p, sz %lx, protInfo=%d, sharedInfo=%d", 60 | strerror(errno), startaddr, sz, protInfo, sharedInfo); 61 | } 62 | 63 | return ptr; 64 | } 65 | }; 66 | 67 | class InternalHeapAllocator { 68 | public: 69 | static void* malloc(size_t sz); 70 | static void free(void* ptr); 71 | static void* allocate(size_t sz); 72 | static void deallocate(void* ptr); 73 | }; 74 | #endif 75 | -------------------------------------------------------------------------------- /hashfuncs.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file hashfuncs.hh: functions related to hash table implementation. 21 | * @author Tongping Liu 22 | * @author Sam Silvestro 23 | */ 24 | #ifndef __HASHFUNCS_HH__ 25 | #define __HASHFUNCS_HH__ 26 | 27 | #include 28 | #include 29 | 30 | class HashFuncs { 31 | public: 32 | // The following functions are borrowed from the STL. 33 | static size_t hashString(char* start, size_t len) { 34 | //static size_t hashString(const void* start, size_t len) { 35 | unsigned long __h = 0; 36 | char* __s = start; 37 | //char* __s = (char*)start; 38 | int i = 0; 39 | //auto i = 0; 40 | 41 | for(; i <= (int) len; i++, ++__s) 42 | __h = 5 * __h + *__s; 43 | 44 | return size_t(__h); 45 | } 46 | 47 | static size_t hashInt(const int x, size_t) { return x; } 48 | 49 | static size_t hashLong(long x, size_t) { return x; } 50 | 51 | static size_t hashUnsignedlong(unsigned long x, size_t) { return x; } 52 | 53 | static size_t hashAddr(void* addr, size_t) { 54 | unsigned long key = (unsigned long)addr; 55 | key ^= (key << 15) ^ 0xcd7dcd7d; 56 | key ^= (key >> 10); 57 | key ^= (key << 3); 58 | key ^= (key >> 6); 59 | key ^= (key << 2) + (key << 14); 60 | key ^= (key >> 16); 61 | return key; 62 | } 63 | 64 | static size_t hashAddrs(intptr_t* addr, size_t len) { 65 | size_t result = ~0; 66 | for(size_t i = 0; i < len; i++) result ^= addr[i]; 67 | return result; 68 | } 69 | 70 | static bool compareAddr(void* addr1, void* addr2, size_t) { return addr1 == addr2; } 71 | 72 | static bool compareInt(int var1, int var2, size_t) { return var1 == var2; } 73 | 74 | //static bool compareString(const char* str1, const char* str2, size_t len) { 75 | static bool compareString(char* str1, char* str2, size_t len) { 76 | return strncmp(str1, str2, len) == 0; 77 | } 78 | }; 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /slist.h: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file slist.h: single-linked list implementation. 21 | * @author Tongping Liu 22 | * @author Sam Silvestro 23 | */ 24 | #ifndef __SLIST_H__ 25 | #define __SLIST_H__ 26 | 27 | #include 28 | 29 | typedef struct slist { 30 | struct slist* next; 31 | } slist_t; 32 | 33 | inline void initSLL(slist_t* slist) { slist->next = NULL; } 34 | 35 | // Whether a slist is empty 36 | inline bool isSLLEmpty(slist_t* slist) { return (slist->next == NULL); } 37 | 38 | // Next node of current node 39 | inline slist_t* nextEntry(slist_t* cur) { return cur->next; } 40 | 41 | // Insert one entry to the head of specified slist. 42 | // Insert between head and head->next 43 | inline void insertSLLHead(slist_t* node, slist_t* slist) { 44 | 45 | node->next = slist->next; 46 | slist->next = node; 47 | } 48 | 49 | inline slist_t * getTailSLL(slist_t *slist); 50 | // Insert all entries to the head of specified slist. 51 | inline void insertAllSLLHead(slist_t* node, slist_t* slist) { 52 | assert(node!=NULL); 53 | slist_t* tmp = slist->next; 54 | slist->next = node->next; 55 | slist_t* tail = getTailSLL(node->next); 56 | tail->next = tmp; 57 | } 58 | 59 | // Delete an entry and re-initialize it. 60 | inline void* removeSLLHead(slist_t* slist) { 61 | slist_t * temp; 62 | 63 | temp = slist->next; 64 | // fprintf(stderr, "slistnext %p\n", slist->next); 65 | // fprintf(stderr, "slist->next->next %p\n", slist->next->next); 66 | slist->next = slist->next->next; 67 | 68 | return temp; 69 | } 70 | 71 | inline slist_t * getTailSLL(slist_t *slist) { 72 | if(slist == NULL) { 73 | return NULL; 74 | } 75 | 76 | slist_t * current = slist; 77 | while(current->next != NULL) { 78 | current = nextEntry(current); 79 | } 80 | return current; 81 | } 82 | 83 | inline int countSLL(slist_t *slist) { 84 | if(slist == NULL) { 85 | return -1; 86 | } 87 | 88 | int length = 0; 89 | slist_t * prev = slist; 90 | slist_t * current = slist->next; 91 | 92 | while(current != NULL) { 93 | length++; 94 | prev = current; 95 | current = nextEntry(current); 96 | } 97 | 98 | return length; 99 | } 100 | 101 | #endif 102 | -------------------------------------------------------------------------------- /rng/arc4random.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: arc4random_linux.h,v 1.11 2016/06/30 12:19:51 bcook Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1996, David Mazieres 5 | * Copyright (c) 2008, Damien Miller 6 | * Copyright (c) 2013, Markus Friedl 7 | * Copyright (c) 2014, Theo de Raadt 8 | * 9 | * Permission to use, copy, modify, and distribute this software for any 10 | * purpose with or without fee is hereby granted, provided that the above 11 | * copyright notice and this permission notice appear in all copies. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 | */ 21 | 22 | /* 23 | * Stub functions for portability. 24 | */ 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | //static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; 35 | //#define _ARC4_LOCK() pthread_mutex_lock(&arc4random_mtx) 36 | //#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx) 37 | 38 | #ifdef __GLIBC__ 39 | extern void *__dso_handle; 40 | extern int __register_atfork(void (*)(void), void(*)(void), void (*)(void), void *); 41 | #define _ARC4_ATFORK(f) __register_atfork(NULL, NULL, (f), __dso_handle) 42 | #else 43 | #define _ARC4_ATFORK(f) pthread_atfork(NULL, NULL, (f)) 44 | #endif 45 | 46 | static inline int getentropy(void *buf, size_t buflen) { 47 | int ret; 48 | if (buflen > 256) 49 | goto failure; 50 | ret = syscall(318, buf, buflen, 0); 51 | //ret = syscall(SYS_getrandom, buf, buflen, 0); 52 | //ret = getrandom(buf, buflen, 0); 53 | if (ret < 0) 54 | return ret; 55 | if (ret == buflen) 56 | return 0; 57 | failure: 58 | errno = EIO; 59 | return -1; 60 | } 61 | 62 | static inline void 63 | _getentropy_fail(void) 64 | { 65 | raise(SIGKILL); 66 | } 67 | 68 | //static volatile sig_atomic_t _rs_forked; 69 | __thread sig_atomic_t _rs_forked; 70 | 71 | static inline void 72 | _rs_forkhandler(void) 73 | { 74 | _rs_forked = 1; 75 | } 76 | 77 | static inline void 78 | _rs_forkdetect(void) 79 | { 80 | static pid_t _rs_pid = 0; 81 | pid_t pid = getpid(); 82 | 83 | /* XXX unusual calls to clone() can bypass checks */ 84 | if (_rs_pid == 0 || _rs_pid == 1 || _rs_pid != pid || _rs_forked) { 85 | _rs_pid = pid; 86 | _rs_forked = 0; 87 | if (rs) 88 | memset(rs, 0, sizeof(*rs)); 89 | } 90 | } 91 | 92 | static inline int 93 | _rs_allocate(struct _rs **rsp, struct _rsx **rsxp) 94 | { 95 | if ((*rsp = mmap(NULL, sizeof(**rsp), PROT_READ|PROT_WRITE, 96 | MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) 97 | return (-1); 98 | 99 | if ((*rsxp = mmap(NULL, sizeof(**rsxp), PROT_READ|PROT_WRITE, 100 | MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) { 101 | munmap(*rsp, sizeof(**rsp)); 102 | *rsp = NULL; 103 | return (-1); 104 | } 105 | 106 | _ARC4_ATFORK(_rs_forkhandler); 107 | return (0); 108 | } 109 | -------------------------------------------------------------------------------- /dlist.h: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file dlist.h: double-linked list implementation. 21 | * @author Tongping Liu 22 | * @author Sam Silvestro 23 | */ 24 | #ifndef __DLIST_H__ 25 | #define __DLIST_H__ 26 | 27 | #include 28 | 29 | typedef struct dlist { 30 | struct slist* next; 31 | struct slist* prev; 32 | } dlist_t; 33 | 34 | inline void initDLL(dlist_t* dlist) { dlist->next = dlist->prev = NULL; } 35 | 36 | // Whether a dlist is empty 37 | inline bool isDLLEmpty(dlist_t* dlist) { return (dlist->next == NULL); } 38 | 39 | // Next node of current node 40 | inline slist_t* nextEntry(dlist_t* cur) { return cur->next; } 41 | 42 | // Previous node of current node 43 | inline slist_t* prevEntry(dlist_t* cur) { return cur->prev; } 44 | 45 | // Insert one entry to the head of specified dlist. 46 | // Insert between head and head->next 47 | inline void insertDLLHead(slist_t* node, dlist_t* dlist) { 48 | slist_t * old_head = dlist->next; 49 | slist_t * old_tail = dlist->prev; 50 | 51 | node->next = old_head; 52 | 53 | if(!old_tail) { 54 | dlist->prev = node; 55 | } 56 | 57 | dlist->next = node; 58 | } 59 | 60 | inline void insertDLLTail(slist_t* node, dlist_t* dlist) { 61 | slist_t * old_tail = dlist->prev; 62 | node->next = NULL; 63 | 64 | if(old_tail) { 65 | old_tail->next = node; 66 | } else { 67 | dlist->next = node; 68 | } 69 | 70 | dlist->prev = node; 71 | } 72 | 73 | inline void printDLLList(dlist_t * dlist) { 74 | slist_t * next = dlist->next; 75 | printf("contents of dlist %p\n", dlist); 76 | printf("%p", next); 77 | 78 | while(next) { 79 | next = nextEntry(next); 80 | printf(", %p", next); 81 | } 82 | printf("\n"); 83 | } 84 | 85 | // Delete an entry and re-initialize it. 86 | inline void* removeDLLHead(dlist_t* dlist) { 87 | slist_t * old_head, * replacement; 88 | 89 | old_head = dlist->next; 90 | replacement = old_head->next; 91 | 92 | if(!replacement) { 93 | dlist->prev = NULL; 94 | } 95 | 96 | dlist->next = replacement; 97 | 98 | return old_head; 99 | } 100 | 101 | inline void insertAllDLLTail(slist_t* slist, dlist_t * dlist) { 102 | slist_t * tail_segment1 = slist->next; 103 | slist_t * tail_segment2 = NULL; 104 | slist_t * old_tail = dlist->prev; 105 | 106 | if(!tail_segment1) { 107 | return; 108 | } 109 | 110 | // Reset the dlist's prev pointer to point to the new tail. 111 | dlist->prev = tail_segment1; 112 | 113 | do { 114 | slist_t * next = nextEntry(tail_segment1); 115 | // The new tail segment should point to what is in front of it. 116 | tail_segment1->next = tail_segment2; 117 | tail_segment2 = tail_segment1; 118 | tail_segment1 = next; 119 | } while(tail_segment1); 120 | 121 | if(old_tail) { 122 | old_tail->next = tail_segment2; 123 | } else { 124 | dlist->next = tail_segment2; 125 | } 126 | } 127 | #endif 128 | -------------------------------------------------------------------------------- /rng/sse2rng.c: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // The Software is provided "AS IS" and possibly with faults. 3 | // Intel disclaims any and all warranties and guarantees, express, implied or 4 | // otherwise, arising, with respect to the software delivered hereunder, 5 | // including but not limited to the warranty of merchantability, the warranty 6 | // of fitness for a particular purpose, and any warranty of non-infringement 7 | // of the intellectual property rights of any third party. 8 | // Intel neither assumes nor authorizes any person to assume for it any other 9 | // liability. Customer will use the software at its own risk. Intel will not 10 | // be liable to customer for any direct or indirect damages incurred in using 11 | // the software. In no event will Intel be liable for loss of profits, loss of 12 | // use, loss of data, business interruption, nor for punitive, incidental, 13 | // consequential, or special damages of any kind, even if advised of 14 | // the possibility of such damages. 15 | // 16 | // Copyright (c) 2003 Intel Corporation 17 | // 18 | // Third-party brands and names are the property of their respective owners 19 | // 20 | /////////////////////////////////////////////////////////////////////////// 21 | // Random Number Generation for SSE / SSE2 22 | // Source File 23 | // Version 0.1 24 | // Author Kipp Owens, Rajiv Parikh 25 | //////////////////////////////////////////////////////////////////////// 26 | #ifndef RAND_SSE_H 27 | #define RAND_SSE_H 28 | #include "emmintrin.h" 29 | 30 | #define COMPATABILITY 31 | 32 | //#include "sse2rng.h" 33 | //define this if you wish to return values similar to the standard rand(); 34 | //void srand_sse( unsigned int seed ) { ; } 35 | //void rand_sse( unsigned int* value) { *value = 5; } 36 | //__attribute__(( aligned (16) )) static __m128i cur_seed; 37 | __thread __attribute__(( aligned (16) )) static __m128i cur_seed; 38 | 39 | void srand_sse( unsigned int seed ) 40 | { 41 | cur_seed = _mm_set_epi32( seed, seed+1, seed, seed+1 ); 42 | } 43 | 44 | //inline void rand_sse( unsigned int* result ) 45 | void rand_sse( unsigned int* result ) 46 | { 47 | __attribute__(( aligned (16) )) __m128i cur_seed_split; 48 | __attribute__(( aligned (16) )) __m128i multiplier; 49 | __attribute__(( aligned (16) )) __m128i adder; 50 | __attribute__(( aligned (16) )) __m128i mod_mask; 51 | __attribute__(( aligned (16) )) __m128i sra_mask; 52 | __attribute__(( aligned (16) )) __m128i sseresult; 53 | __attribute__(( aligned (16) )) static const unsigned int mult[4] = 54 | { 214013, 17405, 214013, 69069 }; 55 | __attribute__(( aligned (16) )) static const unsigned int gadd[4] = 56 | { 2531011, 10395331, 13737667, 1 }; 57 | __attribute__(( aligned (16) )) static const unsigned int mask[4] = 58 | { 0xFFFFFFFF, 0, 0xFFFFFFFF, 0 }; 59 | __attribute__(( aligned (16) )) static const unsigned int masklo[4] = 60 | { 0x00007FFF, 0x00007FFF, 0x00007FFF, 0x00007FFF }; 61 | adder = _mm_load_si128( (__m128i*) gadd); 62 | multiplier = _mm_load_si128( (__m128i*) mult); 63 | mod_mask = _mm_load_si128( (__m128i*) mask); 64 | sra_mask = _mm_load_si128( (__m128i*) masklo); 65 | cur_seed_split = _mm_shuffle_epi32( cur_seed, _MM_SHUFFLE( 2, 3, 0, 1 ) ); 66 | cur_seed = _mm_mul_epu32( cur_seed, multiplier ); 67 | multiplier = _mm_shuffle_epi32( multiplier, _MM_SHUFFLE( 2, 3, 0, 1 ) ); 68 | cur_seed_split = _mm_mul_epu32( cur_seed_split, multiplier ); 69 | cur_seed = _mm_and_si128( cur_seed, mod_mask); 70 | cur_seed_split = _mm_and_si128( cur_seed_split, mod_mask ); 71 | cur_seed_split = _mm_shuffle_epi32( cur_seed_split, _MM_SHUFFLE( 2, 3, 0, 1 ) ); 72 | cur_seed = _mm_or_si128( cur_seed, cur_seed_split ); 73 | cur_seed = _mm_add_epi32( cur_seed, adder); 74 | #ifdef COMPATABILITY 75 | // Add the lines below if you wish to reduce your results to 16-bit vals... 76 | sseresult = _mm_srai_epi32( cur_seed, 16); 77 | sseresult = _mm_and_si128( sseresult, sra_mask ); 78 | _mm_storeu_si128( (__m128i*) result, sseresult ); 79 | return; 80 | #endif 81 | _mm_storeu_si128( (__m128i*) result, cur_seed); 82 | return; 83 | } 84 | #endif 85 | -------------------------------------------------------------------------------- /mylist.hh: -------------------------------------------------------------------------------- 1 | #if !defined(DOUBLETAKE_LIST_H) 2 | #define DOUBLETAKE_LIST_H 3 | 4 | /* 5 | * @file list.h 6 | * @brief Something about list etc. 7 | * @author Tongping Liu 8 | */ 9 | 10 | #include 11 | 12 | typedef struct list { 13 | struct list* prev; 14 | struct list* next; 15 | } my_list; 16 | 17 | // Initialize a node 18 | inline void nodeInit(my_list* node) { node->next = node->prev = node; } 19 | 20 | inline void listInit(my_list* node) { nodeInit(node); } 21 | 22 | // Whether a list is empty 23 | inline bool isListEmpty(my_list* head) { return (head->next == head); } 24 | 25 | // Next node of current node 26 | inline my_list* nextEntry(my_list* cur) { return cur->next; } 27 | 28 | // Previous node of current node 29 | inline my_list* prevEntry(my_list* cur) { return cur->prev; } 30 | 31 | // We donot check whetehr the list is empty or not? 32 | inline my_list* tailList(my_list* head) { 33 | my_list* tail = NULL; 34 | if(!isListEmpty(head)) { 35 | tail = head->prev; 36 | } 37 | 38 | return tail; 39 | } 40 | 41 | // Insert one entry to two consequtive entries 42 | inline void __insert_between(my_list* node, my_list* prev, my_list* next) { 43 | // fprintf(stderr, "line %d: prev %p next %p\n", __LINE__, prev, next); 44 | // fprintf(stderr, "line %d: prev now %lx next %p\n", __LINE__, *((unsigned long *)prev), next); 45 | // fprintf(stderr, "line %d: prev->next %lx next %p\n", __LINE__, *((unsigned long *)((unsigned 46 | // long)prev + 0x8)), next); 47 | node->next = next; 48 | node->prev = prev; 49 | prev->next = node; 50 | next->prev = node; 51 | } 52 | 53 | // Insert one entry to after specified entry prev (prev, prev->next) 54 | inline void listInsertNode(my_list* node, my_list* prev) { __insert_between(node, prev, prev->next); } 55 | 56 | // Insert one entry to the tail of specified list. 57 | // Insert between tail and head 58 | inline void listInsertTail(my_list* node, my_list* head) { 59 | // fprintf(stderr, "node %p head %p head->prev %p\n", node, head, head->prev); 60 | __insert_between(node, head->prev, head); 61 | } 62 | 63 | // Insert one entry to the head of specified list. 64 | // Insert between head and head->next 65 | inline void listInsertHead(my_list* node, my_list* head) { __insert_between(node, head, head->next); } 66 | 67 | // Internal usage to link p with n 68 | // Never use directly outside. 69 | inline void __list_link(my_list* p, my_list* n) { 70 | p->next = n; 71 | n->prev = p; 72 | } 73 | 74 | // We need to verify this 75 | // Insert one entry to the head of specified list. 76 | // Insert the list between where and where->next 77 | inline void listInsertList(my_list* list, my_list* where) { 78 | // Insert after where. 79 | __list_link(where, list); 80 | 81 | // Then modify other pointer 82 | __list_link(list->prev, where->next); 83 | } 84 | 85 | // Insert one list between where->prev and where, however, 86 | // we don't need to insert the node "list" itself 87 | inline void listInsertListTail(my_list* list, my_list* where) { 88 | #if 0 89 | // Link between where->prev and first node of list. 90 | my_list* origtail = where->prev; 91 | my_list* orighead = where; 92 | my_list* newhead = list->next; 93 | my_list* newtail = list->prev; 94 | 95 | origtail->next = newhead; 96 | newhead->prev = origtail; 97 | 98 | newtail->next = orighead; 99 | orighead->prev = newtail; 100 | 101 | p->next = n; 102 | n->prev = p; 103 | #else 104 | __list_link(where->prev, list->next); 105 | 106 | // Link between last node of list and where. 107 | __list_link(list->prev, where); 108 | #endif 109 | } 110 | 111 | // Delete an entry and re-initialize it. 112 | inline void listRemoveNode(my_list* node) { 113 | __list_link(node->prev, node->next); 114 | nodeInit(node); 115 | } 116 | 117 | // Check whether current node is the tail of a list 118 | inline bool isListTail(my_list* node, my_list* head) { return (node->next == head); } 119 | 120 | // Retrieve the first item form a list 121 | // Then this item will be removed from the list. 122 | inline my_list* listRetrieveItem(my_list* list) { 123 | my_list* first = NULL; 124 | 125 | // Retrieve item when the list is not empty 126 | if(!isListEmpty(list)) { 127 | first = list->next; 128 | listRemoveNode(first); 129 | } 130 | 131 | return first; 132 | } 133 | 134 | // Retrieve all items from a list and re-initialize all source list. 135 | inline void listRetrieveAllItems(my_list* dest, my_list* src) { 136 | my_list* first, *last; 137 | first = src->next; 138 | last = src->prev; 139 | 140 | first->prev = dest; 141 | last->next = dest; 142 | dest->next = first; 143 | dest->prev = last; 144 | 145 | // reinitialize the source list 146 | listInit(src); 147 | } 148 | 149 | // Print all entries in the link list 150 | inline void listPrintItems(my_list* head, int num) { 151 | int i = 0; 152 | my_list* first, *entry; 153 | entry = head->next; 154 | first = head; 155 | 156 | while(entry != first && i < num) { 157 | // fprintf(stderr, "%d: ENTRY %d: %p (prev %p). HEAD %p\n", getpid(), i++, entry, 158 | // entry->prev, head); 159 | entry = entry->next; 160 | } 161 | 162 | // PRINF("HEAD %p Head->prev %p head->next %p\n", head, head->prev, head->next); 163 | } 164 | 165 | /* Get the pointer to the struct this entry is part of 166 | * 167 | */ 168 | #define listEntry(ptr, type, member) ((type*)((char*)(ptr) - (unsigned long)(&((type*)0)->member))) 169 | 170 | #endif 171 | -------------------------------------------------------------------------------- /bigheap.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file bigheap.hh: manages the mapping/unmapping of large objects 21 | * @author Tongping Liu 22 | * @author Sam Silvestro 23 | */ 24 | #ifndef __BIGHEAP_HH__ 25 | #define __BIGHEAP_HH__ 26 | 27 | #include "real.hh" 28 | #include "xthread.hh" 29 | #include "mm.hh" 30 | #include "xdefines.hh" 31 | #include "errmsg.hh" 32 | 33 | class BigHeap { 34 | 35 | private: 36 | class bigObjectStatus { 37 | public: 38 | void * actualStart; 39 | void * userStart; 40 | 41 | // pageUpSize and usableSize are usually the same thing, 42 | // unless an aligned allocation function was used (e.g., 43 | // memalign or posix_memalign). In this instance, all 44 | // three size values could be different. 45 | size_t size; 46 | size_t pageUpSize; 47 | size_t usableSize; 48 | 49 | #ifdef DETECT_UAF 50 | unsigned long long freedtime; 51 | #endif 52 | }; 53 | 54 | public: 55 | static BigHeap &getInstance() { 56 | static char buf[sizeof(BigHeap)]; 57 | static BigHeap* theOneTrueObject = new (buf) BigHeap(); 58 | return *theOneTrueObject; 59 | } 60 | 61 | // Initialization of the Big Heap 62 | void initBigHeap(void) { 63 | // Initialize the spin_lock 64 | pthread_spin_init(&_spin_lock, PTHREAD_PROCESS_PRIVATE); 65 | 66 | // Initialize the hash map 67 | _xmap.initialize(HashFuncs::hashAddr, HashFuncs::compareAddr, THREAD_MAP_SIZE); 68 | } 69 | 70 | size_t getUsableSize(void * ptr) { 71 | bigObjectStatus * objStatus; 72 | if(!_xmap.find(ptr, sizeof(void *), &objStatus)) { 73 | return 0; 74 | } 75 | return objStatus->usableSize; 76 | } 77 | 78 | inline void * allocateAtBigHeap(size_t size) { 79 | return allocateAlignedAtBigHeap(16, size); 80 | } 81 | 82 | // For big objects, we don't have the quarantine list. 83 | // Actually, the size information will be kept until new allocation is 84 | void * allocateAlignedAtBigHeap(size_t alignment, size_t size) { 85 | assert(IF_CANARY_CONDITION); 86 | 87 | size_t pageUpSize = alignup(alignment + size, PageSize); 88 | size_t slackSize = pageUpSize - size; 89 | bigObjectStatus * objStatus = (bigObjectStatus *)HeapAllocator::allocate(sizeof(bigObjectStatus)); 90 | void * ptr = MM::mmapAllocatePrivate(pageUpSize, NULL); 91 | 92 | uintptr_t userStartPtr = (uintptr_t)ptr + slackSize; 93 | size_t residualBytes = userStartPtr % alignment; 94 | userStartPtr -= residualBytes; 95 | 96 | acquireGlobalLock(); 97 | _xmap.insert((void *)userStartPtr, sizeof(void *), objStatus); 98 | releaseGlobalLock(); 99 | 100 | objStatus->actualStart = ptr; 101 | objStatus->userStart = (void *)userStartPtr; 102 | objStatus->pageUpSize = pageUpSize; 103 | objStatus->usableSize = size + residualBytes; 104 | objStatus->size = size; 105 | 106 | PRDBG("BigHeap returning 0x%lx (begins @ %p), size %zu (actual %zu, usable %zu)", 107 | userStartPtr, ptr, size, pageUpSize, objStatus->usableSize); 108 | return (void *)userStartPtr; 109 | } 110 | 111 | size_t getObjectSize(void * addr) { 112 | return getUsableSize(addr); 113 | } 114 | 115 | bool isLargeObject(void * addr) { 116 | bigObjectStatus * objStatus; 117 | return(_xmap.find(addr, sizeof(void *), &objStatus)); 118 | } 119 | 120 | void deallocateToBigHeap(void * ptr) { 121 | bigObjectStatus * objStatus; 122 | if(!_xmap.find(ptr, sizeof(void *), &objStatus)) { 123 | PRINT("invalid or double free on address %p", ptr); 124 | printCallStack(); 125 | exit(-1); 126 | } 127 | 128 | //PRDBG("BigHeap freed %p (begins @ %p), size %zu (actual %zu), objStatus @ %p", 129 | // ptr, objStatus->start, objStatus->size, objStatus->pageUpSize, objStatus); 130 | acquireGlobalLock(); 131 | _xmap.erase(ptr, sizeof(void *)); 132 | releaseGlobalLock(); 133 | MM::mmapDeallocate(objStatus->actualStart, objStatus->pageUpSize); 134 | HeapAllocator::deallocate(objStatus); 135 | } 136 | 137 | void acquireGlobalLock() { 138 | spin_lock(); 139 | } 140 | 141 | void releaseGlobalLock() { 142 | spin_unlock(); 143 | } 144 | 145 | private: 146 | size_t _bigObjectStatusSize = sizeof(bigObjectStatus); 147 | unsigned _bigObjectStatusSizeShiftBits = LOG2(_bigObjectStatusSize); 148 | pthread_spinlock_t _spin_lock; 149 | typedef HashMap objectHashMap; 150 | objectHashMap _xmap; 151 | 152 | inline void spin_lock() { 153 | pthread_spin_lock(&_spin_lock); 154 | } 155 | 156 | inline void spin_unlock() { 157 | pthread_spin_unlock(&_spin_lock); 158 | } 159 | }; 160 | 161 | #endif // __BIGHEAP_HH__ 162 | -------------------------------------------------------------------------------- /rng/arc4random.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: arc4random.c,v 1.54 2015/09/13 08:31:47 guenther Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1996, David Mazieres 5 | * Copyright (c) 2008, Damien Miller 6 | * Copyright (c) 2013, Markus Friedl 7 | * Copyright (c) 2014, Theo de Raadt 8 | * 9 | * Permission to use, copy, modify, and distribute this software for any 10 | * purpose with or without fee is hereby granted, provided that the above 11 | * copyright notice and this permission notice appear in all copies. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 | */ 21 | 22 | /* 23 | * ChaCha based random number generator for OpenBSD. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #define KEYSTREAM_ONLY 37 | #include "chacha_private.h" 38 | 39 | #define minimum(a, b) ((a) < (b) ? (a) : (b)) 40 | 41 | #if defined(__GNUC__) || defined(_MSC_VER) 42 | #define inline __inline 43 | #else /* __GNUC__ || _MSC_VER */ 44 | #define inline 45 | #endif /* !__GNUC__ && !_MSC_VER */ 46 | 47 | #define KEYSZ 32 48 | #define IVSZ 8 49 | #define BLOCKSZ 64 50 | #define RSBUFSZ (16*BLOCKSZ) 51 | 52 | /* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */ 53 | //static struct _rs { 54 | // size_t rs_have; /* valid bytes at end of rs_buf */ 55 | // size_t rs_count; /* bytes till reseed */ 56 | //} *rs; 57 | 58 | struct _rs { 59 | size_t rs_have; /* valid bytes at end of rs_buf */ 60 | size_t rs_count; /* bytes till reseed */ 61 | }; 62 | __thread struct _rs *rs; 63 | 64 | /* Maybe be preserved in fork children, if _rs_allocate() decides. */ 65 | //static struct _rsx { 66 | // chacha_ctx rs_chacha; /* chacha context for random keystream */ 67 | // u_char rs_buf[RSBUFSZ]; /* keystream blocks */ 68 | //} *rsx; 69 | 70 | struct _rsx{ 71 | chacha_ctx rs_chacha; /* chacha context for random keystream */ 72 | u_char rs_buf[RSBUFSZ]; /* keystream blocks */ 73 | }; 74 | __thread struct _rsx *rsx; 75 | 76 | static inline int _rs_allocate(struct _rs **, struct _rsx **); 77 | static inline void _rs_forkdetect(void); 78 | #include "arc4random.h" 79 | 80 | static inline void _rs_rekey(u_char *dat, size_t datlen); 81 | 82 | static inline void 83 | _rs_init(u_char *buf, size_t n) 84 | { 85 | if (n < KEYSZ + IVSZ) 86 | return; 87 | 88 | if (rs == NULL) { 89 | if (_rs_allocate(&rs, &rsx) == -1) 90 | abort(); 91 | } 92 | 93 | chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8, 0); 94 | chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ); 95 | } 96 | 97 | static void 98 | _rs_stir(void) 99 | { 100 | u_char rnd[KEYSZ + IVSZ]; 101 | 102 | if (getentropy(rnd, sizeof rnd) == -1) 103 | _getentropy_fail(); 104 | 105 | if (!rs) 106 | _rs_init(rnd, sizeof(rnd)); 107 | else 108 | _rs_rekey(rnd, sizeof(rnd)); 109 | //explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */ 110 | memset(rnd, 0, sizeof(rnd)); /* discard source seed */ 111 | 112 | /* invalidate rs_buf */ 113 | rs->rs_have = 0; 114 | memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); 115 | 116 | rs->rs_count = 1600000; 117 | } 118 | 119 | static inline void 120 | _rs_stir_if_needed(size_t len) 121 | { 122 | _rs_forkdetect(); 123 | if (!rs || rs->rs_count <= len) 124 | _rs_stir(); 125 | if (rs->rs_count <= len) 126 | rs->rs_count = 0; 127 | else 128 | rs->rs_count -= len; 129 | } 130 | 131 | static inline void 132 | _rs_rekey(u_char *dat, size_t datlen) 133 | { 134 | #ifndef KEYSTREAM_ONLY 135 | memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); 136 | #endif 137 | /* fill rs_buf with the keystream */ 138 | chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf, 139 | rsx->rs_buf, sizeof(rsx->rs_buf)); 140 | /* mix in optional user provided data */ 141 | if (dat) { 142 | size_t i, m; 143 | 144 | m = minimum(datlen, KEYSZ + IVSZ); 145 | for (i = 0; i < m; i++) 146 | rsx->rs_buf[i] ^= dat[i]; 147 | } 148 | /* immediately reinit for backtracking resistance */ 149 | _rs_init(rsx->rs_buf, KEYSZ + IVSZ); 150 | memset(rsx->rs_buf, 0, KEYSZ + IVSZ); 151 | rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ; 152 | } 153 | 154 | static inline void 155 | _rs_random_buf(void *_buf, size_t n) 156 | { 157 | u_char *buf = (u_char *)_buf; 158 | u_char *keystream; 159 | size_t m; 160 | 161 | _rs_stir_if_needed(n); 162 | while (n > 0) { 163 | if (rs->rs_have > 0) { 164 | m = minimum(n, rs->rs_have); 165 | keystream = rsx->rs_buf + sizeof(rsx->rs_buf) 166 | - rs->rs_have; 167 | memcpy(buf, keystream, m); 168 | memset(keystream, 0, m); 169 | buf += m; 170 | n -= m; 171 | rs->rs_have -= m; 172 | } 173 | if (rs->rs_have == 0) 174 | _rs_rekey(NULL, 0); 175 | } 176 | } 177 | 178 | static inline void 179 | _rs_random_u32(uint32_t *val) 180 | { 181 | u_char *keystream; 182 | 183 | _rs_stir_if_needed(sizeof(*val)); 184 | if (rs->rs_have < sizeof(*val)) 185 | _rs_rekey(NULL, 0); 186 | keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have; 187 | memcpy(val, keystream, sizeof(*val)); 188 | memset(keystream, 0, sizeof(*val)); 189 | rs->rs_have -= sizeof(*val); 190 | } 191 | 192 | uint32_t 193 | arc4random(void) 194 | { 195 | uint32_t val; 196 | 197 | // _ARC4_LOCK(); 198 | _rs_random_u32(&val); 199 | // _ARC4_UNLOCK(); 200 | return val; 201 | } 202 | 203 | void 204 | arc4random_buf(void *buf, size_t n) 205 | { 206 | // _ARC4_LOCK(); 207 | _rs_random_buf(buf, n); 208 | // _ARC4_UNLOCK(); 209 | } 210 | -------------------------------------------------------------------------------- /list.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file list.hh: double-linked list implementation. 21 | * @author Tongping Liu 22 | * @author Sam Silvestro 23 | */ 24 | #ifndef __LIST_HH__ 25 | #define __LIST_HH__ 26 | 27 | #include 28 | 29 | typedef struct list { 30 | struct list* prev; 31 | struct list* next; 32 | } list_t; 33 | 34 | // Initialize a node 35 | inline void nodeInit(list_t* node) { node->next = node->prev = node; } 36 | 37 | inline void listInit(list_t* node) { nodeInit(node); } 38 | 39 | // Whether a list is empty 40 | inline bool isListEmpty(list_t* head) { return (head->next == head); } 41 | 42 | // Next node of current node 43 | inline list_t* nextEntry(list_t* cur) { return cur->next; } 44 | 45 | // Previous node of current node 46 | inline list_t* prevEntry(list_t* cur) { return cur->prev; } 47 | 48 | // We donot check whetehr the list is empty or not? 49 | inline list_t* tailList(list_t* head) { 50 | list_t* tail = NULL; 51 | if(!isListEmpty(head)) { 52 | tail = head->prev; 53 | } 54 | 55 | return tail; 56 | } 57 | 58 | // Insert one entry to two consequtive entries 59 | inline void __insert_between(list_t* node, list_t* prev, list_t* next) { 60 | // fprintf(stderr, "line %d: prev %p next %p\n", __LINE__, prev, next); 61 | // fprintf(stderr, "line %d: prev now %lx next %p\n", __LINE__, *((unsigned long *)prev), next); 62 | // fprintf(stderr, "line %d: prev->next %lx next %p\n", __LINE__, *((unsigned long *)((unsigned 63 | // long)prev + 0x8)), next); 64 | node->next = next; 65 | node->prev = prev; 66 | prev->next = node; 67 | next->prev = node; 68 | } 69 | 70 | // Insert one entry to after specified entry prev (prev, prev->next) 71 | inline void listInsertNode(list_t* node, list_t* prev) { __insert_between(node, prev, prev->next); } 72 | 73 | // Insert one entry to the tail of specified list. 74 | // Insert between tail and head 75 | inline void listInsertTail(list_t* node, list_t* head) { 76 | // fprintf(stderr, "node %p head %p head->prev %p\n", node, head, head->prev); 77 | __insert_between(node, head->prev, head); 78 | } 79 | 80 | // Insert one entry to the head of specified list. 81 | // Insert between head and head->next 82 | inline void listInsertHead(list_t* node, list_t* head) { __insert_between(node, head, head->next); } 83 | 84 | // Internal usage to link p with n 85 | // Never use directly outside. 86 | inline void __list_link(list_t* p, list_t* n) { 87 | p->next = n; 88 | n->prev = p; 89 | } 90 | 91 | // We need to verify this 92 | // Insert one entry to the head of specified list. 93 | // Insert the list between where and where->next 94 | inline void listInsertList(list_t* list, list_t* where) { 95 | // Insert after where. 96 | __list_link(where, list); 97 | 98 | // Then modify other pointer 99 | __list_link(list->prev, where->next); 100 | } 101 | 102 | // Insert one list between where->prev and where, however, 103 | // we don't need to insert the node "list" itself 104 | inline void listInsertListTail(list_t* list, list_t* where) { 105 | #if 0 106 | // Link between where->prev and first node of list. 107 | list_t* origtail = where->prev; 108 | list_t* orighead = where; 109 | list_t* newhead = list->next; 110 | list_t* newtail = list->prev; 111 | 112 | origtail->next = newhead; 113 | newhead->prev = origtail; 114 | 115 | newtail->next = orighead; 116 | orighead->prev = newtail; 117 | 118 | p->next = n; 119 | n->prev = p; 120 | #else 121 | __list_link(where->prev, list->next); 122 | 123 | // Link between last node of list and where. 124 | __list_link(list->prev, where); 125 | #endif 126 | } 127 | 128 | // Delete an entry and re-initialize it. 129 | inline void listRemoveNode(list_t* node) { 130 | __list_link(node->prev, node->next); 131 | nodeInit(node); 132 | } 133 | 134 | // Check whether current node is the tail of a list 135 | inline bool isListTail(list_t* node, list_t* head) { return (node->next == head); } 136 | 137 | // Retrieve the first item form a list 138 | // Then this item will be removed from the list. 139 | inline list_t* listRetrieveItem(list_t* list) { 140 | list_t* first = NULL; 141 | 142 | // Retrieve item when the list is not empty 143 | if(!isListEmpty(list)) { 144 | first = list->next; 145 | listRemoveNode(first); 146 | } 147 | 148 | return first; 149 | } 150 | 151 | // Retrieve all items from a list and re-initialize all source list. 152 | inline void listRetrieveAllItems(list_t* dest, list_t* src) { 153 | list_t* first, *last; 154 | first = src->next; 155 | last = src->prev; 156 | 157 | first->prev = dest; 158 | last->next = dest; 159 | dest->next = first; 160 | dest->prev = last; 161 | 162 | // reinitialize the source list 163 | listInit(src); 164 | } 165 | 166 | // Print all entries in the link list 167 | inline void listPrintItems(list_t* head, int num) { 168 | int i = 0; 169 | list_t* first, *entry; 170 | entry = head->next; 171 | first = head; 172 | 173 | while(entry != first && i < num) { 174 | // fprintf(stderr, "%d: ENTRY %d: %p (prev %p). HEAD %p\n", getpid(), i++, entry, 175 | // entry->prev, head); 176 | entry = entry->next; 177 | } 178 | 179 | // PRINF("HEAD %p Head->prev %p head->next %p\n", head, head->prev, head->next); 180 | } 181 | 182 | /* Get the pointer to the struct this entry is part of 183 | * 184 | */ 185 | #define listEntry(ptr, type, member) ((type*)((char*)(ptr) - (unsigned long)(&((type*)0)->member))) 186 | 187 | #endif 188 | -------------------------------------------------------------------------------- /rng/chacha_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | chacha-merged.c version 20080118 3 | D. J. Bernstein 4 | Public domain. 5 | */ 6 | 7 | /* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */ 8 | 9 | typedef unsigned char u8; 10 | typedef unsigned int u32; 11 | 12 | typedef struct 13 | { 14 | u32 input[16]; /* could be compressed */ 15 | } chacha_ctx; 16 | 17 | #define U8C(v) (v##U) 18 | #define U32C(v) (v##U) 19 | 20 | #define U8V(v) ((u8)(v) & U8C(0xFF)) 21 | #define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) 22 | 23 | #define ROTL32(v, n) \ 24 | (U32V((v) << (n)) | ((v) >> (32 - (n)))) 25 | 26 | #define U8TO32_LITTLE(p) \ 27 | (((u32)((p)[0]) ) | \ 28 | ((u32)((p)[1]) << 8) | \ 29 | ((u32)((p)[2]) << 16) | \ 30 | ((u32)((p)[3]) << 24)) 31 | 32 | #define U32TO8_LITTLE(p, v) \ 33 | do { \ 34 | (p)[0] = U8V((v) ); \ 35 | (p)[1] = U8V((v) >> 8); \ 36 | (p)[2] = U8V((v) >> 16); \ 37 | (p)[3] = U8V((v) >> 24); \ 38 | } while (0) 39 | 40 | #define ROTATE(v,c) (ROTL32(v,c)) 41 | #define XOR(v,w) ((v) ^ (w)) 42 | #define PLUS(v,w) (U32V((v) + (w))) 43 | #define PLUSONE(v) (PLUS((v),1)) 44 | 45 | #define QUARTERROUND(a,b,c,d) \ 46 | a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ 47 | c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ 48 | a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ 49 | c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); 50 | 51 | static const char sigma[16] = "expand 32-byte k"; 52 | static const char tau[16] = "expand 16-byte k"; 53 | 54 | static void 55 | chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits) 56 | { 57 | const char *constants; 58 | 59 | x->input[4] = U8TO32_LITTLE(k + 0); 60 | x->input[5] = U8TO32_LITTLE(k + 4); 61 | x->input[6] = U8TO32_LITTLE(k + 8); 62 | x->input[7] = U8TO32_LITTLE(k + 12); 63 | if (kbits == 256) { /* recommended */ 64 | k += 16; 65 | constants = sigma; 66 | } else { /* kbits == 128 */ 67 | constants = tau; 68 | } 69 | x->input[8] = U8TO32_LITTLE(k + 0); 70 | x->input[9] = U8TO32_LITTLE(k + 4); 71 | x->input[10] = U8TO32_LITTLE(k + 8); 72 | x->input[11] = U8TO32_LITTLE(k + 12); 73 | x->input[0] = U8TO32_LITTLE(constants + 0); 74 | x->input[1] = U8TO32_LITTLE(constants + 4); 75 | x->input[2] = U8TO32_LITTLE(constants + 8); 76 | x->input[3] = U8TO32_LITTLE(constants + 12); 77 | } 78 | 79 | static void 80 | chacha_ivsetup(chacha_ctx *x,const u8 *iv) 81 | { 82 | x->input[12] = 0; 83 | x->input[13] = 0; 84 | x->input[14] = U8TO32_LITTLE(iv + 0); 85 | x->input[15] = U8TO32_LITTLE(iv + 4); 86 | } 87 | 88 | static void 89 | chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) 90 | { 91 | u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; 92 | u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; 93 | u8 *ctarget = NULL; 94 | u8 tmp[64]; 95 | u_int i; 96 | 97 | if (!bytes) return; 98 | 99 | j0 = x->input[0]; 100 | j1 = x->input[1]; 101 | j2 = x->input[2]; 102 | j3 = x->input[3]; 103 | j4 = x->input[4]; 104 | j5 = x->input[5]; 105 | j6 = x->input[6]; 106 | j7 = x->input[7]; 107 | j8 = x->input[8]; 108 | j9 = x->input[9]; 109 | j10 = x->input[10]; 110 | j11 = x->input[11]; 111 | j12 = x->input[12]; 112 | j13 = x->input[13]; 113 | j14 = x->input[14]; 114 | j15 = x->input[15]; 115 | 116 | for (;;) { 117 | if (bytes < 64) { 118 | for (i = 0;i < bytes;++i) tmp[i] = m[i]; 119 | m = tmp; 120 | ctarget = c; 121 | c = tmp; 122 | } 123 | x0 = j0; 124 | x1 = j1; 125 | x2 = j2; 126 | x3 = j3; 127 | x4 = j4; 128 | x5 = j5; 129 | x6 = j6; 130 | x7 = j7; 131 | x8 = j8; 132 | x9 = j9; 133 | x10 = j10; 134 | x11 = j11; 135 | x12 = j12; 136 | x13 = j13; 137 | x14 = j14; 138 | x15 = j15; 139 | for (i = 20;i > 0;i -= 2) { 140 | QUARTERROUND( x0, x4, x8,x12) 141 | QUARTERROUND( x1, x5, x9,x13) 142 | QUARTERROUND( x2, x6,x10,x14) 143 | QUARTERROUND( x3, x7,x11,x15) 144 | QUARTERROUND( x0, x5,x10,x15) 145 | QUARTERROUND( x1, x6,x11,x12) 146 | QUARTERROUND( x2, x7, x8,x13) 147 | QUARTERROUND( x3, x4, x9,x14) 148 | } 149 | x0 = PLUS(x0,j0); 150 | x1 = PLUS(x1,j1); 151 | x2 = PLUS(x2,j2); 152 | x3 = PLUS(x3,j3); 153 | x4 = PLUS(x4,j4); 154 | x5 = PLUS(x5,j5); 155 | x6 = PLUS(x6,j6); 156 | x7 = PLUS(x7,j7); 157 | x8 = PLUS(x8,j8); 158 | x9 = PLUS(x9,j9); 159 | x10 = PLUS(x10,j10); 160 | x11 = PLUS(x11,j11); 161 | x12 = PLUS(x12,j12); 162 | x13 = PLUS(x13,j13); 163 | x14 = PLUS(x14,j14); 164 | x15 = PLUS(x15,j15); 165 | 166 | #ifndef KEYSTREAM_ONLY 167 | x0 = XOR(x0,U8TO32_LITTLE(m + 0)); 168 | x1 = XOR(x1,U8TO32_LITTLE(m + 4)); 169 | x2 = XOR(x2,U8TO32_LITTLE(m + 8)); 170 | x3 = XOR(x3,U8TO32_LITTLE(m + 12)); 171 | x4 = XOR(x4,U8TO32_LITTLE(m + 16)); 172 | x5 = XOR(x5,U8TO32_LITTLE(m + 20)); 173 | x6 = XOR(x6,U8TO32_LITTLE(m + 24)); 174 | x7 = XOR(x7,U8TO32_LITTLE(m + 28)); 175 | x8 = XOR(x8,U8TO32_LITTLE(m + 32)); 176 | x9 = XOR(x9,U8TO32_LITTLE(m + 36)); 177 | x10 = XOR(x10,U8TO32_LITTLE(m + 40)); 178 | x11 = XOR(x11,U8TO32_LITTLE(m + 44)); 179 | x12 = XOR(x12,U8TO32_LITTLE(m + 48)); 180 | x13 = XOR(x13,U8TO32_LITTLE(m + 52)); 181 | x14 = XOR(x14,U8TO32_LITTLE(m + 56)); 182 | x15 = XOR(x15,U8TO32_LITTLE(m + 60)); 183 | #endif 184 | 185 | j12 = PLUSONE(j12); 186 | if (!j12) { 187 | j13 = PLUSONE(j13); 188 | /* stopping at 2^70 bytes per nonce is user's responsibility */ 189 | } 190 | 191 | U32TO8_LITTLE(c + 0,x0); 192 | U32TO8_LITTLE(c + 4,x1); 193 | U32TO8_LITTLE(c + 8,x2); 194 | U32TO8_LITTLE(c + 12,x3); 195 | U32TO8_LITTLE(c + 16,x4); 196 | U32TO8_LITTLE(c + 20,x5); 197 | U32TO8_LITTLE(c + 24,x6); 198 | U32TO8_LITTLE(c + 28,x7); 199 | U32TO8_LITTLE(c + 32,x8); 200 | U32TO8_LITTLE(c + 36,x9); 201 | U32TO8_LITTLE(c + 40,x10); 202 | U32TO8_LITTLE(c + 44,x11); 203 | U32TO8_LITTLE(c + 48,x12); 204 | U32TO8_LITTLE(c + 52,x13); 205 | U32TO8_LITTLE(c + 56,x14); 206 | U32TO8_LITTLE(c + 60,x15); 207 | 208 | if (bytes <= 64) { 209 | if (bytes < 64) { 210 | for (i = 0;i < bytes;++i) ctarget[i] = c[i]; 211 | } 212 | x->input[12] = j12; 213 | x->input[13] = j13; 214 | return; 215 | } 216 | bytes -= 64; 217 | c += 64; 218 | #ifndef KEYSTREAM_ONLY 219 | m += 64; 220 | #endif 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /log.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file log.hh: logging and debug printing macros. 21 | * Color codes from SNAPPLE: http://sourceforge.net/projects/snapple/ 22 | * @author Tongping Liu , Charlie Curtsinger 23 | * @author Sam Silvestro 24 | */ 25 | #ifndef __LOG_HH__ 26 | #define __LOG_HH__ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include "xdefines.hh" 33 | 34 | #ifndef DEBUG_LEVEL 35 | #define DEBUG_LEVEL 0 36 | #endif 37 | 38 | #define NORMAL_CYAN "\033[36m" 39 | #define NORMAL_MAGENTA "\033[35m" 40 | #define NORMAL_BLUE "\033[34m" 41 | #define NORMAL_YELLOW "\033[33m" 42 | #define NORMAL_GREEN "\033[32m" 43 | #define NORMAL_RED "\033[31m" 44 | 45 | #define BRIGHT_CYAN "\033[1m\033[36m" 46 | #define BRIGHT_MAGENTA "\033[1m\033[35m" 47 | #define BRIGHT_BLUE "\033[1m\033[34m" 48 | #define BRIGHT_YELLOW "\033[1m\033[33m" 49 | #define BRIGHT_GREEN "\033[1m\033[32m" 50 | #define BRIGHT_RED "\033[1m\033[31m" 51 | 52 | #define ESC_INF NORMAL_CYAN 53 | #define ESC_DBG NORMAL_GREEN 54 | #define ESC_WRN BRIGHT_YELLOW 55 | #define ESC_ERR BRIGHT_RED 56 | #define ESC_END "\033[0m" 57 | 58 | #define OUTPUT write 59 | 60 | #ifndef NDEBUG 61 | /** 62 | * Print status-information message: level 0 63 | */ 64 | #define PRINF(fmt, ...) \ 65 | { \ 66 | if(DEBUG_LEVEL < 1) { \ 67 | ::snprintf(getThreadBuffer(), LOG_SIZE, \ 68 | ESC_INF "%lx [INFO]: %20s:%-4d: " fmt ESC_END "\n", pthread_self(), \ 69 | __FILE__, __LINE__, ##__VA_ARGS__); \ 70 | OUTPUT(OUTFD, getThreadBuffer(), strlen(getThreadBuffer())); \ 71 | } \ 72 | } 73 | 74 | /** 75 | * Print status-information message: level 1 76 | */ 77 | #define PRDBG(fmt, ...) \ 78 | { \ 79 | if(DEBUG_LEVEL < 2) { \ 80 | ::snprintf(getThreadBuffer(), LOG_SIZE, \ 81 | ESC_DBG "%lx [DBG]: %20s:%-4d: " fmt ESC_END "\n", pthread_self(), \ 82 | __FILE__, __LINE__, ##__VA_ARGS__); \ 83 | OUTPUT(OUTFD, getThreadBuffer(), strlen(getThreadBuffer())); \ 84 | } \ 85 | } 86 | 87 | /** 88 | * Print warning message: level 2 89 | */ 90 | #define PRWRN(fmt, ...) \ 91 | { \ 92 | if(DEBUG_LEVEL < 3) { \ 93 | ::snprintf(getThreadBuffer(), LOG_SIZE, \ 94 | ESC_WRN "%lx [WRN]: %20s:%-4d: " fmt ESC_END "\n", pthread_self(), \ 95 | __FILE__, __LINE__, ##__VA_ARGS__); \ 96 | OUTPUT(OUTFD, getThreadBuffer(), strlen(getThreadBuffer())); \ 97 | } \ 98 | } 99 | #else 100 | #define PRINF(fmt, ...) 101 | #define PRDBG(fmt, ...) 102 | #define PRWRN(fmt, ...) 103 | #endif 104 | 105 | /** 106 | * Print error message: level 3 107 | */ 108 | #define PRERR(fmt, ...) \ 109 | { \ 110 | if(DEBUG_LEVEL < 4) { \ 111 | ::snprintf(getThreadBuffer(), LOG_SIZE, \ 112 | ESC_ERR "%lx [ERR]: %20s:%-4d: " fmt ESC_END "\n", pthread_self(), \ 113 | __FILE__, __LINE__, ##__VA_ARGS__); \ 114 | OUTPUT(OUTFD, getThreadBuffer(), strlen(getThreadBuffer())); \ 115 | } \ 116 | } 117 | 118 | // Can't be turned off. But we don't want to output those line number information. 119 | #define PRINT(fmt, ...) \ 120 | { \ 121 | ::snprintf(getThreadBuffer(), LOG_SIZE, BRIGHT_MAGENTA fmt ESC_END "\n", ##__VA_ARGS__); \ 122 | OUTPUT(OUTFD, getThreadBuffer(), strlen(getThreadBuffer())); \ 123 | } 124 | 125 | /** 126 | * Print fatal error message, the program is going to exit. 127 | */ 128 | 129 | #define FATAL(fmt, ...) \ 130 | { \ 131 | ::snprintf(getThreadBuffer(), LOG_SIZE, \ 132 | ESC_ERR "%lx [FATALERROR]: %20s:%-4d: " fmt ESC_END "\n", \ 133 | pthread_self(), __FILE__, __LINE__, ##__VA_ARGS__); \ 134 | OUTPUT(OUTFD, getThreadBuffer(), strlen(getThreadBuffer())); \ 135 | exit(-1); \ 136 | } 137 | 138 | // Check a condition. If false, print an error message and abort 139 | #define REQUIRE(cond, ...) \ 140 | if(!(cond)) { \ 141 | FATAL(__VA_ARGS__) \ 142 | } 143 | 144 | #endif 145 | -------------------------------------------------------------------------------- /xdefines.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file xdefines.hh: global constants, enums, definitions, and more. 21 | * @author Tongping Liu 22 | * @author Sam Silvestro 23 | */ 24 | #ifndef __XDEFINES_HH__ 25 | #define __XDEFINES_HH__ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "slist.h" 33 | #include "dlist.h" 34 | 35 | /* 36 | * @file xdefines.h 37 | */ 38 | 39 | extern char * getThreadBuffer(); 40 | 41 | extern "C" { 42 | #ifndef CUSTOMIZED_STACK 43 | __thread extern int _threadIndex; 44 | #endif 45 | typedef void * threadFunction(void*); 46 | 47 | #ifdef LOGTOFILE 48 | extern int outputfd; 49 | #endif 50 | 51 | #ifndef PTHREADEXIT_CODE 52 | #define PTHREADEXIT_CODE 2230 53 | #endif 54 | 55 | typedef enum { LEFT, RIGHT } direction; 56 | 57 | #ifdef LOGTOFILE 58 | inline int getOutputFD() { 59 | return outputfd; 60 | } 61 | #endif 62 | 63 | #ifndef CUSTOMIZED_STACK 64 | inline int getThreadIndex(void * stackVar = NULL) { 65 | #pragma message "using non-customized stack" 66 | return _threadIndex; 67 | } 68 | 69 | inline void setThreadIndex(int index) { 70 | _threadIndex = index; 71 | } 72 | #endif 73 | inline size_t alignup(size_t size, size_t alignto) { 74 | return (size % alignto == 0) ? size : ((size + (alignto - 1)) & ~(alignto - 1)); 75 | } 76 | 77 | inline void * alignupPointer(void * ptr, size_t alignto) { 78 | return ((intptr_t)ptr%alignto == 0) ? ptr : (void *)(((intptr_t)ptr + (alignto - 1)) & ~(alignto - 1)); 79 | } 80 | 81 | inline size_t aligndown(size_t addr, size_t alignto) { return (addr & ~(alignto - 1)); } 82 | 83 | #ifdef LOGTOFILE 84 | #define OUTFD getOutputFD() 85 | #else 86 | #define OUTFD 2 87 | #endif 88 | #define LOG_SIZE 4096 89 | 90 | }; // extern "C" 91 | 92 | #define LOG2(x) ((unsigned) (8*sizeof(unsigned long long) - __builtin_clzll((x)) - 1)) 93 | 94 | #define DEFAULT_MAX_ALIVE_THREADS 128 95 | //#define MAX_ALIVE_THREADS opts.max_alive_threads 96 | #define MAX_ALIVE_THREADS 128 97 | 98 | #define UNINITIALIZED_CACHE_REGION -1 99 | #define ALLOC_SENTINEL 0x1 100 | #define FREE_SENTINEL 0x0 101 | #ifdef USE_CANARY 102 | #pragma message "canary value in use" 103 | #define CANARY_SENTINEL 0x7B 104 | #define NUM_MORE_CANARIES_TO_CHECK 2 105 | #define IF_CANARY_CONDITION ((size + 1) > LARGE_OBJECT_THRESHOLD) 106 | #else 107 | #define IF_CANARY_CONDITION (size > LARGE_OBJECT_THRESHOLD) 108 | #endif 109 | 110 | #ifdef SSE2RNG 111 | #define RNG_MAX 0x8000 112 | #define SRAND(x) srand_sse(x) 113 | #else 114 | #define RNG_MAX RAND_MAX 115 | #define SRAND(x) srand(x) 116 | #endif 117 | 118 | #define DEFAULT_BIBOP_ENTROPY_BITS 10 119 | #define BIBOP_ENTROPY_BITS opts.bibop_entropy_bits 120 | #define BIBOP_CACHE_SIZE opts.bibop_cache_size 121 | #define BIBOP_CACHE_SIZE_MASK (BIBOP_CACHE_SIZE - 1) 122 | #define BIBOP_HALF_CACHE_SIZE (BIBOP_CACHE_SIZE >> 1) 123 | #define BIBOP_HALF_CACHE_SIZE_MASK (BIBOP_HALF_CACHE_SIZE - 1) 124 | #define NUM_CACHE_REGIONS 8 125 | #define NUM_CACHE_REGIONS_MASK (NUM_CACHE_REGIONS - 1) 126 | #define NUM_CACHE_REGIONS_SHIFT_BITS LOG2(NUM_CACHE_REGIONS) 127 | #define CACHE_REGION_SIZE (BIBOP_CACHE_SIZE >> NUM_CACHE_REGIONS_SHIFT_BITS) 128 | #define CACHE_REGION_SIZE_MASK (CACHE_REGION_SIZE - 1) 129 | #define CACHE_REGION_SIZE_SHIFT_BITS LOG2(CACHE_REGION_SIZE) 130 | 131 | #define DEFAULT_OVER_PROV_OBJ_BUF_SZ (BIBOP_CACHE_SIZE >> 1) 132 | #define OVER_PROV_OBJ_BUF_SZ (BIBOP_CACHE_SIZE >> 1) 133 | #define NUM_DEAD_OBJS (OVER_PROV_OBJ_BUF_SZ * \ 134 | (opts.over_prov_numerator - opts.over_prov_denominator) / opts.over_prov_numerator) 135 | #define DEFAULT_OVER_PROV_NUMERATOR 8 136 | #define DEFAULT_OVER_PROV_DENOMINATOR 7 137 | #define DEFAULT_RAND_GUARD_PROP 0.1 // 10% guard pages per bag 138 | 139 | #define PAGESIZE 0x1000 140 | #define CACHE_LINE_SIZE 64 141 | 142 | #define N_64BITS 64 143 | #define TWO_KILOBYTES 2048 144 | #ifdef DESTROY_ON_FREE 145 | #pragma message "destroy-on-free feature in use" 146 | #endif 147 | 148 | struct guarder_opts { 149 | unsigned max_alive_threads = DEFAULT_MAX_ALIVE_THREADS; 150 | unsigned bibop_entropy_bits = DEFAULT_BIBOP_ENTROPY_BITS; 151 | unsigned bibop_cache_size = (1U << (DEFAULT_BIBOP_ENTROPY_BITS + 1)); 152 | unsigned over_prov_numerator = DEFAULT_OVER_PROV_NUMERATOR; 153 | unsigned over_prov_denominator = DEFAULT_OVER_PROV_DENOMINATOR; 154 | float random_guard_prop = DEFAULT_RAND_GUARD_PROP; 155 | }; 156 | 157 | 158 | /* 159 | * Important: 160 | * All BiBOP-related parameters must be specified as powers of 2 161 | */ 162 | //#define BIBOP_BAG_SIZE (size_t)0x080000000 // 2GB 163 | //#define BIBOP_BAG_SIZE (size_t)0x040000000 // 1GB 164 | //#define BIBOP_BAG_SIZE (size_t)0x020000000 // 512MB 165 | //#define BIBOP_BAG_SIZE (size_t)0x010000000 // 256MB (not for PARSEC) 166 | 167 | // Many PARSEC tests require at least a 512MB bag size 168 | //#define MIN_RANDOM_BAG_SIZE (size_t)0x100000000 // 4GB 169 | #define MIN_RANDOM_BAG_SIZE (size_t)0x200000000 // 4GB 170 | #define MAX_RANDOM_BAG_SIZE (size_t)0x200000000 // 8GB 171 | 172 | #define BIBOP_NUM_BAGS 16 173 | #define BIBOP_MIN_BLOCK_SIZE 16 174 | //#define LARGE_OBJECT_THRESHOLD (1U << (LOG2(BIBOP_MIN_BLOCK_SIZE) + BIBOP_NUM_BAGS - 1) 175 | #define LARGE_OBJECT_THRESHOLD 0x80000 // 512KB 176 | 177 | #define BIBOP_NUM_BAGS_MASK (BIBOP_NUM_BAGS - 1) 178 | #define BIBOP_NUM_SUBHEAPS MAX_ALIVE_THREADS 179 | #define BIBOP_SUBHEAP_SIZE (size_t)(BIBOP_NUM_BAGS * _bibopBagSize) 180 | #define BIBOP_HEAP_SIZE (size_t)(BIBOP_SUBHEAP_SIZE * BIBOP_NUM_SUBHEAPS) 181 | #define PageSize 4096UL 182 | #define PageMask (PageSize - 1) 183 | #define RANDOM_GUARD_PROP (opts.random_guard_prop) 184 | #define RANDOM_GUARD_RAND_CUTOFF (RANDOM_GUARD_PROP * RNG_MAX) 185 | #define THREAD_MAP_SIZE 1280 186 | 187 | #ifdef CUSTOMIZED_STACK 188 | #define STACK_SIZE 0x800000 // 8M, PageSize * N 189 | #define STACK_SIZE_BIT 23 // 8M 190 | #define MAX_THREADS MAX_ALIVE_THREADS 191 | #define INLINE inline __attribute__((always_inline)) 192 | 193 | #define GUARD_PAGE_SIZE PageSize // PageSize * N 194 | #include 195 | extern intptr_t globalStackAddr; 196 | // Get the thread index by its stack address 197 | INLINE int getThreadIndex(void* stackVar) { 198 | //int index = ((intptr_t)stackVar - globalStackAddr) / STACK_SIZE; 199 | int index = ((intptr_t)stackVar - globalStackAddr) >> STACK_SIZE_BIT; 200 | #if 0 // test 201 | if(index >= MAX_THREADS || index < 0) { 202 | fprintf(stderr, "var %p stackaddr %lx index %d\n", stackVar, globalStackAddr, index); 203 | } 204 | 205 | if(index == 1 ) { 206 | //char * tmp = (char*)(globalStackAddr + (index+1) * STACK_SIZE - 512); 207 | char * tmp = (char*)(globalStackAddr + (index) * STACK_SIZE + 512); 208 | fprintf(stderr, "touch %p thread %d %p - %p\n", tmp, index, globalStackAddr + (index) * STACK_SIZE, globalStackAddr + (index+1) * STACK_SIZE); 209 | *tmp = 'a'; 210 | } 211 | #endif 212 | #ifdef CUSTOMIZED_MAIN_STACK 213 | assert(index >= 0 && index < MAX_THREADS); 214 | return index; 215 | #endif 216 | if (index >= MAX_THREADS || index <= 0) return 0; 217 | else return index; 218 | } 219 | #endif 220 | 221 | #define WORD_SIZE sizeof(size_t) 222 | #define POINTER_SIZE sizeof(void *) 223 | #define PTR_SIZE_SHIFT_BITS LOG2(sizeof(void *)) 224 | #define CALLSTACK_DEPTH 3 225 | 226 | typedef char shadowObjectInfo; 227 | 228 | #endif 229 | -------------------------------------------------------------------------------- /xthread.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file xthread.hh: thread-related functions implementation. 21 | * @author Tongping Liu 22 | * @author Sam Silvestro 23 | */ 24 | #ifndef __XTHREAD_HH__ 25 | #define __XTHREAD_HH__ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "hashmap.hh" 34 | #include "hashfuncs.hh" 35 | #include "hashheapallocator.hh" 36 | #include "log.hh" 37 | #include "real.hh" 38 | #include "threadstruct.hh" 39 | #include "xdefines.hh" 40 | #ifdef SSE2RNG 41 | #include "sse2rng.h" 42 | #endif 43 | 44 | #ifdef CUSTOMIZED_STACK 45 | extern intptr_t globalStackAddr; 46 | #endif 47 | 48 | class xthread { 49 | 50 | public: 51 | static xthread& getInstance() { 52 | static char buf[sizeof(xthread)]; 53 | static xthread* xthreadObject = new (buf) xthread(); 54 | return *xthreadObject; 55 | } 56 | 57 | void initialize() { 58 | _aliveThreads = 0; 59 | _threadIndex = 0; 60 | 61 | // Initialize the spin_lock 62 | pthread_spin_init(&_spin_lock, PTHREAD_PROCESS_PRIVATE); 63 | 64 | thread_t * thread; 65 | 66 | // Shared the threads information. 67 | memset(&_threads, 0, sizeof(_threads)); 68 | 69 | // Initialize all 70 | for(int i = 0; i < MAX_ALIVE_THREADS; i++) { 71 | thread = &_threads[i]; 72 | 73 | // Those information that are only initialized once. 74 | thread->available = true; 75 | thread->index = i; 76 | } 77 | 78 | // Now we will intialize the initial thread 79 | initializeInitialThread(); 80 | 81 | _xmap.initialize(HashFuncs::hashAddr, HashFuncs::compareAddr, THREAD_MAP_SIZE); 82 | _xmap.insert((void*)pthread_self(), sizeof(void*), 0); 83 | } 84 | 85 | void initializeInitialThread(void) { 86 | int tindex = allocThreadIndex(); 87 | assert(tindex == 0); 88 | 89 | thread_t * thread = getThread(tindex); 90 | 91 | // Initial myself, like threadIndex, tid 92 | initializeCurrentThread(thread); 93 | } 94 | 95 | // This function is only called in the current thread before the real thread function 96 | void initializeCurrentThread(thread_t * thread) { 97 | SRAND(time(NULL)); 98 | thread->tid = syscall(__NR_gettid); 99 | #ifndef CUSTOMIZED_STACK 100 | setThreadIndex(thread->index); 101 | #endif 102 | // Adding the thread's pthreadt. 103 | thread->pthreadt = pthread_self(); 104 | } 105 | 106 | void reinitialize() { 107 | _aliveThreads = 1; 108 | _threadIndex = 0; 109 | 110 | // Reinitialize the spin_lock 111 | pthread_spin_init(&_spin_lock, PTHREAD_PROCESS_PRIVATE); 112 | 113 | thread_t * thread; 114 | 115 | int currentThreadIndex = getThreadIndex(&thread); 116 | 117 | // Initialize all 118 | for(int i = 0; i < MAX_ALIVE_THREADS; i++) { 119 | thread = &_threads[i]; 120 | 121 | // Reinitialize the current living thread 122 | // (the initiator of the fork) 123 | if(i == currentThreadIndex) { 124 | initializeCurrentThread(thread); 125 | continue; 126 | } 127 | 128 | // Those information that are only initialized once. 129 | thread->available = true; 130 | thread->index = i; 131 | } 132 | 133 | _xmap.initialize(HashFuncs::hashAddr, HashFuncs::compareAddr, THREAD_MAP_SIZE); 134 | _xmap.insert((void*)pthread_self(), sizeof(void*), currentThreadIndex); 135 | } 136 | 137 | /// @ internal function: allocation a thread index when spawning. 138 | /// Since we guarantee that only one thread can be in spawning phase, 139 | /// there is no need to acqurie the lock in this function. 140 | int allocThreadIndex() { 141 | int index = -1; 142 | 143 | if(_aliveThreads == MAX_ALIVE_THREADS) { 144 | FATAL("maximum concurrent thread limit reached (%d)", MAX_ALIVE_THREADS); 145 | } 146 | 147 | thread_t* thread; 148 | if(_aliveThreads++ == _threadIndex) { 149 | index = _threadIndex++; 150 | thread = getThread(index); 151 | thread->available = false; 152 | } else { 153 | for(int i = 0; i <= _threadIndex; i++) { 154 | thread = getThread(i); 155 | if(thread->available) { 156 | thread->available = false; 157 | index = i; 158 | break; 159 | } 160 | } 161 | } 162 | return index; 163 | } 164 | 165 | inline thread_t* getThread(int index) { return &_threads[index]; } 166 | #ifndef CUSTOMIZED_STACK 167 | inline thread_t* getThread() { return &_threads[getThreadIndex()]; } 168 | #endif 169 | 170 | int thread_create(pthread_t * tid, const pthread_attr_t * attr, threadFunction * fn, void * arg) { 171 | acquireGlobalLock(); 172 | int tindex = allocThreadIndex(); 173 | releaseGlobalLock(); 174 | 175 | // Acquire the thread structure. 176 | thread_t* children = getThread(tindex); 177 | children->startArg = arg; 178 | children->startRoutine = fn; 179 | children->index = tindex; 180 | 181 | #ifdef CUSTOMIZED_STACK 182 | pthread_attr_t iattr; 183 | if(attr == NULL) { 184 | pthread_attr_init(&iattr); 185 | } else { 186 | memcpy(&iattr, attr, sizeof(pthread_attr_t)); 187 | } 188 | pthread_attr_setstack(&iattr, (void*)(globalStackAddr + (intptr_t)tindex * STACK_SIZE + GUARD_PAGE_SIZE), STACK_SIZE - 2 * GUARD_PAGE_SIZE); 189 | /* Guard pages have already been setted before main() 190 | if(0 != mprotect((void*)(childrenStackStart + STACK_SIZE - GUARD_PAGE_SIZE), GUARD_PAGE_SIZE, PROT_NONE) 191 | || 0 != mprotect((void*)childrenStackStart, GUARD_PAGE_SIZE, PROT_NONE)) { 192 | fprintf(stderr, "Failed to set guard page for thread#%d\n", tindex); 193 | abort(); 194 | } 195 | */ 196 | 197 | int result = Real::pthread_create(tid, &iattr, xthread::startThread, (void *)children); 198 | #else 199 | int result = Real::pthread_create(tid, attr, xthread::startThread, (void *)children); 200 | #endif 201 | 202 | if(result) { 203 | FATAL("thread_create failure"); 204 | } 205 | 206 | // Setting up this in the main thread so that 207 | // pthread_join can always find its pthread_t. 208 | // Otherwise, it can fail because the child have set this value. 209 | children->pthreadt = *tid; 210 | acquireGlobalLock(); 211 | _xmap.insertIfAbsent((void*)*tid, sizeof(void*), tindex); 212 | releaseGlobalLock(); 213 | return result; 214 | } 215 | 216 | static void * startThread(void * arg) { 217 | thread_t * current = (thread_t *) arg; 218 | 219 | xthread::getInstance().initializeCurrentThread(current); 220 | 221 | // Actually run this thread using the function call 222 | void * result = NULL; 223 | try{ 224 | result = current->startRoutine(current->startArg); 225 | } 226 | catch (int err){ 227 | if(err != PTHREADEXIT_CODE){ 228 | throw err; 229 | } 230 | } 231 | 232 | return result; 233 | } 234 | 235 | int thread_join(pthread_t tid, void ** retval) { 236 | int joinretval; 237 | if((joinretval = Real::pthread_join(tid, retval)) == 0) { 238 | int joinee = -1; 239 | 240 | acquireGlobalLock(); 241 | if(!_xmap.find((void *)tid, sizeof(void *), &joinee)) { 242 | PRERR("Cannot find joinee index for thread %p", (void *)tid); 243 | } else { 244 | _threads[joinee].available = true; 245 | } 246 | _aliveThreads--; 247 | releaseGlobalLock(); 248 | } 249 | return joinretval; 250 | } 251 | 252 | void acquireGlobalLock() { 253 | spin_lock(); 254 | } 255 | 256 | void releaseGlobalLock() { 257 | spin_unlock(); 258 | } 259 | 260 | private: 261 | inline void spin_lock() { 262 | pthread_spin_lock(&_spin_lock); 263 | } 264 | 265 | inline void spin_unlock() { 266 | pthread_spin_unlock(&_spin_lock); 267 | } 268 | 269 | pthread_spinlock_t _spin_lock; 270 | // The next available thread index for use by a new thread. 271 | int _threadIndex; 272 | typedef HashMap threadHashMap; 273 | threadHashMap _xmap; // The hash map that map the address of pthread_t to thread index. 274 | // Use _threadIndex as the total possible number of alive threads at 275 | // any given time during execution. 276 | int _aliveThreads; 277 | thread_t _threads[MAX_ALIVE_THREADS]; 278 | }; 279 | #endif 280 | -------------------------------------------------------------------------------- /hashmap.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file hashmap.hh: hash map implementation. 21 | * The original design is from kulesh [squiggly] isis.poly.edu 22 | * @author Tongping Liu 23 | * @author Sam Silvestro 24 | */ 25 | #ifndef __FCHASHMAP_HH__ 26 | #define __FCHASHMAP_HH__ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "list.hh" 35 | #include "xdefines.hh" 36 | 37 | template // Where to call malloc 40 | class HashMap { 41 | 42 | // Each entry has a lock. 43 | struct HashEntry { 44 | list_t list; 45 | // Each entry has a separate lock 46 | size_t count; // How many _entries in this list 47 | 48 | void initialize() { 49 | count = 0; 50 | listInit(&list); 51 | } 52 | 53 | void* getFirstEntry() { return (void*)list.next; } 54 | }; 55 | 56 | struct Entry { 57 | list_t list; 58 | KeyType key; 59 | size_t keylen; 60 | ValueType value; 61 | 62 | void initialize(KeyType ikey = 0, int ikeylen = 0, ValueType ivalue = 0) { 63 | listInit(&list); 64 | key = ikey; 65 | keylen = ikeylen; 66 | value = ivalue; 67 | } 68 | 69 | void erase() { listRemoveNode(&list); } 70 | 71 | struct Entry* nextEntry() { return (struct Entry*)list.next; } 72 | 73 | ValueType getValue() { return value; } 74 | 75 | KeyType getKey() { return key; } 76 | }; 77 | 78 | bool _initialized; 79 | struct HashEntry* _entries; 80 | size_t _buckets; // How many buckets in total 81 | size_t _bucketsUsed; // How many buckets in total 82 | 83 | typedef bool (*keycmpFuncPtr)(const KeyType, const KeyType, size_t); 84 | typedef size_t (*hashFuncPtr)(const KeyType, size_t); 85 | keycmpFuncPtr _keycmp; 86 | hashFuncPtr _hashfunc; 87 | 88 | public: 89 | HashMap() : _initialized(false) { 90 | // printf("RESET hashmap at %p\n", &_initialized); 91 | } 92 | 93 | void initialize(hashFuncPtr hfunc, keycmpFuncPtr kcmp, const size_t size = 4096) { 94 | _entries = NULL; 95 | _bucketsUsed = 0; 96 | _buckets = size; 97 | 98 | if(hfunc == NULL || kcmp == NULL) { 99 | //PRINF("Hashfunc or kcmp should not be null\n"); 100 | abort(); 101 | } 102 | 103 | // Initialize those functions. 104 | _hashfunc = hfunc; 105 | _keycmp = kcmp; 106 | 107 | // Allocated predefined size. 108 | _entries = (struct HashEntry*)SourceHeap::allocate(size * sizeof(struct HashEntry)); 109 | // PRINF("hashmap initialization at %p pid %d index %d\n", &_initialized,getpid(), 110 | // getThreadIndex()); 111 | // PRINF("hashmap initialization _entries %p\n", _entries); 112 | 113 | // Initialize all of these _entries. 114 | struct HashEntry* entry; 115 | for(size_t i = 0; i < size; i++) { 116 | entry = getHashEntry(i); 117 | entry->initialize(); 118 | } 119 | _initialized = true; 120 | } 121 | 122 | inline struct HashEntry* getHashEntry(size_t index) { 123 | if(index < _buckets) { 124 | return &_entries[index]; 125 | } else { 126 | return NULL; 127 | } 128 | } 129 | 130 | inline size_t hashIndex(const KeyType& key, size_t keylen) { 131 | size_t hkey = _hashfunc(key, keylen); 132 | return hkey % _buckets; 133 | } 134 | 135 | // Look up whether an entry is existing or not. 136 | // If existing, return true. *value should be carried specific value for this key. 137 | // Otherwise, return false. 138 | bool find(const KeyType& key, size_t keylen, ValueType* value) { 139 | assert(_initialized == true); 140 | size_t hindex = hashIndex(key, keylen); 141 | struct HashEntry* first = getHashEntry(hindex); 142 | struct Entry* entry = getEntry(first, key, keylen); 143 | bool isFound = false; 144 | 145 | if(entry) { 146 | *value = entry->value; 147 | isFound = true; 148 | } 149 | 150 | return isFound; 151 | } 152 | 153 | void insert(const KeyType& key, size_t keylen, ValueType value) { 154 | if(_initialized != true) { 155 | //PRINT("process %d index %d: initialized at %p hashmap is not true\n", getpid(), 156 | // getThreadIndex(), &_initialized); 157 | } 158 | 159 | assert(_initialized == true); 160 | size_t hindex = hashIndex(key, keylen); 161 | // PRINF("Insert entry: before inserting\n"); 162 | struct HashEntry* first = getHashEntry(hindex); 163 | 164 | // PRINF("Insert entry: key %p\n", key); 165 | insertEntry(first, key, keylen, value); 166 | } 167 | 168 | // Insert a hash table entry if it is not existing. 169 | // If the entry is already existing, return true 170 | bool insertIfAbsent(const KeyType& key, size_t keylen, ValueType value) { 171 | assert(_initialized == true); 172 | size_t hindex = hashIndex(key, keylen); 173 | struct HashEntry* first = getHashEntry(hindex); 174 | struct Entry* entry; 175 | bool isFound = true; 176 | 177 | // Check all _entries with the same hindex. 178 | entry = getEntry(first, key, keylen); 179 | if(!entry) { 180 | isFound = false; 181 | insertEntry(first, key, keylen, value); 182 | } 183 | 184 | return isFound; 185 | } 186 | 187 | // Free an entry with specified 188 | bool erase(const KeyType& key, size_t keylen) { 189 | assert(_initialized == true); 190 | size_t hindex = hashIndex(key, keylen); 191 | struct HashEntry* first = getHashEntry(hindex); 192 | struct Entry* entry; 193 | bool isFound = false; 194 | 195 | entry = getEntry(first, key, keylen); 196 | 197 | // PRINF("Erapse the entry key %p entry %p\n", key, entry); 198 | if(entry) { 199 | isFound = true; 200 | 201 | // Check whether this entry is the first entry. 202 | // Remove this entry if existing. 203 | entry->erase(); 204 | 205 | SourceHeap::deallocate(entry); 206 | } 207 | 208 | first->count--; 209 | 210 | return isFound; 211 | } 212 | 213 | // Clear all _entries 214 | void clear() {} 215 | 216 | private: 217 | // Create a new Entry with specified key and value. 218 | struct Entry* createNewEntry(const KeyType& key, size_t keylen, ValueType value) { 219 | struct Entry* entry = (struct Entry*)SourceHeap::allocate(sizeof(struct Entry)); 220 | 221 | // Initialize this new entry. 222 | entry->initialize(key, keylen, value); 223 | return entry; 224 | } 225 | 226 | void insertEntry(struct HashEntry* head, const KeyType& key, size_t keylen, ValueType value) { 227 | // Check whether the first entry is empty or not. 228 | // Create an entry 229 | struct Entry* entry = createNewEntry(key, keylen, value); 230 | listInsertTail(&entry->list, &head->list); 231 | head->count++; 232 | /* 233 | PRINF("insertEntry entry %p at head %p, headcount %ld\n", entry, head, head->count); 234 | PRINF("insertEntry entry %p, entrynext %p, at head %p hear->list %p headlist->next %p\n", entry, 235 | entry->list.next, head, &head->list, head->list.next); 236 | */ 237 | } 238 | 239 | // Search the entry in the corresponding list. 240 | struct Entry* getEntry(struct HashEntry* first, const KeyType& key, size_t keylen) { 241 | struct Entry* entry = (struct Entry*)first->getFirstEntry(); 242 | struct Entry* result = NULL; 243 | 244 | // Check all _entries with the same hindex. 245 | int count = first->count; 246 | // PRINF("getEntry count is %d\n", count); 247 | while(count > 0) { 248 | if(entry->keylen == keylen && _keycmp(entry->key, key, keylen)) { 249 | result = entry; 250 | break; 251 | } 252 | 253 | entry = entry->nextEntry(); 254 | count--; 255 | } 256 | 257 | return result; 258 | } 259 | 260 | public: 261 | class iterator { 262 | friend class HashMap; 263 | struct Entry* _entry; // Which entry in the current hash entry? 264 | size_t _pos; // which bucket at the moment? [0, nbucket-1] 265 | HashMap* _hashmap; 266 | 267 | public: 268 | iterator(struct Entry* ientry = NULL, int ipos = 0, HashMap* imap = NULL) { 269 | // cout << "In default constructor of iterator\n"; 270 | _pos = ipos; 271 | _entry = ientry; 272 | _hashmap = imap; 273 | } 274 | 275 | ~iterator() {} 276 | 277 | iterator& operator++(int) // in postfix ++ /* parameter? */ 278 | { 279 | struct HashEntry* hashentry = _hashmap->getHashEntry(_pos); 280 | 281 | // Check whether this entry is the last entry in current hash entry. 282 | if(!isListTail(&_entry->list, &hashentry->list)) { 283 | // If not, then we simply get next entry. No need to change pos. 284 | _entry = _entry->nextEntry(); 285 | } else { 286 | // Since current list is empty, we must search next hash entry. 287 | _pos++; 288 | while((hashentry = _hashmap->getHashEntry(_pos)) != NULL) { 289 | if(hashentry->count != 0) { 290 | // Now we can return it. 291 | _entry = (struct Entry*)hashentry->getFirstEntry(); 292 | return *this; 293 | } 294 | _pos++; 295 | } 296 | 297 | _entry = NULL; 298 | } 299 | 300 | return *this; 301 | } 302 | 303 | // iterator& operator -- (); 304 | // Iterpreted as a = b is treated as a.operator=(b) 305 | iterator& operator=(const iterator& that) { 306 | _entry = that._entry; 307 | _pos = that._pos; 308 | _hashmap = that._hashmap; 309 | return *this; 310 | } 311 | 312 | bool operator==(const iterator& that) const { return _entry == that._entry; } 313 | 314 | bool operator!=(const iterator& that) const { return _entry != that._entry; } 315 | 316 | ValueType getData() { return _entry->getValue(); } 317 | 318 | KeyType getkey() { return _entry->getKey(); } 319 | }; 320 | 321 | // Acquire the first entry of the hash table 322 | iterator begin() { 323 | size_t pos = 0; 324 | struct HashEntry* head = NULL; 325 | struct Entry* entry; 326 | 327 | // PRINF("in the beginiing of begin\n"); 328 | // Get the first non-null entry 329 | while(pos < _buckets) { 330 | head = getHashEntry(pos); 331 | // PRINF("begin, head %p pos %ld head->count %ld\n", head, pos, head->count); 332 | if(head->count != 0) { 333 | // Now we can return it. 334 | entry = (struct Entry*)head->getFirstEntry(); 335 | // PRINF("In begin() function, head %p, firstentry %p, firstentry next %p\n", head, entry, 336 | //entry->list.next); 337 | return iterator(entry, pos, this); 338 | } 339 | pos++; 340 | } 341 | 342 | return end(); 343 | } 344 | 345 | iterator end() { return iterator(NULL, 0, this); } 346 | }; 347 | 348 | #endif //__FCHASHMAP_H__ 349 | -------------------------------------------------------------------------------- /libguarder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file libfreeguard.cpp: main file, includes memory interception functions. 21 | * @author Tongping Liu 22 | * @author Sam Silvestro 23 | */ 24 | #include 25 | #include 26 | #include "real.hh" 27 | #include "xthread.hh" 28 | #include "bibopheap.hh" 29 | #include "mm.hh" 30 | #include "bigheap.hh" 31 | #ifdef SSE2RNG 32 | #include "sse2rng.h" 33 | #endif 34 | 35 | void heapinitialize(); 36 | __attribute__((constructor)) void initializer() { 37 | heapinitialize(); 38 | } 39 | 40 | #ifdef CUSTOMIZED_STACK 41 | intptr_t globalStackAddr; 42 | 43 | typedef int (*main_fn_t)(int, char**, char**); 44 | 45 | extern "C" int __libc_start_main(main_fn_t, int, char**, void (*)(), void (*)(), void (*)(), void*) __attribute__((weak, alias("freeguard_libc_start_main"))); 46 | 47 | extern "C" int freeguard_libc_start_main(main_fn_t main_fn, int argc, char** argv, void (*init)(), void (*fini)(), void (*rtld_fini)(), void* stack_end) { 48 | // allocate stack area 49 | size_t stackSize = (size_t)STACK_SIZE * MAX_THREADS; 50 | if((globalStackAddr = (intptr_t)MM::mmapAllocatePrivate(stackSize)) == 0) { 51 | FATAL("Failed to initialize stack area\n"); 52 | } 53 | madvise((void *)globalStackAddr, stackSize, MADV_NOHUGEPAGE); 54 | 55 | // set guard pages in cusotmized stack area. Set in both the beginnning and end. 56 | // better way is to set this when we use a new thread index, which may require changing the bool flag in thread_t to a int. 57 | for(int i = 1; i < MAX_THREADS; i++) { // ingore the first thread 58 | intptr_t stackStart = globalStackAddr + i * STACK_SIZE; 59 | if((mprotect((void*)(stackStart + STACK_SIZE - GUARD_PAGE_SIZE), GUARD_PAGE_SIZE, PROT_NONE) == -1) 60 | || (mprotect((void*)stackStart, GUARD_PAGE_SIZE, PROT_NONE) == -1)) { 61 | perror("Failed to set guard pages"); 62 | abort(); 63 | } 64 | } 65 | #ifdef CUSTOMIZED_MAIN_STACK 66 | intptr_t ebp, esp, customizedEbp, customizedEsp, ebpOffset, espOffset; 67 | intptr_t stackTop = (((intptr_t)&main_fn + PageSize) & ~(PageSize - 1)) + PageSize; // page align 68 | intptr_t newStackTop = globalStackAddr + STACK_SIZE - GUARD_PAGE_SIZE; 69 | // get current stack 70 | #if defined(X86_32BIT) 71 | asm volatile("movl %%ebp,%0\n" 72 | "movl %%esp,%1\n" 73 | : "=r"(ebp), "=r"(esp)::"memory"); 74 | #else 75 | asm volatile("movq %%rbp,%0\n" 76 | "movq %%rsp, %1\n" 77 | : "=r"(ebp), "=r"(esp)::"memory"); 78 | #endif 79 | // copy stack data 80 | ebpOffset = stackTop - ebp; 81 | espOffset = stackTop - esp; 82 | customizedEbp = newStackTop - ebpOffset; 83 | customizedEsp = newStackTop - espOffset; 84 | memcpy((void*)customizedEsp, (void*)esp, espOffset); 85 | #if defined(X86_32BIT) 86 | asm volatile("movl %0, %%ebp\n" 87 | "movl %1, %%esp\n" 88 | :: "r"(customizedEbp), "r"(customizedEsp):"memory"); 89 | #else 90 | asm volatile("movq %0,%%rbp\n" 91 | "movq %1,%%rsp\n" 92 | :: "r"(customizedEbp), "r"(customizedEsp):"memory"); 93 | #endif 94 | // re-direct arguments 95 | argv = (char**)(newStackTop - (stackTop - (intptr_t)argv)); 96 | 97 | for(int i = 0; i < argc; i++) { 98 | argv[i] = (char*)(newStackTop - (stackTop - (intptr_t)argv[i])); 99 | } 100 | 101 | stack_end = (void*)(newStackTop - (stackTop - (intptr_t)stack_end)); 102 | // re-direct arguments 103 | // reset original stack 104 | 105 | memset((void*)esp, 0, espOffset); 106 | #if 0 107 | unsigned long orig = ((unsigned long)esp) & ~(PageSize - 1); 108 | fprintf(stderr, "unmap orig stack %p size %lx\n", orig, stackTop - orig); 109 | if(munmap((void*)orig, stackTop - orig) != 0) { 110 | //fprintf(stderr, "unmap orig stack %p size %lx failed, memeset instead %p\n", orig, stackTop - orig, stack_end); 111 | memset((void*)esp, 0, espOffset); 112 | } 113 | #endif 114 | #endif 115 | 116 | // real run 117 | auto real_libc_start_main = (decltype(__libc_start_main)*)dlsym(RTLD_NEXT, "__libc_start_main"); 118 | return real_libc_start_main(main_fn, argc, argv, init, fini, rtld_fini, stack_end); 119 | } 120 | #else 121 | __thread int _threadIndex; 122 | #endif 123 | 124 | // Variables used by our pre-init private allocator 125 | typedef enum { 126 | E_HEAP_INIT_NOT = 0, 127 | E_HEAP_INIT_WORKING, 128 | E_HEAP_INIT_DONE, 129 | } eHeapInitStatus; 130 | 131 | eHeapInitStatus heapInitStatus = E_HEAP_INIT_NOT; 132 | unsigned long numLargeObjects = 0; 133 | 134 | extern "C" { 135 | void xxfree(void *); 136 | void * xxmalloc(size_t); 137 | void * xxcalloc(size_t, size_t); 138 | void * xxrealloc(void *, size_t); 139 | 140 | void * xxvalloc(size_t); 141 | void * xxaligned_alloc(size_t, size_t); 142 | void * xxmemalign(size_t, size_t); 143 | void * xxpvalloc(size_t); 144 | void * xxalloca(size_t); 145 | int xxposix_memalign(void **, size_t, size_t); 146 | 147 | // Function aliases 148 | void free(void *) __attribute__ ((weak, alias("xxfree"))); 149 | void * malloc(size_t) __attribute__ ((weak, alias("xxmalloc"))); 150 | void * calloc(size_t, size_t) __attribute__ ((weak, alias("xxcalloc"))); 151 | void * realloc(void *, size_t) __attribute__ ((weak, alias("xxrealloc"))); 152 | 153 | void * valloc(size_t) __attribute__ ((weak, alias("xxvalloc"))); 154 | void * aligned_alloc(size_t, size_t) __attribute__ ((weak, 155 | alias("xxaligned_alloc"))); 156 | void * memalign(size_t, size_t) __attribute__ ((weak, alias("xxmemalign"))); 157 | void * pvalloc(size_t) __attribute__ ((weak, alias("xxpvalloc"))); 158 | void * alloca(size_t) __attribute__ ((weak, alias("xxalloca"))); 159 | int posix_memalign(void **, size_t, size_t) __attribute__ ((weak, 160 | alias("xxposix_memalign"))); 161 | } 162 | 163 | __attribute__((destructor)) void finalizer() { 164 | PRDBG("%lu large objects (>%d) were allocated", numLargeObjects, LARGE_OBJECT_THRESHOLD); 165 | } 166 | 167 | void parseEnvOpts() { 168 | char * value; 169 | 170 | // opts is a global struct located in bibopheap.hh 171 | if((value = getenv("GUARDER_NUMERATOR"))) { 172 | opts.over_prov_numerator = atoi(value); 173 | } 174 | if((value = getenv("GUARDER_DENOMINATOR"))) { 175 | opts.over_prov_denominator = atoi(value); 176 | } 177 | // Over provisioning ratio must be greater than or equal to 1 178 | if((opts.over_prov_denominator <= 0) || 179 | (opts.over_prov_numerator < opts.over_prov_denominator)) { 180 | PRERR("over provisioning ratio invalid; setting to 1/1"); 181 | opts.over_prov_numerator = 1; 182 | opts.over_prov_denominator = 1; 183 | } 184 | 185 | if((value = getenv("GUARDER_ENTROPY_BITS"))) { 186 | opts.bibop_entropy_bits = atoi(value); 187 | } 188 | // Entropy bits must be a positive integer 189 | if(opts.bibop_entropy_bits <= 0) { 190 | PRERR("invalid bibop entropy bits; setting to default value (%u)", 191 | DEFAULT_BIBOP_ENTROPY_BITS); 192 | opts.bibop_entropy_bits = DEFAULT_BIBOP_ENTROPY_BITS; 193 | } 194 | 195 | opts.bibop_cache_size = (1U << (opts.bibop_entropy_bits + 1)); 196 | 197 | /* 198 | if((value = getenv("GUARDER_CACHE_DIVISOR"))) { 199 | opts.bibop_cache_allowance_divisor = atoi(value); 200 | } 201 | // Cache allowance divisor must be a positive integer >= 2 202 | if(opts.bibop_cache_allowance_divisor < 2) { 203 | PRERR("invalid bibop cache allowance divisor; " 204 | "setting to default value (%u)", DEFAULT_BIBOP_CACHE_ALLOWANCE_DIVISOR); 205 | opts.bibop_cache_allowance_divisor = DEFAULT_BIBOP_CACHE_ALLOWANCE_DIVISOR; 206 | } 207 | */ 208 | 209 | if((value = getenv("GUARDER_RAND_GUARD_PROP"))) { 210 | opts.random_guard_prop = atof(value); 211 | } 212 | // Random guard proportion must be a fraction between [0, 1) 213 | if((opts.random_guard_prop < 0.0f) || (opts.random_guard_prop >= 1.0f)) { 214 | PRERR("invalid random guard proportion; " 215 | "setting to default value (%4.2f)", DEFAULT_RAND_GUARD_PROP); 216 | opts.random_guard_prop = DEFAULT_RAND_GUARD_PROP; 217 | } 218 | } 219 | 220 | void debugPrintOptions() { 221 | PRINT("DEBUG OUTPUT:"); 222 | PRINT("entropy bits = %d", BIBOP_ENTROPY_BITS); 223 | PRINT("cache size = %d", BIBOP_CACHE_SIZE); 224 | PRINT("half cache size = %d", BIBOP_HALF_CACHE_SIZE); 225 | PRINT("over prov buffer size = %d", OVER_PROV_OBJ_BUF_SZ); 226 | PRINT("over prov num dead objects = %d", NUM_DEAD_OBJS); 227 | PRINT("over prov numerator = %d", opts.over_prov_numerator); 228 | PRINT("over prov denominator = %d", opts.over_prov_denominator); 229 | PRINT("rand guard page proportion = %0.2f", opts.random_guard_prop); 230 | } 231 | 232 | void heapinitialize() { 233 | if(heapInitStatus == E_HEAP_INIT_NOT) { 234 | heapInitStatus = E_HEAP_INIT_WORKING; 235 | parseEnvOpts(); 236 | #ifndef NDEBUG 237 | debugPrintOptions(); 238 | #endif 239 | SRAND(time(NULL)); 240 | BibopHeap::getInstance().initialize(); 241 | heapInitStatus = E_HEAP_INIT_DONE; 242 | // The following function will invoke dlopen and will call malloc in the end. 243 | // Thus, it is putted in the end so that it won't fail 244 | Real::initializer(); 245 | xthread::getInstance().initialize(); 246 | BigHeap::getInstance().initBigHeap(); 247 | } else { 248 | while(heapInitStatus != E_HEAP_INIT_DONE); 249 | } 250 | } 251 | 252 | void * xxmalloc(size_t size) { 253 | if(heapInitStatus != E_HEAP_INIT_DONE) { 254 | heapinitialize(); 255 | } 256 | 257 | // Calculate the proper bag size needed to fulfill this request 258 | if(IF_CANARY_CONDITION) { 259 | numLargeObjects++; 260 | return BigHeap::getInstance().allocateAtBigHeap(size); 261 | } else { 262 | return BibopHeap::getInstance().allocateSmallObject(size); 263 | } 264 | 265 | return NULL; 266 | } 267 | 268 | void xxfree(void * ptr) { 269 | if(ptr == NULL || heapInitStatus != E_HEAP_INIT_DONE) { 270 | return; 271 | } 272 | 273 | if(BibopHeap::getInstance().isSmallObject(ptr)) { 274 | BibopHeap::getInstance().freeSmallObject(ptr); 275 | } else if(BigHeap::getInstance().isLargeObject(ptr)) { 276 | BigHeap::getInstance().deallocateToBigHeap(ptr); 277 | } else { 278 | PRERR("invalid free on address %p", ptr); 279 | } 280 | } 281 | 282 | void * xxcalloc(size_t nelem, size_t elsize) { 283 | void * ptr = NULL; 284 | ptr = malloc(nelem * elsize); 285 | if(ptr != NULL) { 286 | memset(ptr, 0, nelem * elsize); 287 | } 288 | return ptr; 289 | } 290 | 291 | void * xxrealloc(void * ptr, size_t sz) { 292 | // We can't really support this library call when the allocator 293 | // is uninitialized; this is because there is no way for us to 294 | // determine the actual size of an object given only its 295 | // starting address using the temporary allocator. 296 | if(heapInitStatus != E_HEAP_INIT_DONE) { 297 | heapinitialize(); 298 | } 299 | 300 | // If the pointer is null, call is equivalent to malloc(sz). 301 | if(ptr == NULL) { 302 | return xxmalloc(sz); 303 | } 304 | 305 | // If the pointer is non-null and size is zero, call is equivalent 306 | // to free(ptr). 307 | if(sz == 0) { 308 | xxfree(ptr); 309 | return NULL; 310 | } 311 | 312 | // If the object is unknown to us, return NULL to indicate error. 313 | size_t oldSize = -1; 314 | if(BibopHeap::getInstance().isSmallObject(ptr)) { 315 | oldSize = BibopHeap::getInstance().getObjectSize(ptr); 316 | } else if(BigHeap::getInstance().isLargeObject(ptr)) { 317 | oldSize = BigHeap::getInstance().getObjectSize(ptr); 318 | } 319 | 320 | if(oldSize == -1) { 321 | PRERR("realloc called with unknown object"); 322 | return NULL; 323 | } 324 | 325 | // If the requested new size is less than 326 | // or equal to the old size, simply return the object as-is. 327 | if(oldSize >= sz) { 328 | return ptr; 329 | } 330 | 331 | void * newObject = xxmalloc(sz); 332 | memcpy(newObject, ptr, oldSize); 333 | xxfree(ptr); 334 | return newObject; 335 | } 336 | 337 | 338 | void * xxalloca(size_t size) { 339 | PRERR("%s CALLED", __FUNCTION__); 340 | return NULL; 341 | } 342 | 343 | void * xxvalloc(size_t size) { 344 | PRERR("%s CALLED", __FUNCTION__); 345 | return NULL; 346 | } 347 | 348 | int xxposix_memalign(void **memptr, size_t alignment, size_t size) { 349 | void * alignedObject = xxmemalign(alignment, size); 350 | *memptr = alignedObject; 351 | return 0; 352 | } 353 | 354 | void * xxaligned_alloc(size_t alignment, size_t size) { 355 | PRERR("%s CALLED", __FUNCTION__); 356 | return NULL; 357 | } 358 | 359 | void * xxmemalign(size_t alignment, size_t size) { 360 | if(size == 0) { 361 | return NULL; 362 | } 363 | 364 | // Calculate the proper bag size needed to fulfill this request 365 | if(size > LARGE_OBJECT_THRESHOLD) { 366 | numLargeObjects++; 367 | return BigHeap::getInstance().allocateAlignedAtBigHeap(alignment, size); 368 | } else { 369 | size_t allocObjectSize = alignment + size; 370 | uintptr_t object = (uintptr_t)BibopHeap::getInstance().allocateSmallObject(allocObjectSize); 371 | unsigned long residualBytes = alignment - (object % alignment); 372 | void * alignedObject = (void *)(object + residualBytes); 373 | PRDBG("memalign: original object @ 0x%lx, residual bytes=%lu, aligned object @ %p", 374 | object, residualBytes, alignedObject); 375 | return alignedObject; 376 | } 377 | 378 | return NULL; 379 | } 380 | 381 | void * xxpvalloc(size_t size) { 382 | PRERR("%s CALLED", __FUNCTION__); 383 | return NULL; 384 | } 385 | 386 | // Intercept thread creation 387 | int pthread_create(pthread_t * tid, const pthread_attr_t * attr, 388 | void *(*start_routine)(void *), void * arg) { 389 | if(heapInitStatus != E_HEAP_INIT_DONE) { 390 | heapinitialize(); 391 | } 392 | return xthread::getInstance().thread_create(tid, attr, start_routine, arg); 393 | } 394 | int pthread_join(pthread_t tid, void** retval) { 395 | return xthread::getInstance().thread_join(tid, retval); 396 | } 397 | -------------------------------------------------------------------------------- /bibopheap.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeGuard: A Faster Secure Heap Allocator 3 | * Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser, 4 | * Zhiqiang Lin, and Tongping Liu 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * @file bibopheap.hh: main BIBOP heap implementation. 21 | * @author Tongping Liu 22 | * @author Sam Silvestro 23 | */ 24 | #ifndef __BIBOPHEAP_H__ 25 | #define __BIBOPHEAP_H__ 26 | 27 | #include 28 | #include 29 | #include 30 | #include "xdefines.hh" 31 | #include "mm.hh" 32 | #include "log.hh" 33 | #include "errmsg.hh" 34 | 35 | #ifdef SSE2RNG 36 | #include "sse2rng.h" 37 | #elif ARC4RNG 38 | extern "C" uint32_t arc4random_uniform(uint32_t upper_bound); 39 | #endif 40 | 41 | struct guarder_opts opts; 42 | 43 | class BibopHeap { 44 | private: 45 | static unsigned _cacheSize; 46 | static unsigned _overProvObjBufSize; 47 | 48 | // Boundaries of the heap area 49 | char * _heapBegin; 50 | char * _heapEnd; 51 | 52 | // Boundaries of the shadow memory region 53 | char * _shadowMemBegin; 54 | char * _shadowMemEnd; 55 | 56 | // Boundaries of the free object cache region 57 | char * _freeAreaBegin; 58 | char * _freeAreaEnd; 59 | unsigned _numUsableBags; 60 | unsigned _lastUsableBag; 61 | 62 | static size_t _bibopBagSize; 63 | unsigned _threadShiftBits; 64 | 65 | static unsigned long _bagShiftBits; 66 | static unsigned long _bagMask; 67 | unsigned long _numBagsPerSubHeapMask; 68 | unsigned _shadowObjectInfoSizeShiftBits; 69 | 70 | 71 | class PerThreadMap { 72 | private: 73 | unsigned char classSizeToBag[LOG2(MAX_RANDOM_BAG_SIZE) + 1]; // "+1" to create 74 | // indices of 75 | // [0, max-power] 76 | unsigned char bagToClassSize[BIBOP_NUM_BAGS]; 77 | 78 | public: 79 | 80 | void initialize(unsigned classSizePowerMax) { 81 | int i; 82 | 83 | // Initialize the classSize-to-bag mapping with sorted powers-of-two 84 | unsigned minClassSizePower = LOG2(BIBOP_MIN_BLOCK_SIZE); 85 | unsigned numClassSizePowers = BIBOP_NUM_BAGS + minClassSizePower - 1; 86 | classSizeToBag[minClassSizePower] = 0; 87 | for(i = minClassSizePower + 1; i <= numClassSizePowers; i++) { 88 | classSizeToBag[i] = classSizeToBag[i - 1] + 1; 89 | } 90 | 91 | // Shuffle the contents of the classSize-to-bag mapping, 92 | // which will randomize the bag ordering for the subheap 93 | for(i = numClassSizePowers; i >= minClassSizePower; i--) { 94 | unsigned j = getRandomNumber() % ((i - minClassSizePower) + 1); 95 | unsigned temp = classSizeToBag[i]; 96 | classSizeToBag[i] = classSizeToBag[j + minClassSizePower]; 97 | classSizeToBag[j + minClassSizePower] = temp; 98 | } 99 | for(i = 0; i < minClassSizePower; i++) { 100 | classSizeToBag[i] = classSizeToBag[minClassSizePower]; 101 | } 102 | 103 | // Initialize the bag-to-classSize mapping 104 | for(i = minClassSizePower; i <= numClassSizePowers; i++) { 105 | bagToClassSize[classSizeToBag[i]] = i; 106 | } 107 | 108 | static bool isFirstThread = true; 109 | if(isFirstThread) { 110 | // DEBUG OUTPUT 111 | for(i = 0; i <= numClassSizePowers; i++) { 112 | PRDBG("classSizeToBag[%u] = %u", i, classSizeToBag[i]); 113 | } 114 | for(i = 0; i < BIBOP_NUM_BAGS; i++) { 115 | PRDBG("bagToClassSize[%u] = %u", i, bagToClassSize[i]); 116 | } 117 | PRDBG("num bags=%d, num class size powers = %d", BIBOP_NUM_BAGS, numClassSizePowers); 118 | PRDBG("&classSizeToBag = %p, &bagToClassSize = %p", classSizeToBag, bagToClassSize); 119 | isFirstThread = false; 120 | } 121 | } 122 | 123 | unsigned getClassSize(unsigned bagNum) { 124 | return bagToClassSize[bagNum]; 125 | } 126 | 127 | unsigned getBagNum(unsigned classSizePower) { 128 | return classSizeToBag[classSizePower]; 129 | } 130 | }; 131 | 132 | class ObjectSource { 133 | public: 134 | virtual void * getNext() = 0; 135 | }; 136 | 137 | class BibopGlobalFreeCache; 138 | 139 | class alignas(CACHE_LINE_SIZE) BibopFreeCache : public ObjectSource { 140 | private: 141 | uintptr_t _startaddr; 142 | uintptr_t _endaddr; 143 | 144 | // _head is defined as the next usable object; _tail 145 | // is defined as the first unavailable object. 146 | uintptr_t _head, _tail; 147 | unsigned long _capacity; 148 | BibopGlobalFreeCache * _myGlobalFreeCache; 149 | 150 | protected: 151 | unsigned long _numFreeObjects; 152 | 153 | public: 154 | void initialize(uintptr_t startaddr, unsigned long capacity, BibopGlobalFreeCache * globalFreeCache) { 155 | _startaddr = startaddr; 156 | _endaddr = _startaddr + (capacity << PTR_SIZE_SHIFT_BITS); 157 | _head = _startaddr; 158 | _tail = _head; 159 | _capacity = capacity; 160 | _numFreeObjects = 0; 161 | _myGlobalFreeCache = globalFreeCache; 162 | } 163 | 164 | unsigned long getNumObjects() { 165 | #ifdef USE_GLOBAL_FREE_CACHE 166 | if(_myGlobalFreeCache) { 167 | return _numFreeObjects + _myGlobalFreeCache->getNumObjects(); 168 | } else { 169 | return _numFreeObjects; 170 | } 171 | #else 172 | return _numFreeObjects; 173 | #endif 174 | } 175 | 176 | // Attempts to refill up to half the local buffer with global objects 177 | int repopulate() { 178 | unsigned long halfCapacity = _capacity >> 1; 179 | _myGlobalFreeCache->acquireLock(); 180 | unsigned numGlobalFreeObjects = _myGlobalFreeCache->getNumObjects(); 181 | unsigned numObjectsToTransfer = (numGlobalFreeObjects <= halfCapacity) ? numGlobalFreeObjects : halfCapacity; 182 | int i; 183 | 184 | for(i = 0; i < numObjectsToTransfer; i++) { 185 | add(_myGlobalFreeCache->getNext()); 186 | } 187 | _myGlobalFreeCache->releaseLock(); 188 | if(i > 0) { 189 | PRDBG("received %d objects from global cache (numObjectsToTransfer=%u, " 190 | "numGlobalFreeObjects=%u)", i, numObjectsToTransfer, numGlobalFreeObjects); 191 | } 192 | 193 | return i; 194 | } 195 | 196 | inline void * getNext() { 197 | if(_numFreeObjects == 0) { 198 | #ifdef USE_GLOBAL_FREE_CACHE 199 | // Repopulate from the global free cache, if possible 200 | if(_myGlobalFreeCache) { 201 | if(repopulate() == 0) { 202 | return NULL; 203 | } 204 | } else { 205 | return NULL; 206 | } 207 | #else 208 | return NULL; 209 | #endif 210 | } 211 | 212 | void ** oldTail = (void **)_tail; 213 | 214 | _tail += POINTER_SIZE; 215 | if(_tail == _endaddr) { 216 | // do wrap-around on _tail 217 | _tail = _startaddr; 218 | } 219 | 220 | _numFreeObjects--; 221 | if(_head == _tail) { 222 | PRDBG("free cache is now empty"); 223 | } 224 | 225 | PRDBG("freeCache->getNext(): retval=%p, this=%p, _numFreeObjects=%lu, _capacity=%lu, _start=0x%lx, _end=0x%lx", 226 | *oldTail, this, _numFreeObjects, _capacity, _startaddr, _endaddr); 227 | return *oldTail; 228 | } 229 | 230 | inline bool add(void * addr) { 231 | // Check if this buffer has reached full capacity... 232 | if(_numFreeObjects == _capacity) { 233 | #ifdef USE_GLOBAL_FREE_CACHE 234 | // Attempt to donate up to half of the 235 | // local buffer's items to the global buffer 236 | if(_myGlobalFreeCache) { 237 | int i; 238 | 239 | _myGlobalFreeCache->acquireLock(); 240 | for(i = 0; i < (_capacity >> 1); i++) { 241 | if(!_myGlobalFreeCache->add(getNext())) { 242 | break; 243 | } 244 | } 245 | _myGlobalFreeCache->releaseLock(); 246 | PRDBG("donated %d objects to global cache", i); 247 | // If i==0, the global free cache is also at full capacity 248 | if(i == 0) { 249 | FATAL("global and local free cache out of capacity"); 250 | } 251 | } else { 252 | // If we are a global buffer and we're full, 253 | // simply return false back to the caller 254 | return false; 255 | } 256 | #else 257 | // If the global free cache is not in use and the local 258 | // buffer is full, print an error and return false 259 | PRERR("local free cache out of capacity: dropping object %p", addr); 260 | return false; 261 | #endif 262 | } 263 | 264 | *(void **)_head = addr; 265 | _head += POINTER_SIZE; 266 | if(_head == _endaddr) { 267 | // do wrap-around on _head 268 | _head = _startaddr; 269 | } 270 | 271 | _numFreeObjects++; 272 | 273 | /* 274 | // DEBUG: internal consistency check 275 | long count = (_endaddr - _startaddr) / sizeof(void *); 276 | if(_head > _tail) { 277 | count = (_head - _tail) / sizeof(void *); 278 | } else if(_head < _tail) { 279 | count = ((_endaddr - _tail) + (_head - _startaddr)) / sizeof(void *); 280 | } 281 | PRDBG("freeCache->add(%p): this=%p, _numFreeObjects=%lu, count=%ld, _capacity=%lu, _start=0x%lx, _end=0x%lx", 282 | addr, this, _numFreeObjects, count, _capacity, _startaddr, _endaddr); 283 | if(_numFreeObjects != count) { 284 | FATAL("freeCache->add(%p): this=%p, _numFreeObjects=%lu, count=%ld, _capacity=%lu, _start=0x%lx, _end=0x%lx", 285 | addr, this, _numFreeObjects, count, _capacity, _startaddr, _endaddr); 286 | } 287 | */ 288 | 289 | if(_head == _tail) { 290 | PRDBG("free cache is now full"); 291 | if(_numFreeObjects != _capacity) { 292 | PRERR("_numFreeObjects = %lu, _capacity = %lu", _numFreeObjects, _capacity); 293 | } 294 | assert(_numFreeObjects == _capacity); 295 | } 296 | 297 | return true; 298 | } 299 | }; 300 | 301 | 302 | class alignas(CACHE_LINE_SIZE) BibopGlobalFreeCache : public BibopFreeCache { 303 | private: 304 | pthread_spinlock_t _spin_lock; 305 | 306 | inline void spin_lock() { 307 | pthread_spin_lock(&_spin_lock); 308 | } 309 | 310 | inline void spin_unlock() { 311 | pthread_spin_unlock(&_spin_lock); 312 | } 313 | 314 | 315 | public: 316 | void initialize(uintptr_t startaddr, unsigned long capacity) { 317 | pthread_spin_init(&_spin_lock, PTHREAD_PROCESS_PRIVATE); 318 | BibopFreeCache::initialize(startaddr, capacity, NULL); 319 | } 320 | 321 | void acquireLock() { 322 | spin_lock(); 323 | } 324 | 325 | void releaseLock() { 326 | spin_unlock(); 327 | } 328 | 329 | unsigned long getNumObjects() { 330 | return _numFreeObjects; 331 | } 332 | }; 333 | 334 | 335 | class alignas(CACHE_LINE_SIZE) BibopObjCache : private ObjectSource { 336 | private: 337 | BibopFreeCache * _freeCache; 338 | size_t _classSize; 339 | uintptr_t _bagEnd; 340 | uintptr_t _heapTop; 341 | unsigned _nextUp; 342 | unsigned _numUsedObjects; 343 | unsigned _shiftBits; 344 | unsigned _regionCounters[NUM_CACHE_REGIONS]; 345 | void ** _objects; 346 | uintptr_t * _nextObjs; 347 | 348 | 349 | public: 350 | void initialize(uintptr_t ustartaddr, uintptr_t uendaddr, uintptr_t * objectCache, 351 | BibopFreeCache * freeCache, unsigned shiftBits) { 352 | unsigned i; 353 | 354 | // Initialize each of the cache region object 355 | // counters to indicate an uninitialized object cache 356 | for(i = 0; i < NUM_CACHE_REGIONS; i++) { 357 | _regionCounters[i] = UNINITIALIZED_CACHE_REGION; 358 | } 359 | 360 | // Force the over-provisioning to choose a fresh set of objects 361 | _nextUp = BibopHeap::_overProvObjBufSize; 362 | 363 | _shiftBits = shiftBits; 364 | _classSize = (size_t)(1U << _shiftBits); 365 | 366 | // Check whether the current bag size can support the current 367 | // entropy setting (e.g., if any bag has fewer objects than 368 | // needed to fill its object cache or over-provisioning buffer, 369 | // then we cannot support the current entropy setting). 370 | unsigned numObjectsInBag = _bibopBagSize / _classSize; 371 | bool overProvFail = (numObjectsInBag < BibopHeap::_overProvObjBufSize); 372 | bool entropyFail = (numObjectsInBag < BibopHeap::_cacheSize); 373 | if(overProvFail) { 374 | PRERR("cannot support the given over-provisioning factor:"); 375 | PRERR(" class size = %zu", _classSize); 376 | PRERR(" num objects in bag = %u", numObjectsInBag); 377 | PRERR(" over prov buf size = %u", BibopHeap::_overProvObjBufSize); 378 | } 379 | if(entropyFail) { 380 | PRERR("cannot support the given allocator entropy:"); 381 | PRERR(" class size = %zu", _classSize); 382 | PRERR(" num objects in bag = %u", numObjectsInBag); 383 | PRERR(" obj cache size = %u", BibopHeap::_cacheSize); 384 | } 385 | if(overProvFail || entropyFail) { exit(EXIT_FAILURE); } 386 | 387 | _freeCache = freeCache; 388 | _numUsedObjects = 0; 389 | _heapTop = ustartaddr; // next available object 390 | _bagEnd = uendaddr; // last available object 391 | _objects = (void **)objectCache; 392 | _nextObjs = objectCache + BibopHeap::_cacheSize; 393 | } 394 | 395 | inline unsigned getClassSize() { 396 | return _classSize; 397 | } 398 | 399 | void * malloc() { 400 | // TODO: change how this repopulation threshold is calculated 401 | // Ex: cache size = 256, half cache size = 128, bag size = 32MB (yes, very small); 402 | // only 64 objects exist in each 512KB class; thus, we would never reach the cache 403 | // allowance of used objects until something bad has happened (segfault, doubly- 404 | // allocated objects, etc.) -- SAS 405 | if(_numUsedObjects > BIBOP_HALF_CACHE_SIZE) { 406 | // Pull in free objects from the free cache 407 | //PRDBG("out of objects in the cache; need to repopulate from free cache"); 408 | repopulate(); 409 | } 410 | 411 | //#pragma message "doReplacement turned off" 412 | //bool doReplacement = false; 413 | bool doReplacement = true; 414 | uintptr_t object = getRandomObject(doReplacement); 415 | 416 | #ifdef USE_CANARY 417 | // We must install the canary prior to marking the object as in-use, 418 | // otherwise another thread performing neighbor checking could 419 | // identify the object as in-use, but will raise a false alarm 420 | // due to the missing canary value. 421 | char * canary = (char *)object + _classSize - 1; 422 | *canary = CANARY_SENTINEL; 423 | #endif 424 | 425 | // Mark the object as in-use in the shadow memory 426 | if(!markObjectUsed(object)) { 427 | FATAL("object 0x%lx already set as in-use", object); 428 | } 429 | 430 | PRDBG("...returning object 0x%lx", object); 431 | return (void *)object; 432 | } 433 | 434 | 435 | private: 436 | void initialPopulate() { 437 | unsigned i; 438 | 439 | // Initialize each of the cache region object 440 | // counters to indicate a full buffer 441 | for(i = 0; i < NUM_CACHE_REGIONS; i++) { 442 | _regionCounters[i] = CACHE_REGION_SIZE; 443 | } 444 | 445 | // Initialize the cache with new objects from top of current subheap 446 | for(i = 0; i < BibopHeap::_cacheSize; i++) { 447 | _objects[i] = getNext(); 448 | 449 | assert(_objects[i] != NULL); 450 | } 451 | 452 | // If we decide to place the object cache in mmap'd memory rather than 453 | // global memory we MUST ensure that unused entries are initialized to 454 | // zero 455 | for(i = BibopHeap::_cacheSize; i < BibopHeap::_cacheSize; i++) { 456 | _objects[i] = NULL; 457 | } 458 | } 459 | 460 | void * getNext() { 461 | if(_heapTop >= _bagEnd) { 462 | FATAL("heap out of memory (bag size = %lu)", _bibopBagSize); 463 | } 464 | 465 | uintptr_t foundNextObject = 0; 466 | do { 467 | // Repopulate the over provisioning buffer, if necessary... 468 | if(_nextUp >= BibopHeap::_overProvObjBufSize) { 469 | int i; 470 | for(i = 0; i < BibopHeap::_overProvObjBufSize; i++) { 471 | #ifdef RANDOM_GUARD 472 | if((_heapTop & PageMask) == 0) { 473 | tryRandomGuardPage(&_heapTop); 474 | } 475 | #endif 476 | 477 | // Use the top-of-bag pointer to satisfy this request 478 | _nextObjs[i] = _heapTop; 479 | // Bump the top-of-bag pointer to point to next object 480 | _heapTop += _classSize; 481 | } 482 | // Now kill a portion of these objects in accordance with 483 | // the over-provisioning ratio 484 | for(i = 0; i < NUM_DEAD_OBJS; i++) { 485 | unsigned randIndex = getRandomNumber() % BibopHeap::_overProvObjBufSize; 486 | 487 | // Perform a forward sequential search if the 488 | // object we selected for sacrifice is already dead 489 | while(_nextObjs[randIndex] == 0) { 490 | randIndex = (randIndex + 1) % BibopHeap::_overProvObjBufSize; 491 | } 492 | _nextObjs[randIndex] = 0; // Mark selected index as a dead object 493 | } 494 | _nextUp = 0; 495 | } 496 | 497 | // Try the next object in the over-provisioning buffer... 498 | foundNextObject = _nextObjs[_nextUp++]; 499 | } while(foundNextObject == 0); 500 | //PRDBG("\theap top returning object @ 0x%lx", foundNextObject); 501 | 502 | return (void *)foundNextObject; 503 | } 504 | 505 | // Tries to place a random guard page at the current location pointed 506 | // to by the specified top-of-heap pointer. 507 | bool tryRandomGuardPage(uintptr_t * position) { 508 | void * savedPosition = (void *)*position; 509 | 510 | if(getRandomNumber() < RANDOM_GUARD_RAND_CUTOFF) { 511 | size_t guardSize; 512 | if(_classSize < PageSize) { 513 | guardSize = PageSize; 514 | unsigned numObjectsPerPage = PageSize / _classSize; 515 | // For the purposes of the caller (allocateSmallObject()), we want 516 | // it to assume we are operating on the last object of this page; 517 | // thus, we should increment the bump pointer by the number of 518 | // objects that make up a page, minus one. 519 | *position += numObjectsPerPage * _classSize; 520 | } else { 521 | guardSize = _classSize; 522 | *position += _classSize; 523 | } 524 | mprotect(savedPosition, guardSize, PROT_NONE); 525 | 526 | //uintptr_t endPosition = (uintptr_t)savedPosition + guardSize; 527 | //PRDBG("placing random guard page at %p~0x%lx, size=%zu", savedPosition, endPosition, guardSize); 528 | /* 529 | // This version checks the return value of the mprotect call 530 | if(mprotect(savedPosition, guardSize, PROT_NONE) == -1) { 531 | PRERR("mprotect(%p, %zu, PROT_NONE) failed: %s", savedPosition, guardSize, strerror(errno)); 532 | } 533 | */ 534 | 535 | return true; 536 | } 537 | return false; 538 | } 539 | 540 | void repopulate() { 541 | // Perform an O(n) repopulation of this object cache using 542 | // freed objects located in the freeCache 543 | // If there are not enough objects in freeCache to fully perform 544 | // the repopulation, we should shift to using new objects from the 545 | // top of the heap (pointed to by _heapTop) 546 | 547 | PRDBG("*** beginning repopulation ***"); 548 | 549 | ObjectSource * objSource; 550 | if(_freeCache->getNumObjects() > 0) { 551 | PRDBG("\tusing free cache as object source"); 552 | objSource = _freeCache; 553 | } else { 554 | PRDBG("\tusing heap top as object source"); 555 | objSource = this; 556 | } 557 | 558 | unsigned position = 0; 559 | #pragma message "allocation buffer refill level set to 75%" 560 | // Fills the cache back up to 75% available (25% used) 561 | unsigned refill_level = BIBOP_CACHE_SIZE >> 2; 562 | while(_numUsedObjects > refill_level) { 563 | if(_objects[position] == NULL) { 564 | //if((_objects[position] = objSource->getNext()) == NULL) { 565 | void * popObject = objSource->getNext(); 566 | PRDBG("\t\tfree object %p -> _objects[%d] (cache entry %p, obj src = %p)", 567 | popObject, position, &_objects[position], objSource); 568 | // Write the next object from the free cache into this position. 569 | // If the free cache returned NULL then it is out of objects. 570 | if((_objects[position] = popObject) == NULL) { 571 | PRDBG("\t*** switching back to heap top as object source"); 572 | objSource = this; 573 | // We do not increment position in this case because we want 574 | // the loop to attempt to fill this position again, but using 575 | // the heap as the object source instead of the free cache. 576 | } else { 577 | // Our object source returned a valid object -- decrement the 578 | // number of used objects, and increment the array position 579 | // to proceed with the next item 580 | //unsigned currentRegion = position & NUM_CACHE_REGIONS_MASK; 581 | unsigned currentRegion = position >> CACHE_REGION_SIZE_SHIFT_BITS; 582 | PRDBG("_regionCounters[%d]++ (index = %d)", currentRegion, position); 583 | _regionCounters[currentRegion]++; 584 | _numUsedObjects--; 585 | position++; 586 | } 587 | } else { 588 | // If the object at this position is alive, 589 | // simply move to the next object... 590 | position++; 591 | } 592 | } 593 | } 594 | 595 | uintptr_t getRandomObject(bool doReplacement = false) { 596 | unsigned index; 597 | //unsigned numTries = 1; 598 | void * object; 599 | 600 | // Obtain a random number between [0, opts.bibop_cache_size) 601 | index = getRandomNumber() & BIBOP_CACHE_SIZE_MASK; 602 | object = _objects[index]; 603 | 604 | PRDBG("trying object %p at index %d...", object, index); 605 | // Find the next sequential cache region with objects available for use 606 | if(!object) { 607 | int i; 608 | unsigned cacheRegionNumber = index >> CACHE_REGION_SIZE_SHIFT_BITS; 609 | unsigned tryRegionNumber; 610 | 611 | PRDBG(" ... didn't work, current region = %d, searching regions...", cacheRegionNumber); 612 | for(i = cacheRegionNumber; i < cacheRegionNumber + NUM_CACHE_REGIONS; i++) { 613 | tryRegionNumber = i & NUM_CACHE_REGIONS_MASK; 614 | //numTries++; 615 | if(_regionCounters[tryRegionNumber] == UNINITIALIZED_CACHE_REGION) { 616 | initialPopulate(); 617 | break; 618 | } else if(_regionCounters[tryRegionNumber] > 0) { 619 | PRDBG(" ... using region = %d, has %d objects", tryRegionNumber, _regionCounters[tryRegionNumber]); 620 | break; 621 | } else { 622 | PRDBG(" ... region %d has no objects, moving on...", tryRegionNumber); 623 | } 624 | } 625 | 626 | // Attempt to use a "random" object from this region 627 | // (add +1 to index in order to avoid rehecking the same object if the 628 | // same cache region is chosen by the for-loop above). 629 | index = (tryRegionNumber << CACHE_REGION_SIZE_SHIFT_BITS) + ((index + 1) & CACHE_REGION_SIZE_MASK); 630 | object = _objects[index]; 631 | PRDBG(" ...trying first object (%p) in region %d, has index %d...", object, tryRegionNumber, index); 632 | 633 | // Now walk through the region's objects to find an available one 634 | // (that is, if the first object is unavailable)... 635 | //numTries++; 636 | while(!object) { 637 | PRDBG("cache conflict on index %u (object = %p, num used=%d); trying next item...", 638 | index, object, _numUsedObjects); 639 | 640 | // Try the next adjacent index, wrapping around if necessary... 641 | index++; 642 | if((index & CACHE_REGION_SIZE_MASK) == 0) { 643 | index = tryRegionNumber << CACHE_REGION_SIZE_SHIFT_BITS; 644 | } 645 | 646 | object = _objects[index]; 647 | //numTries++; 648 | } 649 | } 650 | unsigned currentRegion = index >> CACHE_REGION_SIZE_SHIFT_BITS; 651 | //PRINT("numTries %u numAvailObjs %u curRegion %d regionObjects %d", 652 | // numTries, (BibopHeap::_cacheSize - _numUsedObjects), currentRegion, _regionCounters[currentRegion]); 653 | 654 | // If desired, we will replace the randomly selected object with a 655 | // fresh object from the free cache, if one is available to use. 656 | if(doReplacement && (_freeCache->getNumObjects() > 0)) { 657 | PRDBG("freecache has free objects, doing replacement of cache index %u", index); 658 | _objects[index] = _freeCache->getNext(); 659 | } else { 660 | // mark the object as NULL in _objects array to indicate 661 | // it is no longer available 662 | PRDBG("writing NULL to used cache index: cache @ %p, entry @ %p equals %p; index=%u", 663 | _objects, &_objects[index], _objects[index], index); 664 | _objects[index] = NULL; 665 | _numUsedObjects++; 666 | 667 | PRDBG("_regionCounters[%d]-- (index = %d)", currentRegion, index); 668 | _regionCounters[currentRegion]--; 669 | assert(_regionCounters[currentRegion] >= 0); 670 | } 671 | 672 | PRDBG("getRandomObject() returning %p", object); 673 | return (uintptr_t)object; 674 | } 675 | 676 | bool markObjectUsed(uintptr_t object) { 677 | shadowObjectInfo * shadowMemAddr = BibopHeap::getInstance().getShadowObjectInfo((void *)object); 678 | shadowObjectInfo oldSmValue = *shadowMemAddr; 679 | *shadowMemAddr = ALLOC_SENTINEL; 680 | 681 | return (oldSmValue == FREE_SENTINEL); 682 | } 683 | }; 684 | 685 | 686 | class alignas(CACHE_LINE_SIZE) PerThreadBag { 687 | public: 688 | BibopObjCache * cache; 689 | BibopFreeCache * freeCache; 690 | 691 | unsigned lastObjectIndex; // currently populated but never used 692 | unsigned bagNum; 693 | unsigned threadIndex; 694 | size_t classSize; 695 | size_t classMask; 696 | unsigned shiftBits; 697 | 698 | // Starting offset of the current bag in the current heap 699 | size_t startOffset; 700 | uintptr_t startShadowMem; 701 | 702 | #ifdef ENABLE_GUARDPAGE 703 | size_t guardsize; 704 | size_t guardoffset; 705 | #endif 706 | }; 707 | 708 | PerThreadMap _threadMap[MAX_ALIVE_THREADS]; 709 | PerThreadBag _threadBag[MAX_ALIVE_THREADS][BIBOP_NUM_BAGS]; 710 | BibopObjCache _bagCache[MAX_ALIVE_THREADS][BIBOP_NUM_BAGS]; 711 | BibopFreeCache _freeCache[MAX_ALIVE_THREADS][BIBOP_NUM_BAGS]; 712 | BibopGlobalFreeCache _globalFreeCache[BIBOP_NUM_BAGS + LOG2(BIBOP_MIN_BLOCK_SIZE)]; 713 | 714 | public: 715 | static BibopHeap & getInstance() { 716 | static char buf[sizeof(BibopHeap)]; 717 | static BibopHeap* theOneTrueObject = new (buf) BibopHeap(); 718 | return *theOneTrueObject; 719 | } 720 | 721 | void * getHeapBegin() { 722 | return _heapBegin; 723 | } 724 | 725 | void * initialize() { 726 | unsigned threadNum, bagNum; 727 | size_t lastUsableBagSize; 728 | 729 | BibopHeap::_cacheSize = BIBOP_CACHE_SIZE; 730 | BibopHeap::_overProvObjBufSize = OVER_PROV_OBJ_BUF_SZ; 731 | 732 | #ifdef BIBOP_BAG_SIZE 733 | #pragma message "BIBOP_BAG_SIZE in use: overrides randomized bag size" 734 | _bibopBagSize = BIBOP_BAG_SIZE; 735 | #else // randomized bag size 736 | unsigned randPower = getRandomNumber() % (LOG2(MAX_RANDOM_BAG_SIZE / MIN_RANDOM_BAG_SIZE) + 1); 737 | _bibopBagSize = MIN_RANDOM_BAG_SIZE << randPower; 738 | #endif 739 | 740 | if(_bibopBagSize > LARGE_OBJECT_THRESHOLD) { 741 | lastUsableBagSize = LARGE_OBJECT_THRESHOLD; 742 | } else { 743 | lastUsableBagSize = _bibopBagSize; 744 | } 745 | _numUsableBags = LOG2(lastUsableBagSize) - LOG2(BIBOP_MIN_BLOCK_SIZE) + 1; 746 | if(_numUsableBags > BIBOP_NUM_BAGS) { 747 | _numUsableBags = BIBOP_NUM_BAGS; 748 | } 749 | _lastUsableBag = _numUsableBags - 1; 750 | 751 | assert(BIBOP_HEAP_SIZE > 0); 752 | 753 | BibopHeap::_bagShiftBits = LOG2(_bibopBagSize); 754 | _threadShiftBits = LOG2((_bibopBagSize * BIBOP_NUM_BAGS)); 755 | BibopHeap::_bagMask = _bibopBagSize - 1; 756 | 757 | PRINF("_bibopBagSize=0x%lx, _bagShiftBits=%ld, sizeof(PerThreadBag)=%zu", 758 | _bibopBagSize, BibopHeap::_bagShiftBits, sizeof(PerThreadBag)); 759 | PRINF("BIBOP_NUM_BAGS=%u, _numUsableBags=%u", BIBOP_NUM_BAGS, _numUsableBags); 760 | PRINF("sizeof(PerThreadBag)=%zu, sizeof(BibopObjCache)=%zu, sizeof(BibopFreeCache)=%zu", 761 | sizeof(PerThreadBag), sizeof(BibopObjCache), sizeof(BibopFreeCache)); 762 | 763 | // Bag size cannot be smaller than the large object threshold. 764 | assert(_bibopBagSize >= LARGE_OBJECT_THRESHOLD); 765 | 766 | // Allocate the heap all at once. 767 | allocHeap(BIBOP_HEAP_SIZE); 768 | 769 | unsigned long numBagObjects; 770 | unsigned long numCumObjects = 0; 771 | size_t unusableHeapSpace = (BIBOP_NUM_BAGS - _numUsableBags) * _bibopBagSize; 772 | 773 | // Initialize each thread bag's free list, and other information 774 | for(threadNum = 0; threadNum < MAX_ALIVE_THREADS; threadNum++) { 775 | size_t classSize = BIBOP_MIN_BLOCK_SIZE; 776 | 777 | for(bagNum = 0; bagNum < _numUsableBags; bagNum++) { 778 | numBagObjects = _bibopBagSize / classSize; 779 | 780 | #ifdef ENABLE_GUARDPAGE 781 | // We must perform this >1 test or else we will underflow this value 782 | // for bags which have 0 objects in them. Also, the last usable bag 783 | // will only contain a single object, but it will not be reduced to 784 | // make room for a guard page, but rather the next bag (which is 785 | // unusable) will be converted entirely into a guard page. 786 | if(numBagObjects > 1) { 787 | if(classSize < PageSize) { 788 | numBagObjects -= (PageSize / classSize); 789 | } else { 790 | numBagObjects--; 791 | } 792 | } 793 | #endif 794 | 795 | // Update the following values; 796 | numCumObjects += numBagObjects; 797 | classSize <<= 1; 798 | } 799 | } 800 | 801 | _shadowObjectInfoSizeShiftBits = LOG2(sizeof(shadowObjectInfo)); 802 | _numBagsPerSubHeapMask = BIBOP_NUM_BAGS - 1; 803 | size_t numObjectsInHeap = numCumObjects; 804 | 805 | //unsigned freeCacheDivisor = 1; // no reduction to deallocation buffer size 806 | unsigned freeCacheDivisor = 16; 807 | unsigned long numFreeAreaObjects = numObjectsInHeap / freeCacheDivisor; 808 | 809 | allocShadowMem(numObjectsInHeap); 810 | allocFreeArea(numFreeAreaObjects); 811 | allocGlobalFreeCache(numObjectsInHeap); 812 | 813 | // Allocate memory for use by each bag's object cache 814 | size_t objectCacheSize = OVER_PROV_OBJ_BUF_SZ + BIBOP_CACHE_SIZE; 815 | size_t objectCacheAreaSize = sizeof(uintptr_t) * objectCacheSize * BIBOP_NUM_BAGS * MAX_ALIVE_THREADS; 816 | uintptr_t * objectCacheStart = (uintptr_t *)MM::mmapAllocatePrivate(objectCacheAreaSize); 817 | uintptr_t * currentObjectCachePos = objectCacheStart; 818 | 819 | uintptr_t _uHeapStart = (uintptr_t)_heapBegin; 820 | uintptr_t _uShadowMemStart = (uintptr_t)_shadowMemBegin; 821 | uintptr_t _uFreeAreaBegin = (uintptr_t)_freeAreaBegin; 822 | unsigned long offsetShadowMem = 0; 823 | unsigned long offsetFreeArea = 0; 824 | unsigned long offsetBag = 0; 825 | 826 | // Initialize each thread bag's free list, and other information 827 | for(threadNum = 0; threadNum < MAX_ALIVE_THREADS; threadNum++) { 828 | PerThreadMap& curMap = _threadMap[threadNum]; 829 | curMap.initialize(_bagShiftBits); 830 | 831 | for(bagNum = 0; bagNum < _numUsableBags; bagNum++) { 832 | unsigned shiftBits = curMap.getClassSize(bagNum); 833 | size_t classSize = (1U << shiftBits); 834 | if(threadNum == 0) 835 | PRDBG("bag %d classSize = %zu, shiftBits = %u", bagNum, classSize, shiftBits); 836 | PerThreadBag * curBag = &_threadBag[threadNum][bagNum]; 837 | 838 | curBag->cache = &_bagCache[threadNum][bagNum]; 839 | curBag->freeCache = &_freeCache[threadNum][bagNum]; 840 | curBag->classSize = classSize; 841 | curBag->classMask = classSize - 1; 842 | curBag->shiftBits = shiftBits; 843 | curBag->bagNum = bagNum; 844 | curBag->threadIndex = threadNum; 845 | 846 | numBagObjects = _bibopBagSize / classSize; 847 | uintptr_t bagStart = _uHeapStart + offsetBag; 848 | uintptr_t bagEnd = bagStart + _bibopBagSize; 849 | uintptr_t bagShadowMemStart = _uShadowMemStart + offsetShadowMem; 850 | uintptr_t bagFreeAreaStart = _uFreeAreaBegin + offsetFreeArea; 851 | 852 | //PRDBG("thread %d bag %d: heap start @ 0x%lx, shadow mem @ 0x%lx, free cache @ 0x%lx, Cache=%p, FreeCache=%p", 853 | // threadNum, bagNum, bagStart, bagShadowMemStart, bagFreeAreaStart, curBag->cache, curBag->freeCache); 854 | 855 | #ifdef ENABLE_GUARDPAGE 856 | size_t guardsize = classSize > PAGESIZE ? classSize : PAGESIZE; 857 | size_t guardoffset = guardsize; 858 | if(bagNum == _lastUsableBag) { 859 | // If this bag can only fit one object, 860 | // forego the use of a guard object at the end of the bag. 861 | if(_bibopBagSize == lastUsableBagSize) { 862 | guardoffset = 0; 863 | guardsize = 0; 864 | } 865 | // Add to the guard size the amount of unusable space left on the heap. 866 | guardsize += (BIBOP_NUM_BAGS - LOG2(lastUsableBagSize) + LOG2(BIBOP_MIN_BLOCK_SIZE) - 1) * _bibopBagSize; 867 | 868 | //PRDBG("last usable bag: lastUsableBagSize=%zu, _bibopBagSize=%zu, guardsize=%zu, guardoffset=%zu", 869 | // lastUsableBagSize, _bibopBagSize, guardsize, guardoffset); 870 | } 871 | curBag->guardsize = guardsize; 872 | curBag->guardoffset = guardoffset; 873 | #else 874 | size_t guardoffset = 0; 875 | #endif 876 | 877 | #ifdef ENABLE_GUARDPAGE 878 | // We must perform this >1 test or else we will underflow this value 879 | // for bags which have 0 objects in them. Also, the last usable bag 880 | // will only contain a single object, but it will not be reduced to 881 | // make room for a guard page, but rather the next bag (which is 882 | // unusable) will be converted entirely into a guard page. 883 | if(numBagObjects > 1) { 884 | if(classSize < PageSize) { 885 | numBagObjects -= (PageSize / classSize); 886 | } else { 887 | numBagObjects--; 888 | } 889 | } 890 | #endif 891 | 892 | unsigned long bagFreeCacheCapacity = numBagObjects / freeCacheDivisor; 893 | 894 | curBag->startShadowMem = bagShadowMemStart; 895 | curBag->cache->initialize(bagStart, bagEnd, currentObjectCachePos, curBag->freeCache, shiftBits); 896 | // In order to prevent false sharing, do not utilize a global 897 | // free buffer for size classes smaller than the cache line size 898 | if(classSize >= CACHE_LINE_SIZE) { 899 | curBag->freeCache->initialize(bagFreeAreaStart, bagFreeCacheCapacity, NULL); 900 | } else { 901 | curBag->freeCache->initialize(bagFreeAreaStart, bagFreeCacheCapacity, &_globalFreeCache[shiftBits]); 902 | } 903 | 904 | currentObjectCachePos += objectCacheSize; 905 | 906 | curBag->startOffset = offsetBag; 907 | curBag->lastObjectIndex = numBagObjects - 1; 908 | 909 | // Update loop variables 910 | offsetBag += _bibopBagSize; 911 | offsetShadowMem += numBagObjects; 912 | offsetFreeArea += bagFreeCacheCapacity * sizeof(uintptr_t); 913 | } 914 | offsetBag += unusableHeapSpace; 915 | } 916 | 917 | #ifndef NDEBUG 918 | // DEBUG 919 | uintptr_t _uFreeAreaEnd = _uFreeAreaBegin + (numFreeAreaObjects * sizeof(uintptr_t)); 920 | assert((_uFreeAreaBegin + offsetFreeArea) <= _uFreeAreaEnd); 921 | #endif 922 | 923 | _numBagsPerSubHeapMask = BIBOP_NUM_BAGS - 1; 924 | 925 | PRINF("_heapBegin=%p, _heapEnd=%p", _heapBegin, _heapEnd); 926 | PRINF("_shadowMemBegin=%p, _shadowMemEnd=%p, _freeAreaBegin=%p, _freeAreaEnd=%p", 927 | _shadowMemBegin, _shadowMemEnd, _freeAreaBegin, _freeAreaEnd); 928 | 929 | return _heapBegin; 930 | } 931 | 932 | void allocHeap(size_t heapSize) { 933 | _heapBegin = (char *)MM::mmapAllocatePrivate(heapSize); 934 | _heapEnd = _heapBegin + heapSize; 935 | madvise(_heapBegin, heapSize, MADV_NOHUGEPAGE); 936 | } 937 | 938 | void allocShadowMem(size_t numObjectsInHeap) { 939 | // Use one byte for each heap object 940 | size_t totalShadowMemSize = numObjectsInHeap; 941 | _shadowMemBegin = (char *)MM::mmapAllocatePrivate(totalShadowMemSize); 942 | _shadowMemEnd = _shadowMemBegin + totalShadowMemSize; 943 | madvise(_shadowMemBegin, totalShadowMemSize, MADV_NOHUGEPAGE); 944 | } 945 | 946 | void allocFreeArea(size_t numObjectsInHeap) { 947 | // Use eight bytes for each heap object 948 | size_t totalFreeAreaSize = numObjectsInHeap * sizeof(void *); 949 | _freeAreaBegin = (char *)MM::mmapAllocatePrivate(totalFreeAreaSize); 950 | _freeAreaEnd = _freeAreaBegin + totalFreeAreaSize; 951 | madvise(_freeAreaBegin, totalFreeAreaSize, MADV_NOHUGEPAGE); 952 | } 953 | 954 | // Initializes the global free cache area 955 | void allocGlobalFreeCache(unsigned numObjectsInHeap) { 956 | unsigned minClassSizePower = LOG2(BIBOP_MIN_BLOCK_SIZE); 957 | unsigned numClassSizePowers = BIBOP_NUM_BAGS + minClassSizePower - 1; 958 | unsigned long approxNumObjectsInSubHeap = (_bibopBagSize / (BIBOP_MIN_BLOCK_SIZE >> 1)) - 959 | (_bibopBagSize / (1U << numClassSizePowers)); 960 | unsigned shiftBits; 961 | 962 | size_t globalFreeCacheSize = approxNumObjectsInSubHeap * sizeof(uintptr_t); 963 | uintptr_t myFreeCacheStart = (uintptr_t)MM::mmapAllocatePrivate(globalFreeCacheSize); 964 | 965 | unsigned long numObjectsInClass = _bibopBagSize / BIBOP_MIN_BLOCK_SIZE; 966 | for(shiftBits = minClassSizePower; shiftBits <= numClassSizePowers; shiftBits++) { 967 | _globalFreeCache[shiftBits].initialize(myFreeCacheStart, numObjectsInClass); 968 | myFreeCacheStart += (numObjectsInClass * POINTER_SIZE); 969 | numObjectsInClass >>= 1; 970 | } 971 | } 972 | 973 | size_t getObjectSize(void * addr) { 974 | void * objectStartAddr; 975 | PerThreadBag * bag; 976 | (void)getShadowObjectInfo(addr, &bag, &objectStartAddr); 977 | 978 | size_t classSize = bag->classSize; 979 | 980 | if(objectStartAddr != addr) { 981 | ptrdiff_t offset = (uintptr_t)addr - (uintptr_t)objectStartAddr; 982 | classSize -= offset; 983 | } 984 | 985 | #ifdef USE_CANARY 986 | return (classSize - 1); 987 | #else 988 | return classSize; 989 | #endif 990 | } 991 | 992 | // The major routine of allocate a small object 993 | void * allocateSmallObject(size_t sz) { 994 | //PRDBG("allocateSmallObject(%zu)", sz); 995 | 996 | #ifdef CUSTOMIZED_STACK 997 | int threadIndex = getThreadIndex(&sz); 998 | #else 999 | int threadIndex = getThreadIndex(); 1000 | #endif 1001 | 1002 | #ifdef USE_CANARY 1003 | sz++; // make room for the buffer overflow canary 1004 | #endif 1005 | 1006 | unsigned classSizePower; 1007 | if(sz <= BIBOP_MIN_BLOCK_SIZE) { 1008 | classSizePower = LOG2(BIBOP_MIN_BLOCK_SIZE); 1009 | } else { 1010 | classSizePower = N_64BITS - __builtin_clzl(sz - 1); 1011 | } 1012 | 1013 | PerThreadMap& curMap = _threadMap[threadIndex]; 1014 | unsigned bagNum = curMap.getBagNum(classSizePower); 1015 | BibopObjCache& curCache = _bagCache[threadIndex][bagNum]; 1016 | 1017 | PRDBG("allocateSmallObject(%zu): threadIndex = %d, bagNum = %d, class size = %u", 1018 | sz, threadIndex, bagNum, curCache.getClassSize()); 1019 | 1020 | void * object = curCache.malloc(); 1021 | 1022 | return object; 1023 | } 1024 | 1025 | inline bool isObjectFree(shadowObjectInfo * shadowinfo) { 1026 | return(*shadowinfo != ALLOC_SENTINEL); 1027 | } 1028 | 1029 | inline void markObjectFree(shadowObjectInfo * shadowinfo) { 1030 | *shadowinfo = FREE_SENTINEL; 1031 | } 1032 | 1033 | void freeSmallObject(void * addr) { 1034 | void * objectStartAddr; 1035 | PerThreadBag * bag; 1036 | #ifdef USE_CANARY 1037 | PerThreadBag * ownerBag; 1038 | shadowObjectInfo * shadowinfo = getShadowObjectInfo(addr, &bag, &objectStartAddr, &ownerBag); 1039 | #else 1040 | shadowObjectInfo * shadowinfo = getShadowObjectInfo(addr, &bag, &objectStartAddr); 1041 | #endif 1042 | 1043 | BibopFreeCache * freeCache = bag->freeCache; 1044 | 1045 | PRDBG("\tfree(%p): smAddr %p (value=%d), threadIndex=%d, bagNum=%d, classSize=%zu, objectStart=%p", 1046 | addr, shadowinfo, *shadowinfo, bag->threadIndex, bag->bagNum, bag->classSize, objectStartAddr); 1047 | 1048 | if(isObjectFree(shadowinfo)) { 1049 | PRERR("Double free or invalid free problem found on object %p (sm %p)", addr, shadowinfo); 1050 | printCallStack(); 1051 | exit(EXIT_FAILURE); 1052 | } 1053 | 1054 | #ifdef DESTROY_ON_FREE 1055 | #ifdef USE_CANARY 1056 | size_t objectSizeNoCanary = bag->classSize - 1; 1057 | #else 1058 | size_t objectSizeNoCanary = bag->classSize; 1059 | #endif 1060 | #endif 1061 | 1062 | #ifdef USE_CANARY 1063 | char * canary = (char *)objectStartAddr + bag->classSize - 1; 1064 | if(*canary != CANARY_SENTINEL) { 1065 | FATAL("canary value for object %p not intact; canary @ %p, value=0x%x", 1066 | addr, canary, (unsigned)*canary); 1067 | } 1068 | #if (NUM_MORE_CANARIES_TO_CHECK > 0) 1069 | for(int move = LEFT; move <= RIGHT; move++) { 1070 | shadowObjectInfo * canaryShadow = shadowinfo; 1071 | for(int pos = 0; pos < NUM_MORE_CANARIES_TO_CHECK; pos++) { 1072 | if((canaryShadow = getNextCanaryNeighbor(canaryShadow, ownerBag, (direction)move))) { 1073 | char * neighborAddr = (char *)getAddrFromShadowInfo(canaryShadow, ownerBag); 1074 | char * canary = neighborAddr + bag->classSize - 1; 1075 | // We will only inspect the canary of objects currently in-use; if the 1076 | // object is free, then it has already been checked previously. 1077 | PRDBG("checking canary value for object %p (neighbor of %p); classSize=%zu, canary @ %p", 1078 | neighborAddr, objectStartAddr, bag->classSize, canary); 1079 | if(!isObjectFree(canaryShadow) && (*canary != CANARY_SENTINEL)) { 1080 | FATAL("canary value for object %p (neighbor of %p) not intact; canary @ %p, value=0x%x", 1081 | neighborAddr, objectStartAddr, canary, (unsigned)*canary); 1082 | } 1083 | } else { 1084 | // getNextCanaryNeighbor will only return null when we attempt to move 1085 | // left or right from the first or last object in a bag. 1086 | break; 1087 | } 1088 | } 1089 | } 1090 | #endif 1091 | #endif 1092 | #ifdef DESTROY_ON_FREE 1093 | destroyObject(objectStartAddr, objectSizeNoCanary); 1094 | #endif 1095 | 1096 | markObjectFree(shadowinfo); 1097 | 1098 | //#pragma message "madvise turned off" 1099 | if(bag->classSize >= 16 * PAGESIZE) { 1100 | madvise(objectStartAddr, bag->classSize, MADV_DONTNEED); 1101 | } 1102 | 1103 | freeCache->add(objectStartAddr); 1104 | } 1105 | 1106 | bool isSmallObject(void * addr) { 1107 | return ((char *)addr >= _heapBegin && (char *)addr <= _heapEnd); 1108 | } 1109 | 1110 | 1111 | private: 1112 | uintptr_t getBagShadowMemStart(unsigned threadNum, unsigned bagNum) { 1113 | return _threadBag[threadNum][bagNum].startShadowMem; 1114 | } 1115 | 1116 | #ifdef DESTROY_ON_FREE 1117 | inline void destroyObject(void * addr, size_t classSize) { 1118 | #pragma message "destroy-on-free only applies to objects <= 2KB in size" 1119 | if(classSize <= TWO_KILOBYTES) { 1120 | memset(addr, 0, classSize); 1121 | } 1122 | } 1123 | #endif 1124 | 1125 | static inline int getRandomNumber() { 1126 | int retVal; 1127 | 1128 | #ifdef SSE2RNG 1129 | #pragma message "using sse2rng routine rather than libc rand" 1130 | unsigned randNum[4]; 1131 | rand_sse(randNum); 1132 | retVal = randNum[0]; 1133 | #elif ARC4RNG 1134 | #pragma mesage "using arc4rng routine rather than libc rand" 1135 | retVal = arc4random_uniform(RAND_MAX); 1136 | #else 1137 | #pragma message "using libc random number generator" 1138 | retVal = rand(); 1139 | #endif 1140 | 1141 | return retVal; 1142 | } 1143 | 1144 | inline shadowObjectInfo * getNextCanaryNeighbor(shadowObjectInfo * shadowinfo, PerThreadBag * bag, direction move) { 1145 | ptrdiff_t shadowOffset = (uintptr_t)shadowinfo - bag->startShadowMem; 1146 | unsigned long objectindex = shadowOffset >> _shadowObjectInfoSizeShiftBits; 1147 | 1148 | //PRDBG("getneighbor: t%3u/b%2u, sm %p, objectindex %lu, dir=%u", 1149 | // bag->threadIndex, bag->bagNum, shadowinfo, objectindex, move); 1150 | 1151 | if(move == LEFT) { 1152 | // Check whether we are physically capable of moving to the left; if not, return null 1153 | if(objectindex == 0) { 1154 | return NULL; 1155 | } else { 1156 | shadowinfo--; 1157 | } 1158 | } else { 1159 | // Check to see if we reached the index of the last object in this bag 1160 | if(objectindex == bag->lastObjectIndex) { 1161 | return NULL; 1162 | } else { 1163 | shadowinfo++; 1164 | } 1165 | } 1166 | 1167 | return shadowinfo; 1168 | } 1169 | 1170 | inline char * getLastOfBag(char * start, size_t guardoffset, size_t classSize) { 1171 | return start + _bibopBagSize - guardoffset - classSize; 1172 | } 1173 | 1174 | inline shadowObjectInfo * getShadowObjectInfo(void * addr, PerThreadBag ** bag = NULL, 1175 | void ** objectStart = NULL, PerThreadBag ** ownerBag = NULL) { 1176 | unsigned long offset = (char *)addr - _heapBegin; 1177 | unsigned long localBagOffset = offset & _bagMask; 1178 | unsigned long globalBagNum = offset >> _bagShiftBits; 1179 | unsigned long origOwnerTindex = offset >> _threadShiftBits; 1180 | unsigned long origBagNum = globalBagNum & _numBagsPerSubHeapMask; 1181 | 1182 | PerThreadBag * origBag = &_threadBag[origOwnerTindex][origBagNum]; 1183 | 1184 | if(bag) { 1185 | unsigned objectSize = _threadMap[origOwnerTindex].getClassSize(origBagNum); 1186 | unsigned currentThread = getThreadIndex(¤tThread); 1187 | unsigned bagNum = _threadMap[currentThread].getBagNum(objectSize); 1188 | *bag = &_threadBag[currentThread][bagNum]; 1189 | } 1190 | 1191 | if(ownerBag) { 1192 | *ownerBag = origBag; 1193 | } 1194 | 1195 | if(objectStart) { 1196 | unsigned long objectStartOffset = localBagOffset & ~origBag->classMask; 1197 | *objectStart = (void *)(_heapBegin + origBag->startOffset + objectStartOffset); 1198 | } 1199 | 1200 | shadowObjectInfo * shadowinfo = (shadowObjectInfo *)(origBag->startShadowMem); 1201 | 1202 | shadowObjectInfo * retval = &shadowinfo[localBagOffset >> origBag->shiftBits]; 1203 | //PRDBG("getShadowObjectInfo(%p) == smAddr %p, local bag offset = 0x%lx, shift bits = %zu", 1204 | // addr, retval, localBagOffset, origBag->shiftBits); 1205 | return retval; 1206 | } 1207 | 1208 | inline void * getAddrFromShadowInfo(shadowObjectInfo * shadowaddr, PerThreadBag * bag, bool debug = false) { 1209 | // Calculate the object number relative to the original bag's shadow mem start 1210 | ptrdiff_t localShadowOffset = (uintptr_t)shadowaddr - bag->startShadowMem; 1211 | unsigned long objectindex = localShadowOffset >> _shadowObjectInfoSizeShiftBits; 1212 | return (void *)(_heapBegin + bag->startOffset + (objectindex << bag->shiftBits)); 1213 | } 1214 | 1215 | #ifdef ENABLE_GUARDPAGE 1216 | inline int setGuardPage(void * bagStartAddr, size_t guardsize, size_t guardoffset) { 1217 | if(guardsize == 0) { return 0; } 1218 | 1219 | uintptr_t guardaddr = (uintptr_t)bagStartAddr + _bibopBagSize; 1220 | guardaddr -= guardoffset; 1221 | 1222 | //uintptr_t endAddr = guardaddr + guardsize; 1223 | //ptrdiff_t diff = endAddr - guardaddr; 1224 | //PRDBG("setGuardPage: mprotect region 0x%lx ~ 0x%lx, size=%lu", guardaddr, endAddr, diff); 1225 | 1226 | /* 1227 | int mresult = mprotect((void *)guardaddr, guardsize, PROT_NONE); 1228 | if(mresult == -1) { 1229 | PRERR("mprotect failed: %s", strerror(errno)); 1230 | } 1231 | return mresult; 1232 | */ 1233 | 1234 | return mprotect((void *)guardaddr, guardsize, PROT_NONE); 1235 | } 1236 | #endif 1237 | 1238 | inline bool isInvalidAddr(void * addr) { 1239 | return !((char *)addr >= _heapBegin && (char *)addr <= _heapEnd); 1240 | } 1241 | }; 1242 | 1243 | size_t BibopHeap::_bagMask = 0; 1244 | unsigned long BibopHeap::_bagShiftBits = 0UL; 1245 | size_t BibopHeap::_bibopBagSize = 0; 1246 | unsigned BibopHeap::_cacheSize; 1247 | unsigned BibopHeap::_overProvObjBufSize; 1248 | #endif 1249 | --------------------------------------------------------------------------------