Index: lib/Transforms/MinSFI/AllocateDataSegment.cpp |
diff --git a/lib/Transforms/MinSFI/AllocateDataSegment.cpp b/lib/Transforms/MinSFI/AllocateDataSegment.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8212df0c39024f1338d614c9c356066101ae3279 |
--- /dev/null |
+++ b/lib/Transforms/MinSFI/AllocateDataSegment.cpp |
@@ -0,0 +1,134 @@ |
+//===- AllocateDataSegment.cpp - Create a template for the data segment ---===// |
+// |
+// The LLVM Compiler Infrastructure |
+// |
+// This file is distributed under the University of Illinois Open Source |
+// License. See LICENSE.TXT for details. |
+// |
+//===----------------------------------------------------------------------===// |
+// |
+// Code sandboxed with MinSFI cannot access the memory containing its data |
+// segment directly because it is located outside its address subspace. To |
+// this end, this pass collates all of the global variables in the module |
+// into an exported global struct named "__sfi_data_segment" and a corresponding |
+// global integer holding the overall size. The runtime is expected to link |
+// against these variables and to initialize the memory region of the sandbox |
+// by copying the data segment template into a fixed address inside the region. |
+// |
+// This pass assumes that the base of the memory region of the sandbox is |
+// aligned to at least 2^29 bytes (=512MB), which is the maximum global variable |
+// alignment supported by LLVM. |
+// |
+//===----------------------------------------------------------------------===// |
+ |
+#include "llvm/Pass.h" |
+#include "llvm/IR/Constants.h" |
+#include "llvm/IR/DataLayout.h" |
+#include "llvm/IR/Module.h" |
+#include "llvm/Transforms/MinSFI.h" |
+ |
+using namespace llvm; |
+ |
+static const char ExternalSymName_DataSegment[] = "__sfi_data_segment"; |
+static const char ExternalSymName_DataSegmentSize[] = "__sfi_data_segment_size"; |
+ |
+static const uint32_t DataSegmentBaseAddress = 0x10000; |
+ |
+namespace { |
+class AllocateDataSegment : public ModulePass { |
+ public: |
+ static char ID; |
+ AllocateDataSegment() : ModulePass(ID) { |
+ initializeAllocateDataSegmentPass(*PassRegistry::getPassRegistry()); |
+ } |
+ |
+ virtual bool runOnModule(Module &M); |
+}; |
+} // namespace |
+ |
+static inline uint32_t getPadding(uint32_t Offset, const GlobalVariable *GV, |
+ const DataLayout &DL) { |
+ uint32_t Alignment = DL.getPreferredAlignment(GV); |
+ if (Alignment <= 1) |
+ return 0; |
+ else |
+ return OffsetToAlignment(Offset, Alignment); |
+} |
+ |
+bool AllocateDataSegment::runOnModule(Module &M) { |
+ DataLayout DL(&M); |
+ Type *I8 = Type::getInt8Ty(M.getContext()); |
+ Type *I32 = Type::getInt32Ty(M.getContext()); |
+ Type *IntPtrType = DL.getIntPtrType(M.getContext()); |
+ |
+ // First, we do a pass over the global variables, in which we compute |
+ // the amount of required padding between them and consequently their |
+ // addresses relative to the memory base of the sandbox. References to each |
+ // global are then replaced with direct memory pointers. |
+ uint32_t VarOffset = 0; |
+ DenseMap<GlobalVariable*, uint32_t> VarPadding; |
+ for (Module::global_iterator GV = M.global_begin(), E = M.global_end(); |
+ GV != E; ++GV) { |
+ assert(GV->hasInitializer()); |
+ |
+ uint32_t Padding = getPadding(VarOffset, GV, DL); |
+ VarPadding[GV] = Padding; |
+ VarOffset += Padding; |
+ |
+ GV->replaceAllUsesWith( |
+ ConstantExpr::getIntToPtr( |
+ ConstantInt::get(IntPtrType, |
+ DataSegmentBaseAddress + VarOffset), |
+ GV->getType())); |
+ |
+ VarOffset += DL.getTypeStoreSize(GV->getType()->getPointerElementType()); |
+ } |
+ |
+ // Using the offsets computed above, we prepare the layout and the contents |
+ // of the desired data structure. After the type and initializer of each |
+ // global is copied, the global is not needed any more and it is erased. |
+ SmallVector<Type*, 10> TemplateLayout; |
+ SmallVector<Constant*, 10> TemplateData; |
+ for (Module::global_iterator It = M.global_begin(), E = M.global_end(); |
+ It != E; ) { |
+ GlobalVariable *GV = It++; |
+ |
+ uint32_t Padding = VarPadding[GV]; |
+ if (Padding > 0) { |
+ Type *PaddingType = ArrayType::get(I8, Padding); |
+ TemplateLayout.push_back(PaddingType); |
+ TemplateData.push_back(ConstantAggregateZero::get(PaddingType)); |
+ } |
+ |
+ TemplateLayout.push_back(GV->getType()->getPointerElementType()); |
+ TemplateData.push_back(GV->getInitializer()); |
+ |
+ GV->eraseFromParent(); |
+ } |
+ |
+ // Finally, we create the struct and size global variables. |
+ StructType *TemplateType = |
+ StructType::create(M.getContext(), ExternalSymName_DataSegment); |
+ TemplateType->setBody(TemplateLayout, /*isPacked=*/true); |
+ |
+ Constant *Template = ConstantStruct::get(TemplateType, TemplateData); |
+ new GlobalVariable(M, Template->getType(), /*isConstant=*/true, |
+ GlobalVariable::ExternalLinkage, Template, |
+ ExternalSymName_DataSegment); |
+ |
+ Constant *TemplateSize = |
+ ConstantInt::get(I32, DL.getTypeAllocSize(TemplateType)); |
+ new GlobalVariable(M, TemplateSize->getType(), /*isConstant=*/true, |
+ GlobalVariable::ExternalLinkage, TemplateSize, |
+ ExternalSymName_DataSegmentSize); |
+ |
+ return true; |
+} |
+ |
+char AllocateDataSegment::ID = 0; |
+INITIALIZE_PASS(AllocateDataSegment, "minsfi-allocate-data-segment", |
+ "Create a template for the data segment", false, false) |
+ |
+ModulePass *llvm::createAllocateDataSegmentPass() { |
+ return new AllocateDataSegment(); |
+} |