/
mod.rs
183 lines (151 loc) · 5.6 KB
/
mod.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Copyright (c) 2022 Intel Corporation
// Copyright (c) 2022 IBM Corp.
//
// SPDX-License-Identifier: Apache-2.0
//
#[cfg(target_arch = "s390x")]
pub use arch_specific::*;
mod arch_specific {
use crate::check;
use crate::types::*;
use anyhow::{anyhow, Result};
use nix::unistd::Uid;
use std::collections::HashMap;
use std::io::BufRead;
use std::io::BufReader;
const CPUINFO_DELIMITER: &str = "processor ";
const CPUINFO_FEATURES_TAG: &str = "features";
const CPU_FEATURES_REQ: &[&str] = &["sie"];
#[allow(dead_code)]
pub const ARCH_CPU_VENDOR_FIELD: &str = check::GENERIC_CPU_VENDOR_FIELD;
#[allow(dead_code)]
pub const ARCH_CPU_MODEL_FIELD: &str = "machine";
// check cpu
fn check_cpu() -> Result<()> {
println!("INFO: check CPU: s390x");
let cpu_info = check::get_single_cpu_info(check::PROC_CPUINFO, CPUINFO_DELIMITER)?;
let cpu_features = check::get_cpu_flags(&cpu_info, CPUINFO_FEATURES_TAG).map_err(|e| {
anyhow!(
"Error parsing CPU features, file {:?}, {:?}",
check::PROC_CPUINFO,
e
)
})?;
let missing_cpu_features = check::check_cpu_flags(&cpu_features, CPU_FEATURES_REQ)?;
if !missing_cpu_features.is_empty() {
eprintln!("WARNING: Missing CPU flags {:?}", missing_cpu_features);
}
Ok(())
}
pub fn check(_args: &str) -> Result<()> {
println!("INFO: check: s390x");
let _cpu_result = check_cpu();
// TODO: add additional checks, e.g, kernel modules as in go runtime
// TODO: collect outcome of tests to determine if checks pass or not
Ok(())
}
// List of check functions
static CHECK_LIST: &[CheckItem] = &[CheckItem {
name: CheckType::Cpu,
descr: "This parameter performs the cpu check",
fp: check,
perm: PermissionType::NonPrivileged,
}];
pub fn get_checks() -> Option<&'static [CheckItem<'static>]> {
Some(CHECK_LIST)
}
#[allow(dead_code)]
fn retrieve_cpu_facilities() -> Result<HashMap<i32, bool>> {
let f = std::fs::File::open(check::PROC_CPUINFO)?;
let mut reader = BufReader::new(f);
let mut contents = String::new();
let facilities_field = "facilities";
let mut facilities = HashMap::new();
while reader.read_line(&mut contents)? > 0 {
let fields: Vec<&str> = contents.split_whitespace().collect();
if fields.len() < 2 {
contents.clear();
continue;
}
if !fields[0].starts_with(facilities_field) {
contents.clear();
continue;
}
let mut start = 1;
if fields[1] == ":" {
start = 2;
}
for field in fields.iter().skip(start) {
let bit = field.parse::<i32>()?;
facilities.insert(bit, true);
}
return Ok(facilities);
}
Ok(facilities)
}
#[allow(dead_code)]
pub fn check_cmd_line(
kernel_cmdline_path: &str,
search_param: &str,
search_values: &[&str],
) -> Result<bool> {
let f = std::fs::File::open(kernel_cmdline_path)?;
let reader = BufReader::new(f);
let check_fn = if search_values.is_empty() {
|param: &str, search_param: &str, _search_values: &[&str]| {
return param.eq_ignore_ascii_case(search_param);
}
} else {
|param: &str, search_param: &str, search_values: &[&str]| {
let split: Vec<&str> = param.splitn(2, "=").collect();
if split.len() < 2 || split[0] != search_param {
return false;
}
for value in search_values {
if value.eq_ignore_ascii_case(split[1]) {
return true;
}
}
false
}
};
for line in reader.lines() {
for field in line?.split_whitespace() {
if check_fn(field, search_param, search_values) {
return Ok(true);
}
}
}
Ok(false)
}
#[allow(dead_code)]
// Guest protection is not supported on ARM64.
pub fn available_guest_protection() -> Result<check::GuestProtection, check::ProtectionError> {
if !Uid::effective().is_root() {
return Err(check::ProtectionError::NoPerms)?;
}
let facilities = retrieve_cpu_facilities().map_err(|err| {
check::ProtectionError::CheckFailed(format!(
"Error retrieving cpu facilities file : {}",
err.to_string()
))
})?;
// Secure Execution
// https://www.kernel.org/doc/html/latest/virt/kvm/s390-pv.html
let se_cpu_facility_bit: i32 = 158;
if !facilities.contains_key(&se_cpu_facility_bit) {
return Ok(check::GuestProtection::NoProtection);
}
let cmd_line_values = vec!["1", "on", "y", "yes"];
let se_cmdline_param = "prot_virt";
let se_cmdline_present =
check_cmd_line("/proc/cmdline", se_cmdline_param, &cmd_line_values)
.map_err(|err| check::ProtectionError::CheckFailed(err.to_string()))?;
if !se_cmdline_present {
return Err(check::ProtectionError::InvalidValue(String::from(
"Protected Virtualization is not enabled on kernel command line!",
)));
}
Ok(check::GuestProtection::Se)
}
}