Skip to content

Commit c848906

Browse files
committed
auto merge of #12085 : alexcrichton/rust/issue-12082, r=brson
This just copies the libuv implementation for libnative which seems reasonable enough (uid/gid fail on windows). Closes #12082
2 parents 425f574 + 74b42c6 commit c848906

File tree

10 files changed

+289
-66
lines changed

10 files changed

+289
-66
lines changed

src/compiletest/procsrv.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,7 @@ pub fn run(lib_path: &str,
5151
let env = env + target_env(lib_path, prog);
5252
let mut opt_process = run::Process::new(prog, args, run::ProcessOptions {
5353
env: Some(env),
54-
dir: None,
55-
in_fd: None,
56-
out_fd: None,
57-
err_fd: None
54+
.. run::ProcessOptions::new()
5855
});
5956

6057
match opt_process {
@@ -83,10 +80,7 @@ pub fn run_background(lib_path: &str,
8380
let env = env + target_env(lib_path, prog);
8481
let opt_process = run::Process::new(prog, args, run::ProcessOptions {
8582
env: Some(env),
86-
dir: None,
87-
in_fd: None,
88-
out_fd: None,
89-
err_fd: None
83+
.. run::ProcessOptions::new()
9084
});
9185

9286
match opt_process {

src/libnative/io/process.rs

+74-21
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ impl Process {
9898

9999
let env = config.env.map(|a| a.to_owned());
100100
let cwd = config.cwd.map(|a| Path::new(a));
101-
let res = spawn_process_os(config.program, config.args, env,
102-
cwd.as_ref(), in_fd, out_fd, err_fd);
101+
let res = spawn_process_os(config, env, cwd.as_ref(), in_fd, out_fd,
102+
err_fd);
103103

104104
unsafe {
105105
for pipe in in_pipe.iter() { let _ = libc::close(pipe.input); }
@@ -180,7 +180,7 @@ struct SpawnProcessResult {
180180
}
181181

182182
#[cfg(windows)]
183-
fn spawn_process_os(prog: &str, args: &[~str],
183+
fn spawn_process_os(config: p::ProcessConfig,
184184
env: Option<~[(~str, ~str)]>,
185185
dir: Option<&Path>,
186186
in_fd: c_int, out_fd: c_int,
@@ -202,6 +202,14 @@ fn spawn_process_os(prog: &str, args: &[~str],
202202

203203
use std::mem;
204204

205+
if config.gid.is_some() || config.uid.is_some() {
206+
return Err(io::IoError {
207+
kind: io::OtherIoError,
208+
desc: "unsupported gid/uid requested on windows",
209+
detail: None,
210+
})
211+
}
212+
205213
unsafe {
206214

207215
let mut si = zeroed_startupinfo();
@@ -237,16 +245,23 @@ fn spawn_process_os(prog: &str, args: &[~str],
237245
fail!("failure in DuplicateHandle: {}", os::last_os_error());
238246
}
239247

240-
let cmd = make_command_line(prog, args);
248+
let cmd = make_command_line(config.program, config.args);
241249
let mut pi = zeroed_process_information();
242250
let mut create_err = None;
243251

252+
// stolen from the libuv code.
253+
let mut flags = 0;
254+
if config.detach {
255+
flags |= libc::DETACHED_PROCESS | libc::CREATE_NEW_PROCESS_GROUP;
256+
}
257+
244258
with_envp(env, |envp| {
245259
with_dirp(dir, |dirp| {
246260
cmd.with_c_str(|cmdp| {
247261
let created = CreateProcessA(ptr::null(), cast::transmute(cmdp),
248262
ptr::mut_null(), ptr::mut_null(), TRUE,
249-
0, envp, dirp, &mut si, &mut pi);
263+
flags, envp, dirp, &mut si,
264+
&mut pi);
250265
if created == FALSE {
251266
create_err = Some(super::last_error());
252267
}
@@ -364,15 +379,14 @@ fn make_command_line(prog: &str, args: &[~str]) -> ~str {
364379
}
365380

366381
#[cfg(unix)]
367-
fn spawn_process_os(prog: &str, args: &[~str],
382+
fn spawn_process_os(config: p::ProcessConfig,
368383
env: Option<~[(~str, ~str)]>,
369384
dir: Option<&Path>,
370385
in_fd: c_int, out_fd: c_int,
371386
err_fd: c_int) -> IoResult<SpawnProcessResult> {
372387
use std::libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
373388
use std::libc::funcs::bsd44::getdtablesize;
374389
use std::libc::c_ulong;
375-
use std::unstable::intrinsics;
376390

377391
mod rustrt {
378392
extern {
@@ -441,22 +455,34 @@ fn spawn_process_os(prog: &str, args: &[~str],
441455
}
442456
drop(input);
443457

458+
fn fail(output: &mut file::FileDesc) -> ! {
459+
let errno = os::errno();
460+
let bytes = [
461+
(errno << 24) as u8,
462+
(errno << 16) as u8,
463+
(errno << 8) as u8,
464+
(errno << 0) as u8,
465+
];
466+
assert!(output.inner_write(bytes).is_ok());
467+
unsafe { libc::_exit(1) }
468+
}
469+
444470
rustrt::rust_unset_sigprocmask();
445471

446472
if in_fd == -1 {
447473
let _ = libc::close(libc::STDIN_FILENO);
448474
} else if retry(|| dup2(in_fd, 0)) == -1 {
449-
fail!("failure in dup2(in_fd, 0): {}", os::last_os_error());
475+
fail(&mut output);
450476
}
451477
if out_fd == -1 {
452478
let _ = libc::close(libc::STDOUT_FILENO);
453479
} else if retry(|| dup2(out_fd, 1)) == -1 {
454-
fail!("failure in dup2(out_fd, 1): {}", os::last_os_error());
480+
fail(&mut output);
455481
}
456482
if err_fd == -1 {
457483
let _ = libc::close(libc::STDERR_FILENO);
458484
} else if retry(|| dup2(err_fd, 2)) == -1 {
459-
fail!("failure in dup3(err_fd, 2): {}", os::last_os_error());
485+
fail(&mut output);
460486
}
461487
// close all other fds
462488
for fd in range(3, getdtablesize()).rev() {
@@ -465,9 +491,44 @@ fn spawn_process_os(prog: &str, args: &[~str],
465491
}
466492
}
467493

494+
match config.gid {
495+
Some(u) => {
496+
if libc::setgid(u as libc::gid_t) != 0 {
497+
fail(&mut output);
498+
}
499+
}
500+
None => {}
501+
}
502+
match config.uid {
503+
Some(u) => {
504+
// When dropping privileges from root, the `setgroups` call will
505+
// remove any extraneous groups. If we don't call this, then
506+
// even though our uid has dropped, we may still have groups
507+
// that enable us to do super-user things. This will fail if we
508+
// aren't root, so don't bother checking the return value, this
509+
// is just done as an optimistic privilege dropping function.
510+
extern {
511+
fn setgroups(ngroups: libc::c_int,
512+
ptr: *libc::c_void) -> libc::c_int;
513+
}
514+
let _ = setgroups(0, 0 as *libc::c_void);
515+
516+
if libc::setuid(u as libc::uid_t) != 0 {
517+
fail(&mut output);
518+
}
519+
}
520+
None => {}
521+
}
522+
if config.detach {
523+
// Don't check the error of setsid because it fails if we're the
524+
// process leader already. We just forked so it shouldn't return
525+
// error, but ignore it anyway.
526+
let _ = libc::setsid();
527+
}
528+
468529
with_dirp(dir, |dirp| {
469530
if !dirp.is_null() && chdir(dirp) == -1 {
470-
fail!("failure in chdir: {}", os::last_os_error());
531+
fail(&mut output);
471532
}
472533
});
473534

@@ -476,17 +537,9 @@ fn spawn_process_os(prog: &str, args: &[~str],
476537
set_environ(envp);
477538
}
478539
});
479-
with_argv(prog, args, |argv| {
540+
with_argv(config.program, config.args, |argv| {
480541
let _ = execvp(*argv, argv);
481-
let errno = os::errno();
482-
let bytes = [
483-
(errno << 24) as u8,
484-
(errno << 16) as u8,
485-
(errno << 8) as u8,
486-
(errno << 0) as u8,
487-
];
488-
assert!(output.inner_write(bytes).is_ok());
489-
intrinsics::abort();
542+
fail(&mut output);
490543
})
491544
}
492545
}

src/librustuv/process.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ impl Process {
5858

5959
let ret = with_argv(config.program, config.args, |argv| {
6060
with_env(config.env, |envp| {
61+
let mut flags = 0;
62+
if config.uid.is_some() {
63+
flags |= uvll::PROCESS_SETUID;
64+
}
65+
if config.gid.is_some() {
66+
flags |= uvll::PROCESS_SETGID;
67+
}
68+
if config.detach {
69+
flags |= uvll::PROCESS_DETACHED;
70+
}
6171
let options = uvll::uv_process_options_t {
6272
exit_cb: on_exit,
6373
file: unsafe { *argv },
@@ -67,11 +77,11 @@ impl Process {
6777
Some(ref cwd) => cwd.with_ref(|p| p),
6878
None => ptr::null(),
6979
},
70-
flags: 0,
80+
flags: flags as libc::c_uint,
7181
stdio_count: stdio.len() as libc::c_int,
7282
stdio: stdio.as_ptr(),
73-
uid: 0,
74-
gid: 0,
83+
uid: config.uid.unwrap_or(0) as uvll::uv_uid_t,
84+
gid: config.gid.unwrap_or(0) as uvll::uv_gid_t,
7585
};
7686

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

0 commit comments

Comments
 (0)