[libc-commits] [libc] [libc] fortify jmp buffer for x86-64 (PR #112769)

Schrodinger ZHU Yifan via libc-commits libc-commits at lists.llvm.org
Tue Nov 12 15:09:55 PST 2024


https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/112769

>From 3a4cf216ab1cbb06ea9b79bb4886088eb319ac76 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 17 Oct 2024 15:52:21 -0400
Subject: [PATCH 1/7] [libc] fortify jmp buffer

---
 libc/config/config.json                |   4 +
 libc/docs/configure.rst                |   1 +
 libc/include/llvm-libc-types/jmp_buf.h |   2 +
 libc/src/setjmp/CMakeLists.txt         |  18 +++++
 libc/src/setjmp/checksum.h             |  46 +++++++++++
 libc/src/setjmp/x86_64/CMakeLists.txt  |   4 +
 libc/src/setjmp/x86_64/longjmp.cpp     |  95 +++++++++++++---------
 libc/src/setjmp/x86_64/setjmp.cpp      | 104 +++++++++++++++----------
 libc/startup/linux/CMakeLists.txt      |   1 +
 libc/startup/linux/do_start.cpp        |   3 +-
 10 files changed, 203 insertions(+), 75 deletions(-)
 create mode 100644 libc/src/setjmp/checksum.h

diff --git a/libc/config/config.json b/libc/config/config.json
index 9a5d5c3c68da60..bea2b49967bcf4 100644
--- a/libc/config/config.json
+++ b/libc/config/config.json
@@ -103,6 +103,10 @@
     "LIBC_CONF_SETJMP_AARCH64_RESTORE_PLATFORM_REGISTER": {
       "value": true,
       "doc": "Make setjmp save the value of x18, and longjmp restore it. The AArch64 ABI delegates this register to platform ABIs, which can choose whether to make it caller-saved."
+    },
+    "LIBC_CONF_SETJMP_ENABLE_FORTIFICATION": {
+      "value": true,
+      "doc": "Enable fortification for setjmp and longjmp."
     }
   },
   "time": {
diff --git a/libc/docs/configure.rst b/libc/docs/configure.rst
index 3db750b1aed214..612da3c994f105 100644
--- a/libc/docs/configure.rst
+++ b/libc/docs/configure.rst
@@ -55,6 +55,7 @@ to learn about the defaults for your platform and target.
     - ``LIBC_CONF_SCANF_DISABLE_INDEX_MODE``: Disable index mode in the scanf format string.
 * **"setjmp" options**
     - ``LIBC_CONF_SETJMP_AARCH64_RESTORE_PLATFORM_REGISTER``: Make setjmp save the value of x18, and longjmp restore it. The AArch64 ABI delegates this register to platform ABIs, which can choose whether to make it caller-saved.
+    - ``LIBC_CONF_SETJMP_ENABLE_FORTIFICATION``: Enable fortification for setjmp and longjmp.
 * **"string" options**
     - ``LIBC_CONF_MEMSET_X86_USE_SOFTWARE_PREFETCHING``: Inserts prefetch for write instructions (PREFETCHW) for memset on x86 to recover performance when hardware prefetcher is disabled.
     - ``LIBC_CONF_STRING_UNSAFE_WIDE_READ``: Read more than a byte at a time to perform byte-string operations like strlen.
diff --git a/libc/include/llvm-libc-types/jmp_buf.h b/libc/include/llvm-libc-types/jmp_buf.h
index f246e6491cf554..76acaf107f9dc1 100644
--- a/libc/include/llvm-libc-types/jmp_buf.h
+++ b/libc/include/llvm-libc-types/jmp_buf.h
@@ -50,6 +50,8 @@ typedef struct {
 #else
 #error "__jmp_buf not available for your target architecture."
 #endif
+  // unused if checksum feature is not enabled.
+  __UINT64_TYPE__ __chksum;
 } __jmp_buf;
 
 typedef __jmp_buf jmp_buf[1];
diff --git a/libc/src/setjmp/CMakeLists.txt b/libc/src/setjmp/CMakeLists.txt
index d85c532e8636c8..a90c3e177fb739 100644
--- a/libc/src/setjmp/CMakeLists.txt
+++ b/libc/src/setjmp/CMakeLists.txt
@@ -2,6 +2,24 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
   add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
 endif()
 
+if (LIBC_CONF_SETJMP_ENABLE_FORTIFICATION)
+  set(checksum_flags "-DLIBC_SETJMP_ENABLE_FORTIFICATION=1")
+else()
+  set(checksum_flags "-DLIBC_SETJMP_ENABLE_FORTIFICATION=0")
+endif()
+
+
+add_header_library(
+  checksum
+  HDRS
+    checksum.h
+  DEPENDS
+    libc.src.__support.common
+    libc.src.__support.OSUtil.osutil
+  COMPILE_OPTIONS
+    ${checksum_flags}
+)
+
 add_entrypoint_object(
   setjmp
   ALIAS
diff --git a/libc/src/setjmp/checksum.h b/libc/src/setjmp/checksum.h
new file mode 100644
index 00000000000000..df6a12d185c3ee
--- /dev/null
+++ b/libc/src/setjmp/checksum.h
@@ -0,0 +1,46 @@
+//===-- Implementation header for jmpbuf checksum ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SETJMP_CHECKSUM_H
+#define LLVM_LIBC_SRC_SETJMP_CHECKSUM_H
+
+#ifndef LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+#define LIBC_COPT_SETJMP_ENABLE_FORTIFICATION 1
+#endif
+
+#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+#include "src/__support/OSUtil/syscall.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h>
+
+namespace LIBC_NAMESPACE_DECL {
+namespace jmpbuf {
+// random bytes from https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h
+LIBC_INLINE __UINTPTR_TYPE__ value_mask = 0x3899'f0d3'5005'd953;
+LIBC_INLINE __UINT64_TYPE__ checksum_cookie = 0xc7d9'd341'6afc'33f2;
+// abitrary prime number
+LIBC_INLINE constexpr __UINT64_TYPE__ ROTATION = 13;
+// initialize the checksum state
+LIBC_INLINE void initialize() {
+  union {
+    struct {
+      __UINTPTR_TYPE__ entropy0;
+      __UINT64_TYPE__ entropy1;
+    };
+    char buffer[sizeof(__UINTPTR_TYPE__) + sizeof(__UINT64_TYPE__)];
+  };
+  syscall_impl<long>(SYS_getrandom, buffer, sizeof(buffer), 0);
+  // add in additional entropy
+  jmpbuf::value_mask ^= entropy0;
+  jmpbuf::checksum_cookie ^= entropy1;
+}
+} // namespace jmpbuf
+} // namespace LIBC_NAMESPACE_DECL
+#endif // LIBC_SETJMP_ENABLE_FORTIFICATION
+
+#endif // LLVM_LIBC_SRC_SETJMP_CHECKSUM_H
diff --git a/libc/src/setjmp/x86_64/CMakeLists.txt b/libc/src/setjmp/x86_64/CMakeLists.txt
index b5b0d9ba65599c..571f3681887106 100644
--- a/libc/src/setjmp/x86_64/CMakeLists.txt
+++ b/libc/src/setjmp/x86_64/CMakeLists.txt
@@ -6,6 +6,7 @@ add_entrypoint_object(
     ../setjmp_impl.h
   DEPENDS
     libc.hdr.types.jmp_buf
+    libc.src.setjmp.checksum
   COMPILE_OPTIONS
     -O3
 )
@@ -18,6 +19,9 @@ add_entrypoint_object(
     ../longjmp.h
   DEPENDS
     libc.hdr.types.jmp_buf
+    libc.src.stdlib.abort
+    libc.src.__support.OSUtil.osutil
+    libc.src.setjmp.checksum
   COMPILE_OPTIONS
     -O3
     -fomit-frame-pointer
diff --git a/libc/src/setjmp/x86_64/longjmp.cpp b/libc/src/setjmp/x86_64/longjmp.cpp
index 143c9deb11e9aa..c3a28333b3ef0a 100644
--- a/libc/src/setjmp/x86_64/longjmp.cpp
+++ b/libc/src/setjmp/x86_64/longjmp.cpp
@@ -8,8 +8,11 @@
 
 #include "src/setjmp/longjmp.h"
 #include "include/llvm-libc-macros/offsetof-macro.h"
+#include "src/__support/OSUtil/io.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
+#include "src/setjmp/checksum.h"
+#include "src/stdlib/abort.h"
 
 #if !defined(LIBC_TARGET_ARCH_IS_X86)
 #error "Invalid file include"
@@ -17,49 +20,71 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-#ifdef __i386__
-[[gnu::naked]]
-LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) {
-  asm(R"(
-      mov 0x4(%%esp), %%ecx
-      mov 0x8(%%esp), %%eax
-      cmpl $0x1, %%eax
-      adcl $0x0, %%eax
+#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+extern "C" [[gnu::cold, noreturn]] void __libc_jmpbuf_corruption() {
+  write_to_stderr("invalid checksum detected in longjmp\n");
+  abort();
+}
+#define LOAD_CHKSUM_STATE_REGISTERS()                                          \
+  asm("mov %0, %%rcx\n\t" ::"m"(jmpbuf::value_mask) : "rcx");                  \
+  asm("mov %0, %%rdx\n\t" ::"m"(jmpbuf::checksum_cookie) : "rdx");
 
-      mov %c[ebx](%%ecx), %%ebx
-      mov %c[esi](%%ecx), %%esi
-      mov %c[edi](%%ecx), %%edi
-      mov %c[ebp](%%ecx), %%ebp
-      mov %c[esp](%%ecx), %%esp
+#define RESTORE_REG(DST)                                                       \
+  "movq %c[" #DST "](%%rdi), %%rax\n\t"                                        \
+  "movq %%rax, %%" #DST "\n\t"                                                 \
+  "xor %%rcx, %%" #DST "\n\t"                                                  \
+  "mul %%rdx\n\t"                                                              \
+  "xor %%rax, %%rdx\n\t"                                                       \
+  "rol $%c[rotation], %%rdx\n\t"
 
-      jmp *%c[eip](%%ecx)
-      )" ::[ebx] "i"(offsetof(__jmp_buf, ebx)),
-      [esi] "i"(offsetof(__jmp_buf, esi)), [edi] "i"(offsetof(__jmp_buf, edi)),
-      [ebp] "i"(offsetof(__jmp_buf, ebp)), [esp] "i"(offsetof(__jmp_buf, esp)),
-      [eip] "i"(offsetof(__jmp_buf, eip)));
-}
+#define RESTORE_RIP()                                                          \
+  "movq %c[rip](%%rdi), %%rax\n\t"                                             \
+  "xor %%rax, %%rcx\n\t"                                                       \
+  "mul %%rdx\n\t"                                                              \
+  "xor %%rax, %%rdx\n\t"                                                       \
+  "rol $%c[rotation], %%rdx\n\t"                                               \
+  "cmp %c[chksum](%%rdi), %%rdx\n\t"                                           \
+  "jne __libc_jmpbuf_corruption\n\t"                                           \
+  "cmpl $0x1, %%esi\n\t"                                                       \
+  "adcl $0x0, %%esi\n\t"                                                       \
+  "movq %%rsi, %%rax\n\t"                                                      \
+  "jmp *%%rcx\n\t"
 #else
