Skip to content

Commit 0653109

Browse files
committed
coreutils: dummy -> true -> coreutils symlink chain runs as true
1 parent 9f0ac6b commit 0653109

File tree

4 files changed

+37
-4
lines changed

4 files changed

+37
-4
lines changed

docs/src/extensions.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,15 @@ $ ls -w=80
2525
With GNU coreutils, `--help` usually prints the help message and `--version` prints the version.
2626
We also commonly provide short options: `-h` for help and `-V` for version.
2727

28-
## `coreutils`
28+
## `coreutils` (multi-call binary)
2929

3030
Our `coreutils` calls utility by `coreutils utility-name` and has `--list` to run against busybox test suite.
3131
Our `coreutils` is called as `utility-name` if its binary name ends with `utility-name` to support prefixed names.
3232
Longer name is prioritized e.g. `sum` with the prefix `ck` is called as `cksum`.
3333

34+
On Linux, the symlink chain `dummy` -> `utility-name` -> `coreutils` tries to run `utility-name`
35+
i.e. `dummy` tries to behave like individual binaries. It is important if `utility-name` is `true`.
36+
3437
## `env`
3538

3639
GNU `env` allows the empty string to be used as an environment variable name.

src/bin/coreutils.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,18 @@ fn main() {
7373
// todo: Remove support of "*box" from binary
7474
uucore::set_utility_is_second_arg();
7575
args.next()
76+
// with the invalid_name -> true -> coreutils symlink chain, run true
77+
// this is possible on the platform not using argv0
78+
} else if cfg!(any(target_os = "linux", target_os = "android"))
79+
&& let Ok(binary) = std::fs::read_link(&binary)
80+
&& let Some(valid) = validation::name(&binary)
81+
&& !valid.ends_with("utils")
82+
&& let Some(&matched) = utils
83+
.keys()
84+
.filter(|&&u| valid.ends_with(u))
85+
.max_by_key(|u| u.len())
86+
{
87+
Some(OsString::from(matched))
7688
} else {
7789
validation::not_found(&OsString::from(binary_as_util));
7890
};

src/common/validation.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,17 @@ pub fn binary_path(args: &mut impl Iterator<Item = OsString>) -> PathBuf {
9494
let exec_path = Path::new(OsStr::from_bytes(execfn_bytes));
9595
let argv0 = args.next().unwrap();
9696
let mut shebang_buf = [0u8; 2];
97-
// exec_path is wrong when called from shebang or memfd_create (/proc/self/fd/*)
98-
// argv0 is not full-path when called from PATH
9997
if execfn_bytes.rsplit(|&b| b == b'/').next() == argv0.as_bytes().rsplit(|&b| b == b'/').next()
100-
|| execfn_bytes.starts_with(b"/proc/")
98+
{
99+
// argv0 is not full-path when called from PATH
100+
exec_path.into()
101+
} else if execfn_bytes.starts_with(b"/proc/")
101102
|| (File::open(Path::new(exec_path))
102103
.and_then(|mut f| f.read_exact(&mut shebang_buf))
103104
.is_ok()
104105
&& &shebang_buf == b"#!")
105106
{
107+
// exec_path is wrong when called from shebang or memfd_create (/proc/self/fd/*)
106108
argv0.into()
107109
} else {
108110
exec_path.into()

tests/test_util_name.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,22 @@ fn init() {
2626
eprintln!("Setting UUTESTS_BINARY_PATH={TESTS_BINARY}");
2727
}
2828

29+
#[test]
30+
#[cfg(all(feature = "env", any(target_os = "linux", target_os = "android")))]
31+
fn binary_name_symlink_chain() {
32+
let ts = TestScenario::new("chain");
33+
let core_path = &ts.bin_path;
34+
let env_path = ts.fixtures.plus("prefixed-env");
35+
let dummy_path = ts.fixtures.plus("dummy");
36+
symlink_file(core_path, &env_path).unwrap();
37+
symlink_file(&env_path, &dummy_path).unwrap();
38+
let is_env = std::process::Command::new(&dummy_path)
39+
.status()
40+
.unwrap()
41+
.success();
42+
assert!(is_env, "symlink chain dummy -> env -> coreutils failed");
43+
}
44+
2945
#[test]
3046
#[cfg(all(feature = "env", any(target_os = "linux", target_os = "android")))]
3147
fn binary_name_protection() {

0 commit comments

Comments
 (0)