[libc-commits] [libc] [libc] fortify jmp buffer for x86-64 (PR #112769)
Nick Desaulniers via libc-commits
libc-commits at lists.llvm.org
Thu Oct 31 09:31:23 PDT 2024
================
@@ -11,32 +11,82 @@
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
+#if LIBC_COPT_SETJMP_FORTIFICATION
+#include "src/setjmp/checksum.h"
+#endif
+
#if !defined(LIBC_TARGET_ARCH_IS_X86_64)
#error "Invalid file include"
#endif
namespace LIBC_NAMESPACE_DECL {
-[[gnu::naked]]
-LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) {
- asm(R"(
- cmpl $0x1, %%esi
- adcl $0x0, %%esi
- movq %%rsi, %%rax
-
- movq %c[rbx](%%rdi), %%rbx
- movq %c[rbp](%%rdi), %%rbp
- movq %c[r12](%%rdi), %%r12
- movq %c[r13](%%rdi), %%r13
- movq %c[r14](%%rdi), %%r14
- movq %c[r15](%%rdi), %%r15
- movq %c[rsp](%%rdi), %%rsp
- jmpq *%c[rip](%%rdi)
- )" ::[rbx] "i"(offsetof(__jmp_buf, rbx)),
- [rbp] "i"(offsetof(__jmp_buf, rbp)), [r12] "i"(offsetof(__jmp_buf, r12)),
- [r13] "i"(offsetof(__jmp_buf, r13)), [r14] "i"(offsetof(__jmp_buf, r14)),
- [r15] "i"(offsetof(__jmp_buf, r15)), [rsp] "i"(offsetof(__jmp_buf, rsp)),
- [rip] "i"(offsetof(__jmp_buf, rip)));
+#define CALCULATE_RETURN_VALUE() \
+ "cmpl $0x1, %%esi\n\t" \
+ "adcl $0x0, %%esi\n\t" \
+ "movq %%rsi, %%rax\n\t"
+
+#if LIBC_COPT_SETJMP_FORTIFICATION
+#include "src/setjmp/x86_64/checksum.def"
+
+// clang-format off
+#define RESTORE_REG(DST) \
+ "movq %c[" #DST "](%%rdi), %%rax\n\t" \
+ "movq %%rax, %%" #DST "\n\t" \
+ "xor %[mask], %%" #DST "\n\t" \
+ ACCUMULATE_CHECKSUM()
+
+#define RESTORE_RIP() \
+ "movq %c[rip](%%rdi), %%rax\n\t" \
+ "xor %%rax, %[mask]\n\t" \
+ ACCUMULATE_CHECKSUM() \
+ "cmp %c[__chksum](%%rdi), %%rdx\n\t" \
+ "jne __libc_jmpbuf_corruption\n\t" \
+ CALCULATE_RETURN_VALUE() \
+ "jmp *%[mask]\n\t"
+// clang-format on
+#else
+#define LOAD_CHKSUM_STATE_REGISTERS()
+#define RESTORE_REG(DST) "movq %c[" #DST "](%%rdi), %%" #DST "\n\t"
+#define RESTORE_RIP() \
+ CALCULATE_RETURN_VALUE() \
+ "jmpq *%c[rip](%%rdi)\n\t"
+#endif
+
+[[gnu::naked]] LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) {
+ // use registers to make sure values propagate correctly across the asm blocks
+ [[maybe_unused]] register __UINTPTR_TYPE__ mask asm("rcx");
+ [[maybe_unused]] register __UINT64_TYPE__ checksum asm("rdx");
+
+ LOAD_CHKSUM_STATE_REGISTERS()
+ asm volatile(
+ // clang-format off
+ RESTORE_REG(rbx)
+ RESTORE_REG(rbp)
+ RESTORE_REG(r12)
+ RESTORE_REG(r13)
+ RESTORE_REG(r14)
+ RESTORE_REG(r15)
+ RESTORE_REG(rsp)
+ RESTORE_RIP()
+ // clang-format on
+ : /* outputs */
+#if LIBC_COPT_SETJMP_FORTIFICATION
+ [mask] "+r"(mask), [checksum] "+r"(checksum)
----------------
nickdesaulniers wrote:
Does this work? (using `+c` and `+d` rather than declaring variables with explicit register storage)?
```suggestion
LOAD_CHKSUM_STATE_REGISTERS()
asm volatile(
// clang-format off
RESTORE_REG(rbx)
RESTORE_REG(rbp)
RESTORE_REG(r12)
RESTORE_REG(r13)
RESTORE_REG(r14)
RESTORE_REG(r15)
RESTORE_REG(rsp)
RESTORE_RIP()
// clang-format on
: /* outputs */
#if LIBC_COPT_SETJMP_FORTIFICATION
[mask] "+c"(mask), [checksum] "+d"(checksum)
```
Though I'm also curious why you're using rdx and rcx specifically?
https://github.com/llvm/llvm-project/pull/112769
More information about the libc-commits
mailing list