base: net: Ignore path of a UnixSeqpacketListener passed by descriptor

The path does not belong to crosvm and should not, for example, be
revealed to UnlinkUnixSeqpacketListener which would try to remove it.

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

Change-Id: I6e81623b76d62961c774010e1dafcf73ffca6471
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3941684
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Commit-Queue: Keir Fraser <keirf@google.com>
This commit is contained in:
Keir Fraser 2022-10-10 08:56:39 +00:00 committed by crosvm LUCI
parent 77e9606589
commit 47cf9446ac

View file

@ -712,6 +712,7 @@ impl IntoRawFd for UnixSeqpacket {
/// Like a `UnixListener` but for accepting `UnixSeqpacket` type sockets. /// Like a `UnixListener` but for accepting `UnixSeqpacket` type sockets.
pub struct UnixSeqpacketListener { pub struct UnixSeqpacketListener {
fd: RawFd, fd: RawFd,
no_path: bool,
} }
impl UnixSeqpacketListener { impl UnixSeqpacketListener {
@ -746,7 +747,7 @@ impl UnixSeqpacketListener {
"specified descriptor is not a listening socket", "specified descriptor is not a listening socket",
)); ));
} }
return Ok(UnixSeqpacketListener { fd }); return Ok(UnixSeqpacketListener { fd, no_path: true });
} }
// Safe socket initialization since we handle the returned error. // Safe socket initialization since we handle the returned error.
let fd = unsafe { let fd = unsafe {
@ -769,7 +770,7 @@ impl UnixSeqpacketListener {
return Err(io::Error::last_os_error()); return Err(io::Error::last_os_error());
} }
} }
Ok(UnixSeqpacketListener { fd }) Ok(UnixSeqpacketListener { fd, no_path: false })
} }
/// Blocks for and accepts a new incoming connection and returns the socket associated with that /// Blocks for and accepts a new incoming connection and returns the socket associated with that
@ -819,6 +820,12 @@ impl UnixSeqpacketListener {
sun_family: libc::AF_UNIX as libc::sa_family_t, sun_family: libc::AF_UNIX as libc::sa_family_t,
sun_path: [0; 108], sun_path: [0; 108],
}; };
if self.no_path {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"socket has no path",
));
}
let sun_path_offset = (&addr.sun_path as *const _ as usize let sun_path_offset = (&addr.sun_path as *const _ as usize
- &addr.sun_family as *const _ as usize) - &addr.sun_family as *const _ as usize)
as libc::socklen_t; as libc::socklen_t;
@ -880,7 +887,7 @@ impl Drop for UnixSeqpacketListener {
impl FromRawFd for UnixSeqpacketListener { impl FromRawFd for UnixSeqpacketListener {
// Unsafe in drop function // Unsafe in drop function
unsafe fn from_raw_fd(fd: RawFd) -> Self { unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self { fd } Self { fd, no_path: false }
} }
} }
@ -1004,18 +1011,22 @@ mod tests {
UnixSeqpacketListener::bind(&socket_path) UnixSeqpacketListener::bind(&socket_path)
.expect("failed to create UnixSeqpacketListener"), .expect("failed to create UnixSeqpacketListener"),
); );
// UnixSeqpacketListener should succeed on a valid listening desriptor. // UnixSeqpacketListener should succeed on a valid listening descriptor.
let good_dup = UnixSeqpacketListener::bind(&format!("/proc/self/fd/{}", unsafe { let good_dup = UnixSeqpacketListener::bind(&format!("/proc/self/fd/{}", unsafe {
libc::dup(listener.as_raw_fd()) libc::dup(listener.as_raw_fd())
})); }));
good_dup.expect("failed to create dup UnixSeqpacketListener"); let good_dup_path = good_dup
.expect("failed to create dup UnixSeqpacketListener")
.path();
// Path of socket created by descriptor should be hidden.
assert!(good_dup_path.is_err());
// UnixSeqpacketListener must fail on an existing non-listener socket. // UnixSeqpacketListener must fail on an existing non-listener socket.
let s1 = let s1 =
UnixSeqpacket::connect(socket_path.as_path()).expect("UnixSeqpacket::connect failed"); UnixSeqpacket::connect(socket_path.as_path()).expect("UnixSeqpacket::connect failed");
let bad_dup = UnixSeqpacketListener::bind(&format!("/proc/self/fd/{}", unsafe { let bad_dup = UnixSeqpacketListener::bind(&format!("/proc/self/fd/{}", unsafe {
libc::dup(s1.as_raw_fd()) libc::dup(s1.as_raw_fd())
})); }));
assert!(bad_dup.is_err()) assert!(bad_dup.is_err());
} }
#[test] #[test]