Skip to content

Commit d8dce52

Browse files
committed
Do not blindly assume strings returned by uname will always be valid UTF-8
1 parent 5d7fcc8 commit d8dce52

File tree

3 files changed

+25
-28
lines changed

3 files changed

+25
-28
lines changed

src/features.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ mod os {
3131
let mut minor: usize = 0;
3232
let mut patch: usize = 0;
3333

34-
for b in u.release().bytes() {
34+
for &b in u.release() {
3535
if curr >= 3 {
3636
break;
3737
}

src/sys/utsname.rs

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
//! Get system identification
22
use std::mem;
3-
use libc::{self, c_char};
4-
use std::ffi::CStr;
5-
use std::str::from_utf8_unchecked;
3+
use libc::c_char;
64
use crate::Errno;
75

86
/// Describes the running system. Return type of [`uname`].
@@ -11,29 +9,29 @@ use crate::Errno;
119
pub struct UtsName(libc::utsname);
1210

1311
impl UtsName {
14-
/// Name of the operating system implementation
15-
pub fn sysname(&self) -> &str {
16-
to_str(&(&self.0.sysname as *const c_char ) as *const *const c_char)
12+
/// Name of the operating system implementation.
13+
pub fn sysname(&self) -> &[u8] {
14+
cast_and_trim(&self.0.sysname)
1715
}
1816

1917
/// Network name of this machine.
20-
pub fn nodename(&self) -> &str {
21-
to_str(&(&self.0.nodename as *const c_char ) as *const *const c_char)
18+
pub fn nodename(&self) -> &[u8] {
19+
cast_and_trim(&self.0.nodename)
2220
}
2321

2422
/// Release level of the operating system.
25-
pub fn release(&self) -> &str {
26-
to_str(&(&self.0.release as *const c_char ) as *const *const c_char)
23+
pub fn release(&self) -> &[u8] {
24+
cast_and_trim(&self.0.release)
2725
}
2826

2927
/// Version level of the operating system.
30-
pub fn version(&self) -> &str {
31-
to_str(&(&self.0.version as *const c_char ) as *const *const c_char)
28+
pub fn version(&self) -> &[u8] {
29+
cast_and_trim(&self.0.version)
3230
}
3331

3432
/// Machine hardware platform.
35-
pub fn machine(&self) -> &str {
36-
to_str(&(&self.0.machine as *const c_char ) as *const *const c_char)
33+
pub fn machine(&self) -> &[u8] {
34+
cast_and_trim(&self.0.machine)
3735
}
3836
}
3937

@@ -46,11 +44,10 @@ pub fn uname() -> Result<UtsName, Errno> {
4644
}
4745
}
4846

49-
#[inline]
50-
fn to_str<'a>(s: *const *const c_char) -> &'a str {
47+
fn cast_and_trim(slice: &[c_char]) -> &[u8] {
48+
let length = slice.iter().position(|&byte| byte == 0).unwrap_or(slice.len());
5149
unsafe {
52-
let res = CStr::from_ptr(*s).to_bytes();
53-
from_utf8_unchecked(res)
50+
std::slice::from_raw_parts(slice.as_ptr().cast(), length)
5451
}
5552
}
5653

@@ -59,18 +56,18 @@ mod test {
5956
#[cfg(target_os = "linux")]
6057
#[test]
6158
pub fn test_uname_linux() {
62-
assert_eq!(super::uname().unwrap().sysname(), "Linux");
59+
assert_eq!(super::uname().unwrap().sysname(), b"Linux");
6360
}
6461

6562
#[cfg(any(target_os = "macos", target_os = "ios"))]
6663
#[test]
6764
pub fn test_uname_darwin() {
68-
assert_eq!(super::uname().unwrap().sysname(), "Darwin");
65+
assert_eq!(super::uname().unwrap().sysname(), b"Darwin");
6966
}
7067

7168
#[cfg(target_os = "freebsd")]
7269
#[test]
7370
pub fn test_uname_freebsd() {
74-
assert_eq!(super::uname().unwrap().sysname(), "FreeBSD");
71+
assert_eq!(super::uname().unwrap().sysname(), b"FreeBSD");
7572
}
7673
}

test/common/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,14 +112,14 @@ cfg_if! {
112112
.expect("Bad match_version provided");
113113

114114
let uname = nix::sys::utsname::uname().unwrap();
115-
println!("{}", uname.sysname());
116-
println!("{}", uname.nodename());
117-
println!("{}", uname.release());
118-
println!("{}", uname.version());
119-
println!("{}", uname.machine());
115+
println!("{}", std::str::from_utf8(uname.sysname()).unwrap());
116+
println!("{}", std::str::from_utf8(uname.nodename()).unwrap());
117+
println!("{}", std::str::from_utf8(uname.release()).unwrap());
118+
println!("{}", std::str::from_utf8(uname.version()).unwrap());
119+
println!("{}", std::str::from_utf8(uname.machine()).unwrap());
120120

121121
// Fix stuff that the semver parser can't handle
122-
let fixed_release = &uname.release().to_string()
122+
let fixed_release = &std::str::from_utf8(uname.release()).unwrap().to_string()
123123
// Fedora 33 reports version as 4.18.el8_2.x86_64 or
124124
// 5.18.200-fc33.x86_64. Remove the underscore.
125125
.replace("_", "-")

0 commit comments

Comments
 (0)