Skip to content

Commit f85a1a3

Browse files
committed
[WIP] Support GNU_PROPERTY_AARCH64_FEATURE_PAUTH
1 parent 908da16 commit f85a1a3

File tree

12 files changed

+184
-33
lines changed

12 files changed

+184
-33
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,20 @@ void CodeGenModule::Release() {
10751075
if (!LangOpts.isSignReturnAddressWithAKey())
10761076
getModule().addModuleFlag(llvm::Module::Min,
10771077
"sign-return-address-with-bkey", 1);
1078+
1079+
if (getTriple().isOSBinFormatELF()) {
1080+
uint64_t PAuthABIVersion =
1081+
(LangOpts.PointerAuthCalls << 0) |
1082+
(LangOpts.PointerAuthReturns << 1) |
1083+
(LangOpts.PointerAuthVTPtrAddressDiscrimination << 2) |
1084+
(LangOpts.PointerAuthVTPtrTypeDiscrimination << 3) |
1085+
(LangOpts.PointerAuthInitFini << 4);
1086+
if (PAuthABIVersion != 0) {
1087+
getModule().addModuleFlag(llvm::Module::Error, "pauthabi-platform", 2);
1088+
getModule().addModuleFlag(llvm::Module::Error, "pauthabi-version",
1089+
PAuthABIVersion);
1090+
}
1091+
}
10781092
}
10791093

10801094
if (!CodeGenOpts.MemoryProfileOutput.empty()) {

lld/ELF/InputFiles.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include "llvm/Support/TarWriter.h"
3232
#include "llvm/Support/raw_ostream.h"
3333

34+
#include <tuple>
35+
3436
using namespace llvm;
3537
using namespace llvm::ELF;
3638
using namespace llvm::object;
@@ -878,11 +880,14 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
878880
// of zero or more type-length-value fields. We want to find a field of a
879881
// certain type. It seems a bit too much to just store a 32-bit value, perhaps
880882
// the ABI is unnecessarily complicated.
881-
template <class ELFT> static uint32_t readAndFeatures(const InputSection &sec) {
883+
template <class ELFT>
884+
static std::pair<uint32_t, SmallVector<uint8_t, 0>>
885+
readGnuProperty(const InputSection &sec) {
882886
using Elf_Nhdr = typename ELFT::Nhdr;
883887
using Elf_Note = typename ELFT::Note;
884888

885889
uint32_t featuresSet = 0;
890+
SmallVector<uint8_t, 0> aarch64PauthAbiTag;
886891
ArrayRef<uint8_t> data = sec.content();
887892
auto reportFatal = [&](const uint8_t *place, const char *msg) {
888893
fatal(toString(sec.file) + ":(" + sec.name + "+0x" +
@@ -926,6 +931,16 @@ template <class ELFT> static uint32_t readAndFeatures(const InputSection &sec) {
926931
featuresSet |= read32<ELFT::TargetEndianness>(desc.data());
927932
}
928933

934+
if (config->emachine == EM_AARCH64 &&
935+
type == GNU_PROPERTY_AARCH64_FEATURE_PAUTH) {
936+
// TODO: proper invalid size handling
937+
assert(size == 16);
938+
// TODO: proper multiple pauth tags handling
939+
assert(aarch64PauthAbiTag.empty());
940+
aarch64PauthAbiTag.resize(size);
941+
memcpy(aarch64PauthAbiTag.data(), desc.data(), size);
942+
}
943+
929944
// Padding is present in the note descriptor, if necessary.
930945
desc = desc.slice(alignTo<(ELFT::Is64Bits ? 8 : 4)>(size));
931946
}
@@ -934,7 +949,7 @@ template <class ELFT> static uint32_t readAndFeatures(const InputSection &sec) {
934949
data = data.slice(nhdr->getSize(sec.addralign));
935950
}
936951

937-
return featuresSet;
952+
return {featuresSet, aarch64PauthAbiTag};
938953
}
939954

940955
// Extract compatibility info for aarch64 pointer authentication from the
@@ -1029,12 +1044,15 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(uint32_t idx,
10291044
// .note.gnu.property containing a single AND'ed bitmap, we discard an input
10301045
// file's .note.gnu.property section.
10311046
if (name == ".note.gnu.property") {
1032-
this->andFeatures = readAndFeatures<ELFT>(InputSection(*this, sec, name));
1047+
std::tie(this->andFeatures, this->aarch64PauthAbiTag) =
1048+
readGnuProperty<ELFT>(InputSection(*this, sec, name));
10331049
return &InputSection::discarded;
10341050
}
10351051

10361052
if (config->emachine == EM_AARCH64 &&
10371053
name == ".note.AARCH64-PAUTH-ABI-tag") {
1054+
// TODO: proper handling of both ways of ELF marking in one file
1055+
assert(this->aarch64PauthAbiTag.empty());
10381056
readAArch64PauthAbiTag<ELFT>(InputSection(*this, sec, name), *this);
10391057
return &InputSection::discarded;
10401058
}

lld/ELF/SyntheticSections.cpp

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -314,22 +314,46 @@ GnuPropertySection::GnuPropertySection()
314314
config->wordsize, ".note.gnu.property") {}
315315

316316
void GnuPropertySection::writeTo(uint8_t *buf) {
317+
write32(buf, 4); // Name size
318+
write32(buf + 4, getSize() - 16); // Content size
319+
write32(buf + 8, NT_GNU_PROPERTY_TYPE_0); // Type
320+
memcpy(buf + 12, "GNU", 4); // Name string
321+
317322
uint32_t featureAndType = config->emachine == EM_AARCH64
318323
? GNU_PROPERTY_AARCH64_FEATURE_1_AND
319324
: GNU_PROPERTY_X86_FEATURE_1_AND;
320325

321-
write32(buf, 4); // Name size
322-
write32(buf + 4, config->is64 ? 16 : 12); // Content size
323-
write32(buf + 8, NT_GNU_PROPERTY_TYPE_0); // Type
324-
memcpy(buf + 12, "GNU", 4); // Name string
325-
write32(buf + 16, featureAndType); // Feature type
326-
write32(buf + 20, 4); // Feature size
327-
write32(buf + 24, config->andFeatures); // Feature flags
328-
if (config->is64)
329-
write32(buf + 28, 0); // Padding
326+
unsigned offset = 16;
327+
328+
if (config->andFeatures != 0) {
329+
write32(buf + offset + 0, featureAndType); // Feature type
330+
write32(buf + offset + 4, 4); // Feature size
331+
write32(buf + offset + 8, config->andFeatures); // Feature flags
332+
if (config->is64)
333+
write32(buf + offset + 12, 0); // Padding
334+
offset += 16;
335+
}
336+
337+
if (!ctx.aarch64PauthAbiTag.empty()) {
338+
write32(buf + offset + 0, GNU_PROPERTY_AARCH64_FEATURE_PAUTH);
339+
write32(buf + offset + 4, 8 * 2);
340+
memcpy(buf + offset + 8, ctx.aarch64PauthAbiTag.data(), 16);
341+
}
330342
}
331343

332-
size_t GnuPropertySection::getSize() const { return config->is64 ? 32 : 28; }
344+
size_t GnuPropertySection::getSize() const {
345+
uint32_t contentSize = 0;
346+
if (config->andFeatures != 0)
347+
contentSize += config->is64 ? 16 : 12;
348+
if (!ctx.aarch64PauthAbiTag.empty()) {
349+
// TODO: proper error handling
350+
assert(ctx.aarch64PauthAbiTag.size() == 16);
351+
assert(config->emachine == EM_AARCH64);
352+
contentSize += 4 + 4 + 8 * 2;
353+
}
354+
assert(contentSize != 0);
355+
return contentSize + 16;
356+
}
333357

334358
AArch64PauthAbiTag::AArch64PauthAbiTag()
335359
: SyntheticSection(llvm::ELF::SHF_ALLOC, llvm::ELF::SHT_NOTE,

lld/ELF/Writer.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -521,13 +521,14 @@ template <class ELFT> void elf::createSyntheticSections() {
521521
in.iplt = std::make_unique<IpltSection>();
522522
add(*in.iplt);
523523

524-
if (config->andFeatures)
524+
if (config->andFeatures || !ctx.aarch64PauthAbiTag.empty())
525525
add(*make<GnuPropertySection>());
526526

527-
if (!ctx.aarch64PauthAbiTag.empty()) {
528-
in.aarch64PauthAbiTag = std::make_unique<AArch64PauthAbiTag>();
529-
add(*in.aarch64PauthAbiTag);
530-
}
527+
// TODO: alternative PAuth ELF marking way
528+
// if (!ctx.aarch64PauthAbiTag.empty()) {
529+
// in.aarch64PauthAbiTag = std::make_unique<AArch64PauthAbiTag>();
530+
// add(*in.aarch64PauthAbiTag);
531+
// }
531532

532533
// .note.GNU-stack is always added when we are creating a re-linkable
533534
// object file. Other linkers are using the presence of this marker

lld/test/ELF/aarch64-feature-pauth.s

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# REQUIRES: aarch64
2+
# TODO: test PAuth ELF marking via GNU property section
23

34
# RUN: rm -rf %t && split-file %s %t && cd %t
45

lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -472,8 +472,13 @@ ClangExpressionParser::ClangExpressionParser(
472472

473473
auto target_info = TargetInfo::CreateTargetInfo(
474474
m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts);
475-
bool is_pauthabi = true;
476-
if (target_machine == llvm::Triple::aarch64 && is_pauthabi) {
475+
476+
bool is_elf_pauthabi = false;
477+
if (llvm::Triple(m_compiler->getTargetOpts().Triple).isOSBinFormatELF()) {
478+
bool is_elf_pauthabi = true; // TODO
479+
}
480+
481+
if (target_machine == llvm::Triple::aarch64 && is_elf_pauthabi) {
477482
// TODO: enable this depending on corresponding tag section in ELF
478483
target_info->getTargetOpts().Features.push_back("+pauth");
479484
}
@@ -622,8 +627,8 @@ ClangExpressionParser::ClangExpressionParser(
622627
// additionally enabling them as expandable builtins is breaking Clang.
623628
lang_opts.NoBuiltin = true;
624629

625-
// TODO: enable this depending on corresponding tag section in ELF
626-
if (is_pauthabi) {
630+
// TODO
631+
if (is_elf_pauthabi) {
627632
lang_opts.PointerAuthCalls = true;
628633
lang_opts.PointerAuthReturns = true;
629634
lang_opts.PointerAuthVTPtrAddressDiscrimination = true;

lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,6 +1284,44 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data,
12841284
return error;
12851285
}
12861286

1287+
void ObjectFileELF::ParseGNUPropertyPAuthABI(DataExtractor &data,
1288+
uint64_t length) {
1289+
lldb::offset_t Offset = 0;
1290+
1291+
uint32_t NameSz = data.GetU32(&Offset);
1292+
if (NameSz != 4)
1293+
return; // TODO
1294+
1295+
uint32_t ContentSz = data.GetU32(&Offset);
1296+
uint32_t SectionType = data.GetU32(&Offset);
1297+
if (SectionType != NT_GNU_PROPERTY_TYPE_0)
1298+
return; // TODO
1299+
1300+
llvm::StringRef Name = data.GetCStr(&Offset, NameSz);
1301+
if (Name != "GNU")
1302+
return; // TODO
1303+
1304+
while (Offset < length) {
1305+
uint32_t FeatureType = data.GetU32(&Offset);
1306+
uint32_t Size = data.GetU32(&Offset);
1307+
if (FeatureType != GNU_PROPERTY_AARCH64_FEATURE_PAUTH) {
1308+
Offset += Size;
1309+
continue;
1310+
}
1311+
assert(Size == 16); // TODO
1312+
uint64_t PAuthABIPlatform = data.GetU64(&Offset);
1313+
uint64_t PAuthABIVersion = data.GetU64(&Offset);
1314+
assert(PAuthABIPlatform == 2); // TODO
1315+
1316+
// TODO
1317+
bool PointerAuthCalls = PAuthABIVersion & (1 << 0);
1318+
bool PointerAuthReturns = PAuthABIVersion & (1 << 1);
1319+
bool PointerAuthVTPtrAddressDiscrimination = PAuthABIVersion & (1 << 2);
1320+
bool PointerAuthVTPtrTypeDiscrimination = PAuthABIVersion & (1 << 3);
1321+
bool PointerAuthInitFini = PAuthABIVersion & (1 << 4);
1322+
}
1323+
}
1324+
12871325
void ObjectFileELF::ParseARMAttributes(DataExtractor &data, uint64_t length,
12881326
ArchSpec &arch_spec) {
12891327
lldb::offset_t Offset = 0;
@@ -1472,6 +1510,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
14721510
for (SectionHeaderCollIter I = section_headers.begin();
14731511
I != section_headers.end(); ++I) {
14741512
static ConstString g_sect_name_gnu_debuglink(".gnu_debuglink");
1513+
static ConstString g_sect_name_gnu_property(".note.gnu.property");
14751514
const ELFSectionHeaderInfo &sheader = *I;
14761515
const uint64_t section_size =
14771516
sheader.sh_type == SHT_NOBITS ? 0 : sheader.sh_size;
@@ -1554,6 +1593,16 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
15541593
ParseARMAttributes(data, section_size, arch_spec);
15551594
}
15561595

1596+
if (arch_spec.GetMachine() == llvm::Triple::aarch64 &&
1597+
name == g_sect_name_gnu_property) {
1598+
DataExtractor data;
1599+
1600+
if (sheader.sh_type == SHT_NOTE && section_size != 0 &&
1601+
data.SetData(object_data, sheader.sh_offset, section_size) ==
1602+
section_size)
1603+
ParseGNUPropertyPAuthABI(data, section_size);
1604+
}
1605+
15571606
if (name == g_sect_name_gnu_debuglink) {
15581607
DataExtractor data;
15591608
if (section_size && (data.SetData(object_data, sheader.sh_offset,

lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@ class ObjectFileELF : public lldb_private::ObjectFile {
258258

259259
lldb::SectionType GetSectionType(const ELFSectionHeaderInfo &H) const;
260260

261+
static void ParseGNUPropertyPAuthABI(lldb_private::DataExtractor &data,
262+
uint64_t length);
263+
261264
static void ParseARMAttributes(lldb_private::DataExtractor &data,
262265
uint64_t length,
263266
lldb_private::ArchSpec &arch_spec);

llvm/include/llvm/BinaryFormat/ELF.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1673,6 +1673,7 @@ enum : unsigned {
16731673
GNU_PROPERTY_STACK_SIZE = 1,
16741674
GNU_PROPERTY_NO_COPY_ON_PROTECTED = 2,
16751675
GNU_PROPERTY_AARCH64_FEATURE_1_AND = 0xc0000000,
1676+
GNU_PROPERTY_AARCH64_FEATURE_PAUTH = 0xc0000001,
16761677
GNU_PROPERTY_X86_FEATURE_1_AND = 0xc0000002,
16771678

16781679
GNU_PROPERTY_X86_UINT32_OR_LO = 0xc0008000,

llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) {
265265
S, MCConstantExpr::create(Feat00Value, MMI->getContext()));
266266
}
267267

268+
// TODO: enhance naming to distinguish MachO ptrauth ABI version and ELF
269+
// pauthabi platform and version
268270
if (TM.getTargetTriple().isOSBinFormatMachO())
269271
EmitPtrAuthVersion(M);
270272

@@ -283,13 +285,25 @@ void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) {
283285
if (Sign->getZExtValue())
284286
Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_PAC;
285287

286-
if (Flags == 0)
287-
return;
288+
uint64_t PAuthABIPlatform = -1;
289+
if (const auto *PAP = mdconst::extract_or_null<ConstantInt>(
290+
M.getModuleFlag("pauthabi-platform")))
291+
PAuthABIPlatform = PAP->getZExtValue();
292+
uint64_t PAuthABIVersion = -1;
293+
if (const auto *PAV = mdconst::extract_or_null<ConstantInt>(
294+
M.getModuleFlag("pauthabi-version")))
295+
PAuthABIVersion = PAV->getZExtValue();
296+
297+
// TODO: proper error handling instead of assertion
298+
// We later rely on this invariant in AArch64TargetStreamer::emitNoteSection,
299+
// but here we might get invalid user input.
300+
assert((PAuthABIPlatform == uint64_t(-1)) ==
301+
(PAuthABIVersion == uint64_t(-1)));
288302

289303
// Emit a .note.gnu.property section with the flags.
290304
auto *TS =
291305
static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
292-
TS->emitNoteSection(Flags);
306+
TS->emitNoteSection(Flags, PAuthABIPlatform, PAuthABIVersion);
293307
}
294308

295309
void AArch64AsmPrinter::emitFunctionHeaderComment() {

0 commit comments

Comments
 (0)