Skip to content

Commit acf4129

Browse files
committed
set_selinux_security_context: also display the error from the crate
+ fix comments from review
1 parent e23f45f commit acf4129

File tree

3 files changed

+82
-58
lines changed

3 files changed

+82
-58
lines changed

src/uu/mkdir/src/mkdir.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -298,10 +298,7 @@ fn create_dir(path: &Path, is_parent: bool, config: &Config) -> UResult<()> {
298298
if let Err(e) = uucore::selinux::set_selinux_security_context(path, config.context)
299299
{
300300
let _ = std::fs::remove_dir(path);
301-
return Err(USimpleError::new(
302-
1,
303-
format!("failed to set SELinux security context: {}", e),
304-
));
301+
return Err(USimpleError::new(1, e.to_string()));
305302
}
306303
}
307304

src/uucore/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ proc-info = ["tty", "walkdir"]
114114
quoting-style = []
115115
ranges = []
116116
ringbuffer = []
117-
selinux = ["dep:selinux"]
117+
selinux = ["dep:selinux", "thiserror"]
118118
signals = []
119119
sum = [
120120
"digest",

src/uucore/src/lib/features/selinux.rs

Lines changed: 80 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,27 @@ pub enum SeLinuxError {
1313
#[error("SELinux is not enabled on this system")]
1414
SELinuxNotEnabled,
1515

16-
#[error("Failed to open the file")]
17-
FileOpenFailure,
16+
#[error("Failed to open the file: {0}")]
17+
FileOpenFailure(String),
1818

19-
#[error("Failed to retrieve the security context")]
20-
ContextRetrievalFailure,
19+
#[error("Failed to retrieve the security context: {0}")]
20+
ContextRetrievalFailure(String),
2121

22-
#[error("failed to set default file creation context to {0}")]
23-
ContextSetFailure(String),
22+
#[error("failed to set default file creation context2 to '{0}': {1}")]
23+
ContextSetFailure(String, String),
2424

25-
#[error("Invalid context string or conversion failure")]
26-
ContextConversionFailure,
25+
#[error("failed to set default file creation context3 to '{0}': {1}")]
26+
ContextConversionFailure(String, String),
2727
}
2828

2929
impl From<SeLinuxError> for i32 {
3030
fn from(error: SeLinuxError) -> i32 {
3131
match error {
3232
SeLinuxError::SELinuxNotEnabled => 1,
33-
SeLinuxError::FileOpenFailure => 2,
34-
SeLinuxError::ContextRetrievalFailure => 3,
35-
SeLinuxError::ContextSetFailure(_) => 4,
36-
SeLinuxError::ContextConversionFailure => 5,
33+
SeLinuxError::FileOpenFailure(_) => 2,
34+
SeLinuxError::ContextRetrievalFailure(_) => 3,
35+
SeLinuxError::ContextSetFailure(_, _) => 4,
36+
SeLinuxError::ContextConversionFailure(_, _) => 5,
3737
}
3838
}
3939
}
@@ -98,26 +98,29 @@ pub fn set_selinux_security_context(
9898

9999
if let Some(ctx_str) = context {
100100
// Create a CString from the provided context string
101-
let c_context = std::ffi::CString::new(ctx_str.as_str())
102-
.map_err(|_| SeLinuxError::ContextConversionFailure)?;
101+
let c_context = std::ffi::CString::new(ctx_str.as_str()).map_err(|e| {
102+
SeLinuxError::ContextConversionFailure(ctx_str.to_string(), e.to_string())
103+
})?;
103104

104105
// Convert the CString into an SELinux security context
105-
let security_context = selinux::OpaqueSecurityContext::from_c_str(&c_context)
106-
.map_err(|_| SeLinuxError::ContextConversionFailure)?;
106+
let security_context =
107+
selinux::OpaqueSecurityContext::from_c_str(&c_context).map_err(|e| {
108+
SeLinuxError::ContextConversionFailure(ctx_str.to_string(), e.to_string())
109+
})?;
107110

108111
// Set the provided security context on the specified path
109112
SecurityContext::from_c_str(
110-
&security_context
111-
.to_c_string()
112-
.map_err(|_| SeLinuxError::ContextConversionFailure)?,
113+
&security_context.to_c_string().map_err(|e| {
114+
SeLinuxError::ContextConversionFailure(ctx_str.to_string(), e.to_string())
115+
})?,
113116
false,
114117
)
115118
.set_for_path(path, false, false)
116-
.map_err(|_| SeLinuxError::ContextSetFailure(ctx_str.to_string()))
119+
.map_err(|e| SeLinuxError::ContextSetFailure(ctx_str.to_string(), e.to_string()))
117120
} else {
118121
// If no context provided, set the default SELinux context for the path
119122
SecurityContext::set_default_for_path(path)
120-
.map_err(|_| SeLinuxError::ContextSetFailure("".to_string()))
123+
.map_err(|e| SeLinuxError::ContextSetFailure(String::new(), e.to_string()))
121124
}
122125
}
123126

@@ -156,28 +159,29 @@ pub fn set_selinux_security_context(
156159
/// }
157160
/// },
158161
/// Err(SeLinuxError::SELinuxNotEnabled) => println!("SELinux is not enabled on this system"),
159-
/// Err(SeLinuxError::FileOpenFailure) => println!("Failed to open the file"),
160-
/// Err(SeLinuxError::ContextRetrievalFailure) => println!("Failed to retrieve the security context"),
161-
/// Err(SeLinuxError::ContextConversionFailure) => println!("Failed to convert the security context to a string"),
162+
/// Err(SeLinuxError::FileOpenFailure(e)) => println!("Failed to open the file: {}", e),
163+
/// Err(SeLinuxError::ContextRetrievalFailure(e)) => println!("Failed to retrieve the security context: {}", e),
164+
/// Err(SeLinuxError::ContextConversionFailure(ctx, e)) => println!("Failed to convert context '{}': {}", ctx, e),
165+
/// Err(SeLinuxError::ContextSetFailure(ctx, e)) => println!("Failed to set context '{}': {}", ctx, e),
162166
/// }
163167
/// ```
164168
pub fn get_selinux_security_context(path: &Path) -> Result<String, SeLinuxError> {
165169
if !is_selinux_enabled() {
166170
return Err(SeLinuxError::SELinuxNotEnabled);
167171
}
168172

169-
let f = std::fs::File::open(path).map_err(|_| SeLinuxError::FileOpenFailure)?;
173+
let f = std::fs::File::open(path).map_err(|e| SeLinuxError::FileOpenFailure(e.to_string()))?;
170174

171175
// Get the security context of the file
172176
let context = match SecurityContext::of_file(&f, false) {
173177
Ok(Some(ctx)) => ctx,
174178
Ok(None) => return Ok(String::new()), // No context found, return empty string
175-
Err(_) => return Err(SeLinuxError::ContextRetrievalFailure),
179+
Err(e) => return Err(SeLinuxError::ContextRetrievalFailure(e.to_string())),
176180
};
177181

178182
let context_c_string = context
179183
.to_c_string()
180-
.map_err(|_| SeLinuxError::ContextConversionFailure)?;
184+
.map_err(|e| SeLinuxError::ContextConversionFailure(String::new(), e.to_string()))?;
181185

182186
if let Some(c_str) = context_c_string {
183187
// Convert the C string to a Rust String
@@ -204,19 +208,16 @@ mod tests {
204208
assert!(true, "Successfully set SELinux context");
205209
} else {
206210
let err = result.unwrap_err();
207-
let valid_errors = [
208-
"SELinux is not enabled on this system",
209-
&format!(
210-
"Failed to set default context: selinux_lsetfilecon_default() failed on path '{}'",
211-
path.display()
212-
),
213-
];
214-
215-
assert!(
216-
valid_errors.contains(&err.as_str()),
217-
"Unexpected error message: {}",
218-
err
219-
);
211+
match err {
212+
SeLinuxError::SELinuxNotEnabled => {
213+
assert!(true, "SELinux is not enabled, which is a valid error case");
214+
}
215+
_ => {
216+
println!("Error setting context: {}", err);
217+
// Only assert for cases where we expect specific error messages
218+
// other errors can happen depending on the SELinux configuration
219+
}
220+
}
220221
}
221222
}
222223

@@ -230,10 +231,18 @@ mod tests {
230231
let result = set_selinux_security_context(path, Some(&invalid_context));
231232

232233
assert!(result.is_err());
233-
assert_eq!(
234-
result.unwrap_err(),
235-
"Invalid context string (contains null bytes)"
236-
);
234+
if let Err(err) = result {
235+
match err {
236+
SeLinuxError::ContextConversionFailure(ctx, msg) => {
237+
assert_eq!(ctx, "invalid\0context");
238+
assert!(
239+
msg.contains("nul byte"),
240+
"Error message should mention nul byte"
241+
);
242+
}
243+
_ => panic!("Expected ContextConversionFailure error but got: {}", err),
244+
}
245+
}
237246
}
238247

239248
#[test]
@@ -267,12 +276,23 @@ mod tests {
267276
// Valid error types
268277
match err {
269278
SeLinuxError::SELinuxNotEnabled => assert!(true, "SELinux not supported"),
270-
SeLinuxError::ContextRetrievalFailure => assert!(true, "Context retrieval failure"),
271-
SeLinuxError::ContextConversionFailure => {
272-
assert!(true, "Context conversion failure")
279+
SeLinuxError::ContextRetrievalFailure(e) => {
280+
println!("Context retrieval failure: {}", e);
281+
assert!(true, "Context retrieval failure");
282+
}
283+
SeLinuxError::ContextConversionFailure(ctx, e) => {
284+
println!("Context conversion failure for '{}': {}", ctx, e);
285+
assert!(true, "Context conversion failure");
273286
}
274-
SeLinuxError::FileOpenFailure => {
275-
panic!("File open failure occurred despite file being created")
287+
SeLinuxError::ContextSetFailure(ctx, e) => {
288+
println!("Context set failure for '{}': {}", ctx, e);
289+
assert!(true, "Context set failure");
290+
}
291+
SeLinuxError::FileOpenFailure(e) => {
292+
panic!(
293+
"File open failure occurred despite file being created: {}",
294+
e
295+
);
276296
}
277297
}
278298
}
@@ -285,9 +305,16 @@ mod tests {
285305
let result = get_selinux_security_context(path);
286306

287307
assert!(result.is_err());
288-
assert!(
289-
matches!(result.unwrap_err(), SeLinuxError::FileOpenFailure),
290-
"Expected file open error for nonexistent file"
291-
);
308+
if let Err(err) = result {
309+
match err {
310+
SeLinuxError::FileOpenFailure(e) => {
311+
assert!(
312+
e.contains("No such file"),
313+
"Error should mention file not found"
314+
);
315+
}
316+
_ => panic!("Expected FileOpenFailure error but got: {}", err),
317+
}
318+
}
292319
}
293320
}

0 commit comments

Comments
 (0)