Skip to content

Commit 0086b39

Browse files
committed
[AArch64][PAC][lldb][ELF][Dwarf] Support GNU_PROPERTY_AARCH64_FEATURE_PAUTH
Apply signing schema for user expressions when debugging AArch64 ELFs depending on the `GNU_PROPERTY_AARCH64_FEATURE_PAUTH` property in `.note.gnu.property` section in the executable object file. To avoid linking against ObjectFileELF plugin everywhere, define `ParseGNUPropertyAArch64PAuthABI` as a virtual function in the base `ObjectFile` class.
1 parent c497154 commit 0086b39

File tree

6 files changed

+274
-0
lines changed

6 files changed

+274
-0
lines changed

lldb/include/lldb/Symbol/ObjectFile.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/Support/Threading.h"
2424
#include "llvm/Support/VersionTuple.h"
2525
#include <optional>
26+
#include <utility>
2627

2728
namespace lldb_private {
2829

@@ -331,6 +332,15 @@ class ObjectFile : public std::enable_shared_from_this<ObjectFile>,
331332
///
332333
virtual void RelocateSection(lldb_private::Section *section);
333334

335+
/// Parse ELF's AArch64 PAuth ABI from GNU property section. If it's missing
336+
/// or the object file is not an ELF, return std::nullopt. Define this as a
337+
/// virtual function in a base class since direct usage of ObjectFileELF in
338+
/// ClangExpressionParser requires linking against the ObjectFileELF plugin.
339+
virtual std::optional<std::pair<uint64_t, uint64_t>>
340+
ParseGNUPropertyAArch64PAuthABI() {
341+
return std::nullopt;
342+
}
343+
334344
/// Appends a Symbol for the specified so_addr to the symbol table.
335345
///
336346
/// If verify_unique is false, the symbol table is not searched to determine

lldb/include/lldb/Target/LanguageRuntime.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,8 @@ class LanguageRuntime : public Runtime, public PluginInterface {
226226
}
227227

228228
LanguageRuntime(Process *process);
229+
230+
std::pair<uint64_t, uint64_t> m_aarch64_pauth_abi_tag;
229231
};
230232