+#define LOAD_CHKSUM_STATE_REGISTERS()
+#define RESTORE_REG(DST) "movq %c[" #DST "](%%rdi), %%" #DST "\n\t"
+#define RESTORE_RIP()                                                          \
+  "cmpl $0x1, %%esi\n\t"                                                       \
+  "adcl $0x0, %%esi\n\t"                                                       \
+  "movq %%rsi, %%rax\n\t"                                                      \
+  "jmpq *%c[rip](%%rdi)\n\t"
+#endif
+
 [[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)),
+  LOAD_CHKSUM_STATE_REGISTERS()
+  asm(
+      // 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
+      ::[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)));
-}
+      [rip] "i"(offsetof(__jmp_buf, rip))
+#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+      // clang-format off
+      ,[rotation] "i"(jmpbuf::ROTATION)
+      , [chksum] "i"(offsetof(__jmp_buf, __chksum))
+  // clang-format on
 #endif
+      : "rax", "rdx", "rcx", "rsi");
+}
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/setjmp/x86_64/setjmp.cpp b/libc/src/setjmp/x86_64/setjmp.cpp
index 5ac10fa87b39a3..14af3cb24c2a5a 100644
--- a/libc/src/setjmp/x86_64/setjmp.cpp
+++ b/libc/src/setjmp/x86_64/setjmp.cpp
@@ -9,62 +9,88 @@
 #include "include/llvm-libc-macros/offsetof-macro.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
+#include "src/setjmp/checksum.h"
 #include "src/setjmp/setjmp_impl.h"
 
 #if !defined(LIBC_TARGET_ARCH_IS_X86)
 #error "Invalid file include"
 #endif
 
-namespace LIBC_NAMESPACE_DECL {
-
-#ifdef __i386__
-[[gnu::naked]]
-LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) {
-  asm(R"(
-      mov 4(%%esp), %%eax
+#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+#define LOAD_CHKSUM_STATE_REGISTERS()                                          \
+  asm("mov %0, %%rcx\n\t" ::"m"(jmpbuf::value_mask) : "rcx");                  \
+  asm("mov %0, %%rdx\n\t" ::"m"(jmpbuf::checksum_cookie) : "rdx");
 
-      mov %%ebx, %c[ebx](%%eax)
-      mov %%esi, %c[esi](%%eax)
-      mov %%edi, %c[edi](%%eax)
-      mov %%ebp, %c[ebp](%%eax)
+#define STORE_REG(SRC)                                                         \
+  "mov %%" #SRC ", %%rax\n\t"                                                  \
+  "xor %%rcx, %%rax\n\t"                                                       \
+  "mov %%rax, %c[" #SRC "](%%rdi)\n\t"                                         \
+  "mul %%rdx\n\t"                                                              \
+  "xor %%rax, %%rdx\n\t"                                                       \
+  "rol $%c[rotation], %%rdx\n\t"
 
-      lea 4(%%esp), %%ecx
-      mov %%ecx, %c[esp](%%eax)
+#define STORE_RSP()                                                            \
+  "lea 8(%%rsp), %%rax\n\t"                                                    \
+  "xor %%rcx, %%rax\n\t"                                                       \
+  "mov %%rax, %c[rsp](%%rdi)\n\t"                                              \
+  "mul %%rdx\n\t"                                                              \
+  "xor %%rax, %%rdx\n\t"                                                       \
+  "rolq $%c[rotation], %%rdx\n\t"
 
-      mov (%%esp), %%ecx
-      mov %%ecx, %c[eip](%%eax)
+#define STORE_RIP()                                                            \
+  "mov (%%rsp), %%rax\n\t"                                                     \
+  "xor %%rcx, %%rax\n\t"                                                       \
+  "mov %%rax, %c[rip](%%rdi)\n\t"                                              \
+  "mul %%rdx\n\t"                                                              \
+  "xor %%rax, %%rdx\n\t"                                                       \
+  "rolq $%c[rotation], %%rdx\n\t"
 
-      xorl %%eax, %%eax
-      retl)" ::[ebx] "i"(offsetof(__jmp_buf, ebx)),
-      [esi] "i"(offsetof(__jmp_buf, esi)), [edi] "i"(offsetof(__jmp_buf, edi)),
-      [ebp] "i"(offsetof(__jmp_buf, ebp)), [esp] "i"(offsetof(__jmp_buf, esp)),
-      [eip] "i"(offsetof(__jmp_buf, eip))
-      : "eax", "ecx");
-}
+#define STORE_CHECKSUM() "mov %%rdx, %c[chksum](%%rdi)\n\t"
 #else
+#define LOAD_CHKSUM_STATE_REGISTERS()
+#define STORE_REG(SRC) "mov %%" #SRC ", %c[" #SRC "](%%rdi)\n\t"
+#define STORE_RSP()                                                            \
+  "lea 8(%%rsp), %%rax\n\t"                                                    \
+  "mov %%rax, %c[rsp](%%rdi)\n\t"
+#define STORE_RIP()                                                            \
+  "mov (%%rsp), %%rax\n\t"                                                     \
+  "mov %%rax, %c[rip](%%rdi)\n\t"
+#define STORE_CHECKSUM()
+#endif
+
+namespace LIBC_NAMESPACE_DECL {
 [[gnu::naked]]
 LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) {
-  asm(R"(
-      mov %%rbx, %c[rbx](%%rdi)
-      mov %%rbp, %c[rbp](%%rdi)
-      mov %%r12, %c[r12](%%rdi)
-      mov %%r13, %c[r13](%%rdi)
-      mov %%r14, %c[r14](%%rdi)
-      mov %%r15, %c[r15](%%rdi)
-
-      lea 8(%%rsp), %%rax
-      mov %%rax, %c[rsp](%%rdi)
-
-      mov (%%rsp), %%rax
-      mov %%rax, %c[rip](%%rdi)
-
-      xorl %%eax, %%eax
-      retq)" ::[rbx] "i"(offsetof(__jmp_buf, rbx)),
+  LOAD_CHKSUM_STATE_REGISTERS()
+  asm(
+      // clang-format off
+    STORE_REG(rbx)
+    STORE_REG(rbp)
+    STORE_REG(r12)
+    STORE_REG(r13)
+    STORE_REG(r14)
+    STORE_REG(r15)
+    STORE_RSP()
+    STORE_RIP()
+    STORE_CHECKSUM()
+      // clang-format on
+      ::[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))
-      : "rax");
+#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+      // clang-format off
+      ,[rotation] "i"(jmpbuf::ROTATION)
+      ,[chksum] "i"(offsetof(__jmp_buf, __chksum))
+  // clang-format on
+#endif
+      : "rax", "rdx");
+
+  asm(R"(
+    xorl %eax, %eax
+    retq
+  )");
 }
 #endif
 
