Skip to content

Commit 9ea1493

Browse files
bors[bot]asomers
andauthored
Merge #1871
1871: Fix using SockaddrStorage to store Unix domain addresses on Linux r=rtzoeller a=asomers Since it has variable length, the user of a sockaddr_un must keep track of its true length. On the BSDs, this is handled by the builtin sun_len field. But on Linux-like operating systems it isn't. Fix this bug by explicitly tracking it for SockaddrStorage just like we already do for UnixAddr. Fixes #1866 Co-authored-by: Alan Somers <[email protected]>
2 parents 8d27985 + fa62534 commit 9ea1493

File tree

2 files changed

+127
-1
lines changed

2 files changed

+127
-1
lines changed

CHANGELOG.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ This project adheres to [Semantic Versioning](https://semver.org/).
66
## [Unreleased] - ReleaseDate
77
### Added
88

9-
- Add `MntFlags` and `unmount` on all of the BSDs.
9+
- Added `SockaddrStorage::{as_unix_addr, as_unix_addr_mut}`
10+
([#1871](https://github.com/nix-rust/nix/pull/1871))
11+
- Added `MntFlags` and `unmount` on all of the BSDs.
1012
([#1849](https://github.com/nix-rust/nix/pull/1849))
1113
- Added a 'Statfs::flags' method.
1214
([#1849](https://github.com/nix-rust/nix/pull/1849))
@@ -44,6 +46,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
4446

4547
### Fixed
4648

49+
- Fixed using `SockaddrStorage` to store a Unix-domain socket address on Linux.
50+
([#1871](https://github.com/nix-rust/nix/pull/1871))
4751
- Fix microsecond calculation for `TimeSpec`.
4852
([#1801](https://github.com/nix-rust/nix/pull/1801))
4953
- Fix `User::from_name` and `Group::from_name` panicking

src/sys/socket/addr.rs

+122
Original file line numberDiff line numberDiff line change
@@ -1536,6 +1536,17 @@ impl SockaddrLike for SockaddrStorage {
15361536
let mut ss: libc::sockaddr_storage = mem::zeroed();
15371537
let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8;
15381538
ptr::copy(addr as *const u8, ssp, len as usize);
1539+
#[cfg(any(
1540+
target_os = "android",
1541+
target_os = "fuchsia",
1542+
target_os = "illumos",
1543+
target_os = "linux"
1544+
))]
1545+
if i32::from(ss.ss_family) == libc::AF_UNIX {
1546+
// Safe because we UnixAddr is strictly smaller than
1547+
// SockaddrStorage, and we just initialized the structure.
1548+
(*(&mut ss as *mut libc::sockaddr_storage as *mut UnixAddr)).sun_len = len as u8;
1549+
}
15391550
Some(Self { ss })
15401551
}
15411552
} else {
@@ -1597,6 +1608,21 @@ impl SockaddrLike for SockaddrStorage {
15971608
}
15981609
}
15991610
}
1611+
1612+
#[cfg(any(
1613+
target_os = "android",
1614+
target_os = "fuchsia",
1615+
target_os = "illumos",
1616+
target_os = "linux"
1617+
))]
1618+
fn len(&self) -> libc::socklen_t {
1619+
match self.as_unix_addr() {
1620+
// The UnixAddr type knows its own length
1621+
Some(ua) => ua.len(),
1622+
// For all else, we're just a boring SockaddrStorage
1623+
None => mem::size_of_val(self) as libc::socklen_t
1624+
}
1625+
}
16001626
}
16011627

16021628
macro_rules! accessors {
@@ -1634,6 +1660,64 @@ macro_rules! accessors {
16341660
}
16351661

16361662
impl SockaddrStorage {
1663+
/// Downcast to an immutable `[UnixAddr]` reference.
1664+
pub fn as_unix_addr(&self) -> Option<&UnixAddr> {
1665+
cfg_if! {
1666+
if #[cfg(any(target_os = "android",
1667+
target_os = "fuchsia",
1668+
target_os = "illumos",
1669+
target_os = "linux"
1670+
))]
1671+
{
1672+
let p = unsafe{ &self.ss as *const libc::sockaddr_storage };
1673+
// Safe because UnixAddr is strictly smaller than
1674+
// sockaddr_storage, and we're fully initialized
1675+
let len = unsafe {
1676+
(*(p as *const UnixAddr )).sun_len as usize
1677+
};
1678+
} else {
1679+
let len = self.len() as usize;
1680+
}
1681+
}
1682+
// Sanity checks
1683+
if self.family() != Some(AddressFamily::Unix) ||
1684+
len < offset_of!(libc::sockaddr_un, sun_path) ||
1685+
len > mem::size_of::<libc::sockaddr_un>() {
1686+
None
1687+
} else {
1688+
Some(unsafe{&self.su})
1689+
}
1690+
}
1691+
1692+
/// Downcast to a mutable `[UnixAddr]` reference.
1693+
pub fn as_unix_addr_mut(&mut self) -> Option<&mut UnixAddr> {
1694+
cfg_if! {
1695+
if #[cfg(any(target_os = "android",
1696+
target_os = "fuchsia",
1697+
target_os = "illumos",
1698+
target_os = "linux"
1699+
))]
1700+
{
1701+
let p = unsafe{ &self.ss as *const libc::sockaddr_storage };
1702+
// Safe because UnixAddr is strictly smaller than
1703+
// sockaddr_storage, and we're fully initialized
1704+
let len = unsafe {
1705+
(*(p as *const UnixAddr )).sun_len as usize
1706+
};
1707+
} else {
1708+
let len = self.len() as usize;
1709+
}
1710+
}
1711+
// Sanity checks
1712+
if self.family() != Some(AddressFamily::Unix) ||
1713+
len < offset_of!(libc::sockaddr_un, sun_path) ||
1714+
len > mem::size_of::<libc::sockaddr_un>() {
1715+
None
1716+
} else {
1717+
Some(unsafe{&mut self.su})
1718+
}
1719+
}
1720+
16371721
#[cfg(any(target_os = "android", target_os = "linux"))]
16381722
accessors! {as_alg_addr, as_alg_addr_mut, AlgAddr,
16391723
AddressFamily::Alg, libc::sockaddr_alg, alg}
@@ -3063,6 +3147,44 @@ mod tests {
30633147
}
30643148
}
30653149

