• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::io::{BufRead, Read};
2 use std::os::raw::c_int;
3 use std::{fs, io};
4 
5 use rustix::process::*;
6 #[cfg(feature = "thread")]
7 use rustix::thread::Capability;
8 
9 #[test]
test_parent_process_death_signal()10 fn test_parent_process_death_signal() {
11     dbg!(parent_process_death_signal().unwrap());
12 }
13 
14 #[test]
test_dumpable_behavior()15 fn test_dumpable_behavior() {
16     dbg!(dumpable_behavior().unwrap());
17 }
18 
19 #[test]
test_timing_method()20 fn test_timing_method() {
21     dbg!(timing_method().unwrap());
22 }
23 
24 #[test]
test_machine_check_memory_corruption_kill_policy()25 fn 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]
test_time_stamp_counter_readability()31 fn test_time_stamp_counter_readability() {
32     dbg!(time_stamp_counter_readability().unwrap());
33 }
34 
35 #[cfg(target_arch = "powerpc")]
36 #[test]
test_unaligned_access_control()37 fn test_unaligned_access_control() {
38     dbg!(unaligned_access_control().unwrap());
39 }
40 
41 #[cfg(target_arch = "powerpc")]
42 #[test]
test_floating_point_exception_mode()43 fn test_floating_point_exception_mode() {
44     dbg!(floating_point_exception_mode().unwrap());
45 }
46 
47 #[cfg(target_arch = "powerpc")]
48 #[test]
test_endian_mode()49 fn test_endian_mode() {
50     dbg!(endian_mode().unwrap());
51 }
52 
53 #[cfg(target_arch = "mips")]
54 #[test]
test_floating_point_mode()55 fn 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"]
test_enabled_pointer_authentication_keys()62 fn test_enabled_pointer_authentication_keys() {
63     dbg!(enabled_pointer_authentication_keys().unwrap());
64 }
65 
66 #[test]
67 #[ignore = "?"]
test_child_subreaper()68 fn test_child_subreaper() {
69     dbg!(child_subreaper().unwrap());
70 }
71 
72 #[test]
73 #[ignore = "?"]
test_speculative_feature_state()74 fn 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]
test_is_io_flusher()85 fn 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]
test_virtual_memory_map_config_struct_size()96 fn 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"]
test_floating_point_emulation_control()114 fn test_floating_point_emulation_control() {
115     dbg!(floating_point_emulation_control().unwrap());
116 }
117 
118 /*
119  * Helper functions.
120  */
121 
122 #[cfg(feature = "thread")]
thread_has_capability(capability: Capability) -> io::Result<bool>123 pub(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 
load_linux_kernel_config() -> io::Result<Vec<u8>>179 fn 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 
is_linux_kernel_config_item_enabled(config: &[u8], name: &str) -> io::Result<bool>196 fn 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 
linux_kernel_config_item_is_enabled(name: &str) -> io::Result<bool>222 pub(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