diff --git a/libc/startup/linux/CMakeLists.txt b/libc/startup/linux/CMakeLists.txt
index eaa724e41f1685..34c870f98b1f1c 100644
--- a/libc/startup/linux/CMakeLists.txt
+++ b/libc/startup/linux/CMakeLists.txt
@@ -104,6 +104,7 @@ add_object_library(
     libc.src.stdlib.exit
     libc.src.stdlib.atexit
     libc.src.unistd.environ
+    libc.src.setjmp.checksum
   COMPILE_OPTIONS
     -ffreestanding       # To avoid compiler warnings about calling the main function.
     -fno-builtin         # avoid emit unexpected calls
diff --git a/libc/startup/linux/do_start.cpp b/libc/startup/linux/do_start.cpp
index ff104c7f0d1d2f..fc40ac0b1b1095 100644
--- a/libc/startup/linux/do_start.cpp
+++ b/libc/startup/linux/do_start.cpp
@@ -11,6 +11,7 @@
 #include "src/__support/OSUtil/syscall.h"
 #include "src/__support/macros/config.h"
 #include "src/__support/threads/thread.h"
+#include "src/setjmp/checksum.h"
 #include "src/stdlib/atexit.h"
 #include "src/stdlib/exit.h"
 #include "src/unistd/environ.h"
@@ -130,7 +131,7 @@ void teardown_main_tls() { cleanup_tls(tls.addr, tls.size); }
   init_tls(tls);
   if (tls.size != 0 && !set_thread_ptr(tls.tp))
     syscall_impl<long>(SYS_exit, 1);
-
+  jmpbuf::initialize();
   self.attrib = &main_thread_attrib;
   main_thread_attrib.atexit_callback_mgr =
       internal::get_thread_atexit_callback_mgr();

>From 2bb6a32e4328b6cfacb61f2357feccbdf718acd6 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 17 Oct 2024 15:54:19 -0400
Subject: [PATCH 2/7] [libc] fortify jmp buffer

---
 libc/src/setjmp/CMakeLists.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/src/setjmp/CMakeLists.txt b/libc/src/setjmp/CMakeLists.txt
index a90c3e177fb739..6ceaaa8dd3a3f7 100644
--- a/libc/src/setjmp/CMakeLists.txt
+++ b/libc/src/setjmp/CMakeLists.txt
@@ -3,9 +3,9 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
 endif()
 
 if (LIBC_CONF_SETJMP_ENABLE_FORTIFICATION)
-  set(checksum_flags "-DLIBC_SETJMP_ENABLE_FORTIFICATION=1")
+  set(checksum_flags "-DLIBC_COPT_SETJMP_ENABLE_FORTIFICATION=1")
 else()
-  set(checksum_flags "-DLIBC_SETJMP_ENABLE_FORTIFICATION=0")
+  set(checksum_flags "-DLIBC_COPT_SETJMP_ENABLE_FORTIFICATION=0")
 endif()
 
 

>From 7901be16e1a06490017984e3f72e9e161c36ff6c Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 17 Oct 2024 15:55:57 -0400
Subject: [PATCH 3/7] [libc] fortify jmp buffer

---
 libc/src/setjmp/x86_64/longjmp.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/setjmp/x86_64/longjmp.cpp b/libc/src/setjmp/x86_64/longjmp.cpp
index c3a28333b3ef0a..ef638a296e07a9 100644
--- a/libc/src/setjmp/x86_64/longjmp.cpp
+++ b/libc/src/setjmp/x86_64/longjmp.cpp
@@ -81,7 +81,7 @@ LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) {
 #if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
       // clang-format off
       ,[rotation] "i"(jmpbuf::ROTATION)
-      , [chksum] "i"(offsetof(__jmp_buf, __chksum))
+      ,[chksum] "i"(offsetof(__jmp_buf, __chksum))
   // clang-format on
 #endif
       : "rax", "rdx", "rcx", "rsi");

>From f591ed8a4543411b8ff2ab305163ee6724cc99e4 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Fri, 18 Oct 2024 10:05:03 -0400
Subject: [PATCH 4/7] [libc] fix startup

---
 libc/startup/linux/do_start.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/libc/startup/linux/do_start.cpp b/libc/startup/linux/do_start.cpp
index fc40ac0b1b1095..55d85c90fca44b 100644
--- a/libc/startup/linux/do_start.cpp
+++ b/libc/startup/linux/do_start.cpp
@@ -131,7 +131,11 @@ void teardown_main_tls() { cleanup_tls(tls.addr, tls.size); }
   init_tls(tls);
   if (tls.size != 0 && !set_thread_ptr(tls.tp))
     syscall_impl<long>(SYS_exit, 1);
+
+#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
   jmpbuf::initialize();
+#endif
+
   self.attrib = &main_thread_attrib;
   main_thread_attrib.atexit_callback_mgr =
       internal::get_thread_atexit_callback_mgr();

>From 3bdd8a8ef016028f36fe0d99bd6dda6622193637 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Fri, 18 Oct 2024 11:24:34 -0400
Subject: [PATCH 5/7] [libc] address CRs

---
 libc/config/config.json               |  2 +-
 libc/docs/configure.rst               |  2 +-
 libc/src/setjmp/CMakeLists.txt        | 36 +++++++------
 libc/src/setjmp/checksum.h            | 33 +++---------
 libc/src/setjmp/linux/CMakeLists.txt  | 11 ++++
 libc/src/setjmp/linux/checksum.cpp    | 42 +++++++++++++++
 libc/src/setjmp/x86_64/CMakeLists.txt |  8 +--
 libc/src/setjmp/x86_64/longjmp.cpp    | 78 +++++++++++++++------------
 libc/src/setjmp/x86_64/setjmp.cpp     | 63 +++++++++++++---------
 libc/startup/linux/CMakeLists.txt     | 11 +++-
 libc/startup/linux/do_start.cpp       |  5 +-
 11 files changed, 182 insertions(+), 109 deletions(-)
 create mode 100644 libc/src/setjmp/linux/CMakeLists.txt
 create mode 100644 libc/src/setjmp/linux/checksum.cpp

