void ClassHierarchyUtils::cacheAllCalleesForVirtualCalls(Module& M) { if (!cachingDone) { for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { if (F->isDeclaration()) continue; for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { if (CallInst* C = dyn_cast<CallInst>(&*I)) { GlobalVariable* definingTypeVTableVar = NULL; GlobalVariable* staticTypeVTableVar = NULL; bool hasMetadata = false; if (MDNode* N = I->getMetadata("soaap_defining_vtable_var")) { definingTypeVTableVar = cast<GlobalVariable>(N->getOperand(0)); hasMetadata = true; } else if (MDNode* N = I->getMetadata("soaap_defining_vtable_name")) { ConstantDataArray* definingTypeVTableConstant = cast<ConstantDataArray>(N->getOperand(0)); string definingTypeVTableConstantStr = definingTypeVTableConstant->getAsString().str(); //dbgs() << "definingTypeVTableConstantStr: " << definingTypeVTableConstantStr << "\n"; definingTypeVTableVar = M.getGlobalVariable(definingTypeVTableConstantStr, true); hasMetadata = true; } if (MDNode* N = I->getMetadata("soaap_static_vtable_var")) { staticTypeVTableVar = cast<GlobalVariable>(N->getOperand(0)); hasMetadata = true; } else if (MDNode* N = I->getMetadata("soaap_static_vtable_name")) { ConstantDataArray* staticTypeVTableConstant = cast<ConstantDataArray>(N->getOperand(0)); string staticTypeVTableConstantStr = staticTypeVTableConstant->getAsString().str(); //dbgs() << "staticTypeVTableConstantStr: " << staticTypeVTableConstantStr << "\n"; staticTypeVTableVar = M.getGlobalVariable(staticTypeVTableConstantStr, true); hasMetadata = true; } if (definingTypeVTableVar != NULL) { SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "Found definingVTableVar: " << *definingTypeVTableVar << "\n"); if (staticTypeVTableVar == NULL) { dbgs() << "definingVTableVar is not null, but staticTypeVTableVar is NULL\n"; // This could be the case if no instance of the static type is ever created staticTypeVTableVar = definingTypeVTableVar; } callToCalleesCache[C] = findAllCalleesForVirtualCall(C, definingTypeVTableVar, staticTypeVTableVar, M); } else if (hasMetadata) { dbgs() << "Defining VTable is NULL!\n"; I->dump(); } } } } cachingDone = true; } }
void AssertionSiteInstrumenter::ParseAssertionLocation( Location *Loc, CallInst *Call) { assert(Call->getCalledFunction()->getName() == INLINE_ASSERTION); if (Call->getNumArgOperands() < 4) panic("TESLA assertion must have at least 4 arguments"); // The filename (argument 1) should be a global variable. GlobalVariable *NameVar = dyn_cast<GlobalVariable>(Call->getOperand(1)->stripPointerCasts()); ConstantDataArray *A; if (!NameVar || !(A = dyn_cast_or_null<ConstantDataArray>(NameVar->getInitializer()))) { Call->dump(); panic("unable to parse filename from TESLA assertion"); } *Loc->mutable_filename() = A->getAsString(); // The line and counter values should be constant integers. ConstantInt *Line = dyn_cast<ConstantInt>(Call->getOperand(2)); if (!Line) { Call->getOperand(2)->dump(); panic("assertion line must be a constant int"); } Loc->set_line(Line->getLimitedValue(INT_MAX)); ConstantInt *Count = dyn_cast<ConstantInt>(Call->getOperand(3)); if (!Count) { Call->getOperand(3)->dump(); panic("assertion count must be a constant int"); } Loc->set_counter(Count->getLimitedValue(INT_MAX)); }
SandboxVector SandboxUtils::findSandboxes(Module& M) { FunctionIntMap funcToOverhead; FunctionIntMap funcToClearances; map<Function*,string> funcToSandboxName; map<string,FunctionSet> sandboxNameToEntryPoints; StringSet ephemeralSandboxes; SandboxVector sandboxes; // function-level annotations of sandboxed code Regex *sboxPerfRegex = new Regex("perf_overhead_\\(([0-9]{1,2})\\)", true); SmallVector<StringRef, 4> matches; if (GlobalVariable* lga = M.getNamedGlobal("llvm.global.annotations")) { ConstantArray* lgaArray = dyn_cast<ConstantArray>(lga->getInitializer()->stripPointerCasts()); for (User::op_iterator i=lgaArray->op_begin(), e = lgaArray->op_end(); e!=i; i++) { ConstantStruct* lgaArrayElement = dyn_cast<ConstantStruct>(i->get()); // get the annotation value first GlobalVariable* annotationStrVar = dyn_cast<GlobalVariable>(lgaArrayElement->getOperand(1)->stripPointerCasts()); ConstantDataArray* annotationStrArray = dyn_cast<ConstantDataArray>(annotationStrVar->getInitializer()); StringRef annotationStrArrayCString = annotationStrArray->getAsCString(); GlobalValue* annotatedVal = dyn_cast<GlobalValue>(lgaArrayElement->getOperand(0)->stripPointerCasts()); if (isa<Function>(annotatedVal)) { Function* annotatedFunc = dyn_cast<Function>(annotatedVal); StringRef sandboxName; if (annotationStrArrayCString.startswith(SANDBOX_PERSISTENT) || annotationStrArrayCString.startswith(SANDBOX_EPHEMERAL)) { sandboxEntryPoints.insert(annotatedFunc); outs() << INDENT_1 << "Found sandbox entrypoint " << annotatedFunc->getName() << "\n"; outs() << INDENT_2 << "Annotation string: " << annotationStrArrayCString << "\n"; if (annotationStrArrayCString.startswith(SANDBOX_PERSISTENT)) { sandboxName = annotationStrArrayCString.substr(strlen(SANDBOX_PERSISTENT)+1); } else if (annotationStrArrayCString.startswith(SANDBOX_EPHEMERAL)) { sandboxName = annotationStrArrayCString.substr(strlen(SANDBOX_EPHEMERAL)+1); ephemeralSandboxes.insert(sandboxName); } outs() << INDENT_2 << "Sandbox name: " << sandboxName << "\n"; if (funcToSandboxName.find(annotatedFunc) != funcToSandboxName.end()) { outs() << INDENT_1 << "*** Error: Function " << annotatedFunc->getName() << " is already an entrypoint for another sandbox\n"; } else { funcToSandboxName[annotatedFunc] = sandboxName; sandboxNameToEntryPoints[sandboxName].insert(annotatedFunc); } } else if (sboxPerfRegex->match(annotationStrArrayCString, &matches)) { int overhead; outs() << INDENT_2 << "Threshold set to " << matches[1].str() << "%\n"; matches[1].getAsInteger(0, overhead); funcToOverhead[annotatedFunc] = overhead; } else if (annotationStrArrayCString.startswith(CLEARANCE)) { StringRef className = annotationStrArrayCString.substr(strlen(CLEARANCE)+1); outs() << INDENT_2 << "Sandbox has clearance for \"" << className << "\"\n"; ClassifiedUtils::assignBitIdxToClassName(className); funcToClearances[annotatedFunc] |= (1 << ClassifiedUtils::getBitIdxFromClassName(className)); } } } } // TODO: sanity check overhead and clearance annotations // Combine all annotation information for function-level sandboxes to create Sandbox instances for (pair<string,FunctionSet> p : sandboxNameToEntryPoints) { string sandboxName = p.first; FunctionSet entryPoints = p.second; int idx = assignBitIdxToSandboxName(sandboxName); int overhead = 0; int clearances = 0; bool persistent = find(ephemeralSandboxes.begin(), ephemeralSandboxes.end(), sandboxName) == ephemeralSandboxes.end(); // set overhead and clearances; any of the entry points could be annotated for (Function* entryPoint : entryPoints) { if (funcToOverhead.find(entryPoint) != funcToOverhead.end()) { overhead = funcToOverhead[entryPoint]; } if (funcToClearances.find(entryPoint) != funcToClearances.end()) { clearances = funcToClearances[entryPoint]; } } SDEBUG("soaap.util.sandbox", 3, dbgs() << INDENT_2 << "Creating new Sandbox instance for " << sandboxName << "\n"); sandboxes.push_back(new Sandbox(sandboxName, idx, entryPoints, persistent, M, overhead, clearances)); SDEBUG("soaap.util.sandbox", 3, dbgs() << INDENT_2 << "Created new Sandbox instance\n"); } /* for (map<Function*,string>::iterator I=funcToSandboxName.begin(), E=funcToSandboxName.end(); I!=E; I++) { Function* entryPoint = I->first; string sandboxName = I->second; int idx = assignBitIdxToSandboxName(sandboxName); int overhead = funcToOverhead[entryPoint]; int clearances = funcToClearances[entryPoint]; bool persistent = find(ephemeralSandboxes.begin(), ephemeralSandboxes.end(), entryPoint) == ephemeralSandboxes.end(); SDEBUG("soaap.util.sandbox", 3, dbgs() << INDENT_2 << "Creating new Sandbox instance\n"); sandboxes.push_back(new Sandbox(sandboxName, idx, entryPoint, persistent, M, overhead, clearances)); SDEBUG("soaap.util.sandbox", 3, dbgs() << INDENT_2 << "Created new Sandbox instance\n"); } */ // Handle sandboxed code regions, i.e. start_sandboxed_code(N) and end_sandboxed_code(N) blocks if (Function* SboxStart = M.getFunction("llvm.annotation.i32")) { for (User* U : SboxStart->users()) { if (IntrinsicInst* annotCall = dyn_cast<IntrinsicInst>(U)) { GlobalVariable* annotationStrVar = dyn_cast<GlobalVariable>(annotCall->getOperand(1)->stripPointerCasts()); ConstantDataArray* annotationStrValArray = dyn_cast<ConstantDataArray>(annotationStrVar->getInitializer()); StringRef annotationStrValCString = annotationStrValArray->getAsCString(); if (annotationStrValCString.startswith(SOAAP_SANDBOX_REGION_START)) { StringRef sandboxName = annotationStrValCString.substr(strlen(SOAAP_SANDBOX_REGION_START)+1); //+1 because of _ SDEBUG("soaap.util.sandbox", 3, dbgs() << INDENT_3 << "Found start of sandboxed code region: "; annotCall->dump();); InstVector sandboxedInsts; findAllSandboxedInstructions(annotCall, sandboxName, sandboxedInsts); int idx = assignBitIdxToSandboxName(sandboxName); sandboxes.push_back(new Sandbox(sandboxName, idx, sandboxedInsts, false, M)); //TODO: obtain persistent/ephemeral information in a better way (currently we obtain it from the creation point) } }
void PrivilegedCallAnalysis::doAnalysis(Module& M, SandboxVector& sandboxes) { // first find all methods annotated as being privileged and then check calls within sandboxes if (GlobalVariable* lga = M.getNamedGlobal("llvm.global.annotations")) { ConstantArray* lgaArray = dyn_cast<ConstantArray>(lga->getInitializer()->stripPointerCasts()); for (User::op_iterator i=lgaArray->op_begin(), e = lgaArray->op_end(); e!=i; i++) { ConstantStruct* lgaArrayElement = dyn_cast<ConstantStruct>(i->get()); // get the annotation value first GlobalVariable* annotationStrVar = dyn_cast<GlobalVariable>(lgaArrayElement->getOperand(1)->stripPointerCasts()); ConstantDataArray* annotationStrArray = dyn_cast<ConstantDataArray>(annotationStrVar->getInitializer()); StringRef annotationStrArrayCString = annotationStrArray->getAsCString(); GlobalValue* annotatedVal = dyn_cast<GlobalValue>(lgaArrayElement->getOperand(0)->stripPointerCasts()); if (isa<Function>(annotatedVal)) { Function* annotatedFunc = dyn_cast<Function>(annotatedVal); if (annotationStrArrayCString == SOAAP_PRIVILEGED) { outs() << " Found function: " << annotatedFunc->getName() << "\n"; privAnnotFuncs.push_back(annotatedFunc); } } } } // now check calls within sandboxes for (Function* privilegedFunc : privAnnotFuncs) { for (User* U : privilegedFunc->users()) { if (CallInst* C = dyn_cast<CallInst>(U)) { Function* enclosingFunc = C->getParent()->getParent(); for (Sandbox* S : sandboxes) { if (!S->hasCallgate(privilegedFunc) && S->containsFunction(enclosingFunc)) { outs() << " *** Sandbox \"" << S->getName() << "\" calls privileged function \"" << privilegedFunc->getName() << "\" that they are not allowed to. If intended, annotate this permission using the __soaap_callgates annotation.\n"; if (MDNode *N = C->getMetadata("dbg")) { // Here I is an LLVM instruction DILocation Loc(N); // DILocation is in DebugInfo.h unsigned Line = Loc.getLineNumber(); StringRef File = Loc.getFilename(); outs() << " +++ Line " << Line << " of file " << File << "\n"; } } } } } } /* for (Sandbox* S : sandboxes) { FunctionVector callgates = S->getCallgates(); for (Function* F : S->getFunctions()) { for (BasicBlock& BB : F->getBasicBlockList()) { for (Instruction& I : BB.getInstList()) { if (CallInst* C = dyn_cast<CallInst>(&I)) { if (Function* Target = C->getCalledFunction()) { if (find(privAnnotFuncs.begin(), privAnnotFuncs.end(), Target) != privAnnotFuncs.end()) { // check if this sandbox is allowed to call the privileged function DEBUG(dbgs() << " Found privileged call: "); DEBUG(C->dump()); if (find(callgates.begin(), callgates.end(), Target) == callgates.end()) { outs() << " *** Sandbox \"" << S->getName() << "\" calls privileged function \"" << Target->getName() << "\" that they are not allowed to. If intended, annotate this permission using the __soaap_callgates annotation.\n"; if (MDNode *N = C->getMetadata("dbg")) { // Here I is an LLVM instruction DILocation Loc(N); // DILocation is in DebugInfo.h unsigned Line = Loc.getLineNumber(); StringRef File = Loc.getFilename(); outs() << " +++ Line " << Line << " of file " << File << "\n"; } } } } } } } } } */ }