diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 68f0841c51bddbf8637506bdc4e41af65f3cf6d0..6797519796abec10af0c0a7174b1c65e8050f1a9 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1742,6 +1742,20 @@ def NoUniqueAddress : InheritableAttr, TargetSpecificAttr { let SimpleHandler = 1; } +def PacDataTag : InheritableAttr { + let Spellings = [GCC<"pac_protected_data">]; + let Subjects = SubjectList<[Field], ErrorDiag>; + let Documentation = [PacDataTagDocs]; + let SimpleHandler = 1; +} + +def PacPtrTag : InheritableAttr { + let Spellings = [GCC<"pac_protected_ptr">]; + let Subjects = SubjectList<[Field], ErrorDiag>; + let Documentation = [PacPtrTagDocs]; + let SimpleHandler = 1; +} + def ReturnsTwice : InheritableAttr { let Spellings = [GCC<"returns_twice">]; let Subjects = SubjectList<[Function]>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 5c84e2fc5b77d1a20831f977b7b779bdb19017ee..caad49026d28595f5efca6d2469407d5f26c0005 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -1355,6 +1355,20 @@ in C++11 onwards. }]; } +def PacDataTagDocs : Documentation { + let Category = DocCatField; + let Content = [{ +The ``pac_protected_data`` attribute asks the compiler to protect the struct field with PA + }]; +} + +def PacPtrTagDocs : Documentation { + let Category = DocCatField; + let Content = [{ +The ``pac_protected_ptr`` attribute asks the compiler to protect the struct pointer type field with PA + }]; +} + def ObjCRequiresSuperDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/include/clang/Pac/PacDfi.h b/clang/include/clang/Pac/PacDfi.h new file mode 100644 index 0000000000000000000000000000000000000000..c2c73a8390cbe7aebd2d8700d6c587f79af9ff97 --- /dev/null +++ b/clang/include/clang/Pac/PacDfi.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Zaheer Gauhar +// Gilang Mentari Hamidy +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef PAC_DFI_H +#define PAC_DFI_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Decl.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Module.h" +using namespace clang; + +void PacDfiParseStruct(RecordDecl *TagDecl, ASTContext &Ctx); +void PacDfiEmitStructFieldsMetadata(llvm::module &M, llvm::LLVMContext &VMContext); +void PacDfiRecordDecl2StructName(const RecordDecl *RD, llvm::StructType *Entry); + +#endif + diff --git a/clang/lib/CMakeLists.txt b/clang/lib/CMakeLists.txt index 1526d65795f8adfe258f15e8ac75d4903dd48f67..f69bff2588e7382ff2fbaecf81677f75a8b1aac6 100644 --- a/clang/lib/CMakeLists.txt +++ b/clang/lib/CMakeLists.txt @@ -30,3 +30,4 @@ if(CLANG_INCLUDE_TESTS) endif() add_subdirectory(Interpreter) add_subdirectory(Support) +add_subdirectory(Pac) diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt index 0bb5abcf60455b08b9cb845ec14ecc41a2e7c06a..7dbf0c8f8d256dfaaf5d77c3b0be8e2323373d7c 100644 --- a/clang/lib/CodeGen/CMakeLists.txt +++ b/clang/lib/CodeGen/CMakeLists.txt @@ -96,4 +96,5 @@ add_clang_library(clangCodeGen clangFrontend clangLex clangSerialization + pacDfi ) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index c67643c43a7d1d13591bb3ea8c47711bab317b47..7e60c49ad585e23acba6745967a625e2df778381 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -47,6 +47,7 @@ #include "clang/CodeGen/BackendUtil.h" #include "clang/CodeGen/ConstantInitBuilder.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Pac/PacDfi.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/Analysis/TargetLibraryInfo.h" @@ -835,6 +836,7 @@ void CodeGenModule::Release() { if (getLangOpts().OpenMPIsDevice) getModule().addModuleFlag(llvm::Module::Max, "openmp-device", LangOpts.OpenMP); + PacDfiEmitStructFieldMetadata(getModule(), VMContext); // Emit OpenCL specific module metadata: OpenCL/SPIR version. if (LangOpts.OpenCL || (LangOpts.CUDAIsDevice && getTriple().isSPIRV())) { diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index fcce424747f1c3245c5b8d7e269b65f7e27771ea..31ad6e33cddd69113f29c068e3401242a3cec743 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -22,6 +22,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" #include "clang/CodeGen/CGFunctionInfo.h" +#include "clang/Pac/PacDfi.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Module.h" @@ -852,6 +853,7 @@ llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) { if (!Entry) { Entry = llvm::StructType::create(getLLVMContext()); addRecordTypeName(RD, Entry, ""); + PacDfiRecordDecl2StructName(RD, Entry); } llvm::StructType *Ty = Entry; diff --git a/clang/lib/Pac/CMakeLists.txt b/clang/lib/Pac/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..9241a8c85448bb4a3fc707231be94d6176eba080 --- /dev/null +++ b/clang/lib/Pac/CMakeLists.txt @@ -0,0 +1,6 @@ +add_clang_library(pacDfi + PacDfi.cpp + + LINK_LIBS + Parts +) \ No newline at end of file diff --git a/clang/lib/Pac/PacDfi.cpp b/clang/lib/Pac/PacDfi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0f89cb84a240746033b11016b3448bb75f5b89b9 --- /dev/null +++ b/clang/lib/Pac/PacDfi.cpp @@ -0,0 +1,106 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Zaheer Gauhar +// Gilang Mentari Hamidy +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Constants.h" +#include "llvm/PARTS/Parts.h" +#include "clang/Basic/AttributeCommonInfo.h" +#include "clang/Basic/Attributes.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/Pac/PacDfi.h" + +using namespace clang; + +std::map RecordDecl2StructName; +std::map> PacFieldInfos; +std::map> PacPtrInfos; + +void PacDfiParseStruct(RecordDecl *TagDecl, ASTContext &Ctx) +{ + if (!llvm::PARTS::useDataFieldTag()) { + return; + } + // find pac_tag attr fields, and insert new fields + std::vector PacFieldIdxs; + std::vector PacPtrIdxs; + unsigned int FieldIdx = 0; + unsigned int ArraySize = 0; + + for (auto Field : TagDecl->fields()) { + if (Field->hasAttr()) { + PacFieldIdxs.push_back(FieldIdx); + if (Field->getType()->isConstantArrayType()) { + auto ArrayTy = dyn_cast(Field->getType()); + ArraySize += ArrayTy->getSize().getZExtValue(); + } else { + ++ArraySize; + } + } else if (Field->hasAttr()) { + PacPtrIdxs.push_back(FieldIdx); + } + ++FieldIdx; + } + + if (!PacFieldIdxs.empty()) { + llvm::APInt ArraySizeInt(32, ArraySize); + auto ArrayTy = Ctx.getConstantArrayType(Ctx.IntTy, ArraySizeInt, nullptr, ArrayType::Normal, + /*IndexTypeQuals=*/ 0); + FieldDecl *PacFD = FieldDecl::Create(Ctx, TagDecl, SourceLocation(), SourceLocation(), nullptr, + ArrayTy, nullptr, nullptr, true, ICIS_NoInit); + + TagDecl->addDecl(PacFD); + PacFieldInfos.insert(std::make_pair(TagDecl, PacFieldIdxs)); + } + if (!PacPtrIdxs.empty()) { + PacPtrInfos.insert(std::make_pair(TagDecl, PacPtrIdxs)); + } +} + +void PacDfiCreateMetaData(std::map> &fieldInfos, StringRef mdName, + llvm::Module &M, llvm::LLVMContext &VMContext) +{ + llvm::NamedMDNode *PacNMD = M.getOrInsertNamedMetadata(mdName); + for (auto item : fieldInfos) { + std::vector PacFields; + auto styName = RecordDecl2StructName.find(item.first)->second; + PacFields.push_back(llvm::MDString::get(VMContext, styName)); + for (auto idx : item.second) { + PacFields.push_back(llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), idx))); + } + PacNMD->addOperand(llvm::MDNode::get(VMContext, PacFields)); + } +} + +void PacDfiEmitStructFieldsMetadata(llvm::module &M, llvm::LLVMContext &VMContext) +{ + if (!llvm::PARTS::useDataFieldTag()) { + return; + } + // emit struct fields that need to protect with PA + if (!PacFieldInfos.empty()) { + PacDfiCreateMetaData(PacFieldInfos, "pa_field_info", M, VMContext); + } + if (!PacPtrInfos.empty()) { + PacDfiCreateMetaData(PacPtrInfos, "pa_ptr_field_info", M, VMContext); + } +} + +void PacDfiRecordDecl2StructName(const RecordDecl *RD, llvm::StructType *Entry) +{ + if (!llvm::PARTS::useDataFieldTag()) { + return; + } + RecordDecl2StructName.insert(std::make_pair(RD, Entry->getName())); +} \ No newline at end of file diff --git a/clang/lib/Parse/CMakeLists.txt b/clang/lib/Parse/CMakeLists.txt index 7e90b37386f9e64b2b36c84c68f0093204e37840..76ca0ac97b0f9c6f87cf37f28537809a9442f02f 100644 --- a/clang/lib/Parse/CMakeLists.txt +++ b/clang/lib/Parse/CMakeLists.txt @@ -28,6 +28,7 @@ add_clang_library(clangParse clangBasic clangLex clangSema + pacDfi DEPENDS omp_gen diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index aef9909a7c971e867a75ddbff29f9e0c7e572341..e983d65951bcd7c743104cc4ee4c4b9324addb94 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -25,6 +25,7 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaDiagnostic.h" +#include "clang/Pac/PacDfi.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" @@ -4529,6 +4530,9 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, TryConsumeToken(tok::semi); } + // find pac_tag attr fields, and insert new fields + PacDfiParseStruct(TagDecl, Actions.getASTContext()); + T.consumeClose(); ParsedAttributes attrs(AttrFactory); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 838fd48357fb71fdc2625a8e22bf59c572a07158..5487b8f25004c17a486e729eb27e039bc51807cd 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -9093,6 +9093,14 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_UsingIfExists: handleSimpleAttribute(S, D, AL); break; + + case ParsedAttr::AT_PacDataTag: + handleSimpleAttribute(S, D, AL); + break; + + case ParsedAttr::AT_PacPtrTag: + handleSimpleAttribute(S, D, AL); + break; } } diff --git a/llvm/include/llvm/IR/IntrinsicsAArch64.td b/llvm/include/llvm/IR/IntrinsicsAArch64.td index fc66bdfc35e04f13e59a37972504166b79edced4..235c35f92cc088cd14f7bfca135a91aee35b97ec 100644 --- a/llvm/include/llvm/IR/IntrinsicsAArch64.td +++ b/llvm/include/llvm/IR/IntrinsicsAArch64.td @@ -848,7 +848,7 @@ def int_aarch64_crc32x : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llv def int_aarch64_crc32cx : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i64_ty], [IntrNoMem]>; } - +include "llvm/PARTS/Intrinsics.td" //===----------------------------------------------------------------------===// // Memory Tagging Extensions (MTE) Intrinsics let TargetPrefix = "aarch64" in { diff --git a/llvm/include/llvm/PARTS/AArch64InstInfo.td b/llvm/include/llvm/PARTS/AArch64InstInfo.td new file mode 100644 index 0000000000000000000000000000000000000000..62c8ad6ea154d08508ffc74f337304352c2b08da --- /dev/null +++ b/llvm/include/llvm/PARTS/AArch64InstInfo.td @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let isPseudo = 1, hasNoSchedulingInfo = 1 in { + def PARTS_PACIA : Pseudo<(outs GPR64:$dst), + (ins GPR64:$ptr, GPR64sp:$mod), + [(set i64:$dst, (int_pa_pacia GPR64:$ptr, GPR64sp:$mod))], + "$dst = $ptr">; + def PARTS_AUTIA : Pseudo<(outs GPR64:$dst), + (ins GPR64:$ptr, GPR64sp:$mod), + [(set i64:$dst, (int_pa_autia GPR64:$ptr, GPR64sp:$mod))], + "$dst = $ptr">; + def PARTS_AUTCALL : Pseudo<(outs GPR64:$dst), + (ins GPR64:$ptr, GPR64sp:$mod), + [(set i64:$dst, (int_pa_autcall GPR64:$ptr, GPR64sp:$mod))], + "$dst = $ptr">; +} + +let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [SP] in { + def TCRETURNriAA : Pseudo<(outs), (ins tcGPR64:$dst, i32imm:$FPDiff, GPR64sp:$mod), []>, + Sched<[WriteBrReg]>; +} diff --git a/llvm/include/llvm/PARTS/Intrinsics.td b/llvm/include/llvm/PARTS/Intrinsics.td new file mode 100644 index 0000000000000000000000000000000000000000..7c780d5af2ef830d308c3289299b7f7b0d2904b0 --- /dev/null +++ b/llvm/include/llvm/PARTS/Intrinsics.td @@ -0,0 +1,13 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +def int_pa_pacia : intrinsic<[llvm_anyptr_ty], [LLVMMatchType<0>, llvm_i64_ty], [IntrNoMem]>; +def int_pa_autia : intrinsic<[llvm_anyptr_ty], [LLVMMatchType<0>, llvm_i64_ty], [IntrNoMem]>; +def int_pa_autcall : intrinsic<[llvm_anyptr_ty], [LLVMMatchType<0>, llvm_i64_ty], [IntrNoMem], "", [SDNPOutGlue]>; diff --git a/llvm/include/llvm/PARTS/Parts.h b/llvm/include/llvm/PARTS/Parts.h new file mode 100644 index 0000000000000000000000000000000000000000..c553be38f246f2a953d950d0630e401f3793e4a1 --- /dev/null +++ b/llvm/include/llvm/PARTS/Parts.h @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PARTS_H +#define LLVM_PARTS_H + +#include "llvm/IR/Constant.h" +#include "llvm/IR/Type.h" +#include "llvm/Pass.h" + +namespace llvm { +namespace PARTS { + +enum PartsBeCfiType { + PartsBeCfiNone, + PartsBeCfiFull, + PartsBeCfiNgFull +}; + +enum PartsDpiType { + PartsDpiNone, + PartsDpiFull, + PartsDpiFullNoType +}; + +bool useBeCfi(); +bool useFeCfi(); +bool useDataPointerProtection(); +bool useDataFieldTag(); +bool useDataFieldProtection(); +PartsBeCfiType getBeCfiType(); +Pass *createPartsPluginPass(); + +} +} +#endif \ No newline at end of file diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt index 5ecdf5af956a31a5b75f8645624ce81a1fba9f3a..476024239441627de183c9128f8e13747016904f 100644 --- a/llvm/lib/CMakeLists.txt +++ b/llvm/lib/CMakeLists.txt @@ -43,6 +43,7 @@ if (LLVM_INCLUDE_TESTS) endif() add_subdirectory(WindowsDriver) add_subdirectory(WindowsManifest) +add_subdirectory(PARTS) set(LLVMCONFIGLIBRARYDEPENDENCIESINC "${LLVM_BINARY_DIR}/tools/llvm-config/LibraryDependencies.inc") diff --git a/llvm/lib/PARTS/CMakeLists.txt b/llvm/lib/PARTS/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..196de8467f3e1952d880b15e21900a539c8bb24d --- /dev/null +++ b/llvm/lib/PARTS/CMakeLists.txt @@ -0,0 +1,23 @@ +add_llvm_component_library(Parts + Parts.cpp + PartsPluginPass.cpp + + ADDITIONAL_HEADER_DIRS + ${LLVM_MAIN_INCLUDE_DIR}/llvm/PARTS + ${LLVM_MAIN_INCLUDE_DIR}/llvm/Support + ${LLVM_MAIN_INCLUDE_DIR}/llvm/IR + + DEPENDS + intrinsics_gen + LLVMCore + LLVMSupport + LLVMTransformUtils + LLVMCodeGen + + LINK_LIBS + LLVMCore + LLVMSupport + LLVMTransformUtils + LLVMCodeGen + ) +set_property(TARGET Parts PROPERTY LLVM_SYSTEM_LIBS) \ No newline at end of file diff --git a/llvm/lib/PARTS/Parts.cpp b/llvm/lib/PARTS/Parts.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1f0a5cde24b0ecbf07512edf6676ce83c72423cb --- /dev/null +++ b/llvm/lib/PARTS/Parts.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#include "llvm/PARTS/Parts.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/CommandLine.h" + +using namespace llvm; +using namespace PARTS; + +static cl::opt EnableFeCfi( + "FECFI", cl::Hidden, + cl::desc("forward-edge CFI"), + cl::init(false)); + +static cl::opt EnableBeCfi( + "FGBECFI", cl::Hidden, + cl::desc("backward-edge CFI"), + cl::init(false)); + +static cl::opt EnableDfiDpTag( + "DFIDPTAG", cl::Hidden, + cl::desc("Data field DFI identify by tag"), + cl::init(false)); + +static cl::opt EnableDfiDppTag( + "DFIDPPTAG", cl::Hidden, + cl::desc("Data pointer DFI identify by tag"), + cl::init(false)); + +static cl::opt EnableDfiDpp( + "DFIDPP", cl::Hidden, + cl::desc("Data pointer DFI identify by config"), + cl::init(false)); + +bool llvm::PARTS::useFeCfi() { + return EnableFeCfi; +} + +bool llvm::PARTS::useBeCfi() { + return EnableBeCfi; +} + +bool llvm::PARTS::useDataPointerProtection() { + return EnableDfiDpp || EnableDfiDppTag; +} + +bool llvm::PARTS::useDataFieldTag() { + return EnableDfiDpTag || EnableDfiDppTag; +} + +bool llvm::PARTS::useDataFieldProtection() { + return EnableDfiDpTag; +} + +PartsBeCfiType PARTS::getBeCfiType() { + if (EnableBeCfi) { + return PartsBeCfiFull; + } + return PartsBeCfiNone; +} \ No newline at end of file diff --git a/llvm/lib/PARTS/PartsPluginPass.cpp b/llvm/lib/PARTS/PartsPluginPass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..97319040e10d9e0c75cad142af994ca66e91c9cf --- /dev/null +++ b/llvm/lib/PARTS/PartsPluginPass.cpp @@ -0,0 +1,106 @@ +//===----------------------------------------------------------------------===// +// +// Author: Zaheer Gauhar +// Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "llvm/IR/AbstractCallSite.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/Pass.h" +#include "llvm/PARTS/Parts.h" +#include "llvm/Support/Debug.h" +#include "llvm/IR/Attributes.h" + +using namespace llvm; +using namespace llvm::PARTS; + +#define DEBUG_TYPE "PartsPluginPass" + +namespace { + +class PartsPluginPass : public ModulePass { +public: + static char ID; + PartsPluginPass() : ModulePass(ID) {} + bool runOnModule(Module &M) override; + +private: + /* + Check the input Value V and recursively change inner parameters, or if V itself needs to be replaced + in the containint function, then uses give builder to generate PACed value and returns said value. + @param M + @param I + @param V + @return + */ + bool handleInstruction(Function &F, Instruction &I); + CallInst *handleAutCallInstruction(Function &F, Instruction &I, Value *value); +}; + +} + +char PartsPluginPass::ID = 0; +static RegisterPass X("parts-plugin", "PARTS Plugin pass"); + +Pass *llvm::PARTS::createPartsPluginPass() { return new PartsPluginPass(); } + +bool PartsPluginPass::runOnModule(Module &M) { + if (!PARTS::useFeCfi()) + return false; + + bool modified = false; + for (auto &F : M) { + for (auto &BB: F) { + for (auto &I: BB) { + modified = handleInstruction(F, I) || modified; + } + } + } + return modified; +} + +bool PartsPluginPass::handleInstruction(Function &F, Instruction &I) { + auto CI = dyn_cast(&I); + if (!CI || CI->isInlineAsm()) { + return false; + } + auto calledValue = CI->getCalledOperand(); + IntrinsicInst *II = dyn_cast(calledValue); + if (II && II->getIntrinsicID() == Intrinsic::pa_autcall) { + Value *paced = nullptr; + paced = handleAutCallInstruction(F, I, calledValue); + if (paced) { + CI->setCalledOperand(paced); + } + } + return false; +} + +CallInst *PartsPluginPass::handleAutCallInstruction(Function &F, Instruction &I, Value *value) { + Instruction *Insn = dyn_cast(value); + auto *Call_BB = I.getParent(); + auto *Insn_BB = Insn->getParent(); + + if (Call_BB == Insn_BB) { + return nullptr; + } + + auto calledValue = Insn->getOperand(0); + const auto calledValueType = calledValue->getType(); + IRBuilder<> Builder(&I); + auto autcall = Intrinsic::getDeclaration(F.getParent(), Intrinsic::pa_autcall, { calledValueType}); + auto typeIdConstant = Insn->getOperand(1); + CallInst *paced = Builder.CreateCall(autcall, { calledValue, typeIdConstant }, ""); + return paced; + } \ No newline at end of file diff --git a/llvm/lib/Target/AArch64/AArch64.h b/llvm/lib/Target/AArch64/AArch64.h index a6065d4ed9ec3c447d6ddefea86d876e185c8ead..33917b444d76de2eaf13905d7fc5486b5ae7329a 100644 --- a/llvm/lib/Target/AArch64/AArch64.h +++ b/llvm/lib/Target/AArch64/AArch64.h @@ -68,6 +68,8 @@ FunctionPass *createAArch64PostLegalizerLowering(); FunctionPass *createAArch64PostSelectOptimize(); FunctionPass *createAArch64StackTaggingPass(bool IsOptNone); FunctionPass *createAArch64StackTaggingPreRAPass(); +FunctionPass *createAArch64EarlyPartsCpiPass(); +FunctionPass *createAArch64PartsCpiPass(); void initializeAArch64A53Fix835769Pass(PassRegistry&); void initializeAArch64A57FPLoadBalancingPass(PassRegistry&); diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index 8ed54a6703cf0110566bd4abd773557b86871ace..552daedc0555357fcd13e91f34f2ded5cb39f7bb 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -579,7 +579,7 @@ void AArch64AsmPrinter::emitEndOfAsmFile(Module &M) { // generates code that does this, it is always safe to set. OutStreamer->emitAssemblerFlag(MCAF_SubsectionsViaSymbols); } - + // Emit stack and fault map information. emitStackMaps(SM); FM.serializeToFaultMapSection(); @@ -1310,6 +1310,14 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { EmitToStreamer(*OutStreamer, TmpInst); return; } + case AArch64::TCRETURNriAA: { + MCInst TmpInst; + TmpInst.setOpcode(AArch64::BRAA); + TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); + TmpInst.addOperand(MCOperand::createReg(MI->getOperand(2).getReg())); + EmitToStreamer(*OutStreamer, TmpInst); + return; + } case AArch64::TCRETURNdi: { MCOperand Dest; MCInstLowering.lowerOperand(MI->getOperand(0), Dest); diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp index a7a1c969faf5e7d11c7d27b3bf639ff1d840e27f..53ad04b31929e6ef65efb82d44fff0f1dda16b80 100644 --- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -192,6 +192,7 @@ #include "AArch64StackProtectorRetLowering.h" #include "AArch64Subtarget.h" #include "AArch64TargetMachine.h" +#include "AArch64PARTS/PartsFrameLowering.h" #include "MCTargetDesc/AArch64AddressingModes.h" #include "MCTargetDesc/AArch64MCTargetDesc.h" #include "llvm/ADT/ScopeExit.h" @@ -274,6 +275,7 @@ static int64_t getArgumentStackToRestore(MachineFunction &MF, unsigned RetOpcode = MBBI->getOpcode(); IsTailCallReturn = RetOpcode == AArch64::TCRETURNdi || RetOpcode == AArch64::TCRETURNri || + RetOpcode == AArch64::TCRETURNriAA || RetOpcode == AArch64::TCRETURNriBTI; } AArch64FunctionInfo *AFI = MF.getInfo(); @@ -1429,6 +1431,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF, .setMIFlags(MachineInstr::FrameSetup); } } + PartsFrameLowering::instrumentPrologue(TII, Subtarget.getRegisterInfo(), MBB, MBBI, DebugLoc()); if (EmitCFI && MFnI.isMTETagged()) { BuildMI(MBB, MBBI, DL, TII->get(AArch64::EMITMTETAGGED)) .setMIFlag(MachineInstr::FrameSetup); @@ -1914,6 +1917,7 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF, auto FinishingTouches = make_scope_exit([&]() { InsertReturnAddressAuth(MF, MBB); + PartsFrameLowering::instrumentEpilogue(TII, Subtarget.getRegisterInfo(), MBB); if (needsShadowCallStackPrologueEpilogue(MF)) emitShadowCallStackEpilogue(*TII, MF, MBB, MBB.getFirstTerminator(), DL); if (EmitCFI) diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td index e70d304f37b92f25a5f653bc8ca4e8287bbe8c4b..aabbf50799761eb79e07e07c86a901c690112a9c 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td +++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td @@ -1747,7 +1747,7 @@ class RCPCLoad sz, string asm, RegisterClass RC> class AuthBase M, dag oops, dag iops, string asm, string operands, list pattern> - : I, Sched<[]> { + : I, Sched<[WriteBrReg]> { let isAuthenticated = 1; let Inst{31-25} = 0b1101011; let Inst{20-11} = 0b1111100001; diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 4976f51b82e16cee9784bab0ad4882be7ab283d6..772b787e4aca6c58de0ceaad2c4d776d33f8f9b5 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -8413,3 +8413,4 @@ include "AArch64InstrAtomics.td" include "AArch64SVEInstrInfo.td" include "AArch64SMEInstrInfo.td" include "AArch64InstrGISel.td" +include "llvm/PARTS/AArch64InstInfo.td" \ No newline at end of file diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h index f070f989a5b7d1504df40ac01963b05b3940880e..987be8a8a06699312e0cbb92ba71ecf7f1269ddd 100644 --- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h +++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h @@ -186,7 +186,9 @@ class AArch64FunctionInfo final : public MachineFunctionInfo { /// True if the function need asynchronous unwind information. mutable Optional NeedsAsyncDwarfUnwindInfo; - + /// Temporary symbol used by PARTS to generate a runtime dependent modifier based on + /// the position of function. Epilogue emission relys on this value beging set. + MCSymbol *PartsSym = nullptr; public: explicit AArch64FunctionInfo(MachineFunction &MF); @@ -433,7 +435,8 @@ public: bool needsDwarfUnwindInfo() const; bool needsAsyncDwarfUnwindInfo() const; - + void setPartsSym(MCSymbol *Sym) { PartsSym = Sym; } + MCSymbol *getPartsSym() const { return PartsSym; } private: // Hold the lists of LOHs. MILOHContainer LOHContainerSet; diff --git a/llvm/lib/Target/AArch64/AArch64PARTS/AArch64EarlyPartsCpiPass.cpp b/llvm/lib/Target/AArch64/AArch64PARTS/AArch64EarlyPartsCpiPass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2cb5449d4986b217c0b706f9ceee317c757938f5 --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64PARTS/AArch64EarlyPartsCpiPass.cpp @@ -0,0 +1,178 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AArch64.h" +#include "AArch64Subtarget.h" +#include "AArch64RegisterInfo.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/PARTS/Parts.h" + +#define DEBUG_TYPE "AArch64EarlyPartsCpiPass" + +STATISTIC(StatAutcall, DEBUG_TYPE ": inserted authenticate and branch instructions"); + +using namespace llvm; +using namespace llvm::PARTS; + +namespace { + +class AArch64EarlyPartsCpiPass : public MachineFunctionPass { +public: + static char ID; + AArch64EarlyPartsCpiPass() : MachineFunctionPass(ID) {} + StringRef getPassName() const override { return DEBUG_TYPE; } + virtual bool doInitialization(Module &M) override; + bool runOnMachineFunction(MachineFunction &) override; +private: + const AArch64Subtarget *STI = nullptr; + const AArch64InstrInfo *TII = nullptr; + inline bool handleInstruction(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::instr_iterator &MIi); + inline MachineInstr *findIndirectCallMachineInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineInstr *MIptr); + void triggerCompilationErrorOrphanAUTCALL(MachineBasicBlock &MBB); + inline bool isIndirectCall(const MachineInstr &MI) const; + inline bool isPartsAUTCALLIntrinsic(unsigned Opcode); + inline const MCInstrDesc &getIndirectCallAuth(MachineInstr *MI_indcall); + inline void replaceBranchByAuthenticatedBranch(MachineBasicBlock &MBB, MachineInstr *MI_indcall, MachineInstr &MI); + inline void insertCOPYInstr(MachineBasicBlock &MBB, MachineInstr *MI_indcall, MachineInstr &MI); +}; +} + +FunctionPass *llvm::createAArch64EarlyPartsCpiPass() { + return new AArch64EarlyPartsCpiPass(); +} + +char AArch64EarlyPartsCpiPass::ID = 0; +bool AArch64EarlyPartsCpiPass::doInitialization(Module &M) { + return true; +} + +bool AArch64EarlyPartsCpiPass::runOnMachineFunction(MachineFunction &MF) { + bool found = false; + STI = &MF.getSubtarget(); + TII = STI->getInstrInfo(); + + for (auto &MBB : MF) { + for (auto MIi = MBB.instr_begin(), MIie = MBB.instr_end(); MIi != MIiE; ++MIi) { + found= handleInstruction(MF, MBB, MIi) || found; + } + } + return found; +} + +/** +* @param MF +* @param MBB +* @param MIi +* @return return true when changing something, otherwise false +**/ +inline bool AArch64EarlyPartsCpiPass::handleInstruction(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::instr_iterator &MIi) { + const auto MIOpcode = MIi->getOpcode(); + if (!isPartsAUTCALLIntrinsic(MIOpcode)) { + return false; + } + auto MIptr = &*MIi; + MachineInstr *MI_indcall = findIndirectCallMachineInstr(MF, MBB, MIptr); + if (MI_indcall == nullptr) { + outs() << "MI_indcall is NULL!!!\n"; + triggerCompilationErrorOrphanAUTCALL(MBB); + } + auto &MI = *MIi--; + replaceBranchByAuthenticatedBranch(MBB, MI_indcall, MI); + ++StatAutcall; + return true; +} + +inline bool AArch64EarlyPartsCpiPass::isPartsAUTCALLIntrinsic(unsigned Opcode) { + switch (Opcode) { + case AArch64::PARTS_AUTCALL: + return true; + } + return false; +} + +inline const MCInstrDesc& AArch64EarlyPartsCpiPass::getIndirectCallAuth(MachineInstr *MI_indcall) { + if (MI_indcall->getOpcode() == AArch64::BLR) { + return TII->get(AArch64::BLRAA); + } + // This is a tail call return, and we need to use BRAA + // (tail-call: ~optimation where a tail-call is coverted to a direct call so that + // the tail-called function can return immediately to the current callee, without + // going through the currently active function.) + + return TII->get(AArch64::TCRETURNriAA); +} + +inline MachineInstr* AArch64EarlyPartsCpiPass::findIndirectCallMachineInstr(MachineFunction &MF, + MachineBasicBlock &MBB, MachineInstr *MIptr) { + unsigned AUTCALLinstr_oper0 = MIptr->getOperand(0).getReg(); + unsigned BLRinstr_oper0 = 0; + for (auto &MBB: MF) { + for (auto MIi = MBB.instr_begin(), MIie = MBB.instr_end(); MIi != MIie; ++MIi) { + if (&*MIi != nullptr && isIndirectCall(*MIi)) { + BLRinstr_oper0 = MIi->getOperand(0).getReg(); + if (AUTCALLinstr_oper0 == BLRinstr_oper0) { + return &*MIi; + } + } + } + } + return nullptr; +} + +inline bool AArch64EarlyPartsCpiPass::isIndirectCall(const MachineInstr &MI) const { + switch(MI.getOpcode()) { + case AArch64::BLR: // Normal indirect call + case AArch64::TCRETURNri: // Indirect tail call + return true; + } + return false; +} + +void AArch64EarlyPartsCpiPass::triggerCompilationErrorOrphanAUTCALL(MachineBasicBlock &MBB) { + LLVM_DEBUG(MBB.dump()); + llvm_unreachable("failed to find BLR for AUTCALL"); +} + +inline void AArch64EarlyPartsCpiPass::replaceBranchByAuthenticatedBranch(MachineBasicBlock &MBB, + MachineInstr *MI_indcall, MachineInstr &MI) { + auto modOperand = MI.getOperand(2); + insertCOPYInstr(MBB, MI_indcall, MI); + auto BMI = BuildMI(MBB, *MI_indcall, MI_indcall->getDebugLoc(), getIndirectCallAuth(MI_indcall)); + BMI.addUse(MI_indcall->getOperand(0).getReg()); + if (MI_indcall->getOpcode() == AArch64::TCRETURNri) { + BMI.add(MI_indcall->getOperand(1)); // Copy FPDiff from original tail call pseudo instrution + } + BMI.add(modOperand); + BMI.copyImplicitOps(*MI_indcall); + + MI_indcall->removeFromParent(); + MI.removeFromParent(); +} +inline void AArch64EarlyPartsCpiPass::insertCOPYInstr(MachineBasicBlock &MBB, MachineInstr *MI_indcall, + MachineInstr &MI) { + auto dstOperand = MI.getOperand(0); + auto srcOperand = MI.getOperand(1); + + auto COPYMI = BuildMI(MBB, *MI_indcall, MI_indcall->getDebugLoc(), TII->get(AArch64::COPY)); + COPYMI.add(dstOperand); + COPYMI.add(srcOperand); +} \ No newline at end of file diff --git a/llvm/lib/Target/AArch64/AArch64PARTS/AArch64PartsCpiPass.cpp b/llvm/lib/Target/AArch64/AArch64PARTS/AArch64PartsCpiPass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3b8033775f6add0e8eae890cdb08245a495f47c6 --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64PARTS/AArch64PartsCpiPass.cpp @@ -0,0 +1,142 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include +#include "AArch64.h" +#include "AArch64Subtarget.h" +#include "AArch64RegisterInfo.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/PARTS/Parts.h" + +#define DEBUG_TYPE "AArch64PartsCpiPass" + +STATISTIC(StatAutia, DEBUG_TYPE ": code pointers authenticated and unPACed"); +STATISTIC(StatPacia, DEBUG_TYPE ": code pointers signed"); + +using namespace llvm; +using namespace llvm::PARTS; + +namespace { +class AArch64PartsCpiPass : public MachineFunctionPass { +public: + static char ID; + AArch64PartsCpiPass() : MachineFunctionPass(ID) {} + StringRef getPassName() const override {return DEBUG_TYPE; } + bool doInitialization(Module &M) override; + bool runOnMachineFunction(MachineFunction &) override; +private: + const AArch64InstrInfo *TII = nullptr; + void lowerPARTSAUTCALL(MachineBasicBlock &MBB, MachineInstr &MI); + void lowerPARTSPACIA(MachineBasicBlock &MBB, MachineInstr &MI); + + inline bool handleInstruction(MachineBasicBlock &MBB, MachineBasicBlock::instr_iterator &MIi); + inline void lowerPARTSAUTIA(MachineBasicBlock &MBB, MachineInstr &MI); + void lowerPARTSIntrinsicCommon(MachineBasicBlock &MBB, MachineInstr &MI, const MCInstrDesc &InstrDesc); + inline bool isPartsIntrinsic(unsigned Opcode); +}; + +} + +FunctionPass *llvm::createAArch64PartsCpiPass() { + return new AArch64PartsCpiPass(); +} + +char AArch64PartsCpiPass::ID = 0; + +bool AArch64PartsCpiPass::doInitialization(Module &M) { + return true; +} + +bool AArch64PartsCpiPass::runOnMachineFunction(MachineFunction &MF) { + bool found = false; + TII = MF.getSubtarget().getInstrInfo(); + + for (auto &MBB : MF) { + for (auto MIi = MBB.instr_begin(), MIie = MBB.instr_end(); MIi != MIie; ++ MIi) { + found = handleInstruction(MBB, MIi) || found; + } + } + return found; +} + +/** +* @param MBB +* @param MIi +* @return return true when changing something, otherwise false +**/ +inline bool AArch64PartsCpiPass::handleInstruction(MachineBasicBlock &MBB, MachineBasicBlock::instr_iterator &MIi) { + const auto MIOpcode = MIi->getOpcode(); + if (!isPartsIntrinsic(MIOpcode)) + return false; + + auto &MI = *MIi--; + switch (MIOpcode) { + default: + llvm_unreachable("Unhandled PARTS intrinsic!!"); + case AArch64::PARTS_PACIA: + lowerPARTSPACIA(MBB, MI); + break; + case AArch64::PARTS_AUTIA: + lowerPARTSAUTIA(MBB, MI); + break; + case AArch64::PARTS_AUTCALL: + lowerPARTSAUTCALL(MBB, MI); + break; + } + MI.removeFromParent(); // Remove the PARTS intrinsic! + return true; +} + +inline bool AArch64PartsCpiPass::isPartsIntrinsic(unsigned Opcode) { + switch (Opcode) { + case AArch64::PARTS_PACIA: + case AArch64::PARTS_AUTIA: + case AArch64::PARTS_AUTCALL: + return true; + } + return false; +} + +void AArch64PartsCpiPass::lowerPARTSPACIA(MachineBasicBlock &MBB, MachieInstr &MI) { + lowerPARTSIntrinsicCommon(MBB, MI, TII->get(AArch64::PACIA)); + ++StatPacia; +} + +inline void AArch64PartsCpiPass::lowerPARTSAUTIA(MachineBasicBlock &MBB, MachieInstr *MI) { + lowerPARTSIntrinsicCommon(MBB, MI, TII->get(AArch64::AUTIA)); + ++StatAutia; +} + +void AArch64PartsCpiPass::lowerPARTSAUTCALL(MachineBasicBlock &MBB, MachineInstr &MI) { + LLVM_DEBUG(MBB.dump()); + llvm_unreachable("Unexpected PARTSAUTCALL found!!!!"); +} + +void AArch64PartsCpiPass::lowerPARTSIntrinsicCommon(MachineBasicBlock &MBB, MachieInstr &MI, + const MCInstrDesc &InstrDesc) { + auto &mod = MI.getOperand(2); + auto &dst = MI.getOperand(0); + auto BMI = BuildMI(MBB, MI, MI.getDebugLoc(), InstrDesc); + BMI.add(dst); + BMI.add(dst); + BMI.add(mod); +} \ No newline at end of file diff --git a/llvm/lib/Target/AArch64/AArch64PARTS/AArch64PartsPassCommon.h b/llvm/lib/Target/AArch64/AArch64PARTS/AArch64PartsPassCommon.h new file mode 100644 index 0000000000000000000000000000000000000000..7531d55181bd3b288935d73e691e02227d1c363a --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64PARTS/AArch64PartsPassCommon.h @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef __AARCH64PARTSOPTPASS_H__ +#define __AARCH64PARTSOPTPASS_H__ + +#include "AArch64InstrInfo.h" +#include "AArch64Subtarget.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/PARTS/Parts.h" + +using namespace llvm; +using namespace llvm::PARTS; + +namespace llvm { +namespace PARTS { + +class AArch64PartsPassCommon { +protected: + inline void initRunOn(MachineFunction &MF); + inline bool hasNoPartsAttribute(MachineFunction &MF); + inline void lowerPartsIntrinsic(MachineFunction &MF, MachineBasicBlock &MBB, MachineInstr &MI, + const MCInstrDesc &InstrDesc); + inline void insertMovInstr(MachineBasicBlock &MBB, MachineInstr *MI, unsigned dstReg, unsigned srcReg); + inline void replacePartsIntrinsic(MachineFunction &MF, MachineBasicBlock &MBB, MachineInstr &MI, + const MCInstrDesc &InstrDesc); + inline void replacePartsXPACDIntrinsic(MachineFunction &MF, MachineBasicBlock &MBB, MachineInstr &MI); + + const TargetMachine *TM = nullptr; + const AArch64Subtarget *STI = nullptr; + const AArch64InstrInfo *TII = nullptr; + const AArch64RegisterInfo *TRI = nullptr; + +public: + static inline void insertPACInstr(MachineBasicBlock &MBB, MachineInstr *MI, unsigned dstReg, + unsigned modReg, const MCInstrDesc &InstrDesc); +}; +} +} + +inline void AArch64PartsPassCommon::initRunOn(MachineFunction &MF) { + TM = &MF.getTarget(); + STI = &MF.getSubtarget(); + TII = STI->getInstrInfo(); + TRI = STI->getRegisterInfo(); +} + +inline bool AArch64PartsPassCommon::hasNoPartsAttribute(MachineFunction &MF) { + return MF.getFunction().getFnAttribute("no-parts").getValueAsString() == "true"; +} + +inline void AArch64PartsPassCommon::lowerPartsIntrinsic(MachineFunction &MF, MachineBasicBlock &MBB, MachineInstr &MI, + const MCInstrDesc &InstrDesc) { + const unsigned mod = MI.getOperand(2).getReg(); + const unsigned dst = MI.getOperand(0).getReg(); + insertPACInstr(MBB, &MI, dst, mod, InstrDesc); +} + +inline void AArch64PartsPassCommon::replacePartsIntrinsic(MachineFunction &MF, MachineBasicBlock &MBB, MachineInstr &MI, + const MCInstrDesc &InstrDesc) { + lowerPartsIntrinsic(MF, MBB, MI, InstrDesc); + MI.removeFromParent(); +} + +static inline void AArch64PartsPassCommon::insertPACInstr(MachineBasicBlock &MBB, MachineInstr *MI, unsigned dstReg, + unsigned modReg, const MCInstrDesc &InstrDesc) { + if (MI != nullptr) { + BuildMI(MBB, MI, MI->getDebugLoc(), InstrDesc, dstReg) + .addReg(dstReg) + .addReg(modReg, RegState::InternalRead); + } else { + BuildMI(&MBB, DebugLoc(), InstrDesc, dstReg) + .addReg(dstReg) + .addReg(modReg, RegState::InternalRead); + } +} + +inline void AArch64PartsPassCommon::insertMovInstr(MachineBasicBlock &MBB, MachineInstr *MI, unsigned dstReg, + unsigned srcReg) { + BuildMI(MBB, MI, MI->getDebugLoc(), TII->get(AArch64::ORRXrs), dstReg) + .addUse(AArch64::XZR) + .addUse(srcReg) + .addImm(0); +} + +inline void AArch64PartsPassCommon::replacePartsXPACDIntrinsic(MachineFunction &MF, MachineBasicBlock &MBB, + MachineInstr &MI) { + const unsigned dst = MI.getOperand(0).getReg(); + BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(AArch64::XPACD), dst); + MI.removeFromParent(); +} + +#endif + diff --git a/llvm/lib/Target/AArch64/AArch64PARTS/PartsFrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64PARTS/PartsFrameLowering.cpp new file mode 100644 index 0000000000000000000000000000000000000000..103bacdb22f5376fe42810de4756a41d38de06be --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64PARTS/PartsFrameLowering.cpp @@ -0,0 +1,188 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Zaheer Gauhar +// Gilang Mentari Hamidy +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PartsFrameLowering.h" +#include "AArch64PartsPassCommon.h" +#include "AArch64InstrInfo.h" +#include "AArch64MachineFunctionInfo.h" +#include "AArch64RegisterInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Support/Debug.h" +#include "llvm/PARTS/Parts.h" +#include + +using namespace llvm; +using namespace llvm::PARTS; +#define DEBUG_TYPE "PartsOptRasPass" + +static constexpr const unsigned modReg = AArch64::X16; +static constexpr const unsigned modScratchReg = AArch64::X17; + +static bool doInstrument(const MachineFunction &MF) { + static const auto becfi = PARTS::getBeCfiType(); + + // Just skip if we're not even using backward-edge CFI + if (becfi == PartsBeCfiNone) return false; + + const Function &F = MF.getFunction(); + // Ignore function with the no-parts attribute + if (F.hasFnAttribute("no-parts")) return false; + // Ignore function without function-id (if we need it) + if (becfi == PartsBeCfiFull && !F.hasFnAttribute("parts-function_id")) return false; + + // Skip if we don't spill LR + for (const auto &Info : MF.getFrameInfo().getCalleeSavedInfo()) { + if (Info.getReg() != AArch64::LR) { + return true; + } + } + return false; +} + +static void createBeCfiModifier(const TargetInstrInfo *TII, MachineBasicBlock &MBB, MachineInstr *MIi, + const DebugLoc &DL) { + auto &F = MBB.getParent()->getFunction(); + + assert(F.hasFnAttribute("parts-function_id")) && "missing parts-functio_id attribute"); + + uint64_t type_id; + std::istringstream iss(F.getFnAttribute("parts-function_id").getValueAsString().str()); + iss >> type_id; + + const auto t1 = ((type_id) % UINT16_MAX); + const auto t2 = ((type_id << 16) % UINT16_MAX); + const auto t3 = ((type_id << 32) % UINT16_MAX); + + if (MIi == nullptr) { + BuildMI(&MBB, DL, TII->get(AArch64::ADDXri), modReg).addReg(AArch64::SP).addImm(0).addImm(0); + BuildMI(&MBB, DL, TII->get(AArch64::MOVKXi), modReg).addReg(modReg).addImm(t1).addImm(16); + BuildMI(&MBB, DL, TII->get(AArch64::MOVKXi), modReg).addReg(modReg).addImm(t2).addImm(32); + BuildMI(&MBB, DL, TII->get(AArch64::MOVKXi), modReg).addReg(modReg).addImm(t3).addImm(48); + } else{ + BuildMI(MBB, MIi, DL, TII->get(AArch64::ADDXri), modReg).addReg(AArch64::SP).addImm(0).addImm(0); + BuildMI(MBB, MIi, DL, TII->get(AArch64::MOVKXi), modReg).addReg(modReg).addImm(t1).addImm(16); + BuildMI(MBB, MIi, DL, TII->get(AArch64::MOVKXi), modReg).addReg(modReg).addImm(t2).addImm(32); + BuildMI(MBB, MIi, DL, TII->get(AArch64::MOVKXi), modReg).addReg(modReg).addImm(t3).addImm(48); + } +} + +static MachineInstr *insertFastModifierInstructions(const TargetInstrInfo *TII, MachineBasicBlock &MBB, + MachineInstr *MI, MCSymbol *Sym, const DebugLoc &DL) { + LLVM_DEBUG(dbgs() << "insertFastModifierInstructions with MI begin.\n"); + + auto FirstModifierMI = BuildMI(MBB, MI, DL, TII->get(AArch64::ADR), modReg) + .addSym(Sym); + BuildMI(MBB, MI, DL, TII->get(AArch64::ADDXri), modScratchReg) + .addReg(AArch64::SP) + .addImm(0) + .addImm(0); + BuildMI(MBB, MI, DL, TII->get(AArch64::BFMXri), modReg) + .addUse(modReg) + .addReg(modScratchReg) + .addImm(32) + .addImm(31); + LLVM_DEBUG(dbgs() << "insertFastModifierInstructions with MI end.\n"); + return FirstModifierMI; +} + +static void insertFastModifierInstructions(const TargetInstrInfo *TII, MachineBasicBlock &MBB, + MCSymbol *Sym, const DebugLoc &DL) { + LLVM_DEBUG(dbgs() << "insertFastModifierInstructions begin.\n"); + + BuildMI(&MBB, DL, TII->get(AArch64::ADR), modReg) + .addSym(Sym); + BuildMI(&MBB, DL, TII->get(AArch64::ADDXri), modScratchReg) + .addReg(AArch64::SP) + .addImm(0) + .addImm(0); + BuildMI(&MBB, DL, TII->get(AArch64::BFMXri), modReg) + .addUse(modReg) + .addReg(modScratchReg) + .addImm(32) + .addImm(31); + LLVM_DEBUG(dbgs() << "insertFastModifierInstructions end.\n"); +} + +#define PARTS_SYMBOL "parts_becfi" + +static MCSymbol *createBeCfiPrologueSymbol(MachineBasicBlock &MBB) { + LLVM_DEBUG(dbgs() << "createBeCfiPrologueSymbol.\n"); + + auto &MF = *MBB.getParent(); + AArch64FunctionInfo *AFI = MF.getInfo(); + auto Sym = MF.getContext().createNamedTempSymbol(PARTS_SYMBOL); + AFI->setPartsSym(Sym); + return Sym; +} + +static MCSymbol *getBeCfiPrologueSymbol(MachineBasicBlock &MBB) { + auto &MF = *MBB.getParent(); + AArch64FunctionInfo *AFI = MF.getInfo(); + return AFI->getPartsSym(); +} + +static void insertPrologueFastBeCfiModifier(const TargetInstrInfo *TII, MachineBasicBlock &MBB, + MachineInstr *MIi, const DebugLoc &DL) { + assert(PARTS::getBeCfiType() == PartsBeCfiNgFull); + LLVM_DEBUG(dbgs() << "insertPrologueFastBeCfiModifier.\n"); + + auto Sym = createBeCfiPrologueSymbol(MBB); + auto MI = insertFastModifierInstructions(TII, MBB, MIi, Sym, DL); + MI->setPreInstrSymbol(*MBB.getParent(), Sym); +} + +static void insertEpilogueFastBeCfiModifier(const TargetInstrInfo *TII, MachineBasicBlock &MBB, + MachineInstr *MIi, const DebugLoc &DL) { + assert(PARTS::getBeCfiType() == PartsBeCfiNgFull); + + auto Sym = getBeCfiPrologueSymbol(MBB); + assert(Sym && "Missing PARTS prologue instruction symbol/label\n"); + LLVM_DEBUG(dbgs() << "insertEpilogueFastBeCfiModifier.\n"); + if (MIi == nullptr) { + insertFastModifierInstructions(TII, MBB, Sym, DL); + } else { + (void)insertFastModifierInstructions(TII, MBB, MIi, Sym, DL); + } +} + +void PartsFrameLowering::instrumentEpilogue(const TargetInstrInfo *TII, const TargetRegisterInfo *TRI, + MachineBasicBlock &MBB) { + if (!doInstrument(*MBB.getParent())) + return; + + const auto loc = MBB.getFirstTerminator(); + auto *MI = (loc != MBB.end() ? &*loc : nullptr); + LLVM_DEBUG(dbgs() << "instrumentEpilogue.\n"); + + if (PARTS::getBeCfiType() == PartsBeCfiFull) + createBeCfiModifier(TII, MBB, MI, DebugLoc()); + else + insertEpilogueFastBeCfiModifier(TII, MBB, MI, DebugLoc()); + + AArch64PartsPassCommon::insertPACInstr(MBB, MI, AArch64::LR, modReg, TII->get(AArch64::AUTIB)); +} + +void PartsFrameLowering::instrumentPrologue(const TargetInstrInfo *TII, const TargetRegisterInfo *TRI, + MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, const DebugLoc &DL) { + if (!doInstrument(*MBB.getParent())) + return; + + LLVM_DEBUG(dbgs() << "instrumentPrologue.\n"); + + if (PARTS::getBeCfiType() == PartsBeCfiFull) + createBeCfiModifier(TII, MBB, &*MBBI, DebugLoc()); + else + insertPrologueFastBeCfiModifier(TII, MBB, &*MBBI, DebugLoc()); + + AArch64PartsPassCommon::insertPACInstr(MBB, &*MBBI, AArch64::LR, modReg, TII->get(AArch64::PACIB)); +} \ No newline at end of file diff --git a/llvm/lib/Target/AArch64/AArch64PARTS/PartsFrameLowering.h b/llvm/lib/Target/AArch64/AArch64PARTS/PartsFrameLowering.h new file mode 100644 index 0000000000000000000000000000000000000000..9d21d8a101a68db1c3b7f717ac68e12dcb8867a6 --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64PARTS/PartsFrameLowering.h @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Zaheer Ahmed Gauhar +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PARTSFRAMELOWERING_H +#define LLVM_PARTSFRAMELOWERING_H + +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" +#include "llvm/IR/DebugLoc.h" + +namespace llvm { +namespace PartsFrameLowering { + +void instrumentEpilogue(const TargetInstrInfo *TII, const TargetRegisterInfo *TRI, + MachineBasicBlock &MBB); +void instrumentPrologue(const TargetInstrInfo *TII, const TargetRegisterInfo *TRI, + MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, const DebugLoc &DL); +} +} + +#endif diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp index 47e4c6589c26cb3e953ee1c8dfcf82b8b2ce344d..e0a1530d63a660440be6250c86dc3b5036487235 100644 --- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp +++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp @@ -42,6 +42,7 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/MC/TargetRegistry.h" +#include "llvm/PARTS/Parts.h" #include "llvm/Pass.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/CommandLine.h" @@ -591,6 +592,9 @@ void AArch64PassConfig::addIRPasses() { if (TM->getTargetTriple().isOSWindows()) addPass(createCFGuardCheckPass()); + if (PARTS::useFeCfi()) + addPass(PARTS::createPartsPluginPass()); + if (TM->Options.JMCInstrument) addPass(createJMCInstrumenterPass()); } @@ -643,6 +647,10 @@ bool AArch64PassConfig::addInstSelector() { getOptLevel() != CodeGenOpt::None) addPass(createAArch64CleanupLocalDynamicTLSPass()); + if (PARTS::useFeCfi()) + // Replace indirect jump instruction such as : BR BLR --> BRAA BLRAA + addPass(createAArch64EarlyPartsCpiPass()); + return false; } @@ -805,6 +813,9 @@ void AArch64PassConfig::addPreEmitPass() { if (TM->getOptLevel() != CodeGenOpt::None && EnableCollectLOH && TM->getTargetTriple().isOSBinFormatMachO()) addPass(createAArch64CollectLOHPass()); + + if (PARTS::useFeCfi()) + addPass(createAArch64PartsCpiPass()); } void AArch64PassConfig::addPreEmitPass2() { diff --git a/llvm/lib/Target/AArch64/CMakeLists.txt b/llvm/lib/Target/AArch64/CMakeLists.txt index e7aba115d6a631bb310e9d2994df575ad07eefa0..54a9482ab907826d08a1afae4e53e3b4422728d1 100644 --- a/llvm/lib/Target/AArch64/CMakeLists.txt +++ b/llvm/lib/Target/AArch64/CMakeLists.txt @@ -40,6 +40,7 @@ add_llvm_target(AArch64CodeGen GISel/AArch64PostLegalizerLowering.cpp GISel/AArch64PostSelectOptimize.cpp GISel/AArch64RegisterBankInfo.cpp + AArch64PARTS/PartsFrameLowering.cpp AArch64A57FPLoadBalancing.cpp AArch64AdvSIMDScalarPass.cpp AArch64AsmPrinter.cpp @@ -85,9 +86,15 @@ add_llvm_target(AArch64CodeGen AArch64TargetTransformInfo.cpp SVEIntrinsicOpts.cpp AArch64SIMDInstrOpt.cpp + AArch64PARTS/AArch64EarlyPartsCpiPass.cpp + AArch64PARTS/AArch64PartsCpiPass.cpp DEPENDS intrinsics_gen + Parts + + LINK_LIBS + Parts LINK_COMPONENTS AArch64Desc