diff --git a/Cargo.toml b/Cargo.toml index 8f2bede1353..e76811762c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,7 +82,8 @@ feat_acl = ["cp/feat_acl"] # "feat_selinux" == enable support for SELinux Security Context (by using `--features feat_selinux`) # NOTE: # * The selinux(-sys) crate requires `libselinux` headers and shared library to be accessible in the C toolchain at compile time. -# * Running a uutils compiled with `feat_selinux` requires an SELinux enabled Kernel at run time. +# * A uutils compiled with `feat_selinux` runs fine on a kernel without SELinux enabled; SELinux-specific +# behavior is just skipped at runtime (see `uucore::selinux::is_selinux_enabled`). feat_selinux = [ "cp/selinux", "feat_require_selinux", @@ -97,7 +98,7 @@ feat_selinux = [ ] # "feat_smack" == enable support for SMACK Security Context (by using `--features feat_smack`) # NOTE: -# * Running a uutils compiled with `feat_smack` requires a SMACK enabled Kernel at run time. +# * A uutils compiled with `feat_smack` runs fine on a kernel without SMACK enabled; SMACK-specific behavior is just skipped at runtime (see `uucore::smack::is_smack_enabled`). feat_smack = [ "id/smack", "ls/smack", diff --git a/src/uu/mkdir/locales/en-US.ftl b/src/uu/mkdir/locales/en-US.ftl index 44fd5f5adf3..4ac212ff670 100644 --- a/src/uu/mkdir/locales/en-US.ftl +++ b/src/uu/mkdir/locales/en-US.ftl @@ -15,5 +15,8 @@ mkdir-error-file-exists = { $path }: File exists mkdir-error-failed-to-create-tree = failed to create whole tree mkdir-error-cannot-set-permissions = cannot set permissions { $path } +# Warning messages +mkdir-warning-context-not-selinux = ignoring --context; it requires an SELinux/SMACK-enabled kernel + # Verbose output mkdir-verbose-created-directory = { $util_name }: created directory { $path } diff --git a/src/uu/mkdir/locales/fr-FR.ftl b/src/uu/mkdir/locales/fr-FR.ftl index d92bed96520..f8b557cc797 100644 --- a/src/uu/mkdir/locales/fr-FR.ftl +++ b/src/uu/mkdir/locales/fr-FR.ftl @@ -15,5 +15,8 @@ mkdir-error-file-exists = { $path } : Le fichier existe mkdir-error-failed-to-create-tree = échec de la création de l'arborescence complète mkdir-error-cannot-set-permissions = impossible de définir les permissions { $path } +# Messages d'avertissement +mkdir-warning-context-not-selinux = --context est ignoré ; cela nécessite un noyau avec SELinux/SMACK activé + # Sortie détaillée mkdir-verbose-created-directory = { $util_name } : répertoire créé { $path } diff --git a/src/uu/mkdir/src/mkdir.rs b/src/uu/mkdir/src/mkdir.rs index ff46ad59556..7bd7024da7f 100644 --- a/src/uu/mkdir/src/mkdir.rs +++ b/src/uu/mkdir/src/mkdir.rs @@ -16,6 +16,11 @@ use uucore::translate; #[cfg(not(windows))] use uucore::mode; +#[cfg(any( + all(feature = "selinux", any(target_os = "android", target_os = "linux")), + all(feature = "smack", target_os = "linux") +))] +use uucore::show_warning; use uucore::{display::Quotable, fs::dir_strip_dot_for_creation}; use uucore::{format_usage, show_if_err}; @@ -321,20 +326,29 @@ fn create_single_dir(path: &Path, is_parent: bool, config: &Config) -> UResult<( // Apply SELinux context if requested #[cfg(all(feature = "selinux", any(target_os = "android", target_os = "linux")))] - if config.set_security_context && uucore::selinux::is_selinux_enabled() { - if let Err(e) = uucore::selinux::set_selinux_security_context(path, config.context) - { - let _ = std::fs::remove_dir(path); - return Err(USimpleError::new(1, e.to_string())); + if config.set_security_context { + if uucore::selinux::is_selinux_enabled() { + if let Err(e) = + uucore::selinux::set_selinux_security_context(path, config.context) + { + let _ = std::fs::remove_dir(path); + return Err(USimpleError::new(1, e.to_string())); + } + } else { + show_warning!("{}", translate!("mkdir-warning-context-not-selinux")); } } // Apply SMACK context if requested #[cfg(all(feature = "smack", target_os = "linux"))] if config.set_security_context { - uucore::smack::set_smack_label_and_cleanup(path, config.context, |p| { - std::fs::remove_dir(p) - })?; + if uucore::smack::is_smack_enabled() { + uucore::smack::set_smack_label_and_cleanup(path, config.context, |p| { + std::fs::remove_dir(p) + })?; + } else { + show_warning!("{}", translate!("mkdir-warning-context-not-selinux")); + } } Ok(()) } diff --git a/tests/by-util/test_mkdir.rs b/tests/by-util/test_mkdir.rs index 5df3c778122..cbf7cd7f67a 100644 --- a/tests/by-util/test_mkdir.rs +++ b/tests/by-util/test_mkdir.rs @@ -564,6 +564,54 @@ fn test_selinux() { } } +#[test] +#[cfg(all( + feature = "feat_selinux", + any(target_os = "linux", target_os = "android") +))] +fn test_selinux_context_warns_when_kernel_not_enabled() { + // --context should still create the directory on a kernel without + // SELinux/SMACK, just with a warning that it had no effect (matches GNU). + // On a kernel that does have it enabled, that's test_selinux's job above. + if uucore::selinux::is_selinux_enabled() { + return; + } + + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + let dest = "test_dir_context_warning"; + + new_ucmd!() + .arg("--context=unconfined_u:object_r:user_tmp_t:s0") + .arg(at.plus_as_string(dest)) + .succeeds() + .no_stdout() + .stderr_contains("ignoring --context"); + + assert!(at.dir_exists(dest)); +} + +#[test] +#[cfg(all(feature = "feat_smack", target_os = "linux"))] +fn test_smack_context_warns_when_kernel_not_enabled() { + if uucore::smack::is_smack_enabled() { + return; + } + + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + let dest = "test_dir_smack_context_warning"; + + new_ucmd!() + .arg("--context=some-label") + .arg(at.plus_as_string(dest)) + .succeeds() + .no_stdout() + .stderr_contains("ignoring --context"); + + assert!(at.dir_exists(dest)); +} + #[test] #[cfg(all( feature = "feat_selinux",