Skip to content

Commit

Permalink
Allow -fsanitize=function on all targets
Browse files Browse the repository at this point in the history
Functions instrumented with -fsanitize=function have two words before
the function label: a signature and a RTTI proxy.
Instrumented call sites check the signature first to skip checks
for uninstrumented callees.

The code is generic and works for all targets supporting C++ RTTI.
Change clangDriver to allow all targets. Add tests for Armv8.5
Branch Target Identification and `-fpatchable-function-entry=`.

Reviewed By: peter.smith

Differential Revision: https://reviews.llvm.org/D148573
  • Loading branch information
MaskRay committed May 19, 2023
1 parent ad31a2d commit 67cbe1b
Show file tree
Hide file tree
Showing 13 changed files with 55 additions and 28 deletions.
3 changes: 1 addition & 2 deletions clang/docs/UndefinedBehaviorSanitizer.rst
Expand Up @@ -100,8 +100,7 @@ Available checks are:
by Clang (and by ISO/IEC/IEEE 60559 / IEEE 754) as producing either an
infinity or NaN value, so is not included in ``-fsanitize=undefined``.
- ``-fsanitize=function``: Indirect call of a function through a
function pointer of the wrong type (Darwin/Linux, C++ and x86/x86_64
only).
function pointer of the wrong type (C++ only).
- ``-fsanitize=implicit-unsigned-integer-truncation``,
``-fsanitize=implicit-signed-integer-truncation``: Implicit conversion from
integer of larger bit width to smaller bit width, if that results in data
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Driver/ToolChain.cpp
Expand Up @@ -1156,8 +1156,7 @@ SanitizerMask ToolChain::getSupportedSanitizers() const {
// platform dependent.

SanitizerMask Res =
(SanitizerKind::Undefined & ~SanitizerKind::Vptr &
~SanitizerKind::Function) |
(SanitizerKind::Undefined & ~SanitizerKind::Vptr) |
(SanitizerKind::CFI & ~SanitizerKind::CFIICall) |
SanitizerKind::CFICastStrict | SanitizerKind::FloatDivideByZero |
SanitizerKind::KCFI | SanitizerKind::UnsignedIntegerOverflow |
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Driver/ToolChains/Darwin.cpp
Expand Up @@ -3269,7 +3269,6 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
Res |= SanitizerKind::Leak;
Res |= SanitizerKind::Fuzzer;
Res |= SanitizerKind::FuzzerNoLink;
Res |= SanitizerKind::Function;
Res |= SanitizerKind::ObjCCast;

// Prior to 10.9, macOS shipped a version of the C++ standard library without
Expand Down
3 changes: 0 additions & 3 deletions clang/lib/Driver/ToolChains/FreeBSD.cpp
Expand Up @@ -483,9 +483,6 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const {
Res |= SanitizerKind::Leak;
Res |= SanitizerKind::Thread;
}
if (IsX86 || IsX86_64) {
Res |= SanitizerKind::Function;
}
if (IsAArch64 || IsX86 || IsX86_64) {
Res |= SanitizerKind::SafeStack;
Res |= SanitizerKind::Fuzzer;
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/Driver/ToolChains/Linux.cpp
Expand Up @@ -797,8 +797,6 @@ SanitizerMask Linux::getSupportedSanitizers() const {
Res |= SanitizerKind::Thread;
if (IsX86_64 || IsSystemZ)
Res |= SanitizerKind::KernelMemory;
if (IsX86 || IsX86_64)
Res |= SanitizerKind::Function;
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch ||
IsPowerPC64 || IsHexagon || IsLoongArch64 || IsRISCV64)
Res |= SanitizerKind::Scudo;
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Driver/ToolChains/NetBSD.cpp
Expand Up @@ -508,7 +508,6 @@ SanitizerMask NetBSD::getSupportedSanitizers() const {
Res |= SanitizerKind::Address;
Res |= SanitizerKind::PointerCompare;
Res |= SanitizerKind::PointerSubtract;
Res |= SanitizerKind::Function;
Res |= SanitizerKind::Leak;
Res |= SanitizerKind::SafeStack;
Res |= SanitizerKind::Scudo;
Expand Down
3 changes: 0 additions & 3 deletions clang/lib/Driver/ToolChains/Solaris.cpp
Expand Up @@ -225,16 +225,13 @@ Solaris::Solaris(const Driver &D, const llvm::Triple &Triple,

SanitizerMask Solaris::getSupportedSanitizers() const {
const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
SanitizerMask Res = ToolChain::getSupportedSanitizers();
// FIXME: Omit X86_64 until 64-bit support is figured out.
if (IsX86) {
Res |= SanitizerKind::Address;
Res |= SanitizerKind::PointerCompare;
Res |= SanitizerKind::PointerSubtract;
}
if (IsX86 || IsX86_64)
Res |= SanitizerKind::Function;
Res |= SanitizerKind::Vptr;
return Res;
}
Expand Down
2 changes: 2 additions & 0 deletions clang/test/CodeGen/ubsan-function.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s
// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s
// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s

// CHECK: @[[PROXY:.*]] = private unnamed_addr constant ptr @_ZTIFvvE
// CHECK: define{{.*}} void @_Z3funv() #0 !func_sanitize ![[FUNCSAN:.*]] {
Expand Down
15 changes: 6 additions & 9 deletions clang/test/Driver/fsanitize.c
Expand Up @@ -24,8 +24,8 @@
// CHECK-UNDEFINED-WIN64: "--dependent-lib={{[^"]*}}ubsan_standalone{{(-x86_64)?}}.lib"
// CHECK-UNDEFINED-WIN64-MINGW: "--dependent-lib={{[^"]*}}libclang_rt.ubsan_standalone{{(-x86_64)?}}.a"
// CHECK-UNDEFINED-WIN-CXX: "--dependent-lib={{[^"]*}}ubsan_standalone_cxx{{[^"]*}}.lib"
// CHECK-UNDEFINED-MSVC-SAME: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){17}"}}
// CHECK-UNDEFINED-WIN64-MINGW-SAME: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|vptr),?){18}"}}
// CHECK-UNDEFINED-MSVC-SAME: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}}
// CHECK-UNDEFINED-WIN64-MINGW-SAME: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|vptr),?){19}"}}

// RUN: %clang --target=i386-pc-win32 -fsanitize-coverage=bb %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-COVERAGE-WIN32
// CHECK-COVERAGE-WIN32: "--dependent-lib={{[^"]*}}ubsan_standalone{{(-i386)?}}.lib"
Expand Down Expand Up @@ -525,9 +525,10 @@
// RUN: %clang --target=x86_64-linux-gnu -fsanitize=thread -fsanitize-thread-atomics -fno-sanitize-thread-atomics %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TSAN-ATOMICS-BOTH-OFF
// CHECK-TSAN-ATOMICS-BOTH-OFF: -cc1{{.*}}tsan-instrument-atomics=0

// RUN: %clang --target=x86_64-apple-darwin10 -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSAN-DARWIN
// RUN: %clang --target=i386-apple-darwin10 -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSAN-DARWIN
// CHECK-FSAN-DARWIN: -cc1{{.*}}"-fsanitize=function" "-fsanitize-recover=function"
// RUN: %clang --target=x86_64-apple-darwin10 -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FUNCTION
// RUN: %clang --target=aarch64-unknown-linux-gnu -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FUNCTION
// RUN: %clang --target=riscv64-pc-freebsd -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FUNCTION
// CHECK-FUNCTION: -cc1{{.*}}"-fsanitize=function" "-fsanitize-recover=function"

// RUN: %clang --target=x86_64-apple-darwin10 -mmacosx-version-min=10.8 -fsanitize=vptr %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-DARWIN-OLD
// CHECK-VPTR-DARWIN-OLD: unsupported option '-fsanitize=vptr' for target 'x86_64-apple-darwin10'
Expand Down Expand Up @@ -791,10 +792,6 @@
// FUNCTION-SOLARIS: "-fsanitize=function"


// RUN: %clang --target=x86_64-scei-ps4 -fsanitize=function -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSAN-UBSAN-PS4
// CHECK-FSAN-UBSAN-PS4: unsupported option '-fsanitize=function' for target 'x86_64-scei-ps4'
// RUN: %clang --target=x86_64-scei-ps4 -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSAN-PS4
// CHECK-FSAN-PS4: unsupported option '-fsanitize=function' for target 'x86_64-scei-ps4'
// RUN: %clang --target=x86_64-scei-ps4 -fsanitize=dataflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-DFSAN-PS4
// CHECK-DFSAN-PS4: unsupported option '-fsanitize=dataflow' for target 'x86_64-scei-ps4'
// RUN: %clang --target=x86_64-scei-ps4 -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-LSAN-PS4
Expand Down
Expand Up @@ -4,9 +4,6 @@
// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK $(%run %t-unique UNIQUE)
// Verify that we can disable symbolization if needed:
// RUN: %env_ubsan_opts=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM $(%run %t-unique NOSYM-UNIQUE)
// XFAIL: target={{.*windows.*}}
// Unsupported function flag
// UNSUPPORTED: target={{.*openbsd.*}}

#ifdef DETERMINE_UNIQUE

Expand Down
@@ -1,3 +1,2 @@
# The function type checker is only supported on x86 and x86_64 for now.
if config.target_arch not in ['x86', 'x86_64']:
if config.host_os not in ['Darwin', 'FreeBSD', 'Linux', 'NetBSD']:
config.unsupported = True
22 changes: 22 additions & 0 deletions llvm/test/CodeGen/AArch64/func-sanitizer.ll
@@ -0,0 +1,22 @@
; RUN: llc -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck %s

; CHECK-LABEL: .type _Z3funv,@function
; CHECK-NEXT: .word 3238382334 // 0xc105cafe
; CHECK-NEXT: .word .L__llvm_rtti_proxy-_Z3funv
; CHECK-NEXT: _Z3funv:
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: ret

; CHECK: .section .rodata,"a",@progbits
; CHECK-LABEL: .L__llvm_rtti_proxy:
; CHECK-NEXT: .xword _ZTIFvvE
; CHECK-NEXT: .size .L__llvm_rtti_proxy, 8

@_ZTIFvvE = linkonce_odr constant i32 1
@__llvm_rtti_proxy = private unnamed_addr constant ptr @_ZTIFvvE

define dso_local void @_Z3funv() nounwind !func_sanitize !0 {
ret void
}

!0 = !{i32 3238382334, ptr @__llvm_rtti_proxy}
22 changes: 22 additions & 0 deletions llvm/test/CodeGen/AArch64/patchable-function-entry-bti.ll
@@ -1,5 +1,8 @@
; RUN: llc -mtriple=aarch64 %s -o - | FileCheck %s

@_ZTIFvvE = linkonce_odr constant i32 2
@__llvm_rtti_proxy = private unnamed_addr constant ptr @_ZTIFvvE

define void @f0() "patchable-function-entry"="0" "branch-target-enforcement"="true" {
; CHECK-LABEL: f0:
; CHECK-NEXT: .Lfunc_begin0:
Expand Down Expand Up @@ -85,3 +88,22 @@ sw.bb4:
call void asm sideeffect "", ""()
ret void
}

;; Test the interaction with -fsanitize=function.
; CHECK: .type sanitize_function,@function
; CHECK-NEXT: .Ltmp{{.*}}:
; CHECK-NEXT: nop
; CHECK-NEXT: .word 3238382334 // 0xc105cafe
; CHECK-NEXT: .word .L__llvm_rtti_proxy-sanitize_function
; CHECK-NEXT: sanitize_function:
; CHECK-NEXT: .Lfunc_begin{{.*}}:
; CHECK-NEXT: .cfi_startproc
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: hint #34
; CHECK-NEXT: nop
; CHECK-NEXT: ret
define void @sanitize_function(ptr noundef %x) "patchable-function-prefix"="1" "patchable-function-entry"="1" "branch-target-enforcement"="true" !func_sanitize !0 {
ret void
}

!0 = !{i32 3238382334, ptr @__llvm_rtti_proxy}

0 comments on commit 67cbe1b

Please sign in to comment.