Skip to content

Commit 7c865b2

Browse files
authored
Merge pull request #7898 from sylvestre/selinux-err
selinux: get closer to the GNU error msgs
2 parents 7d24aa8 + fde3733 commit 7c865b2

File tree

8 files changed

+61
-25
lines changed

8 files changed

+61
-25
lines changed

src/uu/chcon/src/chcon.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ fn process_file(
608608
if result.is_ok() {
609609
if options.verbose {
610610
println!(
611-
"{}: Changing security context of: {}",
611+
"{}: changing security context of {}",
612612
uucore::util_name(),
613613
file_full_name.quote()
614614
);

src/uu/cp/src/cp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1710,7 +1710,7 @@ pub(crate) fn copy_attributes(
17101710
if let Some(context) = context {
17111711
if let Err(e) = context.set_for_path(dest, false, false) {
17121712
return Err(Error::Error(format!(
1713-
"failed to set security context for {}: {e}",
1713+
"failed to set the security context of {}: {e}",
17141714
dest.display()
17151715
)));
17161716
}

src/uu/mkfifo/src/mkfifo.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
7474
uucore::selinux::set_selinux_security_context(Path::new(&f), context)
7575
{
7676
let _ = fs::remove_file(f);
77-
return Err(USimpleError::new(
78-
1,
79-
format!("failed to set SELinux security context: {e}"),
80-
));
77+
return Err(USimpleError::new(1, e.to_string()));
8178
}
8279
}
8380
}

src/uu/mknod/src/mknod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ fn mknod(file_name: &str, config: Config) -> i32 {
9898
) {
9999
// if it fails, delete the file
100100
let _ = std::fs::remove_dir(file_name);
101-
eprintln!("failed to set SELinux security context: {}", e);
101+
eprintln!("{}: {}", uucore::util_name(), e);
102102
return 1;
103103
}
104104
}

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

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// For the full copyright and license information, please view the LICENSE
44
// file that was distributed with this source code.
55

6+
use std::error::Error;
67
use std::path::Path;
78

89
use selinux::SecurityContext;
@@ -13,16 +14,16 @@ pub enum SeLinuxError {
1314
#[error("SELinux is not enabled on this system")]
1415
SELinuxNotEnabled,
1516

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

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

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

25-
#[error("Failed to set default file creation context to '{0}': {1}")]
26+
#[error("failed to set default file creation context to '{0}': {1}")]
2627
ContextConversionFailure(String, String),
2728
}
2829

@@ -45,6 +46,22 @@ pub fn is_selinux_enabled() -> bool {
4546
selinux::kernel_support() != selinux::KernelSupport::Unsupported
4647
}
4748

49+
/// Returns a string describing the error and its causes.
50+
fn selinux_error_description(mut error: &dyn Error) -> String {
51+
let mut description = String::new();
52+
while let Some(source) = error.source() {
53+
let error_text = source.to_string();
54+
// Check if this is an OS error and trim it
55+
if let Some(idx) = error_text.find(" (os error ") {
56+
description.push_str(&error_text[..idx]);
57+
} else {
58+
description.push_str(&error_text);
59+
}
60+
error = source;
61+
}
62+
description
63+
}
64+
4865
/// Sets the SELinux security context for the given filesystem path.
4966
///
5067
/// If a specific context is provided, it attempts to set this context explicitly.
@@ -99,28 +116,40 @@ pub fn set_selinux_security_context(
99116
if let Some(ctx_str) = context {
100117
// Create a CString from the provided context string
101118
let c_context = std::ffi::CString::new(ctx_str.as_str()).map_err(|e| {
102-
SeLinuxError::ContextConversionFailure(ctx_str.to_string(), e.to_string())
119+
SeLinuxError::ContextConversionFailure(
120+
ctx_str.to_string(),
121+
selinux_error_description(&e),
122+
)
103123
})?;
104124

105125
// Convert the CString into an SELinux security context
106126
let security_context =
107127
selinux::OpaqueSecurityContext::from_c_str(&c_context).map_err(|e| {
108-
SeLinuxError::ContextConversionFailure(ctx_str.to_string(), e.to_string())
128+
SeLinuxError::ContextConversionFailure(
129+
ctx_str.to_string(),
130+
selinux_error_description(&e),
131+
)
109132
})?;
110133

111134
// Set the provided security context on the specified path
112135
SecurityContext::from_c_str(
113136
&security_context.to_c_string().map_err(|e| {
114-
SeLinuxError::ContextConversionFailure(ctx_str.to_string(), e.to_string())
137+
SeLinuxError::ContextConversionFailure(
138+
ctx_str.to_string(),
139+
selinux_error_description(&e),
140+
)
115141
})?,
116142
false,
117143
)
118144
.set_for_path(path, false, false)
119-
.map_err(|e| SeLinuxError::ContextSetFailure(ctx_str.to_string(), e.to_string()))
145+
.map_err(|e| {
146+
SeLinuxError::ContextSetFailure(ctx_str.to_string(), selinux_error_description(&e))
147+
})
120148
} else {
121149
// If no context provided, set the default SELinux context for the path
122-
SecurityContext::set_default_for_path(path)
123-
.map_err(|e| SeLinuxError::ContextSetFailure(String::new(), e.to_string()))
150+
SecurityContext::set_default_for_path(path).map_err(|e| {
151+
SeLinuxError::ContextSetFailure(String::new(), selinux_error_description(&e))
152+
})
124153
}
125154
}
126155

@@ -171,18 +200,23 @@ pub fn get_selinux_security_context(path: &Path) -> Result<String, SeLinuxError>
171200
return Err(SeLinuxError::SELinuxNotEnabled);
172201
}
173202

174-
let f = std::fs::File::open(path).map_err(|e| SeLinuxError::FileOpenFailure(e.to_string()))?;
203+
let f = std::fs::File::open(path)
204+
.map_err(|e| SeLinuxError::FileOpenFailure(selinux_error_description(&e)))?;
175205

176206
// Get the security context of the file
177207
let context = match SecurityContext::of_file(&f, false) {
178208
Ok(Some(ctx)) => ctx,
179209
Ok(None) => return Ok(String::new()), // No context found, return empty string
180-
Err(e) => return Err(SeLinuxError::ContextRetrievalFailure(e.to_string())),
210+
Err(e) => {
211+
return Err(SeLinuxError::ContextRetrievalFailure(
212+
selinux_error_description(&e),
213+
));
214+
}
181215
};
182216

183-
let context_c_string = context
184-
.to_c_string()
185-
.map_err(|e| SeLinuxError::ContextConversionFailure(String::new(), e.to_string()))?;
217+
let context_c_string = context.to_c_string().map_err(|e| {
218+
SeLinuxError::ContextConversionFailure(String::new(), selinux_error_description(&e))
219+
})?;
186220

187221
if let Some(c_str) = context_c_string {
188222
// Convert the C string to a Rust String
@@ -336,7 +370,8 @@ mod tests {
336370
println!("Context conversion failure for '{}': {}", ctx, e);
337371
}
338372
SeLinuxError::ContextSetFailure(ctx, e) => {
339-
assert!(false);
373+
assert!(!e.is_empty(), "Error message should not be empty");
374+
println!("Context conversion failure for '{}': {}", ctx, e);
340375
}
341376
SeLinuxError::FileOpenFailure(e) => {
342377
assert!(

tests/by-util/test_cp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6315,7 +6315,7 @@ fn test_cp_selinux_invalid() {
63156315
.arg(TEST_HELLO_WORLD_SOURCE)
63166316
.arg(TEST_HELLO_WORLD_DEST)
63176317
.fails()
6318-
.stderr_contains("Failed to");
6318+
.stderr_contains("failed to");
63196319
if at.file_exists(TEST_HELLO_WORLD_DEST) {
63206320
at.remove(TEST_HELLO_WORLD_DEST);
63216321
}

tests/by-util/test_mkdir.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ fn test_selinux_invalid() {
411411
.arg(at.plus_as_string(dest))
412412
.fails()
413413
.no_stdout()
414-
.stderr_contains("Failed to set default file creation context to 'testtest':");
414+
.stderr_contains("failed to set default file creation context to 'testtest':");
415415
// invalid context, so, no directory
416416
assert!(!at.dir_exists(dest));
417417
}

util/build-gnu.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,3 +365,7 @@ sed -i 's/not supported/unexpected argument/' tests/mv/mv-exchange.sh
365365
# /nix/store/xxxxxxxxxxxx...xxxx/bin/tr
366366
# We just replace the references to `/usr/bin/tr` with the result of `$(which tr)`
367367
sed -i 's/\/usr\/bin\/tr/$(which tr)/' tests/init.sh
368+
369+
# upstream doesn't having the program name in the error message
370+
# but we do. We should keep it that way.
371+
sed -i 's/echo "changing security context/echo "chcon: changing security context/' tests/chcon/chcon.sh

0 commit comments

Comments
 (0)