Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
Signed-off-by: utam0k <k0ma@utam0k.jp>
  • Loading branch information
utam0k committed Jan 19, 2025
1 parent dad3c55 commit 2df813b
Show file tree
Hide file tree
Showing 8 changed files with 479 additions and 426 deletions.
55 changes: 55 additions & 0 deletions experiment/selinux/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use std::path::PathBuf;

#[derive(Debug, thiserror::Error)]
pub enum SELinuxError {
#[error("Failed to set file label for SELinux: {0}")]
SetFileLabel(String),
#[error("Failed to lset file label for SELinux: {0}")]
LSetFileLabel(String),
#[error("Failed to get file label for SELinux: {0}")]
FileLabel(String),
#[error("Failed to get lfile label for SELinux: {0}")]
LFileLabel(String),
#[error("Failed to call is_proc_handle for SELinux: {0}")]
IsProcHandle(String),
#[error("Failed to call read_con_fd for SELinux: {0}")]
ReadConFd(String),
#[error("Failed to call read_con for SELinux: {0}")]
ReadCon(String),
#[error("Failed to call write_con for SELinux: {0}")]
WriteCon(String),
#[error("Failed to find the index for a given class: {0}")]
ClassIndex(String),
#[error("Failed to call peer_label for SELinux: {0}")]
PeerLabel(String),
#[error("Failed to call open_context_file for SELinux: {0}")]
OpenContextFile(String),
#[error("Failed to set enforce mode of SELinux: {0}")]
SetEnforceMode(String),
#[error("Failed to read config file of SELinux: {0}")]
GetConfigKey(String),
#[error("Invalid format for SELinux label: {0}")]
InvalidSELinuxLabel(String),
#[error("Failed to load SELinux labels: {0}")]
LoadLabels(String),
#[error("Failed to load SELinux config: {0}")]
LoadConfig(String),
#[error("SELinux setting error: {0}")]
SELinuxSettingError(#[from] SELinuxSettingError),
}

#[derive(Debug, thiserror::Error)]
pub enum SELinuxSettingError {
#[error("SELinux is not installed")]
NotInstalled,
#[error("Enforce file in SELinux not found: {0}")]
EnforceFileNotFound(PathBuf),
#[error("Invalid SELinux mode: {0}")]
InvalidMode(String),
#[error("Failed to set enforce mode of SELinux: {0}")]
SetEnforceMode(String),
#[error("Failed to load SELinux config: {0}")]
LoadConfig(String),
#[error("Failed to read config file of SELinux: {0}")]
GetConfigKey(String),
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use crate::selinux::*;
use crate::tools::PathXattr;
use crate::tools::*;
use crate::{selinux::*, SELinuxError};
use nix::sys::socket::getsockopt;
use std::convert::TryFrom;
use std::io::{BufRead, BufReader};
use std::os::fd::AsFd;
use std::path::Path;
use std::sync::atomic::Ordering;

const XATTR_NAME_SELINUX: &str = "security.selinux";
const KEY_LABEL_PATH: &str = "/proc/self/attr/keycreate";
Expand Down Expand Up @@ -60,7 +58,7 @@ impl TryFrom<String> for SELinuxLabel {
}

// This impl is for methods related to labels in SELinux struct.
impl SELinux {
impl<'a> SELinux<'a> {
// set_file_label sets the SELinux label for this path, following symlinks, or returns an error.
pub fn set_file_label<P: AsRef<Path> + PathXattr>(
fpath: P,
Expand Down Expand Up @@ -235,7 +233,7 @@ impl SELinux {

// kvm_container_labels returns the default processLabel and mountLabel to be used
// for kvm containers by the calling process.
pub fn kvm_container_labels(&mut self) -> (Option<SELinuxLabel>, Option<SELinuxLabel>) {
pub fn kvm_container_labels(&'a mut self) -> (Option<&SELinuxLabel>, Option<&SELinuxLabel>) {
let process_label =
Self::label(self, "kvm_process").or_else(|| Self::label(self, "process"));
(process_label, Self::label(self, "file"))
Expand All @@ -244,7 +242,7 @@ impl SELinux {

// init_container_labels returns the default processLabel and file labels to be
// used for containers running an init system like systemd by the calling process.
pub fn init_container_labels(&mut self) -> (Option<SELinuxLabel>, Option<SELinuxLabel>) {
pub fn init_container_labels(&'a mut self) -> (Option<&SELinuxLabel>, Option<&SELinuxLabel>) {
let process_label =
Self::label(self, "init_process").or_else(|| Self::label(self, "process"));
(process_label, Self::label(self, "file"))
Expand All @@ -253,61 +251,28 @@ impl SELinux {

// container_labels returns an allocated processLabel and fileLabel to be used for
// container labeling by the calling process.
pub fn container_labels(&mut self) -> (Option<SELinuxLabel>, Option<SELinuxLabel>) {
if !Self::get_enabled(self) {
return (None, None);
}
let process_label = Self::label(self, "process");
let file_label = Self::label(self, "file");
pub fn container_labels(&'a mut self) -> (Option<&SELinuxLabel>, Option<&SELinuxLabel>) {
// let process_label = Self::label(self, "process");
// let file_label = Self::label(self, "file");
let process_label = self.labels.get("process");
let file_label = self.labels.get("file");

if process_label.is_none() || file_label.is_none() {
return (process_label, file_label);
}

let mut read_only_file_label = Self::label(self, "ro_file");
if read_only_file_label.is_none() {
read_only_file_label = file_label.clone();
}
self.read_only_file_label = read_only_file_label;
self.read_only_file_label = match self.labels.get("ro_file") {
None => file_label,
Some(ro_file_label) => Some(ro_file_label),
};

(process_label, file_label)
// TODO: use addMcs
}

// This function returns the value of given key on selinux context
fn label(&mut self, key: &str) -> Option<SELinuxLabel> {
if !self.load_labels_init_done.load(Ordering::SeqCst) {
Self::load_labels(self);
self.load_labels_init_done.store(true, Ordering::SeqCst);
}
self.labels.get(key).cloned()
}

// This function loads context file and reads labels and stores it.
fn load_labels(&mut self) {
// The context file should have pairs of key and value like below.
// ----------
// process = "system_u:system_r:container_t:s0"
// file = "system_u:object_r:container_file_t:s0"
// ----------
if let Ok(file) = Self::open_context_file(self) {
let reader = BufReader::new(file);
for line in reader.lines().map_while(Result::ok) {
let line = line.trim();
if line.is_empty() || line.starts_with(';') || line.starts_with('#') {
continue;
}
let fields: Vec<&str> = line.splitn(2, '=').collect();
if fields.len() != 2 {
continue;
}
let key = fields[0].trim().to_string();
let value = fields[1].trim_matches('"').trim().to_string();
if let Ok(value_label) = SELinuxLabel::try_from(value) {
self.labels.insert(key, value_label);
}
}
}
fn label(&'a self, key: &str) -> Option<&'a SELinuxLabel> {
self.labels.get(key)
}

// format_mount_label returns a string to be used by the mount command.
Expand Down
7 changes: 6 additions & 1 deletion experiment/selinux/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
pub mod error;
pub mod label;
pub mod mode;
pub mod selinux;
pub mod selinux_label;
pub mod setting;
pub mod tools;

pub use error::*;
pub use mode::SELinuxMode;
pub use selinux::SELinux;
31 changes: 12 additions & 19 deletions experiment/selinux/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,24 @@
use selinux::selinux::*;
use selinux::selinux_label::*;
use std::fs::File;
use std::path::Path;

use selinux::{label::*, selinux::*, setting::SELinuxSetting, SELinuxError, SELinuxMode};

fn main() -> Result<(), SELinuxError> {
let mut selinux_instance: SELinux = SELinux::new();
let setting = SELinuxSetting::try_default()?;
println!("current enforce mode is: {}", setting.enforce_mode()?);

if selinux_instance.get_enabled() {
println!("selinux is enabled");
let selinux: SELinux = SELinux::try_default(&setting)?;
if selinux.get_enabled() {
println!("SELinux is enabled");
} else {
println!("selinux is not enabled");

match selinux_instance.set_enforce_mode(SELinuxMode::PERMISSIVE) {
println!("SELinux is not enabled");
match setting.set_enforce_mode(SELinuxMode::PERMISSIVE) {
Ok(_) => println!("set selinux mode as permissive"),
Err(e) => println!("{}", e),
}
Err(e) => return Err(SELinuxError::from(e)),
};
}
println!(
"default enforce mode is: {}",
selinux_instance.default_enforce_mode()
);
println!(
"current enforce mode is: {}",
selinux_instance.enforce_mode()
);

match selinux_instance.current_label() {
match selinux.current_label() {
Ok(l) => println!("SELinux label of current process is: {}", l),
Err(e) => println!("{}", e),
}
Expand Down
53 changes: 53 additions & 0 deletions experiment/selinux/src/mode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use std::fmt;

#[derive(Debug, Copy, Clone)]
pub enum SELinuxMode {
// ENFORCING constant to indicate SELinux is in enforcing mode
ENFORCING = 1,
// PERMISSIVE constant to indicate SELinux is in permissive mode
PERMISSIVE = 0,
// DISABLED constant to indicate SELinux is disabled
DISABLED = -1,
}

impl From<i32> for SELinuxMode {
fn from(mode: i32) -> Self {
match mode {
1 => SELinuxMode::ENFORCING,
0 => SELinuxMode::PERMISSIVE,
-1 => SELinuxMode::DISABLED,
_ => SELinuxMode::DISABLED,
}
}
}

impl From<&str> for SELinuxMode {
fn from(mode: &str) -> Self {
match mode {
"enforcing" => SELinuxMode::ENFORCING,
"permissive" => SELinuxMode::PERMISSIVE,
_ => SELinuxMode::DISABLED,
}
}
}

impl fmt::Display for SELinuxMode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = match self {
SELinuxMode::ENFORCING => "enforcing",
SELinuxMode::PERMISSIVE => "permissive",
SELinuxMode::DISABLED => "disabled",
};
write!(f, "{}", s)
}
}

impl SELinuxMode {
pub fn as_bytes(&self) -> &[u8] {
match self {
SELinuxMode::ENFORCING => b"1",
SELinuxMode::PERMISSIVE => b"0",
SELinuxMode::DISABLED => b"-1",
}
}
}
Loading

0 comments on commit 2df813b

Please sign in to comment.