Auto merge of #42711 - Firstyear:san-on-dylib, r=alexcrichton
Add support for dylibs with Address Sanitizer Many applications use address sanitizer to assert correct behaviour of their programs. When using Rust with C, it's much more important to assert correct programs with tools like asan/lsan due to the unsafe nature of the access across an ffi boundary. However, previously only rust bin types could use asan. This posed a challenge for existing C applications that link or dlopen .so when the C application is compiled with asan. This PR enables asan to be linked to the dylib and cdylib crate type. We alter the test to check the proc-macro crate does not work with -Z sanitizer=address. Finally, we add a test that compiles a shared object in rust, then another rust program links it and demonstrates a crash through the call to the library. This PR is nearly complete, but I do require advice on the change to fix the -lasan that currently exists in the dylib test. This is required because the link statement is not being added correctly to the rustc build when -Z sanitizer=address is added (and I'm not 100% sure why) Thanks,
This commit is contained in:
commit
2652ce6771
14 changed files with 205 additions and 23 deletions
|
@ -856,21 +856,48 @@ impl<'a> CrateLoader<'a> {
|
|||
return
|
||||
}
|
||||
|
||||
if !self.sess.crate_types.borrow().iter().all(|ct| {
|
||||
match *ct {
|
||||
// Link the runtime
|
||||
config::CrateTypeExecutable => true,
|
||||
// This crate will be compiled with the required
|
||||
// instrumentation pass
|
||||
config::CrateTypeRlib => false,
|
||||
_ => {
|
||||
self.sess.err(&format!("Only executables and rlibs can be \
|
||||
compiled with `-Z sanitizer`"));
|
||||
false
|
||||
// firstyear 2017 - during testing I was unable to access an OSX machine
|
||||
// to make this work on different crate types. As a result, today I have
|
||||
// only been able to test and support linux as a target.
|
||||
if self.sess.target.target.llvm_target == "x86_64-unknown-linux-gnu" {
|
||||
if !self.sess.crate_types.borrow().iter().all(|ct| {
|
||||
match *ct {
|
||||
// Link the runtime
|
||||
config::CrateTypeStaticlib |
|
||||
config::CrateTypeExecutable => true,
|
||||
// This crate will be compiled with the required
|
||||
// instrumentation pass
|
||||
config::CrateTypeRlib |
|
||||
config::CrateTypeDylib |
|
||||
config::CrateTypeCdylib =>
|
||||
false,
|
||||
_ => {
|
||||
self.sess.err(&format!("Only executables, staticlibs, \
|
||||
cdylibs, dylibs and rlibs can be compiled with \
|
||||
`-Z sanitizer`"));
|
||||
false
|
||||
}
|
||||
}
|
||||
}) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if !self.sess.crate_types.borrow().iter().all(|ct| {
|
||||
match *ct {
|
||||
// Link the runtime
|
||||
config::CrateTypeExecutable => true,
|
||||
// This crate will be compiled with the required
|
||||
// instrumentation pass
|
||||
config::CrateTypeRlib => false,
|
||||
_ => {
|
||||
self.sess.err(&format!("Only executables and rlibs can be \
|
||||
compiled with `-Z sanitizer`"));
|
||||
false
|
||||
}
|
||||
}
|
||||
}) {
|
||||
return
|
||||
}
|
||||
}) {
|
||||
return
|
||||
}
|
||||
|
||||
let mut uses_std = false;
|
||||
|
@ -890,7 +917,7 @@ impl<'a> CrateLoader<'a> {
|
|||
info!("loading sanitizer: {}", name);
|
||||
|
||||
let symbol = Symbol::intern(name);
|
||||
let dep_kind = DepKind::Implicit;
|
||||
let dep_kind = DepKind::Explicit;
|
||||
let (_, data) =
|
||||
self.resolve_crate(&None, symbol, symbol, None, DUMMY_SP,
|
||||
PathKind::Crate, dep_kind);
|
||||
|
@ -900,6 +927,8 @@ impl<'a> CrateLoader<'a> {
|
|||
self.sess.err(&format!("the crate `{}` is not a sanitizer runtime",
|
||||
name));
|
||||
}
|
||||
} else {
|
||||
self.sess.err(&format!("Must link std to be compiled with `-Z sanitizer`"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,5 +10,5 @@
|
|||
|
||||
fn main() {
|
||||
let xs = [0, 1, 2, 3];
|
||||
let y = unsafe { *xs.as_ptr().offset(4) };
|
||||
let _y = unsafe { *xs.as_ptr().offset(4) };
|
||||
}
|
||||
|
|
19
src/test/run-make/sanitizer-cdylib-link/Makefile
Normal file
19
src/test/run-make/sanitizer-cdylib-link/Makefile
Normal file
|
@ -0,0 +1,19 @@
|
|||
-include ../tools.mk
|
||||
|
||||
# This test builds a shared object, then an executable that links it as a native
|
||||
# rust library (constrast to an rlib). The shared library and executable both
|
||||
# are compiled with address sanitizer, and we assert that a fault in the cdylib
|
||||
# is correctly detected.
|
||||
|
||||
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
|
||||
ASAN_SUPPORT=$(SANITIZER_SUPPORT)
|
||||
EXTRA_RUSTFLAG=
|
||||
endif
|
||||
|
||||
all:
|
||||
ifeq ($(ASAN_SUPPORT),1)
|
||||
$(RUSTC) -g -Z sanitizer=address --crate-type cdylib --target $(TARGET) library.rs
|
||||
$(RUSTC) -g -Z sanitizer=address --crate-type bin --target $(TARGET) -llibrary program.rs
|
||||
LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | grep -q stack-buffer-overflow
|
||||
endif
|
||||
|
15
src/test/run-make/sanitizer-cdylib-link/library.rs
Normal file
15
src/test/run-make/sanitizer-cdylib-link/library.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn overflow() {
|
||||
let xs = [0, 1, 2, 3];
|
||||
let _y = unsafe { *xs.as_ptr().offset(4) };
|
||||
}
|
17
src/test/run-make/sanitizer-cdylib-link/program.rs
Normal file
17
src/test/run-make/sanitizer-cdylib-link/program.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern {
|
||||
fn overflow();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe { overflow() }
|
||||
}
|
19
src/test/run-make/sanitizer-dylib-link/Makefile
Normal file
19
src/test/run-make/sanitizer-dylib-link/Makefile
Normal file
|
@ -0,0 +1,19 @@
|
|||
-include ../tools.mk
|
||||
|
||||
# This test builds a shared object, then an executable that links it as a native
|
||||
# rust library (constrast to an rlib). The shared library and executable both
|
||||
# are compiled with address sanitizer, and we assert that a fault in the dylib
|
||||
# is correctly detected.
|
||||
|
||||
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
|
||||
ASAN_SUPPORT=$(SANITIZER_SUPPORT)
|
||||
EXTRA_RUSTFLAG=
|
||||
endif
|
||||
|
||||
all:
|
||||
ifeq ($(ASAN_SUPPORT),1)
|
||||
$(RUSTC) -g -Z sanitizer=address --crate-type dylib --target $(TARGET) library.rs
|
||||
$(RUSTC) -g -Z sanitizer=address --crate-type bin --target $(TARGET) -llibrary program.rs
|
||||
LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | grep -q stack-buffer-overflow
|
||||
endif
|
||||
|
15
src/test/run-make/sanitizer-dylib-link/library.rs
Normal file
15
src/test/run-make/sanitizer-dylib-link/library.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn overflow() {
|
||||
let xs = [0, 1, 2, 3];
|
||||
let _y = unsafe { *xs.as_ptr().offset(4) };
|
||||
}
|
17
src/test/run-make/sanitizer-dylib-link/program.rs
Normal file
17
src/test/run-make/sanitizer-dylib-link/program.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern {
|
||||
fn overflow();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe { overflow() }
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
-include ../tools.mk
|
||||
|
||||
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
|
||||
all:
|
||||
$(RUSTC) -Z sanitizer=leak --crate-type dylib --target $(TARGET) hello.rs 2>&1 | grep -q 'Only executables and rlibs can be compiled with `-Z sanitizer`'
|
||||
else
|
||||
all:
|
||||
endif
|
18
src/test/run-make/sanitizer-invalid-cratetype/Makefile
Normal file
18
src/test/run-make/sanitizer-invalid-cratetype/Makefile
Normal file
|
@ -0,0 +1,18 @@
|
|||
-include ../tools.mk
|
||||
|
||||
# NOTE the address sanitizer only supports x86_64 linux and macOS
|
||||
|
||||
ifeq ($(TARGET),x86_64-apple-darwin)
|
||||
ASAN_SUPPORT=$(SANITIZER_SUPPORT)
|
||||
EXTRA_RUSTFLAG=-C rpath
|
||||
else
|
||||
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
|
||||
ASAN_SUPPORT=$(SANITIZER_SUPPORT)
|
||||
EXTRA_RUSTFLAG=
|
||||
endif
|
||||
endif
|
||||
|
||||
all:
|
||||
ifeq ($(ASAN_SUPPORT),1)
|
||||
$(RUSTC) -Z sanitizer=address --crate-type proc-macro --target $(TARGET) hello.rs 2>&1 | grep -q -- '-Z sanitizer'
|
||||
endif
|
18
src/test/run-make/sanitizer-staticlib-link/Makefile
Normal file
18
src/test/run-make/sanitizer-staticlib-link/Makefile
Normal file
|
@ -0,0 +1,18 @@
|
|||
-include ../tools.mk
|
||||
|
||||
# This test builds a staticlib, then an executable that links to it.
|
||||
# The staticlib and executable both are compiled with address sanitizer,
|
||||
# and we assert that a fault in the staticlib is correctly detected.
|
||||
|
||||
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
|
||||
ASAN_SUPPORT=$(SANITIZER_SUPPORT)
|
||||
EXTRA_RUSTFLAG=
|
||||
endif
|
||||
|
||||
all:
|
||||
ifeq ($(ASAN_SUPPORT),1)
|
||||
$(RUSTC) -g -Z sanitizer=address --crate-type staticlib --target $(TARGET) library.rs
|
||||
$(CC) program.c $(call STATICLIB,library) $(call OUT_EXE,program) $(EXTRACFLAGS) $(EXTRACXXFLAGS)
|
||||
LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | grep -q stack-buffer-overflow
|
||||
endif
|
||||
|
15
src/test/run-make/sanitizer-staticlib-link/library.rs
Normal file
15
src/test/run-make/sanitizer-staticlib-link/library.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn overflow() {
|
||||
let xs = [0, 1, 2, 3];
|
||||
let _y = unsafe { *xs.as_ptr().offset(4) };
|
||||
}
|
8
src/test/run-make/sanitizer-staticlib-link/program.c
Normal file
8
src/test/run-make/sanitizer-staticlib-link/program.c
Normal file
|
@ -0,0 +1,8 @@
|
|||
// ignore-license
|
||||
void overflow();
|
||||
|
||||
int main() {
|
||||
overflow();
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Add table
Reference in a new issue