]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #16340 : thestinger/rust/pie, r=brson
authorbors <bors@rust-lang.org>
Sat, 9 Aug 2014 13:21:20 +0000 (13:21 +0000)
committerbors <bors@rust-lang.org>
Sat, 9 Aug 2014 13:21:20 +0000 (13:21 +0000)
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

index 6c605fc26286417c08ff31b6775fbacdbe4b5924..7c9844dbe33fb4693616efda8aaa6400786f96a6 100644 (file)
@@ -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