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

`+

  1. == 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"))]

`