mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-01-12 08:40:54 +00:00
net_util: clean up transmutes in create_sockaddr()
Rewrite create_sockaddr() using only safe type conversions instead of the unsafe mem::transmute(), and add helper functions to do the sockaddr to sockaddr_in (and vice versa) conversion safely. BUG=b:365852007 Change-Id: I79690ebd1d10056800d46e8da1641ad44cb04b62 Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/5760286 Reviewed-by: Dennis Kempin <denniskempin@google.com> Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
parent
705a9a6465
commit
1457967c08
1 changed files with 36 additions and 11 deletions
|
@ -504,30 +504,55 @@ fn create_socket() -> Result<net::UdpSocket> {
|
||||||
Err(Error::CreateSocket(SysError::last()))
|
Err(Error::CreateSocket(SysError::last()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sockaddr_from_sockaddr_in(addr_in: libc::sockaddr_in) -> libc::sockaddr {
|
||||||
|
assert_eq!(
|
||||||
|
mem::size_of::<libc::sockaddr_in>(),
|
||||||
|
mem::size_of::<libc::sockaddr>()
|
||||||
|
);
|
||||||
|
|
||||||
|
// SAFETY: trivially safe
|
||||||
|
unsafe { mem::transmute::<libc::sockaddr_in, libc::sockaddr>(addr_in) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sockaddr_in_from_sockaddr(addr: libc::sockaddr) -> Option<libc::sockaddr_in> {
|
||||||
|
if addr.sa_family as i32 != libc::AF_INET {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
mem::size_of::<libc::sockaddr_in>(),
|
||||||
|
mem::size_of::<libc::sockaddr>()
|
||||||
|
);
|
||||||
|
|
||||||
|
// SAFETY:
|
||||||
|
// This is safe because sockaddr and sockaddr_in are the same size, and we've checked that
|
||||||
|
// this address is AF_INET.
|
||||||
|
Some(unsafe { mem::transmute::<libc::sockaddr, libc::sockaddr_in>(addr) })
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a sockaddr_in from an IPv4 address, and expose it as
|
/// Create a sockaddr_in from an IPv4 address, and expose it as
|
||||||
/// an opaque sockaddr suitable for usage by socket ioctls.
|
/// an opaque sockaddr suitable for usage by socket ioctls.
|
||||||
fn create_sockaddr(ip_addr: net::Ipv4Addr) -> libc::sockaddr {
|
fn create_sockaddr(ip_addr: net::Ipv4Addr) -> libc::sockaddr {
|
||||||
// IPv4 addresses big-endian (network order), but Ipv4Addr will give us
|
|
||||||
// a view of those bytes directly so we can avoid any endian trickiness.
|
|
||||||
let addr_in = libc::sockaddr_in {
|
let addr_in = libc::sockaddr_in {
|
||||||
sin_family: libc::AF_INET as u16,
|
sin_family: libc::AF_INET as u16,
|
||||||
sin_port: 0,
|
sin_port: 0,
|
||||||
// SAFETY: trivially safe
|
sin_addr: libc::in_addr {
|
||||||
sin_addr: unsafe { mem::transmute(ip_addr.octets()) },
|
// `Ipv4Addr::octets()` returns the address in network byte order, so use
|
||||||
|
// `from_be_bytes()` to convert it into the native endianness, then `to_be()` to convert
|
||||||
|
// it back into big-endian (network) byte order as required by `sockaddr_in`. This is
|
||||||
|
// effectively a no-op, and we could use `u32::from_ne_bytes()` instead, but it is
|
||||||
|
// easier to understand when written this way.
|
||||||
|
s_addr: u32::from_be_bytes(ip_addr.octets()).to_be(),
|
||||||
|
},
|
||||||
sin_zero: [0; 8usize],
|
sin_zero: [0; 8usize],
|
||||||
};
|
};
|
||||||
|
|
||||||
// SAFETY: trivially safe
|
sockaddr_from_sockaddr_in(addr_in)
|
||||||
unsafe { mem::transmute(addr_in) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract the IPv4 address from a sockaddr. Assumes the sockaddr is a sockaddr_in.
|
/// Extract the IPv4 address from a sockaddr. Assumes the sockaddr is a sockaddr_in.
|
||||||
fn read_ipv4_addr(addr: &libc::sockaddr) -> net::Ipv4Addr {
|
fn read_ipv4_addr(addr: &libc::sockaddr) -> net::Ipv4Addr {
|
||||||
debug_assert_eq!(addr.sa_family as i32, libc::AF_INET);
|
let in_addr = sockaddr_in_from_sockaddr(*addr).unwrap();
|
||||||
// SAFETY:
|
|
||||||
// This is safe because sockaddr and sockaddr_in are the same size, and we've checked that
|
|
||||||
// this address is AF_INET.
|
|
||||||
let in_addr: libc::sockaddr_in = unsafe { mem::transmute(*addr) };
|
|
||||||
net::Ipv4Addr::from(in_addr.sin_addr.s_addr)
|
net::Ipv4Addr::from(in_addr.sin_addr.s_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue