]> git.proxmox.com Git - rustc.git/blob - vendor/compiler_builtins/src/probestack.rs
New upstream version 1.51.0+dfsg1
[rustc.git] / vendor / compiler_builtins / src / probestack.rs
1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! This module defines the `__rust_probestack` intrinsic which is used in the
12 //! implementation of "stack probes" on certain platforms.
13 //!
14 //! The purpose of a stack probe is to provide a static guarantee that if a
15 //! thread has a guard page then a stack overflow is guaranteed to hit that
16 //! guard page. If a function did not have a stack probe then there's a risk of
17 //! having a stack frame *larger* than the guard page, so a function call could
18 //! skip over the guard page entirely and then later hit maybe the heap or
19 //! another thread, possibly leading to security vulnerabilities such as [The
20 //! Stack Clash], for example.
21 //!
22 //! [The Stack Clash]: https://blog.qualys.com/securitylabs/2017/06/19/the-stack-clash
23 //!
24 //! The `__rust_probestack` is called in the prologue of functions whose stack
25 //! size is larger than the guard page, for example larger than 4096 bytes on
26 //! x86. This function is then responsible for "touching" all pages relevant to
27 //! the stack to ensure that that if any of them are the guard page we'll hit
28 //! them guaranteed.
29 //!
30 //! The precise ABI for how this function operates is defined by LLVM. There's
31 //! no real documentation as to what this is, so you'd basically need to read
32 //! the LLVM source code for reference. Often though the test cases can be
33 //! illuminating as to the ABI that's generated, or just looking at the output
34 //! of `llc`.
35 //!
36 //! Note that `#[naked]` is typically used here for the stack probe because the
37 //! ABI corresponds to no actual ABI.
38 //!
39 //! Finally it's worth noting that at the time of this writing LLVM only has
40 //! support for stack probes on x86 and x86_64. There's no support for stack
41 //! probes on any other architecture like ARM or PowerPC64. LLVM I'm sure would
42 //! be more than welcome to accept such a change!
43
44 #![cfg(not(feature = "mangled-names"))]
45 // Windows already has builtins to do this.
46 #![cfg(not(windows))]
47 // All these builtins require assembly
48 #![cfg(not(feature = "no-asm"))]
49 // We only define stack probing for these architectures today.
50 #![cfg(any(target_arch = "x86_64", target_arch = "x86"))]
51
52 extern "C" {
53 pub fn __rust_probestack();
54 }
55
56 // A wrapper for our implementation of __rust_probestack, which allows us to
57 // keep the assembly inline while controlling all CFI directives in the assembly
58 // emitted for the function.
59 //
60 // This is the ELF version.
61 #[cfg(not(any(target_vendor = "apple", target_os = "uefi")))]
62 macro_rules! define_rust_probestack {
63 ($body: expr) => {
64 concat!(
65 "
66 .pushsection .text.__rust_probestack
67 .globl __rust_probestack
68 .type __rust_probestack, @function
69 .hidden __rust_probestack
70 __rust_probestack:
71 ",
72 $body,
73 "
74 .size __rust_probestack, . - __rust_probestack
75 .popsection
76 "
77 )
78 };
79 }
80
81 #[cfg(all(target_os = "uefi", target_arch = "x86_64"))]
82 macro_rules! define_rust_probestack {
83 ($body: expr) => {
84 concat!(
85 "
86 .globl __rust_probestack
87 __rust_probestack:
88 ",
89 $body
90 )
91 };
92 }
93
94 // Same as above, but for Mach-O. Note that the triple underscore
95 // is deliberate
96 #[cfg(target_vendor = "apple")]
97 macro_rules! define_rust_probestack {
98 ($body: expr) => {
99 concat!(
100 "
101 .globl ___rust_probestack
102 ___rust_probestack:
103 ",
104 $body
105 )
106 };
107 }
108
109 // In UEFI x86 arch, triple underscore is deliberate.
110 #[cfg(all(target_os = "uefi", target_arch = "x86"))]
111 macro_rules! define_rust_probestack {
112 ($body: expr) => {
113 concat!(
114 "
115 .globl ___rust_probestack
116 ___rust_probestack:
117 ",
118 $body
119 )
120 };
121 }
122
123 // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax,
124 // ensuring that if any pages are unmapped we'll make a page fault.
125 //
126 // The ABI here is that the stack frame size is located in `%rax`. Upon
127 // return we're not supposed to modify `%rsp` or `%rax`.
128 //
129 // Any changes to this function should be replicated to the SGX version below.
130 #[cfg(all(
131 target_arch = "x86_64",
132 not(all(target_env = "sgx", target_vendor = "fortanix"))
133 ))]
134 global_asm!(define_rust_probestack!(
135 "
136 .cfi_startproc
137 pushq %rbp
138 .cfi_adjust_cfa_offset 8
139 .cfi_offset %rbp, -16
140 movq %rsp, %rbp
141 .cfi_def_cfa_register %rbp
142
143 mov %rax,%r11 // duplicate %rax as we're clobbering %r11
144
145 // Main loop, taken in one page increments. We're decrementing rsp by
146 // a page each time until there's less than a page remaining. We're
147 // guaranteed that this function isn't called unless there's more than a
148 // page needed.
149 //
150 // Note that we're also testing against `8(%rsp)` to account for the 8
151 // bytes pushed on the stack orginally with our return address. Using
152 // `8(%rsp)` simulates us testing the stack pointer in the caller's
153 // context.
154
155 // It's usually called when %rax >= 0x1000, but that's not always true.
156 // Dynamic stack allocation, which is needed to implement unsized
157 // rvalues, triggers stackprobe even if %rax < 0x1000.
158 // Thus we have to check %r11 first to avoid segfault.
159 cmp $0x1000,%r11
160 jna 3f
161 2:
162 sub $0x1000,%rsp
163 test %rsp,8(%rsp)
164 sub $0x1000,%r11
165 cmp $0x1000,%r11
166 ja 2b
167
168 3:
169 // Finish up the last remaining stack space requested, getting the last
170 // bits out of r11
171 sub %r11,%rsp
172 test %rsp,8(%rsp)
173
174 // Restore the stack pointer to what it previously was when entering
175 // this function. The caller will readjust the stack pointer after we
176 // return.
177 add %rax,%rsp
178
179 leave
180 .cfi_def_cfa_register %rsp
181 .cfi_adjust_cfa_offset -8
182 ret
183 .cfi_endproc
184 "
185 ));
186
187 // This function is the same as above, except that some instructions are
188 // [manually patched for LVI].
189 //
190 // [manually patched for LVI]: https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions
191 #[cfg(all(
192 target_arch = "x86_64",
193 all(target_env = "sgx", target_vendor = "fortanix")
194 ))]
195 global_asm!(define_rust_probestack!(
196 "
197 .cfi_startproc
198 pushq %rbp
199 .cfi_adjust_cfa_offset 8
200 .cfi_offset %rbp, -16
201 movq %rsp, %rbp
202 .cfi_def_cfa_register %rbp
203
204 mov %rax,%r11 // duplicate %rax as we're clobbering %r11
205
206 // Main loop, taken in one page increments. We're decrementing rsp by
207 // a page each time until there's less than a page remaining. We're
208 // guaranteed that this function isn't called unless there's more than a
209 // page needed.
210 //
211 // Note that we're also testing against `8(%rsp)` to account for the 8
212 // bytes pushed on the stack orginally with our return address. Using
213 // `8(%rsp)` simulates us testing the stack pointer in the caller's
214 // context.
215
216 // It's usually called when %rax >= 0x1000, but that's not always true.
217 // Dynamic stack allocation, which is needed to implement unsized
218 // rvalues, triggers stackprobe even if %rax < 0x1000.
219 // Thus we have to check %r11 first to avoid segfault.
220 cmp $0x1000,%r11
221 jna 3f
222 2:
223 sub $0x1000,%rsp
224 test %rsp,8(%rsp)
225 sub $0x1000,%r11
226 cmp $0x1000,%r11
227 ja 2b
228
229 3:
230 // Finish up the last remaining stack space requested, getting the last
231 // bits out of r11
232 sub %r11,%rsp
233 test %rsp,8(%rsp)
234
235 // Restore the stack pointer to what it previously was when entering
236 // this function. The caller will readjust the stack pointer after we
237 // return.
238 add %rax,%rsp
239
240 leave
241 .cfi_def_cfa_register %rsp
242 .cfi_adjust_cfa_offset -8
243 pop %r11
244 lfence
245 jmp *%r11
246 .cfi_endproc
247 "
248 ));
249
250 #[cfg(all(target_arch = "x86", not(target_os = "uefi")))]
251 // This is the same as x86_64 above, only translated for 32-bit sizes. Note
252 // that on Unix we're expected to restore everything as it was, this
253 // function basically can't tamper with anything.
254 //
255 // The ABI here is the same as x86_64, except everything is 32-bits large.
256 global_asm!(define_rust_probestack!(
257 "
258 .cfi_startproc
259 push %ebp
260 .cfi_adjust_cfa_offset 4
261 .cfi_offset %ebp, -8
262 mov %esp, %ebp
263 .cfi_def_cfa_register %ebp
264 push %ecx
265 mov %eax,%ecx
266
267 cmp $0x1000,%ecx
268 jna 3f
269 2:
270 sub $0x1000,%esp
271 test %esp,8(%esp)
272 sub $0x1000,%ecx
273 cmp $0x1000,%ecx
274 ja 2b
275
276 3:
277 sub %ecx,%esp
278 test %esp,8(%esp)
279
280 add %eax,%esp
281 pop %ecx
282 leave
283 .cfi_def_cfa_register %esp
284 .cfi_adjust_cfa_offset -4
285 ret
286 .cfi_endproc
287 "
288 ));
289
290 #[cfg(all(target_arch = "x86", target_os = "uefi"))]
291 // UEFI target is windows like target. LLVM will do _chkstk things like windows.
292 // probestack function will also do things like _chkstk in MSVC.
293 // So we need to sub %ax %sp in probestack when arch is x86.
294 //
295 // REF: Rust commit(74e80468347)
296 // rust\src\llvm-project\llvm\lib\Target\X86\X86FrameLowering.cpp: 805
297 // Comments in LLVM:
298 // MSVC x32's _chkstk and cygwin/mingw's _alloca adjust %esp themselves.
299 // MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust %rsp
300 // themselves.
301 global_asm!(define_rust_probestack!(
302 "
303 .cfi_startproc
304 push %ebp
305 .cfi_adjust_cfa_offset 4
306 .cfi_offset %ebp, -8
307 mov %esp, %ebp
308 .cfi_def_cfa_register %ebp
309 push %ecx
310 push %edx
311 mov %eax,%ecx
312
313 cmp $0x1000,%ecx
314 jna 3f
315 2:
316 sub $0x1000,%esp
317 test %esp,8(%esp)
318 sub $0x1000,%ecx
319 cmp $0x1000,%ecx
320 ja 2b
321
322 3:
323 sub %ecx,%esp
324 test %esp,8(%esp)
325 mov 4(%ebp),%edx
326 mov %edx, 12(%esp)
327 add %eax,%esp
328 pop %edx
329 pop %ecx
330 leave
331
332 sub %eax, %esp
333 .cfi_def_cfa_register %esp
334 .cfi_adjust_cfa_offset -4
335 ret
336 .cfi_endproc
337 "
338 ));