diff --git a/clang/docs/ClangCommandLineReference.rst b/clang/docs/ClangCommandLineReference.rst index 0ec99315a1307cf1f6bd00703a82c2e292df2121..2a9b3fc031231eb4591cfb7cd5f0d84df743a7c9 100644 --- a/clang/docs/ClangCommandLineReference.rst +++ b/clang/docs/ClangCommandLineReference.rst @@ -2185,6 +2185,10 @@ Enable stack protectors for all functions Enable stack protectors for some functions vulnerable to stack smashing. Compared to -fstack-protector, this uses a stronger heuristic that includes functions containing arrays of any size (and any type), as well as any calls to alloca or the taking of an address from a local variable +.. option:: -fstack-protector-ret + +Enable stack protectors for all functions with return address check + .. option:: -fstack-size-section, -fno-stack-size-section Emit section containing metadata on function stack sizes diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index c01f0cca9c9c2d91c0540b21d106eef3df99ba19..02375ba9d0b700c64ec986158436b5acb2fde02d 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -324,7 +324,7 @@ ENUM_LANGOPT(ExternDeclNoDLLStorageClassVisibility, Visibility, 3, HiddenVisibil BENIGN_LANGOPT(SemanticInterposition , 1, 0, "semantic interposition") BENIGN_LANGOPT(HalfNoSemanticInterposition, 1, 0, "Like -fno-semantic-interposition but don't use local aliases") -ENUM_LANGOPT(StackProtector, StackProtectorMode, 2, SSPOff, +ENUM_LANGOPT(StackProtector, StackProtectorMode, 3, SSPOff, "stack protector mode") ENUM_LANGOPT(TrivialAutoVarInit, TrivialAutoVarInitKind, 2, TrivialAutoVarInitKind::Uninitialized, "trivial automatic variable initialization") diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index d8bd2a8b52fcd7dea4e9dff5e03e4edf158b7162..a16ac81f785d53b2a1dd41e80190d28e389782c4 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -61,7 +61,7 @@ public: using RoundingMode = llvm::RoundingMode; enum GCMode { NonGC, GCOnly, HybridGC }; - enum StackProtectorMode { SSPOff, SSPOn, SSPStrong, SSPReq }; + enum StackProtectorMode { SSPOff, SSPOn, SSPStrong, SSPReq, SSPRet }; // Automatic variables live on the stack, and when trivial they're usually // uninitialized because it's undefined behavior to use them without diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 9019ea8f72980b5af59f1c27789fd262383347ad..d710897c0f29fbc77db557d29f13ff41346f59a4 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2258,6 +2258,8 @@ defm signed_char : OptOutFFlag<"signed-char", "char is signed", "char is unsigne def fsplit_stack : Flag<["-"], "fsplit-stack">, Group; def fstack_protector_all : Flag<["-"], "fstack-protector-all">, Group, HelpText<"Enable stack protectors for all functions">; +def fstack_protector_ret : Flag<["-"], "fstack-protector-ret">, Group, + HelpText<"Enable stack protectors for all functions with return address check">; defm stack_clash_protection : BoolFOption<"stack-clash-protection", CodeGenOpts<"StackClashProtector">, DefaultFalse, PosFlag, NegFlag, @@ -5115,9 +5117,9 @@ def static_define : Flag<["-"], "static-define">, HelpText<"Should __STATIC__ be defined">, MarshallingInfoFlag>; def stack_protector : Separate<["-"], "stack-protector">, - HelpText<"Enable stack protectors">, Values<"0,1,2,3">, + HelpText<"Enable stack protectors">, Values<"0,1,2,3,4">, NormalizedValuesScope<"LangOptions">, - NormalizedValues<["SSPOff", "SSPOn", "SSPStrong", "SSPReq"]>, + NormalizedValues<["SSPOff", "SSPOn", "SSPStrong", "SSPReq", "SSPRet"]>, MarshallingInfoString, "SSPOff">, AutoNormalizeEnum; def stack_protector_buffer_size : Separate<["-"], "stack-protector-buffer-size">, HelpText<"Lower bound for a buffer to be considered for stack protection">, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 9c9bd4e374af7bfd6026d864ca12c78f51ed83ea..0b9932785d856814cac35eb419b55f8b22499835 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1677,6 +1677,8 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, B.addAttribute(llvm::Attribute::StackProtectStrong); else if (LangOpts.getStackProtector() == LangOptions::SSPReq) B.addAttribute(llvm::Attribute::StackProtectReq); + else if (LangOpts.getStackProtector() == LangOptions::SSPRet) + B.addAttribute(llvm::Attribute::StackProtectRet); } if (!D) { diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 32397abf1b54051a2d2d9898f28d2f35cf53980c..d3ec5c5329aea6b972893680e8c912cb5da265d9 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3007,6 +3007,7 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, options::OPT_fstack_protector_all, + options::OPT_fstack_protector_ret, options::OPT_fstack_protector_strong, options::OPT_fstack_protector)) { if (A->getOption().matches(options::OPT_fstack_protector)) @@ -3014,6 +3015,8 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, std::max<>(LangOptions::SSPOn, DefaultStackProtectorLevel); else if (A->getOption().matches(options::OPT_fstack_protector_strong)) StackProtectorLevel = LangOptions::SSPStrong; + else if (A->getOption().matches(options::OPT_fstack_protector_ret)) + StackProtectorLevel = LangOptions::SSPRet; else if (A->getOption().matches(options::OPT_fstack_protector_all)) StackProtectorLevel = LangOptions::SSPReq; } else { diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index c64a912ce919d878de31301f555c6c04e029b084..1b783ac5d152c755f3954d7850e58aa8bd20dee8 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -1038,6 +1038,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__SSP_STRONG__", "2"); else if (LangOpts.getStackProtector() == LangOptions::SSPReq) Builder.defineMacro("__SSP_ALL__", "3"); + else if (LangOpts.getStackProtector() == LangOptions::SSPRet) + Builder.defineMacro("__SSP_RET__", "4"); if (PPOpts.SetUpStaticAnalyzer) Builder.defineMacro("__clang_analyzer__"); diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index b81812d11821ecf2946e534ab7a8949da5dfd266..d2e9f4b90beb617e1163ed45a3febe5c9370009a 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -1453,6 +1453,7 @@ unsigned ScriptParser::readPhdrType() { .Case("PT_OPENBSD_RANDOMIZE", PT_OPENBSD_RANDOMIZE) .Case("PT_OPENBSD_WXNEEDED", PT_OPENBSD_WXNEEDED) .Case("PT_OPENBSD_BOOTDATA", PT_OPENBSD_BOOTDATA) + .Case("PT_OHOS_RANDOMDATA", PT_OHOS_RANDOMDATA) .Default(-1); if (ret == (unsigned)-1) { diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index f550e6a7333528e09f0b8a18cda82303e921142e..884201c871da31a8b99c5ad418b8bf77200028e9 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -898,7 +898,8 @@ static bool isRelroSection(const OutputSection *sec) { return s == ".data.rel.ro" || s == ".bss.rel.ro" || s == ".ctors" || s == ".dtors" || s == ".jcr" || s == ".eh_frame" || s == ".fini_array" || s == ".init_array" || - s == ".openbsd.randomdata" || s == ".preinit_array"; + s == ".openbsd.randomdata" || s == ".preinit_array" || + s == ".ohos.randomdata"; } // We compute a rank for each section. The rank indicates where the @@ -2451,6 +2452,9 @@ std::vector Writer::createPhdrs(Partition &part) { if (OutputSection *cmd = findSection(".note.gnu.property", partNo)) addHdr(PT_GNU_PROPERTY, PF_R)->add(cmd); + if (OutputSection *cmd = findSection(".ohos.randomdata", partNo)) + addHdr(PT_OHOS_RANDOMDATA, cmd->getPhdrFlags())->add(cmd); + // Create one PT_NOTE per a group of contiguous SHT_NOTE sections with the // same alignment. PhdrEntry *note = nullptr; diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index 1552303b610ca26f03b4f95a73ad1f771c0b3b80..133eaaf9f06b19545ed56af4f0fb299f29fe3930 100644 --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -1238,6 +1238,8 @@ enum { PT_OPENBSD_WXNEEDED = 0x65a3dbe7, // Program does W^X violations. PT_OPENBSD_BOOTDATA = 0x65a41be6, // Section for boot arguments. + PT_OHOS_RANDOMDATA = 0x6788FC60, // Fill with random data. + // ARM program header types. PT_ARM_ARCHEXT = 0x70000000, // Platform architecture compatibility info // These all contain stack unwind tables. diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index 5b4854d6c95e0f9af584028ec30770ebac0896ca..830f1792de58a23baa166a6541a9770f8ebfa83a 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -657,6 +657,7 @@ enum AttributeKindCodes { ATTR_KIND_NO_CALLBACK = 71, ATTR_KIND_HOT = 72, ATTR_KIND_NO_PROFILE = 73, + ATTR_KIND_STACK_PROTECT_RET = 74, }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/CodeGen/MachineFrameInfo.h b/llvm/include/llvm/CodeGen/MachineFrameInfo.h index 7f0ec0df57c52cb60104a6e25d69fe941dc5f6cc..cca3cb091b0a3e3564e8a29a628a7d2c94a35c1e 100644 --- a/llvm/include/llvm/CodeGen/MachineFrameInfo.h +++ b/llvm/include/llvm/CodeGen/MachineFrameInfo.h @@ -274,6 +274,13 @@ private: /// The frame index for the stack protector. int StackProtectorIdx = -1; + struct StackProtectorRet { + /// The register to use for stack protector & backwrad cfi calculations + unsigned Register = 0; + /// Set to true if this function needs stack-protector-ret + bool Needed = false; + } SPR; + /// The frame index for the function context. Used for SjLj exceptions. int FunctionContextIdx = -1; @@ -355,6 +362,14 @@ public: void setStackProtectorIndex(int I) { StackProtectorIdx = I; } bool hasStackProtectorIndex() const { return StackProtectorIdx != -1; } + /// Get / Set stack protector ret calculation register + unsigned getStackProtectorRetRegister() const { return SPR.Register; } + void setStackProtectorRetRegister(unsigned I) { SPR.Register = I; } + bool hasStackProtectorRetRegister() const { return SPR.Register != 0; } + /// Get / Set if this frame needs backward cfi protect. + void setStackProtectorRetNeeded(bool I) { SPR.Needed = I; } + bool getStackProtectorRetNeeded() const { return SPR.Needed; } + /// Return the index for the function context object. /// This object is used for SjLj exceptions. int getFunctionContextIndex() const { return FunctionContextIdx; } diff --git a/llvm/include/llvm/CodeGen/StackProtector.h b/llvm/include/llvm/CodeGen/StackProtector.h index f6513e8d4ea0cb7f4886e85ac82b28a683de0b5a..d2b82009658ff09d98af436f632a1b673f20ec27 100644 --- a/llvm/include/llvm/CodeGen/StackProtector.h +++ b/llvm/include/llvm/CodeGen/StackProtector.h @@ -101,6 +101,8 @@ private: /// stack protector based upon the stack protector level. bool RequiresStackProtector(); + bool CreateSSPRetCookie(); + public: static char ID; // Pass identification, replacement for typeid. diff --git a/llvm/include/llvm/CodeGen/StackProtectorRetLowering.h b/llvm/include/llvm/CodeGen/StackProtectorRetLowering.h new file mode 100644 index 0000000000000000000000000000000000000000..667d0f04ceea3f9b121095ca35e3eec3418afc42 --- /dev/null +++ b/llvm/include/llvm/CodeGen/StackProtectorRetLowering.h @@ -0,0 +1,57 @@ +//===-- StackProtectorRetLowering.h -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_STACKPROTECTORRETLOWERING_H +#define LLVM_CODEGEN_STACKPROTECTORRETLOWERING_H + +#include +#include + +namespace llvm { +class CalleeSavedInfo; +class GlobalVariable; +class MachineBasicBlock; +class MachineFunction; +class MachineInstr; + +class StackProtectorRetLowering { +public: + virtual ~StackProtectorRetLowering() {} + + /// insert stack-protector-ret instrumentation in prologue or epilogue. + virtual void insertStackProtectorRetPrologue(MachineFunction &MF, + MachineBasicBlock &MBB, + GlobalVariable *cookie) const {} + virtual void insertStackProtectorRetEpilogue(MachineFunction &MF, + MachineInstr &MI, + GlobalVariable *cookie) const {} + + /// Check if it is a return instruction. + /// Need to overide the implementation for different architectures. + virtual bool instrIsRet(unsigned opcode) const { return false; } + + /// Get a caller saved temporary register for the target architecture. + /// Need to overide the implementation for different architectures. + virtual unsigned getTargetReg(void) const { return 0; } + + /// Check if backward CFI protection is required. + virtual void setupStackProtectorRet(MachineFunction &MF) const; + + /// Set SSPRetReg as a callee saved register to push the computed stack guard value onto the stack. + virtual void saveStackProtectorRetRegister(MachineFunction &MF, std::vector &CSI) const; + + /// Determine an available SSPRet register and feedback the determination result. + virtual bool determineStackProtectorRetRegister(MachineFunction &MF) const; + + /// insertStackProtectorRets - insert stack-protector-ret instrumentation. + virtual void insertStackProtectorRets(MachineFunction &MF) const; +}; + +} // namespace llvm + +#endif diff --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h index 792452f6e81d6ea18b6a0de3d479672f65b1bf70..22d819032cde12105287aec8891a9b3b0cd4dfb6 100644 --- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h +++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h @@ -14,6 +14,7 @@ #define LLVM_CODEGEN_TARGETFRAMELOWERING_H #include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/StackProtectorRetLowering.h" #include "llvm/Support/TypeSize.h" #include @@ -209,6 +210,10 @@ public: virtual void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const = 0; + virtual const StackProtectorRetLowering *getStackProtectorRet() const { + return nullptr; + } + /// With basic block sections, emit callee saved frame moves for basic blocks /// that are in a different section. virtual void diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td index f7ffc888c65a95dad997b767b5a1935f49028cb4..d188980201f274e7f7ed3e39e274e6251e20b0f3 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -203,6 +203,9 @@ def Speculatable : EnumAttr<"speculatable">; /// Stack protection. def StackProtect : EnumAttr<"ssp">; +/// Stack protection for return address. +def StackProtectRet : EnumAttr<"sspret">; + /// Stack protection required. def StackProtectReq : EnumAttr<"sspreq">; diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h index 7e209bb3769be164ce69904f1978aa7286511631..de6fff21a2ed52eb61ffb86ab0d0f98cdbb7e891 100644 --- a/llvm/include/llvm/IR/Function.h +++ b/llvm/include/llvm/IR/Function.h @@ -387,7 +387,7 @@ public: void setGC(std::string Str); void clearGC(); - /// Returns true if the function has ssp, sspstrong, or sspreq fn attrs. + /// Returns true if the function has ssp, sspstrong, sspret or sspreq fn attrs. bool hasStackProtectorFnAttr() const; /// adds the attribute to the list of attributes. diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 2a3fb8fb6658168a52fd97a986add53775240544..f6c7794f371ff52770f1a93edb3d057d92685fa5 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1383,6 +1383,7 @@ bool LLParser::parseFnAttributeValuePairs(AttrBuilder &B, B.addAttribute(Attribute::ReturnsTwice); break; case lltok::kw_speculatable: B.addAttribute(Attribute::Speculatable); break; case lltok::kw_ssp: B.addAttribute(Attribute::StackProtect); break; + case lltok::kw_sspret: B.addAttribute(Attribute::StackProtectRet); break; case lltok::kw_sspreq: B.addAttribute(Attribute::StackProtectReq); break; case lltok::kw_sspstrong: B.addAttribute(Attribute::StackProtectStrong); break; diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h index 5149f861837adab3b54a2498e9c02eab5650ce53..a93cdfff73ca550c2fefffabfa2d0aa7d16366b8 100644 --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -228,6 +228,7 @@ enum Kind { kw_signext, kw_speculatable, kw_ssp, + kw_sspret, kw_sspreq, kw_sspstrong, kw_safestack, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index f2800201e871114ccbb5f1da1fe164dbbd0d94be..83a5d44da6948e49860fef1359f9df79711e5a72 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1289,6 +1289,8 @@ static uint64_t getRawAttributeMask(Attribute::AttrKind Val) { return 1ULL << 62; case Attribute::NoFree: return 1ULL << 63; + case Attribute::StackProtectRet: + return 1ULL << 64; default: // Other attributes are not supported in the raw format, // as we ran out of space. @@ -1493,6 +1495,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) { return Attribute::StackAlignment; case bitc::ATTR_KIND_STACK_PROTECT: return Attribute::StackProtect; + case bitc::ATTR_KIND_STACK_PROTECT_RET: + return Attribute::StackProtectRet; case bitc::ATTR_KIND_STACK_PROTECT_REQ: return Attribute::StackProtectReq; case bitc::ATTR_KIND_STACK_PROTECT_STRONG: diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 37ecb9992e44abf803e0fb4ce846ff7facc268b4..27d2a625086ea3f845ac87d97553e954584b16bc 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -708,6 +708,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) { return bitc::ATTR_KIND_STACK_ALIGNMENT; case Attribute::StackProtect: return bitc::ATTR_KIND_STACK_PROTECT; + case Attribute::StackProtectRet: + return bitc::ATTR_KIND_STACK_PROTECT_RET; case Attribute::StackProtectReq: return bitc::ATTR_KIND_STACK_PROTECT_REQ; case Attribute::StackProtectStrong: diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt index 32a7946af63bb6b9ae8973ad70c0a13d70381ff0..bd79491541c6c893576b67fc6d978b43a2b61642 100644 --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -164,6 +164,7 @@ add_llvm_component_library(LLVMCodeGen StackMapLivenessAnalysis.cpp StackMaps.cpp StackProtector.cpp + StackProtectorRetLowering.cpp StackSlotColoring.cpp SwiftErrorValueTracking.cpp SwitchLoweringUtils.cpp diff --git a/llvm/lib/CodeGen/LocalStackSlotAllocation.cpp b/llvm/lib/CodeGen/LocalStackSlotAllocation.cpp index ec6e693e8a46abd22dff1ca497ba5f54e3dbd2ff..b005e15f6651fa6a5ef142856654596803cd235b 100644 --- a/llvm/lib/CodeGen/LocalStackSlotAllocation.cpp +++ b/llvm/lib/CodeGen/LocalStackSlotAllocation.cpp @@ -29,6 +29,7 @@ #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/InitializePasses.h" +#include "llvm/IR/Function.h" #include "llvm/Pass.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -197,7 +198,9 @@ void LocalStackSlotPass::calculateFrameObjectOffsets(MachineFunction &Fn) { // Make sure that the stack protector comes before the local variables on the // stack. + Function &F = Fn.getFunction(); SmallSet ProtectedObjs; + if (MFI.hasStackProtectorIndex()) { int StackProtectorFI = MFI.getStackProtectorIndex(); @@ -238,7 +241,37 @@ void LocalStackSlotPass::calculateFrameObjectOffsets(MachineFunction &Fn) { } llvm_unreachable("Unexpected SSPLayoutKind."); } - + AssignProtectedObjSet(LargeArrayObjs, ProtectedObjs, MFI, StackGrowsDown, + Offset, MaxAlign); + AssignProtectedObjSet(SmallArrayObjs, ProtectedObjs, MFI, StackGrowsDown, + Offset, MaxAlign); + AssignProtectedObjSet(AddrOfObjs, ProtectedObjs, MFI, StackGrowsDown, + Offset, MaxAlign); + } else if (F.hasFnAttribute(Attribute::StackProtectRet)) { + StackObjSet LargeArrayObjs; + StackObjSet SmallArrayObjs; + StackObjSet AddrOfObjs; + // Assign large stack objects first. + for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) { + if (MFI.isDeadObjectIndex(i)) + continue; + if (!TFI.isStackIdSafeForLocalArea(MFI.getStackID(i))) + continue; + switch (MFI.getObjectSSPLayout(i)) { + case MachineFrameInfo::SSPLK_None: + continue; + case MachineFrameInfo::SSPLK_SmallArray: + SmallArrayObjs.insert(i); + continue; + case MachineFrameInfo::SSPLK_AddrOf: + AddrOfObjs.insert(i); + continue; + case MachineFrameInfo::SSPLK_LargeArray: + LargeArrayObjs.insert(i); + continue; + } + llvm_unreachable("Unexpected SSPLayoutKind."); + } AssignProtectedObjSet(LargeArrayObjs, ProtectedObjs, MFI, StackGrowsDown, Offset, MaxAlign); AssignProtectedObjSet(SmallArrayObjs, ProtectedObjs, MFI, StackGrowsDown, diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp index 378aaba2a65f15164eea97efd1127d094e053289..145d6ebff90c164dbd90a887b0d4b9511dd29452 100644 --- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp +++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp @@ -217,6 +217,10 @@ bool PEI::runOnMachineFunction(MachineFunction &MF) { const Function &F = MF.getFunction(); const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering(); + const StackProtectorRetLowering *SPRL = TFI->getStackProtectorRet(); + + if (SPRL) + SPRL->setupStackProtectorRet(MF); RS = TRI->requiresRegisterScavenging(MF) ? new RegScavenger() : nullptr; FrameIndexVirtualScavenging = TRI->requiresFrameIndexScavenging(MF); @@ -255,6 +259,10 @@ bool PEI::runOnMachineFunction(MachineFunction &MF) { if (!F.hasFnAttribute(Attribute::Naked)) insertPrologEpilogCode(MF); + // Add StackProtectorRets if using them + if (SPRL) + SPRL->insertStackProtectorRets(MF); + // Reinsert stashed debug values at the start of the entry blocks. for (auto &I : EntryDbgValues) I.first->insert(I.first->begin(), I.second.begin(), I.second.end()); @@ -353,7 +361,9 @@ void PEI::calculateCallFrameInfo(MachineFunction &MF) { /// Compute the sets of entry and return blocks for saving and restoring /// callee-saved registers, and placing prolog and epilog code. void PEI::calculateSaveRestoreBlocks(MachineFunction &MF) { - const MachineFrameInfo &MFI = MF.getFrameInfo(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering(); + const StackProtectorRetLowering *SPRL = TFI->getStackProtectorRet(); // Even when we do not change any CSR, we still want to insert the // prologue and epilogue of the function. @@ -369,7 +379,18 @@ void PEI::calculateSaveRestoreBlocks(MachineFunction &MF) { // epilogue. if (!RestoreBlock->succ_empty() || RestoreBlock->isReturnBlock()) RestoreBlocks.push_back(RestoreBlock); - return; + + // If we are adding stack-protector-rets ensure we can find a available + // register for CFI verification. + if (SPRL && !SPRL->determineStackProtectorRetRegister(MF)) { + // Shrinkwrapping will prevent finding a free register + SaveBlocks.clear(); + RestoreBlocks.clear(); + MFI.setSavePoint(nullptr); + MFI.setRestorePoint(nullptr); + } else { + return; + } } // Save refs to entry and return blocks. @@ -380,6 +401,9 @@ void PEI::calculateSaveRestoreBlocks(MachineFunction &MF) { if (MBB.isReturnBlock()) RestoreBlocks.push_back(&MBB); } + + if (SPRL) + SPRL->determineStackProtectorRetRegister(MF); } static void assignCalleeSavedSpillSlots(MachineFunction &F, @@ -401,6 +425,10 @@ static void assignCalleeSavedSpillSlots(MachineFunction &F, const TargetFrameLowering *TFI = F.getSubtarget().getFrameLowering(); MachineFrameInfo &MFI = F.getFrameInfo(); + + if (TFI->getStackProtectorRet()) + TFI->getStackProtectorRet()->saveStackProtectorRetRegister(F, CSI); + if (!TFI->assignCalleeSavedSpillSlots(F, RegInfo, CSI)) { // If target doesn't implement this, use generic code. @@ -926,6 +954,7 @@ void PEI::calculateFrameObjectOffsets(MachineFunction &MF) { // Make sure that the stack protector comes before the local variables on the // stack. + Function &F = MF.getFunction(); SmallSet ProtectedObjs; if (MFI.hasStackProtectorIndex()) { int StackProtectorFI = MFI.getStackProtectorIndex(); @@ -985,6 +1014,47 @@ void PEI::calculateFrameObjectOffsets(MachineFunction &MF) { llvm_unreachable("Found protected stack objects not pre-allocated by " "LocalStackSlotPass."); + AssignProtectedObjSet(LargeArrayObjs, ProtectedObjs, MFI, StackGrowsDown, + Offset, MaxAlign, Skew); + AssignProtectedObjSet(SmallArrayObjs, ProtectedObjs, MFI, StackGrowsDown, + Offset, MaxAlign, Skew); + AssignProtectedObjSet(AddrOfObjs, ProtectedObjs, MFI, StackGrowsDown, + Offset, MaxAlign, Skew); + } else if (F.hasFnAttribute(Attribute::StackProtectRet)) { + StackObjSet LargeArrayObjs; + StackObjSet SmallArrayObjs; + StackObjSet AddrOfObjs; + // Assign large stack objects first. + for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) { + if (MFI.isObjectPreAllocated(i) && MFI.getUseLocalStackAllocationBlock()) + continue; + if (i >= MinCSFrameIndex && i <= MaxCSFrameIndex) + continue; + if (RS && RS->isScavengingFrameIndex((int)i)) + continue; + if (MFI.isDeadObjectIndex(i)) + continue; + if (EHRegNodeFrameIndex == (int)i) + continue; + if (MFI.getStackID(i) != + TargetStackID::Default) // Only allocate objects on the default stack. + continue; + switch (MFI.getObjectSSPLayout(i)) { + case MachineFrameInfo::SSPLK_None: + continue; + case MachineFrameInfo::SSPLK_SmallArray: + SmallArrayObjs.insert(i); + continue; + case MachineFrameInfo::SSPLK_AddrOf: + AddrOfObjs.insert(i); + continue; + case MachineFrameInfo::SSPLK_LargeArray: + LargeArrayObjs.insert(i); + continue; + } + llvm_unreachable("Unexpected SSPLayoutKind."); + } + AssignProtectedObjSet(LargeArrayObjs, ProtectedObjs, MFI, StackGrowsDown, Offset, MaxAlign, Skew); AssignProtectedObjSet(SmallArrayObjs, ProtectedObjs, MFI, StackGrowsDown, diff --git a/llvm/lib/CodeGen/SafeStack.cpp b/llvm/lib/CodeGen/SafeStack.cpp index 31797631c97b317fb828f34f1d042e831a95cfd9..3f14f68707b7c41d22ec16cfb1a76c0412850bac 100644 --- a/llvm/lib/CodeGen/SafeStack.cpp +++ b/llvm/lib/CodeGen/SafeStack.cpp @@ -809,7 +809,8 @@ bool SafeStack::run() { // FIXME: implement weaker forms of stack protector. if (F.hasFnAttribute(Attribute::StackProtect) || F.hasFnAttribute(Attribute::StackProtectStrong) || - F.hasFnAttribute(Attribute::StackProtectReq)) { + F.hasFnAttribute(Attribute::StackProtectReq) || + F.hasFnAttribute(Attribute::StackProtectRet)) { Value *StackGuard = getStackGuard(IRB, F); StackGuardSlot = IRB.CreateAlloca(StackPtrTy, nullptr); IRB.CreateStore(StackGuard, StackGuardSlot); diff --git a/llvm/lib/CodeGen/StackProtector.cpp b/llvm/lib/CodeGen/StackProtector.cpp index 10c6dcbdb049ea78c3671185b43c9f460d61c913..2f0094fa7369df228f1057f4c02996699be96d35 100644 --- a/llvm/lib/CodeGen/StackProtector.cpp +++ b/llvm/lib/CodeGen/StackProtector.cpp @@ -109,9 +109,35 @@ bool StackProtector::runOnFunction(Function &Fn) { } ++NumFunProtected; + + if (Fn.hasFnAttribute(Attribute::StackProtectRet)) { + HasIRCheck = true; + CreateSSPRetCookie(); + // StackProtectRet requires special code generation methods for backward cfi. + return false; + } + return InsertStackProtectors(); } +bool StackProtector::CreateSSPRetCookie() +{ + std::string cookiename = "__sspret_cookie"; + Type *cookietype = Type::getInt8PtrTy(M->getContext()); + GlobalVariable *cookie = dyn_cast_or_null(M->getOrInsertGlobal(cookiename, cookietype)); + + cookie->setSection(".ohos.randomdata"); + cookie->setExternallyInitialized(true); + cookie->setInitializer(Constant::getNullValue(cookietype)); + cookie->setLinkage(GlobalVariable::LinkOnceAnyLinkage); + cookie->setVisibility(GlobalValue::HiddenVisibility); + cookie->setComdat(M->getOrInsertComdat(cookiename)); + + F->addFnAttr("sspret-randomdata", cookiename); + + return true; +} + /// \param [out] IsLarge is set to true if a protectable array is found and /// it is "large" ( >= ssp-buffer-size). In the case of a structure with /// multiple arrays, this gets set if any of them is large. @@ -292,6 +318,9 @@ bool StackProtector::RequiresStackProtector() { }); NeedsProtector = true; Strong = true; // Use the same heuristic as strong to determine SSPLayout + } else if (F->hasFnAttribute(Attribute::StackProtectRet)) { + NeedsProtector = true; + Strong = true; } else if (F->hasFnAttribute(Attribute::StackProtectStrong)) Strong = true; else if (!F->hasFnAttribute(Attribute::StackProtect)) diff --git a/llvm/lib/CodeGen/StackProtectorRetLowering.cpp b/llvm/lib/CodeGen/StackProtectorRetLowering.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4b068995c7437b5b08314c5be60536749a6ffc8d --- /dev/null +++ b/llvm/lib/CodeGen/StackProtectorRetLowering.cpp @@ -0,0 +1,111 @@ +//===-- StackProtectorRetLowering.cpp ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/StackProtectorRetLowering.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetFrameLowering.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" + +using namespace llvm; + +/// Check if backward CFI protection is required. +void StackProtectorRetLowering::setupStackProtectorRet(MachineFunction &MF) const { + if (MF.getFunction().hasFnAttribute(Attribute::StackProtectRet)) { + for (auto &MBB : MF) { + for (auto &T : MBB.terminators()) { + if (instrIsRet(T.getOpcode())) { + MF.getFrameInfo().setStackProtectorRetNeeded(true); + return; + } + } + } + } +} + +/// Set SSPRetReg as a callee saved register to push the computed stack guard value onto the stack. +void StackProtectorRetLowering::saveStackProtectorRetRegister( + MachineFunction &MF, std::vector &CSI) const { + const MachineFrameInfo &MFI = MF.getFrameInfo(); + if (!MFI.getStackProtectorRetNeeded()) + return; + + if (!MFI.hasStackProtectorRetRegister()) + llvm_unreachable("Missing available stack-protector-ret register"); + + unsigned Reg = MFI.getStackProtectorRetRegister(); + CSI.push_back(CalleeSavedInfo(Reg)); +} + +/// Determine an available SSPRet register and feedback the determination result. +bool StackProtectorRetLowering::determineStackProtectorRetRegister(MachineFunction &MF) const { + MachineFrameInfo &MFI = MF.getFrameInfo(); + if (!MFI.getStackProtectorRetNeeded()) + return true; + + unsigned Reg = getTargetReg(); + MFI.setStackProtectorRetRegister(Reg); + + return MFI.hasStackProtectorRetRegister(); +} + +/// insertStackProtectorRets - insert stack-protector-ret instrumentation. +void StackProtectorRetLowering::insertStackProtectorRets(MachineFunction &MF) const { + MachineFrameInfo &MFI = MF.getFrameInfo(); + const Function &Fn = MF.getFunction(); + const Module *M = Fn.getParent(); + + if (!MFI.getStackProtectorRetNeeded()) + return; + + if (!MFI.hasStackProtectorRetRegister()) + llvm_unreachable("Invalid stack-protector-ret state."); + + GlobalVariable *cookie = dyn_cast_or_null(M->getGlobalVariable( + Fn.getFnAttribute("sspret-randomdata").getValueAsString(), Type::getInt8PtrTy(M->getContext()))); + + if (!cookie) + llvm_unreachable("Function needs stack-protector-ret but missing cookies available."); + + unsigned Reg = MFI.getStackProtectorRetRegister(); + + std::vector returnInstrs; + for (auto &MBB : MF) { + if (MBB.isReturnBlock()) { + for (auto &MI : MBB.terminators()) { + if (instrIsRet(MI.getOpcode())) { + returnInstrs.push_back(&MI); + if (!MBB.isLiveIn(Reg)) { + MBB.addLiveIn(Reg); + } + } + } + } + } + + if (returnInstrs.empty()) { + return; + } + + for (auto &MI : returnInstrs) { + insertStackProtectorRetEpilogue(MF, *MI, cookie); + } + + insertStackProtectorRetPrologue(MF, MF.front(), cookie); + + if (!MF.front().isLiveIn(Reg)) { + MF.front().addLiveIn(Reg); + } +} diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp index c4629decc6d98ebd14e81ead95bfbd9df0259ca5..e0f1cc217d58c8810e48d8a52d8229558074c821 100644 --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -431,6 +431,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const { return "speculatable"; if (hasAttribute(Attribute::StackProtect)) return "ssp"; + if (hasAttribute(Attribute::StackProtectRet)) + return "sspret"; if (hasAttribute(Attribute::StackProtectReq)) return "sspreq"; if (hasAttribute(Attribute::StackProtectStrong)) @@ -1966,9 +1968,16 @@ static void adjustCallerSSPLevel(Function &Caller, const Function &Callee) { AttrBuilder OldSSPAttr; OldSSPAttr.addAttribute(Attribute::StackProtect) .addAttribute(Attribute::StackProtectStrong) - .addAttribute(Attribute::StackProtectReq); + .addAttribute(Attribute::StackProtectReq) + .addAttribute(Attribute::StackProtectRet); - if (Callee.hasFnAttribute(Attribute::StackProtectReq)) { + if (Callee.hasFnAttribute(Attribute::StackProtectRet) && + !Caller.hasFnAttribute(Attribute::StackProtect) && + !Caller.hasFnAttribute(Attribute::StackProtectReq) && + !Caller.hasFnAttribute(Attribute::StackProtectStrong)) { + Caller.removeAttributes(AttributeList::FunctionIndex, OldSSPAttr); + Caller.addFnAttr(Attribute::StackProtectRet); + } else if (Callee.hasFnAttribute(Attribute::StackProtectReq)) { Caller.removeAttributes(AttributeList::FunctionIndex, OldSSPAttr); Caller.addFnAttr(Attribute::StackProtectReq); } else if (Callee.hasFnAttribute(Attribute::StackProtectStrong) && diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp index 17247123f87f887b81dea4f561bd3aa9b8e24455..d6862c2dcc6e00e3a482cc7f8fbce06279671ca5 100644 --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -615,7 +615,8 @@ void Function::clearGC() { bool Function::hasStackProtectorFnAttr() const { return hasFnAttribute(Attribute::StackProtect) || hasFnAttribute(Attribute::StackProtectStrong) || - hasFnAttribute(Attribute::StackProtectReq); + hasFnAttribute(Attribute::StackProtectReq) || + hasFnAttribute(Attribute::StackProtectRet); } /// Copy all additional attributes (those not needed to create a Function) from diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 6dd299ee984504839d617c3790a31e3b6f7818f0..7d70eed0c91dedbbcc06139b7cdd8b797df4e25e 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1612,6 +1612,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) { case Attribute::AlwaysInline: case Attribute::OptimizeForSize: case Attribute::StackProtect: + case Attribute::StackProtectRet: case Attribute::StackProtectReq: case Attribute::StackProtectStrong: case Attribute::SafeStack: diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index a0c5498ee6209b9d084d04479750a7ebe6d68ccb..d296b93bc86a6a11f10194d11d0522365fdba58b 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -1455,6 +1455,19 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { case AArch64::SEH_EpilogEnd: TS->EmitARM64WinCFIEpilogEnd(); return; + + case AArch64::SSP_RET_TRAP: + { + MCSymbol *TempSymbol = OutContext.createTempSymbol(); + /* Compare and branch */ + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::CBZX) + .addReg(MI->getOperand(0).getReg()) + .addExpr(MCSymbolRefExpr::create(TempSymbol, OutContext))); + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::BRK).addImm(1)); + OutStreamer->emitLabel(TempSymbol); + return; + } + } // Finally, do the automated lowerings for everything else. diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp index 65ee5016042cc3d6951c77c65531acaf7d5c0027..bd3bc9ead40090a31d9bb0d9783aa7a0161ca1e3 100644 --- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -116,6 +116,7 @@ #include "AArch64InstrInfo.h" #include "AArch64MachineFunctionInfo.h" #include "AArch64RegisterInfo.h" +#include "AArch64StackProtectorRetLowering.h" #include "AArch64Subtarget.h" #include "AArch64TargetMachine.h" #include "MCTargetDesc/AArch64AddressingModes.h" @@ -2560,6 +2561,10 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF, ? RegInfo->getBaseRegister() : (unsigned)AArch64::NoRegister; + if (MFI.hasStackProtectorRetRegister()) { + SavedRegs.set(MFI.getStackProtectorRetRegister()); + } + unsigned ExtraCSSpill = 0; // Figure out which callee-saved registers to save/restore. for (unsigned i = 0; CSRegs[i]; ++i) { @@ -3307,6 +3312,10 @@ unsigned AArch64FrameLowering::getWinEHFuncletFrameSize( getStackAlign()); } +const StackProtectorRetLowering *AArch64FrameLowering::getStackProtectorRet() const { + return &SPRL; +} + namespace { struct FrameObject { bool IsValid = false; diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.h b/llvm/lib/Target/AArch64/AArch64FrameLowering.h index 80079a9d9836d969496b595229b9817a299ccca6..27450385f89a57526ae7f7a21c5af953f724339f 100644 --- a/llvm/lib/Target/AArch64/AArch64FrameLowering.h +++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.h @@ -13,6 +13,7 @@ #ifndef LLVM_LIB_TARGET_AARCH64_AARCH64FRAMELOWERING_H #define LLVM_LIB_TARGET_AARCH64_AARCH64FRAMELOWERING_H +#include "AArch64StackProtectorRetLowering.h" #include "llvm/Support/TypeSize.h" #include "llvm/CodeGen/TargetFrameLowering.h" @@ -22,9 +23,12 @@ class MCCFIInstruction; class AArch64FrameLowering : public TargetFrameLowering { public: + + const AArch64StackProtectorRetLowering SPRL; + explicit AArch64FrameLowering() : TargetFrameLowering(StackGrowsDown, Align(16), 0, Align(16), - true /*StackRealignable*/) {} + true /*StackRealignable*/), SPRL() {} void emitCalleeSavedFrameMoves(MachineBasicBlock &MBB, @@ -39,6 +43,8 @@ public: void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override; void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + const StackProtectorRetLowering *getStackProtectorRet() const override; + bool canUseAsPrologue(const MachineBasicBlock &MBB) const override; StackOffset getFrameIndexReference(const MachineFunction &MF, int FI, diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 171d3dbaa814a2c67dbd6fa3ba512c64113f3e78..3fb7c5a626782fc6fe8ee80323ec6dd837865572 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -704,6 +704,14 @@ def ADDlowTLS } // isReMaterializable, isCodeGenOnly +//===----------------------------------------------------------------------===// +// Pseudo instruction used by stack protector ret for backward cfi +let isCodeGenOnly = 1, hasNoSchedulingInfo = 1 in { + let Size = 8 in { + def SSP_RET_TRAP: Pseudo<(outs), (ins GPR64:$reg), []>; + } +} + def : Pat<(AArch64LOADgot tglobaltlsaddr:$addr), (LOADgot tglobaltlsaddr:$addr)>; diff --git a/llvm/lib/Target/AArch64/AArch64StackProtectorRetLowering.cpp b/llvm/lib/Target/AArch64/AArch64StackProtectorRetLowering.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c5f67968a2121d9857936748983c6a948b1b4393 --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64StackProtectorRetLowering.cpp @@ -0,0 +1,99 @@ +//===-- AArch64StackProtectorRetLowering.cpp --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "AArch64InstrInfo.h" +#include "AArch64MachineFunctionInfo.h" +#include "AArch64RegisterInfo.h" +#include "AArch64StackProtectorRetLowering.h" +#include "AArch64TargetMachine.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Debug.h" +#include "llvm/Target/TargetOptions.h" +#include + +using namespace llvm; + +void AArch64StackProtectorRetLowering::insertStackProtectorRetPrologue( + MachineFunction &MF, MachineBasicBlock &MBB, GlobalVariable *cookie) const { + + MachineBasicBlock::instr_iterator MI = MBB.instr_begin(); + DebugLoc MBBDL = MBB.findDebugLoc(MI); + const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); + unsigned REG = MF.getFrameInfo().getStackProtectorRetRegister(); + + BuildMI(MBB, MI, MBBDL, TII->get(AArch64::ADRP), REG) + .addGlobalAddress(cookie, 0, AArch64II::MO_PAGE); + BuildMI(MBB, MI, MBBDL, TII->get(AArch64::LDRXui), REG) + .addReg(REG) + .addGlobalAddress(cookie, 0, AArch64II::MO_PAGEOFF | AArch64II::MO_NC); + BuildMI(MBB, MI, MBBDL, TII->get(AArch64::ANDXrr), REG) + .addReg(REG) + .addReg(AArch64::LR); +} + +void AArch64StackProtectorRetLowering::insertStackProtectorRetEpilogue( + MachineFunction &MF, MachineInstr &MI, GlobalVariable *cookie) const { + + MachineBasicBlock &MBB = *MI.getParent(); + DebugLoc MBBDL = MI.getDebugLoc(); + const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); + unsigned REG = MF.getFrameInfo().getStackProtectorRetRegister(); + + MBB.addLiveIn(AArch64::X9); + BuildMI(MBB, MI, MBBDL, TII->get(AArch64::ADRP), AArch64::X9) + .addGlobalAddress(cookie, 0, AArch64II::MO_PAGE); + BuildMI(MBB, MI, MBBDL, TII->get(AArch64::LDRXui), AArch64::X9) + .addReg(AArch64::X9) + .addGlobalAddress(cookie, 0, AArch64II::MO_PAGEOFF | AArch64II::MO_NC); + BuildMI(MBB, MI, MBBDL, TII->get(AArch64::ANDXrr), AArch64::X9) + .addReg(AArch64::X9) + .addReg(AArch64::LR); + BuildMI(MBB, MI, MBBDL, TII->get(AArch64::SUBSXrr), REG) + .addReg(REG) + .addReg(AArch64::X9); + BuildMI(MBB, MI, MBBDL, TII->get(AArch64::SSP_RET_TRAP)) + .addReg(REG); +} + +/// Check if it is a return instruction on the AArch64 architecture. +bool AArch64StackProtectorRetLowering::instrIsRet(unsigned opcode) const { + switch (opcode) { + case AArch64::RET_ReallyLR: + case AArch64::RET: + return true; + default: + return false; + } +} + +/// Returns a caller-saved register for the AArch64 architecture. +unsigned AArch64StackProtectorRetLowering::getTargetReg(void) const { + return AArch64::X15; +} + +/// Set SSPRetReg as a callee saved register to push the computed stack guard value onto the stack. +void AArch64StackProtectorRetLowering::saveStackProtectorRetRegister( + MachineFunction &MF, std::vector &CSI) const { + + const MachineFrameInfo &MFI = MF.getFrameInfo(); + if (!MFI.getStackProtectorRetNeeded()) + return; + + if (!MFI.hasStackProtectorRetRegister()) + llvm_unreachable("Saving unset stack-protector-ret register"); + + unsigned Reg = MFI.getStackProtectorRetRegister(); + + CSI.insert(CSI.begin(), CalleeSavedInfo(Reg)); +} diff --git a/llvm/lib/Target/AArch64/AArch64StackProtectorRetLowering.h b/llvm/lib/Target/AArch64/AArch64StackProtectorRetLowering.h new file mode 100644 index 0000000000000000000000000000000000000000..835b4b90fd2a27a456dbaf907050c2f91f4b0e8c --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64StackProtectorRetLowering.h @@ -0,0 +1,39 @@ +//===-- AArch64StackProtectorRetLowering.h ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64STACKPROTECTORRETLOWERING_H +#define LLVM_LIB_TARGET_AARCH64_AARCH64STACKPROTECTORRETLOWERING_H + +#include "llvm/CodeGen/StackProtectorRetLowering.h" + +namespace llvm { + +class AArch64StackProtectorRetLowering : public StackProtectorRetLowering { +public: + /// insert stack-protector-ret instrumentation in prologue or epilogue. + virtual void + insertStackProtectorRetPrologue(MachineFunction &MF, MachineBasicBlock &MBB, + GlobalVariable *cookie) const override; + virtual void + insertStackProtectorRetEpilogue(MachineFunction &MF, MachineInstr &MI, + GlobalVariable *cookie) const override; + + /// Check if it is a return instruction. + virtual bool instrIsRet(unsigned opcode) const override; + + /// Get a caller saved temporary register for the target architecture. + virtual unsigned getTargetReg(void) const override; + + /// Set SSPRetReg as a callee saved register to push the computed stack guard value onto the stack. + virtual void saveStackProtectorRetRegister(MachineFunction &MF, + std::vector &CSI) const override; +}; + +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/AArch64/CMakeLists.txt b/llvm/lib/Target/AArch64/CMakeLists.txt index 0e9503baf180d2637194a5e5dd390a89c2686a3e..325f56484e74eb9687d13a6d806c35cc8cd38c82 100644 --- a/llvm/lib/Target/AArch64/CMakeLists.txt +++ b/llvm/lib/Target/AArch64/CMakeLists.txt @@ -68,6 +68,7 @@ add_llvm_target(AArch64CodeGen AArch64SLSHardening.cpp AArch64SelectionDAGInfo.cpp AArch64SpeculationHardening.cpp + AArch64StackProtectorRetLowering.cpp AArch64StackTagging.cpp AArch64StackTaggingPreRA.cpp AArch64StorePairSuppress.cpp diff --git a/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp b/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp index 1a8bb225a626c78ae45bcaf8da6f89f6e0984d3d..fc8479496ffd95714bfcd75c0435248302ef4fde 100644 --- a/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp @@ -69,6 +69,7 @@ static Attribute::AttrKind parseAttrKind(StringRef Kind) { .Case("sanitize_memtag", Attribute::SanitizeMemTag) .Case("speculative_load_hardening", Attribute::SpeculativeLoadHardening) .Case("ssp", Attribute::StackProtect) + .Case("sspret", Attribute::StackProtectRet) .Case("sspreq", Attribute::StackProtectReq) .Case("sspstrong", Attribute::StackProtectStrong) .Case("strictfp", Attribute::StrictFP) diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp index 390925a03b73c3fae20249ec5a26c13596f5f27c..cccf36ae9831dd98766d6a9300be8a7efc541688 100644 --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -967,6 +967,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs, case Attribute::SanitizeMemTag: case Attribute::SpeculativeLoadHardening: case Attribute::StackProtect: + case Attribute::StackProtectRet: case Attribute::StackProtectReq: case Attribute::StackProtectStrong: case Attribute::StrictFP: diff --git a/llvm/test/tools/llvm-objdump/ohos-headers.test b/llvm/test/tools/llvm-objdump/ohos-headers.test new file mode 100644 index 0000000000000000000000000000000000000000..045f54fac3592edc956a1888c5579664f30f7238 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/ohos-headers.test @@ -0,0 +1,16 @@ +## Check that llvm-objdump dumps OHOS program headers correctly. + +# RUN: yaml2obj %s -o %t +# RUN: llvm-objdump -p %t | FileCheck %s + +# CHECK: OHOS_RANDOMDATA off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**0 +# CHECK-NEXT: filesz 0x0000000000000000 memsz 0x0000000000000000 flags --- + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +ProgramHeaders: + - Type: 0x6788FC60 ## PT_OHOS_RANDOMDATA diff --git a/llvm/test/tools/llvm-readobj/ELF/program-headers.test b/llvm/test/tools/llvm-readobj/ELF/program-headers.test index 3a0fb1e462d3695b0f6f5318a253f4166829bca2..56ed74040c09f6dccf84ffefdf38a35265807112 100644 --- a/llvm/test/tools/llvm-readobj/ELF/program-headers.test +++ b/llvm/test/tools/llvm-readobj/ELF/program-headers.test @@ -114,6 +114,7 @@ # MAPPING-NEXT: 20 .foo.begin .foo.end {{$}} # MAPPING-NEXT: 21 .foo.begin .foo.end {{$}} # MAPPING-NEXT: 22 .foo.begin .foo.end {{$}} +# MAPPING-NEXT: 23 .foo.begin .foo.end {{$}} # MAPPING-NEXT: None .unused .strtab .shstrtab {{$}} # ELF-LLVM: ProgramHeaders [ @@ -401,6 +402,18 @@ # ELF-LLVM-NEXT: ] # ELF-LLVM-NEXT: Alignment: 1 # ELF-LLVM-NEXT: } +# ELF-LLVM-NEXT: ProgramHeader { +# ELF-LLVM-NEXT: Type: PT_OHOS_RANDOMDATA (0x6788FC60) +# ELF32-LLVM-NEXT: Offset: 0x314 +# ELF64-LLVM-NEXT: Offset: 0x548 +# ELF-LLVM-NEXT: VirtualAddress: 0x1000 +# ELF-LLVM-NEXT: PhysicalAddress: 0x1000 +# ELF-LLVM-NEXT: FileSize: 3 +# ELF-LLVM-NEXT: MemSize: 3 +# ELF-LLVM-NEXT: Flags [ (0x0) +# ELF-LLVM-NEXT: ] +# ELF-LLVM-NEXT: Alignment: 1 +# ELF-LLVM-NEXT: } # ELF-LLVM-NEXT: ] --- !ELF @@ -564,6 +577,11 @@ ProgramHeaders: VAddr: 0x1000 FirstSec: .foo.begin LastSec: .foo.end +## Case 23: the PT_OHOS_RANDOMDATA segment. + - Type: 0x6788FC60 ## PT_OHOS_RANDOMDATA + VAddr: 0x1000 + FirstSec: .foo.begin + LastSec: .foo.end ## Check how we dump ARM specific program headers. # RUN: yaml2obj --docnum=1 -DBITS=64 -DMACHINE=EM_ARM %s -o %tarm.elf diff --git a/llvm/tools/llvm-objdump/ELFDump.cpp b/llvm/tools/llvm-objdump/ELFDump.cpp index 1c4d59179cc722767648297b88ab805ac8e3f3c0..bbbd35802d0fa1f3e5f399a20a65751be5a4b853 100644 --- a/llvm/tools/llvm-objdump/ELFDump.cpp +++ b/llvm/tools/llvm-objdump/ELFDump.cpp @@ -249,6 +249,9 @@ static void printProgramHeaders(const ELFFile &Obj, StringRef FileName) { case ELF::PT_OPENBSD_WXNEEDED: outs() << " OPENBSD_WXNEEDED "; break; + case ELF::PT_OHOS_RANDOMDATA: + outs() << " OHOS_RANDOMDATA "; + break; case ELF::PT_PHDR: outs() << " PHDR "; break; diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 0f508f8dc0f2a50cfa77c5a147a852bed465e992..6b478ce1b2986a6a9974db882d49a82fe5a7107d 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -1352,6 +1352,8 @@ static StringRef segmentTypeToString(unsigned Arch, unsigned Type) { LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_RANDOMIZE); LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_WXNEEDED); LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_BOOTDATA); + + LLVM_READOBJ_ENUM_CASE(ELF, PT_OHOS_RANDOMDATA); default: return ""; }