
Description
See rust-lang/rust#72175 and nix-rust/nix#1421: it seems an external library is allowed to assume a file descriptor is private, for example:
#![allow(clippy::blacklisted_name)]
#![deny(unsafe_code)]
use socket2::SockRef;
use std::mem;
#[allow(unsafe_code)]
mod external_library {
use std::{mem, os::unix::io::RawFd, ptr};
static DATA: i32 = -1;
pub struct Foo([RawFd; 2]);
impl Foo {
pub fn new() -> Self {
let mut sockets = [-1; 2];
assert_eq!(
unsafe {
libc::socketpair(
libc::AF_UNIX,
libc::SOCK_SEQPACKET | libc::SOCK_CLOEXEC,
0,
sockets.as_mut_ptr(),
)
},
0
);
Self(sockets)
}
pub fn foo(&self) {
let data: *const _ = &DATA;
assert_eq!(
unsafe {
libc::send(
self.0[0],
ptr::addr_of!(data).cast(),
mem::size_of_val(&data),
0,
)
},
mem::size_of_val(&data) as _
);
}
pub fn bar(&self) -> i32 {
let mut ptr: *const i32 = ptr::null();
assert_eq!(
unsafe {
libc::recv(
self.0[1],
ptr::addr_of_mut!(ptr).cast(),
mem::size_of_val(&ptr),
0,
)
},
mem::size_of_val(&ptr) as _
);
unsafe { *ptr }
}
}
}
fn main() {
let foo = external_library::Foo::new();
SockRef::from(&3)
.send(&[0; mem::size_of::<*const i32>()])
.unwrap();
foo.foo();
dbg!(foo.bar());
}
Here, the safe SockRef::from
allows to crash a (fake) "external library" by letting it dereference a null pointer using only safe code. Making functions that accept arbitrary file descriptors or SOCKET
s unsafe can probably solve this problem.
Metadata
Metadata
Assignees
Labels
No labels