Skip to content

Commit 3252577

Browse files
committed
Advertise pointer authentication support to GDB
GDB uses the values of the provided pointer authentication mask registers to mask return addresses from the stack trace. Because we weren't providing these masks, the return addresses in the stack trace were incorrect in programs built with -mbranch-protection=pac-ret, such as most of Fedora. Fix it by advertising pointer authentication to GDB, and providing the correct masks. Fixes the following tests on PAC platforms: fork_exec_info_thr fork_exec_info_thr-no-syscallbuf vdso_clock_gettime_stack vdso_time_stack
1 parent b32fc69 commit 3252577

7 files changed

Lines changed: 45 additions & 2 deletions

src/ExtraRegisters.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,21 @@ size_t ExtraRegisters::read_register(uint8_t* buf, GdbServerRegister regno,
275275
} else if (regno == DREG_FPCR) {
276276
reg_data = RegData(offsetof(ARM64Arch::user_fpsimd_state, fpcr),
277277
sizeof(uint32_t));
278+
#ifdef __aarch64__
279+
} else if (regno == DREG_PAUTH_DMASK || regno == DREG_PAUTH_CMASK) {
280+
uint64_t ptr = 1ULL << 55;
281+
// The XPAC instruction will copy bit 55 of the argument into the PAC mask
282+
// bits, so ptr will be set to the mask plus bit 55.
283+
if (regno == DREG_PAUTH_DMASK) {
284+
__asm__ __volatile__(".arch armv8.3-a\nxpacd %0" : "+r"(ptr));
285+
} else {
286+
__asm__ __volatile__(".arch armv8.3-a\nxpaci %0" : "+r"(ptr));
287+
}
288+
uint64_t mask = ptr & ~(1ULL << 55);
289+
*defined = true;
290+
memcpy(buf, &mask, sizeof(mask));
291+
return sizeof(mask);
292+
#endif
278293
} else {
279294
*defined = false;
280295
return 0;

src/GdbServerConnection.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,18 @@
1818
#include <poll.h>
1919
#include <stdio.h>
2020
#include <stdlib.h>
21+
#include <sys/auxv.h>
2122
#include <sys/mman.h>
2223
#include <sys/socket.h>
2324
#include <sys/types.h>
2425
#include <unistd.h>
2526

27+
#ifdef __aarch64__
28+
#ifndef HWCAP_PACA
29+
#define HWCAP_PACA (1 << 30)
30+
#endif
31+
#endif
32+
2633
#include <iomanip>
2734
#include <sstream>
2835
#include <vector>
@@ -106,6 +113,11 @@ static uint32_t get_cpu_features(SupportedArch arch) {
106113
}
107114
case aarch64:
108115
cpu_features = GdbServerConnection::CPU_AARCH64;
116+
#ifdef __aarch64__
117+
if (getauxval(AT_HWCAP) & HWCAP_PACA) {
118+
cpu_features |= GdbServerConnection::CPU_PAUTH;
119+
}
120+
#endif
109121
break;
110122
default:
111123
FATAL() << "Unknown architecture";

src/GdbServerConnection.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,8 @@ class GdbServerConnection {
752752
CPU_AVX = 1 << 1,
753753
CPU_AARCH64 = 1 << 2,
754754
CPU_PKU = 1 << 3,
755-
CPU_AVX512 = 1 << 4
755+
CPU_AVX512 = 1 << 4,
756+
CPU_PAUTH = 1 << 5
756757
};
757758

758759
void set_cpu_features(SupportedArch arch);

src/GdbServerRegister.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,11 @@ enum GdbServerRegister {
320320
DREG_FPSR,
321321
DREG_FPCR,
322322

323-
DREG_NUM_LINUX_AARCH64 = DREG_FPCR + 1,
323+
// aarch64-pauth.xml
324+
DREG_PAUTH_DMASK,
325+
DREG_PAUTH_CMASK,
326+
327+
DREG_NUM_LINUX_AARCH64,
324328
};
325329

326330
} // namespace rr

src/Registers.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,10 @@ RegisterInfo<rr::ARM64Arch>::Table RegisterInfo<rr::ARM64Arch>::registers = {
180180
// comparison errors. This seems to be a unused/undocumented bit in SPSR as per aarch64
181181
// documentation anyways so ignore it.
182182
RV_AARCH64_WITH_MASK(CPSR, pstate, 0xffffffffLL & ~AARCH64_DBG_SPSR_SS & ~AARCH64_DBG_SPSR_11, 4),
183+
// PAuth masks. These aren't real registers, so we set the offset/size to 0
184+
// and use custom handling in read_register().
185+
RegisterInit(DREG_PAUTH_DMASK, RegisterValue("pauth_dmask", 0, 0)),
186+
RegisterInit(DREG_PAUTH_CMASK, RegisterValue("pauth_cmask", 0, 0)),
183187
};
184188

185189
#undef RV_X64

src/TargetDescription.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ FeatureStream& operator<<(FeatureStream& stream, TargetFeature feature) {
7878
case TargetFeature::FPU:
7979
stream << "fpu.xml";
8080
break;
81+
case TargetFeature::PAuth:
82+
stream << "pauth.xml";
83+
break;
8184
}
8285
stream << R"("/>)" << '\n';
8386
return stream;
@@ -103,6 +106,9 @@ TargetDescription::TargetDescription(rr::SupportedArch arch,
103106
case rr::aarch64:
104107
target_features.push_back(TargetFeature::Core);
105108
target_features.push_back(TargetFeature::FPU);
109+
if (cpu_features & rr::GdbServerConnection::CPU_PAUTH) {
110+
target_features.push_back(TargetFeature::PAuth);
111+
}
106112
break;
107113
}
108114

src/TargetDescription.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ enum class TargetFeature : uint32_t {
2020
AVX512,
2121
PKeys,
2222
FPU,
23+
PAuth,
2324
};
2425

2526
class TargetDescription {

0 commit comments

Comments
 (0)