Skip to content

Commit

Permalink
Allow configuration of uid/gid/detach on processes
Browse files Browse the repository at this point in the history
This just copies the libuv implementation for libnative which seems reasonable
enough (uid/gid fail on windows).

Closes #12082
  • Loading branch information
alexcrichton committed Feb 17, 2014
1 parent 13dc521 commit 553b7e6
Show file tree
Hide file tree
Showing 8 changed files with 287 additions and 64 deletions.
10 changes: 2 additions & 8 deletions src/compiletest/procsrv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,7 @@ pub fn run(lib_path: &str,
let env = env + target_env(lib_path, prog);
let mut opt_process = run::Process::new(prog, args, run::ProcessOptions {
env: Some(env),
dir: None,
in_fd: None,
out_fd: None,
err_fd: None
.. run::ProcessOptions::new()
});

match opt_process {
Expand Down Expand Up @@ -83,10 +80,7 @@ pub fn run_background(lib_path: &str,
let env = env + target_env(lib_path, prog);
let opt_process = run::Process::new(prog, args, run::ProcessOptions {
env: Some(env),
dir: None,
in_fd: None,
out_fd: None,
err_fd: None
.. run::ProcessOptions::new()
});

match opt_process {
Expand Down
95 changes: 74 additions & 21 deletions src/libnative/io/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
Expand Down Expand Up @@ -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,
Expand All @@ -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();
Expand Down Expand Up @@ -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());
}
Expand Down Expand Up @@ -364,15 +379,14 @@ 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,
err_fd: c_int) -> IoResult<SpawnProcessResult> {
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 {
Expand Down Expand Up @@ -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() {
Expand All @@ -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);
}
});

Expand All @@ -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);
})
}
}
Expand Down
16 changes: 13 additions & 3 deletions src/librustuv/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ impl Process {

let ret = with_argv(config.program, config.args, |argv| {
with_env(config.env, |envp| {
let mut flags = 0;
if config.uid.is_some() {
flags |= uvll::PROCESS_SETUID;
}
if config.gid.is_some() {
flags |= uvll::PROCESS_SETGID;
}
if config.detach {
flags |= uvll::PROCESS_DETACHED;
}
let options = uvll::uv_process_options_t {
exit_cb: on_exit,
file: unsafe { *argv },
Expand All @@ -67,11 +77,11 @@ impl Process {
Some(ref cwd) => cwd.with_ref(|p| p),
None => ptr::null(),
},
flags: 0,
flags: flags as libc::c_uint,
stdio_count: stdio.len() as libc::c_int,
stdio: stdio.as_ptr(),
uid: 0,
gid: 0,
uid: config.uid.unwrap_or(0) as uvll::uv_uid_t,
gid: config.gid.unwrap_or(0) as uvll::uv_gid_t,
};

let handle = UvHandle::alloc(None::<Process>, uvll::UV_PROCESS);
Expand Down

0 comments on commit 553b7e6

Please sign in to comment.