Closed
Description
Description
I noticed that the implementation of GetSockOpt
for nix::sys::socket::sockopt::SockType
simply assumes that the socket type returned by the kernel is one of those defined in enum nix::sys::socket::SockType
without checking. If that assumption is violated, you get undefined behavior.
Linux has at least one such socket type already (SOCK_PACKET
), and operating systems are free to add new ones at any time.
Other socket options probably suffer from a similar problem, but I haven't tested that.
Alternative
socket2::Type
deals with this problem by being a newtype wrapper around a c_int
instead of an enum
.
Proof of concept
This works on Linux only.
use nix::sys::socket::{getsockopt, sockopt};
use std::process::ExitCode;
fn main() -> ExitCode {
let sockfd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) };
if sockfd == -1 {
eprintln!("Error opening socket: {}", nix::Error::last());
return ExitCode::FAILURE;
}
let socktype = match getsockopt(sockfd, sockopt::SockType) {
Ok(ok) => ok,
Err(error) => {
eprintln!("Error getting socket type: {error}");
return ExitCode::FAILURE
}
};
eprintln!("The socket's type is: {socktype:?}");
ExitCode::SUCCESS
}
Output:
$ target/debug/nix-ub
The socket's type is: Segmentation fault
Note that creating a SOCK_PACKET
socket is a privileged operation, so the executable needs to be granted that privilege first:
$ cargo build
$ sudo setcap CAP_NET_RAW+eip target/debug/nix-ub