OLD | NEW |
(Empty) | |
| 1 //===----- ExpandAllocas.cpp - Allocate memory on the untrusted stack -----===// |
| 2 // |
| 3 // The LLVM Compiler Infrastructure |
| 4 // |
| 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. |
| 7 // |
| 8 //===----------------------------------------------------------------------===// |
| 9 // |
| 10 // Code sandboxed with MinSFI cannot access the execution stack directly |
| 11 // because the stack lies outside of its address subspace, which prevents it |
| 12 // from using memory allocated with the alloca instruction. This pass therefore |
| 13 // replaces allocas with memory allocation on a separate stack at a fixed |
| 14 // location inside the designated memory region. |
| 15 // |
| 16 // The new stack does not have to be trusted as it is only used for memory |
| 17 // allocation inside the sandbox. The call and ret instructions still operate |
| 18 // on the native stack, preventing manipulation with the return address or |
| 19 // callee-saved registers. |
| 20 // |
| 21 // This pass also replaces the @llvm.stacksave and @llvm.stackrestore |
| 22 // intrinsics which would otherwise allow access to the native stack pointer. |
| 23 // Instead, they are expanded out and save/restore the current untrusted stack |
| 24 // pointer. |
| 25 // |
| 26 // When a function is invoked, the current untrusted stack pointer is obtained |
| 27 // from the "__sfi_stack_ptr" global variable (internal to the module). The |
| 28 // function then keeps track of the current value of the stack pointer, but |
| 29 // must update the global variable prior to any function calls and restore the |
| 30 // initial value before it returns. |
| 31 // |
| 32 // The stack pointer is initialized in the entry function of the module, the |
| 33 // _start_minsfi function. The runtime is expected to copy the arguments |
| 34 // (a NULL-terminated integer array) at the end of the allocated memory region, |
| 35 // i.e. at the bottom of the untrusted stack, and pass the pointer to the array |
| 36 // to the entry function. The sandboxed code is then expected to use the |
| 37 // pointer not only to access its arguments but also as the initial value of |
| 38 // its stack pointer and to grow the stack backwards. |
| 39 // |
| 40 // If an alloca requests alignment greater than 1, the untrusted stack pointer |
| 41 // is aligned accordingly. However, the alignment is applied before the address |
| 42 // is sandboxed and therefore the runtime must guarantee that the base address |
| 43 // of the sandbox is aligned to at least 2^29 bytes (=512MB), which is the |
| 44 // maximum alignment supported by LLVM. |
| 45 // |
| 46 // Possible optimizations: |
| 47 // - accumulate constant-sized allocas to reduce the number of stores |
| 48 // into the global stack pointer variable |
| 49 // - remove stores into the global pointer if the respective values never |
| 50 // reach a function call |
| 51 // - align frame to 16 bytes |
| 52 // |
| 53 //===----------------------------------------------------------------------===// |
| 54 |
| 55 #include "llvm/Pass.h" |
| 56 #include "llvm/IR/Constants.h" |
| 57 #include "llvm/IR/DataLayout.h" |
| 58 #include "llvm/IR/Function.h" |
| 59 #include "llvm/IR/Instructions.h" |
| 60 #include "llvm/IR/IntrinsicInst.h" |
| 61 #include "llvm/IR/Module.h" |
| 62 #include "llvm/Support/MathExtras.h" |
| 63 #include "llvm/Transforms/MinSFI.h" |
| 64 #include "llvm/Transforms/NaCl.h" |
| 65 |
| 66 using namespace llvm; |
| 67 |
| 68 static const char InternalSymName_StackPointer[] = "__sfi_stack_ptr"; |
| 69 |
| 70 namespace { |
| 71 // ExpandAllocas needs to be a ModulePass because it adds a GlobalVariable. |
| 72 class ExpandAllocas : public ModulePass { |
| 73 GlobalVariable *StackPtrVar; |
| 74 Type *IntPtrType, *I8Ptr; |
| 75 |
| 76 void runOnFunction(Function &Func); |
| 77 void insertStackPtrInit(Module &M); |
| 78 |
| 79 public: |
| 80 static char ID; |
| 81 ExpandAllocas() : ModulePass(ID), StackPtrVar(NULL), IntPtrType(NULL), |
| 82 I8Ptr(NULL) { |
| 83 initializeExpandAllocasPass(*PassRegistry::getPassRegistry()); |
| 84 } |
| 85 |
| 86 virtual bool runOnModule(Module &M); |
| 87 }; |
| 88 } // namespace |
| 89 |
| 90 bool ExpandAllocas::runOnModule(Module &M) { |
| 91 DataLayout DL(&M); |
| 92 IntPtrType = DL.getIntPtrType(M.getContext()); |
| 93 I8Ptr = Type::getInt8PtrTy(M.getContext()); |
| 94 |
| 95 // Create the stack pointer global variable. We are forced to give it some |
| 96 // initial value, but it will be initialized at runtime. |
| 97 StackPtrVar = new GlobalVariable(M, IntPtrType, /*isConstant=*/false, |
| 98 GlobalVariable::InternalLinkage, |
| 99 ConstantInt::get(IntPtrType, 0), |
| 100 InternalSymName_StackPointer); |
| 101 |
| 102 for (Module::iterator Func = M.begin(), E = M.end(); Func != E; ++Func) |
| 103 runOnFunction(*Func); |
| 104 |
| 105 insertStackPtrInit(M); |
| 106 |
| 107 return true; |
| 108 } |
| 109 |
| 110 static inline void replaceWithPointer(Instruction *OrigInst, Value *IntPtr, |
| 111 SmallVectorImpl<Instruction*> &Dead) { |
| 112 Instruction *NewInst = |
| 113 new IntToPtrInst(IntPtr, OrigInst->getType(), "", OrigInst); |
| 114 NewInst->takeName(OrigInst); |
| 115 OrigInst->replaceAllUsesWith(NewInst); |
| 116 CopyDebug(NewInst, OrigInst); |
| 117 Dead.push_back(OrigInst); |
| 118 } |
| 119 |
| 120 static inline Instruction *getBBStackPtr(BasicBlock *BB) { |
| 121 return BB->getInstList().begin(); |
| 122 } |
| 123 |
| 124 void ExpandAllocas::runOnFunction(Function &Func) { |
| 125 // Do an initial scan of the entire function body. Check whether it contains |
| 126 // instructions which we want to operate on the untrusted stack and return |
| 127 // if there aren't any. Also check whether it contains any function calls. |
| 128 // If not, we will not have to update the global stack pointer variable. |
| 129 bool NoUntrustedStackOps = true; |
| 130 bool MustUpdateStackPtrGlobal = false; |
| 131 for (Function::iterator BB = Func.begin(), E = Func.end(); BB != E; ++BB) { |
| 132 for (BasicBlock::iterator Inst = BB->begin(), E = BB->end(); Inst != E; |
| 133 ++Inst) { |
| 134 NoUntrustedStackOps &= !isa<AllocaInst>(Inst); |
| 135 if (CallInst *Call = dyn_cast<CallInst>(Inst)) { |
| 136 if (isa<IntrinsicInst>(Call)) { |
| 137 unsigned IntrinsicID = Call->getCalledFunction()->getIntrinsicID(); |
| 138 bool IsNotStackIntr = IntrinsicID != Intrinsic::stacksave && |
| 139 IntrinsicID != Intrinsic::stackrestore; |
| 140 NoUntrustedStackOps &= IsNotStackIntr; |
| 141 MustUpdateStackPtrGlobal |= IsNotStackIntr; |
| 142 } else { |
| 143 MustUpdateStackPtrGlobal = true; |
| 144 } |
| 145 } |
| 146 } |
| 147 } |
| 148 |
| 149 if (NoUntrustedStackOps) |
| 150 return; |
| 151 |
| 152 SmallVector<Instruction *, 10> DeadInsts; |
| 153 Instruction *InitialStackPtr = new LoadInst(StackPtrVar, "frame_top"); |
| 154 |
| 155 // First, we insert a new instruction at the beginning of each basic block, |
| 156 // which will represent the value of the stack pointer at that point. For |
| 157 // the entry block, this is the value of the global stack pointer variable. |
| 158 // Other blocks are initialized with empty phi nodes which we will later |
| 159 // fill with the values carried over from the respective predecessors. |
| 160 BasicBlock *EntryBB = &Func.getEntryBlock(); |
| 161 for (Function::iterator BB = Func.begin(), E = Func.end(); BB != E; ++BB) |
| 162 BB->getInstList().push_front( |
| 163 ((BasicBlock*)BB == EntryBB) ? InitialStackPtr |
| 164 : PHINode::Create(IntPtrType, 2, "")); |
| 165 |
| 166 // Now iterate over the instructions and expand out the untrusted stack |
| 167 // operations. Allocas are replaced with pointer arithmetic that pushes |
| 168 // the untrusted stack pointer and updates the global stack pointer variable |
| 169 // if the initial scan identified function calls in the code. |
| 170 // The @llvm.stacksave intrinsic returns the latest value of the stack |
| 171 // pointer, and the @llvm.stackrestore overwrites it and potentially updates |
| 172 // the global variable. If needed, return instructions are prepended with |
| 173 // a store which restores the initial value of the global variable. |
| 174 // At the end of each basic block, the last value of the untrusted stack |
| 175 // pointer is inserted into the phi node at the beginning of each successor |
| 176 // block. |
| 177 for (Function::iterator BB = Func.begin(), EBB = Func.end(); BB != EBB; |
| 178 ++BB) { |
| 179 Instruction *LastTop = getBBStackPtr(BB); |
| 180 for (BasicBlock::iterator Inst = BB->begin(), EInst = BB->end(); |
| 181 Inst != EInst; ++Inst) { |
| 182 if (AllocaInst *Alloca = dyn_cast<AllocaInst>(Inst)) { |
| 183 Value *SizeOp = Alloca->getArraySize(); |
| 184 unsigned Alignment = Alloca->getAlignment(); |
| 185 assert(Alloca->getType() == I8Ptr); |
| 186 assert(SizeOp->getType()->isIntegerTy(32)); |
| 187 assert(Alignment <= (1 << 29)); // 512MB |
| 188 |
| 189 LastTop = BinaryOperator::CreateSub(LastTop, SizeOp, "", Alloca); |
| 190 if (Alignment > 1) |
| 191 LastTop = BinaryOperator::CreateAnd(LastTop, |
| 192 ConstantInt::get(IntPtrType, |
| 193 -Alignment), |
| 194 "", Alloca); |
| 195 if (MustUpdateStackPtrGlobal) |
| 196 new StoreInst(LastTop, StackPtrVar, Alloca); |
| 197 replaceWithPointer(Alloca, LastTop, DeadInsts); |
| 198 } else if (IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(Inst)) { |
| 199 if (Intr->getIntrinsicID() == Intrinsic::stacksave) { |
| 200 replaceWithPointer(Intr, LastTop, DeadInsts); |
| 201 } else if (Intr->getIntrinsicID() == Intrinsic::stackrestore) { |
| 202 Value *NewStackPtr = Intr->getArgOperand(0); |
| 203 LastTop = new PtrToIntInst(NewStackPtr, IntPtrType, "", Intr); |
| 204 if (MustUpdateStackPtrGlobal) |
| 205 new StoreInst(LastTop, StackPtrVar, Intr); |
| 206 CopyDebug(LastTop, Intr); |
| 207 DeadInsts.push_back(Intr); |
| 208 } |
| 209 } else if (ReturnInst *Return = dyn_cast<ReturnInst>(Inst)) { |
| 210 if (MustUpdateStackPtrGlobal) |
| 211 new StoreInst(InitialStackPtr, StackPtrVar, Return); |
| 212 } |
| 213 } |
| 214 |
| 215 // Insert the final frame top value into all successor phi nodes. |
| 216 TerminatorInst *Term = BB->getTerminator(); |
| 217 for (unsigned int I = 0; I < Term->getNumSuccessors(); ++I) { |
| 218 PHINode *Succ = cast<PHINode>(getBBStackPtr(Term->getSuccessor(I))); |
| 219 Succ->addIncoming(LastTop, BB); |
| 220 } |
| 221 } |
| 222 |
| 223 // Delete the replaced instructions. |
| 224 for (SmallVectorImpl<Instruction *>::const_iterator Inst = DeadInsts.begin(), |
| 225 E = DeadInsts.end(); Inst != E; ++Inst) |
| 226 (*Inst)->eraseFromParent(); |
| 227 } |
| 228 |
| 229 void ExpandAllocas::insertStackPtrInit(Module &M) { |
| 230 Function *EntryFunction = M.getFunction(minsfi::EntryFunctionName); |
| 231 if (!EntryFunction) |
| 232 report_fatal_error("ExpandAllocas: Module does not have an entry function"); |
| 233 |
| 234 // Check the signature of the entry function. |
| 235 Function::ArgumentListType &Args = EntryFunction->getArgumentList(); |
| 236 if (Args.size() != 1 || Args.front().getType() != IntPtrType) { |
| 237 report_fatal_error(std::string("ExpandAllocas: Invalid signature of ") + |
| 238 minsfi::EntryFunctionName); |
| 239 } |
| 240 |
| 241 // Insert a store instruction which saves the value of the first argument |
| 242 // to the stack pointer global variable. |
| 243 new StoreInst(&Args.front(), StackPtrVar, |
| 244 EntryFunction->getEntryBlock().getFirstInsertionPt()); |
| 245 } |
| 246 |
| 247 char ExpandAllocas::ID = 0; |
| 248 INITIALIZE_PASS(ExpandAllocas, "minsfi-expand-allocas", |
| 249 "Expand allocas to allocate memory on an untrusted stack", |
| 250 false, false) |
| 251 |
| 252 ModulePass *llvm::createExpandAllocasPass() { |
| 253 return new ExpandAllocas(); |
| 254 } |
OLD | NEW |