Skip to content

Commit

Permalink
initialize msg_name with null pointer when msg_name is empty (nix-rus…
Browse files Browse the repository at this point in the history
…t#2530)

* Use as_mut_ptr() to initialize msg_name in pack_mhdr_to_receive

The msg_name field points to a caller-allocated buffer that is used to
return the source address if the socket is unconnected. The caller
should set msg_namelen to the size of this buffer before this call; upon
return from a successful call, msg_namelen will contain the length of
the returned address. If the application does not need to know the
source address, msg_name can be specified as NULL.

In case we use () msgname_len gets initialized with 0, but a dangling
pointer to the array with msg_name. This works for the first iteration
somehow, but after that kernel sets msgname_len to a non-zero and second
invocation with the same MultiHeader fails

Fixes nix-rust#2506

* CI doesn't check for rustfmt but I'm tired of picking stuff
  • Loading branch information
pacak authored Nov 3, 2024
1 parent a41a1f0 commit 5fe8266
Showing 1 changed file with 20 additions and 8 deletions.
28 changes: 20 additions & 8 deletions src/sys/socket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,20 @@ pub use self::addr::{SockaddrLike, SockaddrStorage};
pub use self::addr::{AddressFamily, UnixAddr};
#[cfg(not(solarish))]
pub use self::addr::{AddressFamily, UnixAddr};
#[cfg(not(any(solarish, target_os = "haiku", target_os = "hurd", target_os = "redox")))]
#[cfg(not(any(
solarish,
target_os = "haiku",
target_os = "hurd",
target_os = "redox"
)))]
#[cfg(feature = "net")]
pub use self::addr::{LinkAddr, SockaddrIn, SockaddrIn6};
#[cfg(any(solarish, target_os = "haiku", target_os = "hurd", target_os = "redox"))]
#[cfg(any(
solarish,
target_os = "haiku",
target_os = "hurd",
target_os = "redox"
))]
#[cfg(feature = "net")]
pub use self::addr::{SockaddrIn, SockaddrIn6};

Expand Down Expand Up @@ -851,17 +861,17 @@ pub enum ControlMessageOwned {
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6HopLimit(i32),

/// Retrieve the DSCP (ToS) header field of the incoming IPv4 packet.
/// Retrieve the DSCP (ToS) header field of the incoming IPv4 packet.
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv4Tos(u8),

/// Retrieve the DSCP (Traffic Class) header field of the incoming IPv6 packet.
/// Retrieve the DSCP (Traffic Class) header field of the incoming IPv6 packet.
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6TClass(i32),
Ipv6TClass(i32),

/// UDP Generic Receive Offload (GRO) allows receiving multiple UDP
/// packets from a single sender.
Expand Down Expand Up @@ -1119,7 +1129,7 @@ impl ControlMessageOwned {
(_, _) => {
let sl = unsafe { std::slice::from_raw_parts(p, len) };
let ucmsg = UnknownCmsg {
cmsg_header: *header,
cmsg_header: *header,
data_bytes: Vec::<u8>::from(sl),
};
ControlMessageOwned::Unknown(ucmsg)
Expand Down Expand Up @@ -2059,7 +2069,10 @@ unsafe fn pack_mhdr_to_receive<S>(
let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
let p = mhdr.as_mut_ptr();
unsafe {
(*p).msg_name = address as *mut c_void;
// it is important to use as_mut_ptr() here since S can be
// a zero sized type representing by a dangling pointer.
// as_mut_ptr() handles this case and uses a null pointer instead
(*p).msg_name = (*address).as_mut_ptr() as *mut c_void;
(*p).msg_namelen = S::size();
(*p).msg_iov = iov_buffer as *mut iovec;
(*p).msg_iovlen = iov_buffer_len as _;
Expand Down Expand Up @@ -2517,4 +2530,3 @@ pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> {
Errno::result(shutdown(df, how)).map(drop)
}
}

0 comments on commit 5fe8266

Please sign in to comment.