riscv64 SCS support.
Bug: https://github.com/google/android-riscv64/issues/55
Test: treehugger
Change-Id: I05d48a07a302305126942d38529ffa280640c7b7
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 7222b62..083c2ed 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -105,9 +105,13 @@
void* alternate_signal_stack;
- // The start address of the shadow call stack's guard region (arm64 only).
+ // The start address of the shadow call stack's guard region (arm64/riscv64).
+ // This region is SCS_GUARD_REGION_SIZE bytes large, but only SCS_SIZE bytes
+ // are actually used.
+ //
// This address is only used to deallocate the shadow call stack on thread
// exit; the address of the stack itself is stored only in the x18 register.
+ //
// Because the protection offered by SCS relies on the secrecy of the stack
// address, storing the address here weakens the protection, but only
// slightly, because it is relatively easy for an attacker to discover the
@@ -115,13 +119,22 @@
// to other allocations), but not the stack itself, which is <0.1% of the size
// of the guard region.
//
+ // longjmp()/setjmp() don't store all the bits of x18, only the bottom bits
+ // covered by SCS_MASK. Since longjmp()/setjmp() between different threads is
+ // undefined behavior (and unsupported on Android), we can retrieve the high
+ // bits of x18 from the current value in x18 --- all the jmp_buf needs to store
+ // is where exactly the shadow stack pointer is in the thread's shadow stack:
+ // the bottom bits of x18.
+ //
// There are at least two other options for discovering the start address of
// the guard region on thread exit, but they are not as simple as storing in
// TLS.
+ //
// 1) Derive it from the value of the x18 register. This is only possible in
// processes that do not contain legacy code that might clobber x18,
// therefore each process must declare early during process startup whether
// it might load legacy code.
+ // TODO: riscv64 has no legacy code, so we can actually go this route there!
// 2) Mark the guard region as such using prctl(PR_SET_VMA_ANON_NAME) and
// discover its address by reading /proc/self/maps. One issue with this is
// that reading /proc/self/maps can race with allocations, so we may need