Skip to content

Commit 7942be5

Browse files
committed
kernel stuff
1 parent 00892a8 commit 7942be5

4 files changed

Lines changed: 147 additions & 220 deletions

File tree

src/checkers/byo_kernel.rs

Lines changed: 16 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@ use crate::helpers::{
22
CheckGroup, CheckGroupCategory, CheckGroupResult, CheckResult,
33
CheckResultValue::{Errored, Failed, Passed},
44
host_executor::HostNamespaceExecutor,
5+
kernel as khelper,
56
};
67

7-
use anyhow::{Result, bail};
88
use async_trait::async_trait;
99
use futures::{FutureExt, future::join_all};
10-
use log::debug;
11-
use procfs::{Current, sys::kernel};
12-
use std::{fs, path::PathBuf, process::Command};
10+
use procfs::sys::kernel;
1311

1412
const GROUP_IDENTIFIER: &str = "byokernel";
1513
const NAME: &str = "Bring-Your-Own Kernel Checks";
@@ -65,157 +63,54 @@ impl BYOKernelChecks {
6563

6664
async fn version_is_good(&self) -> CheckResult {
6765
let name = String::from("Host Kernel Version Is Good");
68-
let mut result = Passed;
66+
let floor = kernel::Version::new(KVER_FLOOR_MAJOR, KVER_FLOOR_MINOR, KVER_FLOOR_PATCH);
6967

70-
// Get host kernel version
71-
let current = self
72-
.host_executor
73-
.spawn_in_host_ns(async { kernel::Version::current() })
74-
.await
75-
.expect("error spawning in host");
68+
let passed = khelper::host_kver_above_floor(&self.host_executor, floor).await;
7669

77-
if let Err(e) = current {
78-
return CheckResult::new(&name, Errored(e.to_string()));
70+
match passed {
71+
Err(e) => CheckResult::new(&name, Errored(e.to_string())),
72+
Ok(true) => CheckResult::new(&name, Passed),
73+
Ok(false) => CheckResult::new(
74+
&name,
75+
Failed(String::from("current kernel version is unsupported")),
76+
),
7977
}
80-
let current = current.unwrap();
81-
let lowest = kernel::Version::new(KVER_FLOOR_MAJOR, KVER_FLOOR_MINOR, KVER_FLOOR_PATCH);
82-
83-
if current < lowest {
84-
result = Failed(String::from("current kernel version is unsupported"));
85-
}
86-
CheckResult::new(&name, result)
8778
}
8879

8980
async fn has_modules(&self) -> CheckResult {
9081
let name = String::from("Host Has Necessary Modules");
91-
let mut result = Passed;
9282

9383
let required_modules: Vec<String> =
9484
REQUIRED_MODULES.iter().map(|s| s.to_string()).collect();
9585

9686
// Search builtin modules
97-
let remaining = match self.find_builtins(&required_modules).await {
87+
let remaining = match khelper::find_builtins(&self.host_executor, &required_modules).await {
9888
Ok(r) => r,
9989
Err(e) => {
10090
return CheckResult::new(&name, Errored(format!("getting kernel builtins {e}")));
10191
}
10292
};
10393

10494
// Search loaded modules
105-
let remaining = match self.find_loaded(&remaining).await {
95+
let remaining = match khelper::find_loaded(&self.host_executor, &remaining).await {
10696
Ok(r) => r,
10797
Err(e) => {
10898
return CheckResult::new(&name, Errored(format!("getting kernel modules {e}")));
10999
}
110100
};
111101

112102
// Search loadable modules
113-
let remaining = match self.find_loadable(&remaining).await {
103+
let remaining = match khelper::find_loadable(&self.host_executor, &remaining).await {
114104
Ok(r) => r,
115105
Err(e) => {
116106
return CheckResult::new(&name, Errored(format!("getting kernel modules {e}")));
117107
}
118108
};
119109
if !remaining.is_empty() {
120-
result = Failed(format!("missing {:?}", remaining))
121-
}
122-
123-
CheckResult::new(&name, result)
124-
}
125-
126-
/// Looks at builtins for kernel_version and compares that to the list of
127-
/// required modules.
128-
/// Returns a vec of everything from required_modules that WAS NOT found in builtins.
129-
async fn find_builtins(&self, required_modules: &[String]) -> Result<Vec<String>> {
130-
let mut modules_to_find: Vec<String> = required_modules.to_owned();
131-
132-
// read host builtins
133-
let builtins = self
134-
.host_executor
135-
.spawn_in_host_ns(async move {
136-
// Get kernel version
137-
let output = Command::new("uname").arg("-r").output()?;
138-
139-
if !output.status.success() {
140-
let error_message = String::from_utf8_lossy(&output.stderr);
141-
bail!("{}", error_message);
142-
}
143-
let kernel_version = String::from_utf8_lossy(&output.stdout).trim().to_string();
144-
let path = PathBuf::from(format!("/lib/modules/{kernel_version}/modules.builtin"));
145-
fs::read_to_string(path).map_err(|e| anyhow::anyhow!(e))
146-
})
147-
.await??;
148-
149-
for builtin in builtins.lines() {
150-
let found = modules_to_find
151-
.iter()
152-
.position(|required| builtin.contains(required));
153-
154-
if let Some(index) = found {
155-
debug!("builtin {}", modules_to_find[index]);
156-
modules_to_find.remove(index);
157-
}
158-
}
159-
160-
Ok(modules_to_find)
161-
}
162-
163-
/// Looks at loaded modules for the current host kernel and compares that to the list of
164-
/// required modules.
165-
/// Returns a vec of everything from required_modules that WAS NOT loaded.
166-
async fn find_loaded(&self, required_modules: &[String]) -> Result<Vec<String>> {
167-
let mut modules_to_find: Vec<String> = required_modules.to_owned();
168-
169-
let modules = self
170-
.host_executor
171-
.spawn_in_host_ns(async move { procfs::KernelModules::current() })
172-
.await?;
173-
174-
let modules = modules.unwrap();
175-
176-
for (name, _) in modules.0.iter() {
177-
let found = modules_to_find.iter().position(|required| required == name);
178-
179-
if let Some(index) = found {
180-
debug!("module {}", modules_to_find[index]);
181-
modules_to_find.remove(index);
182-
}
110+
return CheckResult::new(&name, Failed(format!("missing {:?}", remaining)));
183111
}
184112

185-
Ok(modules_to_find)
186-
}
187-
188-
/// Looks at not-loaded-but-loadable modules for the current host kernel and compares
189-
/// that to the list of required modules.
190-
/// Returns a vec of everything from required_modules that is available to load (exists in
191-
/// modules.dep) but is NOT currently loaded or builtin.
192-
async fn find_loadable(&self, required_modules: &[String]) -> Result<Vec<String>> {
193-
let mut modules_to_find: Vec<String> = required_modules.to_owned();
194-
let dep_file = self
195-
.host_executor
196-
.spawn_in_host_ns(async move {
197-
let output = Command::new("uname").arg("-r").output()?;
198-
if !output.status.success() {
199-
let error_message = String::from_utf8_lossy(&output.stderr);
200-
bail!("{}", error_message);
201-
}
202-
let kernel_version = String::from_utf8_lossy(&output.stdout).trim().to_string();
203-
let path = PathBuf::from(format!("/lib/modules/{kernel_version}/modules.dep"));
204-
fs::read_to_string(path).map_err(|e| anyhow::anyhow!(e))
205-
})
206-
.await??;
207-
208-
for line in dep_file.lines() {
209-
let module_path = line.split(':').next().unwrap_or("");
210-
let found = modules_to_find
211-
.iter()
212-
.position(|required| module_path.contains(required.as_str()));
213-
if let Some(index) = found {
214-
debug!("available {}", modules_to_find[index]);
215-
modules_to_find.remove(index);
216-
}
217-
}
218-
Ok(modules_to_find)
113+
CheckResult::new(&name, Passed)
219114
}
220115
}
221116

src/checkers/kernel.rs

Lines changed: 6 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,17 @@ use crate::helpers::{
22
CheckGroup, CheckGroupCategory, CheckGroupResult, CheckResult,
33
CheckResultValue::{Errored, Failed, Passed},
44
host_executor::HostNamespaceExecutor,
5+
kernel as khelper,
56
};
67

7-
use anyhow::{Result, bail};
88
use async_trait::async_trait;
99
use futures::{FutureExt, future::join_all};
10-
use log::debug;
11-
use procfs::{Current, sys::kernel};
12-
use std::{fs, path::PathBuf, process::Command};
1310

1411
const GROUP_IDENTIFIER: &str = "kernel";
1512
const NAME: &str = "Kernel Checks";
1613
// TODO (bml) assemble actual list
1714
const REQUIRED_MODULES: &[&str] = &["nf_tables", "msr"];
1815

19-
const KVER_FLOOR_PATCH: u16 = 0;
20-
const KVER_FLOOR_MINOR: u8 = 15;
21-
const KVER_FLOOR_MAJOR: u8 = 5;
22-
2316
pub struct KernelChecks {
2417
host_executor: HostNamespaceExecutor,
2518
}
@@ -32,7 +25,7 @@ impl KernelChecks {
3225
/// Run all the checkers asynchronously, then
3326
/// join and collect the results.
3427
pub async fn run_all(&self) -> CheckGroupResult {
35-
let results = join_all([self.has_modules().boxed(), self.version_is_good().boxed()]).await;
28+
let results = join_all([self.has_modules().boxed()]).await;
3629

3730
let mut group_result = Passed;
3831
for res in results.iter() {
@@ -53,118 +46,32 @@ impl KernelChecks {
5346
}
5447
}
5548

56-
async fn version_is_good(&self) -> CheckResult {
57-
let name = String::from("Host Kernel Version Is Good");
58-
let mut result = Passed;
59-
60-
// Get host kernel version
61-
let current = self
62-
.host_executor
63-
.spawn_in_host_ns(async { kernel::Version::current() })
64-
.await
65-
.expect("error spawning in host");
66-
67-
if let Err(e) = current {
68-
return CheckResult::new(&name, Errored(e.to_string()));
69-
}
70-
let current = current.unwrap();
71-
let lowest = kernel::Version::new(KVER_FLOOR_MAJOR, KVER_FLOOR_MINOR, KVER_FLOOR_PATCH);
72-
73-
if current < lowest {
74-
result = Failed(String::from("current kernel version is unsupported"));
75-
}
76-
CheckResult::new(&name, result)
77-
}
78-
7949
async fn has_modules(&self) -> CheckResult {
8050
let name = String::from("Host Has Necessary Modules");
81-
let mut result = Passed;
8251

8352
let required_modules: Vec<String> =
8453
REQUIRED_MODULES.iter().map(|s| s.to_string()).collect();
8554

8655
// Search builtin modules
87-
let remaining = match self.find_builtins(&required_modules).await {
56+
let remaining = match khelper::find_builtins(&self.host_executor, &required_modules).await {
8857
Ok(r) => r,
8958
Err(e) => {
9059
return CheckResult::new(&name, Errored(format!("getting kernel builtins {e}")));
9160
}
9261
};
9362

9463
// Search loaded modules
95-
let remaining = match self.find_loaded(&remaining).await {
64+
let remaining = match khelper::find_loaded(&self.host_executor, &remaining).await {
9665
Ok(r) => r,
9766
Err(e) => {
9867
return CheckResult::new(&name, Errored(format!("getting kernel modules {e}")));
9968
}
10069
};
10170
if !remaining.is_empty() {
102-
result = Failed(format!("missing {:?}", remaining))
103-
}
104-
105-
CheckResult::new(&name, result)
106-
}
107-
108-
/// Looks at builtins for kernel_version and compares that to the list of
109-
/// required modules.
110-
/// Returns a vec of everything from required_modules that WAS NOT found in builtins.
111-
async fn find_builtins(&self, required_modules: &[String]) -> Result<Vec<String>> {
112-
let mut modules_to_find: Vec<String> = required_modules.to_owned();
113-
114-
// read host builtins
115-
let builtins = self
116-
.host_executor
117-
.spawn_in_host_ns(async move {
118-
// Get kernel version
119-
let output = Command::new("uname").arg("-r").output()?;
120-
121-
if !output.status.success() {
122-
let error_message = String::from_utf8_lossy(&output.stderr);
123-
bail!("{}", error_message);
124-
}
125-
let kernel_version = String::from_utf8_lossy(&output.stdout).trim().to_string();
126-
let path = PathBuf::from(format!("/lib/modules/{kernel_version}/modules.builtin"));
127-
fs::read_to_string(path).map_err(|e| anyhow::anyhow!(e))
128-
})
129-
.await??;
130-
131-
for builtin in builtins.lines() {
132-
let found = modules_to_find
133-
.iter()
134-
.position(|required| builtin.contains(required));
135-
136-
if let Some(index) = found {
137-
debug!("builtin {}", modules_to_find[index]);
138-
modules_to_find.remove(index);
139-
}
140-
}
141-
142-
Ok(modules_to_find)
143-
}
144-
145-
/// Looks at loaded modules for the current host kernel and compares that to the list of
146-
/// required modules.
147-
/// Returns a vec of everything from required_modules that WAS NOT loaded.
148-
async fn find_loaded(&self, required_modules: &[String]) -> Result<Vec<String>> {
149-
let mut modules_to_find: Vec<String> = required_modules.to_owned();
150-
151-
let modules = self
152-
.host_executor
153-
.spawn_in_host_ns(async move { procfs::KernelModules::current() })
154-
.await?;
155-
156-
let modules = modules.unwrap();
157-
158-
for (name, _) in modules.0.iter() {
159-
let found = modules_to_find.iter().position(|required| required == name);
160-
161-
if let Some(index) = found {
162-
debug!("module {}", modules_to_find[index]);
163-
modules_to_find.remove(index);
164-
}
71+
return CheckResult::new(&name, Failed(format!("missing {:?}", remaining)));
16572
}
16673

167-
Ok(modules_to_find)
74+
CheckResult::new(&name, Passed)
16875
}
16976
}
17077

0 commit comments

Comments
 (0)