Skip to content

SockRef::from, Socket::sendfile and other functions that operate on arbitrary file descriptors or SOCKETs potentially should be unsafe #218

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 SOCKETs unsafe can probably solve this problem.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions