From 8be5f7a89d3433a8bf2c485399a15b86dc6a4262 Mon Sep 17 00:00:00 2001 From: Ben Wiederhake Date: Sat, 2 Mar 2024 01:35:45 +0100 Subject: [PATCH] chcon: allow repeated flags and arguments --- src/uu/chcon/src/chcon.rs | 3 +- tests/by-util/test_chcon.rs | 117 ++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 1 deletion(-) diff --git a/src/uu/chcon/src/chcon.rs b/src/uu/chcon/src/chcon.rs index ddbaec98b..1a804bd3b 100644 --- a/src/uu/chcon/src/chcon.rs +++ b/src/uu/chcon/src/chcon.rs @@ -154,6 +154,7 @@ pub fn uu_app() -> Command { .override_usage(format_usage(USAGE)) .infer_long_args(true) .disable_help_flag(true) + .args_override_self(true) .arg( Arg::new(options::HELP) .long(options::HELP) @@ -180,7 +181,7 @@ pub fn uu_app() -> Command { .arg( Arg::new(options::preserve_root::PRESERVE_ROOT) .long(options::preserve_root::PRESERVE_ROOT) - .conflicts_with(options::preserve_root::NO_PRESERVE_ROOT) + .overrides_with(options::preserve_root::NO_PRESERVE_ROOT) .help("Fail to operate recursively on '/'.") .action(ArgAction::SetTrue), ) diff --git a/tests/by-util/test_chcon.rs b/tests/by-util/test_chcon.rs index b28996b2b..a8dae9aed 100644 --- a/tests/by-util/test_chcon.rs +++ b/tests/by-util/test_chcon.rs @@ -374,6 +374,30 @@ fn user_change() { ); } +#[test] +fn user_change_repeated() { + let (dir, mut cmd) = at_and_ucmd!(); + + dir.touch("a.tmp"); + let a_context = get_file_context(dir.plus("a.tmp")).unwrap(); + let new_a_context = if let Some(a_context) = a_context { + let mut components: Vec<_> = a_context.split(':').collect(); + components[0] = "guest_u"; + components.join(":") + } else { + set_file_context(dir.plus("a.tmp"), "unconfined_u:object_r:user_tmp_t:s0").unwrap(); + String::from("guest_u:object_r:user_tmp_t:s0") + }; + + cmd.args(&["--verbose", "--user=wrong", "--user=guest_u"]) + .arg(dir.plus("a.tmp")) + .succeeds(); + assert_eq!( + get_file_context(dir.plus("a.tmp")).unwrap(), + Some(new_a_context) + ); +} + #[test] fn role_change() { let (dir, mut cmd) = at_and_ucmd!(); @@ -471,6 +495,99 @@ fn valid_reference() { ); } +#[test] +fn valid_reference_repeat_flags() { + let (dir, mut cmd) = at_and_ucmd!(); + + dir.touch("a.tmp"); + let new_a_context = "guest_u:object_r:etc_t:s0:c42"; + set_file_context(dir.plus("a.tmp"), new_a_context).unwrap(); + + dir.touch("b.tmp"); + let b_context = get_file_context(dir.plus("b.tmp")).unwrap(); + assert_ne!(b_context.as_deref(), Some(new_a_context)); + + cmd.arg("--verbose") + .arg("-vvRRHHLLPP") // spell-checker:disable-line + .arg("--no-preserve-root") + .arg("--no-preserve-root") + .arg("--preserve-root") + .arg("--preserve-root") + .arg("--dereference") + .arg("--dereference") + .arg("--no-dereference") + .arg("--no-dereference") + .arg(format!("--reference={}", dir.plus_as_string("a.tmp"))) + .arg(dir.plus("b.tmp")) + .succeeds(); + assert_eq!( + get_file_context(dir.plus("b.tmp")).unwrap().as_deref(), + Some(new_a_context) + ); +} + +#[test] +fn valid_reference_repeated_reference() { + let (dir, mut cmd) = at_and_ucmd!(); + + dir.touch("a.tmp"); + let new_a_context = "guest_u:object_r:etc_t:s0:c42"; + set_file_context(dir.plus("a.tmp"), new_a_context).unwrap(); + + dir.touch("wrong.tmp"); + let new_wrong_context = "guest_u:object_r:etc_t:s42:c0"; + set_file_context(dir.plus("wrong.tmp"), new_wrong_context).unwrap(); + + dir.touch("b.tmp"); + let b_context = get_file_context(dir.plus("b.tmp")).unwrap(); + assert_ne!(b_context.as_deref(), Some(new_a_context)); + + cmd.arg("--verbose") + .arg(format!("--reference={}", dir.plus_as_string("wrong.tmp"))) + .arg(format!("--reference={}", dir.plus_as_string("a.tmp"))) + .arg(dir.plus("b.tmp")) + .succeeds(); + assert_eq!( + get_file_context(dir.plus("b.tmp")).unwrap().as_deref(), + Some(new_a_context) + ); + assert_eq!( + get_file_context(dir.plus("wrong.tmp")).unwrap().as_deref(), + Some(new_wrong_context) + ); +} + +#[test] +fn valid_reference_multi() { + let (dir, mut cmd) = at_and_ucmd!(); + + dir.touch("a.tmp"); + let new_a_context = "guest_u:object_r:etc_t:s0:c42"; + set_file_context(dir.plus("a.tmp"), new_a_context).unwrap(); + + dir.touch("b1.tmp"); + let b1_context = get_file_context(dir.plus("b1.tmp")).unwrap(); + assert_ne!(b1_context.as_deref(), Some(new_a_context)); + + dir.touch("b2.tmp"); + let b2_context = get_file_context(dir.plus("b2.tmp")).unwrap(); + assert_ne!(b2_context.as_deref(), Some(new_a_context)); + + cmd.arg("--verbose") + .arg(format!("--reference={}", dir.plus_as_string("a.tmp"))) + .arg(dir.plus("b1.tmp")) + .arg(dir.plus("b2.tmp")) + .succeeds(); + assert_eq!( + get_file_context(dir.plus("b1.tmp")).unwrap().as_deref(), + Some(new_a_context) + ); + assert_eq!( + get_file_context(dir.plus("b2.tmp")).unwrap().as_deref(), + Some(new_a_context) + ); +} + fn get_file_context(path: impl AsRef) -> Result, selinux::errors::Error> { let path = path.as_ref(); match selinux::SecurityContext::of_path(path, false, false) {