| 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();
|
| +}
|
|
|