Skip to content
Closed
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
74 changes: 70 additions & 4 deletions .github/workflows/GnuTests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: GnuTests

# spell-checker:ignore (abbrev/names) CodeCov gnulib GnuTests Swatinem
# spell-checker:ignore (jargon) submodules devel
# spell-checker:ignore (libs/utils) autopoint chksum dpkg getenforce getlimits gperf lcov libexpect limactl pyinotify setenforce shopt texinfo valgrind libattr libcap taiki-e
# spell-checker:ignore (libs/utils) autopoint chksum dpkg getenforce getlimits gperf lcov libexpect limactl pyinotify setenforce shopt texinfo valgrind libattr libcap taiki-e zstd cpio
# spell-checker:ignore (options) Ccodegen Coverflow Cpanic Zpanic
# spell-checker:ignore (people) Dawid Dziurla * dawidd dtolnay
# spell-checker:ignore (vars) FILESET SUBDIRS XPASS
Expand Down Expand Up @@ -31,6 +31,8 @@ env:
TEST_STTY_FULL_SUMMARY_FILE: 'gnu-stty-full-result.json'
TEST_SELINUX_FULL_SUMMARY_FILE: 'selinux-gnu-full-result.json'
TEST_SELINUX_ROOT_FULL_SUMMARY_FILE: 'selinux-root-gnu-full-result.json'
TEST_SMACK_FULL_SUMMARY_FILE: 'smack-gnu-full-result.json'
TEST_SMACK_ROOT_FULL_SUMMARY_FILE: 'smack-root-gnu-full-result.json'

jobs:
native:
Expand Down Expand Up @@ -318,8 +320,59 @@ jobs:
gnu/tests-selinux/*.log
gnu/tests-selinux/*/*.log.gz

smack:
name: Run GNU tests (SMACK)
runs-on: ubuntu-24.04
steps:
- name: Checkout code (uutils)
uses: actions/checkout@v6
with:
path: 'uutils'
persist-credentials: false
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
components: rustfmt
- uses: Swatinem/rust-cache@v2
with:
workspaces: "./uutils -> target"
- name: Checkout code (GNU coreutils)
run: (mkdir -p gnu && cd gnu && bash ../uutils/util/fetch-gnu.sh)
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y qemu-system-x86 zstd cpio
- name: Run GNU SMACK tests
run: |
cd uutils
bash util/run-gnu-tests-smack-ci.sh "$GITHUB_WORKSPACE/gnu" "$GITHUB_WORKSPACE/gnu/tests-smack"
- name: Extract testing info into JSON
run: |
python3 uutils/util/gnu-json-result.py gnu/tests-smack > ${{ env.TEST_SMACK_FULL_SUMMARY_FILE }}
# SMACK tests run as root in QEMU, so use same results for root
cp ${{ env.TEST_SMACK_FULL_SUMMARY_FILE }} ${{ env.TEST_SMACK_ROOT_FULL_SUMMARY_FILE }}
- name: Upload SMACK json results
uses: actions/upload-artifact@v5
with:
name: smack-gnu-full-result
path: ${{ env.TEST_SMACK_FULL_SUMMARY_FILE }}
- name: Upload SMACK root json results
uses: actions/upload-artifact@v5
with:
name: smack-root-gnu-full-result
path: ${{ env.TEST_SMACK_ROOT_FULL_SUMMARY_FILE }}
- name: Compress SMACK test logs
run: gzip gnu/tests-smack/*/*.log 2>/dev/null || true
- name: Upload SMACK test logs
uses: actions/upload-artifact@v5
with:
name: smack-test-logs
path: |
gnu/tests-smack/*.log
gnu/tests-smack/*/*.log.gz

aggregate:
needs: [native, selinux]
needs: [native, selinux, smack]
permissions:
actions: read # for dawidd6/action-download-artifact to query and download artifacts
contents: read # for actions/checkout to fetch code
Expand Down Expand Up @@ -384,6 +437,19 @@ jobs:
name: selinux-root-gnu-full-result
path: results
merge-multiple: true

- name: Download smack json results
uses: actions/download-artifact@v6
with:
name: smack-gnu-full-result
path: results
merge-multiple: true
- name: Download smack root json results
uses: actions/download-artifact@v6
with:
name: smack-root-gnu-full-result
path: results
merge-multiple: true
- name: Extract/summarize testing info
id: summary
shell: bash
Expand All @@ -394,8 +460,8 @@ jobs:
path_UUTILS='uutils'

