Skip to content

Commit 22ddcd1

Browse files
committedJan 22, 2021
Auto merge of #72160 - slo1:libstd-setgroups, r=KodrAus
Add setgroups to std::os::unix::process::CommandExt Should fix #38527. I'm not sure groups is the greatest name though.
2 parents b814b63 + a4db851 commit 22ddcd1

File tree

4 files changed

+67
-7
lines changed

4 files changed

+67
-7
lines changed
 

‎library/std/src/sys/unix/ext/process.rs

+18
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ pub trait CommandExt {
3939
#[cfg(target_os = "vxworks")] id: u16,
4040
) -> &mut process::Command;
4141

42+
/// Sets the supplementary group IDs for the calling process. Translates to
43+
/// a `setgroups` call in the child process.
44+
#[unstable(feature = "setgroups", issue = "38527", reason = "")]
45+
fn groups(
46+
&mut self,
47+
#[cfg(not(target_os = "vxworks"))] groups: &[u32],
48+
#[cfg(target_os = "vxworks")] groups: &[u16],
49+
) -> &mut process::Command;
50+
4251
/// Schedules a closure to be run just before the `exec` function is
4352
/// invoked.
4453
///
@@ -149,6 +158,15 @@ impl CommandExt for process::Command {
149158
self
150159
}
151160

161+
fn groups(
162+
&mut self,
163+
#[cfg(not(target_os = "vxworks"))] groups: &[u32],
164+
#[cfg(target_os = "vxworks")] groups: &[u16],
165+
) -> &mut process::Command {
166+
self.as_inner_mut().groups(groups);
167+
self
168+
}
169+
152170
unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
153171
where
154172
F: FnMut() -> io::Result<()> + Send + Sync + 'static,

‎library/std/src/sys/unix/process/process_common.rs

+9
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ pub struct Command {
8787
gid: Option<gid_t>,
8888
saw_nul: bool,
8989
closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
90+
groups: Option<Box<[gid_t]>>,
9091
stdin: Option<Stdio>,
9192
stdout: Option<Stdio>,
9293
stderr: Option<Stdio>,
@@ -148,6 +149,7 @@ impl Command {
148149
gid: None,
149150
saw_nul,
150151
closures: Vec::new(),
152+
groups: None,
151153
stdin: None,
152154
stdout: None,
153155
stderr: None,
@@ -183,6 +185,9 @@ impl Command {
183185
pub fn gid(&mut self, id: gid_t) {
184186
self.gid = Some(id);
185187
}
188+
pub fn groups(&mut self, groups: &[gid_t]) {
189+
self.groups = Some(Box::from(groups));
190+
}
186191

187192
pub fn saw_nul(&self) -> bool {
188193
self.saw_nul
@@ -226,6 +231,10 @@ impl Command {
226231
pub fn get_gid(&self) -> Option<gid_t> {
227232
self.gid
228233
}
234+
#[allow(dead_code)]
235+
pub fn get_groups(&self) -> Option<&[gid_t]> {
236+
self.groups.as_deref()
237+
}
229238

230239
pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
231240
&mut self.closures

‎library/std/src/sys/unix/process/process_unix.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -183,20 +183,26 @@ impl Command {
183183

184184
#[cfg(not(target_os = "l4re"))]
185185
{
186+
if let Some(_g) = self.get_groups() {
187+
//FIXME: Redox kernel does not support setgroups yet
188+
#[cfg(not(target_os = "redox"))]
189+
cvt(libc::setgroups(_g.len().try_into().unwrap(), _g.as_ptr()))?;
190+
}
186191
if let Some(u) = self.get_gid() {
187192
cvt(libc::setgid(u as gid_t))?;
188193
}
189194
if let Some(u) = self.get_uid() {
190195
// When dropping privileges from root, the `setgroups` call
191-
// will remove any extraneous groups. If we don't call this,
192-
// then even though our uid has dropped, we may still have
193-
// groups that enable us to do super-user things. This will
194-
// fail if we aren't root, so don't bother checking the
195-
// return value, this is just done as an optimistic
196-
// privilege dropping function.
196+
// will remove any extraneous groups. We only drop groups
197+
// if the current uid is 0 and we weren't given an explicit
198+
// set of groups. If we don't call this, then even though our
199+
// uid has dropped, we may still have groups that enable us to
200+
// do super-user things.
197201
//FIXME: Redox kernel does not support setgroups yet
198202
#[cfg(not(target_os = "redox"))]
199-
let _ = libc::setgroups(0, ptr::null());
203+
if libc::getuid() == 0 && self.get_groups().is_none() {
204+
cvt(libc::setgroups(0, ptr::null()))?;
205+
}
200206
cvt(libc::setuid(u as uid_t))?;
201207
}
202208
}
@@ -287,6 +293,7 @@ impl Command {
287293
|| self.get_uid().is_some()
288294
|| (self.env_saw_path() && !self.program_is_path())
289295
|| !self.get_closures().is_empty()
296+
|| self.get_groups().is_some()
290297
{
291298
return Ok(None);
292299
}
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// run-pass
2+
// ignore-windows - this is a unix-specific test
3+
// ignore-cloudabi
4+
// ignore-emscripten
5+
// ignore-sgx
6+
7+
#![feature(rustc_private)]
8+
#![feature(setgroups)]
9+
10+
extern crate libc;
11+
use std::process::Command;
12+
use std::os::unix::process::CommandExt;
13+
14+
fn main() {
15+
#[cfg(unix)]
16+
run()
17+
}
18+
19+
#[cfg(unix)]
20+
fn run() {
21+
let max_ngroups = unsafe { libc::sysconf(libc::_SC_NGROUPS_MAX) };
22+
let max_ngroups = max_ngroups as u32 + 1;
23+
let vec: Vec<u32> = (0..max_ngroups).collect();
24+
let p = Command::new("/bin/id").groups(&vec[..]).spawn();
25+
assert!(p.is_err());
26+
}

0 commit comments

Comments
 (0)
Please sign in to comment.