1 use std::io::{BufRead, Read};
2 use std::{fs, io};
3
4 use rustix::thread::*;
5
6 #[test]
test_get_keep_capabilities()7 fn test_get_keep_capabilities() {
8 dbg!(get_keep_capabilities().unwrap());
9 }
10
11 #[test]
test_name()12 fn test_name() {
13 dbg!(name().unwrap());
14 }
15
16 #[test]
test_is_in_capability_bounding_set()17 fn test_is_in_capability_bounding_set() {
18 dbg!(is_in_capability_bounding_set(Capability::ChangeOwnership).unwrap());
19 }
20
21 #[test]
test_capabilities_secure_bits()22 fn test_capabilities_secure_bits() {
23 dbg!(capabilities_secure_bits().unwrap());
24 }
25
26 #[test]
test_current_timer_slack()27 fn test_current_timer_slack() {
28 dbg!(current_timer_slack().unwrap());
29 }
30
31 #[test]
test_no_new_privs()32 fn test_no_new_privs() {
33 dbg!(no_new_privs().unwrap());
34 }
35
36 #[test]
test_capability_is_in_ambient_capability_set()37 fn test_capability_is_in_ambient_capability_set() {
38 dbg!(capability_is_in_ambient_capability_set(Capability::ChangeOwnership).unwrap());
39 }
40
41 #[cfg(target_arch = "aarch64")]
42 #[test]
test_sve_vector_length_configuration()43 fn test_sve_vector_length_configuration() {
44 dbg!(sve_vector_length_configuration().unwrap());
45 }
46
47 #[cfg(target_arch = "aarch64")]
48 #[test]
test_current_tagged_address_mode()49 fn test_current_tagged_address_mode() {
50 dbg!(current_tagged_address_mode().unwrap());
51 }
52
53 #[test]
54 #[ignore = "?"]
test_transparent_huge_pages_are_disabled()55 fn test_transparent_huge_pages_are_disabled() {
56 dbg!(transparent_huge_pages_are_disabled().unwrap());
57 }
58
59 /*
60 #[test]
61 #[ignore = "Might result in SIGKILL"]
62 fn test_secure_computing_mode() {
63 if !linux_kernel_config_item_is_enabled("CONFIG_SECCOMP").unwrap_or(false) {
64 eprintln!("test_secure_computing_mode: Test skipped due to missing kernel feature: CONFIG_SECCOMP.");
65 return;
66 }
67
68 dbg!(secure_computing_mode().unwrap());
69 }
70 */
71
72 #[test]
test_get_clear_child_tid_address()73 fn test_get_clear_child_tid_address() {
74 if !linux_kernel_config_item_is_enabled("CONFIG_CHECKPOINT_RESTORE").unwrap_or(false) {
75 eprintln!("test_get_clear_child_tid_address: Test skipped due to missing kernel feature: CONFIG_CHECKPOINT_RESTORE.");
76 return;
77 }
78
79 match get_clear_child_tid_address() {
80 Ok(address) => println!("get_clear_child_tid_address = {:?}", address),
81
82 Err(r) => {
83 let errno = r.raw_os_error();
84 assert!(errno == libc::ENODEV || errno == libc::EINVAL);
85 eprintln!("test_get_clear_child_tid_address: Test unsupported: {}", r);
86 }
87 }
88 }
89
90 #[test]
test_core_scheduling_cookie()91 fn test_core_scheduling_cookie() {
92 if !linux_kernel_config_item_is_enabled("CONFIG_SCHED_CORE").unwrap_or(false) {
93 eprintln!("test_core_scheduling_cookie: Test skipped due to missing kernel feature: CONFIG_SCHED_CORE.");
94 return;
95 }
96
97 match core_scheduling_cookie(rustix::thread::gettid(), CoreSchedulingScope::Thread) {
98 Ok(cookie) => println!("core_scheduling_cookie = {:?}", cookie),
99
100 Err(r) => {
101 let errno = r.raw_os_error();
102 assert!(errno == libc::ENODEV || errno == libc::EINVAL);
103 eprintln!("test_core_scheduling_cookie: Test unsupported: {}", r);
104 }
105 }
106 }
107
108 /*
109 * Helper functions.
110 */
111
load_linux_kernel_config() -> io::Result<Vec<u8>>112 fn load_linux_kernel_config() -> io::Result<Vec<u8>> {
113 if let Ok(compressed_bytes) = fs::read("/proc/config.gz") {
114 let mut decoder = flate2::bufread::GzDecoder::new(compressed_bytes.as_slice());
115 let mut bytes = Vec::default();
116 decoder.read_to_end(&mut bytes)?;
117 return Ok(bytes);
118 }
119
120 let info = rustix::process::uname();
121 let release = info
122 .release()
123 .to_str()
124 .map_err(|_r| io::Error::from(io::ErrorKind::InvalidData))?;
125
126 fs::read(format!("/boot/config-{}", release))
127 }
128
is_linux_kernel_config_item_enabled(config: &[u8], name: &str) -> io::Result<bool>129 fn is_linux_kernel_config_item_enabled(config: &[u8], name: &str) -> io::Result<bool> {
130 for line in io::Cursor::new(config).lines() {
131 let line = line?;
132 let line = line.trim();
133 if line.is_empty() || line.starts_with('#') {
134 continue;
135 }
136
137 let mut iter = line.splitn(2, '=');
138 if let Some(current_name) = iter.next().map(str::trim) {
139 if current_name == name {
140 if let Some(mut value) = iter.next().map(str::trim) {
141 if value.starts_with('"') && value.ends_with('"') {
142 // Just remove the quotes, but don't bother unescaping the inner string
143 // because we are only trying to find out if the option is an true boolean.
144 value = &value[1..(value.len() - 2)];
145 }
146
147 return Ok(value == "y" || value == "m");
148 }
149 }
150 }
151 }
152 Ok(false)
153 }
154
linux_kernel_config_item_is_enabled(name: &str) -> io::Result<bool>155 pub(crate) fn linux_kernel_config_item_is_enabled(name: &str) -> io::Result<bool> {
156 let config = load_linux_kernel_config()?;
157 is_linux_kernel_config_item_enabled(&config, name)
158 }
159