diff options
| author | Kamal Marhubi <kamal@marhubi.com> | 2016-01-15 15:29:45 -0500 |
|---|---|---|
| committer | Kamal Marhubi <kamal@marhubi.com> | 2016-02-03 10:54:29 -0500 |
| commit | 7c64bf1b9b6e8e97ab652a4922f1c0e68ebc77f0 (patch) | |
| tree | 52eef97ff332e10c18c7469df5d296fc4f64ef0f /src/libstd/sys/unix | |
| parent | 28bed3f5e64dfc083dc193412b65d95533a61d72 (diff) | |
| download | rust-7c64bf1b9b6e8e97ab652a4922f1c0e68ebc77f0.tar.gz rust-7c64bf1b9b6e8e97ab652a4922f1c0e68ebc77f0.zip | |
std: Properly handle interior NULs in std::process
This reports an error at the point of calling `Command::spawn()` or one of its equivalents. Fixes https://github.com/rust-lang/rust/issues/30858 Fixes https://github.com/rust-lang/rust/issues/30862
Diffstat (limited to 'src/libstd/sys/unix')
| -rw-r--r-- | src/libstd/sys/unix/ext/process.rs | 6 | ||||
| -rw-r--r-- | src/libstd/sys/unix/process.rs | 72 |
2 files changed, 60 insertions, 18 deletions
diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index e1111f25db7..212aeb0406e 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -49,17 +49,17 @@ pub trait CommandExt { #[stable(feature = "rust1", since = "1.0.0")] impl CommandExt for process::Command { fn uid(&mut self, id: uid_t) -> &mut process::Command { - self.as_inner_mut().uid = Some(id); + self.as_inner_mut().uid(id); self } fn gid(&mut self, id: gid_t) -> &mut process::Command { - self.as_inner_mut().gid = Some(id); + self.as_inner_mut().gid(id); self } fn session_leader(&mut self, on: bool) -> &mut process::Command { - self.as_inner_mut().session_leader = on; + self.as_inner_mut().session_leader(on); self } } diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index 4a91cece143..04b39f0851a 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -31,57 +31,95 @@ use sys::{self, cvt, cvt_r}; #[derive(Clone)] pub struct Command { - pub program: CString, - pub args: Vec<CString>, - pub env: Option<HashMap<OsString, OsString>>, - pub cwd: Option<CString>, - pub uid: Option<uid_t>, - pub gid: Option<gid_t>, - pub session_leader: bool, + program: CString, + args: Vec<CString>, + env: Option<HashMap<OsString, OsString>>, // Guaranteed to have no NULs. + cwd: Option<CString>, + uid: Option<uid_t>, + gid: Option<gid_t>, + session_leader: bool, + saw_nul: bool, } impl Command { pub fn new(program: &OsStr) -> Command { + let mut saw_nul = false; Command { - program: os2c(program), + program: os2c(program, &mut saw_nul), args: Vec::new(), env: None, cwd: None, uid: None, gid: None, session_leader: false, + saw_nul: saw_nul, } } pub fn arg(&mut self, arg: &OsStr) { - self.args.push(os2c(arg)); + self.args.push(os2c(arg, &mut self.saw_nul)); } pub fn args<'a, I: Iterator<Item = &'a OsStr>>(&mut self, args: I) { - self.args.extend(args.map(os2c)); + let mut saw_nul = self.saw_nul; + self.args.extend(args.map(|arg| os2c(arg, &mut saw_nul))); + self.saw_nul = saw_nul; } fn init_env_map(&mut self) { if self.env.is_none() { + // Will not add NULs to env: preexisting environment will not contain any. self.env = Some(env::vars_os().collect()); } } pub fn env(&mut self, key: &OsStr, val: &OsStr) { + let k = OsString::from_vec(os2c(key, &mut self.saw_nul).into_bytes()); + let v = OsString::from_vec(os2c(val, &mut self.saw_nul).into_bytes()); + + // Will not add NULs to env: return without inserting if any were seen. + if self.saw_nul { + return; + } + self.init_env_map(); - self.env.as_mut().unwrap().insert(key.to_os_string(), val.to_os_string()); + self.env.as_mut() + .unwrap() + .insert(k, v); } pub fn env_remove(&mut self, key: &OsStr) { self.init_env_map(); - self.env.as_mut().unwrap().remove(&key.to_os_string()); + self.env.as_mut().unwrap().remove(key); } pub fn env_clear(&mut self) { self.env = Some(HashMap::new()) } pub fn cwd(&mut self, dir: &OsStr) { - self.cwd = Some(os2c(dir)); + self.cwd = Some(os2c(dir, &mut self.saw_nul)); + } + pub fn uid(&mut self, id: uid_t) { + self.uid = Some(id); } + pub fn gid(&mut self, id: gid_t) { + self.gid = Some(id); + } + pub fn session_leader(&mut self, session_leader: bool) { + self.session_leader = session_leader; + } +} + +fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString { + CString::new(s.as_bytes()).unwrap_or_else(|_e| { + *saw_nul = true; + CString::new("<string-with-nul>").unwrap() + }) } -fn os2c(s: &OsStr) -> CString { - CString::new(s.as_bytes()).unwrap() +impl fmt::Debug for Command { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(write!(f, "{:?}", self.program)); + for arg in &self.args { + try!(write!(f, " {:?}", arg)); + } + Ok(()) + } } //////////////////////////////////////////////////////////////////////////////// @@ -175,6 +213,10 @@ impl Process { in_fd: Stdio, out_fd: Stdio, err_fd: Stdio) -> io::Result<Process> { + if cfg.saw_nul { + return Err(io::Error::new(ErrorKind::InvalidInput, "nul byte found in provided data")); + } + let dirp = cfg.cwd.as_ref().map(|c| c.as_ptr()).unwrap_or(ptr::null()); let (envp, _a, _b) = make_envp(cfg.env.as_ref()); |
