Skip to content

Commit 987e586

Browse files
committed
Exclude NUL characters from OSStrings returned by getsockopt
On FreeBSD, getsockopt appends a single NUL to the returned string. On Linux, it pads the entire buffer with NULs. But both of those behaviors may be version-dependent. Adjust GetOsString to handle any number of NUL characters.
1 parent e7e9809 commit 987e586

File tree

3 files changed

+23
-9
lines changed

3 files changed

+23
-9
lines changed

changelog/2557.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Properly exclude NUL characters from `OSString`s returned by `getsockopt`.

src/sys/socket/sockopt.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use crate::{errno::Errno, Result};
77
use cfg_if::cfg_if;
88
use libc::{self, c_int, c_void, socklen_t};
99
#[cfg(apple_targets)]
10-
use std::ffi::{CStr, CString};
11-
use std::ffi::{OsStr, OsString};
10+
use std::ffi::CString;
11+
use std::ffi::{CStr, OsStr, OsString};
1212
use std::mem::{self, MaybeUninit};
1313
use std::os::unix::ffi::OsStrExt;
1414
#[cfg(linux_android)]
@@ -1745,7 +1745,13 @@ impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
17451745
unsafe fn assume_init(self) -> OsString {
17461746
let len = self.len as usize;
17471747
let mut v = unsafe { self.val.assume_init() };
1748-
OsStr::from_bytes(&v.as_mut()[0..len]).to_owned()
1748+
if let Ok(cs) = CStr::from_bytes_until_nul(&v.as_mut()[0..len]) {
1749+
OsStr::from_bytes(cs.to_bytes())
1750+
} else {
1751+
// The OS returned a non-NUL-terminated string
1752+
OsStr::from_bytes(&v.as_mut()[0..len])
1753+
}
1754+
.to_owned()
17491755
}
17501756
}
17511757

test/sys/test_sockopt.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -249,14 +249,13 @@ fn test_so_type_unknown() {
249249
}
250250

251251
// The CI doesn't supported getsockopt and setsockopt on emulated processors.
252-
// It's believed that a QEMU issue, the tests run ok on a fully emulated system.
253-
// Current CI just run the binary with QEMU but the Kernel remains the same as the host.
252+
// It's believed to be a QEMU issue; the tests run ok on a fully emulated
253+
// system. Current CI just runs the binary with QEMU but the kernel remains the
254+
// same as the host.
254255
// So the syscall doesn't work properly unless the kernel is also emulated.
255256
#[test]
256-
#[cfg(all(
257-
any(target_arch = "x86", target_arch = "x86_64"),
258-
any(target_os = "freebsd", target_os = "linux")
259-
))]
257+
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
258+
#[cfg_attr(qemu, ignore)]
260259
fn test_tcp_congestion() {
261260
use std::ffi::OsString;
262261

@@ -269,6 +268,14 @@ fn test_tcp_congestion() {
269268
.unwrap();
270269

271270
let val = getsockopt(&fd, sockopt::TcpCongestion).unwrap();
271+
let bytes = val.as_os_str().as_encoded_bytes();
272+
for b in bytes.iter() {
273+
assert_ne!(
274+
*b, 0,
275+
"OsString should contain no embedded NULs: {:?}",
276+
val
277+
);
278+
}
272279
setsockopt(&fd, sockopt::TcpCongestion, &val).unwrap();
273280

274281
setsockopt(

0 commit comments

Comments
 (0)