Index: clang/lib/Driver/SanitizerArgs.cpp =================================================================== --- clang/lib/Driver/SanitizerArgs.cpp +++ clang/lib/Driver/SanitizerArgs.cpp @@ -1059,6 +1059,11 @@ CmdArgs.push_back("-tsan-instrument-atomics=0"); } + if (HwasanUseAliases) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-hwasan-use-page-alias=1"); + } + if (CfiCrossDso) CmdArgs.push_back("-fsanitize-cfi-cross-dso"); Index: clang/test/Driver/fsanitize.c =================================================================== --- clang/test/Driver/fsanitize.c +++ clang/test/Driver/fsanitize.c @@ -919,3 +919,6 @@ // RUN: %clang -fsanitize=undefined,float-divide-by-zero %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-DIVBYZERO-UBSAN // CHECK-DIVBYZERO-UBSAN: "-fsanitize={{.*}},float-divide-by-zero,{{.*}}" + +// RUN: %clang -fsanitize=hwaddress -fsanitize-hwaddress-experimental-aliasing %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-HWASAN-ALIAS +// CHECK-HWASAN-ALIAS: "-mllvm" "-hwasan-use-page-alias=1" Index: llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -69,7 +69,6 @@ static const size_t kDefaultShadowScale = 4; static const uint64_t kDynamicShadowSentinel = std::numeric_limits::max(); -static const unsigned kPointerTagShift = 56; static const unsigned kShadowBaseAlignment = 32; @@ -186,6 +185,11 @@ cl::desc("inline all checks"), cl::Hidden, cl::init(false)); +// Clang option "-fsanitize-hwaddress-experimental-aliasing" will enable it. +static cl::opt ClUsePageAlias("hwasan-use-page-alias", + cl::desc("Use page aliasing in HWASan"), + cl::Hidden, cl::init(false)); + namespace { /// An instrumentation pass implementing detection of addressability bugs @@ -227,6 +231,7 @@ bool isInterestingAlloca(const AllocaInst &AI); bool tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag, size_t Size); + Value *getTargetTagPtr(IRBuilder<> &IRB, Value *PtrLong, Value *Tag); Value *tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong, Value *Tag); Value *untagPointer(IRBuilder<> &IRB, Value *PtrLong); bool instrumentStack( @@ -242,6 +247,7 @@ Value *getUARTag(IRBuilder<> &IRB, Value *StackTag); Value *getHwasanThreadSlotPtr(IRBuilder<> &IRB, Type *Ty); + Value *applyTagMask(IRBuilder<> &IRB, Value *OldTag); void emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord); void instrumentGlobal(GlobalVariable *GV, uint8_t Tag); @@ -249,6 +255,9 @@ void instrumentPersonalityFunctions(); + unsigned PointerTagShift; + uint64_t TagMaskByte; + private: LLVMContext *C; Module &M; @@ -487,8 +496,12 @@ // x86_64 uses userspace pointer aliases, currently heap-only with callback // instrumentation only. - UsePageAliases = TargetTriple.getArch() == Triple::x86_64; - InstrumentWithCalls = UsePageAliases ? true : ClInstrumentWithCalls; + bool IsX86_64 = TargetTriple.getArch() == Triple::x86_64; + UsePageAliases = ClUsePageAlias && IsX86_64; + if (IsX86_64) + InstrumentWithCalls = true; + else + InstrumentWithCalls = ClInstrumentWithCalls; InstrumentStack = UsePageAliases ? false : ClInstrumentStack; Mapping.init(TargetTriple, InstrumentWithCalls); @@ -502,6 +515,14 @@ HwasanCtorFunction = nullptr; + if (IsX86_64) { + PointerTagShift = 57; + TagMaskByte = 0x3FLL; + } else { + PointerTagShift = 56; + TagMaskByte = 0xFFLL; + } + // Older versions of Android do not have the required runtime support for // short granules, global or personality function instrumentation. On other // platforms we currently require using the latest version of the runtime. @@ -533,7 +554,9 @@ createHwasanCtorComdat(); bool InstrumentGlobals = ClGlobals.getNumOccurrences() ? ClGlobals : NewRuntime; - if (InstrumentGlobals && !UsePageAliases) + + // TODO: We need instrumenting globals for x86 in the future. + if (InstrumentGlobals && !UsePageAliases && !IsX86_64) instrumentGlobals(); bool InstrumentPersonalityFunctions = @@ -755,7 +778,7 @@ } Value *PtrLong = IRB.CreatePointerCast(Ptr, IntptrTy); - Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift), + Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, PointerTagShift), IRB.getInt8Ty()); Value *AddrLong = untagPointer(IRB, PtrLong); Value *Shadow = memToShadow(AddrLong, IRB); @@ -923,7 +946,7 @@ return true; } -static unsigned RetagMask(unsigned AllocaNo) { +static unsigned retagMaskArmv8(unsigned AllocaNo) { // A list of 8-bit numbers that have at most one run of non-zero bits. // x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these // masks. @@ -941,6 +964,29 @@ return FastMasks[AllocaNo % (sizeof(FastMasks) / sizeof(FastMasks[0]))]; } +static unsigned retagX86(unsigned AllocaNo, uint64_t TagMaskByte) { + return AllocaNo & TagMaskByte; +} + +static unsigned retagMask(unsigned AllocaNo, Triple TargetTriple, + uint64_t TagMaskByte) { + if (TargetTriple.getArch() == Triple::x86_64) + return retagX86(AllocaNo, TagMaskByte); + return retagMaskArmv8(AllocaNo); +} + +// The whole pass imply the Tag is 8-bits size, because it is first +// implemented by aarch64 whose tag is happen 1 byte. We should diff +// it frome other targets now. +Value *HWAddressSanitizer::applyTagMask(IRBuilder<> &IRB, Value *OldTag) { + if (TargetTriple.getArch() == Triple::x86_64) { + Constant *TagMask = ConstantInt::get(IntptrTy, TagMaskByte); + Value *NewTag = IRB.CreateAnd(OldTag, TagMask); + return NewTag; + } + return OldTag; +} + Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) { return IRB.CreateZExt(IRB.CreateCall(HwasanGenerateTagFunc), IntptrTy); } @@ -966,6 +1012,7 @@ Value *StackTag = IRB.CreateXor(StackPointerLong, IRB.CreateLShr(StackPointerLong, 20), "hwasan.stack.base.tag"); + return StackTag; } @@ -973,32 +1020,47 @@ AllocaInst *AI, unsigned AllocaNo) { if (ClGenerateTagsWithCalls) return getNextTagWithCall(IRB); - return IRB.CreateXor(StackTag, - ConstantInt::get(IntptrTy, RetagMask(AllocaNo))); + + Value *Tag = IRB.CreateXor( + StackTag, ConstantInt::get( + IntptrTy, retagMask(AllocaNo, TargetTriple, TagMaskByte))); + return applyTagMask(IRB, Tag); } Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB, Value *StackTag) { if (ClUARRetagToZero) return ConstantInt::get(IntptrTy, 0); + if (ClGenerateTagsWithCalls) return getNextTagWithCall(IRB); - return IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU)); + + Value *Tag = IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU)); + return applyTagMask(IRB, Tag); } +Value *HWAddressSanitizer::getTargetTagPtr(IRBuilder<> &IRB, Value *PtrLong, + Value *Tag) {} + // Add a tag to an address. Value *HWAddressSanitizer::tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong, Value *Tag) { assert(!UsePageAliases); Value *TaggedPtrLong; + Value *ShiftedTag = IRB.CreateShl(Tag, PointerTagShift); + // Kernel addresses have 0xFF in the most significant byte. if (CompileKernel) { - // Kernel addresses have 0xFF in the most significant byte. - Value *ShiftedTag = IRB.CreateOr( - IRB.CreateShl(Tag, kPointerTagShift), - ConstantInt::get(IntptrTy, (1ULL << kPointerTagShift) - 1)); - TaggedPtrLong = IRB.CreateAnd(PtrLong, ShiftedTag); + // TODO: Currently, X86_64 don't tag in kernel state. + if (TargetTriple.getArch() == Triple::x86_64) { + TaggedPtrLong = PtrLong; + } else { + // Kernel addresses have 0xFF in the most significant byte. + ShiftedTag = IRB.CreateOr( + ShiftedTag, + ConstantInt::get(IntptrTy, (1ULL << PointerTagShift) - 1)); + TaggedPtrLong = IRB.CreateAnd(PtrLong, ShiftedTag); + } } else { - // Userspace can simply do OR (tag << 56); - Value *ShiftedTag = IRB.CreateShl(Tag, kPointerTagShift); + // Userspace can simply do OR (tag << PointerTagShift); TaggedPtrLong = IRB.CreateOr(PtrLong, ShiftedTag); } return IRB.CreateIntToPtr(TaggedPtrLong, Ty); @@ -1012,12 +1074,12 @@ // Kernel addresses have 0xFF in the most significant byte. UntaggedPtrLong = IRB.CreateOr(PtrLong, ConstantInt::get(PtrLong->getType(), - 0xFFULL << kPointerTagShift)); + 0xFFULL << PointerTagShift)); } else { // Userspace addresses have 0x00. - UntaggedPtrLong = IRB.CreateAnd( - PtrLong, - ConstantInt::get(PtrLong->getType(), ~(0xFFULL << kPointerTagShift))); + UntaggedPtrLong = + IRB.CreateAnd(PtrLong, ConstantInt::get(PtrLong->getType(), + ~(0xFFULL << PointerTagShift))); } return UntaggedPtrLong; } @@ -1166,8 +1228,9 @@ // Prepend "tag_offset, N" to the dwarf expression. // Tag offset logically applies to the alloca pointer, and it makes sense // to put it at the beginning of the expression. - SmallVector NewOps = {dwarf::DW_OP_LLVM_tag_offset, - RetagMask(N)}; + SmallVector NewOps = { + dwarf::DW_OP_LLVM_tag_offset, + retagMask(N, TargetTriple, TagMaskByte)}; auto Locations = DDI->location_ops(); unsigned LocNo = std::distance(Locations.begin(), find(Locations, AI)); DDI->setExpression( @@ -1424,7 +1487,7 @@ Constant *Aliasee = ConstantExpr::getIntToPtr( ConstantExpr::getAdd( ConstantExpr::getPtrToInt(NewGV, Int64Ty), - ConstantInt::get(Int64Ty, uint64_t(Tag) << kPointerTagShift)), + ConstantInt::get(Int64Ty, uint64_t(Tag) << PointerTagShift)), GV->getType()); auto *Alias = GlobalAlias::create(GV->getValueType(), GV->getAddressSpace(), GV->getLinkage(), "", Aliasee, &M);