From 6b16797322545a66f8021229f93ff99aca9035e1 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Sun, 25 Mar 2018 18:07:45 -0700 Subject: [PATCH 1/6] compiletest: show rustc env when verbose --- src/tools/compiletest/src/runtest.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 85434bb8a69b8..b8c09901e55e0 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1535,6 +1535,7 @@ impl<'test> TestCx<'test> { } } + logv(self.config, format!("rustc env {:?}", self.props.rustc_env)); rustc.envs(self.props.rustc_env.clone()); self.compose_and_run( rustc, From 8780e3fdf27178b6035842c2c2c2a2c21361cfd7 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Sun, 25 Mar 2018 19:03:34 +0100 Subject: [PATCH 2/6] First cut of process environment sandbox for rustc The sandbox can control which environment variables are readable and can set their values. It also maintains a set of path prefixes which can be used for file access; accessing a path without one of the defined prefixes is disallowed. --- src/librustc_env_sandbox/Cargo.toml | 12 ++ src/librustc_env_sandbox/lib.rs | 282 ++++++++++++++++++++++++++++ 2 files changed, 294 insertions(+) create mode 100644 src/librustc_env_sandbox/Cargo.toml create mode 100644 src/librustc_env_sandbox/lib.rs diff --git a/src/librustc_env_sandbox/Cargo.toml b/src/librustc_env_sandbox/Cargo.toml new file mode 100644 index 0000000000000..d9f393318097c --- /dev/null +++ b/src/librustc_env_sandbox/Cargo.toml @@ -0,0 +1,12 @@ +[package] +authors = ["The Rust Project Developers"] +name = "env_sandbox" +version = "0.0.0" + +[lib] +name = "env_sandbox" +path = "lib.rs" +crate-type = ["dylib"] + +[dev-dependencies] +tempdir = "0.3" diff --git a/src/librustc_env_sandbox/lib.rs b/src/librustc_env_sandbox/lib.rs new file mode 100644 index 0000000000000..c135a7cccec1b --- /dev/null +++ b/src/librustc_env_sandbox/lib.rs @@ -0,0 +1,282 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![deny(warnings)] + +#[cfg(test)] +extern crate tempdir; + +use std::collections::HashMap; +use std::env; +use std::fs::{self, File}; +use std::io; +use std::path::{Path, PathBuf}; + +// Set up a sandbox to access the compiler's system environment. This includes: +// - what appears in the environment (ie, visible to the `env!()` and `option_env!()` macros) +// - constrain the path prefixs files may be included from + +/// Aspects of the compiler's environment which can be sandboxed. If the field is `None`, +/// is unconstrained. +#[derive(Debug, Clone, Default)] +pub struct EnvSandbox { + /// Set of environment variables available. If a variable appears with a `None` value + /// then it means the variable can be read from the real system environment. Otherwise + /// the variable is as it has been defined here. + env: Option>>, + /// Set of paths from which files can be included. These are normalized to the real path, + /// so all files being opened are also opened via normalized real paths. + paths: Option>, +} + +/// Builder for an `EnvSandbox` +pub struct EnvSandboxBuilder(EnvSandbox); + +impl EnvSandboxBuilder { + /// Construct a new `EnvSandboxBuilder`. + pub fn new() -> Self { + EnvSandboxBuilder(EnvSandbox { + env: None, + paths: None, + }) + } + + fn env_add_filter(&mut self, var: K, val: Option) + where + String: From, + String: From, + { + let var = String::from(var); + let val = val.map(String::from); + + let mut env = self.0.env.take().unwrap_or(HashMap::new()); + + env.insert(var, val); + + self.0.env = Some(env); + } + + /// Define a new name->value mapping + pub fn env_define(&mut self, var: K, val: V) -> &mut Self + where + String: From, + String: From, + { + self.env_add_filter(var, Some(val)); + self + } + + /// Allow a give name to be accessed from the environment + pub fn env_allow(&mut self, var: K) -> &mut Self + where + String: From, + { + self.env_add_filter::<_, String>(var, None); + self + } + + /// Set up an empty mapping, prohibiting access to the process environment without + /// defining any new variables. + pub fn env_clear(&mut self) -> &mut Self { + self.0.env = Some(HashMap::new()); + self + } + + /// Clear all path prefixes, leaving no valid prefixes. This prevents all file access. + pub fn paths_clear(&mut self) -> &mut Self { + self.0.paths = Some(Vec::new()); + self + } + + /// Add a path prefix to the allowed set. The path must exist so that it can + /// be canonicalized. + pub fn path_add>(&mut self, path: P) -> io::Result<&mut Self> { + let path = path.as_ref(); + let path = fs::canonicalize(path)?; + + let mut paths = self.0.paths.take().unwrap_or(Vec::new()); + paths.push(path); + self.0.paths = Some(paths); + + Ok(self) + } + + /// Construct an `EnvSandbox` from the builder + pub fn build(self) -> EnvSandbox { + self.0 + } +} + +impl EnvSandbox { + /// Get an environment variable, either from the real environment + /// or from the locally defined sandbox variables. + pub fn env_get(&self, var: &str) -> Option { + match &self.env { + &None => env::var(var).ok(), + &Some(ref map) => match map.get(var) { + None => None, + Some(&Some(ref val)) => Some(val.to_string()), + Some(&None) => env::var(var).ok(), + }, + } + } + + /// Return true if a given path has a valid prefix. Fails if the path + /// can't be canonicalized. + pub fn path_ok>(&self, path: P) -> io::Result { + let path = path.as_ref(); + let fullpath = fs::canonicalize(path)?; + + let ret = if let Some(ref paths) = self.paths { + paths.iter().any(|p| fullpath.starts_with(p)) + } else { + true + }; + Ok(ret) + } + + /// Map a path to itself if it has a valid prefix, otherwise return a suitable + /// error. + pub fn path_lookup

(&self, path: P) -> io::Result

+ where + P: AsRef, + { + if self.path_ok(&path)? { + Ok(path) + } else { + Err(io::Error::new( + io::ErrorKind::PermissionDenied, + "path does not have a valid prefix", + )) + } + } + + /// Open a path for reading if it has a valid prefix. + pub fn path_open>(&self, path: P) -> io::Result { + File::open(self.path_lookup(path)?) + } +} + +#[cfg(test)] +mod test { + use super::*; + + use std::env; + use tempdir::TempDir; + + #[test] + fn test_env() { + env::set_var("ZUBZUB", "ZIBZIB"); + + let sb = EnvSandbox::default(); + + assert_eq!(env::var("ZUBZUB"), Ok("ZIBZIB".to_string())); + assert_eq!(sb.env_get("ZUBZUB"), Some("ZIBZIB".to_string())); + } + + #[test] + fn test_env_filter() { + let mut sb = EnvSandboxBuilder::new(); + + sb.env_define("FOO", "BAR"); + + let sb = sb.build(); + + assert_eq!(sb.env_get("FOO"), Some("BAR".to_string())); + assert_eq!(sb.env_get("BLAHBLAH"), None); + } + + #[test] + fn test_env_allow() { + let mut sb = EnvSandboxBuilder::new(); + + sb.env_define("FOO", "BAR") + .env_allow("BLOP") + .env_allow("GLUB"); + + let sb = sb.build(); + + env::set_var("ZUBZUB", "ZIBZIB"); + env::set_var("BLOP", "Blub"); + env::remove_var("GLUB"); + + assert_eq!(sb.env_get("FOO"), Some("BAR".to_string())); + assert_eq!(sb.env_get("ZUBZUB"), None); + assert_eq!(sb.env_get("BLOP"), Some("Blub".to_string())); + assert_eq!(sb.env_get("GLUB"), None); + } + + #[test] + fn test_env_clear() { + let mut sb = EnvSandboxBuilder::new(); + + sb.env_define("FOO", "BAR") + .env_allow("BLOP") + .env_allow("GLUB") + .env_clear(); + + let sb = sb.build(); + + env::set_var("ZUBZUB", "ZIBZIB"); + env::set_var("BLOP", "Blub"); + env::remove_var("GLUB"); + + assert_eq!(sb.env_get("FOO"), None); + assert_eq!(sb.env_get("ZUBZUB"), None); + assert_eq!(sb.env_get("BLOP"), None); + assert_eq!(sb.env_get("GLUB"), None); + } + + #[test] + fn test_path() { + let dir = TempDir::new("test").expect("tempdir failed"); + let subdir = dir.path().join("subdir"); + fs::create_dir(&subdir).expect("subdir failed"); + + let sb = EnvSandbox::default(); + + assert!(sb.path_ok(&dir).unwrap()); + assert!(sb.path_ok(dir.path().parent().unwrap()).unwrap()); + assert!(sb.path_ok(&subdir).unwrap()); + assert!(sb.path_ok("/").unwrap()); + } + + #[test] + fn test_path_filter() { + let dir = TempDir::new("test").expect("tempdir failed"); + let subdir = dir.path().join("subdir"); + fs::create_dir(&subdir).expect("subdir failed"); + + let mut sb = EnvSandboxBuilder::new(); + sb.path_add(&dir).unwrap(); + let sb = sb.build(); + + assert!(sb.path_ok(&dir).unwrap()); + assert!(!sb.path_ok(dir.path().parent().unwrap()).unwrap()); + assert!(sb.path_ok(&subdir).unwrap()); + assert!(!sb.path_ok("/").unwrap()); + } + + #[test] + fn test_path_clear() { + let dir = TempDir::new("test").expect("tempdir failed"); + let subdir = dir.path().join("subdir"); + fs::create_dir(&subdir).expect("subdir failed"); + + let mut sb = EnvSandboxBuilder::new(); + sb.path_add(&dir).unwrap(); + sb.paths_clear(); + let sb = sb.build(); + + assert!(!sb.path_ok(&dir).unwrap()); + assert!(!sb.path_ok(dir.path().parent().unwrap()).unwrap()); + assert!(!sb.path_ok(&subdir).unwrap()); + assert!(!sb.path_ok("/").unwrap()); + } +} From 13904d5a2e055d3ec57c77b54d25429653407f8d Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Sun, 25 Mar 2018 20:57:19 +0100 Subject: [PATCH 3/6] Add command-line options to configure environment sandbox The environment sandbox controls access to environment variables and which path prefixes are available for opening from source (ie, with the env!() and include!() class of macros). By default, it does nothing. However, if you configure some sandbox options then they will override the default-open mode of operation. The options are: --env-clear - clear entire environment, making all env!() operations fail --env-allow VAR - allow a specific environment variable to be used --env-define VAR=VAL - define the value of an environment variable for env!() --clear-include-prefixes - clear all valid prefixes, making all include!() operations fail --include-prefix PATH - define a path prefix that all include files must start with These options are cumulative. The environment sandboxing is different from controlling the environment that's present when rustc is invoked, say with the "env" command. Sandboxing allows the environment used by rustc - such as PATH or LD_LIBRARY_PATH (or equiv) - versus the environment that's available to the compiled Rust source itself. (This change just collects the options and sets up the EnvSandbox, but does not implement any constraints.) --- src/Cargo.lock | 8 +++++ src/librustc/Cargo.toml | 1 + src/librustc/lib.rs | 1 + src/librustc/session/config.rs | 61 ++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+) diff --git a/src/Cargo.lock b/src/Cargo.lock index 5fd8334e8ed9a..b0e34418c1d0e 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -613,6 +613,13 @@ dependencies = [ "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "env_sandbox" +version = "0.0.0" +dependencies = [ + "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "error-chain" version = "0.11.0" @@ -1692,6 +1699,7 @@ dependencies = [ "backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_sandbox 0.0.0", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "fmt_macros 0.0.0", "graphviz 0.0.0", diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 2aae0f24d4849..6037808edc216 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -27,6 +27,7 @@ syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } backtrace = "0.3.3" byteorder = { version = "1.1", features = ["i128"]} +env_sandbox = { path = "../librustc_env_sandbox" } # Note that these dependencies are a lie, they're just here to get linkage to # work. diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index bb495049483ac..545e41fa5fd04 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -91,6 +91,7 @@ extern crate rustc_errors as errors; extern crate syntax_pos; extern crate jobserver; extern crate proc_macro; +extern crate env_sandbox; extern crate serialize as rustc_serialize; // used by deriving diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 456e83f4700e4..bbac05a3af5d3 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -38,6 +38,8 @@ use syntax::feature_gate::UnstableFeatures; use errors::{ColorConfig, FatalError, Handler}; +use env_sandbox::{EnvSandboxBuilder, EnvSandbox}; + use getopts; use std::collections::{BTreeMap, BTreeSet}; use std::collections::btree_map::Iter as BTreeMapIter; @@ -413,6 +415,9 @@ top_level_options!( // Remap source path prefixes in all output (messages, object files, debug, etc) remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED], edition: Edition [TRACKED], + + // Environment sandbox for process envvars and include path prefixes + env_sb: EnvSandbox [UNTRACKED], } ); @@ -593,6 +598,7 @@ pub fn basic_options() -> Options { cli_forced_thinlto_off: false, remap_path_prefix: Vec::new(), edition: DEFAULT_EDITION, + env_sb: EnvSandbox::default(), } } @@ -1653,6 +1659,34 @@ pub fn rustc_optgroups() -> Vec { "Remap source names in all output (compiler messages and output files)", "FROM=TO", ), + opt::multi_s( + "", + "env-allow", + "Allow a specific environment variable to be accessed with an env!() macro", + "ENVVAR", + ), + opt::multi_s( + "", + "env-define", + "Define an environment variable for reading with an env!() macro", + "ENVVAR=VALUE", + ), + opt::flag_s( + "", + "env-clear", + "Clear all environment, and prevent access to process environment", + ), + opt::multi_s( + "", + "include-prefix", + "Define a valid prefix for include!() macros", + "PATH", + ), + opt::flag_s( + "", + "clear-include-prefixes", + "Clear all path prefixes, disallowing access to all files", + ), ]); opts } @@ -2161,6 +2195,32 @@ pub fn build_session_options_and_crate_config( }) .collect(); + let mut env_sb = EnvSandboxBuilder::new(); + + if matches.opt_present("env-clear") { + env_sb.env_clear(); + } + for env in matches.opt_strs("env-allow") { + env_sb.env_allow(env); + } + for envvar in matches.opt_strs("env-define") { + let envvar: Vec<_> = envvar.splitn(2, '=').collect(); + if envvar.len() != 2 { + early_error(error_format, "--env-define must contain '=' between ENVVAR and VALUE"); + } + env_sb.env_define(envvar[0], envvar[1]); + } + + if matches.opt_present("clear-include-prefixes") { + env_sb.paths_clear(); + } + for pathpfx in matches.opt_strs("include-prefix") { + if let Err(err) = env_sb.path_add(pathpfx) { + early_error(error_format, &format!("--include-prefix path error: {}", err)); + } + } + let env_sb = env_sb.build(); + ( Options { crate_types, @@ -2191,6 +2251,7 @@ pub fn build_session_options_and_crate_config( cli_forced_thinlto_off: disable_thinlto, remap_path_prefix, edition, + env_sb, }, cfg, ) From b40ae5fe22789a12d46887b59d65e5f926d327a9 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Sun, 25 Mar 2018 21:54:19 +0100 Subject: [PATCH 4/6] Wire EnvSandbox into the ParseSess --- src/Cargo.lock | 1 + src/librustc/session/mod.rs | 3 ++- src/libsyntax/Cargo.toml | 1 + src/libsyntax/lib.rs | 1 + src/libsyntax/parse/lexer/mod.rs | 2 ++ src/libsyntax/parse/mod.rs | 13 +++++++++++-- 6 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index b0e34418c1d0e..bd7176721095e 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2488,6 +2488,7 @@ name = "syntax" version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_sandbox 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", "rustc_data_structures 0.0.0", diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 3bd2bb3c8beb0..56a5f618aa4a8 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -1052,7 +1052,8 @@ pub fn build_session_( }; let target_cfg = config::build_target_config(&sopts, &span_diagnostic); - let p_s = parse::ParseSess::with_span_handler(span_diagnostic, codemap); + let env_sb = Lrc::new(sopts.env_sb.clone()); + let p_s = parse::ParseSess::with_span_handler(span_diagnostic, codemap, env_sb); let default_sysroot = match sopts.maybe_sysroot { Some(_) => None, None => Some(filesearch::get_or_default_sysroot()), diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index 8c24f36615bd2..6120eb68c9eb1 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -17,3 +17,4 @@ syntax_pos = { path = "../libsyntax_pos" } rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } rustc_errors = { path = "../librustc_errors" } rustc_data_structures = { path = "../librustc_data_structures" } +env_sandbox = { path = "../librustc_env_sandbox" } \ No newline at end of file diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index ad98e2a6b71ad..ea445171be44b 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -40,6 +40,7 @@ pub extern crate rustc_errors as errors; extern crate syntax_pos; extern crate rustc_data_structures; #[macro_use] extern crate scoped_tls; +extern crate env_sandbox; extern crate serialize as rustc_serialize; // used by deriving diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 22a0261d8c6b1..54525d5828d88 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1787,6 +1787,7 @@ mod tests { use diagnostics::plugin::ErrorMap; use rustc_data_structures::sync::Lock; use with_globals; + use env_sandbox::EnvSandbox; fn mk_sess(cm: Lrc) -> ParseSess { let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()), Some(cm.clone()), @@ -1802,6 +1803,7 @@ mod tests { raw_identifier_spans: Lock::new(Vec::new()), registered_diagnostics: Lock::new(ErrorMap::new()), non_modrs_mods: Lock::new(vec![]), + env_sandbox: Lrc::new(EnvSandbox::default()), } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 0397c3297db0a..adcc58fd36af7 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -22,6 +22,7 @@ use str::char_at; use symbol::Symbol; use tokenstream::{TokenStream, TokenTree}; use diagnostics::plugin::ErrorMap; +use env_sandbox::EnvSandbox; use std::collections::HashSet; use std::iter; @@ -57,6 +58,7 @@ pub struct ParseSess { /// Used to determine and report recursive mod inclusions included_mod_stack: Lock>, code_map: Lrc, + env_sandbox: Lrc, } impl ParseSess { @@ -66,10 +68,12 @@ impl ParseSess { true, false, Some(cm.clone())); - ParseSess::with_span_handler(handler, cm) + let env_sb = Lrc::new(EnvSandbox::default()); + ParseSess::with_span_handler(handler, cm, env_sb) } - pub fn with_span_handler(handler: Handler, code_map: Lrc) -> ParseSess { + pub fn with_span_handler(handler: Handler, code_map: Lrc, env_sandbox: Lrc) + -> ParseSess { ParseSess { span_diagnostic: handler, unstable_features: UnstableFeatures::from_environment(), @@ -80,12 +84,17 @@ impl ParseSess { included_mod_stack: Lock::new(vec![]), code_map, non_modrs_mods: Lock::new(vec![]), + env_sandbox, } } pub fn codemap(&self) -> &CodeMap { &self.code_map } + + pub fn env_sandbox(&self) -> &EnvSandbox { + &self.env_sandbox + } } #[derive(Clone)] From f78f462f5e54e4898e7f7675386f43afcf158683 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Sun, 25 Mar 2018 21:54:37 +0100 Subject: [PATCH 5/6] Enforce sandbox for environment --- src/libsyntax_ext/env.rs | 18 ++++++++++-------- src/test/run-pass/sb-env.rs | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 src/test/run-pass/sb-env.rs diff --git a/src/libsyntax_ext/env.rs b/src/libsyntax_ext/env.rs index 4e1af108ab4fa..90a06d5f399a7 100644 --- a/src/libsyntax_ext/env.rs +++ b/src/libsyntax_ext/env.rs @@ -21,8 +21,6 @@ use syntax::symbol::{keywords, Symbol}; use syntax_pos::Span; use syntax::tokenstream; -use std::env; - pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) @@ -33,8 +31,10 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, }; let sp = sp.apply_mark(cx.current_expansion.mark); - let e = match env::var(&*var.as_str()) { - Err(..) => { + let env_sb = cx.parse_sess().env_sandbox(); + + let e = match env_sb.env_get(&*var.as_str()) { + None => { let lt = cx.lifetime(sp, keywords::StaticLifetime.ident()); cx.expr_path(cx.path_all(sp, true, @@ -46,7 +46,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, ast::Mutability::Immutable)], Vec::new())) } - Ok(s) => { + Some(s) => { cx.expr_call_global(sp, cx.std_path(&["option", "Option", "Some"]), vec![cx.expr_str(sp, Symbol::intern(&s))]) @@ -68,6 +68,8 @@ pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, Some(exprs) => exprs.into_iter(), }; + let env_sb = cx.parse_sess().env_sandbox(); + let var = match expr_to_string(cx, exprs.next().unwrap(), "expected string literal") { None => return DummyResult::expr(sp), Some((v, _style)) => v, @@ -87,12 +89,12 @@ pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, return DummyResult::expr(sp); } - let e = match env::var(&*var.as_str()) { - Err(_) => { + let e = match env_sb.env_get(&*var.as_str()) { + None => { cx.span_err(sp, &msg.as_str()); cx.expr_usize(sp, 0) } - Ok(s) => cx.expr_str(sp, Symbol::intern(&s)), + Some(s) => cx.expr_str(sp, Symbol::intern(&s)), }; MacEager::expr(e) } diff --git a/src/test/run-pass/sb-env.rs b/src/test/run-pass/sb-env.rs new file mode 100644 index 0000000000000..3d0a690c0af45 --- /dev/null +++ b/src/test/run-pass/sb-env.rs @@ -0,0 +1,22 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test to see how environment sandboxing is working +// rustc-env:BLOBBIE=FOO +// rustc-env:FOOBIE=BAR +// rustc-env:THINGY=OLD +// compile-flags:--env-allow BLOBBIE --env-define ZIPPIE=BLARG --env-define THINGY=NEW + +fn main() { + assert_eq!(option_env!("BLOBBIE"), Some("FOO")); // actual environment, allowed to be seen + assert_eq!(option_env!("ZIPPIE"), Some("BLARG")); // defined on command-line + assert_eq!(option_env!("THINGY"), Some("NEW")); // overridden on command-line + assert_eq!(option_env!("FOOBIE"), None); // actual environment, but not allowed to be seen +} From dc1ed74c3359e57aff255b6eff2fb65553e80d22 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Sun, 25 Mar 2018 21:54:51 +0100 Subject: [PATCH 6/6] Enforce sandbox for include --- src/libsyntax/ext/source_util.rs | 20 ++++++++++++++---- src/test/compile-fail/sb-fixtures/a/a.in | 1 + src/test/compile-fail/sb-fixtures/b/b.in | 1 + src/test/compile-fail/sb-inc-limit.rs | 17 +++++++++++++++ src/test/compile-fail/sb-inc-none.rs | 27 ++++++++++++++++++++++++ src/test/run-pass/sb-fixtures/a/a.in | 1 + src/test/run-pass/sb-fixtures/b/b.in | 1 + src/test/run-pass/sb-inc.rs | 18 ++++++++++++++++ 8 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 src/test/compile-fail/sb-fixtures/a/a.in create mode 100644 src/test/compile-fail/sb-fixtures/b/b.in create mode 100644 src/test/compile-fail/sb-inc-limit.rs create mode 100644 src/test/compile-fail/sb-inc-none.rs create mode 100644 src/test/run-pass/sb-fixtures/a/a.in create mode 100644 src/test/run-pass/sb-fixtures/b/b.in create mode 100644 src/test/run-pass/sb-inc.rs diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index d6dce63ea5e4b..d1d0c456c7675 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -21,7 +21,6 @@ use symbol::Symbol; use tokenstream; use util::small_vector::SmallVector; -use std::fs::File; use std::io::prelude::*; use std::path::PathBuf; use rustc_data_structures::sync::Lrc; @@ -99,7 +98,18 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::T None => return DummyResult::expr(sp), }; // The file will be added to the code map by the parser - let path = res_rel_file(cx, sp, file); + let path = res_rel_file(cx, sp, file.clone()); + let env_sb = cx.parse_sess().env_sandbox(); + let path = match env_sb.path_lookup(&path) { + Ok(path) => path, + Err(e) => { + cx.span_err(sp, + &format!("couldn't read {}: {}", + file, + e)); + return DummyResult::expr(sp); + } + }; let directory_ownership = DirectoryOwnership::Owned { relative: None }; let p = parse::new_sub_parser_from_file(cx.parse_sess(), &path, directory_ownership, None, sp); @@ -136,9 +146,10 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenT Some(f) => f, None => return DummyResult::expr(sp) }; + let env_sb = cx.parse_sess().env_sandbox(); let file = res_rel_file(cx, sp, file); let mut bytes = Vec::new(); - match File::open(&file).and_then(|mut f| f.read_to_end(&mut bytes)) { + match env_sb.path_open(&file).and_then(|mut f| f.read_to_end(&mut bytes)) { Ok(..) => {} Err(e) => { cx.span_err(sp, @@ -171,9 +182,10 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::Toke Some(f) => f, None => return DummyResult::expr(sp) }; + let env_sb = cx.parse_sess().env_sandbox(); let file = res_rel_file(cx, sp, file); let mut bytes = Vec::new(); - match File::open(&file).and_then(|mut f| f.read_to_end(&mut bytes)) { + match env_sb.path_open(&file).and_then(|mut f| f.read_to_end(&mut bytes)) { Err(e) => { cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e)); diff --git a/src/test/compile-fail/sb-fixtures/a/a.in b/src/test/compile-fail/sb-fixtures/a/a.in new file mode 100644 index 0000000000000..6d8b18077cc99 --- /dev/null +++ b/src/test/compile-fail/sb-fixtures/a/a.in @@ -0,0 +1 @@ +File A diff --git a/src/test/compile-fail/sb-fixtures/b/b.in b/src/test/compile-fail/sb-fixtures/b/b.in new file mode 100644 index 0000000000000..c512b6c64656b --- /dev/null +++ b/src/test/compile-fail/sb-fixtures/b/b.in @@ -0,0 +1 @@ +File B diff --git a/src/test/compile-fail/sb-inc-limit.rs b/src/test/compile-fail/sb-inc-limit.rs new file mode 100644 index 0000000000000..436efde0cf6ae --- /dev/null +++ b/src/test/compile-fail/sb-inc-limit.rs @@ -0,0 +1,17 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test to see how file sandboxing is working. This blocks all includes. +// compile-flags:--include-prefix {{src-base}}/sb-fixtures/a + +fn main() { + let _ = include_str!("sb-fixtures/a/a.in"); + let _ = include_str!("sb-fixtures/b/b.in"); //~ERROR: path does not have a valid prefix +} diff --git a/src/test/compile-fail/sb-inc-none.rs b/src/test/compile-fail/sb-inc-none.rs new file mode 100644 index 0000000000000..cc71ef68f5519 --- /dev/null +++ b/src/test/compile-fail/sb-inc-none.rs @@ -0,0 +1,27 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test to see how file sandboxing is working. This blocks all includes. +// compile-flags:--clear-include-prefixes +// revisions: include include_str include_bytes + +fn main() { + #[cfg(include)] + include!("sb-fixtures/a/a.in"); + //[include]~^ERROR path does not have a valid prefix + + #[cfg(include_str)] + let _ = include_str!("sb-fixtures/a/a.in"); + //[include_str]~^ERROR path does not have a valid prefix + + #[cfg(include_bytes)] + let _ = include_bytes!("sb-fixtures/a/a.in"); + //[include_bytes]~^ERROR path does not have a valid prefix +} diff --git a/src/test/run-pass/sb-fixtures/a/a.in b/src/test/run-pass/sb-fixtures/a/a.in new file mode 100644 index 0000000000000..6d8b18077cc99 --- /dev/null +++ b/src/test/run-pass/sb-fixtures/a/a.in @@ -0,0 +1 @@ +File A diff --git a/src/test/run-pass/sb-fixtures/b/b.in b/src/test/run-pass/sb-fixtures/b/b.in new file mode 100644 index 0000000000000..c512b6c64656b --- /dev/null +++ b/src/test/run-pass/sb-fixtures/b/b.in @@ -0,0 +1 @@ +File B diff --git a/src/test/run-pass/sb-inc.rs b/src/test/run-pass/sb-inc.rs new file mode 100644 index 0000000000000..207c23f6376ec --- /dev/null +++ b/src/test/run-pass/sb-inc.rs @@ -0,0 +1,18 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test to see how environment sandboxing is working +// compile-flags:--include-prefix {{src-base}}/sb-fixtures/a +// compile-flags:--include-prefix {{src-base}}/sb-fixtures/b/b.in + +fn main() { + assert_eq!(include_str!("sb-fixtures/a/a.in"), "File A\n"); + assert_eq!(include_str!("sb-fixtures/b/b.in"), "File B\n"); +}