From 3cbff72da24d2a45552dd51eb7735ae3ee235bf3 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Thu, 7 Aug 2014 20:50:03 -0400 Subject: [PATCH] enable PIE by default on Linux for full ASLR Rust already builds all code as position independent by default, so the linker can be told to build a position independent executable if it's not disabled with `-C relocation-model=dynamic-no-pic`. Position independent code does have a significant cost on i686 (not on x86_64 or ARM) but there's no significant cost to linking code that's already position independent as a position independent executable. Address space layout randomization makes exploiting vulnerabilities much more difficult by providing a statistical defence against an attempt to find or modify existing code / data. Without ASLR, it's trivial to use a vulnerability to take over control of the process via return-oriented programming. Rust code can be used for return-oriented programming whether it is safe or unsafe, so even a fully safe application needs to be built as a position independent executable to defend against vulnerabilities in unsafe blocks or C libraries. Sample program: extern crate libc; use std::mem; static mut global: u32 = 5; static constant: u32 = 5; fn foo() {} fn main() { let local = 5; println!("stack: {}, global: {}, constant: {}, fn: {}, lib fn: {}", &local as *const u32, unsafe { &global as *const u32 }, &constant as *const u32, unsafe { mem::transmute::<_, *const ()>(foo) }, unsafe { mem::transmute::<_, *const ()>(libc::mprotect) }); } Before: stack: 0x3ff15eb9f94, global: 0x6ab488, constant: 0x47db40, fn: 0x4030e0, lib fn: 0x32749547530 stack: 0x3b5d47d80e4, global: 0x6ab488, constant: 0x47db40, fn: 0x4030e0, lib fn: 0x394469a7530 stack: 0x3fe2c4e5564, global: 0x6ab488, constant: 0x47db40, fn: 0x4030e0, lib fn: 0x399734a2530 stack: 0x3e525e0fb24, global: 0x6ab488, constant: 0x47db40, fn: 0x4030e0, lib fn: 0x2f62a810530 stack: 0x3b50fb3eae4, global: 0x6ab488, constant: 0x47db40, fn: 0x4030e0, lib fn: 0x2e590e86530 After: stack: 0x38cf12c90a4, global: 0x3e2d46b488, constant: 0x3e2d23cf80, fn: 0x3e2d1c2510, lib fn: 0x2617d3b4530 stack: 0x3d733faf474, global: 0x7eb1839488, constant: 0x7eb160af80, fn: 0x7eb1590510, lib fn: 0x32d30c1f530 stack: 0x3bb42212ec4, global: 0x5bbb365488, constant: 0x5bbb136f80, fn: 0x5bbb0bc510, lib fn: 0x3595e6c1530 stack: 0x39f678c1ab4, global: 0x22c4e3c488, constant: 0x22c4c0df80, fn: 0x22c4b93510, lib fn: 0x3835b727530 stack: 0x3afb25bd394, global: 0x493eab2488, constant: 0x493e883f80, fn: 0x493e809510, lib fn: 0x3478d6a7530 This may also be necessary on other platforms, but I can only test on Linux right now. Note that GDB gained support for debugging position independent executables in version 7.1 (March 2010). --- src/librustc/back/link.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 6c605fc262864..7c9844dbe33fb 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -1400,6 +1400,20 @@ fn link_args(cmd: &mut Command, cmd.arg("-Wl,--gc-sections"); } + let used_link_args = sess.cstore.get_used_link_args().borrow(); + + // Dynamically linked executables can be compiled as position independent if the default + // relocation model of position independent code is not changed. This is a requirement to take + // advantage of ASLR, as otherwise the functions in the executable are not randomized and can + // be used during an exploit of a vulnerability in any code. + if sess.targ_cfg.os == abi::OsLinux { + let mut args = sess.opts.cg.link_args.iter().chain(used_link_args.iter()); + if !dylib && sess.opts.cg.relocation_model.as_slice() == "pic" && + !args.any(|x| x.as_slice() == "-static") { + cmd.arg("-pie"); + } + } + if sess.targ_cfg.os == abi::OsLinux || sess.targ_cfg.os == abi::OsDragonfly { // GNU-style linkers will use this to omit linking to libraries which // don't actually fulfill any relocations, but only for libraries which @@ -1568,9 +1582,7 @@ fn link_args(cmd: &mut Command, // Finally add all the linker arguments provided on the command line along // with any #[link_args] attributes found inside the crate cmd.args(sess.opts.cg.link_args.as_slice()); - for arg in sess.cstore.get_used_link_args().borrow().iter() { - cmd.arg(arg.as_slice()); - } + cmd.args(used_link_args.as_slice()); } // # Native library linking