json_count=$(ls -l results/*.json | wc -l)
if [[ "$json_count" -ne 5 ]]; then
echo "::error ::Failed to download all results json files (expected 4 files, found $json_count); failing early"
if [[ "$json_count" -ne 7 ]]; then
echo "::error ::Failed to download all results json files (expected 7 files, found $json_count); failing early"
ls -lR results || true
exit 1
fi
Expand Down
10 changes: 10 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ feat_selinux = [
"selinux",
"stat/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.
feat_smack = [
"id/smack",
"ls/smack",
"mkdir/smack",
"mkfifo/smack",
"mknod/smack",
]
##
## feature sets
## (common/core and Tier1) feature sets
Expand Down
1 change: 1 addition & 0 deletions src/uu/id/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ path = "src/main.rs"

[features]
feat_selinux = ["selinux"]
smack = ["uucore/smack"]
53 changes: 45 additions & 8 deletions src/uu/id/src/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@
}

fn get_context_help_text() -> String {
#[cfg(not(feature = "selinux"))]
return translate!("id-context-help-disabled");
#[cfg(feature = "selinux")]
#[cfg(any(feature = "selinux", feature = "smack"))]
return translate!("id-context-help-enabled");
#[cfg(not(any(feature = "selinux", feature = "smack")))]
return translate!("id-context-help-disabled");
}

mod options {
Expand Down Expand Up @@ -99,6 +99,7 @@
zflag: bool, // --zero
cflag: bool, // --context
selinux_supported: bool,
smack_supported: bool,
ids: Option<Ids>,
// The behavior for calling GNU's `id` and calling GNU's `id $USER` is similar but different.
// * The SELinux context is only displayed without a specified user.
Expand Down Expand Up @@ -146,6 +147,16 @@
false
}
},
smack_supported: {
#[cfg(feature = "smack")]
{
uucore::smack::is_smack_enabled()
}
#[cfg(not(feature = "smack"))]
{
false
}
},
user_specified: !users.is_empty(),
ids: None,
};
Expand Down Expand Up @@ -179,7 +190,7 @@
let line_ending = LineEnding::from_zero_flag(state.zflag);

if state.cflag {
return if state.selinux_supported {
if state.selinux_supported {
// print SElinux context and exit
#[cfg(all(any(target_os = "linux", target_os = "android"), feature = "selinux"))]
if let Ok(context) = selinux::SecurityContext::current(false) {
Expand All @@ -192,13 +203,28 @@
translate!("id-error-cannot-get-context"),
));
}
Ok(())
return Ok(());
} else if state.smack_supported {
// print SMACK context and exit
#[cfg(all(target_os = "linux", feature = "smack"))]
match uucore::smack::get_smack_label_for_self() {
Ok(label) => {
print!("{}{line_ending}", label);
}
Err(_) => {
return Err(USimpleError::new(
1,
translate!("id-error-cannot-get-context"),
));
}
}
return Ok(());
} else {

Check failure on line 222 in src/uu/id/src/id.rs

View workflow job for this annotation

GitHub Actions / Style and Lint (ubuntu-24.04, unix)

ERROR: `cargo clippy`: redundant else block (file:'src/uu/id/src/id.rs', line:222)

Check failure on line 222 in src/uu/id/src/id.rs

View workflow job for this annotation

GitHub Actions / Style and Lint (unix)

ERROR: `cargo clippy`: redundant else block (file:'src/uu/id/src/id.rs', line:222)
Err(USimpleError::new(
return Err(USimpleError::new(
1,
translate!("id-error-context-selinux-only"),
))
};
));
}
}

for i in 0..=users.len() {
Expand Down Expand Up @@ -676,6 +702,17 @@
print!(" context={}", String::from_utf8_lossy(bytes));
}
}

#[cfg(all(target_os = "linux", feature = "smack"))]
if state.smack_supported
&& !state.user_specified
&& std::env::var_os("POSIXLY_CORRECT").is_none()
{
// print SMACK context (does not depend on "-Z")
if let Ok(label) = uucore::smack::get_smack_label_for_self() {
print!(" context={}", label);
}
}
}

#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "openbsd")))]
Expand Down
1 change: 1 addition & 0 deletions src/uu/ls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,4 @@ harness = false

[features]
feat_selinux = ["selinux", "uucore/selinux"]
smack = ["uucore/smack"]
35 changes: 35 additions & 0 deletions src/uu/ls/src/ls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ pub struct Config {
time_format_older: Option<String>, // Time format for older dates (optional, if not present, time_format_recent is used)
context: bool,
selinux_supported: bool,
smack_supported: bool,
group_directories_first: bool,
line_ending: LineEnding,
dired: bool,
Expand Down Expand Up @@ -1167,6 +1168,16 @@ impl Config {
false
}
},
smack_supported: {
#[cfg(all(feature = "smack", target_os = "linux"))]
{
uucore::smack::is_smack_enabled()
}
#[cfg(not(all(feature = "smack", target_os = "linux")))]
{
false
}
},
group_directories_first: options.get_flag(options::GROUP_DIRECTORIES_FIRST),
line_ending: LineEnding::from_zero_flag(options.get_flag(options::ZERO)),
dired,
Expand Down Expand Up @@ -3418,6 +3429,30 @@ fn get_security_context<'a>(
}
}

if config.smack_supported {
#[cfg(all(feature = "smack", target_os = "linux"))]
{
// For SMACK, use the path to get the label
// If must_dereference is true, we follow the symlink
let target_path = if must_dereference {
match std::fs::canonicalize(path) {
Ok(p) => p,
Err(_) => path.to_path_buf(),
}
} else {
path.to_path_buf()
};

match uucore::smack::get_smack_label_for_path(&target_path) {
Ok(label) => return Cow::Owned(label),
Err(_) => {
// No label or error getting label
return Cow::Borrowed(SUBSTITUTE_STRING);
}
}
}
}

Cow::Borrowed(SUBSTITUTE_STRING)
}

Expand Down
1 change: 1 addition & 0 deletions src/uu/mkdir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ fluent = { workspace = true }

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

[[bin]]
name = "mkdir"
Expand Down
1 change: 1 addition & 0 deletions src/uu/mkdir/locales/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ mkdir-error-empty-directory-name = cannot create directory '': No such file or d
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 }
mkdir-error-smack-context = failed to set default file creation context to '{ $context }':

# Verbose output
mkdir-verbose-created-directory = { $util_name }: created directory { $path }
11 changes: 11 additions & 0 deletions src/uu/mkdir/src/mkdir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,17 @@ fn create_single_dir(path: &Path, is_parent: bool, config: &Config) -> UResult<(
}
}

// Apply SMACK context if requested
#[cfg(feature = "smack")]
if config.set_selinux_context && uucore::smack::is_smack_enabled() {
if let Some(ctx) = config.context {
if let Err(e) = uucore::smack::set_smack_label_for_path(path, ctx) {
let _ = std::fs::remove_dir(path);
return Err(USimpleError::new(1, e.to_string()));
}
}
}

Ok(())
}

Expand Down
1 change: 1 addition & 0 deletions src/uu/mkfifo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ fluent = { workspace = true }

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

[[bin]]
name = "mkfifo"
Expand Down
1 change: 1 addition & 0 deletions src/uu/mkfifo/locales/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ mkfifo-error-invalid-mode = invalid mode: { $error }
mkfifo-error-missing-operand = missing operand
mkfifo-error-cannot-create-fifo = cannot create fifo { $path }: File exists
mkfifo-error-cannot-set-permissions = cannot set permissions on { $path }: { $error }
mkfifo-error-smack-context = failed to set default file creation context to '{ $context }':
17 changes: 17 additions & 0 deletions src/uu/mkfifo/src/mkfifo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,23 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
}
}
}

// Apply SMACK context if requested
#[cfg(feature = "smack")]
{
let set_smack_context = matches.get_flag(options::SELINUX);
let context = matches.get_one::<String>(options::CONTEXT);

if (set_smack_context || context.is_some()) && uucore::smack::is_smack_enabled() {
if let Some(ctx) = context {
use std::path::Path;
if let Err(e) = uucore::smack::set_smack_label_for_path(Path::new(&f), ctx) {
let _ = fs::remove_file(&f);
return Err(USimpleError::new(1, e.to_string()));
}
}
}
}
}

Ok(())
Expand Down
1 change: 1 addition & 0 deletions src/uu/mknod/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ fluent = { workspace = true }

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

[[bin]]
name = "mknod"
Expand Down
1 change: 1 addition & 0 deletions src/uu/mknod/locales/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ mknod-error-invalid-mode = invalid mode ({ $error })
mknod-error-mode-permission-bits-only = mode must specify only file permission bits
mknod-error-missing-device-type = missing device type
mknod-error-invalid-device-type = invalid device type { $type }
mknod-error-smack-context = failed to set default file creation context to '{ $context }':
15 changes: 15 additions & 0 deletions src/uu/mknod/src/mknod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,21 @@ fn mknod(file_name: &str, config: Config) -> i32 {
}
}

// Apply SMACK context if requested
#[cfg(feature = "smack")]
if config.set_selinux_context && uucore::smack::is_smack_enabled() {
if let Some(ctx) = config.context {
if let Err(e) =
uucore::smack::set_smack_label_for_path(std::path::Path::new(file_name), ctx)
{
// if it fails, delete the file
let _ = std::fs::remove_file(file_name);
eprintln!("{}: {}", uucore::util_name(), e);
return 1;
}
}
}

errno
}
}
Expand Down
Loading
Loading