Skip to content

Commit 81f77d3

Browse files
committed
WIP PROOF-OF-CONCEPT fixup linux libs
1 parent 09be027 commit 81f77d3

File tree

8 files changed

+62
-43
lines changed

8 files changed

+62
-43
lines changed

library/panic_unwind/src/gcc.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@
3636
//! Once stack has been unwound down to the handler frame level, unwinding stops
3737
//! and the last personality routine transfers control to the catch block.
3838
39+
// FIXME(strict_provenance_magic): the unwinder has special permissions and semantics.
40+
//
41+
// This is at worst an Interesting Case Study that is worth doing a deep dive on.
42+
//
43+
// I haven't looked closely at this implementation yet.
44+
#![cfg_attr(not(bootstrap), allow(fuzzy_provenance_casts))]
45+
3946
use alloc::boxed::Box;
4047
use core::any::Any;
4148

library/std/src/backtrace.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ impl RawFrame {
493493
match self {
494494
RawFrame::Actual(frame) => frame.ip(),
495495
#[cfg(test)]
496-
RawFrame::Fake => ptr::invalid_mut(1),
496+
RawFrame::Fake => crate::ptr::invalid_mut(1),
497497
}
498498
}
499499
}

library/std/src/os/unix/net/addr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ mod libc {
1717

1818
fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
1919
// Work with an actual instance of the type since using a null pointer is UB
20-
let base = addr as *const _ as usize;
21-
let path = &addr.sun_path as *const _ as usize;
20+
let base = (addr as *const libc::sockaddr_un).addr();
21+
let path = (&addr.sun_path as *const i8).addr();
2222
path - base
2323
}
2424

library/std/src/sys/unix/memchr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
99
haystack.len(),
1010
)
1111
};
12-
if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) }
12+
if p.is_null() { None } else { Some(p.addr() - haystack.as_ptr().addr()) }
1313
}
1414

1515
pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
@@ -26,7 +26,7 @@ pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
2626
haystack.len(),
2727
)
2828
};
29-
if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) }
29+
if p.is_null() { None } else { Some(p.addr() - haystack.as_ptr().addr()) }
3030
}
3131

3232
#[cfg(not(target_os = "linux"))]

library/std/src/sys/unix/process/process_unix.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// FIXME(strict_provenance_magic): system API wants us to pass a pointer as a u64 :(
2+
#![cfg_attr(not(bootstrap), allow(fuzzy_provenance_casts))]
3+
14
use crate::convert::{TryFrom, TryInto};
25
use crate::fmt;
36
use crate::io::{self, Error, ErrorKind};

library/std/src/sys/unix/stack_overflow.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// FIXME(strict_provenance_magic): system API wants us to pass a pointer as size_t :(
2+
#![cfg_attr(not(bootstrap), allow(fuzzy_provenance_casts))]
13
#![cfg_attr(test, allow(dead_code))]
24

35
use self::imp::{drop_handler, make_handler};
@@ -62,12 +64,12 @@ mod imp {
6264
si_addr: *mut libc::c_void,
6365
}
6466

65-
(*(info as *const siginfo_t)).si_addr as usize
67+
(*(info as *const siginfo_t)).si_addr.addr()
6668
}
6769

6870
#[cfg(not(any(target_os = "linux", target_os = "android")))]
6971
unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
70-
(*info).si_addr as usize
72+
(*info).si_addr.addr()
7173
}
7274

7375
// Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages

library/std/src/sys/unix/thread.rs

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// FIXME(strict_provenance_magic): system API wants us to pass a pointer as ulong :(
2+
#![cfg_attr(not(bootstrap), allow(fuzzy_provenance_casts))]
3+
14
use crate::cmp;
25
use crate::ffi::CStr;
36
use crate::io;
@@ -505,24 +508,24 @@ pub mod guard {
505508
#[cfg(target_os = "macos")]
506509
unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
507510
let th = libc::pthread_self();
508-
let stackaddr =
509-
libc::pthread_get_stackaddr_np(th) as usize - libc::pthread_get_stacksize_np(th);
510-
Some(stackaddr as *mut libc::c_void)
511+
let stackptr = libc::pthread_get_stackaddr_np(th);
512+
Some(stackptr.with_addr(stackptr.with_addr() - libc::pthread_get_stacksize_np(th)))
511513
}
512514

513515
#[cfg(target_os = "openbsd")]
514516
unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
515517
let mut current_stack: libc::stack_t = crate::mem::zeroed();
516518
assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), &mut current_stack), 0);
517519

520+
let stack_ptr = current_stack.ss_sp;
518521
let stackaddr = if libc::pthread_main_np() == 1 {
519522
// main thread
520-
current_stack.ss_sp as usize - current_stack.ss_size + PAGE_SIZE.load(Ordering::Relaxed)
523+
stack_ptr.addr() - current_stack.ss_size + PAGE_SIZE.load(Ordering::Relaxed)
521524
} else {
522525
// new thread
523-
current_stack.ss_sp as usize - current_stack.ss_size
526+
stack_ptr.addr() - current_stack.ss_size
524527
};
525-
Some(stackaddr as *mut libc::c_void)
528+
Some(stack_ptr.with_addr(stack_addr))
526529
}
527530

528531
#[cfg(any(
@@ -557,19 +560,20 @@ pub mod guard {
557560
unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> {
558561
let page_size = PAGE_SIZE.load(Ordering::Relaxed);
559562
assert!(page_size != 0);
560-
let stackaddr = get_stack_start()?;
563+
let stackptr = get_stack_start()?;
564+
let stackaddr = stackptr.addr();
561565

562566
// Ensure stackaddr is page aligned! A parent process might
563567
// have reset RLIMIT_STACK to be non-page aligned. The
564568
// pthread_attr_getstack() reports the usable stack area
565569
// stackaddr < stackaddr + stacksize, so if stackaddr is not
566570
// page-aligned, calculate the fix such that stackaddr <
567571
// new_page_aligned_stackaddr < stackaddr + stacksize
568-
let remainder = (stackaddr as usize) % page_size;
572+
let remainder = (stackaddr) % page_size;
569573
Some(if remainder == 0 {
570-
stackaddr
574+
stackptr
571575
} else {
572-
((stackaddr as usize) + page_size - remainder) as *mut libc::c_void
576+
stackptr.with_addr(stackaddr + page_size - remainder)
573577
})
574578
}
575579

@@ -588,8 +592,8 @@ pub mod guard {
588592
// Instead, we'll just note where we expect rlimit to start
589593
// faulting, so our handler can report "stack overflow", and
590594
// trust that the kernel's own stack guard will work.
591-
let stackaddr = get_stack_start_aligned()?;
592-
let stackaddr = stackaddr as usize;
595+
let stackptr = get_stack_start_aligned()?;
596+
let stackaddr = stackptr.addr();
593597
Some(stackaddr - page_size..stackaddr)
594598
} else if cfg!(all(target_os = "linux", target_env = "musl")) {
595599
// For the main thread, the musl's pthread_attr_getstack
@@ -602,8 +606,8 @@ pub mod guard {
602606
// at the bottom. If we try to remap the bottom of the stack
603607
// ourselves, FreeBSD's guard page moves upwards. So we'll just use
604608
// the builtin guard page.
605-
let stackaddr = get_stack_start_aligned()?;
606-
let guardaddr = stackaddr as usize;
609+
let stackptr = get_stack_start_aligned()?;
610+
let guardaddr = stackptr.addr();
607611
// Technically the number of guard pages is tunable and controlled
608612
// by the security.bsd.stack_guard_page sysctl, but there are
609613
// few reasons to change it from the default. The default value has
@@ -620,33 +624,34 @@ pub mod guard {
620624
// than the initial mmap() used, so we mmap() here with
621625
// read/write permissions and only then mprotect() it to
622626
// no permissions at all. See issue #50313.
623-
let stackaddr = get_stack_start_aligned()?;
627+
let stackptr = get_stack_start_aligned()?;
624628
let result = mmap(
625-
stackaddr,
629+
stackptr,
626630
page_size,
627631
PROT_READ | PROT_WRITE,
628632
MAP_PRIVATE | MAP_ANON | MAP_FIXED,
629633
-1,
630634
0,
631635
);
632-
if result != stackaddr || result == MAP_FAILED {
636+
if result != stackptr || result == MAP_FAILED {
633637
panic!("failed to allocate a guard page: {}", io::Error::last_os_error());
634638
}
635639

636-
let result = mprotect(stackaddr, page_size, PROT_NONE);
640+
let result = mprotect(stackptr, page_size, PROT_NONE);
637641
if result != 0 {
638642
panic!("failed to protect the guard page: {}", io::Error::last_os_error());
639643
}
640644

641-
let guardaddr = stackaddr as usize;
645+
let guardaddr = stackptr.addr();
642646

643647
Some(guardaddr..guardaddr + page_size)
644648
}
645649
}
646650

647651
#[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))]
648652
pub unsafe fn current() -> Option<Guard> {
649-
let stackaddr = get_stack_start()? as usize;
653+
let stackptr = get_stack_start()?;
654+
let stackaddr = stackptr.addr();
650655
Some(stackaddr - PAGE_SIZE.load(Ordering::Relaxed)..stackaddr)
651656
}
652657

@@ -679,11 +684,11 @@ pub mod guard {
679684
panic!("there is no guard page");
680685
}
681686
}
682-
let mut stackaddr = crate::ptr::null_mut();
687+
let mut stackptr = crate::ptr::null_mut::<libc::c_void>();
683688
let mut size = 0;
684-
assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0);
689+
assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackptr, &mut size), 0);
685690

686-
let stackaddr = stackaddr as usize;
691+
let stackaddr = stackptr.addr();
687692
ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd")) {
688693
Some(stackaddr - guardsize..stackaddr)
689694
} else if cfg!(all(target_os = "linux", target_env = "musl")) {

library/std/src/sys/unix/weak.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@
2222
// that, we'll just allow that some unix targets don't use this module at all.
2323
#![allow(dead_code, unused_macros)]
2424

25-
use crate::ffi::CStr;
25+
use crate::ffi::{c_void, CStr};
2626
use crate::marker::PhantomData;
2727
use crate::mem;
28-
use crate::sync::atomic::{self, AtomicUsize, Ordering};
28+
use crate::ptr;
29+
use crate::sync::atomic::{self, AtomicPtr, Ordering};
2930

3031
// We can use true weak linkage on ELF targets.
3132
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
@@ -83,25 +84,26 @@ pub(crate) macro dlsym {
8384
}
8485
pub(crate) struct DlsymWeak<F> {
8586
name: &'static str,
86-
addr: AtomicUsize,
87+
addr: AtomicPtr<c_void>,
8788
_marker: PhantomData<F>,
8889
}
8990

9091
impl<F> DlsymWeak<F> {
9192
pub(crate) const fn new(name: &'static str) -> Self {
92-
DlsymWeak { name, addr: AtomicUsize::new(1), _marker: PhantomData }
93+
DlsymWeak { name, addr: AtomicPtr::new(ptr::invalid_mut(1)), _marker: PhantomData }
9394
}
9495

9596
#[inline]
9697
pub(crate) fn get(&self) -> Option<F> {
9798
unsafe {
9899
// Relaxed is fine here because we fence before reading through the
99100
// pointer (see the comment below).
100-
match self.addr.load(Ordering::Relaxed) {
101+
let fn_ptr = self.addr.load(Ordering::Relaxed);
102+
match fn_ptr.addr() {
101103
1 => self.initialize(),
102104
0 => None,
103-
addr => {
104-
let func = mem::transmute_copy::<usize, F>(&addr);
105+
_ => {
106+
let func = mem::transmute_copy::<*mut c_void, F>(&fn_ptr);
105107
// The caller is presumably going to read through this value
106108
// (by calling the function we've dlsymed). This means we'd
107109
// need to have loaded it with at least C11's consume
@@ -129,25 +131,25 @@ impl<F> DlsymWeak<F> {
129131
// Cold because it should only happen during first-time initialization.
130132
#[cold]
131133
unsafe fn initialize(&self) -> Option<F> {
132-
assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
134+
assert_eq!(mem::size_of::<F>(), mem::size_of::<*mut ()>());
133135

134136
let val = fetch(self.name);
135137
// This synchronizes with the acquire fence in `get`.
136138
self.addr.store(val, Ordering::Release);
137139

138-
match val {
140+
match val.addr() {
139141
0 => None,
140-
addr => Some(mem::transmute_copy::<usize, F>(&addr)),
142+
_ => Some(mem::transmute_copy::<*mut c_void, F>(&val)),
141143
}
142144
}
143145
}
144146

145-
unsafe fn fetch(name: &str) -> usize {
147+
unsafe fn fetch(name: &str) -> *mut c_void {
146148
let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
147149
Ok(cstr) => cstr,
148-
Err(..) => return 0,
150+
Err(..) => return ptr::null_mut(),
149151
};
150-
libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
152+
libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr())
151153
}
152154

153155
#[cfg(not(any(target_os = "linux", target_os = "android")))]

0 commit comments

Comments
 (0)