Rollup merge of #127845 - workingjubilee:actually-break-up-big-ass-st… · model-checking/verify-rust-std@1f3311b (original) (raw)
`@@ -44,6 +44,7 @@ mod imp {
`
44
44
`use crate::ops::Range;
`
45
45
`use crate::ptr;
`
46
46
`use crate::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering};
`
``
47
`+
use crate::sync::OnceLock;
`
47
48
`use crate::sys::pal::unix::os;
`
48
49
`use crate::thread;
`
49
50
``
`@@ -306,9 +307,8 @@ mod imp {
`
306
307
` ret
`
307
308
`}
`
308
309
``
309
``
`-
unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> {
`
310
``
`-
let page_size = PAGE_SIZE.load(Ordering::Relaxed);
`
311
``
`-
let stackptr = get_stack_start()?;
`
``
310
`+
fn stack_start_aligned(page_size: usize) -> Option<*mut libc::c_void> {
`
``
311
`+
let stackptr = unsafe { get_stack_start()? };
`
312
312
`let stackaddr = stackptr.addr();
`
313
313
``
314
314
`// Ensure stackaddr is page aligned! A parent process might
`
`@@ -325,104 +325,133 @@ mod imp {
`
325
325
`})
`
326
326
`}
`
327
327
``
``
328
`+
#[forbid(unsafe_op_in_unsafe_fn)]
`
328
329
`unsafe fn install_main_guard() -> Option<Range> {
`
329
330
`let page_size = PAGE_SIZE.load(Ordering::Relaxed);
`
330
``
`-
if cfg!(all(target_os = "linux", not(target_env = "musl"))) {
`
331
``
`-
// Linux doesn't allocate the whole stack right away, and
`
332
``
`-
// the kernel has its own stack-guard mechanism to fault
`
333
``
`-
// when growing too close to an existing mapping. If we map
`
334
``
`-
// our own guard, then the kernel starts enforcing a rather
`
335
``
`-
// large gap above that, rendering much of the possible
`
336
``
`-
// stack space useless. See #43052.
`
337
``
`-
//
`
338
``
`-
// Instead, we'll just note where we expect rlimit to start
`
339
``
`-
// faulting, so our handler can report "stack overflow", and
`
340
``
`-
// trust that the kernel's own stack guard will work.
`
341
``
`-
let stackptr = get_stack_start_aligned()?;
`
342
``
`-
let stackaddr = stackptr.addr();
`
343
``
`-
Some(stackaddr - page_size..stackaddr)
`
344
``
`-
} else if cfg!(all(target_os = "linux", target_env = "musl")) {
`
345
``
`-
// For the main thread, the musl's pthread_attr_getstack
`
346
``
`-
// returns the current stack size, rather than maximum size
`
347
``
`-
// it can eventually grow to. It cannot be used to determine
`
348
``
`-
// the position of kernel's stack guard.
`
349
``
`-
None
`
350
``
`-
} else if cfg!(target_os = "freebsd") {
`
351
``
`-
// FreeBSD's stack autogrows, and optionally includes a guard page
`
352
``
`-
// at the bottom. If we try to remap the bottom of the stack
`
353
``
`-
// ourselves, FreeBSD's guard page moves upwards. So we'll just use
`
354
``
`-
// the builtin guard page.
`
355
``
`-
let stackptr = get_stack_start_aligned()?;
`
356
``
`-
let guardaddr = stackptr.addr();
`
357
``
`-
// Technically the number of guard pages is tunable and controlled
`
358
``
`-
// by the security.bsd.stack_guard_page sysctl.
`
359
``
`-
// By default it is 1, checking once is enough since it is
`
360
``
`-
// a boot time config value.
`
361
``
`-
static PAGES: crate::sync::OnceLock = crate::sync::OnceLock::new();
`
362
``
-
363
``
`-
let pages = PAGES.get_or_init(|| {
`
364
``
`-
use crate::sys::weak::dlsym;
`
365
``
`-
dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int);
`
366
``
`-
let mut guard: usize = 0;
`
367
``
`-
let mut size = crate::mem::size_of_val(&guard);
`
368
``
`-
let oid = crate::ffi::CStr::from_bytes_with_nul(
`
369
``
`-
b"security.bsd.stack_guard_page\0",
`
370
``
`-
)
`
371
``
`-
.unwrap();
`
372
``
`-
match sysctlbyname.get() {
`
373
``
`-
Some(fcn) => {
`
374
``
`-
if fcn(oid.as_ptr(), core::ptr::addr_of_mut!(guard) as *mut _, core::ptr::addr_of_mut!(size) as *mut _, crate::ptr::null_mut(), 0) == 0 {
`
375
``
`-
guard
`
376
``
`-
} else {
`
377
``
`-
1
`
378
``
`-
}
`
379
``
`-
},
`
380
``
`-
_ => 1,
`
381
``
`-
}
`
382
``
`-
});
`
383
``
`-
Some(guardaddr..guardaddr + pages * page_size)
`
384
``
`-
} else if cfg!(any(target_os = "openbsd", target_os = "netbsd")) {
`
385
``
`-
// OpenBSD stack already includes a guard page, and stack is
`
386
``
`-
// immutable.
`
387
``
`-
// NetBSD stack includes the guard page.
`
388
``
`-
//
`
389
``
`-
// We'll just note where we expect rlimit to start
`
390
``
`-
// faulting, so our handler can report "stack overflow", and
`
391
``
`-
// trust that the kernel's own stack guard will work.
`
392
``
`-
let stackptr = get_stack_start_aligned()?;
`
393
``
`-
let stackaddr = stackptr.addr();
`
394
``
`-
Some(stackaddr - page_size..stackaddr)
`
395
``
`-
} else {
`
396
``
`-
// Reallocate the last page of the stack.
`
397
``
`-
// This ensures SIGBUS will be raised on
`
398
``
`-
// stack overflow.
`
399
``
`-
// Systems which enforce strict PAX MPROTECT do not allow
`
400
``
`-
// to mprotect() a mapping with less restrictive permissions
`
401
``
`-
// than the initial mmap() used, so we mmap() here with
`
402
``
`-
// read/write permissions and only then mprotect() it to
`
403
``
`-
// no permissions at all. See issue #50313.
`
404
``
`-
let stackptr = get_stack_start_aligned()?;
`
405
``
`-
let result = mmap64(
`
``
331
+
``
332
`+
unsafe {
`
``
333
`+
// this way someone on any unix-y OS can check that all these compile
`
``
334
`+
if cfg!(all(target_os = "linux", not(target_env = "musl"))) {
`
``
335
`+
install_main_guard_linux(page_size)
`
``
336
`+
} else if cfg!(all(target_os = "linux", target_env = "musl")) {
`
``
337
`+
install_main_guard_linux_musl(page_size)
`
``
338
`+
} else if cfg!(target_os = "freebsd") {
`
``
339
`+
install_main_guard_freebsd(page_size)
`
``
340
`+
} else if cfg!(any(target_os = "netbsd", target_os = "openbsd")) {
`
``
341
`+
install_main_guard_bsds(page_size)
`
``
342
`+
} else {
`
``
343
`+
install_main_guard_default(page_size)
`
``
344
`+
}
`
``
345
`+
}
`
``
346
`+
}
`
``
347
+
``
348
`+
#[forbid(unsafe_op_in_unsafe_fn)]
`
``
349
`+
unsafe fn install_main_guard_linux(page_size: usize) -> Option<Range> {
`
``
350
`+
// Linux doesn't allocate the whole stack right away, and
`
``
351
`+
// the kernel has its own stack-guard mechanism to fault
`
``
352
`+
// when growing too close to an existing mapping. If we map
`
``
353
`+
// our own guard, then the kernel starts enforcing a rather
`
``
354
`+
// large gap above that, rendering much of the possible
`
``
355
`+
// stack space useless. See #43052.
`
``
356
`+
//
`
``
357
`+
// Instead, we'll just note where we expect rlimit to start
`
``
358
`+
// faulting, so our handler can report "stack overflow", and
`
``
359
`+
// trust that the kernel's own stack guard will work.
`
``
360
`+
let stackptr = stack_start_aligned(page_size)?;
`
``
361
`+
let stackaddr = stackptr.addr();
`
``
362
`+
Some(stackaddr - page_size..stackaddr)
`
``
363
`+
}
`
``
364
+
``
365
`+
#[forbid(unsafe_op_in_unsafe_fn)]
`
``
366
`+
unsafe fn install_main_guard_linux_musl(_page_size: usize) -> Option<Range> {
`
``
367
`+
// For the main thread, the musl's pthread_attr_getstack
`
``
368
`+
// returns the current stack size, rather than maximum size
`
``
369
`+
// it can eventually grow to. It cannot be used to determine
`
``
370
`+
// the position of kernel's stack guard.
`
``
371
`+
None
`
``
372
`+
}
`
``
373
+
``
374
`+
#[forbid(unsafe_op_in_unsafe_fn)]
`
``
375
`+
unsafe fn install_main_guard_freebsd(page_size: usize) -> Option<Range> {
`
``
376
`+
// FreeBSD's stack autogrows, and optionally includes a guard page
`
``
377
`+
// at the bottom. If we try to remap the bottom of the stack
`
``
378
`+
// ourselves, FreeBSD's guard page moves upwards. So we'll just use
`
``
379
`+
// the builtin guard page.
`
``
380
`+
let stackptr = stack_start_aligned(page_size)?;
`
``
381
`+
let guardaddr = stackptr.addr();
`
``
382
`+
// Technically the number of guard pages is tunable and controlled
`
``
383
`+
// by the security.bsd.stack_guard_page sysctl.
`
``
384
`+
// By default it is 1, checking once is enough since it is
`
``
385
`+
// a boot time config value.
`
``
386
`+
static PAGES: OnceLock = OnceLock::new();
`
``
387
+
``
388
`+
let pages = PAGES.get_or_init(|| {
`
``
389
`+
use crate::sys::weak::dlsym;
`
``
390
`+
dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int);
`
``
391
`+
let mut guard: usize = 0;
`
``
392
`+
let mut size = mem::size_of_val(&guard);
`
``
393
`+
let oid = c"security.bsd.stack_guard_page";
`
``
394
`+
match sysctlbyname.get() {
`
``
395
`+
Some(fcn) if unsafe {
`
``
396
`+
fcn(oid.as_ptr(),
`
``
397
`+
ptr::addr_of_mut!(guard).cast(),
`
``
398
`+
ptr::addr_of_mut!(size),
`
``
399
`+
ptr::null_mut(),
`
``
400
`+
- == 0
`
``
401
`+
} => guard,
`
``
402
`+
_ => 1,
`
``
403
`+
}
`
``
404
`+
});
`
``
405
`+
Some(guardaddr..guardaddr + pages * page_size)
`
``
406
`+
}
`
``
407
+
``
408
`+
#[forbid(unsafe_op_in_unsafe_fn)]
`
``
409
`+
unsafe fn install_main_guard_bsds(page_size: usize) -> Option<Range> {
`
``
410
`+
// OpenBSD stack already includes a guard page, and stack is
`
``
411
`+
// immutable.
`
``
412
`+
// NetBSD stack includes the guard page.
`
``
413
`+
//
`
``
414
`+
// We'll just note where we expect rlimit to start
`
``
415
`+
// faulting, so our handler can report "stack overflow", and
`
``
416
`+
// trust that the kernel's own stack guard will work.
`
``
417
`+
let stackptr = stack_start_aligned(page_size)?;
`
``
418
`+
let stackaddr = stackptr.addr();
`
``
419
`+
Some(stackaddr - page_size..stackaddr)
`
``
420
`+
}
`
``
421
+
``
422
`+
#[forbid(unsafe_op_in_unsafe_fn)]
`
``
423
`+
unsafe fn install_main_guard_default(page_size: usize) -> Option<Range> {
`
``
424
`+
// Reallocate the last page of the stack.
`
``
425
`+
// This ensures SIGBUS will be raised on
`
``
426
`+
// stack overflow.
`
``
427
`+
// Systems which enforce strict PAX MPROTECT do not allow
`
``
428
`+
// to mprotect() a mapping with less restrictive permissions
`
``
429
`+
// than the initial mmap() used, so we mmap() here with
`
``
430
`+
// read/write permissions and only then mprotect() it to
`
``
431
`+
// no permissions at all. See issue #50313.
`
``
432
`+
let stackptr = stack_start_aligned(page_size)?;
`
``
433
`+
let result = unsafe {
`
``
434
`+
mmap64(
`
406
435
` stackptr,
`
407
436
` page_size,
`
408
437
`PROT_READ | PROT_WRITE,
`
409
438
`MAP_PRIVATE | MAP_ANON | MAP_FIXED,
`
410
439
` -1,
`
411
440
`0,
`
412
``
`-
);
`
413
``
`-
if result != stackptr || result == MAP_FAILED {
`
414
``
`-
panic!("failed to allocate a guard page: {}", io::Error::last_os_error());
`
415
``
`-
}
`
``
441
`+
)
`
``
442
`+
};
`
``
443
`+
if result != stackptr || result == MAP_FAILED {
`
``
444
`+
panic!("failed to allocate a guard page: {}", io::Error::last_os_error());
`
``
445
`+
}
`
416
446
``
417
``
`-
let result = mprotect(stackptr, page_size, PROT_NONE);
`
418
``
`-
if result != 0 {
`
419
``
`-
panic!("failed to protect the guard page: {}", io::Error::last_os_error());
`
420
``
`-
}
`
``
447
`+
let result = unsafe { mprotect(stackptr, page_size, PROT_NONE) };
`
``
448
`+
if result != 0 {
`
``
449
`+
panic!("failed to protect the guard page: {}", io::Error::last_os_error());
`
``
450
`+
}
`
421
451
``
422
``
`-
let guardaddr = stackptr.addr();
`
``
452
`+
let guardaddr = stackptr.addr();
`
423
453
``
424
``
`-
Some(guardaddr..guardaddr + page_size)
`
425
``
`-
}
`
``
454
`+
Some(guardaddr..guardaddr + page_size)
`
426
455
`}
`
427
456
``
428
457
`#[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))]
`