Skip to content

Commit 74e225c

Browse files
committed
uucore: move the selinux function
1 parent b7bb4c8 commit 74e225c

File tree

8 files changed

+116
-55
lines changed

8 files changed

+116
-55
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ feat_selinux = [
5252
"cp/selinux",
5353
"id/selinux",
5454
"ls/selinux",
55+
"mkdir/selinux",
5556
"selinux",
5657
"feat_require_selinux",
5758
]

src/uu/mkdir/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ path = "src/mkdir.rs"
1818

1919
[dependencies]
2020
clap = { workspace = true }
21-
selinux = { workspace = true }
2221
uucore = { workspace = true, features = ["fs", "mode", "fsxattr"] }
2322

23+
[features]
24+
selinux = ["uucore/selinux"]
2425

2526
[[bin]]
2627
name = "mkdir"

src/uu/mkdir/src/mkdir.rs

Lines changed: 2 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use clap::builder::ValueParser;
99
use clap::parser::ValuesRef;
1010
use clap::{Arg, ArgAction, ArgMatches, Command};
11-
use selinux::SecurityContext;
1211
use std::ffi::OsString;
1312
use std::path::{Path, PathBuf};
1413
#[cfg(not(windows))]
@@ -75,58 +74,6 @@ fn strip_minus_from_mode(args: &mut Vec<String>) -> bool {
7574
mode::strip_minus_from_mode(args)
7675
}
7776

78-
// Add a new function to handle setting the SELinux security context
79-
#[cfg(target_os = "linux")]
80-
fn set_selinux_security_context(path: &Path, context: Option<&String>) -> Result<(), String> {
81-
// Get SELinux kernel support
82-
let support = selinux::kernel_support();
83-
84-
// If SELinux is not enabled, return early
85-
if support == selinux::KernelSupport::Unsupported {
86-
return Err("SELinux is not enabled on this system".to_string());
87-
}
88-
89-
// If a specific context was provided, use it
90-
if let Some(ctx_str) = context {
91-
// Use the provided context
92-
match SecurityContext::of_path(path, false, false) {
93-
Ok(_) => {
94-
// Create a CString from the context string
95-
let c_context = std::ffi::CString::new(ctx_str.as_str())
96-
.map_err(|_| "Invalid context string (contains null bytes)".to_string())?;
97-
98-
// Create a security context from the string
99-
let security_context = match selinux::OpaqueSecurityContext::from_c_str(&c_context)
100-
{
101-
Ok(ctx) => ctx,
102-
Err(e) => return Err(format!("Failed to create security context: {}", e)),
103-
};
104-
105-
// Convert back to string for the API
106-
let context_str = match security_context.to_c_string() {
107-
Ok(ctx) => ctx,
108-
Err(e) => return Err(format!("Failed to convert context to string: {}", e)),
109-
};
110-
111-
// Set the context on the file
112-
let sc = SecurityContext::from_c_str(&context_str, false);
113-
114-
match sc.set_for_path(path, false, false) {
115-
Ok(_) => Ok(()),
116-
Err(e) => Err(format!("Failed to set context: {}", e)),
117-
}
118-
}
119-
Err(e) => Err(format!("Failed to get current context: {}", e)),
120-
}
121-
} else {
122-
// If no context was specified, use the default context for the path
123-
match SecurityContext::set_default_for_path(path) {
124-
Ok(_) => Ok(()),
125-
Err(e) => Err(format!("Failed to set default context: {}", e)),
126-
}
127-
}
128-
}
129-
13077
#[uucore::main]
13178
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
13279
let mut args = args.collect_lossy();
@@ -373,7 +320,8 @@ fn create_dir(
373320
// Apply SELinux context if requested
374321
#[cfg(target_os = "linux")]
375322
if set_selinux_context {
376-
if let Err(e) = set_selinux_security_context(path, context) {
323+
if let Err(e) = uucore::selinux_support::set_selinux_security_context(path, context)
324+
{
377325
return Err(USimpleError::new(
378326
1,
379327
format!("failed to set SELinux security context: {}", e),

src/uucore/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ crc32fast = { workspace = true, optional = true }
6060
regex = { workspace = true, optional = true }
6161
bigdecimal = { workspace = true, optional = true }
6262
num-traits = { workspace = true, optional = true }
63+
selinux = { workspace = true, optional = true }
6364

6465
[target.'cfg(unix)'.dependencies]
6566
walkdir = { workspace = true, optional = true }
@@ -106,6 +107,7 @@ proc-info = ["tty", "walkdir"]
106107
quoting-style = []
107108
ranges = []
108109
ringbuffer = []
110+
selinux = ["dep:selinux"]
109111
signals = []
110112
sum = [
111113
"digest",

src/uucore/src/lib/features.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ pub mod tty;
6060

6161
#[cfg(all(unix, feature = "fsxattr"))]
6262
pub mod fsxattr;
63+
#[cfg(all(target_os = "linux", feature = "selinux"))]
64+
pub mod selinux;
6365
#[cfg(all(unix, not(target_os = "fuchsia"), feature = "signals"))]
6466
pub mod signals;
6567
#[cfg(all(
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// This file is part of the uutils uucore package.
2+
//
3+
// For the full copyright and license information, please view the LICENSE
4+
// file that was distributed with this source code.
5+
6+
use std::path::Path;
7+
8+
use selinux::SecurityContext;
9+
10+
/// Sets the SELinux security context for the given filesystem path.
11+
///
12+
/// If a specific context is provided, it attempts to set this context explicitly.
13+
/// Otherwise, it applies the default SELinux context for the provided path.
14+
///
15+
/// # Arguments
16+
///
17+
/// * `path` - Filesystem path on which to set the SELinux context.
18+
/// * `context` - Optional SELinux context string to explicitly set.
19+
///
20+
/// # Errors
21+
///
22+
/// Returns an error if:
23+
/// - SELinux is not enabled on the system.
24+
/// - The provided context is invalid or cannot be applied.
25+
/// - The default SELinux context cannot be set.
26+
pub fn set_selinux_security_context(path: &Path, context: Option<&String>) -> Result<(), String> {
27+
// Check if SELinux is enabled on the system
28+
if selinux::kernel_support() == selinux::KernelSupport::Unsupported {
29+
return Err("SELinux is not enabled on this system".into());
30+
}
31+
32+
if let Some(ctx_str) = context {
33+
// Create a CString from the provided context string
34+
let c_context = std::ffi::CString::new(ctx_str.as_str())
35+
.map_err(|_| "Invalid context string (contains null bytes)".to_string())?;
36+
37+
// Convert the CString into an SELinux security context
38+
let security_context = selinux::OpaqueSecurityContext::from_c_str(&c_context)
39+
.map_err(|e| format!("Failed to create security context: {}", e))?;
40+
41+
// Set the provided security context on the specified path
42+
SecurityContext::from_c_str(
43+
&security_context.to_c_string().map_err(|e| e.to_string())?,
44+
false,
45+
)
46+
.set_for_path(path, false, false)
47+
.map_err(|e| format!("Failed to set context: {}", e))
48+
} else {
49+
// If no context provided, set the default SELinux context for the path
50+
SecurityContext::set_default_for_path(path)
51+
.map_err(|e| format!("Failed to set default context: {}", e))
52+
}
53+
}
54+
55+
#[cfg(test)]
56+
mod tests {
57+
use super::*;
58+
use tempfile::NamedTempFile;
59+
60+
#[test]
61+
fn test_selinux_context_setting() {
62+
let tmpfile = NamedTempFile::new().expect("Failed to create tempfile");
63+
let path = tmpfile.path();
64+
65+
let result = set_selinux_security_context(path, None);
66+
67+
if result.is_ok() {
68+
// SELinux enabled and successfully set default context
69+
assert!(true, "Successfully set SELinux context");
70+
} else {
71+
let err = result.unwrap_err();
72+
let valid_errors = [
73+
"SELinux is not enabled on this system",
74+
&format!(
75+
"Failed to set default context: selinux_lsetfilecon_default() failed on path '{}'",
76+
path.display()
77+
),
78+
];
79+
80+
assert!(
81+
valid_errors.contains(&err.as_str()),
82+
"Unexpected error message: {}",
83+
err
84+
);
85+
}
86+
}
87+
88+
#[test]
89+
fn test_invalid_context_string_error() {
90+
let tmpfile = NamedTempFile::new().expect("Failed to create tempfile");
91+
let path = tmpfile.path();
92+
93+
// Pass a context string containing a null byte to trigger CString::new error
94+
let invalid_context = String::from("invalid\0context");
95+
let result = set_selinux_security_context(path, Some(&invalid_context));
96+
97+
assert!(result.is_err());
98+
assert_eq!(
99+
result.unwrap_err(),
100+
"Invalid context string (contains null bytes)"
101+
);
102+
}
103+
}

src/uucore/src/lib/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ pub use crate::features::fsext;
106106
#[cfg(all(unix, feature = "fsxattr"))]
107107
pub use crate::features::fsxattr;
108108

109+
#[cfg(all(target_os = "linux", feature = "selinux"))]
110+
pub use crate::features::selinux;
111+
109112
//## core functions
110113

111114
#[cfg(unix)]

0 commit comments

Comments
 (0)