diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 4b41572c1a10..83734c926ee1 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -19,7 +19,7 @@ pub use self::DebugInfoLevel::*; use session::{early_error, early_warn, Session}; use session::search_paths::SearchPaths; -use rustc_back::{LinkerFlavor, PanicStrategy}; +use rustc_back::{LinkerFlavor, PanicStrategy, RelroLevel}; use rustc_back::target::Target; use lint; use middle::cstore; @@ -654,6 +654,8 @@ macro_rules! options { Some("a number"); pub const parse_panic_strategy: Option<&'static str> = Some("either `panic` or `abort`"); + pub const parse_relro_level: Option<&'static str> = + Some("one of: `full`, `partial`, or `off`"); pub const parse_sanitizer: Option<&'static str> = Some("one of: `address`, `leak`, `memory` or `thread`"); pub const parse_linker_flavor: Option<&'static str> = @@ -665,7 +667,7 @@ macro_rules! options { #[allow(dead_code)] mod $mod_set { use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer}; - use rustc_back::{LinkerFlavor, PanicStrategy}; + use rustc_back::{LinkerFlavor, PanicStrategy, RelroLevel}; $( pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool { @@ -786,6 +788,16 @@ macro_rules! options { true } + fn parse_relro_level(slot: &mut Option, v: Option<&str>) -> bool { + match v { + Some("full") => *slot = Some(RelroLevel::Full), + Some("partial") => *slot = Some(RelroLevel::Partial), + Some("off") => *slot = Some(RelroLevel::Off), + _ => return false + } + true + } + fn parse_sanitizer(slote: &mut Option, v: Option<&str>) -> bool { match v { Some("address") => *slote = Some(Sanitizer::Address), @@ -869,6 +881,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, "disable the use of the redzone"), relocation_model: Option = (None, parse_opt_string, [TRACKED], "choose the relocation model to use (rustc --print relocation-models for details)"), + relro_level: Option = (None, parse_relro_level, [TRACKED], + "choose which RELRO level to use"), code_model: Option = (None, parse_opt_string, [TRACKED], "choose the code model to use (rustc --print code-models for details)"), metadata: Vec = (Vec::new(), parse_list, [TRACKED], @@ -1776,7 +1790,7 @@ mod dep_tracking { use super::{Passes, CrateType, OptLevel, DebugInfoLevel, OutputTypes, Externs, ErrorOutputType, Sanitizer}; use syntax::feature_gate::UnstableFeatures; - use rustc_back::PanicStrategy; + use rustc_back::{PanicStrategy, RelroLevel}; pub trait DepTrackingHash { fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType); @@ -1818,11 +1832,13 @@ mod dep_tracking { impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option<(String, u64)>); impl_dep_tracking_hash_via_hash!(Option); + impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(CrateType); impl_dep_tracking_hash_via_hash!(PanicStrategy); + impl_dep_tracking_hash_via_hash!(RelroLevel); impl_dep_tracking_hash_via_hash!(Passes); impl_dep_tracking_hash_via_hash!(OptLevel); impl_dep_tracking_hash_via_hash!(DebugInfoLevel); @@ -1904,7 +1920,7 @@ mod tests { use std::path::PathBuf; use std::rc::Rc; use super::{OutputType, OutputTypes, Externs}; - use rustc_back::PanicStrategy; + use rustc_back::{PanicStrategy, RelroLevel}; use syntax::symbol::Symbol; fn optgroups() -> getopts::Options { @@ -2434,6 +2450,10 @@ mod tests { opts.cg.relocation_model = Some(String::from("relocation model")); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); + opts = reference.clone(); + opts.cg.relro_level = Some(RelroLevel::Full); + assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); + opts = reference.clone(); opts.cg.code_model = Some(String::from("code model")); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index c776f28ecd0b..7ec9b77af4bf 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -114,3 +114,30 @@ impl ToJson for PanicStrategy { } } } + +#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] +pub enum RelroLevel { + Full, + Partial, + Off, +} + +impl RelroLevel { + pub fn desc(&self) -> &str { + match *self { + RelroLevel::Full => "full", + RelroLevel::Partial => "partial", + RelroLevel::Off => "off", + } + } +} + +impl ToJson for RelroLevel { + fn to_json(&self) -> Json { + match *self { + RelroLevel::Full => "full".to_json(), + RelroLevel::Partial => "partial".to_json(), + RelroLevel::Off => "off".to_json(), + } + } +} diff --git a/src/librustc_back/target/bitrig_base.rs b/src/librustc_back/target/bitrig_base.rs index 5a0ab83cd723..45ceb2d5a604 100644 --- a/src/librustc_back/target/bitrig_base.rs +++ b/src/librustc_back/target/bitrig_base.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use target::{TargetOptions, RelroLevel}; use std::default::Default; pub fn opts() -> TargetOptions { @@ -19,7 +19,7 @@ pub fn opts() -> TargetOptions { linker_is_gnu: true, has_rpath: true, position_independent_executables: true, - full_relro: true, + relro_level: RelroLevel::Full, .. Default::default() } diff --git a/src/librustc_back/target/dragonfly_base.rs b/src/librustc_back/target/dragonfly_base.rs index ca116e82379b..21dca99aa500 100644 --- a/src/librustc_back/target/dragonfly_base.rs +++ b/src/librustc_back/target/dragonfly_base.rs @@ -9,7 +9,7 @@ // except according to those terms. use LinkerFlavor; -use target::{LinkArgs, TargetOptions}; +use target::{LinkArgs, TargetOptions, RelroLevel}; use std::default::Default; pub fn opts() -> TargetOptions { @@ -33,7 +33,7 @@ pub fn opts() -> TargetOptions { has_rpath: true, pre_link_args: args, position_independent_executables: true, - full_relro: true, + relro_level: RelroLevel::Full, exe_allocation_crate: super::maybe_jemalloc(), .. Default::default() } diff --git a/src/librustc_back/target/freebsd_base.rs b/src/librustc_back/target/freebsd_base.rs index ca116e82379b..21dca99aa500 100644 --- a/src/librustc_back/target/freebsd_base.rs +++ b/src/librustc_back/target/freebsd_base.rs @@ -9,7 +9,7 @@ // except according to those terms. use LinkerFlavor; -use target::{LinkArgs, TargetOptions}; +use target::{LinkArgs, TargetOptions, RelroLevel}; use std::default::Default; pub fn opts() -> TargetOptions { @@ -33,7 +33,7 @@ pub fn opts() -> TargetOptions { has_rpath: true, pre_link_args: args, position_independent_executables: true, - full_relro: true, + relro_level: RelroLevel::Full, exe_allocation_crate: super::maybe_jemalloc(), .. Default::default() } diff --git a/src/librustc_back/target/haiku_base.rs b/src/librustc_back/target/haiku_base.rs index c52b28708c36..21410dcd4126 100644 --- a/src/librustc_back/target/haiku_base.rs +++ b/src/librustc_back/target/haiku_base.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use target::{TargetOptions, RelroLevel}; use std::default::Default; pub fn opts() -> TargetOptions { @@ -18,7 +18,7 @@ pub fn opts() -> TargetOptions { executables: true, has_rpath: false, target_family: Some("unix".to_string()), - full_relro: true, + relro_level: RelroLevel::Full, linker_is_gnu: true, no_integrated_as: true, .. Default::default() diff --git a/src/librustc_back/target/linux_base.rs b/src/librustc_back/target/linux_base.rs index e4e7f062f88f..52f700ac7519 100644 --- a/src/librustc_back/target/linux_base.rs +++ b/src/librustc_back/target/linux_base.rs @@ -9,7 +9,7 @@ // except according to those terms. use LinkerFlavor; -use target::{LinkArgs, TargetOptions}; +use target::{LinkArgs, TargetOptions, RelroLevel}; use std::default::Default; pub fn opts() -> TargetOptions { @@ -36,7 +36,7 @@ pub fn opts() -> TargetOptions { has_rpath: true, pre_link_args: args, position_independent_executables: true, - full_relro: true, + relro_level: RelroLevel::Full, exe_allocation_crate: super::maybe_jemalloc(), has_elf_tls: true, .. Default::default() diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 673c01f4b7e7..a07f5d154a18 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -50,7 +50,7 @@ use std::default::Default; use std::io::prelude::*; use syntax::abi::{Abi, lookup as lookup_abi}; -use {LinkerFlavor, PanicStrategy}; +use {LinkerFlavor, PanicStrategy, RelroLevel}; mod android_base; mod apple_base; @@ -367,9 +367,10 @@ pub struct TargetOptions { /// the functions in the executable are not randomized and can be used /// during an exploit of a vulnerability in any code. pub position_independent_executables: bool, - /// Full RELRO makes the dynamic linker resolve all symbols at startup and marks the GOT - /// read-only before starting the program, preventing overwriting the GOT. - pub full_relro: bool, + /// Either partial, full, or off. Full RELRO makes the dynamic linker + /// resolve all symbols at startup and marks the GOT read-only before + /// starting the program, preventing overwriting the GOT. + pub relro_level: RelroLevel, /// Format that archives should be emitted in. This affects whether we use /// LLVM to assemble an archive or fall back to the system linker, and /// currently only "gnu" is used to fall into LLVM. Unknown strings cause @@ -457,7 +458,7 @@ impl Default for TargetOptions { has_rpath: false, no_default_libraries: true, position_independent_executables: false, - full_relro: false, + relro_level: RelroLevel::Off, pre_link_objects_exe: Vec::new(), pre_link_objects_dll: Vec::new(), post_link_objects: Vec::new(), @@ -584,6 +585,20 @@ impl Target { Some(Ok(())) })).unwrap_or(Ok(())) } ); + ($key_name:ident, RelroLevel) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| { + match s { + "full" => base.options.$key_name = RelroLevel::Full, + "partial" => base.options.$key_name = RelroLevel::Partial, + "off" => base.options.$key_name = RelroLevel::Off, + _ => return Some(Err(format!("'{}' is not a valid value for \ + relro-level. Use 'full', 'partial, or 'off'.", + s))), + } + Some(Ok(())) + })).unwrap_or(Ok(())) + } ); ($key_name:ident, list) => ( { let name = (stringify!($key_name)).replace("_", "-"); obj.find(&name[..]).map(|o| o.as_array() @@ -687,7 +702,7 @@ impl Target { key!(has_rpath, bool); key!(no_default_libraries, bool); key!(position_independent_executables, bool); - key!(full_relro, bool); + try!(key!(relro_level, RelroLevel)); key!(archive_format); key!(allow_asm, bool); key!(custom_unwind_resume, bool); @@ -875,7 +890,7 @@ impl ToJson for Target { target_option_val!(has_rpath); target_option_val!(no_default_libraries); target_option_val!(position_independent_executables); - target_option_val!(full_relro); + target_option_val!(relro_level); target_option_val!(archive_format); target_option_val!(allow_asm); target_option_val!(custom_unwind_resume); diff --git a/src/librustc_back/target/netbsd_base.rs b/src/librustc_back/target/netbsd_base.rs index 1d7d1b36008a..1cb311371938 100644 --- a/src/librustc_back/target/netbsd_base.rs +++ b/src/librustc_back/target/netbsd_base.rs @@ -9,7 +9,7 @@ // except according to those terms. use LinkerFlavor; -use target::{LinkArgs, TargetOptions}; +use target::{LinkArgs, TargetOptions, RelroLevel}; use std::default::Default; pub fn opts() -> TargetOptions { @@ -33,7 +33,7 @@ pub fn opts() -> TargetOptions { has_rpath: true, pre_link_args: args, position_independent_executables: true, - full_relro: true, + relro_level: RelroLevel::Full, .. Default::default() } } diff --git a/src/librustc_back/target/openbsd_base.rs b/src/librustc_back/target/openbsd_base.rs index df17f853b3b3..a5f8e7ae5f91 100644 --- a/src/librustc_back/target/openbsd_base.rs +++ b/src/librustc_back/target/openbsd_base.rs @@ -9,7 +9,7 @@ // except according to those terms. use LinkerFlavor; -use target::{LinkArgs, TargetOptions}; +use target::{LinkArgs, TargetOptions, RelroLevel}; use std::default::Default; pub fn opts() -> TargetOptions { @@ -34,7 +34,7 @@ pub fn opts() -> TargetOptions { is_like_openbsd: true, pre_link_args: args, position_independent_executables: true, - full_relro: true, + relro_level: RelroLevel::Full, .. Default::default() } } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 238b7fd2e19b..e4ef0c73c539 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -27,7 +27,7 @@ use rustc::dep_graph::{DepKind, DepNode}; use rustc::hir::def_id::CrateNum; use rustc::hir::svh::Svh; use rustc_back::tempdir::TempDir; -use rustc_back::PanicStrategy; +use rustc_back::{PanicStrategy, RelroLevel}; use rustc_incremental::IncrementalHashesMap; use context::get_reloc_model; use llvm; @@ -1029,8 +1029,18 @@ fn link_args(cmd: &mut Linker, } } - if t.options.full_relro { - cmd.full_relro(); + let relro_level = match sess.opts.cg.relro_level { + Some(level) => level, + None => t.options.relro_level, + }; + match relro_level { + RelroLevel::Full => { + cmd.full_relro(); + }, + RelroLevel::Partial => { + cmd.partial_relro(); + }, + RelroLevel::Off => {}, } // Pass optimization flags down to the linker. diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 025b57956594..89ebfd0d254e 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -104,6 +104,7 @@ pub trait Linker { fn add_object(&mut self, path: &Path); fn gc_sections(&mut self, keep_metadata: bool); fn position_independent_executable(&mut self); + fn partial_relro(&mut self); fn full_relro(&mut self); fn optimize(&mut self); fn debuginfo(&mut self); @@ -176,6 +177,7 @@ impl<'a> Linker for GccLinker<'a> { fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); } fn add_object(&mut self, path: &Path) { self.cmd.arg(path); } fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); } + fn partial_relro(&mut self) { self.linker_arg("-z,relro"); } fn full_relro(&mut self) { self.linker_arg("-z,relro,-z,now"); } fn args(&mut self, args: &[String]) { self.cmd.args(args); } @@ -430,6 +432,10 @@ impl<'a> Linker for MsvcLinker<'a> { // noop } + fn partial_relro(&mut self) { + // noop + } + fn full_relro(&mut self) { // noop } @@ -601,6 +607,10 @@ impl<'a> Linker for EmLinker<'a> { // noop } + fn partial_relro(&mut self) { + // noop + } + fn full_relro(&mut self) { // noop }