| 1 | //===--- SanitizerMetadata.cpp - Ignored entities for sanitizers ----------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // Class which emits metadata consumed by sanitizer instrumentation passes. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | #include "SanitizerMetadata.h" |
| 13 | #include "CodeGenModule.h" |
| 14 | #include "clang/AST/Attr.h" |
| 15 | #include "clang/AST/Type.h" |
| 16 | |
| 17 | using namespace clang; |
| 18 | using namespace CodeGen; |
| 19 | |
| 20 | SanitizerMetadata::SanitizerMetadata(CodeGenModule &CGM) : CGM(CGM) {} |
| 21 | |
| 22 | static bool isAsanHwasanMemTagOrTysan(const SanitizerSet &SS) { |
| 23 | return SS.hasOneOf(K: SanitizerKind::Address | SanitizerKind::KernelAddress | |
| 24 | SanitizerKind::HWAddress | SanitizerKind::MemTag | |
| 25 | SanitizerKind::Type); |
| 26 | } |
| 27 | |
| 28 | static SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) { |
| 29 | if (Mask & (SanitizerKind::Address | SanitizerKind::KernelAddress)) |
| 30 | Mask |= SanitizerKind::Address | SanitizerKind::KernelAddress; |
| 31 | // Note: KHWASan doesn't support globals. |
| 32 | return Mask; |
| 33 | } |
| 34 | |
| 35 | void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, |
| 36 | SourceLocation Loc, StringRef Name, |
| 37 | QualType Ty, |
| 38 | SanitizerMask NoSanitizeAttrMask, |
| 39 | bool IsDynInit) { |
| 40 | SanitizerSet FsanitizeArgument = CGM.getLangOpts().Sanitize; |
| 41 | if (!isAsanHwasanMemTagOrTysan(SS: FsanitizeArgument)) |
| 42 | return; |
| 43 | |
| 44 | FsanitizeArgument.Mask = expandKernelSanitizerMasks(Mask: FsanitizeArgument.Mask); |
| 45 | NoSanitizeAttrMask = expandKernelSanitizerMasks(Mask: NoSanitizeAttrMask); |
| 46 | SanitizerSet NoSanitizeAttrSet = {.Mask: NoSanitizeAttrMask & |
| 47 | FsanitizeArgument.Mask}; |
| 48 | |
| 49 | llvm::GlobalVariable::SanitizerMetadata Meta; |
| 50 | if (GV->hasSanitizerMetadata()) |
| 51 | Meta = GV->getSanitizerMetadata(); |
| 52 | |
| 53 | Meta.NoAddress |= NoSanitizeAttrSet.hasOneOf(K: SanitizerKind::Address); |
| 54 | Meta.NoAddress |= CGM.isInNoSanitizeList( |
| 55 | Kind: FsanitizeArgument.Mask & SanitizerKind::Address, GV, Loc, Ty); |
| 56 | |
| 57 | Meta.NoHWAddress |= NoSanitizeAttrSet.hasOneOf(K: SanitizerKind::HWAddress); |
| 58 | Meta.NoHWAddress |= CGM.isInNoSanitizeList( |
| 59 | Kind: FsanitizeArgument.Mask & SanitizerKind::HWAddress, GV, Loc, Ty); |
| 60 | |
| 61 | Meta.Memtag |= |
| 62 | static_cast<bool>(FsanitizeArgument.Mask & SanitizerKind::MemtagGlobals); |
| 63 | Meta.Memtag &= !NoSanitizeAttrSet.hasOneOf(K: SanitizerKind::MemTag); |
| 64 | Meta.Memtag &= !CGM.isInNoSanitizeList( |
| 65 | Kind: FsanitizeArgument.Mask & SanitizerKind::MemTag, GV, Loc, Ty); |
| 66 | |
| 67 | Meta.IsDynInit = IsDynInit && !Meta.NoAddress && |
| 68 | FsanitizeArgument.has(K: SanitizerKind::Address) && |
| 69 | !CGM.isInNoSanitizeList(Kind: SanitizerKind::Address | |
| 70 | SanitizerKind::KernelAddress, |
| 71 | GV, Loc, Ty, Category: "init" ); |
| 72 | |
| 73 | GV->setSanitizerMetadata(Meta); |
| 74 | |
| 75 | if (Ty.isNull() || !CGM.getLangOpts().Sanitize.has(K: SanitizerKind::Type) || |
| 76 | NoSanitizeAttrMask & SanitizerKind::Type) |
| 77 | return; |
| 78 | |
| 79 | llvm::MDNode *TBAAInfo = CGM.getTBAATypeInfo(QTy: Ty); |
| 80 | if (!TBAAInfo || TBAAInfo == CGM.getTBAATypeInfo(QTy: CGM.getContext().CharTy)) |
| 81 | return; |
| 82 | |
| 83 | llvm::Metadata *GlobalMetadata[] = {llvm::ConstantAsMetadata::get(C: GV), |
| 84 | TBAAInfo}; |
| 85 | |
| 86 | // Metadata for the global already registered. |
| 87 | if (llvm::MDNode::getIfExists(Context&: CGM.getLLVMContext(), MDs: GlobalMetadata)) |
| 88 | return; |
| 89 | |
| 90 | llvm::MDNode *ThisGlobal = |
| 91 | llvm::MDNode::get(Context&: CGM.getLLVMContext(), MDs: GlobalMetadata); |
| 92 | llvm::NamedMDNode *TysanGlobals = |
| 93 | CGM.getModule().getOrInsertNamedMetadata(Name: "llvm.tysan.globals" ); |
| 94 | TysanGlobals->addOperand(M: ThisGlobal); |
| 95 | } |
| 96 | |
| 97 | void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D, |
| 98 | bool IsDynInit) { |
| 99 | if (!isAsanHwasanMemTagOrTysan(SS: CGM.getLangOpts().Sanitize)) |
| 100 | return; |
| 101 | std::string QualName; |
| 102 | llvm::raw_string_ostream OS(QualName); |
| 103 | D.printQualifiedName(OS); |
| 104 | |
| 105 | auto getNoSanitizeMask = [](const VarDecl &D) { |
| 106 | if (D.hasAttr<DisableSanitizerInstrumentationAttr>()) |
| 107 | return SanitizerKind::All; |
| 108 | |
| 109 | SanitizerMask NoSanitizeMask; |
| 110 | for (auto *Attr : D.specific_attrs<NoSanitizeAttr>()) |
| 111 | NoSanitizeMask |= Attr->getMask(); |
| 112 | |
| 113 | // External definitions and incomplete types get handled at the place they |
| 114 | // are defined. |
| 115 | if (D.hasExternalStorage() || D.getType()->isIncompleteType()) |
| 116 | NoSanitizeMask |= SanitizerKind::Type; |
| 117 | |
| 118 | return NoSanitizeMask; |
| 119 | }; |
| 120 | |
| 121 | reportGlobal(GV, Loc: D.getLocation(), Name: QualName, Ty: D.getType(), NoSanitizeAttrMask: getNoSanitizeMask(D), |
| 122 | IsDynInit); |
| 123 | } |
| 124 | |
| 125 | void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) { |
| 126 | reportGlobal(GV, Loc: SourceLocation(), Name: "" , Ty: QualType(), NoSanitizeAttrMask: SanitizerKind::All); |
| 127 | } |
| 128 | |