diff options
author | Alan Somers <asomers@gmail.com> | 2022-09-15 14:58:56 -0600 |
---|---|---|
committer | Alan Somers <asomers@gmail.com> | 2022-11-28 23:07:54 -0700 |
commit | 8e91b28b64bdd18fc6fa61af8e89947ad7fb97bf (patch) | |
tree | 335f72ffe2636d3783cdfba3214ea33458e6e11e /src/sys | |
parent | 12fb35434f04dccf941c3e1e52fb98df6cea41e6 (diff) | |
download | nix-8e91b28b64bdd18fc6fa61af8e89947ad7fb97bf.zip |
Fix UB in the SO_TYPE sockopt
When reading a value into an enum from getsockopt, we must validate it.
Failing to do so can lead to UB for example with SOCK_PACKET on Linux.
Perform the validation in GetSockOpt::get. Currently SockType is the
only type that requires validation.
Fixes #1819
Diffstat (limited to 'src/sys')
-rw-r--r-- | src/sys/socket/mod.rs | 20 | ||||
-rw-r--r-- | src/sys/socket/sockopt.rs | 13 |
2 files changed, 29 insertions, 4 deletions
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index a0702585..2d7159a6 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -12,7 +12,7 @@ use libc::{ self, c_int, c_void, iovec, size_t, socklen_t, CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_NXTHDR, }; -use std::convert::TryInto; +use std::convert::{TryFrom, TryInto}; use std::io::{IoSlice, IoSliceMut}; #[cfg(feature = "net")] use std::net; @@ -107,6 +107,24 @@ pub enum SockType { #[cfg(not(any(target_os = "haiku")))] Rdm = libc::SOCK_RDM, } +// The TryFrom impl could've been derived using libc_enum!. But for +// backwards-compatibility with Nix-0.25.0 we manually implement it, so as to +// keep the old variant names. +impl TryFrom<i32> for SockType { + type Error = crate::Error; + + fn try_from(x: i32) -> Result<Self> { + match x { + libc::SOCK_STREAM => Ok(Self::Stream), + libc::SOCK_DGRAM => Ok(Self::Datagram), + libc::SOCK_SEQPACKET => Ok(Self::SeqPacket), + libc::SOCK_RAW => Ok(Self::Raw), + #[cfg(not(any(target_os = "haiku")))] + libc::SOCK_RDM => Ok(Self::Rdm), + _ => Err(Errno::EINVAL) + } + } +} /// Constants used in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) /// to specify the protocol to use. diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 7489858e..06e9ee45 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -6,7 +6,10 @@ use crate::Result; use cfg_if::cfg_if; use libc::{self, c_int, c_void, socklen_t}; use std::ffi::{OsStr, OsString}; -use std::mem::{self, MaybeUninit}; +use std::{ + convert::TryFrom, + mem::{self, MaybeUninit} +}; #[cfg(target_family = "unix")] use std::os::unix::ffi::OsStrExt; use std::os::unix::io::RawFd; @@ -102,7 +105,10 @@ macro_rules! getsockopt_impl { ); Errno::result(res)?; - Ok(getter.assume_init()) + match <$ty>::try_from(getter.assume_init()) { + Err(_) => Err(Errno::EINVAL), + Ok(r) => Ok(r) + } } } } @@ -629,7 +635,8 @@ sockopt_impl!( GetOnly, libc::SOL_SOCKET, libc::SO_TYPE, - super::SockType + super::SockType, + GetStruct<i32> ); sockopt_impl!( /// Returns a value indicating whether or not this socket has been marked to |