Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor the selinux crate #3021

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions experiment/selinux/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test_file.txt
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,9 @@ 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<&'a SELinuxLabel>, Option<&'a 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 +244,9 @@ 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<&'a SELinuxLabel>, Option<&'a 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 +255,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<&'a SELinuxLabel>, Option<&'a 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
Loading