231233
} // namespace lldb_private

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,11 @@ ClangExpressionParser::ClangExpressionParser(
445445
// Supported subsets of x86
446446
if (target_machine == llvm::Triple::x86 ||
447447
target_machine == llvm::Triple::x86_64) {
448+
// FIXME: shouldn't this be placed after
449+
// `auto target_info = TargetInfo::CreateTargetInfo(...)`
450+
// (see `if (target_machine == llvm::Triple::aarch64)`)?
451+
// It computes `Features` from `FeatureMap` and `FeaturesAsWritten` and
452+
// erases initial `Features` vector.
448453
m_compiler->getTargetOpts().Features.push_back("+sse");
449454
m_compiler->getTargetOpts().Features.push_back("+sse2");
450455
}
@@ -467,6 +472,22 @@ ClangExpressionParser::ClangExpressionParser(
467472

468473
auto target_info = TargetInfo::CreateTargetInfo(
469474
m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts);
475+
476+
std::optional<std::pair<uint64_t, uint64_t>> elf_pauth_abi_tag;
477+
if (target_machine == llvm::Triple::aarch64) {
478+
do {
479+
Module *module_sp = target_sp->GetExecutableModulePointer();
480+
if (module_sp == nullptr)
481+
break;
482+
ObjectFile *obj_file = module_sp->GetObjectFile();
483+
if (obj_file == nullptr)
484+
break;
485+
elf_pauth_abi_tag = obj_file->ParseGNUPropertyAArch64PAuthABI();
486+
if (elf_pauth_abi_tag != std::nullopt)
487+
target_info->getTargetOpts().Features.push_back("+pauth");
488+
} while (false);
489+
}
490+
470491
if (log) {
471492
LLDB_LOGF(log, "Target datalayout string: '%s'",
472493
target_info->getDataLayoutString());
@@ -482,6 +503,22 @@ ClangExpressionParser::ClangExpressionParser(
482503
lldb::LanguageType language = expr.Language();
483504
LangOptions &lang_opts = m_compiler->getLangOpts();
484505

506+
if (elf_pauth_abi_tag != std::nullopt) {
507+
uint64_t elf_pauth_abi_platform = elf_pauth_abi_tag->first;
508+
// TODO: store this magic constant corresponding to Linux platform in some
509+
// header
510+
if (elf_pauth_abi_platform == 2) {
511+
uint64_t elf_pauth_abi_version = elf_pauth_abi_tag->second;
512+
lang_opts.PointerAuthCalls = elf_pauth_abi_version & (1 << 0);
513+
lang_opts.PointerAuthReturns = elf_pauth_abi_version & (1 << 1);
514+
lang_opts.PointerAuthVTPtrAddressDiscrimination =
515+
elf_pauth_abi_version & (1 << 2);
516+
lang_opts.PointerAuthVTPtrTypeDiscrimination =
517+
elf_pauth_abi_version & (1 << 3);
518+
lang_opts.PointerAuthInitFini = elf_pauth_abi_version & (1 << 4);
519+
}
520+
}
521+
485522
switch (language) {
486523
case lldb::eLanguageTypeC:
487524
case lldb::eLanguageTypeC89:
@@ -622,6 +659,10 @@ ClangExpressionParser::ClangExpressionParser(
622659
else
623660
m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::NoDebugInfo);
624661

662+
CompilerInvocation::setDefaultPointerAuthOptions(
663+
m_compiler->getCodeGenOpts().PointerAuth, lang_opts,
664+
target_arch.GetTriple());
665+
625666
// Disable some warnings.
626667
SetupDefaultClangDiagnostics(*m_compiler);
627668

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

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

1287+
std::optional<std::pair<uint64_t, uint64_t>>
1288+
ObjectFileELF::ParseGNUPropertyAArch64PAuthABI() {
1289+
// TODO: store parsing results in some kind of cache to avoid recurrent
1290+
// parsing on multiple calls
1291+
assert(m_arch_spec.GetMachine() == llvm::Triple::aarch64);
1292+
1293+
SectionList *SL = GetSectionList();
1294+
if (SL == nullptr)
1295+
return std::nullopt;
1296+
1297+
lldb::SectionSP GNUPropSecSP =
1298+
SL->FindSectionByName(ConstString(".note.gnu.property"));
1299+
if (GNUPropSecSP == nullptr)
1300+
return std::nullopt;
1301+
1302+
DataExtractor Data;
1303+
lldb::offset_t Length = GNUPropSecSP->GetSectionData(Data);
1304+
if (Length < 16)
1305+
return std::nullopt;
1306+
1307+
lldb::offset_t Offset = 0;
1308+
uint32_t NameSz = Data.GetU32(&Offset);
1309+
if (NameSz != 4)
1310+
return std::nullopt;
1311+
1312+
uint32_t ContentSz = Data.GetU32(&Offset);
1313+
if (ContentSz + 16 != Length) // the section is ill-formed
1314+
return std::nullopt;
1315+
uint32_t SectionType = Data.GetU32(&Offset);
1316+
if (SectionType != NT_GNU_PROPERTY_TYPE_0)
1317+
return std::nullopt;
1318+
1319+
llvm::StringRef Name = Data.GetCStr(&Offset, NameSz);
1320+
if (Name != "GNU")
1321+
return std::nullopt;
1322+
1323+
while (Offset < Length) {
1324+
lldb::offset_t OldOffset = Offset;
1325+
1326+
uint32_t FeatureType = Data.GetU32(&Offset);
1327+
uint32_t Size = Data.GetU32(&Offset);
1328+
if (OldOffset + 8 != Offset) // there were not enough bytes
1329+
return std::nullopt;
1330+
if (FeatureType != GNU_PROPERTY_AARCH64_FEATURE_PAUTH) {
1331+
Offset += Size;
1332+
Offset =
1333+
llvm::alignTo(Offset, (uint64_t(1) << GNUPropSecSP->GetLog2Align()));
1334+
continue;
1335+
}
1336+
if (Size != 16)
1337+
return std::nullopt;
1338+
1339+
uint64_t PAuthABIPlatform = Data.GetU64(&Offset);
1340+
uint64_t PAuthABIVersion = Data.GetU64(&Offset);
1341+
if (OldOffset + 24 != Offset) // there were not enough bytes
1342+
return std::nullopt;
1343+
return std::make_pair(PAuthABIPlatform, PAuthABIVersion);
1344+
}
1345+
1346+
return std::nullopt;
1347+
}
1348+
12871349
void ObjectFileELF::ParseARMAttributes(DataExtractor &data, uint64_t length,
12881350
ArchSpec &arch_spec) {
12891351
lldb::offset_t Offset = 0;

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <cstdint>
1313

1414
#include <optional>
15+
#include <utility>
1516
#include <vector>
1617

1718
#include "lldb/Symbol/ObjectFile.h"
@@ -155,6 +156,9 @@ class ObjectFileELF : public lldb_private::ObjectFile {
155156

156157
void RelocateSection(lldb_private::Section *section) override;
157158

159+
std::optional<std::pair<uint64_t, uint64_t>>
160+
ParseGNUPropertyAArch64PAuthABI() override;
161+
158162
protected:
159163

160164
std::vector<LoadableData>

lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,161 @@ TEST_F(ObjectFileELFTest, SectionsResolveConsistently) {
117117
EXPECT_EQ(text_sp, start->GetAddress().GetSection());
118118
}
119119

120+
TEST_F(ObjectFileELFTest, GNUPropertyAArch64PAuthABI) {
121+
// Successful parsing
122+
{
123+
llvm::StringRef SinglePropertyYaml = R"(
124+
--- !ELF
125+
FileHeader:
126+
Class: ELFCLASS64
127+
Data: ELFDATA2LSB
128+
Type: ET_DYN
129+
Machine: EM_AARCH64
130+
Sections:
131+
- Name: .note.gnu.property
132+
Type: SHT_NOTE
133+
Flags: [ SHF_ALLOC ]
134+
AddressAlign: 0x8
135+
Notes:
136+
- Name: GNU
137+
Desc: 010000C01000000002000000000000001F00000000000000
138+
# ^^^^^^^^
139+
# type = 0xC0000001 = GNU_PROPERTY_AARCH64_FEATURE_PAUTH
140+
# ^^^^^^^^
141+
# size = 0x00000010 = 16
142+
# ^^^^^^^^^^^^^^^^
143+
# platform = 0x0000000000000002 = 2
144+
# ^^^^^^^^^^^^^^^^
145+
# version = 0x000000000000001F = 31
146+
Type: NT_GNU_PROPERTY_TYPE_0
147+
...
148+
)";
149+
llvm::StringRef MultiplePropertiesYaml = R"(
150+
--- !ELF
151+
FileHeader:
152+
Class: ELFCLASS64
153+
Data: ELFDATA2LSB
154+
Type: ET_DYN
155+
Machine: EM_AARCH64
156+
Sections:
157+
- Name: .note.gnu.property
158+
Type: SHT_NOTE
159+
Flags: [ SHF_ALLOC ]
160+
AddressAlign: 0x8
161+
Notes:
162+
- Name: GNU
163+
Desc: 42424242040000001234567800000000010000C01000000002000000000000001F00000000000000
164+
# ^^^^^^^^
165+
# dummy property type = 0x42424242
166+
# ^^^^^^^^
167+
# dummy property size = 0x00000008 = 4
168+
# ^^^^^^^^________
169+
# dummy property contents = 0x78563412 and padding
170+
# ^^^^^^^^
171+
# type = 0xC0000001 = GNU_PROPERTY_AARCH64_FEATURE_PAUTH
172+
# ^^^^^^^^
173+
# size = 0x00000010 = 16
174+
# ^^^^^^^^^^^^^^^^
175+
# platform = 0x0000000000000002 = 2
176+
# ^^^^^^^^^^^^^^^^
177+
# version = 0x000000000000001F = 31
178+
Type: NT_GNU_PROPERTY_TYPE_0
179+
...
180+
)";
181+
std::array<llvm::Expected<TestFile>, 2> TestFiles = {
182+
TestFile::fromYaml(SinglePropertyYaml),
183+
TestFile::fromYaml(MultiplePropertiesYaml)};
184+
185+
for (auto &TF : TestFiles) {
186+
ASSERT_THAT_EXPECTED(TF, llvm::Succeeded());
187+
188+
auto module_sp = std::make_shared<Module>(TF->moduleSpec());
189+
ObjectFile *obj_file = module_sp->GetObjectFile();
190+
ASSERT_NE(nullptr, obj_file);
191+
192+
std::optional<std::pair<uint64_t, uint64_t>> pauthabi =
193+
obj_file->ParseGNUPropertyAArch64PAuthABI();
194+
ASSERT_NE(std::nullopt, pauthabi);
195+
ASSERT_EQ(uint64_t(2), pauthabi->first);
196+
ASSERT_EQ(uint64_t(31), pauthabi->second);
197+
}
198+
}
199+
200+
// Error during parsing
201+
{
202+
llvm::StringRef InvalidNameSizeYaml = R"(
203+
--- !ELF
204+
FileHeader:
205+
Class: ELFCLASS64
206+
Data: ELFDATA2LSB
207+
Type: ET_DYN
208+
Machine: EM_AARCH64
209+
Sections:
210+
- Name: .note.gnu.property
211+
Type: SHT_NOTE
212+
Flags: [ SHF_ALLOC ]
213+
AddressAlign: 0x8
214+
Notes:
215+
- Name: XXXXX
216+
Desc: 010000C01000000002000000000000001F00000000000000
217+
Type: NT_GNU_PROPERTY_TYPE_0
218+
...
219+
)";
220+
llvm::StringRef InvalidNameYaml = R"(
221+
--- !ELF
222+
FileHeader:
223+
Class: ELFCLASS64
224+
Data: ELFDATA2LSB
225+
Type: ET_DYN
226+
Machine: EM_AARCH64
227+
Sections:
228+
- Name: .note.gnu.property
229+
Type: SHT_NOTE
230+
Flags: [ SHF_ALLOC ]
231+
AddressAlign: 0x8
232+
Notes:
233+
- Name: XXX
234+
Desc: 010000C01000000002000000000000001F00000000000000
235+
Type: NT_GNU_PROPERTY_TYPE_0
236+
...
237+
)";
238+
llvm::StringRef InvalidPropertySizeYaml = R"(
239+
--- !ELF
240+
FileHeader:
241+
Class: ELFCLASS64
242+
Data: ELFDATA2LSB
243+
Type: ET_DYN
244+
Machine: EM_AARCH64
245+
Sections:
246+
- Name: .note.gnu.property
247+
Type: SHT_NOTE
248+
Flags: [ SHF_ALLOC ]
249+
AddressAlign: 0x8
250+
Notes:
251+
- Name: XXXXX
252+
Desc: 0000000000000000
253+
Type: NT_GNU_PROPERTY_TYPE_0
254+
...
255+
)";
256+
std::array<llvm::Expected<TestFile>, 3> TestFiles = {
257+
TestFile::fromYaml(InvalidNameSizeYaml),
258+
TestFile::fromYaml(InvalidNameYaml),
259+
TestFile::fromYaml(InvalidPropertySizeYaml)};
260+
261+
for (auto &TF : TestFiles) {
262+
ASSERT_THAT_EXPECTED(TF, llvm::Succeeded());
263+
264+
auto module_sp = std::make_shared<Module>(TF->moduleSpec());
265+
ObjectFile *obj_file = module_sp->GetObjectFile();
266+
ASSERT_NE(nullptr, obj_file);
267+
268+
std::optional<std::pair<uint64_t, uint64_t>> pauthabi =
269+
obj_file->ParseGNUPropertyAArch64PAuthABI();
270+
ASSERT_EQ(std::nullopt, pauthabi);
271+
}
272+
}
273+
}
274+
120275
// Test that GetModuleSpecifications works on an "atypical" object file which
121276
// has section headers right after the ELF header (instead of the more common
122277
// layout where the section headers are at the very end of the object file).

0 commit comments

Comments
 (0)