Skip to content

Commit 3cbff72

Browse files
committed
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).
1 parent 12e0f72 commit 3cbff72

File tree

1 file changed

+15
-3
lines changed

1 file changed

+15
-3
lines changed

src/librustc/back/link.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -1400,6 +1400,20 @@ fn link_args(cmd: &mut Command,
14001400
cmd.arg("-Wl,--gc-sections");
14011401
}
14021402

1403+
let used_link_args = sess.cstore.get_used_link_args().borrow();
1404+
1405+
// Dynamically linked executables can be compiled as position independent if the default
1406+
// relocation model of position independent code is not changed. This is a requirement to take
1407+
// advantage of ASLR, as otherwise the functions in the executable are not randomized and can
1408+
// be used during an exploit of a vulnerability in any code.
1409+
if sess.targ_cfg.os == abi::OsLinux {
1410+
let mut args = sess.opts.cg.link_args.iter().chain(used_link_args.iter());
1411+
if !dylib && sess.opts.cg.relocation_model.as_slice() == "pic" &&
1412+
!args.any(|x| x.as_slice() == "-static") {
1413+
cmd.arg("-pie");
1414+
}
1415+
}
1416+
14031417
if sess.targ_cfg.os == abi::OsLinux || sess.targ_cfg.os == abi::OsDragonfly {
14041418
// GNU-style linkers will use this to omit linking to libraries which
14051419
// don't actually fulfill any relocations, but only for libraries which
@@ -1568,9 +1582,7 @@ fn link_args(cmd: &mut Command,
15681582
// Finally add all the linker arguments provided on the command line along
15691583
// with any #[link_args] attributes found inside the crate
15701584
cmd.args(sess.opts.cg.link_args.as_slice());
1571-
for arg in sess.cstore.get_used_link_args().borrow().iter() {
1572-
cmd.arg(arg.as_slice());
1573-
}
1585+
cmd.args(used_link_args.as_slice());
15741586
}
15751587

15761588
// # Native library linking

0 commit comments

Comments
 (0)