Skip to content

Commit 3bdd8a8

Browse files
[libc] address CRs
1 parent f591ed8 commit 3bdd8a8

File tree

11 files changed

+182
-109
lines changed

11 files changed

+182
-109
lines changed

libc/config/config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@
106106
},
107107
"LIBC_CONF_SETJMP_ENABLE_FORTIFICATION": {
108108
"value": true,
109-
"doc": "Enable fortification for setjmp and longjmp."
109+
"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."
110110
}
111111
},
112112
"time": {

libc/docs/configure.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ to learn about the defaults for your platform and target.
5555
- ``LIBC_CONF_SCANF_DISABLE_INDEX_MODE``: Disable index mode in the scanf format string.
5656
* **"setjmp" options**
5757
- ``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.
58-
- ``LIBC_CONF_SETJMP_ENABLE_FORTIFICATION``: Enable fortification for setjmp and longjmp.
58+
- ``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.
5959
* **"string" options**
6060
- ``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.
6161
- ``LIBC_CONF_STRING_UNSAFE_WIDE_READ``: Read more than a byte at a time to perform byte-string operations like strlen.

libc/src/setjmp/CMakeLists.txt

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
1-
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
2-
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
1+
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
2+
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
33
endif()
44

55
if (LIBC_CONF_SETJMP_ENABLE_FORTIFICATION)
6-
set(checksum_flags "-DLIBC_COPT_SETJMP_ENABLE_FORTIFICATION=1")
7-
else()
8-
set(checksum_flags "-DLIBC_COPT_SETJMP_ENABLE_FORTIFICATION=0")
6+
if (TARGET libc.src.setjmp.${LIBC_TARGET_OS}.checksum
7+
AND LIBC_TARGET_ARCHITECTURE STREQUAL "x86_64")
8+
add_object_library(
9+
checksum
10+
ALIAS
11+
DEPENDS
12+
.${LIBC_TARGET_OS}.checksum
13+
)
14+
set(fortification_deps libc.src.setjmp.checksum)
15+
set(fortification_defs -DLIBC_COPT_SETJMP_ENABLE_FORTIFICATION=1)
16+
else()
17+
message(WARNING "Jmpbuf fortification is enabled but not supported for target ${LIBC_TARGET_ARCHITECTURE} ${LIBC_TARGET_OS}")
18+
set(fortification_deps)
19+
set(fortification_defs -DLIBC_COPT_SETJMP_ENABLE_FORTIFICATION=0)
20+
endif()
921
endif()
1022

11-
12-
add_header_library(
13-
checksum
14-
HDRS
15-
checksum.h
16-
DEPENDS
17-
libc.src.__support.common
18-
libc.src.__support.OSUtil.osutil
19-
COMPILE_OPTIONS
20-
${checksum_flags}
21-
)
23+
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
24+
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
25+
endif()
2226

2327
add_entrypoint_object(
2428
setjmp

libc/src/setjmp/checksum.h

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,38 +9,19 @@
99
#ifndef LLVM_LIBC_SRC_SETJMP_CHECKSUM_H
1010
#define LLVM_LIBC_SRC_SETJMP_CHECKSUM_H
1111

12-
#ifndef LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
13-
#define LIBC_COPT_SETJMP_ENABLE_FORTIFICATION 1
14-
#endif
15-
16-
#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
17-
#include "src/__support/OSUtil/syscall.h"
18-
#include "src/__support/macros/config.h"
19-
#include <sys/syscall.h>
12+
#include "src/__support/common.h"
2013

2114
namespace LIBC_NAMESPACE_DECL {
2215
namespace jmpbuf {
23-
// random bytes from https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h
24-
LIBC_INLINE __UINTPTR_TYPE__ value_mask = 0x3899'f0d3'5005'd953;
25-
LIBC_INLINE __UINT64_TYPE__ checksum_cookie = 0xc7d9'd341'6afc'33f2;
16+
17+
extern __UINTPTR_TYPE__ value_mask;
18+
extern __UINT64_TYPE__ checksum_cookie;
19+
2620
// abitrary prime number
2721
LIBC_INLINE constexpr __UINT64_TYPE__ ROTATION = 13;
28-
// initialize the checksum state
29-
LIBC_INLINE void initialize() {
30-
union {
31-
struct {
32-
__UINTPTR_TYPE__ entropy0;
33-
__UINT64_TYPE__ entropy1;
34-
};
35-
char buffer[sizeof(__UINTPTR_TYPE__) + sizeof(__UINT64_TYPE__)];
36-
};
37-
syscall_impl<long>(SYS_getrandom, buffer, sizeof(buffer), 0);
38-
// add in additional entropy
39-
jmpbuf::value_mask ^= entropy0;
40-
jmpbuf::checksum_cookie ^= entropy1;
41-
}
22+
void initialize();
23+
extern "C" [[gnu::cold, noreturn]] void __libc_jmpbuf_corruption();
4224
} // namespace jmpbuf
4325
} // namespace LIBC_NAMESPACE_DECL
44-
#endif // LIBC_SETJMP_ENABLE_FORTIFICATION
4526

4627
#endif // LLVM_LIBC_SRC_SETJMP_CHECKSUM_H
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
add_object_library(
2+
checksum
3+
SRCS
4+
checksum.cpp
5+
HDRS
6+
../checksum.h
7+
DEPENDS
8+
libc.src.__support.common
9+
libc.src.__support.OSUtil.osutil
10+
libc.src.stdlib.abort
11+
)

libc/src/setjmp/linux/checksum.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===-- Implementation for jmpbuf checksum ----------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/setjmp/checksum.h"
10+
#include "src/__support/OSUtil/io.h"
11+
#include "src/stdlib/abort.h"
12+
#include <sys/syscall.h>
13+
14+
namespace LIBC_NAMESPACE_DECL {
15+
namespace jmpbuf {
16+
// random bytes from https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h
17+
// the cookie should not be zero otherwise it will be a bad seed as a multiplier
18+
__UINTPTR_TYPE__ value_mask = 0x3899'f0d3'5005'd953;
19+
__UINT64_TYPE__ checksum_cookie = 0xc7d9'd341'6afc'33f2;
20+
21+
// initialize the checksum state
22+
void initialize() {
23+
union {
24+
struct {
25+
__UINTPTR_TYPE__ entropy0;
26+
__UINT64_TYPE__ entropy1;
27+
};
28+
char buffer[sizeof(__UINTPTR_TYPE__) + sizeof(__UINT64_TYPE__)];
29+
};
30+
syscall_impl<long>(SYS_getrandom, buffer, sizeof(buffer), 0);
31+
// add in additional entropy
32+
jmpbuf::value_mask ^= entropy0;
33+
jmpbuf::checksum_cookie ^= entropy1;
34+
}
35+
36+
extern "C" [[gnu::cold, noreturn]] void __libc_jmpbuf_corruption() {
37+
write_to_stderr("invalid checksum detected in longjmp\n");
38+
abort();
39+
}
40+
41+
} // namespace jmpbuf
42+
} // namespace LIBC_NAMESPACE_DECL

libc/src/setjmp/x86_64/CMakeLists.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ add_entrypoint_object(
66
../setjmp_impl.h
77
DEPENDS
88
libc.hdr.types.jmp_buf
9-
libc.src.setjmp.checksum
9+
${fortification_deps}
1010
COMPILE_OPTIONS
1111
-O3
12+
${fortification_defs}
1213
)
1314

1415
add_entrypoint_object(
@@ -19,10 +20,9 @@ add_entrypoint_object(
1920
../longjmp.h
2021
DEPENDS
2122
libc.hdr.types.jmp_buf
22-
libc.src.stdlib.abort
23-
libc.src.__support.OSUtil.osutil
24-
libc.src.setjmp.checksum
23+
${fortification_deps}
2524
COMPILE_OPTIONS
2625
-O3
2726
-fomit-frame-pointer
27+
${fortification_defs}
2828
)

libc/src/setjmp/x86_64/longjmp.cpp

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,61 +8,68 @@
88

99
#include "src/setjmp/longjmp.h"
1010
#include "include/llvm-libc-macros/offsetof-macro.h"
11-
#include "src/__support/OSUtil/io.h"
1211
#include "src/__support/common.h"
1312
#include "src/__support/macros/config.h"
13+
14+
#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
1415
#include "src/setjmp/checksum.h"
15-
#include "src/stdlib/abort.h"
16+
#endif
1617

1718
#if !defined(LIBC_TARGET_ARCH_IS_X86)
1819
#error "Invalid file include"
1920
#endif
2021

2122
namespace LIBC_NAMESPACE_DECL {
2223

24+
#define CALCULATE_RETURN_VALUE() \
25+
"cmpl $0x1, %%esi\n\t" \
26+
"adcl $0x0, %%esi\n\t" \
27+
"movq %%rsi, %%rax\n\t"
28+
2329
#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
24-
extern "C" [[gnu::cold, noreturn]] void __libc_jmpbuf_corruption() {
25-
write_to_stderr("invalid checksum detected in longjmp\n");
26-
abort();
27-
}
30+
#define ACCUMULATE_CHECKSUM() \
31+
"mul %[checksum]\n\t" \
32+
"xor %%rax, %[checksum]\n\t" \
33+
"rol $%c[rotation], %[checksum]\n\t"
34+
2835
#define LOAD_CHKSUM_STATE_REGISTERS() \
29-
asm("mov %0, %%rcx\n\t" ::"m"(jmpbuf::value_mask) : "rcx"); \
30-
asm("mov %0, %%rdx\n\t" ::"m"(jmpbuf::checksum_cookie) : "rdx");
36+
asm("mov %[value_mask], %[mask]\n\t" \
37+
"mov %[checksum_cookie], %[checksum]\n\t" \
38+
: [mask] "=r"(mask), [checksum] "=r"(checksum) \
39+
: [value_mask] "m"(jmpbuf::value_mask), [checksum_cookie] "m"( \
40+
jmpbuf::checksum_cookie));
3141

42+
// clang-format off
3243
#define RESTORE_REG(DST) \
3344
"movq %c[" #DST "](%%rdi), %%rax\n\t" \
3445
"movq %%rax, %%" #DST "\n\t" \
35-
"xor %%rcx, %%" #DST "\n\t" \
36-
"mul %%rdx\n\t" \
37-
"xor %%rax, %%rdx\n\t" \
38-
"rol $%c[rotation], %%rdx\n\t"
46+
"xor %[mask], %%" #DST "\n\t" \
47+
ACCUMULATE_CHECKSUM()
3948

4049
#define RESTORE_RIP() \
4150
"movq %c[rip](%%rdi), %%rax\n\t" \
42-
"xor %%rax, %%rcx\n\t" \
43-
"mul %%rdx\n\t" \
44-
"xor %%rax, %%rdx\n\t" \
45-
"rol $%c[rotation], %%rdx\n\t" \
46-
"cmp %c[chksum](%%rdi), %%rdx\n\t" \
51+
"xor %%rax, %[mask]\n\t" \
52+
ACCUMULATE_CHECKSUM() \
53+
"cmp %c[__chksum](%%rdi), %%rdx\n\t" \
4754
"jne __libc_jmpbuf_corruption\n\t" \
48-
"cmpl $0x1, %%esi\n\t" \
49-
"adcl $0x0, %%esi\n\t" \
50-
"movq %%rsi, %%rax\n\t" \
51-
"jmp *%%rcx\n\t"
55+
CALCULATE_RETURN_VALUE() \
56+
"jmp *%[mask]\n\t"
57+
// clang-format on
5258
#else
5359
#define LOAD_CHKSUM_STATE_REGISTERS()
5460
#define RESTORE_REG(DST) "movq %c[" #DST "](%%rdi), %%" #DST "\n\t"
5561
#define RESTORE_RIP() \
56-
"cmpl $0x1, %%esi\n\t" \
57-
"adcl $0x0, %%esi\n\t" \
58-
"movq %%rsi, %%rax\n\t" \
62+
CALCULATE_RETURN_VALUE() \
5963
"jmpq *%c[rip](%%rdi)\n\t"
6064
#endif
6165

62-
[[gnu::naked]]
63-
LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) {
66+
[[gnu::naked]] LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) {
67+
// use registers to make sure values propagate correctly across the asm blocks
68+
[[maybe_unused]] register __UINTPTR_TYPE__ mask asm("rcx");
69+
[[maybe_unused]] register __UINT64_TYPE__ checksum asm("rdx");
70+
6471
LOAD_CHKSUM_STATE_REGISTERS()
65-
asm(
72+
asm volatile(
6673
// clang-format off
6774
RESTORE_REG(rbx)
6875
RESTORE_REG(rbp)
@@ -73,18 +80,23 @@ LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) {
7380
RESTORE_REG(rsp)
7481
RESTORE_RIP()
7582
// clang-format on
76-
::[rbx] "i"(offsetof(__jmp_buf, rbx)),
77-
[rbp] "i"(offsetof(__jmp_buf, rbp)), [r12] "i"(offsetof(__jmp_buf, r12)),
78-
[r13] "i"(offsetof(__jmp_buf, r13)), [r14] "i"(offsetof(__jmp_buf, r14)),
79-
[r15] "i"(offsetof(__jmp_buf, r15)), [rsp] "i"(offsetof(__jmp_buf, rsp)),
83+
: /* outputs */
84+
#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
85+
[mask] "+r"(mask), [checksum] "+r"(checksum)
86+
#endif
87+
: /* inputs */
88+
[rbx] "i"(offsetof(__jmp_buf, rbx)), [rbp] "i"(offsetof(__jmp_buf, rbp)),
89+
[r12] "i"(offsetof(__jmp_buf, r12)), [r13] "i"(offsetof(__jmp_buf, r13)),
90+
[r14] "i"(offsetof(__jmp_buf, r14)), [r15] "i"(offsetof(__jmp_buf, r15)),
91+
[rsp] "i"(offsetof(__jmp_buf, rsp)),
8092
[rip] "i"(offsetof(__jmp_buf, rip))
8193
#if LIBC_COPT_SETJMP_ENABLE_FORTIFICATION
8294
// clang-format off
8395
,[rotation] "i"(jmpbuf::ROTATION)
84-
,[chksum] "i"(offsetof(__jmp_buf, __chksum))
96+
,[__chksum] "i"(offsetof(__jmp_buf, __chksum))
8597
// clang-format on
8698
#endif
87-
: "rax", "rdx", "rcx", "rsi");
99+
: "rax", "rsi");
88100
}
89101

90102
} // namespace LIBC_NAMESPACE_DECL

0 commit comments

Comments
 (0)