Skip to content

Commit 1337cbc

Browse files
committed
coreutils: Protect against env -a for security
1 parent 194d980 commit 1337cbc

File tree

4 files changed

+38
-7
lines changed

4 files changed

+38
-7
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ clap_mangen = { workspace = true, optional = true }
422422
clap.workspace = true
423423
fluent-syntax = { workspace = true, optional = true }
424424
itertools.workspace = true
425+
libc.workspace = true
425426
phf.workspace = true
426427
selinux = { workspace = true, optional = true }
427428
textwrap.workspace = true

src/bin/coreutils.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,12 @@ fn main() {
5555
let is_coreutils = binary_as_util.ends_with("utils");
5656
let matched_util = utils
5757
.keys()
58+
//*utils is not ls
5859
.filter(|&&u| binary_as_util.ends_with(u) && !is_coreutils)
59-
.max_by_key(|u| u.len()); //Prefer stty more than tty. *utils is not ls
60+
//Prefer stty more than tty
61+
.max_by_key(|u| u.len())
62+
// todo: with coreutils -> ls -> blah symlink chain, blah calls ls
63+
;
6064

6165
let util_name = if let Some(&util) = matched_util {
6266
Some(OsString::from(util))

src/common/validation.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// For the full copyright and license information, please view the LICENSE
44
// file that was distributed with this source code.
55

6-
// spell-checker:ignore prefixcat testcat
6+
// spell-checker:ignore prefixcat testcat getauxval EXECFN
77

88
use std::ffi::{OsStr, OsString};
99
use std::path::{Path, PathBuf};
@@ -67,15 +67,29 @@ fn get_canonical_util_name(util_name: &str) -> &str {
6767
}
6868

6969
/// Gets the binary path from command line arguments
70-
/// # Panics
7170
/// Panics if the binary path cannot be determined
71+
#[cfg(not(any(target_os = "linux", target_os = "android")))]
7272
pub fn binary_path(args: &mut impl Iterator<Item = OsString>) -> PathBuf {
7373
match args.next() {
7474
Some(ref s) if !s.is_empty() => PathBuf::from(s),
7575
_ => std::env::current_exe().unwrap(),
7676
}
7777
}
78-
78+
/// protect against env -a
79+
#[cfg(any(target_os = "linux", target_os = "android"))]
80+
pub fn binary_path(args: &mut impl Iterator<Item = OsString>) -> PathBuf {
81+
use std::ffi::{CStr, OsString};
82+
use std::os::unix::ffi::OsStringExt;
83+
let p: *const libc::c_char = unsafe { libc::getauxval(libc::AT_EXECFN) as _ };
84+
if p.is_null() {
85+
use std::io::{Write as _, stderr};
86+
let _ = writeln!(stderr(), "getauxval failed");
87+
process::exit(1);
88+
}
89+
let _ = args.next();
90+
let n = unsafe { CStr::from_ptr(p) };
91+
OsString::from_vec(n.to_bytes().to_vec()).into()
92+
}
7993
/// Extracts the binary name from a path
8094
pub fn name(binary_path: &Path) -> Option<&str> {
8195
binary_path.file_stem()?.to_str()

tests/by-util/test_env.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,11 @@ fn test_env_with_empty_executable_double_quotes() {
722722
}
723723

724724
#[test]
725-
#[cfg(all(unix, feature = "dirname", feature = "echo"))]
725+
#[cfg(all(
726+
all(unix, feature = "dirname", feature = "echo"),
727+
not(any(target_os = "linux", target_os = "android"))
728+
))]
729+
// protected against hijack at Linux
726730
fn test_env_overwrite_arg0() {
727731
let ts = TestScenario::new(util_name!());
728732

@@ -746,7 +750,11 @@ fn test_env_overwrite_arg0() {
746750
}
747751

748752
#[test]
749-
#[cfg(all(unix, feature = "echo"))]
753+
#[cfg(all(
754+
all(unix, feature = "echo"),
755+
not(any(target_os = "linux", target_os = "android"))
756+
))]
757+
// protected against hijack at Linux
750758
fn test_env_arg_argv0_overwrite() {
751759
let ts = TestScenario::new(util_name!());
752760

@@ -794,7 +802,11 @@ fn test_env_arg_argv0_overwrite() {
794802
}
795803

796804
#[test]
797-
#[cfg(all(unix, feature = "echo"))]
805+
#[cfg(all(
806+
all(unix, feature = "echo"),
807+
not(any(target_os = "linux", target_os = "android"))
808+
))]
809+
// protected against hijack at Linux
798810
fn test_env_arg_argv0_overwrite_mixed_with_string_args() {
799811
let ts = TestScenario::new(util_name!());
800812

0 commit comments

Comments
 (0)