Stack Check

Reference1

safecode/include/StackSafety.h: This file defines checks for stack safety.

    struct checkStackSafety : public ModulePass {
      
    public :
      ...
      virtual bool runOnModule(Module &M);
      virtual void getAnalysisUsage(AnalysisUsage &AU) const {
        AU.addRequired<DataLayout>();
        AU.addRequired<EQTDDataStructures>();
        AU.setPreservesAll();
      }

    private :
      //
      // Tracks the DSNodes that have already been analyzed by an invocation of
      // markReachableAllocas().
      //
      std::set<DSNode *> reachableAllocaNodes; 
      bool markReachableAllocas(DSNode *DSN, bool start=false);
      bool markReachableAllocasInt(DSNode *DSN, bool start=false);
    };
  }
}

safecode/lib/StackSafety/CheckStackPointer.cpp: Implementation of StackSafety.h

“FixMe: Can this pass get better results by using another DSA pass? It seems this pass may be too conservative by using the Top-Down DSA results.”

  • runOnModule(): no changes.

    • EQTDDataStructures: An DSA pass that “computes new data structure graphs for each function using the closed graphs for the callers computed by the EQ bottom-up pass.” more

      bool
      checkStackSafety::runOnModule(Module &M) {
      //  TDDataStructures *TDDS;
      //  TDDS = &getAnalysis<TDDataStructures>();
      EQTDDataStructures *BUDS;
      BUDS = &getAnalysis<EQTDDataStructures>();
      
      //
      // Get a pointer to the entry of the program.
      //
      Function *MainFunc = M.getFunction("main") ? M.getFunction("main")
                                           : M.getFunction ("MAIN__");
      
      //
      // Scan each function and look for stack objects which can escape from the
      // function.
      //
      for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
      Function &F = *MI;
      if (&F != MainFunc) {
      if (!F.isDeclaration()) {
      DSGraph * BUG = BUDS->getDSGraph(F);
      
      //
      // If the function can return a pointer, see if a stack object can
      // escape via the return value.
      //
      if (isa<PointerType>(F.getReturnType())) {
        for (inst_iterator ii = inst_begin(F), ie = inst_end(&F);
                           ii != ie;
                           ++ii) {
          if (ReturnInst *RI = dyn_cast<ReturnInst>(&*ii)) {
            DSNode *DSN = BUG->getNodeForValue(RI).getNode();
            if (DSN) {
              markReachableAllocas(DSN);
            }
          }
        }
      }
          
      //
      // Conservatively assume that any stack object reachable from one of
      // the incoming arguments is a stack object that is placed there as an
      // "output" by this function (or one of its callees).
      //
      Function::arg_iterator AI = F.arg_begin(), AE = F.arg_end();
      for (; AI != AE; ++AI) {
        if (isa<PointerType>(AI->getType())) {
          DSNode *DSN = BUG->getNodeForValue(AI).getNode();
          markReachableAllocas(DSN, true);
        }
      }
      
      //
      // Any stack object that is reachable by a global may also escape the
      // function.  Scan both for local variables that may alias with globals
      // as well as globals that are directly accessed by the function.
      //
      DSGraph::node_iterator DSNI = BUG->node_begin(), DSNE = BUG->node_end();
      for (; DSNI != DSNE; ++DSNI) {
        if (DSNI->isGlobalNode()) {
          markReachableAllocas(DSNI);
        }
      }
      
      DSGraph * GlobalGraph = BUG->getGlobalsGraph();
      DSNI = GlobalGraph->node_begin(), DSNE = GlobalGraph->node_end();
      for (; DSNI != DSNE; ++DSNI) {
        if (DSNI->isGlobalNode()) {
          markReachableAllocas(DSNI);
        }
      }
      }
      }
      }
      
      //
      // This pass never changes the module; always return false.
      //
      return false;
      }
      
  • markReachableAllocasInt(DSNode *DSN, bool start): Find all of the DSNodes that alias with stack objects and are reachable from the specified DSNode.

    bool
    checkStackSafety::markReachableAllocasInt(DSNode *DSN, bool start) {
    bool returnValue = false;
    reachableAllocaNodes.insert(DSN);
    
    //
    // If the initial node is an alloca node, then put it in the reachable set.
    //
    if (!start && DSN->isAllocaNode()) {
    returnValue =  true;
    AllocaNodes.insert (DSN);
    }
    
    //
    // Look at the DSNodes reachable from this DSNode.  If they alias with the
    // stack, put them in the reachable set.
    //
    DataLayout & TD = getAnalysis<DataLayout>();
    for (unsigned i = 0, e = DSN->getSize(); i < e; i += TD.getPointerSize())
    if (DSNode *DSNchild = DSN->getLink(i).getNode()) {
      if (reachableAllocaNodes.find(DSNchild) != reachableAllocaNodes.end()) {
        continue;
      } else if (markReachableAllocasInt(DSNchild)) {
        returnValue = returnValue || true;
      }
    }
    return returnValue;
    }
    
Created Jul 25, 2019 // Last Updated Aug 31, 2020

If you could revise
the fundmental principles of
computer system design
to improve security...

... what would you change?