3150+
mod sockaddr_storage {
3151+
use super::*;
3152+
3153+
#[test]
3154+
fn from_sockaddr_un_named() {
3155+
let ua = UnixAddr::new("/var/run/mysock").unwrap();
3156+
let ptr = ua.as_ptr() as *const libc::sockaddr;
3157+
let ss = unsafe {
3158+
SockaddrStorage::from_raw(ptr, Some(ua.len()))
3159+
}.unwrap();
3160+
assert_eq!(ss.len(), ua.len());
3161+
}
3162+
3163+
#[cfg(any(target_os = "android", target_os = "linux"))]
3164+
#[test]
3165+
fn from_sockaddr_un_abstract_named() {
3166+
let name = String::from("nix\0abstract\0test");
3167+
let ua = UnixAddr::new_abstract(name.as_bytes()).unwrap();
3168+
let ptr = ua.as_ptr() as *const libc::sockaddr;
3169+
let ss = unsafe {
3170+
SockaddrStorage::from_raw(ptr, Some(ua.len()))
3171+
}.unwrap();
3172+
assert_eq!(ss.len(), ua.len());
3173+
}
3174+
3175+
#[cfg(any(target_os = "android", target_os = "linux"))]
3176+
#[test]
3177+
fn from_sockaddr_un_abstract_unnamed() {
3178+
let empty = String::new();
3179+
let ua = UnixAddr::new_abstract(empty.as_bytes()).unwrap();
3180+
let ptr = ua.as_ptr() as *const libc::sockaddr;
3181+
let ss = unsafe {
3182+
SockaddrStorage::from_raw(ptr, Some(ua.len()))
3183+
}.unwrap();
3184+
assert_eq!(ss.len(), ua.len());
3185+
}
3186+
}
3187+
30663188
mod unixaddr {
30673189
use super::*;
30683190

0 commit comments

Comments
 (0)