diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp index 9538dd4a70bae..30ce41e4effa8 100644 --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -1044,8 +1044,7 @@ AArch64BtiPac::AArch64BtiPac(Ctx &ctx) : AArch64(ctx) { // instructions. if (ctx.arg.zPacPlt) { - if (llvm::any_of(ctx.aarch64PauthAbiCoreInfo, - [](uint8_t c) { return c != 0; })) + if (ctx.aarch64PauthAbiCoreInfo && ctx.aarch64PauthAbiCoreInfo->isValid()) pacEntryKind = PEK_Auth; else pacEntryKind = PEK_AuthHint; diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index f0e9592d85dd6..d8d9e3fd1699e 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -139,6 +139,23 @@ enum class GcsPolicy { Implicit, Never, Always }; // For some options that resemble -z bti-report={none,warning,error} enum class ReportPolicy { None, Warning, Error }; +// Describes the signing schema for a file using the PAuth ABI extension. +// Two files are considered compatible when both `platform` and `version` match. +// The pair (0, 0) is reserved to indicate incompatibility with the PAuth ABI. +struct AArch64PauthAbiCoreInfo { + uint64_t platform; + uint64_t version; + // Returns true if the core info is not the reserved (0, 0) value. + bool isValid() const { return platform || version; } + static constexpr size_t size() { return sizeof(platform) + sizeof(version); } + bool operator==(const AArch64PauthAbiCoreInfo &other) const { + return platform == other.platform && version == other.version; + } + bool operator!=(const AArch64PauthAbiCoreInfo &other) const { + return !(*this == other); + } +}; + struct SymbolVersion { llvm::StringRef name; bool isExternCpp; @@ -695,7 +712,7 @@ struct Ctx : CommonLinkerContext { llvm::raw_fd_ostream openAuxiliaryFile(llvm::StringRef, std::error_code &); - ArrayRef aarch64PauthAbiCoreInfo; + std::optional aarch64PauthAbiCoreInfo; }; // The first two elements of versionDefinitions represent VER_NDX_LOCAL and diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 76a37b706c5fa..da51d9fab8d07 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -2841,15 +2841,15 @@ static void readSecurityNotes(Ctx &ctx) { StringRef referenceFileName; if (ctx.arg.emachine == EM_AARCH64) { auto it = llvm::find_if(ctx.objectFiles, [](const ELFFileBase *f) { - return !f->aarch64PauthAbiCoreInfo.empty(); + return f->aarch64PauthAbiCoreInfo.has_value(); }); if (it != ctx.objectFiles.end()) { ctx.aarch64PauthAbiCoreInfo = (*it)->aarch64PauthAbiCoreInfo; referenceFileName = (*it)->getName(); } } - bool hasValidPauthAbiCoreInfo = llvm::any_of( - ctx.aarch64PauthAbiCoreInfo, [](uint8_t c) { return c != 0; }); + bool hasValidPauthAbiCoreInfo = + ctx.aarch64PauthAbiCoreInfo && ctx.aarch64PauthAbiCoreInfo->isValid(); auto report = [&](ReportPolicy policy) -> ELFSyncStream { return {ctx, toDiagLevel(policy)}; @@ -2909,10 +2909,10 @@ static void readSecurityNotes(Ctx &ctx) { } ctx.arg.andFeatures &= features; - if (ctx.aarch64PauthAbiCoreInfo.empty()) + if (!ctx.aarch64PauthAbiCoreInfo) continue; - if (f->aarch64PauthAbiCoreInfo.empty()) { + if (!f->aarch64PauthAbiCoreInfo) { report(ctx.arg.zPauthReport) << f << ": -z pauth-report: file does not have AArch64 " @@ -2922,11 +2922,18 @@ static void readSecurityNotes(Ctx &ctx) { } if (ctx.aarch64PauthAbiCoreInfo != f->aarch64PauthAbiCoreInfo) - Err(ctx) << "incompatible values of AArch64 PAuth core info found\n>>> " - << referenceFileName << ": 0x" - << toHex(ctx.aarch64PauthAbiCoreInfo, /*LowerCase=*/true) - << "\n>>> " << f << ": 0x" - << toHex(f->aarch64PauthAbiCoreInfo, /*LowerCase=*/true); + Err(ctx) + << "incompatible values of AArch64 PAuth core info found\n" + << "platform:\n" + << ">>> " << referenceFileName << ": 0x" + << toHex(ctx.aarch64PauthAbiCoreInfo->platform, /*LowerCase=*/true) + << "\n>>> " << f << ": 0x" + << toHex(f->aarch64PauthAbiCoreInfo->platform, /*LowerCase=*/true) + << "\nversion:\n" + << ">>> " << referenceFileName << ": 0x" + << toHex(ctx.aarch64PauthAbiCoreInfo->version, /*LowerCase=*/true) + << "\n>>> " << f << ": 0x" + << toHex(f->aarch64PauthAbiCoreInfo->version, /*LowerCase=*/true); } // Force enable Shadow Stack. diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 5f6d2b6b647ee..817af15a841ec 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -950,7 +950,7 @@ static void parseGnuPropertyNote(Ctx &ctx, ELFFileBase &f, } else if (ctx.arg.emachine == EM_AARCH64 && type == GNU_PROPERTY_AARCH64_FEATURE_PAUTH) { ArrayRef contents = data ? *data : desc; - if (!f.aarch64PauthAbiCoreInfo.empty()) { + if (f.aarch64PauthAbiCoreInfo) { return void( err(contents.data()) << "multiple GNU_PROPERTY_AARCH64_FEATURE_PAUTH entries are " @@ -961,7 +961,9 @@ static void parseGnuPropertyNote(Ctx &ctx, ELFFileBase &f, "is invalid: expected 16 bytes, but got " << size); } - f.aarch64PauthAbiCoreInfo = desc; + f.aarch64PauthAbiCoreInfo = { + support::endian::read64(&desc[0]), + support::endian::read64(&desc[8])}; } // Padding is present in the note descriptor, if necessary. diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index 808cb5d24079f..ba844ad18f637 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -241,7 +241,7 @@ class ELFFileBase : public InputFile { StringRef sourceFile; uint32_t andFeatures = 0; bool hasCommonSyms = false; - ArrayRef aarch64PauthAbiCoreInfo; + std::optional aarch64PauthAbiCoreInfo; }; // .o file. diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 46591e909ba4f..eb902767746de 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -344,11 +344,11 @@ void GnuPropertySection::writeTo(uint8_t *buf) { offset += 16; } - if (!ctx.aarch64PauthAbiCoreInfo.empty()) { + if (ctx.aarch64PauthAbiCoreInfo) { write32(ctx, buf + offset + 0, GNU_PROPERTY_AARCH64_FEATURE_PAUTH); - write32(ctx, buf + offset + 4, ctx.aarch64PauthAbiCoreInfo.size()); - memcpy(buf + offset + 8, ctx.aarch64PauthAbiCoreInfo.data(), - ctx.aarch64PauthAbiCoreInfo.size()); + write32(ctx, buf + offset + 4, AArch64PauthAbiCoreInfo::size()); + write64(ctx, buf + offset + 8, ctx.aarch64PauthAbiCoreInfo->platform); + write64(ctx, buf + offset + 16, ctx.aarch64PauthAbiCoreInfo->version); } } @@ -356,8 +356,8 @@ size_t GnuPropertySection::getSize() const { uint32_t contentSize = 0; if (ctx.arg.andFeatures != 0) contentSize += ctx.arg.is64 ? 16 : 12; - if (!ctx.aarch64PauthAbiCoreInfo.empty()) - contentSize += 4 + 4 + ctx.aarch64PauthAbiCoreInfo.size(); + if (ctx.aarch64PauthAbiCoreInfo) + contentSize += 4 + 4 + AArch64PauthAbiCoreInfo::size(); assert(contentSize != 0); return contentSize + 16; } @@ -4959,7 +4959,7 @@ template void elf::createSyntheticSections(Ctx &ctx) { ctx.in.iplt = std::make_unique(ctx); add(*ctx.in.iplt); - if (ctx.arg.andFeatures || !ctx.aarch64PauthAbiCoreInfo.empty()) { + if (ctx.arg.andFeatures || ctx.aarch64PauthAbiCoreInfo) { ctx.in.gnuProperty = std::make_unique(ctx); add(*ctx.in.gnuProperty); } diff --git a/lld/test/ELF/aarch64-feature-pauth.s b/lld/test/ELF/aarch64-feature-pauth.s index bc58f69d32f2b..e8c900b9cb134 100644 --- a/lld/test/ELF/aarch64-feature-pauth.s +++ b/lld/test/ELF/aarch64-feature-pauth.s @@ -13,8 +13,12 @@ # RUN: not ld.lld tag1.o tag1a.o tag2.o -o /dev/null 2>&1 | FileCheck --check-prefix ERR1 %s # ERR1: error: incompatible values of AArch64 PAuth core info found -# ERR1-NEXT: >>> tag1.o: 0x2a000000000000000{{1|2}}00000000000000 -# ERR1-NEXT: >>> tag2.o: 0x2a000000000000000{{1|2}}00000000000000 +# ERR1-NEXT: platform: +# ERR1-NEXT: >>> tag1.o: 0x2a +# ERR1-NEXT: >>> tag2.o: 0x2a +# ERR1-NEXT: version: +# ERR1-NEXT: >>> tag1.o: 0x01 +# ERR1-NEXT: >>> tag2.o: 0x02 # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu abi-tag-short.s -o short.o # RUN: not ld.lld short.o -o /dev/null 2>&1 | FileCheck --check-prefix ERR2 %s