diff --git a/libc/config/config.json b/libc/config/config.json
index bea2b49967bcf4..f2cf98f8678e45 100644
--- a/libc/config/config.json
+++ b/libc/config/config.json
@@ -106,7 +106,7 @@
     },
     "LIBC_CONF_SETJMP_ENABLE_FORTIFICATION": {
       "value": true,
-      "doc": "Enable fortification for setjmp and longjmp."
+      "doc": "Protect jmp_buf by masking its contents and storing a simple checksum, to make it harder for an attacker to read meaningful information from a jmp_buf or to modify it. This is only supported on x86-64 Linux."
     }
   },
   "time": {
diff --git a/libc/docs/configure.rst b/libc/docs/configure.rst
index 612da3c994f105..73f66e303132b8 100644
--- a/libc/docs/configure.rst
+++ b/libc/docs/configure.rst
@@ -55,7 +55,7 @@ to learn about the defaults for your platform and target.
     - ``LIBC_CONF_SCANF_DISABLE_INDEX_MODE``: Disable index mode in the scanf format string.
 * **"setjmp" options**
     - ``LIBC_CONF_SETJMP_AARCH64_RESTORE_PLATFORM_REGISTER``: Make setjmp save the value of x18, and longjmp restore it. The AArch64 ABI delegates this register to platform ABIs, which can choose whether to make it caller-saved.
-    - ``LIBC_CONF_SETJMP_ENABLE_FORTIFICATION``: Enable fortification for setjmp and longjmp.
+    - ``LIBC_CONF_SETJMP_ENABLE_FORTIFICATION``: Protect jmp_buf by masking its contents and storing a simple checksum, to make it harder for an attacker to read meaningful information from a jmp_buf or to modify it. This is only supported on x86-64 Linux.
 * **"string" options**
     - ``LIBC_CONF_MEMSET_X86_USE_SOFTWARE_PREFETCHING``: Inserts prefetch for write instructions (PREFETCHW) for memset on x86 to recover performance when hardware prefetcher is disabled.
     - ``LIBC_CONF_STRING_UNSAFE_WIDE_READ``: Read more than a byte at a time to perform byte-string operations like strlen.
diff --git a/libc/src/setjmp/CMakeLists.txt b/libc/src/setjmp/CMakeLists.txt
index 6ceaaa8dd3a3f7..21ac0b6ba52e25 100644
--- a/libc/src/setjmp/CMakeLists.txt
+++ b/libc/src/setjmp/CMakeLists.txt
@@ -1,24 +1,28 @@
-if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
-  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
 endif()
 
 if (LIBC_CONF_SETJMP_ENABLE_FORTIFICATION)
-  set(checksum_flags "-DLIBC_COPT_SETJMP_ENABLE_FORTIFICATION=1")
-else()
-  set(checksum_flags "-DLIBC_COPT_SETJMP_ENABLE_FORTIFICATION=0")
+  if (TARGET libc.src.setjmp.${LIBC_TARGET_OS}.checksum
+      AND LIBC_TARGET_ARCHITECTURE STREQUAL "x86_64")
+    add_object_library(
+      checksum
+      ALIAS
+      DEPENDS
+        .${LIBC_TARGET_OS}.checksum
+    )
+    set(fortification_deps libc.src.setjmp.checksum)
+    set(fortification_defs -DLIBC_COPT_SETJMP_ENABLE_FORTIFICATION=1)
+  else()
+    message(WARNING "Jmpbuf fortification is enabled but not supported for target ${LIBC_TARGET_ARCHITECTURE} ${LIBC_TARGET_OS}")
+    set(fortification_deps)
+    set(fortification_defs -DLIBC_COPT_SETJMP_ENABLE_FORTIFICATION=0)
+  endif()
 endif()
 
-
-add_header_library(
-  checksum
-  HDRS
-    checksum.h
-  DEPENDS
-    libc.src.__support.common
-    libc.src.__support.OSUtil.osutil
-  COMPILE_OPTIONS
-    ${checksum_flags}
-)
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
+  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
+endif()
 
 add_entrypoint_object(
   setjmp
diff --git a/libc/src/setjmp/checksum.h b/libc/src/setjmp/checksum.h
index df6a12d185c3ee..1c443629426743 100644
--- a/libc/src/setjmp/checksum.h
+++ b/libc/src/setjmp/checksum.h
@@ -9,38 +9,19 @@
 #ifndef LLVM_LIBC_SRC_SETJMP_CHECKSUM_H
 #define LLVM_LIBC_SRC_SETJMP_CHECKSUM_H
 
-#ifndef LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
-#define LIBC_COPT_SETJMP_ENABLE_FORTIFICATION 1
-#endif
-
-#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
-#include "src/__support/OSUtil/syscall.h"
-#include "src/__support/macros/config.h"
-#include <sys/syscall.h>
+#include "src/__support/common.h"
 
 namespace LIBC_NAMESPACE_DECL {
 namespace jmpbuf {
-// random bytes from https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h
-LIBC_INLINE __UINTPTR_TYPE__ value_mask = 0x3899'f0d3'5005'd953;
-LIBC_INLINE __UINT64_TYPE__ checksum_cookie = 0xc7d9'd341'6afc'33f2;
+
+extern __UINTPTR_TYPE__ value_mask;
+extern __UINT64_TYPE__ checksum_cookie;
+
 // abitrary prime number
 LIBC_INLINE constexpr __UINT64_TYPE__ ROTATION = 13;
-// initialize the checksum state
-LIBC_INLINE void initialize() {
-  union {
-    struct {
-      __UINTPTR_TYPE__ entropy0;
-      __UINT64_TYPE__ entropy1;
-    };
-    char buffer[sizeof(__UINTPTR_TYPE__) + sizeof(__UINT64_TYPE__)];
-  };
-  syscall_impl<long>(SYS_getrandom, buffer, sizeof(buffer), 0);
-  // add in additional entropy
-  jmpbuf::value_mask ^= entropy0;
-  jmpbuf::checksum_cookie ^= entropy1;
-}
+void initialize();
+extern "C" [[gnu::cold, noreturn]] void __libc_jmpbuf_corruption();
 } // namespace jmpbuf
 } // namespace LIBC_NAMESPACE_DECL
-#endif // LIBC_SETJMP_ENABLE_FORTIFICATION
 
 #endif // LLVM_LIBC_SRC_SETJMP_CHECKSUM_H
diff --git a/libc/src/setjmp/linux/CMakeLists.txt b/libc/src/setjmp/linux/CMakeLists.txt
new file mode 100644
index 00000000000000..81275cbd3340e4
--- /dev/null
+++ b/libc/src/setjmp/linux/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_object_library(
+  checksum
+  SRCS
+  checksum.cpp
+  HDRS
+    ../checksum.h
+  DEPENDS
+    libc.src.__support.common
+    libc.src.__support.OSUtil.osutil
+    libc.src.stdlib.abort
+)
diff --git a/libc/src/setjmp/linux/checksum.cpp b/libc/src/setjmp/linux/checksum.cpp
new file mode 100644
index 00000000000000..d23c2aca05df38
--- /dev/null
+++ b/libc/src/setjmp/linux/checksum.cpp
@@ -0,0 +1,42 @@
+//===-- Implementation for jmpbuf checksum ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/setjmp/checksum.h"
+#include "src/__support/OSUtil/io.h"
+#include "src/stdlib/abort.h"
+#include <sys/syscall.h>
+
+namespace LIBC_NAMESPACE_DECL {
+namespace jmpbuf {
+// random bytes from https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h
+// the cookie should not be zero otherwise it will be a bad seed as a multiplier
+__UINTPTR_TYPE__ value_mask = 0x3899'f0d3'5005'd953;
+__UINT64_TYPE__ checksum_cookie = 0xc7d9'd341'6afc'33f2;
+
+// initialize the checksum state
+void initialize() {
+  union {
+    struct {
+      __UINTPTR_TYPE__ entropy0;
+      __UINT64_TYPE__ entropy1;
+    };
+    char buffer[sizeof(__UINTPTR_TYPE__) + sizeof(__UINT64_TYPE__)];
+  };
+  syscall_impl<long>(SYS_getrandom, buffer, sizeof(buffer), 0);
+  // add in additional entropy
+  jmpbuf::value_mask ^= entropy0;
+  jmpbuf::checksum_cookie ^= entropy1;
+}
+
+extern "C" [[gnu::cold, noreturn]] void __libc_jmpbuf_corruption() {
+  write_to_stderr("invalid checksum detected in longjmp\n");
+  abort();
+}
+
+} // namespace jmpbuf
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/setjmp/x86_64/CMakeLists.txt b/libc/src/setjmp/x86_64/CMakeLists.txt
index 571f3681887106..06100be5c1b6f8 100644
--- a/libc/src/setjmp/x86_64/CMakeLists.txt
+++ b/libc/src/setjmp/x86_64/CMakeLists.txt
@@ -6,9 +6,10 @@ add_entrypoint_object(
     ../setjmp_impl.h
   DEPENDS
     libc.hdr.types.jmp_buf
-    libc.src.setjmp.checksum
+    ${fortification_deps}
   COMPILE_OPTIONS
     -O3
+    ${fortification_defs}
 )
 
 add_entrypoint_object(
@@ -19,10 +20,9 @@ add_entrypoint_object(
     ../longjmp.h
   DEPENDS
     libc.hdr.types.jmp_buf
-    libc.src.stdlib.abort
-    libc.src.__support.OSUtil.osutil
-    libc.src.setjmp.checksum
+    ${fortification_deps}
   COMPILE_OPTIONS
     -O3
     -fomit-frame-pointer
+    ${fortification_defs}
 )
diff --git a/libc/src/setjmp/x86_64/longjmp.cpp b/libc/src/setjmp/x86_64/longjmp.cpp
index ef638a296e07a9..d7c9ef4f32970c 100644
--- a/libc/src/setjmp/x86_64/longjmp.cpp
+++ b/libc/src/setjmp/x86_64/longjmp.cpp
@@ -8,11 +8,12 @@
 
 #include "src/setjmp/longjmp.h"
 #include "include/llvm-libc-macros/offsetof-macro.h"
-#include "src/__support/OSUtil/io.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
+
+#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
 #include "src/setjmp/checksum.h"
-#include "src/stdlib/abort.h"
+#endif
 
 #if !defined(LIBC_TARGET_ARCH_IS_X86)
 #error "Invalid file include"
@@ -20,49 +21,55 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
+#define CALCULATE_RETURN_VALUE()                                               \
+  "cmpl $0x1, %%esi\n\t"                                                       \
+  "adcl $0x0, %%esi\n\t"                                                       \
+  "movq %%rsi, %%rax\n\t"
+
 #if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
-extern "C" [[gnu::cold, noreturn]] void __libc_jmpbuf_corruption() {
-  write_to_stderr("invalid checksum detected in longjmp\n");
-  abort();
-}
+#define ACCUMULATE_CHECKSUM()                                                  \
+  "mul %[checksum]\n\t"                                                        \
+  "xor %%rax, %[checksum]\n\t"                                                 \
+  "rol $%c[rotation], %[checksum]\n\t"
+
 #define LOAD_CHKSUM_STATE_REGISTERS()                                          \
-  asm("mov %0, %%rcx\n\t" ::"m"(jmpbuf::value_mask) : "rcx");                  \
-  asm("mov %0, %%rdx\n\t" ::"m"(jmpbuf::checksum_cookie) : "rdx");
+  asm("mov %[value_mask], %[mask]\n\t"                                         \
+      "mov %[checksum_cookie], %[checksum]\n\t"                                \
+      : [mask] "=r"(mask), [checksum] "=r"(checksum)                           \
+      : [value_mask] "m"(jmpbuf::value_mask), [checksum_cookie] "m"(           \
+                                                  jmpbuf::checksum_cookie));
 
+// clang-format off
 #define RESTORE_REG(DST)                                                       \
   "movq %c[" #DST "](%%rdi), %%rax\n\t"                                        \
   "movq %%rax, %%" #DST "\n\t"                                                 \
-  "xor %%rcx, %%" #DST "\n\t"                                                  \
-  "mul %%rdx\n\t"                                                              \
-  "xor %%rax, %%rdx\n\t"                                                       \
-  "rol $%c[rotation], %%rdx\n\t"
+  "xor %[mask], %%" #DST "\n\t"                                                \
+  ACCUMULATE_CHECKSUM()
 
 #define RESTORE_RIP()                                                          \
   "movq %c[rip](%%rdi), %%rax\n\t"                                             \
-  "xor %%rax, %%rcx\n\t"                                                       \
-  "mul %%rdx\n\t"                                                              \
-  "xor %%rax, %%rdx\n\t"                                                       \
-  "rol $%c[rotation], %%rdx\n\t"                                               \
-  "cmp %c[chksum](%%rdi), %%rdx\n\t"                                           \
+  "xor %%rax, %[mask]\n\t"                                                     \
+  ACCUMULATE_CHECKSUM()                                                        \
+  "cmp %c[__chksum](%%rdi), %%rdx\n\t"                                         \
   "jne __libc_jmpbuf_corruption\n\t"                                           \
-  "cmpl $0x1, %%esi\n\t"                                                       \
-  "adcl $0x0, %%esi\n\t"                                                       \
-  "movq %%rsi, %%rax\n\t"                                                      \
-  "jmp *%%rcx\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()                                                          \
-  "cmpl $0x1, %%esi\n\t"                                                       \
-  "adcl $0x0, %%esi\n\t"                                                       \
-  "movq %%rsi, %%rax\n\t"                                                      \
+  CALCULATE_RETURN_VALUE()                                                     \
   "jmpq *%c[rip](%%rdi)\n\t"
 #endif
 
-[[gnu::naked]]
-LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) {
+[[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(
+  asm volatile(
       // clang-format off
       RESTORE_REG(rbx)
       RESTORE_REG(rbp)
@@ -73,18 +80,23 @@ LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) {
       RESTORE_REG(rsp)
       RESTORE_RIP()
       // clang-format on
-      ::[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)),
+      : /* outputs */
+#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+      [mask] "+r"(mask), [checksum] "+r"(checksum)
+#endif
+      : /* inputs */
+      [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))
 #if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
       // clang-format off
       ,[rotation] "i"(jmpbuf::ROTATION)
-      ,[chksum] "i"(offsetof(__jmp_buf, __chksum))
+      ,[__chksum] "i"(offsetof(__jmp_buf, __chksum))
   // clang-format on
 #endif
-      : "rax", "rdx", "rcx", "rsi");
+      : "rax", "rsi");
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/setjmp/x86_64/setjmp.cpp b/libc/src/setjmp/x86_64/setjmp.cpp
index 14af3cb24c2a5a..101dbd97642f93 100644
--- a/libc/src/setjmp/x86_64/setjmp.cpp
+++ b/libc/src/setjmp/x86_64/setjmp.cpp
@@ -9,43 +9,45 @@
 #include "include/llvm-libc-macros/offsetof-macro.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
-#include "src/setjmp/checksum.h"
 #include "src/setjmp/setjmp_impl.h"
 
+#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+#include "src/setjmp/checksum.h"
+#endif
+
 #if !defined(LIBC_TARGET_ARCH_IS_X86)
 #error "Invalid file include"
 #endif
 
 #if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+#define ACCUMULATE_CHECKSUM()                                                  \
+  "mul %[checksum]\n\t"                                                        \
+  "xor %%rax, %[checksum]\n\t"                                                 \
+  "rol $%c[rotation], %[checksum]\n\t"
+
 #define LOAD_CHKSUM_STATE_REGISTERS()                                          \
-  asm("mov %0, %%rcx\n\t" ::"m"(jmpbuf::value_mask) : "rcx");                  \
-  asm("mov %0, %%rdx\n\t" ::"m"(jmpbuf::checksum_cookie) : "rdx");
+  asm("mov %[value_mask], %[mask]\n\t"                                         \
+      "mov %[checksum_cookie], %[checksum]\n\t"                                \
+      : [mask] "=r"(mask), [checksum] "=r"(checksum)                           \
+      : [value_mask] "m"(jmpbuf::value_mask), [checksum_cookie] "m"(           \
+                                                  jmpbuf::checksum_cookie));
 
 #define STORE_REG(SRC)                                                         \
   "mov %%" #SRC ", %%rax\n\t"                                                  \
-  "xor %%rcx, %%rax\n\t"                                                       \
-  "mov %%rax, %c[" #SRC "](%%rdi)\n\t"                                         \
-  "mul %%rdx\n\t"                                                              \
-  "xor %%rax, %%rdx\n\t"                                                       \
-  "rol $%c[rotation], %%rdx\n\t"
+  "xor %[mask], %%rax\n\t"                                                     \
+  "mov %%rax, %c[" #SRC "](%%rdi)\n\t" ACCUMULATE_CHECKSUM()
 
 #define STORE_RSP()                                                            \
   "lea 8(%%rsp), %%rax\n\t"                                                    \
-  "xor %%rcx, %%rax\n\t"                                                       \
-  "mov %%rax, %c[rsp](%%rdi)\n\t"                                              \
-  "mul %%rdx\n\t"                                                              \
-  "xor %%rax, %%rdx\n\t"                                                       \
-  "rolq $%c[rotation], %%rdx\n\t"
+  "xor %[mask], %%rax\n\t"                                                     \
+  "mov %%rax, %c[rsp](%%rdi)\n\t" ACCUMULATE_CHECKSUM()
 
 #define STORE_RIP()                                                            \
   "mov (%%rsp), %%rax\n\t"                                                     \
-  "xor %%rcx, %%rax\n\t"                                                       \
-  "mov %%rax, %c[rip](%%rdi)\n\t"                                              \
-  "mul %%rdx\n\t"                                                              \
-  "xor %%rax, %%rdx\n\t"                                                       \
-  "rolq $%c[rotation], %%rdx\n\t"
+  "xor %[mask], %%rax\n\t"                                                     \
+  "mov %%rax, %c[rip](%%rdi)\n\t" ACCUMULATE_CHECKSUM()
 
-#define STORE_CHECKSUM() "mov %%rdx, %c[chksum](%%rdi)\n\t"
+#define STORE_CHECKSUM() "mov %%rdx, %c[__chksum](%%rdi)\n\t"
 #else
 #define LOAD_CHKSUM_STATE_REGISTERS()
 #define STORE_REG(SRC) "mov %%" #SRC ", %c[" #SRC "](%%rdi)\n\t"
@@ -61,8 +63,11 @@
 namespace LIBC_NAMESPACE_DECL {
 [[gnu::naked]]
 LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) {
+  // 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(
+  asm volatile(
       // clang-format off
     STORE_REG(rbx)
     STORE_REG(rbp)
@@ -74,18 +79,24 @@ LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) {
     STORE_RIP()
     STORE_CHECKSUM()
       // clang-format on
-      ::[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)),
+      :
+#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+      [checksum] "+r"(checksum)
+#endif
+      :
+      [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))
 #if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
       // clang-format off
       ,[rotation] "i"(jmpbuf::ROTATION)
-      ,[chksum] "i"(offsetof(__jmp_buf, __chksum))
+      ,[__chksum] "i"(offsetof(__jmp_buf, __chksum))
+      ,[mask] "r"(mask)
   // clang-format on
 #endif
-      : "rax", "rdx");
+      : "rax");
 
   asm(R"(
     xorl %eax, %eax
diff --git a/libc/startup/linux/CMakeLists.txt b/libc/startup/linux/CMakeLists.txt
index 34c870f98b1f1c..a185e8c04a5a33 100644
--- a/libc/startup/linux/CMakeLists.txt
+++ b/libc/startup/linux/CMakeLists.txt
@@ -88,6 +88,14 @@ endif()
 
 add_subdirectory(${LIBC_TARGET_ARCHITECTURE})
 
+if (LIBC_CONF_SETJMP_ENABLE_FORTIFICATION AND LIBC_TARGET_ARCHITECTURE STREQUAL "x86_64")
+  set(jmpbuf_fortification_deps libc.src.setjmp.checksum)  
+  set(jmpbuf_fortification_defs -DLIBC_COPT_SETJMP_ENABLE_FORTIFICATION=1)
+else()
+  set(jmpbuf_fortification_deps)
+  set(jmpbuf_fortification_defs -DLIBC_COPT_SETJMP_ENABLE_FORTIFICATION=0)
+endif()
+
 add_object_library(
   do_start
   SRCS
@@ -104,11 +112,12 @@ add_object_library(
     libc.src.stdlib.exit
     libc.src.stdlib.atexit
     libc.src.unistd.environ
-    libc.src.setjmp.checksum
+    ${jmpbuf_fortification_deps}
   COMPILE_OPTIONS
     -ffreestanding       # To avoid compiler warnings about calling the main function.
     -fno-builtin         # avoid emit unexpected calls
     -fno-stack-protector # stack protect canary is not available yet.
+    ${jmpbuf_fortification_defs}
 )
 
 # TODO: factor out crt1 into multiple objects
diff --git a/libc/startup/linux/do_start.cpp b/libc/startup/linux/do_start.cpp
index 55d85c90fca44b..0af216ea01eeed 100644
--- a/libc/startup/linux/do_start.cpp
+++ b/libc/startup/linux/do_start.cpp
@@ -11,7 +11,6 @@
 #include "src/__support/OSUtil/syscall.h"
 #include "src/__support/macros/config.h"
 #include "src/__support/threads/thread.h"
-#include "src/setjmp/checksum.h"
 #include "src/stdlib/atexit.h"
 #include "src/stdlib/exit.h"
 #include "src/unistd/environ.h"
@@ -22,6 +21,10 @@
 #include <sys/mman.h>
 #include <sys/syscall.h>
 
+#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+#include "src/setjmp/checksum.h"
+#endif
+
 extern "C" int main(int argc, char **argv, char **envp);
 
 extern "C" {

>From e6ce912524d5f642b9021327119902f0bad76bd3 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Fri, 18 Oct 2024 13:42:37 -0400
Subject: [PATCH 6/7] [libc] address CRs

---
 libc/config/config.json             |  2 +-
 libc/docs/configure.rst             |  2 +-
 libc/src/setjmp/CMakeLists.txt      |  6 ++---
 libc/src/setjmp/x86_64/checksum.def | 34 +++++++++++++++++++++++++++++
 libc/src/setjmp/x86_64/longjmp.cpp  | 20 +++++------------
 libc/src/setjmp/x86_64/setjmp.cpp   | 20 +++++------------
 libc/startup/linux/CMakeLists.txt   |  6 ++---
 libc/startup/linux/do_start.cpp     |  4 ++--
 8 files changed, 54 insertions(+), 40 deletions(-)
 create mode 100644 libc/src/setjmp/x86_64/checksum.def

diff --git a/libc/config/config.json b/libc/config/config.json
index f2cf98f8678e45..e1cfa9c37cf4a2 100644
--- a/libc/config/config.json
+++ b/libc/config/config.json
@@ -104,7 +104,7 @@
       "value": true,
       "doc": "Make setjmp save the value of x18, and longjmp restore it. The AArch64 ABI delegates this register to platform ABIs, which can choose whether to make it caller-saved."
     },
-    "LIBC_CONF_SETJMP_ENABLE_FORTIFICATION": {
+    "LIBC_CONF_SETJMP_FORTIFICATION": {
       "value": true,
       "doc": "Protect jmp_buf by masking its contents and storing a simple checksum, to make it harder for an attacker to read meaningful information from a jmp_buf or to modify it. This is only supported on x86-64 Linux."
     }
diff --git a/libc/docs/configure.rst b/libc/docs/configure.rst
index 73f66e303132b8..269c3ff121844b 100644
--- a/libc/docs/configure.rst
+++ b/libc/docs/configure.rst
@@ -55,7 +55,7 @@ to learn about the defaults for your platform and target.
     - ``LIBC_CONF_SCANF_DISABLE_INDEX_MODE``: Disable index mode in the scanf format string.
 * **"setjmp" options**
     - ``LIBC_CONF_SETJMP_AARCH64_RESTORE_PLATFORM_REGISTER``: Make setjmp save the value of x18, and longjmp restore it. The AArch64 ABI delegates this register to platform ABIs, which can choose whether to make it caller-saved.
-    - ``LIBC_CONF_SETJMP_ENABLE_FORTIFICATION``: Protect jmp_buf by masking its contents and storing a simple checksum, to make it harder for an attacker to read meaningful information from a jmp_buf or to modify it. This is only supported on x86-64 Linux.
+    - ``LIBC_CONF_SETJMP_FORTIFICATION``: Protect jmp_buf by masking its contents and storing a simple checksum, to make it harder for an attacker to read meaningful information from a jmp_buf or to modify it. This is only supported on x86-64 Linux.
 * **"string" options**
     - ``LIBC_CONF_MEMSET_X86_USE_SOFTWARE_PREFETCHING``: Inserts prefetch for write instructions (PREFETCHW) for memset on x86 to recover performance when hardware prefetcher is disabled.
     - ``LIBC_CONF_STRING_UNSAFE_WIDE_READ``: Read more than a byte at a time to perform byte-string operations like strlen.
diff --git a/libc/src/setjmp/CMakeLists.txt b/libc/src/setjmp/CMakeLists.txt
index 21ac0b6ba52e25..0073ca1a6930ba 100644
--- a/libc/src/setjmp/CMakeLists.txt
+++ b/libc/src/setjmp/CMakeLists.txt
@@ -2,7 +2,7 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
   add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
 endif()
 
-if (LIBC_CONF_SETJMP_ENABLE_FORTIFICATION)
+if (LIBC_CONF_SETJMP_FORTIFICATION)
   if (TARGET libc.src.setjmp.${LIBC_TARGET_OS}.checksum
       AND LIBC_TARGET_ARCHITECTURE STREQUAL "x86_64")
     add_object_library(
@@ -12,11 +12,11 @@ if (LIBC_CONF_SETJMP_ENABLE_FORTIFICATION)
         .${LIBC_TARGET_OS}.checksum
     )
     set(fortification_deps libc.src.setjmp.checksum)
-    set(fortification_defs -DLIBC_COPT_SETJMP_ENABLE_FORTIFICATION=1)
+    set(fortification_defs -DLIBC_COPT_SETJMP_FORTIFICATION=1)
   else()
     message(WARNING "Jmpbuf fortification is enabled but not supported for target ${LIBC_TARGET_ARCHITECTURE} ${LIBC_TARGET_OS}")
     set(fortification_deps)
-    set(fortification_defs -DLIBC_COPT_SETJMP_ENABLE_FORTIFICATION=0)
+    set(fortification_defs -DLIBC_COPT_SETJMP_FORTIFICATION=0)
   endif()
 endif()
 
diff --git a/libc/src/setjmp/x86_64/checksum.def b/libc/src/setjmp/x86_64/checksum.def
new file mode 100644
index 00000000000000..b4934ca8224f14
--- /dev/null
+++ b/libc/src/setjmp/x86_64/checksum.def
@@ -0,0 +1,34 @@
+//===-- Common macros for jmpbuf checksum -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// For now, the checksum is computed with a simple multiply-xor-rotation
+// algorithm. The pesudo code is as follows:
+//
+// def checksum(x, acc):
+//     masked = x ^ MASK
+//     high, low = full_multiply(masked, acc)
+//     return rotate(high ^ low, ROTATION)
+//
+// Similar other multiplication-based hashing, zero inputs
+// for the `full_multiply` function may pollute the checksum with zero.
+// However, user inputs are always masked where the initial ACC amd MASK are
+// generated with random entropy and ROTATION is a fixed prime number. It should
+// be of a ultra-low chance for masked or acc being zero given a good quality of
+// system-level entropy.
+
+#define ACCUMULATE_CHECKSUM()                                                  \
+  "mul %[checksum]\n\t"                                                        \
+  "xor %%rax, %[checksum]\n\t"                                                 \
+  "rol $%c[rotation], %[checksum]\n\t"
+
+#define LOAD_CHKSUM_STATE_REGISTERS()                                          \
+  asm("mov %[value_mask], %[mask]\n\t"                                         \
+      "mov %[checksum_cookie], %[checksum]\n\t"                                \
+      : [mask] "=r"(mask), [checksum] "=r"(checksum)                           \
+      : [value_mask] "m"(jmpbuf::value_mask), [checksum_cookie] "m"(           \
+                                                  jmpbuf::checksum_cookie));
diff --git a/libc/src/setjmp/x86_64/longjmp.cpp b/libc/src/setjmp/x86_64/longjmp.cpp
index d7c9ef4f32970c..35fde48be691e4 100644
--- a/libc/src/setjmp/x86_64/longjmp.cpp
+++ b/libc/src/setjmp/x86_64/longjmp.cpp
@@ -11,7 +11,7 @@
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
 
-#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+#if LIBC_COPT_SETJMP_FORTIFICATION
 #include "src/setjmp/checksum.h"
 #endif
 
@@ -26,18 +26,8 @@ namespace LIBC_NAMESPACE_DECL {
   "adcl $0x0, %%esi\n\t"                                                       \
   "movq %%rsi, %%rax\n\t"
 
-#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
-#define ACCUMULATE_CHECKSUM()                                                  \
-  "mul %[checksum]\n\t"                                                        \
-  "xor %%rax, %[checksum]\n\t"                                                 \
-  "rol $%c[rotation], %[checksum]\n\t"
-
-#define LOAD_CHKSUM_STATE_REGISTERS()                                          \
-  asm("mov %[value_mask], %[mask]\n\t"                                         \
-      "mov %[checksum_cookie], %[checksum]\n\t"                                \
-      : [mask] "=r"(mask), [checksum] "=r"(checksum)                           \
-      : [value_mask] "m"(jmpbuf::value_mask), [checksum_cookie] "m"(           \
-                                                  jmpbuf::checksum_cookie));
+#if LIBC_COPT_SETJMP_FORTIFICATION
+#include "src/setjmp/x86_64/checksum.def"
 
 // clang-format off
 #define RESTORE_REG(DST)                                                       \
@@ -81,7 +71,7 @@ namespace LIBC_NAMESPACE_DECL {
       RESTORE_RIP()
       // clang-format on
       : /* outputs */
-#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+#if LIBC_COPT_SETJMP_FORTIFICATION
       [mask] "+r"(mask), [checksum] "+r"(checksum)
 #endif
       : /* inputs */
@@ -90,7 +80,7 @@ namespace LIBC_NAMESPACE_DECL {
       [r14] "i"(offsetof(__jmp_buf, r14)), [r15] "i"(offsetof(__jmp_buf, r15)),
       [rsp] "i"(offsetof(__jmp_buf, rsp)),
       [rip] "i"(offsetof(__jmp_buf, rip))
-#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+#if LIBC_COPT_SETJMP_FORTIFICATION
       // clang-format off
       ,[rotation] "i"(jmpbuf::ROTATION)
       ,[__chksum] "i"(offsetof(__jmp_buf, __chksum))
diff --git a/libc/src/setjmp/x86_64/setjmp.cpp b/libc/src/setjmp/x86_64/setjmp.cpp
index 101dbd97642f93..367cc0a6c3586b 100644
--- a/libc/src/setjmp/x86_64/setjmp.cpp
+++ b/libc/src/setjmp/x86_64/setjmp.cpp
@@ -11,7 +11,7 @@
 #include "src/__support/macros/config.h"
 #include "src/setjmp/setjmp_impl.h"
 
-#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+#if LIBC_COPT_SETJMP_FORTIFICATION
 #include "src/setjmp/checksum.h"
 #endif
 
@@ -19,18 +19,8 @@
 #error "Invalid file include"
 #endif
 
-#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
-#define ACCUMULATE_CHECKSUM()                                                  \
-  "mul %[checksum]\n\t"                                                        \
-  "xor %%rax, %[checksum]\n\t"                                                 \
-  "rol $%c[rotation], %[checksum]\n\t"
-
-#define LOAD_CHKSUM_STATE_REGISTERS()                                          \
-  asm("mov %[value_mask], %[mask]\n\t"                                         \
-      "mov %[checksum_cookie], %[checksum]\n\t"                                \
-      : [mask] "=r"(mask), [checksum] "=r"(checksum)                           \
-      : [value_mask] "m"(jmpbuf::value_mask), [checksum_cookie] "m"(           \
-                                                  jmpbuf::checksum_cookie));
+#if LIBC_COPT_SETJMP_FORTIFICATION
+#include "src/setjmp/x86_64/checksum.def"
 
 #define STORE_REG(SRC)                                                         \
   "mov %%" #SRC ", %%rax\n\t"                                                  \
@@ -80,7 +70,7 @@ LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) {
     STORE_CHECKSUM()
       // clang-format on
       :
-#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+#if LIBC_COPT_SETJMP_FORTIFICATION
       [checksum] "+r"(checksum)
 #endif
       :
@@ -89,7 +79,7 @@ LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) {
       [r14] "i"(offsetof(__jmp_buf, r14)), [r15] "i"(offsetof(__jmp_buf, r15)),
       [rsp] "i"(offsetof(__jmp_buf, rsp)),
       [rip] "i"(offsetof(__jmp_buf, rip))
-#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+#if LIBC_COPT_SETJMP_FORTIFICATION
       // clang-format off
       ,[rotation] "i"(jmpbuf::ROTATION)
       ,[__chksum] "i"(offsetof(__jmp_buf, __chksum))
diff --git a/libc/startup/linux/CMakeLists.txt b/libc/startup/linux/CMakeLists.txt
index a185e8c04a5a33..245dfca5b3ed3f 100644
--- a/libc/startup/linux/CMakeLists.txt
+++ b/libc/startup/linux/CMakeLists.txt
@@ -88,12 +88,12 @@ endif()
 
 add_subdirectory(${LIBC_TARGET_ARCHITECTURE})
 
-if (LIBC_CONF_SETJMP_ENABLE_FORTIFICATION AND LIBC_TARGET_ARCHITECTURE STREQUAL "x86_64")
+if (LIBC_CONF_SETJMP_FORTIFICATION AND LIBC_TARGET_ARCHITECTURE STREQUAL "x86_64")
   set(jmpbuf_fortification_deps libc.src.setjmp.checksum)  
-  set(jmpbuf_fortification_defs -DLIBC_COPT_SETJMP_ENABLE_FORTIFICATION=1)
+  set(jmpbuf_fortification_defs -DLIBC_COPT_SETJMP_FORTIFICATION=1)
 else()
   set(jmpbuf_fortification_deps)
-  set(jmpbuf_fortification_defs -DLIBC_COPT_SETJMP_ENABLE_FORTIFICATION=0)
+  set(jmpbuf_fortification_defs -DLIBC_COPT_SETJMP_FORTIFICATION=0)
 endif()
 
 add_object_library(
diff --git a/libc/startup/linux/do_start.cpp b/libc/startup/linux/do_start.cpp
index 0af216ea01eeed..ded94768f0b92c 100644
--- a/libc/startup/linux/do_start.cpp
+++ b/libc/startup/linux/do_start.cpp
@@ -21,7 +21,7 @@
 #include <sys/mman.h>
 #include <sys/syscall.h>
 
-#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+#if LIBC_COPT_SETJMP_FORTIFICATION
 #include "src/setjmp/checksum.h"
 #endif
 
@@ -135,7 +135,7 @@ void teardown_main_tls() { cleanup_tls(tls.addr, tls.size); }
   if (tls.size != 0 && !set_thread_ptr(tls.tp))
     syscall_impl<long>(SYS_exit, 1);
 
-#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
+#if LIBC_COPT_SETJMP_FORTIFICATION
   jmpbuf::initialize();
 #endif
 

>From ef9ccdb2d55c31bf6c2ee2c325b4941aa6a76c12 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Tue, 12 Nov 2024 18:09:11 -0500
Subject: [PATCH 7/7] fix and rebase

---
 libc/src/setjmp/linux/checksum.cpp  |   4 +-
 libc/src/setjmp/x86_64/checksum.def |  34 -------
 libc/src/setjmp/x86_64/common.h     | 147 ++++++++++++++++++++++++++++
 libc/src/setjmp/x86_64/longjmp.cpp  |  76 ++++----------
 libc/src/setjmp/x86_64/setjmp.cpp   |  79 ++++-----------
 5 files changed, 184 insertions(+), 156 deletions(-)
 delete mode 100644 libc/src/setjmp/x86_64/checksum.def
 create mode 100644 libc/src/setjmp/x86_64/common.h

diff --git a/libc/src/setjmp/linux/checksum.cpp b/libc/src/setjmp/linux/checksum.cpp
index d23c2aca05df38..c0eebf9395db09 100644
--- a/libc/src/setjmp/linux/checksum.cpp
+++ b/libc/src/setjmp/linux/checksum.cpp
@@ -23,9 +23,9 @@ void initialize() {
   union {
     struct {
       __UINTPTR_TYPE__ entropy0;
-      __UINT64_TYPE__ entropy1;
+      __UINTPTR_TYPE__ entropy1;
     };
-    char buffer[sizeof(__UINTPTR_TYPE__) + sizeof(__UINT64_TYPE__)];
+    char buffer[sizeof(__UINTPTR_TYPE__) * 2];
   };
   syscall_impl<long>(SYS_getrandom, buffer, sizeof(buffer), 0);
   // add in additional entropy
diff --git a/libc/src/setjmp/x86_64/checksum.def b/libc/src/setjmp/x86_64/checksum.def
deleted file mode 100644
index b4934ca8224f14..00000000000000
--- a/libc/src/setjmp/x86_64/checksum.def
+++ /dev/null
@@ -1,34 +0,0 @@
-//===-- Common macros for jmpbuf checksum -----------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// For now, the checksum is computed with a simple multiply-xor-rotation
-// algorithm. The pesudo code is as follows:
-//
-// def checksum(x, acc):
-//     masked = x ^ MASK
-//     high, low = full_multiply(masked, acc)
-//     return rotate(high ^ low, ROTATION)
-//
-// Similar other multiplication-based hashing, zero inputs
-// for the `full_multiply` function may pollute the checksum with zero.
-// However, user inputs are always masked where the initial ACC amd MASK are
-// generated with random entropy and ROTATION is a fixed prime number. It should
-// be of a ultra-low chance for masked or acc being zero given a good quality of
-// system-level entropy.
-
-#define ACCUMULATE_CHECKSUM()                                                  \
-  "mul %[checksum]\n\t"                                                        \
-  "xor %%rax, %[checksum]\n\t"                                                 \
-  "rol $%c[rotation], %[checksum]\n\t"
-
-#define LOAD_CHKSUM_STATE_REGISTERS()                                          \
-  asm("mov %[value_mask], %[mask]\n\t"                                         \
-      "mov %[checksum_cookie], %[checksum]\n\t"                                \
-      : [mask] "=r"(mask), [checksum] "=r"(checksum)                           \
-      : [value_mask] "m"(jmpbuf::value_mask), [checksum_cookie] "m"(           \
-                                                  jmpbuf::checksum_cookie));
diff --git a/libc/src/setjmp/x86_64/common.h b/libc/src/setjmp/x86_64/common.h
new file mode 100644
index 00000000000000..305ec2dfe269eb
--- /dev/null
+++ b/libc/src/setjmp/x86_64/common.h
@@ -0,0 +1,147 @@
+//===-- Common macros for jmpbuf  -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LIBC_SRC_SETJMP_X86_64_COMMON_H
+#define LIBC_SRC_SETJMP_X86_64_COMMON_H
+
+#include "include/llvm-libc-macros/offsetof-macro.h"
+
+//===----------------------------------------------------------------------===//
+// Architecture specific macros for x86_64.
+//===----------------------------------------------------------------------===//
+
+#ifdef __i386__
+#define RET_REG eax
+#define BASE_REG ecx
+#define MUL_REG edx
+#define STACK_REG esp
+#define PC_REG eip
+#define NORMAL_STORE_REGS ebx, esi, edi, ebp
+#define STORE_ALL_REGS(M) M(ebx) M(esi) M(edi) M(ebp)
+#define LOAD_ALL_REGS(M) M(ebx) M(esi) M(edi) M(ebp) M(esp)
+#define DECLARE_ALL_REGS(M) M(ebx), M(esi), M(edi), M(ebp), M(esp), M(eip)
+#define LOAD_BASE() "mov 4(%%esp), %%ecx\n\t"
+#define CALCULATE_RETURN_VALUE()                                               \
+  "mov 0x8(%%esp), %%eax"                                                      \
+  "cmp $0x1, %%eax\n\t"                                                        \
+  "adc $0x0, %%eax\n\t"
+#else
+#define RET_REG rax
+#define BASE_REG rdi
+#define MUL_REG rdx
+#define STACK_REG rsp
+#define PC_REG rip
+#define STORE_ALL_REGS(M) M(rbx) M(rbp) M(r12) M(r13) M(r14) M(r15)
+#define LOAD_ALL_REGS(M) M(rbx) M(rbp) M(r12) M(r13) M(r14) M(r15) M(rsp)
+#define DECLARE_ALL_REGS(M)                                                    \
+  M(rbx), M(rbp), M(r12), M(r13), M(r14), M(r15), M(rsp), M(rip)
+#define LOAD_BASE()
+#define CALCULATE_RETURN_VALUE()                                               \
+  "cmp $0x1, %%esi\n\t"                                                        \
+  "adc $0x0, %%esi\n\t"                                                        \
+  "mov %%rsi, %%rax\n\t"
+#endif
+
+//===----------------------------------------------------------------------===//
+// Utility macros.
+//===----------------------------------------------------------------------===//
+
+#define _STR(X) #X
+#define STR(X) _STR(X)
+#define REG(X) "%%" STR(X)
+#define XOR(X, Y) "xor " REG(X) ", " REG(Y) "\n\t"
+#define MOV(X, Y) "mov " REG(X) ", " REG(Y) "\n\t"
+#define STORE(R, OFFSET, BASE)                                                 \
+  "mov " REG(R) ", %c[" STR(OFFSET) "](" REG(BASE) ")\n\t"
+#define LOAD(OFFSET, BASE, R)                                                  \
+  "mov %c[" STR(OFFSET) "](" REG(BASE) "), " REG(R) "\n\t"
+#define COMPUTE_STACK_TO_RET()                                                 \
+  "lea " STR(__SIZEOF_POINTER__) "(" REG(STACK_REG) "), " REG(RET_REG) "\n\t"
+#define COMPUTE_PC_TO_RET() "mov (" REG(STACK_REG) "), " REG(RET_REG) "\n\t"
+#define RETURN() "ret\n\t"
+#define DECLARE_OFFSET(X) [X] "i"(offsetof(__jmp_buf, X))
+#define CMP_MEM_REG(OFFSET, BASE, DST)                                         \
+  "cmp %c[" STR(OFFSET) "](" REG(BASE) "), " REG(DST) "\n\t"
+#define JNE_LABEL(LABEL) "jne " STR(LABEL) "\n\t"
+
+//===----------------------------------------------------------------------===//
+// Checksum related macros.
+//===----------------------------------------------------------------------===//
+// For now, the checksum is computed with a simple multiply-xor-rotation
+// algorithm. The pesudo code is as follows:
+//
+// def checksum(x, acc):
+//     masked = x ^ MASK
+//     high, low = full_multiply(masked, acc)
+//     return rotate(high ^ low, ROTATION)
+//
+// Similar other multiplication-based hashing, zero inputs
+// for the `full_multiply` function may pollute the checksum with zero.
+// However, user inputs are always masked where the initial ACC amd MASK are
+// generated with random entropy and ROTATION is a fixed prime number. It should
+// be of a ultra-low chance for masked or acc being zero given a good quality of
+// system-level entropy.
+//
+// Notice that on x86-64, one-operand form of `mul` instruction:
+//  mul %rdx
+// has the following effect:
+//  RAX = LOW(RDX * RAX)
+//  RDX = HIGH(RDX * RAX)
+//===----------------------------------------------------------------------===//
+
+#if LIBC_COPT_SETJMP_FORTIFICATION
+#define XOR_MASK(X) "xor %[value_mask], " REG(X) "\n\t"
+#define MUL(X) "mul " REG(X) "\n\t"
+#define ROTATE(X) "rol $%c[rotation], " REG(X) "\n\t"
+#define ACCUMULATE_CHECKSUM() MUL(MUL_REG) XOR(RET_REG, MUL_REG) ROTATE(MUL_REG)
+
+#define LOAD_CHKSUM_STATE_REGS() "mov %[checksum_cookie], " REG(MUL_REG) "\n\t"
+
+#define STORE_REG(SRC)                                                         \
+  MOV(SRC, RET_REG) XOR_MASK(RET_REG) STORE(RET_REG, SRC, BASE_REG)
+#define STORE_STACK()                                                          \
+  COMPUTE_STACK_TO_RET()                                                       \
+  XOR_MASK(RET_REG)                                                            \
+  STORE(RET_REG, STACK_REG, BASE_REG)
+
+#define STORE_PC()                                                             \
+  COMPUTE_PC_TO_RET()                                                          \
+  XOR_MASK(RET_REG)                                                            \
+  STORE(RET_REG, PC_REG, BASE_REG)
+
+#define STORE_CHECKSUM() STORE(MUL_REG, __chksum, BASE_REG)
+#define EXAMINE_CHECKSUM()                                                     \
+  LOAD(PC_REG, BASE_REG, RET_REG)                                              \
+  ACCUMULATE_CHECKSUM()                                                        \
+  CMP_MEM_REG(__chksum, BASE_REG, MUL_REG)                                     \
+  JNE_LABEL(__libc_jmpbuf_corruption)
+
+#define RESTORE_PC()                                                           \
+  LOAD(PC_REG, BASE_REG, BASE_REG)                                             \
+  XOR_MASK(BASE_REG)                                                           \
+  "jmp *" REG(BASE_REG)
+#define RESTORE_REG(SRC)                                                       \
+  LOAD(SRC, BASE_REG, RET_REG)                                                 \
+  MOV(RET_REG, SRC)                                                            \
+  ACCUMULATE_CHECKSUM() XOR_MASK(SRC)
+#else
+#define XOR_MASK(X)
+#define ACCUMULATE_CHECKSUM()
+#define LOAD_CHKSUM_STATE_REGS()
+#define STORE_REG(SRC) STORE(SRC, SRC, BASE_REG)
+#define STORE_STACK() COMPUTE_STACK_TO_RET() STORE(RET_REG, STACK_REG, BASE_REG)
+#define STORE_PC() COMPUTE_PC_TO_RET() STORE(RET_REG, PC_REG, BASE_REG)
+#define STORE_CHECKSUM()
+#define EXAMINE_CHECKSUM()
+#define RESTORE_PC() "jmp *%c[" STR(PC_REG) "](" REG(BASE_REG) ")\n\t"
+#define RESTORE_REG(SRC) LOAD(SRC, BASE_REG, SRC)
+#endif
+
+#define STORE_REG_ACCUMULATE(SRC) STORE_REG(SRC) ACCUMULATE_CHECKSUM()
+
+#endif // LIBC_SRC_SETJMP_X86_64_COMMON_H
diff --git a/libc/src/setjmp/x86_64/longjmp.cpp b/libc/src/setjmp/x86_64/longjmp.cpp
index 35fde48be691e4..aff4b5bfa87523 100644
--- a/libc/src/setjmp/x86_64/longjmp.cpp
+++ b/libc/src/setjmp/x86_64/longjmp.cpp
@@ -7,86 +7,44 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/setjmp/longjmp.h"
-#include "include/llvm-libc-macros/offsetof-macro.h"
 #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)
 #error "Invalid file include"
 #endif
 
-namespace LIBC_NAMESPACE_DECL {
-
-#define CALCULATE_RETURN_VALUE()                                               \
-  "cmpl $0x1, %%esi\n\t"                                                       \
-  "adcl $0x0, %%esi\n\t"                                                       \
-  "movq %%rsi, %%rax\n\t"
+#include "src/setjmp/x86_64/common.h"
 
 #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"
+#include "src/setjmp/checksum.h"
 #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");
+namespace LIBC_NAMESPACE_DECL {
 
-  LOAD_CHKSUM_STATE_REGISTERS()
+[[gnu::naked]] LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) {
   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()
+      LOAD_BASE()
+      LOAD_CHKSUM_STATE_REGS() 
+      LOAD_ALL_REGS(RESTORE_REG)
+      EXAMINE_CHECKSUM()
+      CALCULATE_RETURN_VALUE()
+      RESTORE_PC()
       // clang-format on
-      : /* outputs */
+      :
 #if LIBC_COPT_SETJMP_FORTIFICATION
-      [mask] "+r"(mask), [checksum] "+r"(checksum)
+      [value_mask] "=m"(jmpbuf::value_mask)
 #endif
-      : /* inputs */
-      [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))
+      : DECLARE_ALL_REGS(DECLARE_OFFSET)
 #if LIBC_COPT_SETJMP_FORTIFICATION
-      // clang-format off
+        // clang-format off
       ,[rotation] "i"(jmpbuf::ROTATION)
       ,[__chksum] "i"(offsetof(__jmp_buf, __chksum))
-  // clang-format on
+      ,[checksum_cookie] "m"(jmpbuf::checksum_cookie)
+
 #endif
-      : "rax", "rsi");
+      : STR(RET_REG), STR(BASE_REG), STR(MUL_REG));
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/setjmp/x86_64/setjmp.cpp b/libc/src/setjmp/x86_64/setjmp.cpp
index 367cc0a6c3586b..453cf2475c4cb6 100644
--- a/libc/src/setjmp/x86_64/setjmp.cpp
+++ b/libc/src/setjmp/x86_64/setjmp.cpp
@@ -11,88 +11,45 @@
 #include "src/__support/macros/config.h"
 #include "src/setjmp/setjmp_impl.h"
 
-#if LIBC_COPT_SETJMP_FORTIFICATION
-#include "src/setjmp/checksum.h"
-#endif
-
 #if !defined(LIBC_TARGET_ARCH_IS_X86)
 #error "Invalid file include"
 #endif
 
-#if LIBC_COPT_SETJMP_FORTIFICATION
-#include "src/setjmp/x86_64/checksum.def"
-
-#define STORE_REG(SRC)                                                         \
-  "mov %%" #SRC ", %%rax\n\t"                                                  \
-  "xor %[mask], %%rax\n\t"                                                     \
-  "mov %%rax, %c[" #SRC "](%%rdi)\n\t" ACCUMULATE_CHECKSUM()
-
-#define STORE_RSP()                                                            \
-  "lea 8(%%rsp), %%rax\n\t"                                                    \
-  "xor %[mask], %%rax\n\t"                                                     \
-  "mov %%rax, %c[rsp](%%rdi)\n\t" ACCUMULATE_CHECKSUM()
-
-#define STORE_RIP()                                                            \
-  "mov (%%rsp), %%rax\n\t"                                                     \
-  "xor %[mask], %%rax\n\t"                                                     \
-  "mov %%rax, %c[rip](%%rdi)\n\t" ACCUMULATE_CHECKSUM()
+#include "src/setjmp/x86_64/common.h"
 
-#define STORE_CHECKSUM() "mov %%rdx, %c[__chksum](%%rdi)\n\t"
-#else
-#define LOAD_CHKSUM_STATE_REGISTERS()
-#define STORE_REG(SRC) "mov %%" #SRC ", %c[" #SRC "](%%rdi)\n\t"
-#define STORE_RSP()                                                            \
-  "lea 8(%%rsp), %%rax\n\t"                                                    \
-  "mov %%rax, %c[rsp](%%rdi)\n\t"
-#define STORE_RIP()                                                            \
-  "mov (%%rsp), %%rax\n\t"                                                     \
-  "mov %%rax, %c[rip](%%rdi)\n\t"
-#define STORE_CHECKSUM()
+#if LIBC_COPT_SETJMP_FORTIFICATION
+#include "src/setjmp/checksum.h"
 #endif
 
 namespace LIBC_NAMESPACE_DECL {
 [[gnu::naked]]
 LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) {
-  // 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
-    STORE_REG(rbx)
-    STORE_REG(rbp)
-    STORE_REG(r12)
-    STORE_REG(r13)
-    STORE_REG(r14)
-    STORE_REG(r15)
-    STORE_RSP()
-    STORE_RIP()
+    LOAD_BASE()
+    LOAD_CHKSUM_STATE_REGS()      
+    STORE_ALL_REGS(STORE_REG_ACCUMULATE)
+    STORE_STACK()
+    ACCUMULATE_CHECKSUM()
+    STORE_PC()
+    ACCUMULATE_CHECKSUM()
     STORE_CHECKSUM()
+    XOR(RET_REG, RET_REG)
+    RETURN()
       // clang-format on
       :
 #if LIBC_COPT_SETJMP_FORTIFICATION
-      [checksum] "+r"(checksum)
+      [value_mask] "=m"(jmpbuf::value_mask)
 #endif
-      :
-      [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))
+      : DECLARE_ALL_REGS(DECLARE_OFFSET)
 #if LIBC_COPT_SETJMP_FORTIFICATION
-      // clang-format off
+        // clang-format off
       ,[rotation] "i"(jmpbuf::ROTATION)
       ,[__chksum] "i"(offsetof(__jmp_buf, __chksum))
-      ,[mask] "r"(mask)
-  // clang-format on
-#endif
-      : "rax");
+      ,[checksum_cookie] "m"(jmpbuf::checksum_cookie)
 
-  asm(R"(
-    xorl %eax, %eax
-    retq
-  )");
-}
 #endif
+      : STR(RET_REG), STR(BASE_REG), STR(MUL_REG));
+}
 
 } // namespace LIBC_NAMESPACE_DECL



More information about the libc-commits mailing list