summaryrefslogtreecommitdiff
path: root/src/sys
diff options
context:
space:
mode:
authorAlan Somers <asomers@gmail.com>2022-09-15 14:58:56 -0600
committerAlan Somers <asomers@gmail.com>2022-11-28 23:07:54 -0700
commit8e91b28b64bdd18fc6fa61af8e89947ad7fb97bf (patch)
tree335f72ffe2636d3783cdfba3214ea33458e6e11e /src/sys
parent12fb35434f04dccf941c3e1e52fb98df6cea41e6 (diff)
downloadnix-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.rs20
-rw-r--r--src/sys/socket/sockopt.rs13
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