Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for full RELRO #43170

Merged
merged 5 commits into from
Jul 19, 2017
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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> =
Expand All @@ -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 {
Expand Down Expand Up @@ -786,6 +788,16 @@ macro_rules! options {
true
}

fn parse_relro_level(slot: &mut Option<RelroLevel>, 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<Sanitizer>, v: Option<&str>) -> bool {
match v {
Some("address") => *slote = Some(Sanitizer::Address),
Expand Down Expand Up @@ -869,6 +881,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
"disable the use of the redzone"),
relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
"choose the relocation model to use (rustc --print relocation-models for details)"),
relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this actually start out in the list of debugging options so it goes through the normal channels for stability?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be an issue that the change in default behavior is insta-stable, while the new knob to control it is still unstable? One could use -Clink-arg=-Wl,-z,norelro to cancel the first part, but I don't think -z now has an off switch.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cuviper -z lazy is the inverse of -z now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, here I was looking only for something like -z nonow, -z notnow... :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cuviper yeah that'd be a consequence of changing the defaults. I'd also be fine not changing the defaults and adding this option to eventually get stabilized.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind the new default now that I know -Clink-arg can still undo it all if needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like a strange place to put it, but sure, I'll move it down to DebuggingOptions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kyrias oh sure yeah it's still a "codegen option" but I'd just prefer to have it start out behind -Z which is our set of unstable flags, whereas -C would be "instantly stable"

"choose which RELRO level to use"),
code_model: Option<String> = (None, parse_opt_string, [TRACKED],
"choose the code model to use (rustc --print code-models for details)"),
metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1818,11 +1832,13 @@ mod dep_tracking {
impl_dep_tracking_hash_via_hash!(Option<String>);
impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
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);
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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());
Expand Down
27 changes: 27 additions & 0 deletions src/librustc_back/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
}
}
}
3 changes: 2 additions & 1 deletion src/librustc_back/target/bitrig_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -19,6 +19,7 @@ pub fn opts() -> TargetOptions {
linker_is_gnu: true,
has_rpath: true,
position_independent_executables: true,
relro_level: RelroLevel::Full,

.. Default::default()
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_back/target/dragonfly_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -33,6 +33,7 @@ pub fn opts() -> TargetOptions {
has_rpath: true,
pre_link_args: args,
position_independent_executables: true,
relro_level: RelroLevel::Full,
exe_allocation_crate: super::maybe_jemalloc(),
.. Default::default()
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_back/target/freebsd_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -33,6 +33,7 @@ pub fn opts() -> TargetOptions {
has_rpath: true,
pre_link_args: args,
position_independent_executables: true,
relro_level: RelroLevel::Full,
exe_allocation_crate: super::maybe_jemalloc(),
.. Default::default()
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_back/target/haiku_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -18,6 +18,7 @@ pub fn opts() -> TargetOptions {
executables: true,
has_rpath: false,
target_family: Some("unix".to_string()),
relro_level: RelroLevel::Full,
linker_is_gnu: true,
no_integrated_as: true,
.. Default::default()
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_back/target/linux_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -36,6 +36,7 @@ pub fn opts() -> TargetOptions {
has_rpath: true,
pre_link_args: args,
position_independent_executables: true,
relro_level: RelroLevel::Full,
exe_allocation_crate: super::maybe_jemalloc(),
has_elf_tls: true,
.. Default::default()
Expand Down
23 changes: 22 additions & 1 deletion src/librustc_back/target/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -367,6 +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,
/// 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
Expand Down Expand Up @@ -454,6 +458,7 @@ impl Default for TargetOptions {
has_rpath: false,
no_default_libraries: true,
position_independent_executables: false,
relro_level: RelroLevel::Off,
pre_link_objects_exe: Vec::new(),
pre_link_objects_dll: Vec::new(),
post_link_objects: Vec::new(),
Expand Down Expand Up @@ -580,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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be deduplicated with parse_relro_level above?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just duplicating the way it was done for PanicStrategy, but I can look into deduplicating it later this week.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh heh good point! We should deduplicate that one as well at some point...

_ => 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()
Expand Down Expand Up @@ -683,6 +702,7 @@ impl Target {
key!(has_rpath, bool);
key!(no_default_libraries, bool);
key!(position_independent_executables, bool);
try!(key!(relro_level, RelroLevel));
key!(archive_format);
key!(allow_asm, bool);
key!(custom_unwind_resume, bool);
Expand Down Expand Up @@ -870,6 +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!(relro_level);
target_option_val!(archive_format);
target_option_val!(allow_asm);
target_option_val!(custom_unwind_resume);
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_back/target/netbsd_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -33,6 +33,7 @@ pub fn opts() -> TargetOptions {
has_rpath: true,
pre_link_args: args,
position_independent_executables: true,
relro_level: RelroLevel::Full,
.. Default::default()
}
}
3 changes: 2 additions & 1 deletion src/librustc_back/target/openbsd_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -34,6 +34,7 @@ pub fn opts() -> TargetOptions {
is_like_openbsd: true,
pre_link_args: args,
position_independent_executables: true,
relro_level: RelroLevel::Full,
.. Default::default()
}
}
6 changes: 5 additions & 1 deletion src/librustc_back/target/powerpc64_unknown_linux_gnu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@
// except according to those terms.

use LinkerFlavor;
use target::{Target, TargetResult};
use target::{Target, TargetResult, RelroLevel};

pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.cpu = "ppc64".to_string();
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.max_atomic_width = Some(64);

// ld.so in at least RHEL6 on ppc64 has a bug related to BIND_NOW, so only enable partial RELRO
// for now. https://github.com/rust-lang/rust/pull/43170#issuecomment-315411474
base.relro_level = RelroLevel::Partial;

// see #36994
base.exe_allocation_crate = None;

Expand Down
16 changes: 15 additions & 1 deletion src/librustc_trans/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1029,6 +1029,20 @@ fn link_args(cmd: &mut Linker,
}
}

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.
cmd.optimize();

Expand Down
Loading