Skip to content

Commit 7a730e0

Browse files
authored
Use drop_privilege wrapper (#1528)
2 parents f5ba22d + 687c916 commit 7a730e0

File tree

3 files changed

+27
-13
lines changed

3 files changed

+27
-13
lines changed

src/pam/askpass.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use libc::O_CLOEXEC;
99
use crate::cutils::cerr;
1010
use crate::log::user_error;
1111
use crate::system::interface::ProcessId;
12-
use crate::system::{ForkResult, fork, mark_fds_as_cloexec};
12+
use crate::system::{ForkResult, audit, fork, mark_fds_as_cloexec};
1313

1414
pub(super) fn spawn_askpass(program: &Path, prompt: &str) -> io::Result<(ProcessId, OwnedFd)> {
1515
// Create socket
@@ -38,17 +38,15 @@ pub(super) fn spawn_askpass(program: &Path, prompt: &str) -> io::Result<(Process
3838
}
3939

4040
fn handle_child(program: &Path, prompt: &str, stdout: OwnedFd) -> ! {
41-
// Drop root privileges.
42-
// SAFETY: setuid does not change any memory and only affects OS state.
43-
unsafe {
44-
libc::setuid(libc::getuid());
45-
}
46-
4741
if let Err(e) = mark_fds_as_cloexec() {
4842
eprintln_ignore_io_error!("Failed to mark fds as CLOEXEC: {e}");
4943
process::exit(1);
5044
};
5145

46+
// root privileges are dangerous after this point, since we are about to
47+
// execute a command under control of the user, so drop them
48+
audit::irrevocably_drop_privileges();
49+
5250
// Exec askpass program
5351
let error = Command::new(program).arg(prompt).stdout(stdout).exec();
5452
user_error!(

src/sudo/edit.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::exec::ExitReason;
1414
use crate::log::{user_error, user_info};
1515
use crate::system::file::{FileLock, create_temporary_dir};
1616
use crate::system::wait::{Wait, WaitError, WaitOptions};
17-
use crate::system::{ForkResult, fork, mark_fds_as_cloexec};
17+
use crate::system::{ForkResult, audit, fork, mark_fds_as_cloexec};
1818

1919
struct ParentFileInfo<'a> {
2020
path: &'a Path,
@@ -206,11 +206,9 @@ fn handle_child_inner(
206206
) -> Result<(), String> {
207207
mark_fds_as_cloexec().map_err(|e| format!("Failed to mark fds as CLOEXEC: {e}"))?;
208208

209-
// Drop root privileges.
210-
// SAFETY: setuid does not change any memory and only affects OS state.
211-
unsafe {
212-
libc::setuid(libc::getuid());
213-
}
209+
// root privileges are dangerous after this point, since we are about to manipulate the
210+
// file system and execute a command under control of the user, so drop them
211+
audit::irrevocably_drop_privileges();
214212

215213
let tempdir = TempDirDropGuard(
216214
create_temporary_dir()

src/system/audit.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,24 @@ pub(crate) fn sudo_call<T>(
9595
Ok(result)
9696
}
9797

98+
/// Drop root privileges by setting effective user id equal to the real user id.
99+
/// This routine will panic if the process is not privileged.
100+
pub fn irrevocably_drop_privileges() {
101+
// SAFETY:
102+
// - getuid() and geteuid() are always safe to call
103+
// - setuid() does not change any memory and only affects OS state.
104+
unsafe {
105+
let real_uid = libc::getuid();
106+
let effective_uid = libc::geteuid();
107+
// we never use setuid/setgid/setgroups except in the pre_exec hook before exec'ing,
108+
// or in sudo_call (which always resets the user state after the closure finishes).
109+
// this extra check is here to punish programming mistakes due to sloppiness.
110+
assert_eq!(effective_uid, UserId::ROOT.inner(), "setuid violation");
111+
112+
cerr(libc::setuid(real_uid)).expect("setuid violation");
113+
}
114+
}
115+
98116
// of course we can also write "file & 0o040 != 0", but this makes the intent explicit
99117
enum Op {
100118
Read = 4,

0 commit comments

Comments
 (0)