#define _magic_first_stack_dsentry (_magic_vars->first_stack_dsentry)
#define _magic_last_stack_dsentry (_magic_vars->last_stack_dsentry)
+/* Magic unmap-memory variables. */
+#ifdef __MINIX
+#define _magic_unmap_mem (_magic_vars->unmap_mem)
+#endif
+
/* Magic default stubs. */
EXTERN struct _magic_type magic_default_type;
EXTERN struct _magic_dsentry magic_default_dsentry;
#define MAGIC_PREFIX_STR "magic_"
#define MAGIC_ASR_PREFIX magic_asr_
#define MAGIC_ASR_PREFIX_STR "magic_asr_"
+#define MAGIC_NESTED_PREFIX_STR "nested_"
#define MAGIC_EVAL_FUNC_PREFIX "me_"
#define MAGIC_ANON_MEMBER_PREFIX "magic.anon"
#define MAGIC_STRINGREF_HAS_MAGIC_HIDDEN_PREFIX(S) \
#define MAGIC_MEM_FUNC_ALLOC_FLAGS \
MAGIC_MEMA_FUNC_ALLOC_FLAGS MAGIC_MEMA_EXTRA_FUNC_ALLOC_FLAGS, MAGIC_MEMD_FUNC_ALLOC_FLAGS
+#ifdef __MINIX
+/* Nested allocation functions to hook. That is, functions that are being
+ * called as part of allocation functions - in particular, malloc - and need to
+ * be intercepted for tracking purposes - in particular, so that mmap'ed malloc
+ * page directories can be unmapped in order to avoid memory leaks. MINIX3 only.
+ */
+#define MAGIC_MEMN_FUNCS \
+ __X(mmap), __X(munmap)
+#else
+#define MAGIC_MEMN_FUNCS ""
+#endif
+
#define MAGIC_DL_FUNCS \
__X(dlopen), __X(dlclose)
#define MAGIC_MEMA_FUNC_NAMES MAGIC_MEMA_FUNCS MAGIC_MEMA_EXTRA_FUNCS, ""
#define MAGIC_MEMD_FUNC_NAMES MAGIC_MEMD_FUNCS, ""
+#define MAGIC_MEMN_FUNC_NAMES MAGIC_MEMN_FUNCS, ""
#define MAGIC_MEM_FUNC_NAMES MAGIC_MEM_FUNCS, ""
#define MAGIC_DL_FUNC_NAMES MAGIC_DL_FUNCS, ""
struct _magic_dsodesc *next;
};
+/* The following constant is specific to MINIX3; on other platforms, this
+ * functionality is unused altogether. On MINIX3, the libc malloc code uses
+ * mmap to create page directories. Since malloc state is discarded upon state
+ * transfer, we must not instrument its mmap calls in the regular way. On the
+ * other hand, since mmap'ed regions are transferred to new instances, we end
+ * up with a memory leak if we do not unmap those mmap'ed regions. Therefore,
+ * we specifically track the mmap/munmap calls made from the malloc code, and
+ * explicitly unmap its regions during state transfer. The following constant
+ * defines how many ranges can be mmap'ed at once. The malloc code uses only
+ * one page directory, but it may enlarge it by first allocating a new area
+ * and then unmapping the old one. Therefore, we need two entries.
+ */
+#ifdef __MINIX
+#define MAGIC_UNMAP_MEM_ENTRIES 2
+#endif
+
/* Magic vars. */
struct _magic_vars_t {
int update_dsentry_ranges;
int update_dfunction_ranges;
+#ifdef __MINIX
+ /* Memory to unmap after state transfer (MINIX3 only) */
+ struct {
+ void *start;
+ size_t length;
+ } unmap_mem[MAGIC_UNMAP_MEM_ENTRIES];
+#endif
+
/* Range lookup index */
void *sentry_rl_buff;
size_t sentry_rl_buff_offset;
unsigned getMaxRecursiveSequenceLength(TYPECONST TypeInfo *aTypeInfo);
FunctionType* getFunctionType(TYPECONST FunctionType *baseType, std::vector<unsigned> selectedArgs);
bool isCompatibleMagicMemFuncType(TYPECONST FunctionType *type, TYPECONST FunctionType* magicType);
+ Function* findWrapper(Module &M, std::string *magicMemPrefixes, Function *f, std::string fName);
+
void indexCasts(Module &M, User *U, std::vector<TYPECONST Type*> &intCastTypes, std::vector<int> &intCastValues, std::map<TYPECONST Type*, std::set<TYPECONST Type*> > &bitcastMap);
void fillStackInstrumentedFunctions(std::vector<Function*> &stackIntrumentedFuncs, Function *deepestLLFunction);
class MagicMemFunction {
public:
- MagicMemFunction(Module &M, Function *function, Function *wrapper, bool isDealloc, int allocFlags);
+ MagicMemFunction(Module &M, Function *function, Function *wrapper, bool isDealloc, bool isNested, int allocFlags);
Function* getFunction() const;
Function* getWrapper() const;
bool isDeallocFunction() const;
+ bool isNestedFunction() const;
int getAllocFlags() const;
Instruction* getInstruction() const;
Function* getInstructionParent() const;
Function *function;
Function *wrapper;
bool isDealloc;
+ bool isNested;
int allocFlags;
Instruction *instruction;
TypeInfo* aTypeInfo;
OS << "NULL";
OS << ", isDeallocFunction = ";
OS << isDealloc;
+ OS << ", isNestedFunction = ";
+ OS << isNested;
OS << ", instruction = ";
if (instruction)
instruction->print(OS);
return string;
}
-inline MagicMemFunction::MagicMemFunction(Module &M, Function *function, Function *wrapper, bool isDealloc, int allocFlags) {
+inline MagicMemFunction::MagicMemFunction(Module &M, Function *function, Function *wrapper, bool isDealloc, bool isNested, int allocFlags) {
this->module = &M;
this->function = function;
this->wrapper = wrapper;
this->isDealloc = isDealloc;
+ this->isNested = isNested;
this->allocFlags = allocFlags;
this->instruction = NULL;
this->aTypeInfo = NULL;
this->allocNameValue = NULL;
this->allocParentNameValue = NULL;
assert(function);
- if (wrapper && !isDealloc) {
+ if (wrapper && !isDealloc && !isNested) {
lastAllocWrapper = wrapper;
}
if (isDealloc) {
return isDealloc;
}
+inline bool MagicMemFunction::isNestedFunction() const {
+ return isNested;
+}
+
inline int MagicMemFunction::getAllocFlags() const {
return allocFlags;
}
buildWrapper(magicArrayTypePtrMap, voidPtrTypeInfo);
}
//inject magic args
- if (!isDeallocFunction()) {
+ if (!isDeallocFunction() && !isNestedFunction()) {
std::map<TypeInfo*, Constant*>::iterator it;
if (!typeValue) {
assert(aTypeInfo);
inline void MagicMemFunction::buildWrapper(std::map<TypeInfo*, Constant*> &magicArrayTypePtrMap, TypeInfo *voidPtrTypeInfo) {
assert(!isDeallocFunction());
+ assert(!isNestedFunction());
assert(lastAllocWrapper);
std::vector<TYPECONST Type*> ArgTypes;
VALUE_TO_VALUE_MAP_TY VMap;
#define __X(P) #P
std::string magicMemFuncNames[] = { MAGIC_MEM_FUNC_NAMES };
std::string magicMemDeallocFuncNames[] = { MAGIC_MEMD_FUNC_NAMES };
+ std::string magicMemNestedFuncNames[] = { MAGIC_MEMN_FUNC_NAMES };
#undef __X
int magicMemFuncAllocFlags[] = { MAGIC_MEM_FUNC_ALLOC_FLAGS };
std::string magicMemPrefixes[] = { MAGIC_MEM_PREFIX_STRS };
for(i=0;magicMemFuncNames[i].compare("");i++) {
int allocFlags = magicMemFuncAllocFlags[i];
for(unsigned j=0;j<llvmCallPrefixes.size();j++) {
- Function *f = M.getFunction(llvmCallPrefixes[j] + magicMemFuncNames[i]);
+ std::string fName = magicMemFuncNames[i];
+ Function *f = M.getFunction(llvmCallPrefixes[j] + fName);
if(!f) {
continue;
}
//missing function prototype, i.e. no realistic caller. Skip.
continue;
}
- if(!magicMemFuncNames[i].compare("brk")) {
+ if(!fName.compare("brk")) {
brkFunctions.insert(f);
}
- if(!magicMemFuncNames[i].compare("sbrk")) {
+ if(!fName.compare("sbrk")) {
sbrkFunctions.insert(f);
}
- std::string wName, wName2;
- Function *w = NULL, *w2 = NULL;
- for(unsigned k=0;magicMemPrefixes[k].compare("");k++) {
- wName = magicMemPrefixes[k] + magicMemFuncNames[i];
- w = M.getFunction(wName);
- if(w) {
- wName2 = wName + "_";
+ bool isDeallocFunction = false;
+ for(unsigned k=0;magicMemDeallocFuncNames[k].compare("");k++) {
+ if(!magicMemDeallocFuncNames[k].compare(fName)) {
+ isDeallocFunction = true;
break;
}
}
- if(!w) {
- magicPassErr("Error: no wrapper function found for " << magicMemFuncNames[i] << "()");
- exit(1);
- }
- while(!isCompatibleMagicMemFuncType(f->getFunctionType(), w->getFunctionType()) && (w2 = M.getFunction(wName2))) {
- w = w2;
- wName2.append("_");
- }
- if(!isCompatibleMagicMemFuncType(f->getFunctionType(), w->getFunctionType())) {
- magicPassErr("Error: wrapper function with incompatible type " << wName << "() found");
- magicPassErr(TypeUtil::getDescription(f->getFunctionType(), MAGIC_TYPE_STR_PRINT_MAX, MAGIC_TYPE_STR_PRINT_MAX_LEVEL) << " != " << TypeUtil::getDescription(w->getFunctionType(), MAGIC_TYPE_STR_PRINT_MAX, MAGIC_TYPE_STR_PRINT_MAX_LEVEL));
- exit(1);
- }
- bool isDeallocFunction = false;
- for(unsigned j=0;magicMemDeallocFuncNames[j].compare("");j++) {
- if(!magicMemDeallocFuncNames[j].compare(magicMemFuncNames[i])) {
- isDeallocFunction = true;
+ bool makeNestedFunction = false;
+ for(unsigned k=0;magicMemNestedFuncNames[k].compare("");k++) {
+ if (!magicMemNestedFuncNames[k].compare(fName)) {
+ makeNestedFunction = true;
break;
}
}
- MagicMemFunction memFunction(M, f, w, isDeallocFunction, allocFlags);
+
+ Function* w = findWrapper(M, magicMemPrefixes, f, fName);
+ MagicMemFunction memFunction(M, f, w, isDeallocFunction, false, allocFlags);
magicMemFunctions.push_back(memFunction);
+ if (makeNestedFunction) {
+ w = findWrapper(M, magicMemPrefixes, f, MAGIC_NESTED_PREFIX_STR + fName);
+ MagicMemFunction memFunction(M, f, w, isDeallocFunction, true, allocFlags);
+ magicMemFunctions.push_back(memFunction);
+ }
originalMagicMemFunctions.insert(f);
#if DEBUG_ALLOC_LEVEL >= 1
Function *allocWrapper = MagicMemFunction::getCustomWrapper(allocFunction, stdAllocFunc, stdAllocWrapperFunc, allocArgMapping, false);
// register the wrapper
- MagicMemFunction memFunctionAlloc(M, allocFunction, allocWrapper, false, stdAllocFlags);
+ MagicMemFunction memFunctionAlloc(M, allocFunction, allocWrapper, false, false, stdAllocFlags);
magicMemFunctions.push_back(memFunctionAlloc);
originalMagicMemFunctions.insert(allocFunction);
#if DEBUG_ALLOC_LEVEL >= 1
exit(1);
}
Function *blockAllocWrapper = MagicMemFunction::getCustomWrapper(blockAllocFunc, mempoolBlockAllocTemplate, mempoolBlockAllocTemplateWrapper, argMapping, false);
- MagicMemFunction memFunctionBlockAlloc(M, blockAllocFunc, blockAllocWrapper, false, mempoolAllocFlags);
+ MagicMemFunction memFunctionBlockAlloc(M, blockAllocFunc, blockAllocWrapper, false, false, mempoolAllocFlags);
mempoolMagicMemFunctions.push_back(memFunctionBlockAlloc);
}
if (!mempoolMagicMemFunctions.empty()) { // only if the block allocation functions have been successfully processed
CS.getCalledValue()) != EqPointers.end())) {
bool isDeallocFunction = magicMemFunction.isDeallocFunction();
bool wrapParent = false;
+ bool isNested = false;
TypeInfo *typeInfo = magicVoidTypeInfo;
std::string allocName = "";
std::string allocParentName = "";
//check if we have to skip
- if(extendedMagicMemFunctions.find(CS.getInstruction()->getParent()->getParent()) != extendedMagicMemFunctions.end()) {
- //this call site is only called from some predefined mem function. skip.
+ //if this call site is only called from some predefined mem function, it is nested
+ //some function wrappers are for such nested calls, some are not. this must match.
+ isNested = (extendedMagicMemFunctions.find(CS.getInstruction()->getParent()->getParent()) != extendedMagicMemFunctions.end());
+ if (isNested != magicMemFunction.isNestedFunction()) {
continue;
}
if(sbrkFunctions.find(MagicUtil::getCalledFunctionFromCS(CS)) != sbrkFunctions.end()) {
continue;
}
//figure out the type and the names
- if(!isDeallocFunction) {
+ if(!isDeallocFunction && !isNested) {
int allocCounter = 1;
int ret;
std::map< std::pair<std::string,std::string>, int>::iterator namesMapIt;
}
if(!magicMemParent && wrapParent) {
//if there is no existing parent but we have to wrap the parent, create a parent now and add it to the function queue
- MagicMemFunction newMagicMemFunction(M, instructionParent, NULL, false, 0);
+ assert(!isNested);
+ MagicMemFunction newMagicMemFunction(M, instructionParent, NULL, false, false, 0);
magicMemFunctions.push_back(newMagicMemFunction);
magicMemParent = &magicMemFunctions[magicMemFunctions.size()-1];
}
return true;
}
+Function* MagicPass::findWrapper(Module &M, std::string *magicMemPrefixes, Function *f, std::string fName)
+{
+ std::string wName, wName2;
+ Function *w = NULL, *w2 = NULL;
+ for(unsigned k=0;magicMemPrefixes[k].compare("");k++) {
+ wName = magicMemPrefixes[k] + fName;
+ w = M.getFunction(wName);
+ if(w) {
+ wName2 = wName + "_";
+ break;
+ }
+ }
+ if(!w) {
+ magicPassErr("Error: no wrapper function found for " << fName << "()");
+ exit(1);
+ }
+ while(!isCompatibleMagicMemFuncType(f->getFunctionType(), w->getFunctionType()) && (w2 = M.getFunction(wName2))) {
+ w = w2;
+ wName2.append("_");
+ }
+ if(!isCompatibleMagicMemFuncType(f->getFunctionType(), w->getFunctionType())) {
+ magicPassErr("Error: wrapper function with incompatible type " << wName << "() found");
+ magicPassErr(TypeUtil::getDescription(f->getFunctionType(), MAGIC_TYPE_STR_PRINT_MAX, MAGIC_TYPE_STR_PRINT_MAX_LEVEL) << " != " << TypeUtil::getDescription(w->getFunctionType(), MAGIC_TYPE_STR_PRINT_MAX, MAGIC_TYPE_STR_PRINT_MAX_LEVEL));
+ exit(1);
+ }
+ return w;
+}
+
void MagicPass::indexCasts(Module &M, User *U, std::vector<TYPECONST Type*> &intCastTypes, std::vector<int> &intCastValues, std::map<TYPECONST Type*, std::set<TYPECONST Type*> > &bitCastMap) {
unsigned i;
std::map<TYPECONST Type*, std::set<TYPECONST Type*> >::iterator bitCastMapIt;
1, /* update_dsentry_ranges */
1, /* update_dfunction_ranges */
+#ifdef __MINIX
+ { { NULL, 0 } }, /* unmap_mem */
+#endif
+
NULL, /* sentry_rl_buff */
0, /* sentry_rl_buff_offset */
0, /* sentry_rl_buff_size */
return data_ptr;
}
+
+/*===========================================================================*
+ * magic_nested_mmap *
+ *===========================================================================*/
+void *
+magic_nested_mmap(void *start, size_t length, int prot, int flags,
+ int fd, off_t offset)
+{
+ void *ptr;
+ int i;
+
+ ptr = mmap(start, length, prot, flags, fd, offset);
+
+ if (ptr != MAP_FAILED) {
+ MAGIC_MEM_PRINTF("MAGIC: nested mmap (%p, %zu)\n", ptr,
+ length);
+
+ /*
+ * Find a free entry. We do not expect the malloc code to have
+ * more than two areas mapped at any time.
+ */
+ for (i = 0; i < MAGIC_UNMAP_MEM_ENTRIES; i++)
+ if (_magic_unmap_mem[i].length == 0)
+ break;
+ assert(i < MAGIC_UNMAP_MEM_ENTRIES);
+
+ /* Store the mapping in this entry. */
+ _magic_unmap_mem[i].start = ptr;
+ _magic_unmap_mem[i].length = length;
+ }
+
+ return ptr;
+}
+
+/*===========================================================================*
+ * magic_nested_munmap *
+ *===========================================================================*/
+int
+magic_nested_munmap(void *start, size_t length)
+{
+ int i, r;
+
+ r = munmap(start, length);
+
+ if (r == 0) {
+ MAGIC_MEM_PRINTF("MAGIC: nested munmap (%p, %zu)\n", start,
+ length);
+
+ /* Find the corresponding entry. This must always succeed. */
+ for (i = 0; i < MAGIC_UNMAP_MEM_ENTRIES; i++)
+ if (_magic_unmap_mem[i].start == start &&
+ _magic_unmap_mem[i].length == length)
+ break;
+ assert(i < MAGIC_UNMAP_MEM_ENTRIES);
+
+ /* Clear the entry. */
+ _magic_unmap_mem[i].start = NULL;
+ _magic_unmap_mem[i].length = 0;
+ }
+
+ return r;
+}
#endif
*((void **)(((char *)magic_vars) + offset_list[i])) = NULL;
}
+
+#ifdef __MINIX
+PRIVATE void st_unmap_mem(struct _magic_vars_t *magic_vars)
+{
+ int i, r;
+
+ for (i = 0; i < MAGIC_UNMAP_MEM_ENTRIES; i++) {
+ if (magic_vars->unmap_mem[i].length != 0) {
+#if ST_DEBUG_LEVEL > 0
+ printf("st_unmap_mem: unmapping (%p, %zu)\n",
+ magic_vars->unmap_mem[i].start,
+ magic_vars->unmap_mem[i].length);
+#endif
+ r = munmap(magic_vars->unmap_mem[i].start,
+ magic_vars->unmap_mem[i].length);
+ assert(r == 0);
+ }
+ }
+}
+#endif
+
PUBLIC int st_init(st_init_info_t *info)
{
int r, max_buff_sz = 0, dsentries_num;
st_init_function_hash(info, _magic_vars);
#endif
+#ifdef __MINIX
+ /* Unmap any memory ranges that are not needed in the new process. */
+ st_unmap_mem(&st_cached_magic_vars);
+#endif
+
/* Pair metadata entities */
r = pair_metadata_types(info, &st_cached_magic_vars, &st_counterparts, allow_unpaired_types);
assert( r == OK && "ERROR occurred during call to pair_metadata_types().");