Skip to content

Commit c77458f

Browse files
asomersrtzoeller
authored andcommitted
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 cfacd8f commit c77458f

File tree

2 files changed

+128
-1
lines changed

2 files changed

+128
-1
lines changed

CHANGELOG.md

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

9+
- Added `SockaddrStorage::{as_unix_addr, as_unix_addr_mut}`
10+
([#1871](https://github.com/nix-rust/nix/pull/1871))
11+
912
### Changed
1013

1114
### Fixed
@@ -19,6 +22,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
1922
([#1815](https://github.com/nix-rust/nix/pull/1815))
2023
- Fix `User::from_uid` and `User::from_name` crash on Android platform.
2124
([#1824](https://github.com/nix-rust/nix/pull/1824))
25+
- Fixed using `SockaddrStorage` to store a Unix-domain socket address on Linux.
26+
([#1871](https://github.com/nix-rust/nix/pull/1871))
2227

2328
### Removed
2429

src/sys/socket/addr.rs

+123-1
Original file line numberDiff line numberDiff line change
@@ -1398,7 +1398,18 @@ impl SockaddrLike for SockaddrStorage {
13981398
let mut ss: libc::sockaddr_storage = mem::zeroed();
13991399
let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8;
14001400
ptr::copy(addr as *const u8, ssp, len as usize);
1401-
Some(Self{ss})
1401+
#[cfg(any(
1402+
target_os = "android",
1403+
target_os = "fuchsia",
1404+
target_os = "illumos",
1405+
target_os = "linux"
1406+
))]
1407+
if i32::from(ss.ss_family) == libc::AF_UNIX {
1408+
// Safe because we UnixAddr is strictly smaller than
1409+
// SockaddrStorage, and we just initialized the structure.
1410+
(*(&mut ss as *mut libc::sockaddr_storage as *mut UnixAddr)).sun_len = len as u8;
1411+
}
1412+
Some(Self { ss })
14021413
}
14031414
} else {
14041415
// If length is not available and addr is of a fixed-length type,
@@ -1445,6 +1456,21 @@ impl SockaddrLike for SockaddrStorage {
14451456
}
14461457
}
14471458
}
1459+
1460+
#[cfg(any(
1461+
target_os = "android",
1462+
target_os = "fuchsia",
1463+
target_os = "illumos",
1464+
target_os = "linux"
1465+
))]
1466+
fn len(&self) -> libc::socklen_t {
1467+
match self.as_unix_addr() {
1468+
// The UnixAddr type knows its own length
1469+
Some(ua) => ua.len(),
1470+
// For all else, we're just a boring SockaddrStorage
1471+
None => mem::size_of_val(self) as libc::socklen_t
1472+
}
1473+
}
14481474
}
14491475

14501476
macro_rules! accessors {
@@ -1483,6 +1509,64 @@ macro_rules! accessors {
14831509
}
14841510

14851511
impl SockaddrStorage {
1512+
/// Downcast to an immutable `[UnixAddr]` reference.
1513+
pub fn as_unix_addr(&self) -> Option<&UnixAddr> {
1514+
cfg_if! {
1515+
if #[cfg(any(target_os = "android",
1516+
target_os = "fuchsia",
1517+
target_os = "illumos",
1518+
target_os = "linux"
1519+
))]
1520+
{
1521+
let p = unsafe{ &self.ss as *const libc::sockaddr_storage };
1522+
// Safe because UnixAddr is strictly smaller than
1523+
// sockaddr_storage, and we're fully initialized
1524+
let len = unsafe {
1525+
(*(p as *const UnixAddr )).sun_len as usize
1526+
};
1527+
} else {
1528+
let len = self.len() as usize;
1529+
}
1530+
}
1531+
// Sanity checks
1532+
if self.family() != Some(AddressFamily::Unix) ||
1533+
len < offset_of!(libc::sockaddr_un, sun_path) ||
1534+
len > mem::size_of::<libc::sockaddr_un>() {
1535+
None
1536+
} else {
1537+
Some(unsafe{&self.su})
1538+
}
1539+
}
1540+
1541+
/// Downcast to a mutable `[UnixAddr]` reference.
1542+
pub fn as_unix_addr_mut(&mut self) -> Option<&mut UnixAddr> {
1543+
cfg_if! {
1544+
if #[cfg(any(target_os = "android",
1545+
target_os = "fuchsia",
1546+
target_os = "illumos",
1547+
target_os = "linux"
1548+
))]
1549+
{
1550+
let p = unsafe{ &self.ss as *const libc::sockaddr_storage };
1551+
// Safe because UnixAddr is strictly smaller than
1552+
// sockaddr_storage, and we're fully initialized
1553+
let len = unsafe {
1554+
(*(p as *const UnixAddr )).sun_len as usize
1555+
};
1556+
} else {
1557+
let len = self.len() as usize;
1558+
}
1559+
}
1560+
// Sanity checks
1561+
if self.family() != Some(AddressFamily::Unix) ||
1562+
len < offset_of!(libc::sockaddr_un, sun_path) ||
1563+
len > mem::size_of::<libc::sockaddr_un>() {
1564+
None
1565+
} else {
1566+
Some(unsafe{&mut self.su})
1567+
}
1568+
}
1569+
14861570
#[cfg(any(target_os = "android", target_os = "linux"))]
14871571
accessors!{as_alg_addr, as_alg_addr_mut, AlgAddr,
14881572
AddressFamily::Alg, libc::sockaddr_alg, alg}
@@ -2789,6 +2873,44 @@ mod tests {
27892873
}
27902874
}
27912875

2876+
mod sockaddr_storage {
2877+
use super::*;
2878+
2879+
#[test]
2880+
fn from_sockaddr_un_named() {
2881+
let ua = UnixAddr::new("/var/run/mysock").unwrap();
2882+
let ptr = ua.as_ptr() as *const libc::sockaddr;
2883+
let ss = unsafe {
2884+
SockaddrStorage::from_raw(ptr, Some(ua.len()))
2885+
}.unwrap();
2886+
assert_eq!(ss.len(), ua.len());
2887+
}
2888+
2889+
#[cfg(any(target_os = "android", target_os = "linux"))]
2890+
#[test]
2891+
fn from_sockaddr_un_abstract_named() {
2892+
let name = String::from("nix\0abstract\0test");
2893+
let ua = UnixAddr::new_abstract(name.as_bytes()).unwrap();
2894+
let ptr = ua.as_ptr() as *const libc::sockaddr;
2895+
let ss = unsafe {
2896+
SockaddrStorage::from_raw(ptr, Some(ua.len()))
2897+
}.unwrap();
2898+
assert_eq!(ss.len(), ua.len());
2899+
}
2900+
2901+
#[cfg(any(target_os = "android", target_os = "linux"))]
2902+
#[test]
2903+
fn from_sockaddr_un_abstract_unnamed() {
2904+
let empty = String::new();
2905+
let ua = UnixAddr::new_abstract(empty.as_bytes()).unwrap();
2906+
let ptr = ua.as_ptr() as *const libc::sockaddr;
2907+
let ss = unsafe {
2908+
SockaddrStorage::from_raw(ptr, Some(ua.len()))
2909+
}.unwrap();
2910+
assert_eq!(ss.len(), ua.len());
2911+
}
2912+
}
2913+
27922914
mod unixaddr {
27932915
use super::*;
27942916

0 commit comments

Comments
 (0)