diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2014-02-06 22:38:05 -0800 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2014-02-16 16:01:03 -0800 |
| commit | 553b7e67d70dbf72dd705616acaa496a20fba765 (patch) | |
| tree | 4274ee5030cea6f05dbbb23f75c1c9eb4e58c2f1 /src/libnative | |
| parent | 13dc521861f6c3be909ba9317fde50f946e9f85d (diff) | |
| download | rust-553b7e67d70dbf72dd705616acaa496a20fba765.tar.gz rust-553b7e67d70dbf72dd705616acaa496a20fba765.zip | |
Allow configuration of uid/gid/detach on processes
This just copies the libuv implementation for libnative which seems reasonable enough (uid/gid fail on windows). Closes #12082
Diffstat (limited to 'src/libnative')
| -rw-r--r-- | src/libnative/io/process.rs | 95 |
1 files changed, 74 insertions, 21 deletions
diff --git a/src/libnative/io/process.rs b/src/libnative/io/process.rs index b796535371f..affa3ebf544 100644 --- a/src/libnative/io/process.rs +++ b/src/libnative/io/process.rs @@ -98,8 +98,8 @@ impl Process { let env = config.env.map(|a| a.to_owned()); let cwd = config.cwd.map(|a| Path::new(a)); - let res = spawn_process_os(config.program, config.args, env, - cwd.as_ref(), in_fd, out_fd, err_fd); + let res = spawn_process_os(config, env, cwd.as_ref(), in_fd, out_fd, + err_fd); unsafe { for pipe in in_pipe.iter() { let _ = libc::close(pipe.input); } @@ -180,7 +180,7 @@ struct SpawnProcessResult { } #[cfg(windows)] -fn spawn_process_os(prog: &str, args: &[~str], +fn spawn_process_os(config: p::ProcessConfig, env: Option<~[(~str, ~str)]>, dir: Option<&Path>, in_fd: c_int, out_fd: c_int, @@ -202,6 +202,14 @@ fn spawn_process_os(prog: &str, args: &[~str], use std::mem; + if config.gid.is_some() || config.uid.is_some() { + return Err(io::IoError { + kind: io::OtherIoError, + desc: "unsupported gid/uid requested on windows", + detail: None, + }) + } + unsafe { let mut si = zeroed_startupinfo(); @@ -237,16 +245,23 @@ fn spawn_process_os(prog: &str, args: &[~str], fail!("failure in DuplicateHandle: {}", os::last_os_error()); } - let cmd = make_command_line(prog, args); + let cmd = make_command_line(config.program, config.args); let mut pi = zeroed_process_information(); let mut create_err = None; + // stolen from the libuv code. + let mut flags = 0; + if config.detach { + flags |= libc::DETACHED_PROCESS | libc::CREATE_NEW_PROCESS_GROUP; + } + with_envp(env, |envp| { with_dirp(dir, |dirp| { cmd.with_c_str(|cmdp| { let created = CreateProcessA(ptr::null(), cast::transmute(cmdp), ptr::mut_null(), ptr::mut_null(), TRUE, - 0, envp, dirp, &mut si, &mut pi); + flags, envp, dirp, &mut si, + &mut pi); if created == FALSE { create_err = Some(super::last_error()); } @@ -364,7 +379,7 @@ fn make_command_line(prog: &str, args: &[~str]) -> ~str { } #[cfg(unix)] -fn spawn_process_os(prog: &str, args: &[~str], +fn spawn_process_os(config: p::ProcessConfig, env: Option<~[(~str, ~str)]>, dir: Option<&Path>, in_fd: c_int, out_fd: c_int, @@ -372,7 +387,6 @@ fn spawn_process_os(prog: &str, args: &[~str], use std::libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp}; use std::libc::funcs::bsd44::getdtablesize; use std::libc::c_ulong; - use std::unstable::intrinsics; mod rustrt { extern { @@ -441,22 +455,34 @@ fn spawn_process_os(prog: &str, args: &[~str], } drop(input); + fn fail(output: &mut file::FileDesc) -> ! { + let errno = os::errno(); + let bytes = [ + (errno << 24) as u8, + (errno << 16) as u8, + (errno << 8) as u8, + (errno << 0) as u8, + ]; + assert!(output.inner_write(bytes).is_ok()); + unsafe { libc::_exit(1) } + } + rustrt::rust_unset_sigprocmask(); if in_fd == -1 { let _ = libc::close(libc::STDIN_FILENO); } else if retry(|| dup2(in_fd, 0)) == -1 { - fail!("failure in dup2(in_fd, 0): {}", os::last_os_error()); + fail(&mut output); } if out_fd == -1 { let _ = libc::close(libc::STDOUT_FILENO); } else if retry(|| dup2(out_fd, 1)) == -1 { - fail!("failure in dup2(out_fd, 1): {}", os::last_os_error()); + fail(&mut output); } if err_fd == -1 { let _ = libc::close(libc::STDERR_FILENO); } else if retry(|| dup2(err_fd, 2)) == -1 { - fail!("failure in dup3(err_fd, 2): {}", os::last_os_error()); + fail(&mut output); } // close all other fds for fd in range(3, getdtablesize()).rev() { @@ -465,9 +491,44 @@ fn spawn_process_os(prog: &str, args: &[~str], } } + match config.gid { + Some(u) => { + if libc::setgid(u as libc::gid_t) != 0 { + fail(&mut output); + } + } + None => {} + } + match config.uid { + Some(u) => { + // When dropping privileges from root, the `setgroups` call will + // remove any extraneous groups. If we don't call this, then + // even though our uid has dropped, we may still have groups + // that enable us to do super-user things. This will fail if we + // aren't root, so don't bother checking the return value, this + // is just done as an optimistic privilege dropping function. + extern { + fn setgroups(ngroups: libc::c_int, + ptr: *libc::c_void) -> libc::c_int; + } + let _ = setgroups(0, 0 as *libc::c_void); + + if libc::setuid(u as libc::uid_t) != 0 { + fail(&mut output); + } + } + None => {} + } + if config.detach { + // Don't check the error of setsid because it fails if we're the + // process leader already. We just forked so it shouldn't return + // error, but ignore it anyway. + let _ = libc::setsid(); + } + with_dirp(dir, |dirp| { if !dirp.is_null() && chdir(dirp) == -1 { - fail!("failure in chdir: {}", os::last_os_error()); + fail(&mut output); } }); @@ -476,17 +537,9 @@ fn spawn_process_os(prog: &str, args: &[~str], set_environ(envp); } }); - with_argv(prog, args, |argv| { + with_argv(config.program, config.args, |argv| { let _ = execvp(*argv, argv); - let errno = os::errno(); - let bytes = [ - (errno << 24) as u8, - (errno << 16) as u8, - (errno << 8) as u8, - (errno << 0) as u8, - ]; - assert!(output.inner_write(bytes).is_ok()); - intrinsics::abort(); + fail(&mut output); }) } } |
