diff --git a/Cargo.lock b/Cargo.lock index c9424de..cbda2b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2743,9 +2743,9 @@ checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" [[package]] name = "sysinfo" -version = "0.39.6" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2071df9448915b71c4fe6d25deaf1c22f12bd234f01540b77312bb8e41361e6" +checksum = "0e8a3edbe0394ce115f3917a00349dd242be09eb5a091ed509eaf67b55cfb8a8" dependencies = [ "libc", "memchr", diff --git a/Cargo.toml b/Cargo.toml index 231b3a2..5e06ea2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,7 +81,7 @@ crossterm = "0.29.0" dashmap = "6.1.0" subtle = "2.6.1" regex-lite = "0.1.8" -sysinfo = { version = "0.39.0", default-features = false, features = ["system", "disk", "network"] } +sysinfo = { version = "0.40.1", default-features = false, features = ["system", "disk", "network"] } x509-cert = { version = "0.3.0", features = ["builder"] } signature = "3.0.0" sha2 = "0.11.0" diff --git a/crates/rite-stdlib/src/verification/host.rs b/crates/rite-stdlib/src/verification/host.rs index 29b91c8..3c1b285 100644 --- a/crates/rite-stdlib/src/verification/host.rs +++ b/crates/rite-stdlib/src/verification/host.rs @@ -41,8 +41,8 @@ pub enum HostInfoScope { pub fn gather_host_info(scope: HostInfoScope) -> HostInfo { // These are associated functions in `sysinfo`; no `System` instance or // refresh is needed, so the `Basic` scope stays cheap. - let os = System::name(); - let os_version = System::long_os_version(); + let os = System::name().ok(); + let os_version = System::long_os_version().ok(); let hostname = get_hostname(); let mut info = HostInfo { @@ -57,7 +57,7 @@ pub fn gather_host_info(scope: HostInfoScope) -> HostInfo { }; if scope == HostInfoScope::Full { - info.kernel_version = System::kernel_version(); + info.kernel_version = System::kernel_version().ok(); info.cpu_model = cpu_model(); info.machine_id = get_machine_id(); info.hardening = Some(collect_security_features()); @@ -69,10 +69,11 @@ pub fn gather_host_info(scope: HostInfoScope) -> HostInfo { /// Gather the live device environment. MVP: block devices. #[must_use] pub fn gather_environment() -> Environment { - let disks = sysinfo::Disks::new_with_refreshed_list(); + // Failure handled as in `network_snapshot`. + let disks = sysinfo::Disks::new_with_refreshed_list().ok(); let disks = disks - .list() .iter() + .flatten() .map(|d| { let file_system = osstr_opt(d.file_system()); let kind = match d.kind() { @@ -104,6 +105,7 @@ fn osstr_opt(value: &std::ffi::OsStr) -> Option { fn get_hostname() -> String { System::host_name() + .ok() .or_else(|| std::env::var("HOSTNAME").ok()) .unwrap_or_else(|| "unknown".to_string()) } @@ -112,7 +114,8 @@ fn cpu_model() -> Option { // Refresh CPUs only: the brand is all we need, so skip the // process/memory scan a full `System::new_all()` would run. let sys = - System::new_with_specifics(RefreshKind::nothing().with_cpu(CpuRefreshKind::everything())); + System::new_with_specifics(RefreshKind::nothing().with_cpu(CpuRefreshKind::everything())) + .ok()?; sys.cpus() .first() // AMD brand strings end in padding spaces. diff --git a/crates/rite-stdlib/src/verification/network.rs b/crates/rite-stdlib/src/verification/network.rs index 30e889a..d2a82a7 100644 --- a/crates/rite-stdlib/src/verification/network.rs +++ b/crates/rite-stdlib/src/verification/network.rs @@ -6,6 +6,7 @@ //! and connects it, which only queries the routing table. The sysfs probes //! read under a root given as a parameter (see `probe_fixtures`). +use std::ffi::OsStr; use std::io::ErrorKind; #[cfg(any(target_os = "linux", test))] use std::path::Path; @@ -37,16 +38,24 @@ const ARPHRD_RAWIP: u16 = 519; /// Take a snapshot of the network state. #[must_use] pub fn network_snapshot() -> NetworkSnapshot { - let networks = sysinfo::Networks::new_with_refreshed_list(); - let mut interfaces: Vec = networks - .list() + // `sysinfo` fails only on systems it does not support, none of them a + // Rite target. + let networks = sysinfo::Networks::new_with_refreshed_list().ok(); + let mut listed: Vec<_> = networks .iter() + .flatten() .filter(|(name, data)| is_interface(name) && !is_loopback(name, data.ip_networks())) + .collect(); + // Sorted on the OS name, so the order holds even if two names that are + // not UTF-8 read the same once converted. + listed.sort_by_key(|(name, _)| *name); + let interfaces: Vec = listed + .into_iter() .map(|(name, data)| { let (kind, carrier) = link(name); let mac = data.mac_address(); NetworkInterface { - name: name.clone(), + name: name.to_string_lossy().into_owned(), kind, state: data.operational_state().to_string(), carrier, @@ -61,7 +70,6 @@ pub fn network_snapshot() -> NetworkSnapshot { } }) .collect(); - interfaces.sort_by(|a, b| a.name.cmp(&b.name)); #[cfg(target_os = "linux")] let radios = radios( Path::new("/sys/class/rfkill"), @@ -79,8 +87,9 @@ pub fn network_snapshot() -> NetworkSnapshot { /// Whether an interface is loopback: named so, or with only loopback /// addresses. -fn is_loopback(name: &str, addresses: &[sysinfo::IpNetwork]) -> bool { - matches!(name, "lo" | "lo0") +fn is_loopback(name: &OsStr, addresses: &[sysinfo::IpNetwork]) -> bool { + name == "lo" + || name == "lo0" || (!addresses.is_empty() && addresses.iter().all(|net| net.addr.is_loopback())) } @@ -111,22 +120,22 @@ fn has_route(bind: &str, target: &str) -> Option { /// `/sys/class/net`, and the bonding driver keeps a file there /// (`bonding_masters`); interfaces are directories. #[cfg(target_os = "linux")] -fn is_interface(name: &str) -> bool { +fn is_interface(name: &OsStr) -> bool { Path::new("/sys/class/net").join(name).is_dir() } #[cfg(not(target_os = "linux"))] -fn is_interface(_name: &str) -> bool { +fn is_interface(_name: &OsStr) -> bool { true } #[cfg(target_os = "linux")] -fn link(name: &str) -> (InterfaceKind, Option) { +fn link(name: &OsStr) -> (InterfaceKind, Option) { sysfs_link(&Path::new("/sys/class/net").join(name)) } #[cfg(not(target_os = "linux"))] -fn link(_name: &str) -> (InterfaceKind, Option) { +fn link(_name: &OsStr) -> (InterfaceKind, Option) { (InterfaceKind::Unknown, None) } @@ -311,11 +320,17 @@ mod tests { addr: addr.parse().expect("an address"), prefix: 8, }; - assert!(is_loopback("lo", &[])); - assert!(is_loopback("lo0", &[net("127.0.0.1")])); - assert!(is_loopback("other", &[net("127.0.0.1"), net("::1")])); - assert!(!is_loopback("en0", &[])); - assert!(!is_loopback("en0", &[net("127.0.0.1"), net("192.168.1.2")])); + assert!(is_loopback(OsStr::new("lo"), &[])); + assert!(is_loopback(OsStr::new("lo0"), &[net("127.0.0.1")])); + assert!(is_loopback( + OsStr::new("other"), + &[net("127.0.0.1"), net("::1")] + )); + assert!(!is_loopback(OsStr::new("en0"), &[])); + assert!(!is_loopback( + OsStr::new("en0"), + &[net("127.0.0.1"), net("192.168.1.2")] + )); } #[test] diff --git a/crates/rite-stdlib/src/verification/platform.rs b/crates/rite-stdlib/src/verification/platform.rs index 00c1a1c..5a647e8 100644 --- a/crates/rite-stdlib/src/verification/platform.rs +++ b/crates/rite-stdlib/src/verification/platform.rs @@ -56,8 +56,8 @@ pub fn detect_platform() -> Platform { Platform { os: OsIdentity { id: Some(sysinfo::System::distribution_id()), - version: sysinfo::System::os_version(), - name: sysinfo::System::long_os_version(), + version: sysinfo::System::os_version().ok(), + name: sysinfo::System::long_os_version().ok(), }, virtualization: guest_virtualization(), ..Platform::default()