From 3a4cf216ab1cbb06ea9b79bb4886088eb319ac76 Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Thu, 17 Oct 2024 15:52:21 -0400 Subject: [PATCH 01/17] [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 9a5d5c3c68da6..bea2b49967bcf 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 3db750b1aed21..612da3c994f10 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 f246e6491cf55..76acaf107f9dc 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 d85c532e8636c..a90c3e177fb73 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 0000000000000..df6a12d185c3e --- /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 + +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(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 b5b0d9ba65599..571f368188710 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 143c9deb11e9a..c3a28333b3ef0 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 5ac10fa87b39a..14af3cb24c2a5 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 eaa724e41f168..34c870f98b1f1 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 ff104c7f0d1d2..fc40ac0b1b109 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(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 Date: Thu, 17 Oct 2024 15:54:19 -0400 Subject: [PATCH 02/17] [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 a90c3e177fb73..6ceaaa8dd3a3f 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 Date: Thu, 17 Oct 2024 15:55:57 -0400 Subject: [PATCH 03/17] [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 c3a28333b3ef0..ef638a296e07a 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 Date: Fri, 18 Oct 2024 10:05:03 -0400 Subject: [PATCH 04/17] [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 fc40ac0b1b109..55d85c90fca44 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(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 Date: Fri, 18 Oct 2024 11:24:34 -0400 Subject: [PATCH 05/17] [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 bea2b49967bcf..f2cf98f8678e4 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 612da3c994f10..73f66e303132b 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 6ceaaa8dd3a3f..21ac0b6ba52e2 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 df6a12d185c3e..1c44362942674 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 +#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(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 0000000000000..81275cbd3340e --- /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 0000000000000..d23c2aca05df3 --- /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 + +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(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 571f368188710..06100be5c1b6f 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 ef638a296e07a..d7c9ef4f32970 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 14af3cb24c2a5..101dbd97642f9 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 34c870f98b1f1..a185e8c04a5a3 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 55d85c90fca44..0af216ea01eee 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 #include +#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 Date: Fri, 18 Oct 2024 13:42:37 -0400 Subject: [PATCH 06/17] [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 f2cf98f8678e4..e1cfa9c37cf4a 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 73f66e303132b..269c3ff121844 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 21ac0b6ba52e2..0073ca1a6930b 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 0000000000000..b4934ca8224f1 --- /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 d7c9ef4f32970..35fde48be691e 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 101dbd97642f9..367cc0a6c3586 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 a185e8c04a5a3..245dfca5b3ed3 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 0af216ea01eee..ded94768f0b92 100644 --- a/libc/startup/linux/do_start.cpp +++ b/libc/startup/linux/do_start.cpp @@ -21,7 +21,7 @@ #include #include -#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(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 Date: Tue, 12 Nov 2024 18:09:11 -0500 Subject: [PATCH 07/17] 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 d23c2aca05df3..c0eebf9395db0 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(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 b4934ca8224f1..0000000000000 --- 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 0000000000000..305ec2dfe269e --- /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 35fde48be691e..aff4b5bfa8752 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 367cc0a6c3586..453cf2475c4cb 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 From 35a1f08e0c65c061022ba6ab49fec3476e3f2d97 Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Tue, 12 Nov 2024 18:14:38 -0500 Subject: [PATCH 08/17] more fixes for 32bits --- libc/include/llvm-libc-types/jmp_buf.h | 2 +- libc/src/setjmp/checksum.h | 4 ++-- libc/src/setjmp/linux/checksum.cpp | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libc/include/llvm-libc-types/jmp_buf.h b/libc/include/llvm-libc-types/jmp_buf.h index 76acaf107f9dc..10374ccdc8a4d 100644 --- a/libc/include/llvm-libc-types/jmp_buf.h +++ b/libc/include/llvm-libc-types/jmp_buf.h @@ -51,7 +51,7 @@ typedef struct { #error "__jmp_buf not available for your target architecture." #endif // unused if checksum feature is not enabled. - __UINT64_TYPE__ __chksum; + __UINTPTR_TYPE__ __chksum; } __jmp_buf; typedef __jmp_buf jmp_buf[1]; diff --git a/libc/src/setjmp/checksum.h b/libc/src/setjmp/checksum.h index 1c44362942674..488b328950c23 100644 --- a/libc/src/setjmp/checksum.h +++ b/libc/src/setjmp/checksum.h @@ -15,10 +15,10 @@ namespace LIBC_NAMESPACE_DECL { namespace jmpbuf { extern __UINTPTR_TYPE__ value_mask; -extern __UINT64_TYPE__ checksum_cookie; +extern __UINTPTR_TYPE__ checksum_cookie; // abitrary prime number -LIBC_INLINE constexpr __UINT64_TYPE__ ROTATION = 13; +LIBC_INLINE constexpr __UINTPTR_TYPE__ ROTATION = 13; void initialize(); extern "C" [[gnu::cold, noreturn]] void __libc_jmpbuf_corruption(); } // namespace jmpbuf diff --git a/libc/src/setjmp/linux/checksum.cpp b/libc/src/setjmp/linux/checksum.cpp index c0eebf9395db0..a166c377c0d37 100644 --- a/libc/src/setjmp/linux/checksum.cpp +++ b/libc/src/setjmp/linux/checksum.cpp @@ -15,8 +15,10 @@ 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; +__UINTPTR_TYPE__ value_mask = + static_cast<__UINTPTR_TYPE__>(0x3899'f0d3'5005'd953ull); +__UINTPTR_TYPE__ checksum_cookie = + static_cast<__UINTPTR_TYPE__>(0xc7d9'd341'6afc'33f2ull); // initialize the checksum state void initialize() { From 30e338c8791a3f92447012003d5bf59d88120fc7 Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Tue, 12 Nov 2024 18:30:05 -0500 Subject: [PATCH 09/17] soften the warning --- libc/src/setjmp/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/src/setjmp/CMakeLists.txt b/libc/src/setjmp/CMakeLists.txt index 0073ca1a6930b..4117420b12a91 100644 --- a/libc/src/setjmp/CMakeLists.txt +++ b/libc/src/setjmp/CMakeLists.txt @@ -14,7 +14,7 @@ if (LIBC_CONF_SETJMP_FORTIFICATION) set(fortification_deps libc.src.setjmp.checksum) 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}") + message(STATUS "Jmpbuf fortification is enabled but not supported for target ${LIBC_TARGET_ARCHITECTURE} ${LIBC_TARGET_OS}") set(fortification_deps) set(fortification_defs -DLIBC_COPT_SETJMP_FORTIFICATION=0) endif() From b67f5f11c664c070618886ffcbd0cd6c8d63af78 Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Mon, 18 Nov 2024 11:42:04 -0500 Subject: [PATCH 10/17] [libc] override config --- libc/config/config.json | 2 +- libc/config/linux/i386/config.json | 8 ++++++++ libc/config/linux/x86_64/config.json | 8 ++++++++ libc/src/setjmp/CMakeLists.txt | 2 +- 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 libc/config/linux/i386/config.json create mode 100644 libc/config/linux/x86_64/config.json diff --git a/libc/config/config.json b/libc/config/config.json index e1cfa9c37cf4a..408909ba6be8c 100644 --- a/libc/config/config.json +++ b/libc/config/config.json @@ -105,7 +105,7 @@ "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_FORTIFICATION": { - "value": true, + "value": false, "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/config/linux/i386/config.json b/libc/config/linux/i386/config.json new file mode 100644 index 0000000000000..1cad9f17d655e --- /dev/null +++ b/libc/config/linux/i386/config.json @@ -0,0 +1,8 @@ +{ + "setjmp": { + "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/config/linux/x86_64/config.json b/libc/config/linux/x86_64/config.json new file mode 100644 index 0000000000000..1cad9f17d655e --- /dev/null +++ b/libc/config/linux/x86_64/config.json @@ -0,0 +1,8 @@ +{ + "setjmp": { + "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/src/setjmp/CMakeLists.txt b/libc/src/setjmp/CMakeLists.txt index 4117420b12a91..0073ca1a6930b 100644 --- a/libc/src/setjmp/CMakeLists.txt +++ b/libc/src/setjmp/CMakeLists.txt @@ -14,7 +14,7 @@ if (LIBC_CONF_SETJMP_FORTIFICATION) set(fortification_deps libc.src.setjmp.checksum) set(fortification_defs -DLIBC_COPT_SETJMP_FORTIFICATION=1) else() - message(STATUS "Jmpbuf fortification is enabled but not supported for target ${LIBC_TARGET_ARCHITECTURE} ${LIBC_TARGET_OS}") + 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_FORTIFICATION=0) endif() From f18519a8330a67eaa091f09d09c1097f4c775e9d Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Mon, 18 Nov 2024 13:53:47 -0500 Subject: [PATCH 11/17] [libc] simplify checksum --- libc/config/linux/i386/config.json | 8 - libc/src/setjmp/checksum.h | 11 +- libc/src/setjmp/x86_64/common.h | 147 ------------------ libc/src/setjmp/x86_64/longjmp.cpp | 41 +---- libc/src/setjmp/x86_64/longjmp_32.cpp.inc | 41 +++++ libc/src/setjmp/x86_64/longjmp_64.cpp.inc | 42 +++++ .../x86_64/longjmp_64_fortified.cpp.inc | 102 ++++++++++++ libc/src/setjmp/x86_64/setjmp.cpp | 46 +----- libc/src/setjmp/x86_64/setjmp_32.cpp.inc | 43 +++++ libc/src/setjmp/x86_64/setjmp_64.cpp.inc | 44 ++++++ .../setjmp/x86_64/setjmp_64_fortified.cpp.inc | 105 +++++++++++++ 11 files changed, 398 insertions(+), 232 deletions(-) delete mode 100644 libc/config/linux/i386/config.json delete mode 100644 libc/src/setjmp/x86_64/common.h create mode 100644 libc/src/setjmp/x86_64/longjmp_32.cpp.inc create mode 100644 libc/src/setjmp/x86_64/longjmp_64.cpp.inc create mode 100644 libc/src/setjmp/x86_64/longjmp_64_fortified.cpp.inc create mode 100644 libc/src/setjmp/x86_64/setjmp_32.cpp.inc create mode 100644 libc/src/setjmp/x86_64/setjmp_64.cpp.inc create mode 100644 libc/src/setjmp/x86_64/setjmp_64_fortified.cpp.inc diff --git a/libc/config/linux/i386/config.json b/libc/config/linux/i386/config.json deleted file mode 100644 index 1cad9f17d655e..0000000000000 --- a/libc/config/linux/i386/config.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "setjmp": { - "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/src/setjmp/checksum.h b/libc/src/setjmp/checksum.h index 488b328950c23..3acba61263e8a 100644 --- a/libc/src/setjmp/checksum.h +++ b/libc/src/setjmp/checksum.h @@ -17,8 +17,15 @@ namespace jmpbuf { extern __UINTPTR_TYPE__ value_mask; extern __UINTPTR_TYPE__ checksum_cookie; -// abitrary prime number -LIBC_INLINE constexpr __UINTPTR_TYPE__ ROTATION = 13; +// single register update derived from aHash +// https://github.com/tkaitchuck/aHash/blob/master/src/fallback_hash.rs#L95 +// +// checksum = folded_multiple(data ^ checksum, MULTIPLE) +// folded_multiple(x, m) = HIGH(x * m) ^ LOW(x * m) + +// From Knuth's PRNG +LIBC_INLINE constexpr __UINTPTR_TYPE__ MULTIPLE = + static_cast<__UINTPTR_TYPE__>(6364136223846793005ull); void initialize(); extern "C" [[gnu::cold, noreturn]] void __libc_jmpbuf_corruption(); } // namespace jmpbuf diff --git a/libc/src/setjmp/x86_64/common.h b/libc/src/setjmp/x86_64/common.h deleted file mode 100644 index 305ec2dfe269e..0000000000000 --- a/libc/src/setjmp/x86_64/common.h +++ /dev/null @@ -1,147 +0,0 @@ -//===-- 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 aff4b5bfa8752..b73df3d303d44 100644 --- a/libc/src/setjmp/x86_64/longjmp.cpp +++ b/libc/src/setjmp/x86_64/longjmp.cpp @@ -10,41 +10,12 @@ #include "src/__support/common.h" #include "src/__support/macros/config.h" -#if !defined(LIBC_TARGET_ARCH_IS_X86) -#error "Invalid file include" -#endif - -#include "src/setjmp/x86_64/common.h" - -#if LIBC_COPT_SETJMP_FORTIFICATION -#include "src/setjmp/checksum.h" -#endif - -namespace LIBC_NAMESPACE_DECL { - -[[gnu::naked]] LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) { - asm volatile( - // clang-format off - LOAD_BASE() - LOAD_CHKSUM_STATE_REGS() - LOAD_ALL_REGS(RESTORE_REG) - EXAMINE_CHECKSUM() - CALCULATE_RETURN_VALUE() - RESTORE_PC() - // clang-format on - : +#ifdef LIBC_TARGET_ARCH_IS_X86_64 #if LIBC_COPT_SETJMP_FORTIFICATION - [value_mask] "=m"(jmpbuf::value_mask) +#include "longjmp_64_fortified.cpp.inc" +#else +#include "longjmp_64.cpp.inc" #endif - : DECLARE_ALL_REGS(DECLARE_OFFSET) -#if LIBC_COPT_SETJMP_FORTIFICATION - // clang-format off - ,[rotation] "i"(jmpbuf::ROTATION) - ,[__chksum] "i"(offsetof(__jmp_buf, __chksum)) - ,[checksum_cookie] "m"(jmpbuf::checksum_cookie) - +#else +#include "longjmp_32.cpp.inc" #endif - : STR(RET_REG), STR(BASE_REG), STR(MUL_REG)); -} - -} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/setjmp/x86_64/longjmp_32.cpp.inc b/libc/src/setjmp/x86_64/longjmp_32.cpp.inc new file mode 100644 index 0000000000000..6b874b24939b1 --- /dev/null +++ b/libc/src/setjmp/x86_64/longjmp_32.cpp.inc @@ -0,0 +1,41 @@ +//===-- Implementation of longjmp (32-bit) --------------------------------===// +// +// 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 "include/llvm-libc-macros/offsetof-macro.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/setjmp/longjmp.h" + +#if !defined(LIBC_TARGET_ARCH_IS_X86_32) +#error "Invalid file include" +#endif + +namespace LIBC_NAMESPACE_DECL { + +[[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 + + 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 + + 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))); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/setjmp/x86_64/longjmp_64.cpp.inc b/libc/src/setjmp/x86_64/longjmp_64.cpp.inc new file mode 100644 index 0000000000000..b240e5359bb99 --- /dev/null +++ b/libc/src/setjmp/x86_64/longjmp_64.cpp.inc @@ -0,0 +1,42 @@ +//===-- Implementation of longjmp (64-bit) --------------------------------===// +// +// 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 "include/llvm-libc-macros/offsetof-macro.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/setjmp/longjmp.h" + +#if !defined(LIBC_TARGET_ARCH_IS_X86_64) || LIBC_COPT_SETJMP_FORTIFICATION +#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))); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/setjmp/x86_64/longjmp_64_fortified.cpp.inc b/libc/src/setjmp/x86_64/longjmp_64_fortified.cpp.inc new file mode 100644 index 0000000000000..8ebe859c4a702 --- /dev/null +++ b/libc/src/setjmp/x86_64/longjmp_64_fortified.cpp.inc @@ -0,0 +1,102 @@ +//===-- Implementation of longjmp (64-bit) --------------------------------===// +// +// 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 "include/llvm-libc-macros/offsetof-macro.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/setjmp/longjmp.h" + +#if !defined(LIBC_TARGET_ARCH_IS_X86_64) || !LIBC_COPT_SETJMP_FORTIFICATION +#error "Invalid file include" +#endif + +#include "src/setjmp/checksum.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) { + asm(R"( + mov %[cookie], %%rdx + + mov %c[rbx](%%rdi), %%rbx + xor %%rbx, %%rdx + xor %[mask], %%rbx + mov $%c[multiple], %%rax + mul %%rdx + xor %%rax, %%rdx + + mov %c[rbp](%%rdi), %%rbp + xor %%rbp, %%rdx + xor %[mask], %%rbp + mov $%c[multiple], %%rax + mul %%rdx + xor %%rax, %%rdx + + mov %c[r12](%%rdi), %%r12 + xor %%r12, %%rdx + xor %[mask], %%r12 + mov $%c[multiple], %%rax + mul %%rdx + xor %%rax, %%rdx + + mov %c[r13](%%rdi), %%r13 + xor %%r13, %%rdx + xor %[mask], %%r13 + mov $%c[multiple], %%rax + mul %%rdx + xor %%rax, %%rdx + + mov %c[r14](%%rdi), %%r14 + xor %%r14, %%rdx + xor %[mask], %%r14 + mov $%c[multiple], %%rax + mul %%rdx + xor %%rax, %%rdx + + mov %c[r15](%%rdi), %%r15 + xor %%r15, %%rdx + xor %[mask], %%r15 + mov $%c[multiple], %%rax + mul %%rdx + xor %%rax, %%rdx + + mov %c[rsp](%%rdi), %%rsp + xor %%rsp, %%rdx + xor %[mask], %%rsp + mov $%c[multiple], %%rax + mul %%rdx + xor %%rax, %%rdx + + mov %c[rip](%%rdi), %%rcx + xor %%rcx, %%rdx + xor %[mask], %%rcx + mov $%c[multiple], %%rax + mul %%rdx + xor %%rax, %%rdx + + cmp %c[chksum](%%rdi), %%rdx + jne __libc_jmpbuf_corruption + + cmpl $0x1, %%esi + adcl $0x0, %%esi + movq %%rsi, %%rax + + jmpq *%%rcx + )" + : [cookie] "=m"(jmpbuf::checksum_cookie), [mask] "=m"(jmpbuf::value_mask) + : + [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)), + [chksum] "i"(offsetof(__jmp_buf, __chksum)), + [multiple] "i"(jmpbuf::MULTIPLE) + : "rax", "rcx", "rdx"); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/setjmp/x86_64/setjmp.cpp b/libc/src/setjmp/x86_64/setjmp.cpp index 453cf2475c4cb..b1de6fbb0c79f 100644 --- a/libc/src/setjmp/x86_64/setjmp.cpp +++ b/libc/src/setjmp/x86_64/setjmp.cpp @@ -6,50 +6,16 @@ // //===----------------------------------------------------------------------===// -#include "include/llvm-libc-macros/offsetof-macro.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" #include "src/setjmp/setjmp_impl.h" -#if !defined(LIBC_TARGET_ARCH_IS_X86) -#error "Invalid file include" -#endif - -#include "src/setjmp/x86_64/common.h" - +#ifdef LIBC_TARGET_ARCH_IS_X86_64 #if LIBC_COPT_SETJMP_FORTIFICATION -#include "src/setjmp/checksum.h" +#include "setjmp_64_fortified.cpp.inc" +#else +#include "setjmp_64.cpp.inc" #endif - -namespace LIBC_NAMESPACE_DECL { -[[gnu::naked]] -LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) { - asm volatile( - // clang-format off - 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 - [value_mask] "=m"(jmpbuf::value_mask) +#else +#include "setjmp_32.cpp.inc" #endif - : DECLARE_ALL_REGS(DECLARE_OFFSET) -#if LIBC_COPT_SETJMP_FORTIFICATION - // clang-format off - ,[rotation] "i"(jmpbuf::ROTATION) - ,[__chksum] "i"(offsetof(__jmp_buf, __chksum)) - ,[checksum_cookie] "m"(jmpbuf::checksum_cookie) - -#endif - : STR(RET_REG), STR(BASE_REG), STR(MUL_REG)); -} - -} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/setjmp/x86_64/setjmp_32.cpp.inc b/libc/src/setjmp/x86_64/setjmp_32.cpp.inc new file mode 100644 index 0000000000000..5a26f5b1aed10 --- /dev/null +++ b/libc/src/setjmp/x86_64/setjmp_32.cpp.inc @@ -0,0 +1,43 @@ +//===-- Implementation of setjmp (32-bit) ---------------------------------===// +// +// 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 "include/llvm-libc-macros/offsetof-macro.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/setjmp/setjmp_impl.h" + +#if !defined(LIBC_TARGET_ARCH_IS_X86_32) +#error "Invalid file include" +#endif + +namespace LIBC_NAMESPACE_DECL { +[[gnu::naked]] +LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) { + asm(R"( + mov 4(%%esp), %%eax + + mov %%ebx, %c[ebx](%%eax) + mov %%esi, %c[esi](%%eax) + mov %%edi, %c[edi](%%eax) + mov %%ebp, %c[ebp](%%eax) + + lea 4(%%esp), %%ecx + mov %%ecx, %c[esp](%%eax) + + mov (%%esp), %%ecx + mov %%ecx, %c[eip](%%eax) + + 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"); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/setjmp/x86_64/setjmp_64.cpp.inc b/libc/src/setjmp/x86_64/setjmp_64.cpp.inc new file mode 100644 index 0000000000000..82ff509a678f0 --- /dev/null +++ b/libc/src/setjmp/x86_64/setjmp_64.cpp.inc @@ -0,0 +1,44 @@ +//===-- Implementation of setjmp (64-bit) ---------------------------------===// +// +// 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 "include/llvm-libc-macros/offsetof-macro.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/setjmp/setjmp_impl.h" + +#if !defined(LIBC_TARGET_ARCH_IS_X86_64) || LIBC_COPT_SETJMP_FORTIFICATION +#error "Invalid file include" +#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)), + [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"); +} +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/setjmp/x86_64/setjmp_64_fortified.cpp.inc b/libc/src/setjmp/x86_64/setjmp_64_fortified.cpp.inc new file mode 100644 index 0000000000000..146870806f1cd --- /dev/null +++ b/libc/src/setjmp/x86_64/setjmp_64_fortified.cpp.inc @@ -0,0 +1,105 @@ +//===-- Implementation of setjmp (64-bit) ---------------------------------===// +// +// 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 "include/llvm-libc-macros/offsetof-macro.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/setjmp/setjmp_impl.h" + +#if !defined(LIBC_TARGET_ARCH_IS_X86_64) || !LIBC_COPT_SETJMP_FORTIFICATION +#error "Invalid file include" +#endif + +#include "src/setjmp/checksum.h" + +namespace LIBC_NAMESPACE_DECL { + +[[gnu::naked]] +LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) { + asm(R"( + mov %[cookie], %%rdx + + mov %%rbx, %%rax + xor %[mask], %%rax + mov %%rax, %c[rbx](%%rdi) + xor %%rax, %%rdx + mov $%c[multiple], %%rax + mul %%rdx + xor %%rax, %%rdx + + mov %%rbp, %%rax + xor %[mask], %%rax + mov %%rax, %c[rbp](%%rdi) + xor %%rax, %%rdx + mov $%c[multiple], %%rax + mul %%rdx + xor %%rax, %%rdx + + mov %%r12, %%rax + xor %[mask], %%rax + mov %%rax, %c[r12](%%rdi) + xor %%rax, %%rdx + mov $%c[multiple], %%rax + mul %%rdx + xor %%rax, %%rdx + + mov %%r13, %%rax + xor %[mask], %%rax + mov %%rax, %c[r13](%%rdi) + xor %%rax, %%rdx + mov $%c[multiple], %%rax + mul %%rdx + xor %%rax, %%rdx + + mov %%r14, %%rax + xor %[mask], %%rax + mov %%rax, %c[r14](%%rdi) + xor %%rax, %%rdx + mov $%c[multiple], %%rax + mul %%rdx + xor %%rax, %%rdx + + mov %%r15, %%rax + xor %[mask], %%rax + mov %%rax, %c[r15](%%rdi) + xor %%rax, %%rdx + mov $%c[multiple], %%rax + mul %%rdx + xor %%rax, %%rdx + + lea 8(%%rsp), %%rax + xor %[mask], %%rax + mov %%rax, %c[rsp](%%rdi) + xor %%rax, %%rdx + mov $%c[multiple], %%rax + mul %%rdx + xor %%rax, %%rdx + + mov (%%rsp), %%rax + xor %[mask], %%rax + mov %%rax, %c[rip](%%rdi) + xor %%rax, %%rdx + mov $%c[multiple], %%rax + mul %%rdx + xor %%rax, %%rdx + + mov %%rdx, %c[chksum](%%rdi) + xor %%rax, %%rax + ret)" + : [cookie] "=m"(jmpbuf::checksum_cookie), [mask] "=m"(jmpbuf::value_mask) + : + [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)), + [chksum] "i"(offsetof(__jmp_buf, __chksum)), + [multiple] "i"(jmpbuf::MULTIPLE) + : "rax", "rdx"); +} + +} // namespace LIBC_NAMESPACE_DECL From b28493046e0ba9e6b93ee6ce6c79673b2ec52ea4 Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Mon, 18 Nov 2024 17:43:18 -0500 Subject: [PATCH 12/17] [libc] address CRs --- libc/src/setjmp/i386/CMakeLists.txt | 24 ++++++++++ .../longjmp_32.cpp.inc => i386/longjmp.cpp} | 0 .../setjmp_32.cpp.inc => i386/setjmp.cpp} | 0 libc/src/setjmp/linux/checksum.cpp | 14 ++---- libc/src/setjmp/x86_64/CMakeLists.txt | 12 ++++- libc/src/setjmp/x86_64/longjmp.cpp | 41 ++++++++++++----- libc/src/setjmp/x86_64/longjmp_64.cpp.inc | 42 ------------------ ...ortified.cpp.inc => longjmp_fortified.cpp} | 0 libc/src/setjmp/x86_64/setjmp.cpp | 41 +++++++++++++---- libc/src/setjmp/x86_64/setjmp_64.cpp.inc | 44 ------------------- ...fortified.cpp.inc => setjmp_fortified.cpp} | 0 11 files changed, 101 insertions(+), 117 deletions(-) create mode 100644 libc/src/setjmp/i386/CMakeLists.txt rename libc/src/setjmp/{x86_64/longjmp_32.cpp.inc => i386/longjmp.cpp} (100%) rename libc/src/setjmp/{x86_64/setjmp_32.cpp.inc => i386/setjmp.cpp} (100%) delete mode 100644 libc/src/setjmp/x86_64/longjmp_64.cpp.inc rename libc/src/setjmp/x86_64/{longjmp_64_fortified.cpp.inc => longjmp_fortified.cpp} (100%) delete mode 100644 libc/src/setjmp/x86_64/setjmp_64.cpp.inc rename libc/src/setjmp/x86_64/{setjmp_64_fortified.cpp.inc => setjmp_fortified.cpp} (100%) diff --git a/libc/src/setjmp/i386/CMakeLists.txt b/libc/src/setjmp/i386/CMakeLists.txt new file mode 100644 index 0000000000000..b5b0d9ba65599 --- /dev/null +++ b/libc/src/setjmp/i386/CMakeLists.txt @@ -0,0 +1,24 @@ +add_entrypoint_object( + setjmp + SRCS + setjmp.cpp + HDRS + ../setjmp_impl.h + DEPENDS + libc.hdr.types.jmp_buf + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + longjmp + SRCS + longjmp.cpp + HDRS + ../longjmp.h + DEPENDS + libc.hdr.types.jmp_buf + COMPILE_OPTIONS + -O3 + -fomit-frame-pointer +) diff --git a/libc/src/setjmp/x86_64/longjmp_32.cpp.inc b/libc/src/setjmp/i386/longjmp.cpp similarity index 100% rename from libc/src/setjmp/x86_64/longjmp_32.cpp.inc rename to libc/src/setjmp/i386/longjmp.cpp diff --git a/libc/src/setjmp/x86_64/setjmp_32.cpp.inc b/libc/src/setjmp/i386/setjmp.cpp similarity index 100% rename from libc/src/setjmp/x86_64/setjmp_32.cpp.inc rename to libc/src/setjmp/i386/setjmp.cpp diff --git a/libc/src/setjmp/linux/checksum.cpp b/libc/src/setjmp/linux/checksum.cpp index a166c377c0d37..cb3f6f89a6bab 100644 --- a/libc/src/setjmp/linux/checksum.cpp +++ b/libc/src/setjmp/linux/checksum.cpp @@ -22,17 +22,11 @@ __UINTPTR_TYPE__ checksum_cookie = // initialize the checksum state void initialize() { - union { - struct { - __UINTPTR_TYPE__ entropy0; - __UINTPTR_TYPE__ entropy1; - }; - char buffer[sizeof(__UINTPTR_TYPE__) * 2]; - }; - syscall_impl(SYS_getrandom, buffer, sizeof(buffer), 0); + __UINTPTR_TYPE__ entropy[2]; + syscall_impl(SYS_getrandom, entropy, sizeof(entropy), 0); // add in additional entropy - jmpbuf::value_mask ^= entropy0; - jmpbuf::checksum_cookie ^= entropy1; + jmpbuf::value_mask ^= entropy[0]; + jmpbuf::checksum_cookie ^= entropy[0]; } extern "C" [[gnu::cold, noreturn]] void __libc_jmpbuf_corruption() { diff --git a/libc/src/setjmp/x86_64/CMakeLists.txt b/libc/src/setjmp/x86_64/CMakeLists.txt index 06100be5c1b6f..df3d352696a05 100644 --- a/libc/src/setjmp/x86_64/CMakeLists.txt +++ b/libc/src/setjmp/x86_64/CMakeLists.txt @@ -1,7 +1,15 @@ +if(LIBC_CONF_SETJMP_FORTIFICATION) + set (setjmp_src setjmp_fortified.cpp) + set (longjmp_src longjmp_fortified.cpp) +else() + set (setjmp_src setjmp.cpp) + set (longjmp_src longjmp.cpp) +endif() + add_entrypoint_object( setjmp SRCS - setjmp.cpp + ${setjmp_src} HDRS ../setjmp_impl.h DEPENDS @@ -15,7 +23,7 @@ add_entrypoint_object( add_entrypoint_object( longjmp SRCS - longjmp.cpp + ${longjmp_src} HDRS ../longjmp.h DEPENDS diff --git a/libc/src/setjmp/x86_64/longjmp.cpp b/libc/src/setjmp/x86_64/longjmp.cpp index b73df3d303d44..b240e5359bb99 100644 --- a/libc/src/setjmp/x86_64/longjmp.cpp +++ b/libc/src/setjmp/x86_64/longjmp.cpp @@ -1,4 +1,4 @@ -//===-- Implementation of longjmp -----------------------------------------===// +//===-- Implementation of longjmp (64-bit) --------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,16 +6,37 @@ // //===----------------------------------------------------------------------===// -#include "src/setjmp/longjmp.h" +#include "include/llvm-libc-macros/offsetof-macro.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" +#include "src/setjmp/longjmp.h" -#ifdef LIBC_TARGET_ARCH_IS_X86_64 -#if LIBC_COPT_SETJMP_FORTIFICATION -#include "longjmp_64_fortified.cpp.inc" -#else -#include "longjmp_64.cpp.inc" -#endif -#else -#include "longjmp_32.cpp.inc" +#if !defined(LIBC_TARGET_ARCH_IS_X86_64) || LIBC_COPT_SETJMP_FORTIFICATION +#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))); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/setjmp/x86_64/longjmp_64.cpp.inc b/libc/src/setjmp/x86_64/longjmp_64.cpp.inc deleted file mode 100644 index b240e5359bb99..0000000000000 --- a/libc/src/setjmp/x86_64/longjmp_64.cpp.inc +++ /dev/null @@ -1,42 +0,0 @@ -//===-- Implementation of longjmp (64-bit) --------------------------------===// -// -// 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 "include/llvm-libc-macros/offsetof-macro.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" -#include "src/setjmp/longjmp.h" - -#if !defined(LIBC_TARGET_ARCH_IS_X86_64) || LIBC_COPT_SETJMP_FORTIFICATION -#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))); -} - -} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/setjmp/x86_64/longjmp_64_fortified.cpp.inc b/libc/src/setjmp/x86_64/longjmp_fortified.cpp similarity index 100% rename from libc/src/setjmp/x86_64/longjmp_64_fortified.cpp.inc rename to libc/src/setjmp/x86_64/longjmp_fortified.cpp diff --git a/libc/src/setjmp/x86_64/setjmp.cpp b/libc/src/setjmp/x86_64/setjmp.cpp index b1de6fbb0c79f..82ff509a678f0 100644 --- a/libc/src/setjmp/x86_64/setjmp.cpp +++ b/libc/src/setjmp/x86_64/setjmp.cpp @@ -1,4 +1,4 @@ -//===-- Implementation of setjmp ------------------------------------------===// +//===-- Implementation of setjmp (64-bit) ---------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,16 +6,39 @@ // //===----------------------------------------------------------------------===// +#include "include/llvm-libc-macros/offsetof-macro.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" #include "src/setjmp/setjmp_impl.h" -#ifdef LIBC_TARGET_ARCH_IS_X86_64 -#if LIBC_COPT_SETJMP_FORTIFICATION -#include "setjmp_64_fortified.cpp.inc" -#else -#include "setjmp_64.cpp.inc" -#endif -#else -#include "setjmp_32.cpp.inc" +#if !defined(LIBC_TARGET_ARCH_IS_X86_64) || LIBC_COPT_SETJMP_FORTIFICATION +#error "Invalid file include" #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)), + [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"); +} +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/setjmp/x86_64/setjmp_64.cpp.inc b/libc/src/setjmp/x86_64/setjmp_64.cpp.inc deleted file mode 100644 index 82ff509a678f0..0000000000000 --- a/libc/src/setjmp/x86_64/setjmp_64.cpp.inc +++ /dev/null @@ -1,44 +0,0 @@ -//===-- Implementation of setjmp (64-bit) ---------------------------------===// -// -// 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 "include/llvm-libc-macros/offsetof-macro.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" -#include "src/setjmp/setjmp_impl.h" - -#if !defined(LIBC_TARGET_ARCH_IS_X86_64) || LIBC_COPT_SETJMP_FORTIFICATION -#error "Invalid file include" -#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)), - [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"); -} -} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/setjmp/x86_64/setjmp_64_fortified.cpp.inc b/libc/src/setjmp/x86_64/setjmp_fortified.cpp similarity index 100% rename from libc/src/setjmp/x86_64/setjmp_64_fortified.cpp.inc rename to libc/src/setjmp/x86_64/setjmp_fortified.cpp From 6c7d9648d6c5b8aa389f99f27ac23279c97e862a Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Mon, 18 Nov 2024 17:48:42 -0500 Subject: [PATCH 13/17] [libc] fixes --- libc/src/setjmp/CMakeLists.txt | 7 +++---- libc/src/setjmp/i386/longjmp.cpp | 2 +- libc/src/setjmp/x86_64/longjmp.cpp | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/libc/src/setjmp/CMakeLists.txt b/libc/src/setjmp/CMakeLists.txt index 0073ca1a6930b..aabd05bedc220 100644 --- a/libc/src/setjmp/CMakeLists.txt +++ b/libc/src/setjmp/CMakeLists.txt @@ -1,8 +1,7 @@ -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) -endif() - if (LIBC_CONF_SETJMP_FORTIFICATION) + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) + endif() if (TARGET libc.src.setjmp.${LIBC_TARGET_OS}.checksum AND LIBC_TARGET_ARCHITECTURE STREQUAL "x86_64") add_object_library( diff --git a/libc/src/setjmp/i386/longjmp.cpp b/libc/src/setjmp/i386/longjmp.cpp index 6b874b24939b1..fc60f3a8672a0 100644 --- a/libc/src/setjmp/i386/longjmp.cpp +++ b/libc/src/setjmp/i386/longjmp.cpp @@ -6,10 +6,10 @@ // //===----------------------------------------------------------------------===// +#include "src/setjmp/longjmp.h" #include "include/llvm-libc-macros/offsetof-macro.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" -#include "src/setjmp/longjmp.h" #if !defined(LIBC_TARGET_ARCH_IS_X86_32) #error "Invalid file include" diff --git a/libc/src/setjmp/x86_64/longjmp.cpp b/libc/src/setjmp/x86_64/longjmp.cpp index b240e5359bb99..f30c752d2e71a 100644 --- a/libc/src/setjmp/x86_64/longjmp.cpp +++ b/libc/src/setjmp/x86_64/longjmp.cpp @@ -6,10 +6,10 @@ // //===----------------------------------------------------------------------===// +#include "src/setjmp/longjmp.h" #include "include/llvm-libc-macros/offsetof-macro.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" -#include "src/setjmp/longjmp.h" #if !defined(LIBC_TARGET_ARCH_IS_X86_64) || LIBC_COPT_SETJMP_FORTIFICATION #error "Invalid file include" From 6e70ac512021bbc535662bcb2ead1da6c9133139 Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Tue, 19 Nov 2024 10:48:23 -0500 Subject: [PATCH 14/17] [libc] address CRs --- libc/src/setjmp/x86_64/longjmp_fortified.cpp | 19 ++++++++----------- libc/src/setjmp/x86_64/setjmp_fortified.cpp | 19 ++++++++----------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/libc/src/setjmp/x86_64/longjmp_fortified.cpp b/libc/src/setjmp/x86_64/longjmp_fortified.cpp index 8ebe859c4a702..5529f9b15025c 100644 --- a/libc/src/setjmp/x86_64/longjmp_fortified.cpp +++ b/libc/src/setjmp/x86_64/longjmp_fortified.cpp @@ -21,8 +21,6 @@ namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) { asm(R"( - mov %[cookie], %%rdx - mov %c[rbx](%%rdi), %%rbx xor %%rbx, %%rdx xor %[mask], %%rbx @@ -87,16 +85,15 @@ LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) { movq %%rsi, %%rax jmpq *%%rcx - )" - : [cookie] "=m"(jmpbuf::checksum_cookie), [mask] "=m"(jmpbuf::value_mask) - : - [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)), + )" ::[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)), [chksum] "i"(offsetof(__jmp_buf, __chksum)), - [multiple] "i"(jmpbuf::MULTIPLE) - : "rax", "rcx", "rdx"); + [multiple] "i"(jmpbuf::MULTIPLE), [cookie] "d"(jmpbuf::checksum_cookie), + [mask] "m"(jmpbuf::value_mask) + :); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/setjmp/x86_64/setjmp_fortified.cpp b/libc/src/setjmp/x86_64/setjmp_fortified.cpp index 146870806f1cd..76cd0d2ac64d8 100644 --- a/libc/src/setjmp/x86_64/setjmp_fortified.cpp +++ b/libc/src/setjmp/x86_64/setjmp_fortified.cpp @@ -22,8 +22,6 @@ namespace LIBC_NAMESPACE_DECL { [[gnu::naked]] LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) { asm(R"( - mov %[cookie], %%rdx - mov %%rbx, %%rax xor %[mask], %%rax mov %%rax, %c[rbx](%%rdi) @@ -90,16 +88,15 @@ LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) { mov %%rdx, %c[chksum](%%rdi) xor %%rax, %%rax - ret)" - : [cookie] "=m"(jmpbuf::checksum_cookie), [mask] "=m"(jmpbuf::value_mask) - : - [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)), + ret)" ::[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)), [chksum] "i"(offsetof(__jmp_buf, __chksum)), - [multiple] "i"(jmpbuf::MULTIPLE) - : "rax", "rdx"); + [multiple] "i"(jmpbuf::MULTIPLE), [cookie] "d"(jmpbuf::checksum_cookie), + [mask] "m"(jmpbuf::value_mask) + :); } } // namespace LIBC_NAMESPACE_DECL From 70f663d6e4b2bc3112905ded42a63f67dee841ec Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Tue, 19 Nov 2024 11:09:44 -0500 Subject: [PATCH 15/17] [libc] simplify assembly --- libc/src/setjmp/x86_64/longjmp_fortified.cpp | 62 +++++------ libc/src/setjmp/x86_64/setjmp_fortified.cpp | 111 +++++++++---------- 2 files changed, 78 insertions(+), 95 deletions(-) diff --git a/libc/src/setjmp/x86_64/longjmp_fortified.cpp b/libc/src/setjmp/x86_64/longjmp_fortified.cpp index 5529f9b15025c..e53b76498a029 100644 --- a/libc/src/setjmp/x86_64/longjmp_fortified.cpp +++ b/libc/src/setjmp/x86_64/longjmp_fortified.cpp @@ -22,62 +22,55 @@ namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) { asm(R"( mov %c[rbx](%%rdi), %%rbx - xor %%rbx, %%rdx + xor %%rbx, %%rax xor %[mask], %%rbx - mov $%c[multiple], %%rax - mul %%rdx - xor %%rax, %%rdx + mul %%rcx + xor %%rdx, %%rax mov %c[rbp](%%rdi), %%rbp - xor %%rbp, %%rdx + xor %%rbp, %%rax xor %[mask], %%rbp - mov $%c[multiple], %%rax - mul %%rdx - xor %%rax, %%rdx + mul %%rcx + xor %%rdx, %%rax mov %c[r12](%%rdi), %%r12 - xor %%r12, %%rdx + xor %%r12, %%rax xor %[mask], %%r12 - mov $%c[multiple], %%rax - mul %%rdx - xor %%rax, %%rdx + mul %%rcx + xor %%rdx, %%rax mov %c[r13](%%rdi), %%r13 - xor %%r13, %%rdx + xor %%r13, %%rax xor %[mask], %%r13 - mov $%c[multiple], %%rax - mul %%rdx - xor %%rax, %%rdx + mul %%rcx + xor %%rdx, %%rax mov %c[r14](%%rdi), %%r14 - xor %%r14, %%rdx + xor %%r14, %%rax xor %[mask], %%r14 - mov $%c[multiple], %%rax - mul %%rdx - xor %%rax, %%rdx + mul %%rcx + xor %%rdx, %%rax mov %c[r15](%%rdi), %%r15 - xor %%r15, %%rdx + xor %%r15, %%rax xor %[mask], %%r15 - mov $%c[multiple], %%rax - mul %%rdx - xor %%rax, %%rdx + mul %%rcx + xor %%rdx, %%rax mov %c[rsp](%%rdi), %%rsp - xor %%rsp, %%rdx + xor %%rsp, %%rax xor %[mask], %%rsp - mov $%c[multiple], %%rax - mul %%rdx - xor %%rax, %%rdx + mul %%rcx + xor %%rdx, %%rax + mov %%rcx, %%rdx mov %c[rip](%%rdi), %%rcx - xor %%rcx, %%rdx + xor %%rcx, %%rax xor %[mask], %%rcx - mov $%c[multiple], %%rax mul %%rdx - xor %%rax, %%rdx + xor %%rdx, %%rax - cmp %c[chksum](%%rdi), %%rdx + cmp %c[chksum](%%rdi), %%rax jne __libc_jmpbuf_corruption cmpl $0x1, %%esi @@ -90,9 +83,8 @@ LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) { [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)), - [chksum] "i"(offsetof(__jmp_buf, __chksum)), - [multiple] "i"(jmpbuf::MULTIPLE), [cookie] "d"(jmpbuf::checksum_cookie), - [mask] "m"(jmpbuf::value_mask) + [chksum] "i"(offsetof(__jmp_buf, __chksum)), "c"(jmpbuf::MULTIPLE), + [cookie] "a"(jmpbuf::checksum_cookie), [mask] "m"(jmpbuf::value_mask) :); } diff --git a/libc/src/setjmp/x86_64/setjmp_fortified.cpp b/libc/src/setjmp/x86_64/setjmp_fortified.cpp index 76cd0d2ac64d8..2367302a49787 100644 --- a/libc/src/setjmp/x86_64/setjmp_fortified.cpp +++ b/libc/src/setjmp/x86_64/setjmp_fortified.cpp @@ -22,80 +22,71 @@ namespace LIBC_NAMESPACE_DECL { [[gnu::naked]] LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) { asm(R"( - mov %%rbx, %%rax - xor %[mask], %%rax - mov %%rax, %c[rbx](%%rdi) - xor %%rax, %%rdx - mov $%c[multiple], %%rax - mul %%rdx - xor %%rax, %%rdx + mov %%rbx, %%rdx + xor %[mask], %%rdx + mov %%rdx, %c[rbx](%%rdi) + xor %%rdx, %%rax + mul %%rcx + xor %%rdx, %%rax - mov %%rbp, %%rax - xor %[mask], %%rax - mov %%rax, %c[rbp](%%rdi) - xor %%rax, %%rdx - mov $%c[multiple], %%rax - mul %%rdx - xor %%rax, %%rdx + mov %%rbp, %%rdx + xor %[mask], %%rdx + mov %%rdx, %c[rbp](%%rdi) + xor %%rdx, %%rax + mul %%rcx + xor %%rdx, %%rax - mov %%r12, %%rax - xor %[mask], %%rax - mov %%rax, %c[r12](%%rdi) - xor %%rax, %%rdx - mov $%c[multiple], %%rax - mul %%rdx - xor %%rax, %%rdx + mov %%r12, %%rdx + xor %[mask], %%rdx + mov %%rdx, %c[r12](%%rdi) + xor %%rdx, %%rax + mul %%rcx + xor %%rdx, %%rax - mov %%r13, %%rax - xor %[mask], %%rax - mov %%rax, %c[r13](%%rdi) - xor %%rax, %%rdx - mov $%c[multiple], %%rax - mul %%rdx - xor %%rax, %%rdx + mov %%r13, %%rdx + xor %[mask], %%rdx + mov %%rdx, %c[r13](%%rdi) + xor %%rdx, %%rax + mul %%rcx + xor %%rdx, %%rax - mov %%r14, %%rax - xor %[mask], %%rax - mov %%rax, %c[r14](%%rdi) - xor %%rax, %%rdx - mov $%c[multiple], %%rax - mul %%rdx - xor %%rax, %%rdx + mov %%r14, %%rdx + xor %[mask], %%rdx + mov %%rdx, %c[r14](%%rdi) + xor %%rdx, %%rax + mul %%rcx + xor %%rdx, %%rax - mov %%r15, %%rax - xor %[mask], %%rax - mov %%rax, %c[r15](%%rdi) - xor %%rax, %%rdx - mov $%c[multiple], %%rax - mul %%rdx - xor %%rax, %%rdx + mov %%r15, %%rdx + xor %[mask], %%rdx + mov %%rdx, %c[r15](%%rdi) + xor %%rdx, %%rax + mul %%rcx + xor %%rdx, %%rax - lea 8(%%rsp), %%rax - xor %[mask], %%rax - mov %%rax, %c[rsp](%%rdi) - xor %%rax, %%rdx - mov $%c[multiple], %%rax - mul %%rdx - xor %%rax, %%rdx + lea 8(%%rsp), %%rdx + xor %[mask], %%rdx + mov %%rdx, %c[rsp](%%rdi) + xor %%rdx, %%rax + mul %%rcx + xor %%rdx, %%rax - mov (%%rsp), %%rax - xor %[mask], %%rax - mov %%rax, %c[rip](%%rdi) - xor %%rax, %%rdx - mov $%c[multiple], %%rax - mul %%rdx - xor %%rax, %%rdx + mov (%%rsp), %%rdx + xor %[mask], %%rdx + mov %%rdx, %c[rip](%%rdi) + xor %%rdx, %%rax + mul %%rcx + xor %%rdx, %%rax - mov %%rdx, %c[chksum](%%rdi) + mov %%rax, %c[chksum](%%rdi) xor %%rax, %%rax ret)" ::[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)), - [chksum] "i"(offsetof(__jmp_buf, __chksum)), - [multiple] "i"(jmpbuf::MULTIPLE), [cookie] "d"(jmpbuf::checksum_cookie), - [mask] "m"(jmpbuf::value_mask) + [chksum] "i"(offsetof(__jmp_buf, __chksum)), "c"(jmpbuf::MULTIPLE), + [cookie] "a"(jmpbuf::checksum_cookie), [mask] "m"(jmpbuf::value_mask) :); } From d5791e18b995f13dd34796d9c66fc21b76d676c9 Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Tue, 19 Nov 2024 11:43:55 -0500 Subject: [PATCH 16/17] [libc] simplify assembly --- libc/src/setjmp/x86_64/setjmp_fortified.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/libc/src/setjmp/x86_64/setjmp_fortified.cpp b/libc/src/setjmp/x86_64/setjmp_fortified.cpp index 2367302a49787..074d1a0fbfcc1 100644 --- a/libc/src/setjmp/x86_64/setjmp_fortified.cpp +++ b/libc/src/setjmp/x86_64/setjmp_fortified.cpp @@ -26,56 +26,56 @@ LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) { xor %[mask], %%rdx mov %%rdx, %c[rbx](%%rdi) xor %%rdx, %%rax - mul %%rcx + mulq %[multiple] xor %%rdx, %%rax mov %%rbp, %%rdx xor %[mask], %%rdx mov %%rdx, %c[rbp](%%rdi) xor %%rdx, %%rax - mul %%rcx + mulq %[multiple] xor %%rdx, %%rax mov %%r12, %%rdx xor %[mask], %%rdx mov %%rdx, %c[r12](%%rdi) xor %%rdx, %%rax - mul %%rcx + mulq %[multiple] xor %%rdx, %%rax mov %%r13, %%rdx xor %[mask], %%rdx mov %%rdx, %c[r13](%%rdi) xor %%rdx, %%rax - mul %%rcx + mulq %[multiple] xor %%rdx, %%rax mov %%r14, %%rdx xor %[mask], %%rdx mov %%rdx, %c[r14](%%rdi) xor %%rdx, %%rax - mul %%rcx + mulq %[multiple] xor %%rdx, %%rax mov %%r15, %%rdx xor %[mask], %%rdx mov %%rdx, %c[r15](%%rdi) xor %%rdx, %%rax - mul %%rcx + mulq %[multiple] xor %%rdx, %%rax lea 8(%%rsp), %%rdx xor %[mask], %%rdx mov %%rdx, %c[rsp](%%rdi) xor %%rdx, %%rax - mul %%rcx + mulq %[multiple] xor %%rdx, %%rax mov (%%rsp), %%rdx xor %[mask], %%rdx mov %%rdx, %c[rip](%%rdi) xor %%rdx, %%rax - mul %%rcx + mulq %[multiple] xor %%rdx, %%rax mov %%rax, %c[chksum](%%rdi) @@ -85,8 +85,9 @@ LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) { [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)), - [chksum] "i"(offsetof(__jmp_buf, __chksum)), "c"(jmpbuf::MULTIPLE), - [cookie] "a"(jmpbuf::checksum_cookie), [mask] "m"(jmpbuf::value_mask) + [chksum] "i"(offsetof(__jmp_buf, __chksum)), + [multiple] "m"(jmpbuf::MULTIPLE), [cookie] "a"(jmpbuf::checksum_cookie), + [mask] "m"(jmpbuf::value_mask) :); } From 30b48d3af181f91bfcb446b0a7162a196568f224 Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Fri, 22 Nov 2024 13:43:40 -0500 Subject: [PATCH 17/17] address CRs --- libc/src/setjmp/x86_64/longjmp_fortified.cpp | 60 +++++++++++--------- libc/src/setjmp/x86_64/setjmp_fortified.cpp | 56 +++++++++--------- 2 files changed, 61 insertions(+), 55 deletions(-) diff --git a/libc/src/setjmp/x86_64/longjmp_fortified.cpp b/libc/src/setjmp/x86_64/longjmp_fortified.cpp index e53b76498a029..27c8d9a9e6179 100644 --- a/libc/src/setjmp/x86_64/longjmp_fortified.cpp +++ b/libc/src/setjmp/x86_64/longjmp_fortified.cpp @@ -22,60 +22,63 @@ namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) { asm(R"( mov %c[rbx](%%rdi), %%rbx - xor %%rbx, %%rax + xor %%rbx, %[cookie] xor %[mask], %%rbx - mul %%rcx - xor %%rdx, %%rax + mul %[multiple] + xor %%rdx, %[cookie] mov %c[rbp](%%rdi), %%rbp - xor %%rbp, %%rax + xor %%rbp, %[cookie] xor %[mask], %%rbp - mul %%rcx - xor %%rdx, %%rax + mul %[multiple] + xor %%rdx, %[cookie] mov %c[r12](%%rdi), %%r12 - xor %%r12, %%rax + xor %%r12, %[cookie] xor %[mask], %%r12 - mul %%rcx - xor %%rdx, %%rax + mul %[multiple] + xor %%rdx, %[cookie] mov %c[r13](%%rdi), %%r13 - xor %%r13, %%rax + xor %%r13, %[cookie] xor %[mask], %%r13 - mul %%rcx - xor %%rdx, %%rax + mul %[multiple] + xor %%rdx, %[cookie] mov %c[r14](%%rdi), %%r14 - xor %%r14, %%rax + xor %%r14, %[cookie] xor %[mask], %%r14 - mul %%rcx - xor %%rdx, %%rax + mul %[multiple] + xor %%rdx, %[cookie] mov %c[r15](%%rdi), %%r15 - xor %%r15, %%rax + xor %%r15, %[cookie] xor %[mask], %%r15 - mul %%rcx - xor %%rdx, %%rax + mul %[multiple] + xor %%rdx, %[cookie] mov %c[rsp](%%rdi), %%rsp - xor %%rsp, %%rax + xor %%rsp, %[cookie] xor %[mask], %%rsp - mul %%rcx - xor %%rdx, %%rax + mul %[multiple] + xor %%rdx, %[cookie] - mov %%rcx, %%rdx + # move multiplication factor (which should be in rcx) to rdx + # free up rcx for PC recovery + mov %[multiple], %%rdx mov %c[rip](%%rdi), %%rcx - xor %%rcx, %%rax + xor %%rcx, %[cookie] xor %[mask], %%rcx mul %%rdx - xor %%rdx, %%rax + xor %%rdx, %[cookie] - cmp %c[chksum](%%rdi), %%rax + cmp %c[chksum](%%rdi), %[cookie] jne __libc_jmpbuf_corruption + # from this point, rax does not stand for accumulator but for return value cmpl $0x1, %%esi adcl $0x0, %%esi - movq %%rsi, %%rax + movq %%rsi, %%rax jmpq *%%rcx )" ::[rbx] "i"(offsetof(__jmp_buf, rbx)), @@ -83,8 +86,9 @@ LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) { [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)), - [chksum] "i"(offsetof(__jmp_buf, __chksum)), "c"(jmpbuf::MULTIPLE), - [cookie] "a"(jmpbuf::checksum_cookie), [mask] "m"(jmpbuf::value_mask) + [chksum] "i"(offsetof(__jmp_buf, __chksum)), + [multiple] "c"(jmpbuf::MULTIPLE), [cookie] "a"(jmpbuf::checksum_cookie), + [mask] "m"(jmpbuf::value_mask) :); } diff --git a/libc/src/setjmp/x86_64/setjmp_fortified.cpp b/libc/src/setjmp/x86_64/setjmp_fortified.cpp index 074d1a0fbfcc1..155b836413368 100644 --- a/libc/src/setjmp/x86_64/setjmp_fortified.cpp +++ b/libc/src/setjmp/x86_64/setjmp_fortified.cpp @@ -25,60 +25,62 @@ LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) { mov %%rbx, %%rdx xor %[mask], %%rdx mov %%rdx, %c[rbx](%%rdi) - xor %%rdx, %%rax - mulq %[multiple] - xor %%rdx, %%rax + xor %%rdx, %[cookie] + mul %[multiple] + xor %%rdx, %[cookie] mov %%rbp, %%rdx xor %[mask], %%rdx mov %%rdx, %c[rbp](%%rdi) - xor %%rdx, %%rax - mulq %[multiple] - xor %%rdx, %%rax + xor %%rdx, %[cookie] + mul %[multiple] + xor %%rdx, %[cookie] mov %%r12, %%rdx xor %[mask], %%rdx mov %%rdx, %c[r12](%%rdi) - xor %%rdx, %%rax - mulq %[multiple] - xor %%rdx, %%rax + xor %%rdx, %[cookie] + mul %[multiple] + xor %%rdx, %[cookie] mov %%r13, %%rdx xor %[mask], %%rdx mov %%rdx, %c[r13](%%rdi) - xor %%rdx, %%rax - mulq %[multiple] - xor %%rdx, %%rax + xor %%rdx, %[cookie] + mul %[multiple] + xor %%rdx, %[cookie] mov %%r14, %%rdx xor %[mask], %%rdx mov %%rdx, %c[r14](%%rdi) - xor %%rdx, %%rax - mulq %[multiple] - xor %%rdx, %%rax + xor %%rdx, %[cookie] + mul %[multiple] + xor %%rdx, %[cookie] mov %%r15, %%rdx xor %[mask], %%rdx mov %%rdx, %c[r15](%%rdi) - xor %%rdx, %%rax - mulq %[multiple] - xor %%rdx, %%rax + xor %%rdx, %[cookie] + mul %[multiple] + xor %%rdx, %[cookie] lea 8(%%rsp), %%rdx xor %[mask], %%rdx mov %%rdx, %c[rsp](%%rdi) - xor %%rdx, %%rax - mulq %[multiple] - xor %%rdx, %%rax + xor %%rdx, %[cookie] + mul %[multiple] + xor %%rdx, %[cookie] mov (%%rsp), %%rdx xor %[mask], %%rdx mov %%rdx, %c[rip](%%rdi) - xor %%rdx, %%rax - mulq %[multiple] - xor %%rdx, %%rax + xor %%rdx, %[cookie] + mul %[multiple] + xor %%rdx, %[cookie] - mov %%rax, %c[chksum](%%rdi) + mov %[cookie], %c[chksum](%%rdi) + + # from this point, rax does not stand for accumulator but for return value xor %%rax, %%rax ret)" ::[rbx] "i"(offsetof(__jmp_buf, rbx)), [rbp] "i"(offsetof(__jmp_buf, rbp)), [r12] "i"(offsetof(__jmp_buf, r12)), @@ -86,8 +88,8 @@ LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) { [r15] "i"(offsetof(__jmp_buf, r15)), [rsp] "i"(offsetof(__jmp_buf, rsp)), [rip] "i"(offsetof(__jmp_buf, rip)), [chksum] "i"(offsetof(__jmp_buf, __chksum)), - [multiple] "m"(jmpbuf::MULTIPLE), [cookie] "a"(jmpbuf::checksum_cookie), - [mask] "m"(jmpbuf::value_mask) + [multiple] "c"(jmpbuf::MULTIPLE), [cookie] "a"(jmpbuf::checksum_cookie), + [mask] "S"(jmpbuf::value_mask) :); }