From 4a178ed8f4d90b9a778512ddf95b0a9c092aa9a9 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Tue, 19 Sep 2023 20:04:26 +0200 Subject: [PATCH] Handle posix hostname edge cases (#14) * Handle extra nul byte HOST_NAME_MAX is the maximum allowed hostname excluding the terminating nul byte. This means that HOST_NAME_MAX + 1 must be used for gethostname call. Otherwise -1 may be returned, e.g. by glibc's gethostname. How to reproduce on Linux with glibc: - Set hostname to a 64 character long string - Try to retrieve hostname * Handle posix systems without HOST_NAME_MAX limits If sysconf returns -1 this either means that an error occurred or that no limit exists. Casting -1 to size_t leads to a huge number, so only use the returned limit if it is not -1. If sysconf returned an error or no limit exists, use 255. * Fail if hostname is too long Invalid hostnames supplied to set should be rejected. Otherwise it could happen that on FreeBSD a partial hostname is set. --- src/nix.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/nix.rs b/src/nix.rs index 756bdb5..d585590 100644 --- a/src/nix.rs +++ b/src/nix.rs @@ -8,15 +8,18 @@ use std::os::unix::ffi::OsStringExt; use libc; +const _POSIX_HOST_NAME_MAX: libc::c_long = 255; + pub fn get() -> io::Result { // According to the POSIX specification, // host names are limited to `HOST_NAME_MAX` bytes // // https://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html - let size = - unsafe { libc::sysconf(libc::_SC_HOST_NAME_MAX) as libc::size_t }; + let limit = unsafe { libc::sysconf(libc::_SC_HOST_NAME_MAX) }; + let size = libc::c_long::max(limit, _POSIX_HOST_NAME_MAX) as usize; - let mut buffer = vec![0u8; size]; + // Reserve additional space for terminating nul byte. + let mut buffer = vec![0u8; size + 1]; let result = unsafe { libc::gethostname(buffer.as_mut_ptr() as *mut libc::c_char, size) @@ -58,6 +61,10 @@ pub fn set(hostname: &OsStr) -> io::Result<()> { #[allow(non_camel_case_types)] type hostname_len_t = libc::c_int; + if hostname.len() > hostname_len_t::MAX { + return Err(io::Error::new(io::ErrorKind::Other, "hostname too long")); + } + let size = hostname.len() as hostname_len_t; let result = unsafe {