Skip to content

Commit a20396a

Browse files
committed
libffi: patches to support software CFI
1 parent b03b1d1 commit a20396a

File tree

3 files changed

+352
-0
lines changed

3 files changed

+352
-0
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
From 3aa0ebdd2ee6b5634443d7464f1e37be5c20786e Mon Sep 17 00:00:00 2001
2+
From: Gilles Duboscq <[email protected]>
3+
Date: Wed, 23 Apr 2025 18:42:40 +0200
4+
Subject: [PATCH 1/3] If other methods fail, attempt to use mprotect in
5+
ffi_tramp_init_os
6+
7+
---
8+
src/tramp.c | 39 ++++++++++++++++++++++++++++-----------
9+
1 file changed, 28 insertions(+), 11 deletions(-)
10+
11+
diff --git a/src/tramp.c b/src/tramp.c
12+
index 8ec0848..7edaebc 100644
13+
--- a/src/tramp.c
14+
+++ b/src/tramp.c
15+
@@ -289,7 +289,10 @@ ffi_tramp_init_os (void)
16+
{
17+
if (ffi_tramp_get_libffi ())
18+
return 1;
19+
- return ffi_tramp_get_temp_file ();
20+
+ if (ffi_tramp_get_temp_file ())
21+
+ return 1;
22+
+ // try to allocate with the mprotect fall-back
23+
+ return tramp_table_alloc ();
24+
}
25+
26+
#endif /* defined (__linux__) || defined (__CYGWIN__) */
27+
@@ -347,18 +350,32 @@ tramp_table_map (struct tramp_table *table)
28+
if (addr == MAP_FAILED)
29+
return 0;
30+
31+
- /*
32+
- * Replace the top half of the anonymous mapping with the code table mapping.
33+
- */
34+
- table->code_table = mmap (addr, tramp_globals.map_size, PROT_READ | PROT_EXEC,
35+
- MAP_PRIVATE | MAP_FIXED, tramp_globals.fd, tramp_globals.offset);
36+
- if (table->code_table == MAP_FAILED)
37+
+ if (tramp_globals.fd != -1)
38+
{
39+
- (void) munmap (addr, tramp_globals.map_size * 2);
40+
- return 0;
41+
+ /*
42+
+ * Replace the top half of the anonymous mapping with the code table mapping.
43+
+ */
44+
+ table->code_table = mmap(addr, tramp_globals.map_size, PROT_READ | PROT_EXEC,
45+
+ MAP_PRIVATE | MAP_FIXED, tramp_globals.fd, tramp_globals.offset);
46+
+ if (table->code_table != MAP_FAILED) {
47+
+ table->parm_table = table->code_table + tramp_globals.map_size;
48+
+ return 1;
49+
+ }
50+
}
51+
- table->parm_table = table->code_table + tramp_globals.map_size;
52+
- return 1;
53+
+
54+
+ /*
55+
+ * Try to copy the trampolines and mprotect
56+
+ */
57+
+ memcpy(addr, tramp_globals.text, tramp_globals.map_size);
58+
+ if (mprotect(addr, tramp_globals.map_size, PROT_READ | PROT_EXEC) == 0)
59+
+ {
60+
+ table->code_table = addr;
61+
+ table->parm_table = table->code_table + tramp_globals.map_size;
62+
+ return 1;
63+
+ }
64+
+
65+
+ (void) munmap (addr, tramp_globals.map_size * 2);
66+
+ return 0;
67+
}
68+
69+
static void
70+
--
71+
2.43.0
72+
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
From 4900a67c4daabedbf83b563d77830c3f1c6eb599 Mon Sep 17 00:00:00 2001
2+
From: Gilles Duboscq <[email protected]>
3+
Date: Wed, 23 Apr 2025 18:45:10 +0200
4+
Subject: [PATCH 2/3] Add support __SANDBOX_SWCFI__ in unix64.S and win64.S
5+
6+
This mode requires a software check for jump targets.
7+
---
8+
src/x86/internal64.h | 4 +++
9+
src/x86/unix64.S | 30 ++++++++++++++++++++
10+
src/x86/win64.S | 65 +++++++++++++++++++++++++++++++++++++++++++-
11+
3 files changed, 98 insertions(+), 1 deletion(-)
12+
13+
diff --git a/src/x86/internal64.h b/src/x86/internal64.h
14+
index 282b408..7142645 100644
15+
--- a/src/x86/internal64.h
16+
+++ b/src/x86/internal64.h
17+
@@ -29,7 +29,11 @@
18+
#define UNIX64_TRAMP_MAP_SHIFT 12
19+
#define UNIX64_TRAMP_MAP_SIZE (1 << UNIX64_TRAMP_MAP_SHIFT)
20+
#ifdef ENDBR_PRESENT
21+
+#ifdef __SANDBOX_SWCFI__
22+
+#define UNIX64_TRAMP_SIZE 48
23+
+#else
24+
#define UNIX64_TRAMP_SIZE 40
25+
+#endif
26+
#else
27+
#define UNIX64_TRAMP_SIZE 32
28+
#endif
29+
diff --git a/src/x86/unix64.S b/src/x86/unix64.S
30+
index d9c5bd4..10d9c8d 100644
31+
--- a/src/x86/unix64.S
32+
+++ b/src/x86/unix64.S
33+
@@ -98,6 +98,13 @@ L(ret_from_load_sse):
34+
35+
/* Deallocate the reg arg area, except for r10, then load via pop. */
36+
leaq 0xb8(%r10), %rsp
37+
+#ifdef __SANDBOX_SWCFI__
38+
+ movl (%r11), %r10d
39+
+ addl $0x5e1f00d, %r10d
40+
+ jz 1f
41+
+ int3
42+
+1:
43+
+#endif
44+
popq %r10
45+
46+
/* Call the user function. */
47+
@@ -126,6 +133,13 @@ L(UW2):
48+
#endif
49+
leaq (%r11, %r10, 8), %r10
50+
51+
+#ifdef __SANDBOX_SWCFI__
52+
+ movl (%r10), %r11d
53+
+ addl $0x5e1f00d, %r11d
54+
+ jz 1f
55+
+ int3
56+
+1:
57+
+#endif
58+
/* Prep for the structure cases: scratch area in redzone. */
59+
leaq -20(%rsp), %rsi
60+
jmp *%r10
61+
@@ -318,6 +332,13 @@ L(UW10):
62+
addl %r10d, %r10d
63+
#endif
64+
leaq (%r11, %r10, 8), %r10
65+
+#ifdef __SANDBOX_SWCFI__
66+
+ movl (%r10), %r11d
67+
+ addl $0x5e1f00d, %r11d
68+
+ jz 1f
69+
+ int3
70+
+1:
71+
+#endif
72+
leaq ffi_closure_RED_RVALUE(%rsp), %rsi
73+
jmp *%r10
74+
75+
@@ -538,6 +559,15 @@ C(trampoline_code_table):
76+
movl X86_CODE_OFFSET(%rip), %r10d /* Copy code into %r10 */
77+
#else
78+
movq X86_CODE_OFFSET(%rip), %r10 /* Copy code into %r10 */
79+
+#endif
80+
+#ifdef __SANDBOX_SWCFI__
81+
+ pushq %rdi
82+
+ movl (%r10), %edi
83+
+ addl $0x5e1f00d, %edi
84+
+ jz 1f
85+
+ int3
86+
+1:
87+
+ popq %rdi
88+
#endif
89+
jmp *%r10 /* Jump to code */
90+
.align 8
91+
diff --git a/src/x86/win64.S b/src/x86/win64.S
92+
index 58ec6a1..d1a180a 100644
93+
--- a/src/x86/win64.S
94+
+++ b/src/x86/win64.S
95+
@@ -27,7 +27,10 @@
96+
actual table. The entry points into the table are all 8 bytes.
97+
The use of ORG asserts that we're at the correct location. */
98+
/* ??? The clang assembler doesn't handle .org with symbolic expressions. */
99+
-#if defined(__clang__) || defined(__APPLE__) || (defined (__sun__) && defined(__svr4__))
100+
+#ifdef __SANDBOX_SWCFI__
101+
+/* Triple slot size to 24 byte to add ENDBR64 and jump for ret. */
102+
+# define E(BASE, X) .balign 8; .org BASE + (X) * 24
103+
+#elif defined(__clang__) || defined(__APPLE__) || (defined (__sun__) && defined(__svr4__))
104+
# define E(BASE, X) .balign 8
105+
#else
106+
# define E(BASE, X) .balign 8; .org BASE + (X) * 8
107+
@@ -73,18 +76,58 @@ C(ffi_call_win64):
108+
movq 24(%rsp), %r9
109+
movsd 24(%rsp), %xmm3
110+
111+
+#ifdef __SANDBOX_SWCFI__
112+
+ movq 16(%rbp), %r11
113+
+ pushq %r10
114+
+ movl (%r11), %r10d
115+
+ addl $0x5e1f00d, %r10d
116+
+ jz 1f
117+
+ int3
118+
+1:
119+
+ popq %r10
120+
+ call *%r11
121+
+#else
122+
call *16(%rbp)
123+
+#endif
124+
125+
movl 24(%rbp), %ecx
126+
movq 32(%rbp), %r8
127+
leaq 0f(%rip), %r10
128+
cmpl $FFI_TYPE_SMALL_STRUCT_4B, %ecx
129+
+
130+
+#ifdef __SANDBOX_SWCFI__
131+
+ /* avoid leave in this mode, use larger slots (3*8) */
132+
+ ja 99f
133+
+ movl %ecx, %r11d
134+
+ addl %ecx, %ecx
135+
+ addl %r11d, %ecx
136+
+ leaq (%r10, %rcx, 8), %r10
137+
+ movl (%r10), %ecx
138+
+ addl $0x5e1f00d, %ecx
139+
+ jz 1f
140+
+ int3
141+
+1:
142+
+ jmp *%r10
143+
+
144+
+#define jmp_target \
145+
+ _CET_ENDBR
146+
+#define epilogue \
147+
+ movq %rbp, %rsp; \
148+
+ popq %rbp; \
149+
+ cfi_remember_state; \
150+
+ cfi_def_cfa(%rsp, 8); \
151+
+ cfi_restore(%rbp); \
152+
+ ret; \
153+
+ cfi_restore_state
154+
+#else
155+
+
156+
leaq (%r10, %rcx, 8), %r10
157+
ja 99f
158+
_CET_NOTRACK jmp *%r10
159+
160+
/* Below, we're space constrained most of the time. Thus we eschew the
161+
modern "mov, pop, ret" sequence (5 bytes) for "leave, ret" (2 bytes). */
162+
+#define jmp_target
163+
#define epilogue \
164+
leaveq; \
165+
cfi_remember_state; \
166+
@@ -92,66 +135,86 @@ C(ffi_call_win64):
167+
cfi_restore(%rbp); \
168+
ret; \
169+
cfi_restore_state
170+
+#endif
171+
172+
.align 8
173+
0:
174+
E(0b, FFI_TYPE_VOID)
175+
+ jmp_target
176+
epilogue
177+
E(0b, FFI_TYPE_INT)
178+
+ jmp_target
179+
movslq %eax, %rax
180+
movq %rax, (%r8)
181+
epilogue
182+
E(0b, FFI_TYPE_FLOAT)
183+
+ jmp_target
184+
movss %xmm0, (%r8)
185+
epilogue
186+
E(0b, FFI_TYPE_DOUBLE)
187+
+ jmp_target
188+
movsd %xmm0, (%r8)
189+
epilogue
190+
// FFI_TYPE_LONGDOUBLE may be FFI_TYPE_DOUBLE but we need a different value here.
191+
E(0b, FFI_TYPE_DOUBLE + 1)
192+
+ jmp_target
193+
call PLT(C(abort))
194+
E(0b, FFI_TYPE_UINT8)
195+
+ jmp_target
196+
movzbl %al, %eax
197+
movq %rax, (%r8)
198+
epilogue
199+
E(0b, FFI_TYPE_SINT8)
200+
+ jmp_target
201+
movsbq %al, %rax
202+
jmp 98f
203+
E(0b, FFI_TYPE_UINT16)
204+
+ jmp_target
205+
movzwl %ax, %eax
206+
movq %rax, (%r8)
207+
epilogue
208+
E(0b, FFI_TYPE_SINT16)
209+
+ jmp_target
210+
movswq %ax, %rax
211+
jmp 98f
212+
E(0b, FFI_TYPE_UINT32)
213+
+ jmp_target
214+
movl %eax, %eax
215+
movq %rax, (%r8)
216+
epilogue
217+
E(0b, FFI_TYPE_SINT32)
218+
+ jmp_target
219+
movslq %eax, %rax
220+
movq %rax, (%r8)
221+
epilogue
222+
E(0b, FFI_TYPE_UINT64)
223+
+ jmp_target
224+
98: movq %rax, (%r8)
225+
epilogue
226+
E(0b, FFI_TYPE_SINT64)
227+
+ jmp_target
228+
movq %rax, (%r8)
229+
epilogue
230+
E(0b, FFI_TYPE_STRUCT)
231+
+ jmp_target
232+
epilogue
233+
E(0b, FFI_TYPE_POINTER)
234+
+ jmp_target
235+
movq %rax, (%r8)
236+
epilogue
237+
E(0b, FFI_TYPE_COMPLEX)
238+
+ jmp_target
239+
call PLT(C(abort))
240+
E(0b, FFI_TYPE_SMALL_STRUCT_1B)
241+
+ jmp_target
242+
movb %al, (%r8)
243+
epilogue
244+
E(0b, FFI_TYPE_SMALL_STRUCT_2B)
245+
+ jmp_target
246+
movw %ax, (%r8)
247+
epilogue
248+
E(0b, FFI_TYPE_SMALL_STRUCT_4B)
249+
+ jmp_target
250+
movl %eax, (%r8)
251+
epilogue
252+
253+
--
254+
2.43.0
255+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
From b92f010761442c7a44fbf5972a259dedcdf27624 Mon Sep 17 00:00:00 2001
2+
From: Gilles Duboscq <[email protected]>
3+
Date: Wed, 23 Apr 2025 21:28:04 +0200
4+
Subject: [PATCH 3/3] Also run alternative ABI tests on clang
5+
6+
---
7+
testsuite/lib/libffi.exp | 2 +-
8+
1 file changed, 1 insertion(+), 1 deletion(-)
9+
10+
diff --git a/testsuite/lib/libffi.exp b/testsuite/lib/libffi.exp
11+
index b5731db..607013d 100644
12+
--- a/testsuite/lib/libffi.exp
13+
+++ b/testsuite/lib/libffi.exp
14+
@@ -537,7 +537,7 @@ proc run-many-tests { testcases extra_flags } {
15+
info exists env(LD_LIBRARY_PATH)
16+
17+
set targetabis { "" }
18+
- if [string match $compiler_vendor "gnu"] {
19+
+ if { [string match $compiler_vendor "gnu"] || [string match $compiler_vendor "clang"] } then {
20+
if [libffi_feature_test "#ifdef __i386__"] {
21+
set targetabis {
22+
""
23+
--
24+
2.43.0
25+

0 commit comments

Comments
 (0)