base: net: Validate descriptor passed to UnixSeqpacketListener

The existing file descriptor must refer to a listening socket.

TEST=cargo test, added a new unit test
BUG=b:238931628

Change-Id: Ia6bd5d6d30af69fb4b5fa00865f5528f19f569d9
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3932714
Commit-Queue: Keir Fraser <keirf@google.com>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
Keir Fraser 2022-10-03 11:42:34 +00:00 committed by crosvm LUCI
parent d1a1397542
commit 88674cade9

View file

@ -726,6 +726,26 @@ impl UnixSeqpacketListener {
.expect("fd filename should be unicode")
.parse::<i32>()
.expect("fd should be an integer");
let mut result: c_int = 0;
let mut result_len = size_of::<c_int>() as libc::socklen_t;
let ret = unsafe {
libc::getsockopt(
fd,
libc::SOL_SOCKET,
libc::SO_ACCEPTCONN,
&mut result as *mut _ as *mut libc::c_void,
&mut result_len,
)
};
if ret < 0 {
return Err(io::Error::last_os_error());
}
if result != 1 {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"specified descriptor is not a listening socket",
));
}
return Ok(UnixSeqpacketListener { fd });
}
// Safe socket initialization since we handle the returned error.
@ -976,6 +996,28 @@ mod tests {
assert_eq!(socket_path, listener_path);
}
#[test]
fn unix_seqpacket_listener_from_fd() {
let mut socket_path = tmpdir();
socket_path.push("unix_seqpacket_listener_from_fd");
let listener = UnlinkUnixSeqpacketListener(
UnixSeqpacketListener::bind(&socket_path)
.expect("failed to create UnixSeqpacketListener"),
);
// UnixSeqpacketListener should succeed on a valid listening desriptor.
let good_dup = UnixSeqpacketListener::bind(&format!("/proc/self/fd/{}", unsafe {
libc::dup(listener.as_raw_fd())
}));
good_dup.expect("failed to create dup UnixSeqpacketListener");
// UnixSeqpacketListener must fail on an existing non-listener socket.
let s1 =
UnixSeqpacket::connect(socket_path.as_path()).expect("UnixSeqpacket::connect failed");
let bad_dup = UnixSeqpacketListener::bind(&format!("/proc/self/fd/{}", unsafe {
libc::dup(s1.as_raw_fd())
}));
assert!(bad_dup.is_err())
}
#[test]
fn unix_seqpacket_path_exists_pass() {
let mut socket_path = tmpdir();