Skip to content

Commit

Permalink
[lldb][Linux] Add Control Protection Fault signal (llvm#122917)
Browse files Browse the repository at this point in the history
This will be sent by Arm's Guarded Control Stack extension when an
invalid return is executed.

The signal does have an address we could show, but it's the PC at which
the fault occured. The debugger has plenty of ways to show you that
already, so I've left it out.

```
(lldb) c
Process 460 resuming
Process 460 stopped
* thread #1, name = 'test', stop reason = signal SIGSEGV: control protection fault
    frame #0: 0x0000000000400784 test`main at main.c:57:1
   54  	  afunc();
   55  	  printf("return from main\n");
   56  	  return 0;
-> 57  	}
(lldb) dis
<...>
->  0x400784 <+100>: ret
```

The new test case generates the signal by corrupting the link register
then attempting to return. This will work whether we manually enable GCS
or the C library does it for us.

(in the former case you could just return from main and it would fault)
  • Loading branch information
DavidSpickett authored Jan 21, 2025
1 parent 547bfda commit 5658bc4
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 1 deletion.
4 changes: 4 additions & 0 deletions lldb/source/Plugins/Process/Utility/LinuxSignals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
#ifndef SEGV_MTESERR
#define SEGV_MTESERR 9
#endif
#ifndef SEGV_CPERR
#define SEGV_CPERR 10
#endif

#define ADD_SIGCODE(signal_name, signal_value, code_name, code_value, ...) \
static_assert(signal_name == signal_value, \
Expand Down Expand Up @@ -82,6 +85,7 @@ void LinuxSignals::Reset() {
ADD_SIGCODE(SIGSEGV, 11, SEGV_BNDERR, 3, "failed address bounds checks", SignalCodePrintOption::Bounds);
ADD_SIGCODE(SIGSEGV, 11, SEGV_MTEAERR, 8, "async tag check fault");
ADD_SIGCODE(SIGSEGV, 11, SEGV_MTESERR, 9, "sync tag check fault", SignalCodePrintOption::Address);
ADD_SIGCODE(SIGSEGV, 11, SEGV_CPERR, 10, "control protection fault");
// Some platforms will occasionally send nonstandard spurious SI_KERNEL
// codes. One way to get this is via unaligned SIMD loads. Treat it as invalid address.
ADD_SIGCODE(SIGSEGV, 11, SI_KERNEL, 0x80, "invalid address", SignalCodePrintOption::Address);
Expand Down
22 changes: 22 additions & 0 deletions lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,25 @@ def test_gcs_region(self):

# Note that we must let the debugee get killed here as it cannot exit
# cleanly if GCS was manually enabled.

@skipUnlessArch("aarch64")
@skipUnlessPlatform(["linux"])
def test_gcs_fault(self):
if not self.isAArch64GCS():
self.skipTest("Target must support GCS.")

self.build()
self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
self.runCmd("run", RUN_SUCCEEDED)

if self.process().GetState() == lldb.eStateExited:
self.fail("Test program failed to run.")

self.expect(
"thread list",
"Expected stopped by SIGSEGV.",
substrs=[
"stopped",
"stop reason = signal SIGSEGV: control protection fault",
],
)
17 changes: 16 additions & 1 deletion lldb/test/API/linux/aarch64/gcs/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ unsigned long get_gcs_status() {
return mode;
}

void gcs_signal() {
// If we enabled GCS manually, then we could just return from main to generate
// a signal. However, if the C library enabled it, then we'd just exit
// normally. Assume the latter, and try to return to some bogus address to
// generate the signal.
__asm__ __volatile__(
// Corrupt the link register. This could be many numbers but 16 is a
// nicely aligned value that is unlikely to result in a fault because the
// PC is misaligned, which would hide the GCS fault.
"add x30, x30, #10\n"
"ret\n");
}

int main() {
if (!(getauxval(AT_HWCAP2) & HWCAP2_GCS))
return 1;
Expand All @@ -50,5 +63,7 @@ int main() {
}

// By now we should have one memory region where the GCS is stored.
return 0; // Set break point at this line.
gcs_signal(); // Set break point at this line.

return 0;
}

0 comments on commit 5658bc4

Please sign in to comment.