From faf5e0ec737a676088649d7c13cb50f3f91a703a Mon Sep 17 00:00:00 2001 From: Mitch Phillips <31459023+hctim@users.noreply.github.com> Date: Fri, 24 Jun 2022 10:48:18 -0700 Subject: [PATCH] Add no_sanitize('hwaddress') (and 'memtag', but that's a no-op). Currently, `__attribute__((no_sanitize('hwaddress')))` is not possible. Add this piece of plumbing, and now that we properly support copying attributes between an old and a new global variable, add a regression test for the GlobalOpt bug that previously lost the attribute. Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D127544 --- clang/lib/Sema/SemaDeclAttr.cpp | 7 ++- .../CodeGen/Inputs/sanitizer-extra-source.cpp | 1 + .../Inputs/sanitizer-ignorelist-global.txt | 1 + .../Inputs/sanitizer-ignorelist-src.txt | 1 + clang/test/CodeGen/hwasan-globals.cpp | 57 +++++++++++++++++ clang/test/CodeGen/memtag-globals.cpp | 62 +++++++++++++++++++ .../hwasan/TestCases/global-with-reduction.c | 50 +++++++++++++++ compiler-rt/test/hwasan/TestCases/global.c | 14 +++++ 8 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGen/Inputs/sanitizer-extra-source.cpp create mode 100644 clang/test/CodeGen/Inputs/sanitizer-ignorelist-global.txt create mode 100644 clang/test/CodeGen/Inputs/sanitizer-ignorelist-src.txt create mode 100644 clang/test/CodeGen/hwasan-globals.cpp create mode 100644 clang/test/CodeGen/memtag-globals.cpp create mode 100644 compiler-rt/test/hwasan/TestCases/global-with-reduction.c diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 2563a07b4034..73a4be54861b 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7859,6 +7859,11 @@ static bool isGlobalVar(const Decl *D) { return false; } +static bool isSanitizerAttributeAllowedOnGlobals(StringRef Sanitizer) { + return Sanitizer == "address" || Sanitizer == "hwaddress" || + Sanitizer == "memtag"; +} + static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.checkAtLeastNumArgs(S, 1)) return; @@ -7876,7 +7881,7 @@ static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { SanitizerMask() && SanitizerName != "coverage") S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName; - else if (isGlobalVar(D) && SanitizerName != "address") + else if (isGlobalVar(D) && !isSanitizerAttributeAllowedOnGlobals(SanitizerName)) S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) << AL << ExpectedFunctionOrMethod; Sanitizers.push_back(SanitizerName); diff --git a/clang/test/CodeGen/Inputs/sanitizer-extra-source.cpp b/clang/test/CodeGen/Inputs/sanitizer-extra-source.cpp new file mode 100644 index 000000000000..21371d534255 --- /dev/null +++ b/clang/test/CodeGen/Inputs/sanitizer-extra-source.cpp @@ -0,0 +1 @@ +int extra_global; diff --git a/clang/test/CodeGen/Inputs/sanitizer-ignorelist-global.txt b/clang/test/CodeGen/Inputs/sanitizer-ignorelist-global.txt new file mode 100644 index 000000000000..40a1d07fb895 --- /dev/null +++ b/clang/test/CodeGen/Inputs/sanitizer-ignorelist-global.txt @@ -0,0 +1 @@ +global:*ignorelisted_global* diff --git a/clang/test/CodeGen/Inputs/sanitizer-ignorelist-src.txt b/clang/test/CodeGen/Inputs/sanitizer-ignorelist-src.txt new file mode 100644 index 000000000000..67e50c852606 --- /dev/null +++ b/clang/test/CodeGen/Inputs/sanitizer-ignorelist-src.txt @@ -0,0 +1 @@ +src:*-globals.cpp diff --git a/clang/test/CodeGen/hwasan-globals.cpp b/clang/test/CodeGen/hwasan-globals.cpp new file mode 100644 index 000000000000..7edf6e6b7e57 --- /dev/null +++ b/clang/test/CodeGen/hwasan-globals.cpp @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 -include %S/Inputs/sanitizer-extra-source.cpp \ +// RUN: -fsanitize-ignorelist=%S/Inputs/sanitizer-ignorelist-global.txt \ +// RUN: -fsanitize=hwaddress -emit-llvm -o - %s | FileCheck %s + +// RUN: %clang_cc1 -include %S/Inputs/sanitizer-extra-source.cpp \ +// RUN: -fsanitize-ignorelist=%S/Inputs/sanitizer-ignorelist-src.txt \ +// RUN: -fsanitize=hwaddress -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefix=IGNORELIST + +int global; +int __attribute__((no_sanitize("hwaddress"))) attributed_global; +int __attribute__((disable_sanitizer_instrumentation)) disable_instrumentation_global; +int ignorelisted_global; + +void func() { + static int static_var = 0; + const char *literal = "Hello, world!"; +} + +// CHECK: @{{.*}}attributed_global{{.*}} ={{.*}} global {{.*}}, no_sanitize_hwaddress +// CHECK: @{{.*}}disable_instrumentation_global{{.*}} ={{.*}} global {{.*}}, no_sanitize_hwaddress +// CHECK: @{{.*}}ignorelisted_global{{.*}} ={{.*}} global {{.*}}, no_sanitize_hwaddress +// CHECK: @{{.*}}extra_global{{.*}}.hwasan{{.*}} = +// CHECK: @{{.*}}global{{.*}}.hwasan{{.*}} = +// CHECK: @{{.*}}static_var{{.*}}.hwasan{{.*}} = +// CHECK: @{{.*}}.hwasan{{.*}} = {{.*}} c"Hello, world!\00" + +// CHECK: !llvm.asan.globals = !{![[EXTRA_GLOBAL:[0-9]+]], ![[GLOBAL:[0-9]+]], ![[ATTR_GLOBAL:[0-9]+]], ![[DISABLE_INSTR_GLOBAL:[0-9]+]], ![[IGNORELISTED_GLOBAL:[0-9]+]], ![[STATIC_VAR:[0-9]+]], ![[LITERAL:[0-9]+]]} +// CHECK: ![[EXTRA_GLOBAL]] = !{{{.*}} ![[EXTRA_GLOBAL_LOC:[0-9]+]], !"extra_global", i1 false, i1 false} +// CHECK: ![[EXTRA_GLOBAL_LOC]] = !{!"{{.*}}extra-source.cpp", i32 1, i32 5} +// CHECK: ![[GLOBAL]] = !{{{.*}} ![[GLOBAL_LOC:[0-9]+]], !"global", i1 false, i1 false} +// CHECK: ![[GLOBAL_LOC]] = !{!"{{.*}}hwasan-globals.cpp", i32 10, i32 5} +// CHECK: ![[ATTR_GLOBAL]] = !{{{.*attributed_global.*}}, null, null, i1 false, i1 true} +// CHECK: ![[DISABLE_INSTR_GLOBAL]] = !{{{.*disable_instrumentation_global.*}}, null, null, i1 false, i1 true} +// CHECK: ![[IGNORELISTED_GLOBAL]] = !{{{.*ignorelisted_global.*}}, null, null, i1 false, i1 true} +// CHECK: ![[STATIC_VAR]] = !{{{.*}} ![[STATIC_LOC:[0-9]+]], !"static_var", i1 false, i1 false} +// CHECK: ![[STATIC_LOC]] = !{!"{{.*}}hwasan-globals.cpp", i32 16, i32 14} +// CHECK: ![[LITERAL]] = !{{{.*}} ![[LITERAL_LOC:[0-9]+]], !"", i1 false, i1 false} +// CHECK: ![[LITERAL_LOC]] = !{!"{{.*}}hwasan-globals.cpp", i32 17, i32 25} + +// IGNORELIST: @{{.*}}global{{.*}} ={{.*}} global {{.*}}, no_sanitize_hwaddress +// IGNORELIST: @{{.*}}attributed_global{{.*}} ={{.*}} global {{.*}}, no_sanitize_hwaddress +// IGNORELIST: @{{.*}}disable_instrumentation_global{{.*}} ={{.*}} global {{.*}}, no_sanitize_hwaddress +// IGNORELIST: @{{.*}}ignorelisted_globa{{.*}} ={{.*}} global {{.*}}, no_sanitize_hwaddress +// IGNORELIST: @{{.*}}static_var{{.*}} ={{.*}} global {{.*}}, no_sanitize_hwaddress +// IGNORELIST: @{{.*}} = {{.*}} c"Hello, world!\00"{{.*}}, no_sanitize_hwaddress +// IGNORELIST: @{{.*}}extra_global{{.*}}.hwasan{{.*}} = + +// IGNORELIST: !llvm.asan.globals = !{![[EXTRA_GLOBAL:[0-9]+]], ![[GLOBAL:[0-9]+]], ![[ATTR_GLOBAL:[0-9]+]], ![[DISABLE_INSTR_GLOBAL:[0-9]+]], ![[IGNORELISTED_GLOBAL:[0-9]+]], ![[STATIC_VAR:[0-9]+]], ![[LITERAL:[0-9]+]]} +// IGNORELIST: ![[EXTRA_GLOBAL]] = !{{{.*}} ![[EXTRA_GLOBAL_LOC:[0-9]+]], !"extra_global", i1 false, i1 false} +// IGNORELIST: ![[EXTRA_GLOBAL_LOC]] = !{!"{{.*}}extra-source.cpp", i32 1, i32 5} +// IGNORELIST: ![[GLOBAL]] = !{{{.*}} null, null, i1 false, i1 true} +// IGNORELIST: ![[ATTR_GLOBAL]] = !{{{.*attributed_global.*}}, null, null, i1 false, i1 true} +// IGNORELIST: ![[DISABLE_INSTR_GLOBAL]] = !{{{.*disable_instrumentation_global.*}}, null, null, i1 false, i1 true} +// IGNORELIST: ![[IGNORELISTED_GLOBAL]] = !{{{.*ignorelisted_global.*}}, null, null, i1 false, i1 true} +// IGNORELIST: ![[STATIC_VAR]] = !{{{.*}} null, null, i1 false, i1 true} +// IGNORELIST: ![[LITERAL]] = !{{{.*}} null, null, i1 false, i1 true} diff --git a/clang/test/CodeGen/memtag-globals.cpp b/clang/test/CodeGen/memtag-globals.cpp new file mode 100644 index 000000000000..6deb0e2ad0bd --- /dev/null +++ b/clang/test/CodeGen/memtag-globals.cpp @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -include %S/Inputs/sanitizer-extra-source.cpp \ +// RUN: -fsanitize-ignorelist=%S/Inputs/sanitizer-ignorelist-global.txt \ +// RUN: -fsanitize=memtag-globals -emit-llvm -o - %s | FileCheck %s + +// RUN: %clang_cc1 -include %S/Inputs/sanitizer-extra-source.cpp \ +// RUN: -fsanitize-ignorelist=%S/Inputs/sanitizer-ignorelist-src.txt \ +// RUN: -fsanitize=memtag-globals -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefix=IGNORELIST + +int global; +int __attribute__((no_sanitize("memtag"))) attributed_global; +int __attribute__((disable_sanitizer_instrumentation)) disable_instrumentation_global; +int ignorelisted_global; + +void func() { + static int static_var = 0; + const char *literal = "Hello, world!"; +} + +// CHECK: @{{.*}}extra_global{{.*}} = +// CHECK-NOT: no_sanitize_memtag +// CHECK: @{{.*}}global{{.*}} = +// CHECK-NOT: no_sanitize_memtag +// CHECK: @{{.*}}attributed_global{{.*}} ={{.*}} global {{.*}}, no_sanitize_memtag +// CHECK: @{{.*}}disable_instrumentation_global{{.*}} ={{.*}} global {{.*}}, no_sanitize_memtag +// CHECK: @{{.*}}ignorelisted_global{{.*}} ={{.*}} global {{.*}}, no_sanitize_memtag +// CHECK: @{{.*}}static_var{{.*}} = +// CHECK-NOT: no_sanitize_memtag +// CHECK: @{{.*}} = {{.*}} c"Hello, world!\00" +// CHECK-NOT: no_sanitize_memtag + +// CHECK: !llvm.asan.globals = !{![[EXTRA_GLOBAL:[0-9]+]], ![[GLOBAL:[0-9]+]], ![[ATTR_GLOBAL:[0-9]+]], ![[DISABLE_INSTR_GLOBAL:[0-9]+]], ![[IGNORELISTED_GLOBAL:[0-9]+]], ![[STATIC_VAR:[0-9]+]], ![[LITERAL:[0-9]+]]} +// CHECK: ![[EXTRA_GLOBAL]] = !{{{.*}} ![[EXTRA_GLOBAL_LOC:[0-9]+]], !"extra_global", i1 false, i1 false} +// CHECK: ![[EXTRA_GLOBAL_LOC]] = !{!"{{.*}}extra-source.cpp", i32 1, i32 5} +// CHECK: ![[GLOBAL]] = !{{{.*}} ![[GLOBAL_LOC:[0-9]+]], !"global", i1 false, i1 false} +// CHECK: ![[GLOBAL_LOC]] = !{!"{{.*}}memtag-globals.cpp", i32 10, i32 5} +// CHECK: ![[ATTR_GLOBAL]] = !{{{.*attributed_global.*}}, null, null, i1 false, i1 true} +// CHECK: ![[DISABLE_INSTR_GLOBAL]] = !{{{.*disable_instrumentation_global.*}}, null, null, i1 false, i1 true} +// CHECK: ![[IGNORELISTED_GLOBAL]] = !{{{.*ignorelisted_global.*}}, null, null, i1 false, i1 true} +// CHECK: ![[STATIC_VAR]] = !{{{.*}} ![[STATIC_LOC:[0-9]+]], !"static_var", i1 false, i1 false} +// CHECK: ![[STATIC_LOC]] = !{!"{{.*}}memtag-globals.cpp", i32 16, i32 14} +// CHECK: ![[LITERAL]] = !{{{.*}} ![[LITERAL_LOC:[0-9]+]], !"", i1 false, i1 false} +// CHECK: ![[LITERAL_LOC]] = !{!"{{.*}}memtag-globals.cpp", i32 17, i32 25} + +// IGNORELIST: @{{.*}}extra_global{{.*}} ={{.*}} global +// IGNORELIST-NOT: no_sanitize_memtag +// IGNORELIST: @{{.*}}global{{.*}} ={{.*}} global {{.*}}, no_sanitize_memtag +// IGNORELIST: @{{.*}}attributed_global{{.*}} ={{.*}} global {{.*}}, no_sanitize_memtag +// IGNORELIST: @{{.*}}disable_instrumentation_global{{.*}} ={{.*}} global {{.*}}, no_sanitize_memtag +// IGNORELIST: @{{.*}}ignorelisted_globa{{.*}} ={{.*}} global {{.*}}, no_sanitize_memtag +// IGNORELIST: @{{.*}}static_var{{.*}} ={{.*}} global {{.*}}, no_sanitize_memtag +// IGNORELIST: @{{.*}} = {{.*}} c"Hello, world!\00"{{.*}}, no_sanitize_memtag + +// IGNORELIST: !llvm.asan.globals = !{![[EXTRA_GLOBAL:[0-9]+]], ![[GLOBAL:[0-9]+]], ![[ATTR_GLOBAL:[0-9]+]], ![[DISABLE_INSTR_GLOBAL:[0-9]+]], ![[IGNORELISTED_GLOBAL:[0-9]+]], ![[STATIC_VAR:[0-9]+]], ![[LITERAL:[0-9]+]]} +// IGNORELIST: ![[EXTRA_GLOBAL]] = !{{{.*}} ![[EXTRA_GLOBAL_LOC:[0-9]+]], !"extra_global", i1 false, i1 false} +// IGNORELIST: ![[EXTRA_GLOBAL_LOC]] = !{!"{{.*}}extra-source.cpp", i32 1, i32 5} +// IGNORELIST: ![[GLOBAL]] = !{{{.*}} null, null, i1 false, i1 true} +// IGNORELIST: ![[ATTR_GLOBAL]] = !{{{.*attributed_global.*}}, null, null, i1 false, i1 true} +// IGNORELIST: ![[DISABLE_INSTR_GLOBAL]] = !{{{.*disable_instrumentation_global.*}}, null, null, i1 false, i1 true} +// IGNORELIST: ![[IGNORELISTED_GLOBAL]] = !{{{.*ignorelisted_global.*}}, null, null, i1 false, i1 true} +// IGNORELIST: ![[STATIC_VAR]] = !{{{.*}} null, null, i1 false, i1 true} +// IGNORELIST: ![[LITERAL]] = !{{{.*}} null, null, i1 false, i1 true} diff --git a/compiler-rt/test/hwasan/TestCases/global-with-reduction.c b/compiler-rt/test/hwasan/TestCases/global-with-reduction.c new file mode 100644 index 000000000000..22a4efccc5ed --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/global-with-reduction.c @@ -0,0 +1,50 @@ +// RUN: %clang_hwasan %s -o %t +// RUN: %run %t 0 +// RUN: not %run %t 1 2>&1 | FileCheck --check-prefixes=CHECK,RSYM %s +// RUN: not %env_hwasan_opts=symbolize=0 %run %t 1 2>&1 | FileCheck --check-prefixes=CHECK,RNOSYM %s +// RUN: not %run %t -1 2>&1 | FileCheck --check-prefixes=CHECK,LSYM %s +// RUN: not %env_hwasan_opts=symbolize=0 %run %t -1 2>&1 | FileCheck --check-prefixes=CHECK,LNOSYM %s + +// Test with and without optimizations, with and without PIC, since different +// backend passes run depending on these flags. +// RUN: %clang_hwasan -fno-pic %s -o %t +// RUN: not %run %t 1 2>&1 | FileCheck --check-prefixes=CHECK,RSYM %s +// RUN: %clang_hwasan -fno-pic -O2 %s -o %t +// RUN: not %run %t 1 2>&1 | FileCheck --check-prefixes=CHECK,RSYM %s +// RUN: %clang_hwasan -O2 %s -o %t +// RUN: not %run %t 1 2>&1 | FileCheck --check-prefixes=CHECK,RSYM %s + +// RUN: %clang_hwasan -DUSE_NOSANITIZE %s -o %t && %run %t 0 +// RUN: %clang_hwasan -DUSE_NOSANITIZE %s -o %t && %run %t 1 +// RUN: %clang_hwasan -DUSE_NOSANITIZE %s -o %t -fno-pic && %run %t 1 +// RUN: %clang_hwasan -DUSE_NOSANITIZE %s -o %t -O2 && %run %t 1 +// RUN: %clang_hwasan -DUSE_NOSANITIZE %s -o %t -fno-pic -O2 && %run %t 1 + +// REQUIRES: pointer-tagging + +#include + +// GlobalOpt may replace the current GV with a new boolean-typed GV. Previously, +// this resulted in the "nosanitize" getting dropped because while the data/code +// references to the GV were updated, the old metadata references weren't. +int* f() { +#ifdef USE_NOSANITIZE +__attribute__((no_sanitize("hwaddress"))) static int x = 1; +#else // USE_NOSANITIZE + static int x = 1; +#endif // USE_NOSANITIZE + if (x == 1) x = 0; + return &x; +} + +int main(int argc, char **argv) { + // CHECK: Cause: global-overflow + // RSYM: is located 0 bytes to the right of 4-byte global variable f.x {{.*}} in {{.*}}global-with-reduction.c.tmp + // RNOSYM: is located to the right of a 4-byte global variable in + // RNOSYM-NEXT: #0 0x{{.*}} ({{.*}}global-with-reduction.c.tmp+{{.*}}) + // LSYM: is located 4 bytes to the left of 4-byte global variable f.x {{.*}} in {{.*}}global-with-reduction.c.tmp + // LNOSYM: is located to the left of a 4-byte global variable in + // LNOSYM-NEXT: #0 0x{{.*}} ({{.*}}global-with-reduction.c.tmp+{{.*}}) + // CHECK-NOT: can not describe + f()[atoi(argv[1])] = 1; +} diff --git a/compiler-rt/test/hwasan/TestCases/global.c b/compiler-rt/test/hwasan/TestCases/global.c index 2da3b6dce964..4a790e2d08be 100644 --- a/compiler-rt/test/hwasan/TestCases/global.c +++ b/compiler-rt/test/hwasan/TestCases/global.c @@ -14,9 +14,23 @@ // RUN: %clang_hwasan -O2 %s -o %t // RUN: not %run %t 1 2>&1 | FileCheck --check-prefixes=CHECK,RSYM %s +// RUN: %clang_hwasan -DUSE_NOSANITIZE %s -o %t && %run %t 0 +// RUN: %clang_hwasan -DUSE_NOSANITIZE %s -o %t && %run %t 1 +// RUN: %clang_hwasan -DUSE_NOSANITIZE %s -o %t -fno-pic && %run %t 1 +// RUN: %clang_hwasan -DUSE_NOSANITIZE %s -o %t -O2 && %run %t 1 +// RUN: %clang_hwasan -DUSE_NOSANITIZE %s -o %t -fno-pic -O2 && %run %t 1 + // REQUIRES: pointer-tagging +#include + +int a = 1; +#ifdef USE_NOSANITIZE +__attribute__((no_sanitize("hwaddress"))) int x = 1; +#else // USE_NOSANITIZE int x = 1; +#endif // USE_NOSANITIZE +int b = 1; int atoi(const char *);