nix icon indicating copy to clipboard operation
nix copied to clipboard

`impl GetSockOpt for nix::sys::socket::sockopt::SockType` causes UB with unknown socket type

Open ahcodedthat opened this issue 3 years ago • 1 comments
trafficstars

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

ahcodedthat avatar Sep 15 '22 19:09 ahcodedthat

Good catch.

asomers avatar Sep 15 '22 20:09 asomers