Skip to content

Commit

Permalink
Allow disabling ASan instrumentation for globals
Browse files Browse the repository at this point in the history
AddressSanitizer adds instrumentation to global variables unless the
[`no_sanitize_address`](https://llvm.org/docs/LangRef.html#global-attributes)
attribute is set on them.

This commit extends the existing `#[no_sanitize(address)]` attribute to
set this; previously it only had the desired effect on functions.
  • Loading branch information
BertalanD committed Nov 2, 2024
1 parent 00ed73c commit 204b228
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 34 deletions.
9 changes: 9 additions & 0 deletions compiler/rustc_codegen_llvm/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,12 @@ pub(crate) fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility {
Visibility::Protected => llvm::Visibility::Protected,
}
}

pub(crate) fn set_variable_sanitizer_attrs(llval: &Value, attrs: &CodegenFnAttrs) {
if attrs.no_sanitize.contains(SanitizerSet::ADDRESS) {
unsafe { llvm::LLVMRustSetNoSanitizeAddress(llval) };
}
if attrs.no_sanitize.contains(SanitizerSet::HWADDRESS) {
unsafe { llvm::LLVMRustSetNoSanitizeHWAddress(llval) };
}
}
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_llvm/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,8 @@ impl<'ll> CodegenCx<'ll, '_> {
base::set_link_section(g, attrs);
}

base::set_variable_sanitizer_attrs(g, attrs);

if attrs.flags.contains(CodegenFnAttrFlags::USED) {
// `USED` and `USED_LINKER` can't be used together.
assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER));
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2474,4 +2474,7 @@ unsafe extern "C" {
pub fn LLVMRustIs64BitSymbolicFile(buf_ptr: *const u8, buf_len: usize) -> bool;

pub fn LLVMRustIsECObject(buf_ptr: *const u8, buf_len: usize) -> bool;

pub fn LLVMRustSetNoSanitizeAddress(Global: &Value);
pub fn LLVMRustSetNoSanitizeHWAddress(Global: &Value);
}
19 changes: 19 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1999,6 +1999,25 @@ extern "C" bool LLVMRustLLVMHasZstdCompressionForDebugSymbols() {
return llvm::compression::zstd::isAvailable();
}

extern "C" void LLVMRustSetNoSanitizeAddress(LLVMValueRef Global) {
GlobalValue &GV = *unwrap<GlobalValue>(Global);
GlobalValue::SanitizerMetadata MD;
if (GV.hasSanitizerMetadata())
MD = GV.getSanitizerMetadata();
MD.NoAddress = true;
MD.IsDynInit = false;
GV.setSanitizerMetadata(MD);
}

extern "C" void LLVMRustSetNoSanitizeHWAddress(LLVMValueRef Global) {
GlobalValue &GV = *unwrap<GlobalValue>(Global);
GlobalValue::SanitizerMetadata MD;
if (GV.hasSanitizerMetadata())
MD = GV.getSanitizerMetadata();
MD.NoHWAddress = true;
GV.setSanitizerMetadata(MD);
}

