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
12 changes: 12 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ jobs:
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0

- name: Correct permissions
run: sudo chmod -R 755 /usr/share

- name: Install llvm-tools component
run: rustup component add llvm-tools

Expand Down Expand Up @@ -212,6 +215,9 @@ jobs:
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0

- name: Correct permissions
run: sudo chmod -R 755 /usr/share

- name: Install nightly rust
run: |
rustup set profile minimal
Expand Down Expand Up @@ -240,6 +246,9 @@ jobs:
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0

- name: Correct permissions
run: sudo chmod -R 755 /usr/share

- name: Install rust 1.70
run: rustup override set 1.70

Expand Down Expand Up @@ -316,6 +325,9 @@ jobs:
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0

- name: Correct permissions
run: sudo chmod -R 755 /usr/share

- name: Add 32-bit target
run: |
rustup target add i686-unknown-linux-gnu
Expand Down
30 changes: 0 additions & 30 deletions build.rs

This file was deleted.

3 changes: 3 additions & 0 deletions src/pam/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ mod securemem;
#[allow(nonstandard_style)]
pub mod sys;

#[link(name = "pam")]
extern "C" {}

#[cfg(target_os = "freebsd")]
const PAM_DATA_SILENT: std::ffi::c_int = 0;

Expand Down
5 changes: 3 additions & 2 deletions src/su/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ use super::cli::SuRunOptions;
const VALID_LOGIN_SHELLS_LIST: &str = "/etc/shells";
const FALLBACK_LOGIN_SHELL: &str = "/bin/sh";

const PATH_DEFAULT: &str = env!("SU_PATH_DEFAULT");
const PATH_DEFAULT_ROOT: &str = env!("SU_PATH_DEFAULT_ROOT");
// TODO: use _PATH_STDPATH and _PATH_DEFPATH_ROOT from paths.h
const PATH_DEFAULT: &str = "/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games";
const PATH_DEFAULT_ROOT: &str = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";

#[derive(Debug)]
pub(crate) struct SuContext {
Expand Down
27 changes: 13 additions & 14 deletions src/sudo/env/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ use std::{

use crate::common::{CommandAndArguments, Context, Error};
use crate::sudoers::Restrictions;
use crate::system::PATH_MAX;
use crate::system::{audit::zoneinfo_path, PATH_MAX};

use super::wildcard_match::wildcard_match;

const PATH_ZONEINFO: &str = env!("PATH_ZONEINFO");
const PATH_DEFAULT: &str = env!("SUDO_PATH_DEFAULT");
// TODO: use _PATH_STDPATH from paths.h
pub(crate) const PATH_DEFAULT: &str = "/usr/bin:/bin:/usr/sbin:/sbin";

pub type Environment = HashMap<OsString, OsString>;

Expand Down Expand Up @@ -138,12 +138,9 @@ fn is_safe_tz(value: &[u8]) -> bool {
};

if check_value.starts_with(b"/") {
// clippy 1.79 wants to us to optimise this check away; but we don't know what this will always
// be possible; and the compiler is clever enough to do that for us anyway if it can be.
#[allow(clippy::const_is_empty)]
if !PATH_ZONEINFO.is_empty() {
if !check_value.starts_with(PATH_ZONEINFO.as_bytes())
|| check_value.get(PATH_ZONEINFO.len()) != Some(&b'/')
if let Some(path_zoneinfo) = zoneinfo_path() {
if !check_value.starts_with(path_zoneinfo.as_bytes())
|| check_value.get(path_zoneinfo.len()) != Some(&b'/')
{
return false;
}
Expand Down Expand Up @@ -255,7 +252,7 @@ where

#[cfg(test)]
mod tests {
use super::{is_safe_tz, should_keep, PATH_ZONEINFO};
use super::{is_safe_tz, should_keep, zoneinfo_path};
use std::{collections::HashSet, ffi::OsStr};

struct TestConfiguration {
Expand Down Expand Up @@ -317,25 +314,27 @@ mod tests {
#[allow(clippy::bool_assert_comparison)]
#[test]
fn test_tzinfo() {
let path_zoneinfo = zoneinfo_path().unwrap();
assert_eq!(is_safe_tz("Europe/Amsterdam".as_bytes()), true);
assert_eq!(
is_safe_tz(format!("{PATH_ZONEINFO}/Europe/London").as_bytes()),
is_safe_tz(format!("{path_zoneinfo}/Europe/London").as_bytes()),
true
);
assert_eq!(
is_safe_tz(format!(":{PATH_ZONEINFO}/Europe/Amsterdam").as_bytes()),
is_safe_tz(format!(":{path_zoneinfo}/Europe/Amsterdam").as_bytes()),
true
);
assert_eq!(is_safe_tz(format!("/Europe/Amsterdam").as_bytes()), false);
assert_eq!(
is_safe_tz(format!("/schaap/Europe/Amsterdam").as_bytes()),
false
);
assert_eq!(
is_safe_tz(format!("{PATH_ZONEINFO}/../Europe/London").as_bytes()),
is_safe_tz(format!("{path_zoneinfo}/../Europe/London").as_bytes()),
false
);
assert_eq!(
is_safe_tz(format!("{PATH_ZONEINFO}/../Europe/London").as_bytes()),
is_safe_tz(format!("{path_zoneinfo}/../Europe/London").as_bytes()),
false
);
}
Expand Down
1 change: 1 addition & 0 deletions src/sudo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mod edit;

pub(crate) mod diagnostic;
mod env;
pub(crate) use env::environment::PATH_DEFAULT;
mod pam;
mod pipeline;

Expand Down
2 changes: 1 addition & 1 deletion src/sudoers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ fn select_editor(settings: &Settings, trusted_env: bool) -> PathBuf {
editor
} else if let Some(editor) = resolve_path(
&editor,
&std::env::var("PATH").unwrap_or(env!("SUDO_PATH_DEFAULT").to_string()),
&std::env::var("PATH").unwrap_or(crate::sudo::PATH_DEFAULT.to_string()),
) {
editor
} else {
Expand Down
14 changes: 14 additions & 0 deletions src/system/audit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,20 @@ pub fn secure_open_cookie_file(path: impl AsRef<Path>) -> io::Result<File> {
secure_open_impl(path.as_ref(), &mut open_options, true, true)
}

/// Return the system zoneinfo path after validating that it is safe
pub fn zoneinfo_path() -> Option<&'static str> {
let paths = [
"/usr/share/zoneinfo",
"/usr/share/lib/zoneinfo",
"/usr/lib/zoneinfo",
];

paths.into_iter().find(|p| {
let path = Path::new(p);
path.metadata().and_then(|meta| checks(path, meta)).is_ok()
})
}

fn checks(path: &Path, meta: Metadata) -> io::Result<()> {
let error = |msg| Error::new(ErrorKind::PermissionDenied, msg);

Expand Down
Loading