Allow receiving memcpy/memset/memmove instrumentation by using __asan or __hwasan prefixed versions for AddressSanitizer and HWAddressSanitizer respectively when compiling in kernel mode, by passing params -asan-kernel-mem-intrinsic-prefix or -hwasan-kernel-mem-intrinsic-prefix. By default the kernel-specialized versions of both passes drop the prefixes for calls generated by memintrinsics. This assumes that all locations that can lower the intrinsics to libcalls can safely be instrumented. This unfortunately is not the case when implicit calls to memintrinsics are inserted by the compiler in no_sanitize functions [1]. To solve the issue, normal memcpy/memset/memmove need to be uninstrumented, and instrumented code should instead use the prefixed versions. This also aligns with ASan behaviour in user space. [1] https://lore.kernel.org/lkml/Yj2yYFloadFobRPx@lakrids/ Reviewed By: glider Differential Revision: https://reviews.llvm.org/D122724
199 lines
5.8 KiB
LLVM
199 lines
5.8 KiB
LLVM
; Test basic address sanitizer instrumentation.
|
|
;
|
|
|
|
; RUN: opt < %s -passes='asan-pipeline' -S | FileCheck --check-prefixes=CHECK,CHECK-S3 %s
|
|
; RUN: opt < %s -passes='asan-pipeline' -asan-mapping-scale=5 -S | FileCheck --check-prefixes=CHECK,CHECK-S5 %s
|
|
|
|
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
|
|
target triple = "x86_64-unknown-linux-gnu"
|
|
; CHECK: @llvm.used = appending global [1 x i8*] [i8* bitcast (void ()* @asan.module_ctor to i8*)]
|
|
; CHECK: @llvm.global_ctors = {{.*}}{ i32 1, void ()* @asan.module_ctor, i8* bitcast (void ()* @asan.module_ctor to i8*) }
|
|
|
|
define i32 @test_load(i32* %a) sanitize_address {
|
|
; CHECK-LABEL: @test_load
|
|
; CHECK-NOT: load
|
|
; CHECK: %[[LOAD_ADDR:[^ ]*]] = ptrtoint i32* %a to i64
|
|
; CHECK-S3: lshr i64 %[[LOAD_ADDR]], 3
|
|
; CHECK-S5: lshr i64 %[[LOAD_ADDR]], 5
|
|
; CHECK: {{or|add}}
|
|
; CHECK: %[[LOAD_SHADOW_PTR:[^ ]*]] = inttoptr
|
|
; CHECK: %[[LOAD_SHADOW:[^ ]*]] = load i8, i8* %[[LOAD_SHADOW_PTR]]
|
|
; CHECK: icmp ne i8
|
|
; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}!prof ![[PROF:[0-9]+]]
|
|
;
|
|
; First instrumentation block refines the shadow test.
|
|
; CHECK-S3: and i64 %[[LOAD_ADDR]], 7
|
|
; CHECK-S5: and i64 %[[LOAD_ADDR]], 31
|
|
; CHECK: add i64 %{{.*}}, 3
|
|
; CHECK: trunc i64 %{{.*}} to i8
|
|
; CHECK: icmp sge i8 %{{.*}}, %[[LOAD_SHADOW]]
|
|
; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
|
|
;
|
|
; The crash block reports the error.
|
|
; CHECK: call void @__asan_report_load4(i64 %[[LOAD_ADDR]])
|
|
; CHECK: unreachable
|
|
;
|
|
; The actual load.
|
|
; CHECK: %tmp1 = load i32, i32* %a
|
|
; CHECK: ret i32 %tmp1
|
|
|
|
|
|
|
|
entry:
|
|
%tmp1 = load i32, i32* %a, align 4
|
|
ret i32 %tmp1
|
|
}
|
|
|
|
define void @test_store(i32* %a) sanitize_address {
|
|
; CHECK-LABEL: @test_store
|
|
; CHECK-NOT: store
|
|
; CHECK: %[[STORE_ADDR:[^ ]*]] = ptrtoint i32* %a to i64
|
|
; CHECK-S3: lshr i64 %[[STORE_ADDR]], 3
|
|
; CHECK-S5: lshr i64 %[[STORE_ADDR]], 5
|
|
; CHECK: {{or|add}}
|
|
; CHECK: %[[STORE_SHADOW_PTR:[^ ]*]] = inttoptr
|
|
; CHECK: %[[STORE_SHADOW:[^ ]*]] = load i8, i8* %[[STORE_SHADOW_PTR]]
|
|
; CHECK: icmp ne i8
|
|
; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
|
|
;
|
|
; First instrumentation block refines the shadow test.
|
|
; CHECK-S3: and i64 %[[STORE_ADDR]], 7
|
|
; CHECK-S5: and i64 %[[STORE_ADDR]], 31
|
|
; CHECK: add i64 %{{.*}}, 3
|
|
; CHECK: trunc i64 %{{.*}} to i8
|
|
; CHECK: icmp sge i8 %{{.*}}, %[[STORE_SHADOW]]
|
|
; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
|
|
;
|
|
; The crash block reports the error.
|
|
; CHECK: call void @__asan_report_store4(i64 %[[STORE_ADDR]])
|
|
; CHECK: unreachable
|
|
;
|
|
; The actual load.
|
|
; CHECK: store i32 42, i32* %a
|
|
; CHECK: ret void
|
|
;
|
|
|
|
entry:
|
|
store i32 42, i32* %a, align 4
|
|
ret void
|
|
}
|
|
|
|
; Check that asan leaves just one alloca.
|
|
|
|
declare void @alloca_test_use([10 x i8]*)
|
|
define void @alloca_test() sanitize_address {
|
|
entry:
|
|
%x = alloca [10 x i8], align 1
|
|
%y = alloca [10 x i8], align 1
|
|
%z = alloca [10 x i8], align 1
|
|
call void @alloca_test_use([10 x i8]* %x)
|
|
call void @alloca_test_use([10 x i8]* %y)
|
|
call void @alloca_test_use([10 x i8]* %z)
|
|
ret void
|
|
}
|
|
|
|
; CHECK-LABEL: define void @alloca_test()
|
|
; CHECK: %asan_local_stack_base = alloca
|
|
; CHECK: = alloca
|
|
; CHECK-NOT: = alloca
|
|
; CHECK: ret void
|
|
|
|
define void @LongDoubleTest(x86_fp80* nocapture %a) nounwind uwtable sanitize_address {
|
|
entry:
|
|
store x86_fp80 0xK3FFF8000000000000000, x86_fp80* %a, align 16
|
|
ret void
|
|
}
|
|
|
|
; CHECK-LABEL: LongDoubleTest
|
|
; CHECK: __asan_report_store_n
|
|
; CHECK: __asan_report_store_n
|
|
; CHECK: ret void
|
|
|
|
|
|
define void @i40test(i40* %a, i40* %b) nounwind uwtable sanitize_address {
|
|
entry:
|
|
%t = load i40, i40* %a
|
|
store i40 %t, i40* %b, align 8
|
|
ret void
|
|
}
|
|
|
|
; CHECK-LABEL: i40test
|
|
; CHECK: __asan_report_load_n{{.*}}, i64 5)
|
|
; CHECK: __asan_report_load_n{{.*}}, i64 5)
|
|
; CHECK: __asan_report_store_n{{.*}}, i64 5)
|
|
; CHECK: __asan_report_store_n{{.*}}, i64 5)
|
|
; CHECK: ret void
|
|
|
|
define void @i64test_align1(i64* %b) nounwind uwtable sanitize_address {
|
|
entry:
|
|
store i64 0, i64* %b, align 1
|
|
ret void
|
|
}
|
|
|
|
; CHECK-LABEL: i64test_align1
|
|
; CHECK: __asan_report_store_n{{.*}}, i64 8)
|
|
; CHECK: __asan_report_store_n{{.*}}, i64 8)
|
|
; CHECK: ret void
|
|
|
|
|
|
define void @i80test(i80* %a, i80* %b) nounwind uwtable sanitize_address {
|
|
entry:
|
|
%t = load i80, i80* %a
|
|
store i80 %t, i80* %b, align 8
|
|
ret void
|
|
}
|
|
|
|
; CHECK-LABEL: i80test
|
|
; CHECK: __asan_report_load_n{{.*}}, i64 10)
|
|
; CHECK: __asan_report_load_n{{.*}}, i64 10)
|
|
; CHECK: __asan_report_store_n{{.*}}, i64 10)
|
|
; CHECK: __asan_report_store_n{{.*}}, i64 10)
|
|
; CHECK: ret void
|
|
|
|
; asan should not instrument functions with available_externally linkage.
|
|
define available_externally i32 @f_available_externally(i32* %a) sanitize_address {
|
|
entry:
|
|
%tmp1 = load i32, i32* %a
|
|
ret i32 %tmp1
|
|
}
|
|
; CHECK-LABEL: @f_available_externally
|
|
; CHECK-NOT: __asan_report
|
|
; CHECK: ret i32
|
|
|
|
|
|
; CHECK-LABEL: @test_swifterror
|
|
; CHECK-NOT: __asan_report_load
|
|
; CHECK: ret void
|
|
define void @test_swifterror(i8** swifterror) sanitize_address {
|
|
%swifterror_ptr_value = load i8*, i8** %0
|
|
ret void
|
|
}
|
|
|
|
; CHECK-LABEL: @test_swifterror_2
|
|
; CHECK-NOT: __asan_report_store
|
|
; CHECK: ret void
|
|
define void @test_swifterror_2(i8** swifterror) sanitize_address {
|
|
store i8* null, i8** %0
|
|
ret void
|
|
}
|
|
|
|
; CHECK-LABEL: @test_swifterror_3
|
|
; CHECK-NOT: __asan_report_store
|
|
; CHECK: ret void
|
|
define void @test_swifterror_3() sanitize_address {
|
|
%swifterror_addr = alloca swifterror i8*
|
|
store i8* null, i8** %swifterror_addr
|
|
call void @test_swifterror_2(i8** swifterror %swifterror_addr)
|
|
ret void
|
|
}
|
|
|
|
;; ctor/dtor have the nounwind attribute. See uwtable.ll, they additionally have
|
|
;; the uwtable attribute with the module flag "uwtable".
|
|
; CHECK: define internal void @asan.module_ctor() #[[#ATTR:]] {{(comdat )?}}{
|
|
; CHECK: call void @__asan_init()
|
|
|
|
; CHECK: attributes #[[#ATTR]] = { nounwind }
|
|
|
|
; PROF
|
|
; CHECK: ![[PROF]] = !{!"branch_weights", i32 1, i32 100000}
|