// Operations on composite constants.
// These are clones of LLVM api functions that will become available in future
// releases. They can be removed once Rust's minimum supported LLVM version
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,10 @@ passes_no_mangle_foreign =
passes_no_patterns =
patterns not allowed in naked function parameters
passes_no_sanitize =
`#[no_sanitize({$attr_str})]` should be applied to {$accepted_kind}
.label = not {$accepted_kind}
passes_non_exported_macro_invalid_attrs =
attribute should be applied to function or closure
.label = not a function or closure
Expand Down
37 changes: 34 additions & 3 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
[sym::inline, ..] => self.check_inline(hir_id, attr, span, target),
[sym::coverage, ..] => self.check_coverage(attr, span, target),
[sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target),
[sym::no_sanitize, ..] => {
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
}
[sym::no_sanitize, ..] => self.check_no_sanitize(attr, span, target),
[sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target),
[sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
[sym::target_feature, ..] => {
Expand Down Expand Up @@ -450,6 +448,39 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}

fn check_no_sanitize(&self, attr: &Attribute, span: Span, target: Target) {
if let Some(list) = attr.meta_item_list() {
for item in list.iter() {
let sym = item.name_or_empty();
match sym {
sym::address | sym::hwaddress => {
let is_valid =
matches!(target, Target::Fn | Target::Method(..) | Target::Static);
if !is_valid {
self.dcx().emit_err(errors::NoSanitize {
attr_span: item.span(),
defn_span: span,
accepted_kind: "a function or static",
attr_str: sym.as_str(),
});
}
}
_ => {
let is_valid = matches!(target, Target::Fn | Target::Method(..));
if !is_valid {
self.dcx().emit_err(errors::NoSanitize {
attr_span: item.span(),
defn_span: span,
accepted_kind: "a function",
attr_str: sym.as_str(),
});
}
}
}
}
}
}

fn check_generic_attr(
&self,
hir_id: HirId,
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1848,3 +1848,14 @@ pub(crate) struct AttrCrateLevelOnlySugg {
#[primary_span]
pub attr: Span,
}

#[derive(Diagnostic)]
#[diag(passes_no_sanitize)]
pub(crate) struct NoSanitize<'a> {
#[primary_span]
pub attr_span: Span,
#[label]
pub defn_span: Span,
pub accepted_kind: &'a str,
pub attr_str: &'a str,
}
10 changes: 10 additions & 0 deletions tests/codegen/sanitizer/no-sanitize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@
#![crate_type = "lib"]
#![feature(no_sanitize)]

// CHECK: @UNSANITIZED = constant{{.*}} no_sanitize_address
// CHECK-NOT: @__asan_global_UNSANITIZED
#[no_mangle]
#[no_sanitize(address)]
pub static UNSANITIZED: u32 = 0;

// CHECK: @__asan_global_SANITIZED
#[no_mangle]
pub static SANITIZED: u32 = 0;

// CHECK-LABEL: ; no_sanitize::unsanitized
// CHECK-NEXT: ; Function Attrs:
// CHECK-NOT: sanitize_address
Expand Down
18 changes: 12 additions & 6 deletions tests/ui/attributes/no-sanitize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,37 @@
#![allow(dead_code)]

fn invalid() {
#[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
#[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
{
1
};
}

#[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
#[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
type InvalidTy = ();

#[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
#[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
mod invalid_module {}

fn main() {
let _ = #[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
let _ = #[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
(|| 1);
}

#[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
#[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
struct F;

#[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
#[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
impl F {
#[no_sanitize(memory)]
fn valid(&self) {}
}

#[no_sanitize(address, memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
static INVALID : i32 = 0;

#[no_sanitize(memory)]
fn valid() {}

#[no_sanitize(address)]
static VALID : i32 = 0;
58 changes: 33 additions & 25 deletions tests/ui/attributes/no-sanitize.stderr
Original file line number Diff line number Diff line change
@@ -1,55 +1,63 @@
error: attribute should be applied to a function definition
--> $DIR/no-sanitize.rs:7:5
error: `#[no_sanitize(memory)]` should be applied to a function
--> $DIR/no-sanitize.rs:7:19
|
LL | #[no_sanitize(memory)]
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^
LL | / {
LL | | 1
LL | | };
| |_____- not a function definition
| |_____- not a function

error: attribute should be applied to a function definition
--> $DIR/no-sanitize.rs:13:1
error: `#[no_sanitize(memory)]` should be applied to a function
--> $DIR/no-sanitize.rs:13:15
|
LL | #[no_sanitize(memory)]
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^
LL | type InvalidTy = ();
| -------------------- not a function definition
| -------------------- not a function

error: attribute should be applied to a function definition
--> $DIR/no-sanitize.rs:16:1
error: `#[no_sanitize(memory)]` should be applied to a function
--> $DIR/no-sanitize.rs:16:15
|
LL | #[no_sanitize(memory)]
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^
LL | mod invalid_module {}
| --------------------- not a function definition
| --------------------- not a function

error: attribute should be applied to a function definition
--> $DIR/no-sanitize.rs:20:13
error: `#[no_sanitize(memory)]` should be applied to a function
--> $DIR/no-sanitize.rs:20:27
|
LL | let _ = #[no_sanitize(memory)]
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^
LL | (|| 1);
| ------ not a function definition
| ------ not a function

error: attribute should be applied to a function definition
--> $DIR/no-sanitize.rs:24:1
error: `#[no_sanitize(memory)]` should be applied to a function
--> $DIR/no-sanitize.rs:24:15
|
LL | #[no_sanitize(memory)]
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^
LL | struct F;
| --------- not a function definition
| --------- not a function

error: attribute should be applied to a function definition
--> $DIR/no-sanitize.rs:27:1
error: `#[no_sanitize(memory)]` should be applied to a function
--> $DIR/no-sanitize.rs:27:15
|
LL | #[no_sanitize(memory)]
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^
LL | / impl F {
LL | | #[no_sanitize(memory)]
LL | | fn valid(&self) {}
LL | | }
| |_- not a function definition
| |_- not a function

error: aborting due to 6 previous errors
error: `#[no_sanitize(memory)]` should be applied to a function
--> $DIR/no-sanitize.rs:33:24
|
LL | #[no_sanitize(address, memory)]
| ^^^^^^
LL | static INVALID : i32 = 0;
| ------------------------- not a function

error: aborting due to 7 previous errors

0 comments on commit 204b228

Please sign in to comment.