Having looked at the Command and unix::CommandExt docs, I find that they are actually lacking. Currently, in rust, you need to use .pre_exec to set a list of groups or to chroot before executing the command. Both are suboptimal for the following reasons:
- You need to allocate in order to call
chroot(2)(I will not start a rant about OsStr being entirely useless, but suffice it to say, I am not the biggest fan of it). - You almost always need to allocate in order to set a suplementary groups list.
- When the
pre_execclosure is called, the directory has already been changed, which is incorrect when presented withchroot(2), since it will leave it at the same physical working directory (which may be outside the new root directory), so in order to usechroot, you also have to usechdir, requiring more allocations. - It is also not defined the order that changes of uid and gid will take place wrt.
pre_exec, which means that you can't use.uidif you plan to do anything that needs elevation because if it occurs beforepre_exec, all privileged operations will be all but guaranteed to EPERM, includingroot_directoryandgroups. -
pre_execalso cannot use closures that capture by-move, which is understandable, but prevents taking ownership of theVecorCString(which could then beforgotten in the child), which could be dropped in the parent (To avoid having to leak or borrow, which limits or prevents returning the Command, in forwarding methods that operate on Command). -
groupsclosely mirrors the presence ofgid. It doesn't necessarily make sense to set the primary group idea while leaving all suplementary group ids untouched. -
chrootis potetionally useful in privileged code, and is very difficult to use correctly as-is with CommandExt, for the reasons described above.
Thus, I propose two additional functions be added to std::os::unix::process::CommandExt as follows:
groups
fn groups<A: AsRef<[u32]>>(&mut self,groups: A) -> &mut Self
Sets the supplementary groups of the child process to the the list provided by groups.
root_directory
fn root_directory<S: AsRef<Path>>(&mut self,dir: S) -> &mut Self;
Sets the Root directory of the the child process.
Notes
root_directory applies to both current_directory and the program name for the command. The new directory is the path name within the root directory. If the path passed to current_directory is relative, it is resolved relative to /. If no call to self.current_directory is made, then the working directory in the child will be /.