Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/cspell.dictionaries/jargon.wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ flamegraph
fsxattr
fullblock
getfacl
getfattr
getopt
gibi
gibibytes
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ feat_selinux = [
"id/selinux",
"ls/selinux",
"mkdir/selinux",
"mkfifo/selinux",
"mknod/selinux",
"stat/selinux",
"selinux",
Expand Down
3 changes: 3 additions & 0 deletions src/uu/mkfifo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ clap = { workspace = true }
libc = { workspace = true }
uucore = { workspace = true, features = ["fs", "mode"] }

[features]
selinux = ["uucore/selinux"]

[[bin]]
name = "mkfifo"
path = "src/main.rs"
37 changes: 27 additions & 10 deletions src/uu/mkfifo/src/mkfifo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

use clap::{Arg, ArgAction, Command};
use clap::{Arg, ArgAction, Command, value_parser};
use libc::mkfifo;
use std::ffi::CString;
use std::fs;
Expand All @@ -17,7 +17,7 @@ static ABOUT: &str = help_about!("mkfifo.md");

mod options {
pub static MODE: &str = "mode";
pub static SE_LINUX_SECURITY_CONTEXT: &str = "Z";
pub static SELINUX: &str = "Z";
pub static CONTEXT: &str = "context";
pub static FIFO: &str = "fifo";
}
Expand All @@ -26,13 +26,6 @@ mod options {
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uu_app().try_get_matches_from(args)?;

if matches.contains_id(options::CONTEXT) {
return Err(USimpleError::new(1, "--context is not implemented"));
}
if matches.get_flag(options::SE_LINUX_SECURITY_CONTEXT) {
return Err(USimpleError::new(1, "-Z is not implemented"));
}

let mode = match matches.get_one::<String>(options::MODE) {
// if mode is passed, ignore umask
Some(m) => match usize::from_str_radix(m, 8) {
Expand Down Expand Up @@ -67,6 +60,27 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
format!("cannot set permissions on {}: {e}", f.quote()),
));
}

// Apply SELinux context if requested
#[cfg(feature = "selinux")]
{
// Extract the SELinux related flags and options
let set_selinux_context = matches.get_flag(options::SELINUX);
let context = matches.get_one::<String>(options::CONTEXT);

if set_selinux_context || context.is_some() {
use std::path::Path;
if let Err(e) =
uucore::selinux::set_selinux_security_context(Path::new(&f), context)
{
let _ = fs::remove_file(f);
return Err(USimpleError::new(
1,
format!("failed to set SELinux security context: {e}"),
));
}
}
}
}

Ok(())
Expand All @@ -86,7 +100,7 @@ pub fn uu_app() -> Command {
.value_name("MODE"),
)
.arg(
Arg::new(options::SE_LINUX_SECURITY_CONTEXT)
Arg::new(options::SELINUX)
.short('Z')
.help("set the SELinux security context to default type")
.action(ArgAction::SetTrue),
Expand All @@ -95,6 +109,9 @@ pub fn uu_app() -> Command {
Arg::new(options::CONTEXT)
.long(options::CONTEXT)
.value_name("CTX")
.value_parser(value_parser!(String))
.num_args(0..=1)
.require_equals(true)
.help(
"like -Z, or if CTX is specified then set the SELinux \
or SMACK security context to CTX",
Expand Down
2 changes: 1 addition & 1 deletion tests/by-util/test_cp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore (flags) reflink (fs) tmpfs (linux) rlimit Rlim NOFILE clob btrfs neve ROOTDIR USERDIR procfs outfile uufs xattrs
// spell-checker:ignore bdfl hlsl IRWXO IRWXG getfattr
// spell-checker:ignore bdfl hlsl IRWXO IRWXG
use uutests::at_and_ucmd;
use uutests::new_ucmd;
use uutests::path_concat;
Expand Down
2 changes: 1 addition & 1 deletion tests/by-util/test_mkdir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore bindgen getfattr testtest
// spell-checker:ignore bindgen testtest

#![allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]

Expand Down
65 changes: 65 additions & 0 deletions tests/by-util/test_mkfifo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore nconfined

use uutests::new_ucmd;
use uutests::util::TestScenario;
use uutests::util_name;
Expand Down Expand Up @@ -101,3 +104,65 @@ fn test_create_fifo_with_umask() {
test_fifo_creation(0o022, "prw-r--r--"); // spell-checker:disable-line
test_fifo_creation(0o777, "p---------"); // spell-checker:disable-line
}

#[test]
#[cfg(feature = "feat_selinux")]
fn test_mkfifo_selinux() {
use std::process::Command;
let ts = TestScenario::new(util_name!());
let at = &ts.fixtures;
let dest = "test_file";
let args = [
"-Z",
"--context",
"--context=unconfined_u:object_r:user_tmp_t:s0",
];
for arg in args {
ts.ucmd().arg(arg).arg(dest).succeeds();
assert!(at.is_fifo("test_file"));

let getfattr_output = Command::new("getfattr")
.arg(at.plus_as_string(dest))
.arg("-n")
.arg("security.selinux")
.output()
.expect("Failed to run `getfattr` on the destination file");
println!("{:?}", getfattr_output);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this println! intentional?

assert!(
getfattr_output.status.success(),
"getfattr did not run successfully: {}",
String::from_utf8_lossy(&getfattr_output.stderr)
);

let stdout = String::from_utf8_lossy(&getfattr_output.stdout);
assert!(
stdout.contains("unconfined_u"),
"Expected 'foo' not found in getfattr output:\n{stdout}"
);
at.remove(&at.plus_as_string(dest));
}
}

#[test]
#[cfg(feature = "feat_selinux")]
fn test_mkfifo_selinux_invalid() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let dest = "orig";

let args = [
"--context=a",
"--context=unconfined_u:object_r:user_tmp_t:s0:a",
"--context=nconfined_u:object_r:user_tmp_t:s0",
];
for arg in args {
new_ucmd!()
.arg(arg)
.arg(dest)
.fails()
.stderr_contains("Failed to");
if at.file_exists(dest) {
at.remove(dest);
}
}
}
2 changes: 1 addition & 1 deletion tests/by-util/test_mknod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore getfattr nconfined
// spell-checker:ignore nconfined

use uutests::new_ucmd;
use uutests::util::TestScenario;
Expand Down
Loading