#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
#[derive(Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub enum LockDownState
{
Off,
Integrity,
Confidentiality,
}
impl Default for LockDownState
{
#[inline(always)]
fn default() -> Self
{
LockDownState::Off
}
}
impl LockDownState
{
pub fn current(sys_path: &SysPath) -> io::Result<Self>
{
assert_effective_user_id_is_root("read from /sys/kernel/security/lockdown");
let file_path = Self::file_path(sys_path);
let bytes = file_path.read_raw_without_line_feed()?;
for raw_bytes in bytes.split_bytes_n(3, b' ')
{
let length = raw_bytes.len();
if length >= 2
{
let last_index = length - 1;
let first = raw_bytes.get_unchecked_value_safe(0);
let last = raw_bytes.get_unchecked_value_safe(last_index);
if first == b'[' && last == b']'
{
use self::LockDownState::*;
return match &raw_bytes[1 .. last_index]
{
b"none" => Ok(Off),
b"integrity" => Ok(Integrity),
b"confidentiality" => Ok(Confidentiality),
inner @ _ => Err(io_error_other(format!("Did not expect lock down state `{:?}`", inner))),
}
}
}
}
Err(io_error_invalid_data("No active lock down state"))
}
pub fn set(self, sys_path: &SysPath) -> io::Result<()>
{
if self == LockDownState::Off
{
return Ok(())
}
let current = Self::current(sys_path)?;
if current >= self
{
return Ok(())
}
assert_effective_user_id_is_root("write to /sys/kernel/security/lockdown");
let file_path = Self::file_path(sys_path);
if file_path.exists()
{
file_path.write_value(self.to_bytes_for_writing())
}
else
{
Ok(())
}
}
#[inline(always)]
fn to_bytes_for_writing(self) -> &'static [u8]
{
use self::LockDownState::*;
match self
{
Off => unreachable_code(format_args!("We should never be writing this value")),
Integrity => b"integrity\n" as &[u8],
Confidentiality => b"confidentiality\n" as &[u8],
}
}
#[inline(always)]
fn file_path(sys_path: &SysPath) -> PathBuf
{
sys_path.kernel_security_file_path("lockdown")
}
}