From 92912f8e121a0afc0991142e24522378d0b3bc95 Mon Sep 17 00:00:00 2001 From: arvinzzz Date: Fri, 30 Sep 2022 15:08:15 +0800 Subject: [PATCH] feature: add backward cfi compile options for ohos on aarch64 arch close: #I5F0NE Signed-off-by: arvinzzz Change-Id: Ibf78466e6ef53bb6d72b50ed809b63ca7b6c8347 --- clang/docs/ClangCommandLineReference.rst | 4 + clang/include/clang/Basic/LangOptions.def | 2 +- clang/include/clang/Basic/LangOptions.h | 2 +- clang/include/clang/Driver/Options.td | 6 +- clang/lib/CodeGen/CodeGenModule.cpp | 2 + clang/lib/Driver/ToolChains/Clang.cpp | 3 + clang/lib/Frontend/InitPreprocessor.cpp | 2 + lld/ELF/ScriptParser.cpp | 1 + lld/ELF/Writer.cpp | 6 +- llvm/include/llvm/BinaryFormat/ELF.h | 2 + llvm/include/llvm/Bitcode/LLVMBitCodes.h | 1 + llvm/include/llvm/CodeGen/MachineFrameInfo.h | 15 +++ llvm/include/llvm/CodeGen/StackProtector.h | 2 + .../llvm/CodeGen/StackProtectorRetLowering.h | 57 +++++++++ .../llvm/CodeGen/TargetFrameLowering.h | 5 + llvm/include/llvm/IR/Attributes.td | 3 + llvm/include/llvm/IR/Function.h | 2 +- llvm/lib/AsmParser/LLParser.cpp | 1 + llvm/lib/AsmParser/LLToken.h | 1 + llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 4 + llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 2 + llvm/lib/CodeGen/CMakeLists.txt | 1 + llvm/lib/CodeGen/LocalStackSlotAllocation.cpp | 35 +++++- llvm/lib/CodeGen/PrologEpilogInserter.cpp | 74 +++++++++++- llvm/lib/CodeGen/SafeStack.cpp | 3 +- llvm/lib/CodeGen/StackProtector.cpp | 29 +++++ .../lib/CodeGen/StackProtectorRetLowering.cpp | 111 ++++++++++++++++++ llvm/lib/IR/Attributes.cpp | 13 +- llvm/lib/IR/Function.cpp | 3 +- llvm/lib/IR/Verifier.cpp | 1 + llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 13 ++ .../Target/AArch64/AArch64FrameLowering.cpp | 9 ++ .../lib/Target/AArch64/AArch64FrameLowering.h | 8 +- llvm/lib/Target/AArch64/AArch64InstrInfo.td | 8 ++ .../AArch64StackProtectorRetLowering.cpp | 99 ++++++++++++++++ .../AArch64StackProtectorRetLowering.h | 39 ++++++ llvm/lib/Target/AArch64/CMakeLists.txt | 1 + .../lib/Transforms/IPO/ForceFunctionAttrs.cpp | 1 + llvm/lib/Transforms/Utils/CodeExtractor.cpp | 1 + .../test/tools/llvm-objdump/ohos-headers.test | 16 +++ .../llvm-readobj/ELF/program-headers.test | 18 +++ llvm/tools/llvm-objdump/ELFDump.cpp | 3 + llvm/tools/llvm-readobj/ELFDumper.cpp | 2 + 43 files changed, 597 insertions(+), 14 deletions(-) create mode 100644 llvm/include/llvm/CodeGen/StackProtectorRetLowering.h create mode 100644 llvm/lib/CodeGen/StackProtectorRetLowering.cpp create mode 100644 llvm/lib/Target/AArch64/AArch64StackProtectorRetLowering.cpp create mode 100644 llvm/lib/Target/AArch64/AArch64StackProtectorRetLowering.h create mode 100644 llvm/test/tools/llvm-objdump/ohos-headers.test diff --git a/clang/docs/ClangCommandLineReference.rst b/clang/docs/ClangCommandLineReference.rst index 0ec99315a130..2a9b3fc03123 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 c01f0cca9c9c..02375ba9d0b7 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 d8bd2a8b52fc..a16ac81f785d 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 9019ea8f7298..d710897c0f29 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 9c9bd4e374af..0b9932785d85 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 32397abf1b54..d3ec5c5329ae 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 c64a912ce919..1b783ac5d152 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 b81812d11821..d2e9f4b90beb 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 f550e6a73335..884201c871da 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 1552303b610c..133eaaf9f06b 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 5b4854d6c95e..830f1792de58 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 7f0ec0df57c5..cca3cb091b0a 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 f6513e8d4ea0..d2b82009658f 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 000000000000..667d0f04ceea --- /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 792452f6e81d..22d819032cde 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 f7ffc888c65a..d188980201f2 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 7e209bb3769b..de6fff21a2ed 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 2a3fb8fb6658..f6c7794f371f 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 5149f861837a..a93cdfff73ca 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 f2800201e871..83a5d44da694 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 37ecb9992e44..27d2a625086e 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 32a7946af63b..bd79491541c6 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 ec6e693e8a46..b005e15f6651 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 378aaba2a65f..145d6ebff90c 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 31797631c97b..3f14f68707b7 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 10c6dcbdb049..2f0094fa7369 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 000000000000..4b068995c743 --- /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 c4629decc6d9..e0f1cc217d58 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 17247123f87f..d6862c2dcc6e 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 6dd299ee9845..7d70eed0c91d 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 a0c5498ee620..d296b93bc86a 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 65ee5016042c..bd3bc9ead400 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 80079a9d9836..27450385f89a 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 171d3dbaa814..3fb7c5a62678 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 000000000000..c5f67968a212 --- /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 000000000000..835b4b90fd2a --- /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 0e9503baf180..325f56484e74 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 1a8bb225a626..fc8479496ffd 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 390925a03b73..cccf36ae9831 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 000000000000..045f54fac359 --- /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 3a0fb1e462d3..56ed74040c09 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 1c4d59179cc7..bbbd35802d0f 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 0f508f8dc0f2..6b478ce1b298 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 ""; } -- Gitee