Skip to content

Invalid transmute from std::net::Ipv4Addr to libc::in_addr #2053

Closed
@stevenengler

Description

@stevenengler

The functions ipv4addr_to_libc and ipv6addr_to_libc transmute from std::net::Ipv4Addr to libc::in_addr, but this is unsound.

/// Convert a std::net::Ipv4Addr into the libc form.
#[cfg(feature = "net")]
pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr {
static_assertions::assert_eq_size!(net::Ipv4Addr, libc::in_addr);
// Safe because both types have the same memory layout, and no fancy Drop
// impls.
unsafe { mem::transmute(addr) }
}
/// Convert a std::net::Ipv6Addr into the libc form.
#[cfg(feature = "net")]
pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr {
static_assertions::assert_eq_size!(net::Ipv6Addr, libc::in6_addr);
// Safe because both are Newtype wrappers around the same libc type
unsafe { mem::transmute(*addr) }
}

The rust socket address types do not have the same layouts as their corresponding libc types, even if their size is the same.

See rust-lang/rust#78802 for details.

This release changes the memory layout of Ipv4Addr, Ipv6Addr, SocketAddrV4 and SocketAddrV6. The standard library no longer implements these as the corresponding libc structs (sockaddr_in, sockaddr_in6 etc.). This internal representation was never exposed, but some crates relied on it anyway by unsafely transmuting. This change will cause those crates to make invalid memory accesses.

This change obviously changes the memory layout of the types. And it turns out some libraries invalidly assumes the memory layout and does very dangerous pointer casts to convert them. These libraries will have undefined behaviour and perform invalid memory access until patched.

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