1use std::io::{BufRead, Read}; 2use std::os::raw::c_int; 3use std::{fs, io}; 4 5use rustix::process::*; 6#[cfg(feature = "thread")] 7use rustix::thread::Capability; 8 9#[test] 10fn test_parent_process_death_signal() { 11 dbg!(parent_process_death_signal().unwrap()); 12} 13 14#[test] 15fn test_dumpable_behavior() { 16 dbg!(dumpable_behavior().unwrap()); 17} 18 19#[test] 20fn test_timing_method() { 21 dbg!(timing_method().unwrap()); 22} 23 24#[test] 25fn test_machine_check_memory_corruption_kill_policy() { 26 dbg!(machine_check_memory_corruption_kill_policy().unwrap()); 27} 28 29#[cfg(target_arch = "x86")] 30#[test] 31fn test_time_stamp_counter_readability() { 32 dbg!(time_stamp_counter_readability().unwrap()); 33} 34 35#[cfg(target_arch = "powerpc")] 36#[test] 37fn test_unaligned_access_control() { 38 dbg!(unaligned_access_control().unwrap()); 39} 40 41#[cfg(target_arch = "powerpc")] 42#[test] 43fn test_floating_point_exception_mode() { 44 dbg!(floating_point_exception_mode().unwrap()); 45} 46 47#[cfg(target_arch = "powerpc")] 48#[test] 49fn test_endian_mode() { 50 dbg!(endian_mode().unwrap()); 51} 52 53#[cfg(target_arch = "mips")] 54#[test] 55fn test_floating_point_mode() { 56 dbg!(floating_point_mode().unwrap()); 57} 58 59#[cfg(target_arch = "aarch64")] 60#[test] 61#[ignore = "Only on ARMv8.3 and later"] 62fn test_enabled_pointer_authentication_keys() { 63 dbg!(enabled_pointer_authentication_keys().unwrap()); 64} 65 66#[test] 67#[ignore = "?"] 68fn test_child_subreaper() { 69 dbg!(child_subreaper().unwrap()); 70} 71 72#[test] 73#[ignore = "?"] 74fn test_speculative_feature_state() { 75 dbg!(speculative_feature_state(SpeculationFeature::SpeculativeStoreBypass).unwrap()); 76 dbg!(speculative_feature_state(SpeculationFeature::IndirectBranchSpeculation).unwrap()); 77 dbg!( 78 speculative_feature_state(SpeculationFeature::FlushL1DCacheOnContextSwitchOutOfTask) 79 .unwrap() 80 ); 81} 82 83#[cfg(feature = "thread")] 84#[test] 85fn test_is_io_flusher() { 86 if !thread_has_capability(Capability::SystemResource).unwrap() { 87 eprintln!("test_is_io_flusher: Test skipped due to missing capability: CAP_SYS_RESOURCE."); 88 return; 89 } 90 91 dbg!(is_io_flusher().unwrap()); 92} 93 94#[cfg(feature = "thread")] 95#[test] 96fn test_virtual_memory_map_config_struct_size() { 97 if !thread_has_capability(Capability::SystemResource).unwrap() { 98 eprintln!( 99 "test_virtual_memory_map_config_struct_size: Test skipped due to missing capability: CAP_SYS_RESOURCE." 100 ); 101 return; 102 } 103 104 if !linux_kernel_config_item_is_enabled("CONFIG_CHECKPOINT_RESTORE").unwrap_or(false) { 105 eprintln!("test_virtual_memory_map_config_struct_size: Test skipped due to missing kernel feature: CONFIG_CHECKPOINT_RESTORE."); 106 return; 107 } 108 109 dbg!(virtual_memory_map_config_struct_size().unwrap()); 110} 111 112#[test] 113#[ignore = "Only on ia64"] 114fn test_floating_point_emulation_control() { 115 dbg!(floating_point_emulation_control().unwrap()); 116} 117 118/* 119 * Helper functions. 120 */ 121 122#[cfg(feature = "thread")] 123pub(crate) fn thread_has_capability(capability: Capability) -> io::Result<bool> { 124 const _LINUX_CAPABILITY_VERSION_3: u32 = 0x20080522; 125 126 #[repr(C)] 127 struct cap_user_header_t { 128 version: u32, 129 pid: c_int, 130 } 131 132 #[repr(C)] 133 struct cap_user_data_t { 134 effective: u32, 135 permitted: u32, 136 inheritable: u32, 137 } 138 139 let header = cap_user_header_t { 140 version: _LINUX_CAPABILITY_VERSION_3, 141 pid: 0, 142 }; 143 144 let mut data: [cap_user_data_t; 2] = [ 145 cap_user_data_t { 146 effective: 0, 147 permitted: 0, 148 inheritable: 0, 149 }, 150 cap_user_data_t { 151 effective: 0, 152 permitted: 0, 153 inheritable: 0, 154 }, 155 ]; 156 157 let r = unsafe { 158 libc::syscall( 159 libc::SYS_capget, 160 &header as *const cap_user_header_t, 161 data.as_mut_ptr() as *mut cap_user_data_t, 162 ) 163 }; 164 165 if r == -1 { 166 return Err(io::Error::last_os_error()); 167 } 168 169 let cap_index = capability as u32; 170 let (data_index, cap_index) = if cap_index < 32 { 171 (0, cap_index) 172 } else { 173 (1, cap_index - 32) 174 }; 175 let flag = 1_u32 << cap_index; 176 Ok((flag & data[data_index].effective) != 0) 177} 178 179fn load_linux_kernel_config() -> io::Result<Vec<u8>> { 180 if let Ok(compressed_bytes) = fs::read("/proc/config.gz") { 181 let mut decoder = flate2::bufread::GzDecoder::new(compressed_bytes.as_slice()); 182 let mut bytes = Vec::default(); 183 decoder.read_to_end(&mut bytes)?; 184 return Ok(bytes); 185 } 186 187 let info = rustix::process::uname(); 188 let release = info 189 .release() 190 .to_str() 191 .map_err(|_r| io::Error::from(io::ErrorKind::InvalidData))?; 192 193 fs::read(format!("/boot/config-{}", release)) 194} 195 196fn is_linux_kernel_config_item_enabled(config: &[u8], name: &str) -> io::Result<bool> { 197 for line in io::Cursor::new(config).lines() { 198 let line = line?; 199 let line = line.trim(); 200 if line.is_empty() || line.starts_with('#') { 201 continue; 202 } 203 204 let mut iter = line.splitn(2, '='); 205 if let Some(current_name) = iter.next().map(str::trim) { 206 if current_name == name { 207 if let Some(mut value) = iter.next().map(str::trim) { 208 if value.starts_with('"') && value.ends_with('"') { 209 // Just remove the quotes, but don't bother unescaping the inner string 210 // because we are only trying to find out if the option is an true boolean. 211 value = &value[1..(value.len() - 2)]; 212 } 213 214 return Ok(value == "y" || value == "m"); 215 } 216 } 217 } 218 } 219 Ok(false) 220} 221 222pub(crate) fn linux_kernel_config_item_is_enabled(name: &str) -> io::Result<bool> { 223 let config = load_linux_kernel_config()?; 224 is_linux_kernel_config_item_enabled(&config, name) 225} 226