Support both partial and full RELRO
Signed-off-by: Johannes Löthberg <johannes@kyriasis.com>
This commit is contained in:
parent
230668765d
commit
94b9cc90fb
12 changed files with 110 additions and 28 deletions
|
|
@ -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<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),
|
||||
|
|
@ -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],
|
||||
"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],
|
||||
|
|
@ -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<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);
|
||||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue