Skip to content

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

Closed
@ahcodedthat

Description

@ahcodedthat

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions