diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 19229687de7dea1659b82225f3fdb340e771ebc1..453ae6ed1ab615695542c3a1555e71d7755b6e5f 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3129,6 +3129,16 @@ def NoSanitizeSpecific : InheritableAttr { let ASTNode = 0; } +// OHOS_LOCAL begin +// Attributes to enable GWP sanitizer. +def GWPSanitizeSpecific : InheritableAttr { + let Spellings = [Clang<"sanitize_with_gwp">]; + let Subjects = SubjectList<[Function, ObjCMethod], ErrorDiag>; + let Documentation = [GWPSanitizeSpecificDocs]; + let SimpleHandler = 1; +} +// OHOS_LOCAL end + def DisableSanitizerInstrumentation : InheritableAttr { let Spellings = [Clang<"disable_sanitizer_instrumentation">]; let Subjects = SubjectList<[Function, ObjCMethod, GlobalVar]>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 06dd22833dae8e5290718a48b034da54c2199fef..f1ee3c291e314d55ff1ad6855564fc6352966c27 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2839,6 +2839,16 @@ on the tool may still insert instrumentation to prevent false positive reports. }]; } +// OHOS_LOCAL begin +def GWPSanitizeSpecificDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Use the ``sanitize_with_gwp`` attribute on a function, Objective-C method, to +specify that heap memory in this function should be checked by GWP sanitizer. + }]; +} +// OHOS_LOCAL end + def NoSanitizeAddressDocs : Documentation { let Category = DocCatFunction; // This function has multiple distinct spellings, and so it requires a custom diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index 7151e923ae9cf37565a26ed5a9d6c87959a2d240..0b257340cf8e25f287c35c3c084356c7e23e0cbc 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -99,6 +99,9 @@ FEATURE(memory_sanitizer, FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread)) FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow)) FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo)) +// OHOS_LOCAL begin +FEATURE(gwp_asan, LangOpts.Sanitize.hasOneOf(SanitizerKind::GWPAsan)) +// OHOS_LOCAL end FEATURE(swiftasynccc, PP.getTargetInfo().checkCallingConvention(CC_SwiftAsync) == clang::TargetInfo::CCCR_OK) diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def index 8e7b6cd0a7e29eca81ff0f8d2fc79b7c43307175..61d6ebe20aded6112525e529c14330ccc77c825a 100644 --- a/clang/include/clang/Basic/Sanitizers.def +++ b/clang/include/clang/Basic/Sanitizers.def @@ -184,6 +184,11 @@ SANITIZER_GROUP("bounds", Bounds, ArrayBounds | LocalBounds) // Scudo hardened allocator SANITIZER("scudo", Scudo) +// OHOS_LOCAL begin +// Guarded pool allocator +SANITIZER("gwp_asan", GWPAsan) +// OHOS_LOCAL end + // Magic group, containing all sanitizers. For example, "-fno-sanitize=all" // can be used to disable all the sanitizers. SANITIZER_GROUP("all", All, ~SanitizerMask()) diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 18d0a9892e8ed21cd3439f4ac03febd976740da9..a7e50abc7441c0f82da95f591ed53b367144cf36 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -99,6 +99,9 @@ public: bool needsCfiDiagRt() const; bool needsStatsRt() const { return Stats; } bool needsScudoRt() const { return Sanitizers.has(SanitizerKind::Scudo); } + // OHOS_LOCAL begin + bool needsGWPAsanRt() const {return Sanitizers.has(SanitizerKind::GWPAsan);} + // OHOS_LOCAL end bool hasMemTag() const { return hasMemtagHeap() || hasMemtagStack() || hasMemtagGlobals(); diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 7c4e35634e5dc8cfe2025762536ddf00d19f8eec..44df6ff4b78a3f8d3866b7f79dd3f4d0a1d257e1 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -74,6 +74,9 @@ #include "llvm/Transforms/Instrumentation/MemorySanitizer.h" #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h" #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" +// OHOS_LOCAL begin +#include "llvm/Transforms/Instrumentation/GWPAddressSanitizer.h" +// OHOS_LOCAL end #include "llvm/Transforms/ObjCARC.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/EarlyCSE.h" @@ -665,6 +668,13 @@ static void addSanitizers(const Triple &TargetTriple, MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass())); } + // OHOS_LOCAL begin + if (LangOpts.Sanitize.has(SanitizerKind::GWPAsan)) { + MPM.addPass(ModuleGWPAddressSanitizerPass()); + MPM.addPass(createModuleToFunctionPassAdaptor(GWPAddressSanitizerPass())); + } + // OHOS_LOCAL end + auto ASanPass = [&](SanitizerMask Mask, bool CompileKernel) { if (LangOpts.Sanitize.has(Mask)) { bool UseGlobalGC = asanUseGlobalsGC(TargetTriple, CodeGenOpts); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 5012bd822bd36a91475e6df3f35a1b63b7fe4bce..c04b9997137a6b75b86e57dcff2899e7f18e089b 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -537,6 +537,14 @@ bool CodeGenFunction::ShouldSkipSanitizerInstrumentation() { return CurFuncDecl->hasAttr(); } +// OHOS_LOCAL begin +bool CodeGenFunction::ShouldInstrumentFunctionWithGWPAsan() { + if (!CurFuncDecl) + return false; + return CurFuncDecl->hasAttr(); +} +// OHOS_LOCAL end + /// ShouldXRayInstrument - Return true if the current function should be /// instrumented with XRay nop sleds. bool CodeGenFunction::ShouldXRayInstrumentFunction() const { @@ -751,6 +759,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, if (ShouldSkipSanitizerInstrumentation()) { CurFn->addFnAttr(llvm::Attribute::DisableSanitizerInstrumentation); + // OHOS_LOCAL begin + } else if (ShouldInstrumentFunctionWithGWPAsan()) { + CurFn->addFnAttr(llvm::Attribute::GWPSanitizeSpecific); + // OHOS_LOCAL end } else { // Apply sanitizer attributes to the function. if (SanOpts.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress)) diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index f9096d05ecde83d572c4ca386b7c288d982baa23..f1e02ec3fc47093e5b96721f8ff9bf082f8f4666 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -2349,6 +2349,12 @@ public: /// should not be instrumented with sanitizers. bool ShouldSkipSanitizerInstrumentation(); + /// OHOS_LOCAL begin + /// ShouldInstrumentFunctionWithGWPAsan - Return true if the current function + /// should be instrumented with GWP sanitizers. + bool ShouldInstrumentFunctionWithGWPAsan(); + /// OHOS_LOCAL end + /// ShouldXRayInstrument - Return true if the current function should be /// instrumented with XRay nop sleds. bool ShouldXRayInstrumentFunction() const; diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index d52afc636445f176adedc138430a9b87ada0a29a..bd4b7a2bcc7d8920d2b2a1d8cf391fb2f4ccb180 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -483,6 +483,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Leak | SanitizerKind::Thread | SanitizerKind::Memory | SanitizerKind::KernelAddress), + // OHOS_LOCAL begin + std::make_pair(SanitizerKind::GWPAsan, + SanitizerKind::Address | SanitizerKind::HWAddress | + SanitizerKind::Leak | SanitizerKind::Thread | + SanitizerKind::Memory | SanitizerKind::KernelAddress | + SanitizerKind::Scudo | SanitizerKind::KernelHWAddress), + // OHOS_LOCAL end std::make_pair(SanitizerKind::SafeStack, (TC.getTriple().isOSFuchsia() ? SanitizerMask() : SanitizerKind::Leak) | @@ -498,7 +505,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Leak | SanitizerKind::Thread | SanitizerKind::Memory | SanitizerKind::KernelAddress | - SanitizerKind::Scudo | SanitizerKind::SafeStack), + SanitizerKind::Scudo | SanitizerKind::SafeStack | + SanitizerKind::GWPAsan), // OHOS_LOCAL std::make_pair(SanitizerKind::MemTag, SanitizerKind::Address | SanitizerKind::KernelAddress | SanitizerKind::HWAddress | diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 152139369ef09280af9e2d4d2f089d812efb84be..56eb19b00be1f169436a1d8eb2623b68e2fad460 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -911,6 +911,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, else SharedRuntimes.push_back("scudo"); } + // OHOS_LOCAL begin + if (SanArgs.needsGWPAsanRt() && SanArgs.linkRuntimes()) + SharedRuntimes.push_back("gwp_asan"); + // OHOS_LOCAL end if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes()) SharedRuntimes.push_back("tsan"); if (SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) { @@ -1016,6 +1020,11 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, StaticRuntimes.push_back("scudo_cxx"); } } + // OHOS_LOCAL begin + if (!SanArgs.needsSharedRt() && SanArgs.needsGWPAsanRt() && + SanArgs.linkRuntimes()) + StaticRuntimes.push_back("gwp_asan"); + // OHOS_LOCAL end } // Should be called before we add system libraries (C++ ABI, libstdc++/libc++, diff --git a/clang/lib/Driver/ToolChains/OHOS.cpp b/clang/lib/Driver/ToolChains/OHOS.cpp index b1f27a48c860c551e1c99f06c7fe4f205741e5fb..ec95b0889081c94e9e81a63834f4f6a52c63e0ee 100644 --- a/clang/lib/Driver/ToolChains/OHOS.cpp +++ b/clang/lib/Driver/ToolChains/OHOS.cpp @@ -429,8 +429,10 @@ SanitizerMask OHOS::getSupportedSanitizers() const { Res |= SanitizerKind::Scudo; Res |= SanitizerKind::KernelAddress; Res |= SanitizerKind::KernelMemory; - // OHOS_LOCAL + // OHOS_LOCAL begin Res |= SanitizerKind::HWAddress; + Res |= SanitizerKind::GWPAsan; + // OHOS_LOCAL end // TODO: Support TSAN and HWASAN and update mask. if (IsAArch64 || IsX86_64 || IsLoongArch64) // OHOS_LOCAL Res |= SanitizerKind::Thread; diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index 3008bf5afe6ef0f88b4118b45dbc6d88de2f8727..ae909cbebb9ee699c8ba97c9cd71e87056afd38c 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -71,6 +71,7 @@ // CHECK-NEXT: Flatten (SubjectMatchRule_function) // CHECK-NEXT: FunctionReturnThunks (SubjectMatchRule_function) // CHECK-NEXT: GNUInline (SubjectMatchRule_function) +// CHECK-NEXT: GWPSanitizeSpecific (SubjectMatchRule_function, SubjectMatchRule_objc_method) // CHECK-NEXT: HIPManaged (SubjectMatchRule_variable) // CHECK-NEXT: Hot (SubjectMatchRule_function) // CHECK-NEXT: IBAction (SubjectMatchRule_objc_method_is_instance) diff --git a/compiler-rt/lib/gwp_asan/CMakeLists.txt b/compiler-rt/lib/gwp_asan/CMakeLists.txt index da6a08d5bde81af99351ee7dd90f92c94f8bb5cd..bc2ab445409a6bf2328bf3c970dce3aeb6cbcd2a 100644 --- a/compiler-rt/lib/gwp_asan/CMakeLists.txt +++ b/compiler-rt/lib/gwp_asan/CMakeLists.txt @@ -106,6 +106,25 @@ if (COMPILER_RT_HAS_GWP_ASAN) ) endforeach() + # OHOS_LOCAL begin + foreach(arch ${GWP_ASAN_SUPPORTED_ARCH}) + add_compiler_rt_runtime( + clang_rt.gwp_asan + SHARED + ARCHS ${arch} + SOURCES ${GWP_ASAN_SOURCES} + ADDITIONAL_HEADERS ${GWP_ASAN_HEADERS} + CFLAGS ${GWP_ASAN_CFLAGS} + OBJECT_LIBS ${GWP_ASAN_OBJECT_LIBS} + # OHOS_LOCAL begin + RTSanitizerCommon + RTSanitizerCommonLibc + # OHOS_LOCAL end + PARENT_TARGET gwp_asan + ) + endforeach() + # OHOS_LOCAL end + add_compiler_rt_object_libraries(RTGwpAsan ARCHS ${GWP_ASAN_SUPPORTED_ARCH} SOURCES ${GWP_ASAN_SOURCES} diff --git a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.h b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.h index 9f4f6c1d202425594749cfac35c304fe380a00b2..0ead83f09aa0f631307440f66d2447ef5b936ab2 100644 --- a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.h +++ b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.h @@ -105,6 +105,14 @@ public: // class must be valid when zero-initialised, and we wish to sample as // infrequently as possible when this is the case, hence we underflow to // UINT32_MAX. + // OHOS_LOCAL begin + // If the RandomState is calculated from getRandomUnsigned32, the value + // of RandomState will never be 1, so we use RandomState == 1 to force + // GWP_ASAN sample. + if (GWP_ASAN_UNLIKELY(getThreadLocals()->RandomState == 1)) + return true; + // OHOS_LOCAL end + if (GWP_ASAN_UNLIKELY(getThreadLocals()->NextSampleCounter == 0)) getThreadLocals()->NextSampleCounter = ((getRandomUnsigned32() % (AdjustedSampleRatePlusOne - 1)) + 1) & @@ -113,6 +121,23 @@ public: return GWP_ASAN_UNLIKELY(--getThreadLocals()->NextSampleCounter == 0); } + // OHOS_LOCAL begin + // Force the allocation to do sample according to the function attribute. + void forceSampleByFuncAttr() { + getThreadLocals()->RandomState = 1; + } + + // Unforce the allocation to do sample when out the fucntion scope with + // attribute. + void unforceSampleByFuncAttr() { + // Initialised to a magic constant so that an uninitialised GWP-ASan won't + // regenerate its sample counter for as long as possible. The xorshift32() + // algorithm used below results in getRandomUnsigned32(0xacd979ce) == + // 0xfffffffe. + getThreadLocals()->RandomState = 0xacd979ce; + } + // OHOS_LOCAL end + // Returns whether the provided pointer is a current sampled allocation that // is owned by this pool. GWP_ASAN_ALWAYS_INLINE bool pointerIsMine(const void *Ptr) const { diff --git a/compiler-rt/lib/gwp_asan/gwp_asan_c_interface.cpp b/compiler-rt/lib/gwp_asan/gwp_asan_c_interface.cpp index a46b33d939d42e451b249af76a761746fd020b3f..e6be5df71c2f4c8952b744f43b2bac9c9ce73e77 100644 --- a/compiler-rt/lib/gwp_asan/gwp_asan_c_interface.cpp +++ b/compiler-rt/lib/gwp_asan/gwp_asan_c_interface.cpp @@ -11,6 +11,7 @@ #include "gwp_asan/optional/printf.h" // OHOS_LOCAL end #include "gwp_asan/optional/segv_handler.h" +#include "sanitizer_common/sanitizer_internal_defs.h" // OHOS_LOCAL #include #include @@ -85,6 +86,18 @@ bool gwp_asan_should_sample() return guarded_poll_alloctor.shouldSample(); } +// OHOS_LOCAL begin +SANITIZER_INTERFACE_ATTRIBUTE void gwp_asan_force_sample_by_funcattr() +{ + return guarded_poll_alloctor.forceSampleByFuncAttr(); +} + +SANITIZER_INTERFACE_ATTRIBUTE void gwp_asan_unforce_sample_by_funcattr() +{ + return guarded_poll_alloctor.unforceSampleByFuncAttr(); +} +// OHOS_LOCAL end + bool gwp_asan_pointer_is_mine(void *mem) { return guarded_poll_alloctor.pointerIsMine(mem); diff --git a/compiler-rt/test/gwp_asan/sanitize_with_gwp.cpp b/compiler-rt/test/gwp_asan/sanitize_with_gwp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fcff51dbcd531b9c86c3e853ea3a98909c52fa36 --- /dev/null +++ b/compiler-rt/test/gwp_asan/sanitize_with_gwp.cpp @@ -0,0 +1,20 @@ +// REQUIRES: gwp_asan +// RUN: %clangxx_gwp_asan -fsanitize=gwp_asan %s -o %t +// RUN: %expect_crash %run %t 2>&1 | FileCheck %s + +// CHECK: GWP-ASan detected a memory error +// CHECK: Double Free at 0x{{[a-f0-9]+}} (a 1-byte allocation) + +#include + +__attribute__((sanitize_with_gwp)) void doubleFree() { + char *Ptr = new char; + delete Ptr; + delete Ptr; + return 0; +} + +int main() { + doubleFree(); + return 0; +} diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index 6cd0011085e0654c7b662577ae4653e4654c788f..0b8bf586a6cace285cf900bf5c5c57c3c6fc280b 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -692,7 +692,8 @@ enum AttributeKindCodes { /// OHOS_LOCAL begin ATTR_KIND_STACK_PROTECT_RET_REQ = 85, ATTR_KIND_STACK_PROTECT_RET_STRONG = 86, - /// OHOS_LOCAL end + ATTR_KIND_FUNCTION_INSTRUMENT_WITH_GWP_SANITIZER = 87, + // OHOS_LOCAL end }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td index a10d9d9c6b235efc262dcdff82f2605262c3b737..afe9ce47b8335964bc927430c7f1031fad2af683 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -99,6 +99,10 @@ def DereferenceableOrNull : IntAttr<"dereferenceable_or_null", /// Do not instrument function with sanitizers. def DisableSanitizerInstrumentation: EnumAttr<"disable_sanitizer_instrumentation", [FnAttr]>; +// OHOS_LOCAL begin +def GWPSanitizeSpecific : EnumAttr<"sanitize_with_gwp", [FnAttr]>; +// OHOS_LOCAL end + /// Provide pointer element type to intrinsic. def ElementType : TypeAttr<"elementtype", [ParamAttr]>; diff --git a/llvm/include/llvm/Transforms/Instrumentation/GWPAddressSanitizer.h b/llvm/include/llvm/Transforms/Instrumentation/GWPAddressSanitizer.h new file mode 100644 index 0000000000000000000000000000000000000000..574f27db7c85d7db47b7e34a6de90f353016023a --- /dev/null +++ b/llvm/include/llvm/Transforms/Instrumentation/GWPAddressSanitizer.h @@ -0,0 +1,35 @@ +//===--------- Definition of the GWPAddressSanitizer class -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file declares the GWPAddressSanitizer. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_GWPADDRESSSANITIZER_H +#define LLVM_TRANSFORMS_INSTRUMENTATION_GWPADDRESSSANITIZER_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { +class Functions; +class Module; + +/// This is a public interface to the gwp address sanitizer pass for +/// instrumenting malloc to gwp_asan_malloc to check for memory errors at runtime. +struct GWPAddressSanitizerPass : public PassInfoMixin { + PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); + static bool isRequired() { return true; } +}; + +struct ModuleGWPAddressSanitizerPass + : public PassInfoMixin { + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); + static bool isRequired() { return true; } +}; +} // namespace llvm + +#endif diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 4e88d10e7f65cde12a173ea4e440b2eae4983a54..8f13135b26efc910225ca8e8e0218c0959aadb96 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1853,6 +1853,10 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) { return Attribute::Convergent; case bitc::ATTR_KIND_DISABLE_SANITIZER_INSTRUMENTATION: return Attribute::DisableSanitizerInstrumentation; + // OHOS_LOCAL begin + case bitc::ATTR_KIND_FUNCTION_INSTRUMENT_WITH_GWP_SANITIZER: + return Attribute::GWPSanitizeSpecific; + // OHOS_LOCAL end case bitc::ATTR_KIND_ELEMENTTYPE: return Attribute::ElementType; case bitc::ATTR_KIND_FNRETTHUNK_EXTERN: diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 5e05ff26647e3d0576e1eb28465980184cccbe6c..aa4276bb54c89a5de52af98ddef0e99a1b58ebd6 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -634,6 +634,10 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) { return bitc::ATTR_KIND_COLD; case Attribute::DisableSanitizerInstrumentation: return bitc::ATTR_KIND_DISABLE_SANITIZER_INSTRUMENTATION; + // OHOS_LOCAL begin + case Attribute::GWPSanitizeSpecific: + return bitc::ATTR_KIND_FUNCTION_INSTRUMENT_WITH_GWP_SANITIZER; + // OHOS_LOCAL end case Attribute::FnRetThunkExtern: return bitc::ATTR_KIND_FNRETTHUNK_EXTERN; case Attribute::Hot: diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index 42fde3752724ea27a74cee91c47e1464a225aa32..13a92d41d023a1b1c69a0b51c8c465d82e07a060 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -131,6 +131,9 @@ #include "llvm/Transforms/Instrumentation/ControlHeightReduction.h" #include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h" #include "llvm/Transforms/Instrumentation/GCOVProfiler.h" +// OHOS_LOCAL begin +#include "llvm/Transforms/Instrumentation/GWPAddressSanitizer.h" +// OHOS_LOCAL end #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h" #include "llvm/Transforms/Instrumentation/InstrOrderFile.h" #include "llvm/Transforms/Instrumentation/InstrProfiling.h" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index 7c29bffbc327bfd6e050f18e5339742f2ca56e15..9d5981d88cedd13b33e2c7d1877661a9ff8ca95b 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -122,6 +122,9 @@ MODULE_PASS("dfsan", DataFlowSanitizerPass()) MODULE_PASS("msan-module", ModuleMemorySanitizerPass({})) MODULE_PASS("module-inline", ModuleInlinerPass()) MODULE_PASS("tsan-module", ModuleThreadSanitizerPass()) +// OHOS_LOCAL begin +MODULE_PASS("gwpasan-module", ModuleGWPAddressSanitizerPass()) +// OHOS_LOCAL end MODULE_PASS("sancov-module", ModuleSanitizerCoveragePass()) MODULE_PASS("memprof-module", ModuleMemProfilerPass()) MODULE_PASS("poison-checking", PoisonCheckingPass()) @@ -382,6 +385,9 @@ FUNCTION_PASS("tlshoist", TLSVariableHoistPass()) FUNCTION_PASS("transform-warning", WarnMissedTransformationsPass()) FUNCTION_PASS("tsan", ThreadSanitizerPass()) FUNCTION_PASS("memprof", MemProfilerPass()) +// OHOS_LOCAL begin +FUNCTION_PASS("gwp_asan", GWPAddressSanitizerPass()) +// OHOS_LOCAL end #undef FUNCTION_PASS #ifndef FUNCTION_PASS_WITH_PARAMS diff --git a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt index a4e09f6cc54d6811c8370e47985caae4d4f19419..2ea9b3a3049f63eb978bebdb1138a1781bb1b68f 100644 --- a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt +++ b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt @@ -18,6 +18,9 @@ add_llvm_component_library(LLVMInstrumentation ValueProfileCollector.cpp ThreadSanitizer.cpp HWAddressSanitizer.cpp + # OHOS_LOCAL begin + GWPAddressSanitizer.cpp + # OHOS_LOCAL end ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms diff --git a/llvm/lib/Transforms/Instrumentation/GWPAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/GWPAddressSanitizer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f649dcb435d4306e1e257c0238cc853b1a07b51 --- /dev/null +++ b/llvm/lib/Transforms/Instrumentation/GWPAddressSanitizer.cpp @@ -0,0 +1,88 @@ +//===- GWPAddressSanitizer.cpp - detector of uninitialized reads -------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +/// \file +/// This file is a part of GWPAddressSanitizer, an address basic correctness +/// checker based on tagged addressing. +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/Instrumentation/GWPAddressSanitizer.h" +#include "llvm/Transforms/Utils/EscapeEnumerator.h" + +using namespace llvm; + +#define DEBUG_TYPE "gwp_asan" + +/// An instrumentation pass implementing detection of addressability bugs +/// using tagged pointers. +class GWPAddressSanitizer { +public: + bool sanitizeFunction(Function &F); + + void initializeCallbacks(Module &M); + +private: + FunctionCallee GwpasanSetForceSampleFunc; + FunctionCallee GwpasanSetUnforceSampleFunc; +}; + +PreservedAnalyses GWPAddressSanitizerPass::run(Function &F, + FunctionAnalysisManager &FAM) { + GWPAddressSanitizer GWPASan; + if (GWPASan.sanitizeFunction(F)) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); +} + +void GWPAddressSanitizer::initializeCallbacks(Module &M) { + IRBuilder<> IRB(M.getContext()); + + AttributeList Attr; + Attr = Attr.addFnAttribute(M.getContext(), Attribute::NoUnwind); + + GwpasanSetForceSampleFunc = M.getOrInsertFunction( + "gwp_asan_force_sample_by_funcattr", Attr, IRB.getVoidTy()); + GwpasanSetUnforceSampleFunc = M.getOrInsertFunction( + "gwp_asan_unforce_sample_by_funcattr", Attr, IRB.getVoidTy()); +} + +PreservedAnalyses ModuleGWPAddressSanitizerPass::run(Module &M, + ModuleAnalysisManager + &MAM) { + return PreservedAnalyses::none(); +} + +bool GWPAddressSanitizer::sanitizeFunction(Function &F) { + if (!F.hasFnAttribute(Attribute::GWPSanitizeSpecific)) + return false; + + // Naked functions can not have prologue/epilogue generated, so + // don't instrument them at all. + if (F.hasFnAttribute(Attribute::Naked)) + return false; + + initializeCallbacks(*F.getParent()); + LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n"); + + Instruction *InsertPt = &*F.getEntryBlock().begin(); + IRBuilder<> EntryIRB(InsertPt); + EntryIRB.CreateCall(GwpasanSetForceSampleFunc); + EscapeEnumerator EE(F, "", true); + while (IRBuilder<> *AtExit = EE.Next()) { + InstrumentationIRBuilder::ensureDebugInfo(*AtExit, F); + AtExit->CreateCall(GwpasanSetUnforceSampleFunc, {}); + } + return true; +} diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp index 10134e26671f31603a1416d03f224fdbfcefaa2c..186ffd4678f203578383c9267f0e6d0dadc411da 100644 --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -927,6 +927,9 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs, case Attribute::AlwaysInline: case Attribute::Cold: case Attribute::DisableSanitizerInstrumentation: + // OHOS_LOCAL begin + case Attribute::GWPSanitizeSpecific: + // OHOS_LOCAL end case Attribute::FnRetThunkExtern: case Attribute::Hot: case Attribute::NoRecurse: