File tree Expand file tree Collapse file tree 3 files changed +27
-13
lines changed
Expand file tree Collapse file tree 3 files changed +27
-13
lines changed Original file line number Diff line number Diff line change @@ -9,7 +9,7 @@ use libc::O_CLOEXEC;
99use crate :: cutils:: cerr;
1010use crate :: log:: user_error;
1111use 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
1414pub ( 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
4040fn 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 ! (
Original file line number Diff line number Diff line change @@ -14,7 +14,7 @@ use crate::exec::ExitReason;
1414use crate :: log:: { user_error, user_info} ;
1515use crate :: system:: file:: { FileLock , create_temporary_dir} ;
1616use 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
1919struct 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 ( )
Original file line number Diff line number Diff 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
99117enum Op {
100118 Read = 4 ,
You can’t perform that action at this time.
0 commit comments