Skip to content

Commit 63403e7

Browse files
committed
Fix using SockaddrStorage to store Unix domain addresses on Linux
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 nix-rust#1866
1 parent fbebb21 commit 63403e7

File tree

2 files changed

+131
-1
lines changed

2 files changed

+131
-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+
([#TODO](https://github.com/nix-rust/nix/pull/TODO))
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))
@@ -38,6 +40,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
3840

3941
### Fixed
4042

43+
- Fixed using `SockaddrStorage` to store a Unix-domain socket address on Linux.
44+
([#TODO](https://github.com/nix-rust/nix/pull/TODO))
4145
- Fix microsecond calculation for `TimeSpec`.
4246
([#1801](https://github.com/nix-rust/nix/pull/1801))
4347
- Fix `User::from_name` and `Group::from_name` panicking

src/sys/socket/addr.rs

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

16031629
macro_rules! accessors {
@@ -1635,6 +1661,68 @@ macro_rules! accessors {
16351661
}
16361662

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

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

0 commit comments

Comments
 (0)