Skip to content

Commit 3436294

Browse files
committed
Check what happens if we fail to setup the gcs
1 parent 3fe267f commit 3436294

File tree

2 files changed

+37
-13
lines changed

2 files changed

+37
-13
lines changed

lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,21 @@ static Status PushToLinuxGuardedControlStack(addr_t return_addr,
101101
Status error;
102102
size_t wrote = thread.GetProcess()->WriteMemory(gcspr_el0, &return_addr,
103103
sizeof(return_addr), error);
104-
if ((wrote != sizeof(return_addr) || error.Fail()))
104+
if ((wrote != sizeof(return_addr) || error.Fail())) {
105+
// When PrepareTrivialCall fails, the register context is not restored,
106+
// unlike when an expression fails to execute. This is arguably a bug,
107+
// see https://github.com/llvm/llvm-project/issues/124269.
108+
// For now we are handling this here specifically. We can assume this
109+
// write will work as the one to decrement the register did.
110+
reg_ctx->WriteRegisterFromUnsigned(gcspr_el0_info, gcspr_el0 + 8);
105111
return Status("Failed to write new Guarded Control Stack entry.");
112+
}
106113

107114
Log *log = GetLog(LLDBLog::Expressions);
108115
LLDB_LOGF(log,
109-
"Pushed return address 0x%" PRIx64 "to Guarded Control Stack. "
116+
"Pushed return address 0x%" PRIx64 " to Guarded Control Stack. "
110117
"gcspr_el0 was 0%" PRIx64 ", is now 0x%" PRIx64 ".",
111-
return_addr, gcspr_el0 + 8, gcspr_el0);
118+
return_addr, gcspr_el0 - 8, gcspr_el0);
112119

113120
// gcspr_el0 will be restored to the original value by lldb-server after
114121
// the call has finished, which serves as the "pop".
@@ -143,6 +150,18 @@ bool ABISysV_arm64::PrepareTrivialCall(Thread &thread, addr_t sp,
143150
if (args.size() > 8)
144151
return false;
145152

153+
// Do this first, as it's got the most chance of failing (though still very
154+
// low).
155+
if (GetProcessSP()->GetTarget().GetArchitecture().GetTriple().isOSLinux()) {
156+
Status err = PushToLinuxGuardedControlStack(return_addr, reg_ctx, thread);
157+
// If we could not manage the GCS, the expression will certainly fail,
158+
// and if we just carried on, that failure would be a lot more cryptic.
159+
if (err.Fail()) {
160+
LLDB_LOGF(log, "Failed to setup Guarded Call Stack: %s", err.AsCString());
161+
return false;
162+
}
163+
}
164+
146165
for (size_t i = 0; i < args.size(); ++i) {
147166
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(
148167
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i);
@@ -159,16 +178,6 @@ bool ABISysV_arm64::PrepareTrivialCall(Thread &thread, addr_t sp,
159178
return_addr))
160179
return false;
161180

162-
if (GetProcessSP()->GetTarget().GetArchitecture().GetTriple().isOSLinux()) {
163-
Status err = PushToLinuxGuardedControlStack(return_addr, reg_ctx, thread);
164-
// If we could not manage the GCS, the expression will certainly fail,
165-
// and if we just carried on, that failure would be a lot more cryptic.
166-
if (err.Fail()) {
167-
LLDB_LOGF(log, "Failed to setup Guarded Call Stack: %s", err.AsCString());
168-
return false;
169-
}
170-
}
171-
172181
// Set "sp" to the requested value
173182
if (!reg_ctx->WriteRegisterFromUnsigned(
174183
reg_ctx->GetRegisterInfo(eRegisterKindGeneric,

lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,12 +281,27 @@ def test_gcs_expression_simple(self):
281281
substrs=["stopped", "stop reason = breakpoint"],
282282
)
283283

284+
# If we fail to setup the GCS entry, we should not leave any of the GCS registers
285+
# changed. The last thing we do is write a new GCS entry to memory and
286+
# to simulate the failure of that, temporarily point the GCS to the zero page.
287+
#
288+
# We use the value 8 here because LLDB will decrement it by 8 so it points to
289+
# what we think will be an empty entry on the guarded control stack.
290+
_, _, original_gcspr = self.check_gcs_registers()
291+
self.runCmd("register write gcspr_el0 8")
292+
before = self.check_gcs_registers()
293+
self.expect(expr_cmd, error=True)
294+
self.check_gcs_registers(*before)
295+
# Point to the valid shadow stack region again.
296+
self.runCmd(f"register write gcspr_el0 {original_gcspr}")
297+
284298
# This time we do need to push to the GCS and having done so, we can
285299
# return from this expression without causing a fault.
286300
before = self.check_gcs_registers()
287301
self.expect(expr_cmd, substrs=["(unsigned long) 1"])
288302
self.check_gcs_registers(*before)
289303

304+
290305
@skipUnlessPlatform(["linux"])
291306
def test_gcs_expression_disable_gcs(self):
292307
if not self.isAArch64GCS():

0 commit comments

Comments
 (0)