[compiler-rt] c533b88 - [DFSan] Add force_zero_label abilist option to DFSan. This can be used as a work-around for overtainting.

Andrew Browne via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 17 12:58:32 PDT 2021


Author: Andrew Browne
Date: 2021-09-17T12:57:40-07:00
New Revision: c533b88a6dc970b5f98451bb3e676cdf6e9129f8

URL: https://github.com/llvm/llvm-project/commit/c533b88a6dc970b5f98451bb3e676cdf6e9129f8
DIFF: https://github.com/llvm/llvm-project/commit/c533b88a6dc970b5f98451bb3e676cdf6e9129f8.diff

LOG: [DFSan] Add force_zero_label abilist option to DFSan. This can be used as a work-around for overtainting.

Reviewed By: morehouse

Differential Revision: https://reviews.llvm.org/D109847

Added: 
    compiler-rt/test/dfsan/force_zero.c
    llvm/test/Instrumentation/DataFlowSanitizer/force_zero.ll

Modified: 
    clang/docs/DataFlowSanitizer.rst
    compiler-rt/test/dfsan/Inputs/flags_abilist.txt
    llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
    llvm/test/Instrumentation/DataFlowSanitizer/Inputs/abilist.txt

Removed: 
    


################################################################################
diff  --git a/clang/docs/DataFlowSanitizer.rst b/clang/docs/DataFlowSanitizer.rst
index 1253cb98e6349..cce50dc913185 100644
--- a/clang/docs/DataFlowSanitizer.rst
+++ b/clang/docs/DataFlowSanitizer.rst
@@ -137,6 +137,20 @@ For example:
   fun:memcpy=uninstrumented
   fun:memcpy=custom
 
+For instrumented functions, the ABI list supports a ``force_zero_labels``
+category, which will make all stores and return values set zero labels.
+Functions should never be labelled with both ``force_zero_labels``
+and ``uninstrumented`` or any of the unistrumented wrapper kinds.
+
+For example:
+
+.. code-block:: none
+
+  # e.g. void writes_data(char* out_buf, int out_buf_len) {...}
+  # Applying force_zero_labels will force out_buf shadow to zero.
+  fun:writes_data=force_zero_labels
+
+
 Compilation Flags
 -----------------
 

diff  --git a/compiler-rt/test/dfsan/Inputs/flags_abilist.txt b/compiler-rt/test/dfsan/Inputs/flags_abilist.txt
index 94b1fa2982599..ce827dd7a642d 100644
--- a/compiler-rt/test/dfsan/Inputs/flags_abilist.txt
+++ b/compiler-rt/test/dfsan/Inputs/flags_abilist.txt
@@ -1,10 +1,9 @@
 fun:f=uninstrumented
 
+fun:function_to_force_zero=force_zero_labels
+
 fun:main=uninstrumented
 fun:main=discard
 
-fun:dfsan_create_label=uninstrumented
-fun:dfsan_create_label=discard
-
 fun:dfsan_set_label=uninstrumented
 fun:dfsan_set_label=discard

diff  --git a/compiler-rt/test/dfsan/force_zero.c b/compiler-rt/test/dfsan/force_zero.c
new file mode 100644
index 0000000000000..6e1e87a6e6721
--- /dev/null
+++ b/compiler-rt/test/dfsan/force_zero.c
@@ -0,0 +1,32 @@
+// RUN: %clang_dfsan %s -fsanitize-ignorelist=%S/Inputs/flags_abilist.txt -DFORCE_ZERO_LABELS -o %t && %run %t
+// RUN: %clang_dfsan %s -o %t && %run %t
+//
+// REQUIRES: x86_64-target-arch
+
+#include <sanitizer/dfsan_interface.h>
+
+#include <assert.h>
+
+int function_to_force_zero(int i, int* out) {
+  *out = i;
+  return i;
+}
+
+int main(void) {
+  int i = 1;
+  dfsan_label i_label = 2;
+  dfsan_set_label(i_label, &i, sizeof(i));
+
+  int out = 0;
+  int ret = function_to_force_zero(i, &out);
+
+#ifdef FORCE_ZERO_LABELS
+  assert(dfsan_get_label(out) == 0);
+  assert(dfsan_get_label(ret) == 0);
+#else
+  assert(dfsan_get_label(out) == i_label);
+  assert(dfsan_get_label(ret) == i_label);
+#endif
+
+  return 0;
+}

diff  --git a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
index 6a62f5e9ad774..2b9fd1dfd105f 100644
--- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
@@ -144,8 +144,17 @@ static cl::opt<bool> ClPreserveAlignment(
 // to the "native" (i.e. unsanitized) ABI.  Unless the ABI list contains
 // additional annotations for those functions, a call to one of those functions
 // will produce a warning message, as the labelling behaviour of the function is
-// unknown.  The other supported annotations are "functional" and "discard",
-// which are described below under DataFlowSanitizer::WrapperKind.
+// unknown. The other supported annotations for uninstrumented functions are
+// "functional" and "discard", which are described below under
+// DataFlowSanitizer::WrapperKind.
+// Functions will often be labelled with both "uninstrumented" and one of
+// "functional" or "discard". This will leave the function unchanged by this
+// pass, and create a wrapper function that will call the original.
+//
+// Instrumented functions can also be annotated as "force_zero_labels", which
+// will make all shadow and return values set zero labels.
+// Functions should never be labelled with both "force_zero_labels" and
+// "uninstrumented" or any of the unistrumented wrapper kinds.
 static cl::list<std::string> ClABIListFiles(
     "dfsan-abilist",
     cl::desc("File listing native ABI functions and how the pass treats them"),
@@ -469,6 +478,7 @@ class DataFlowSanitizer {
   getShadowOriginAddress(Value *Addr, Align InstAlignment, Instruction *Pos);
   bool isInstrumented(const Function *F);
   bool isInstrumented(const GlobalAlias *GA);
+  bool isForceZeroLabels(const Function *F);
   FunctionType *getArgsFunctionType(FunctionType *T);
   FunctionType *getTrampolineFunctionType(FunctionType *T);
   TransformedFunction getCustomFunctionType(FunctionType *T);
@@ -541,6 +551,7 @@ struct DFSanFunction {
   DominatorTree DT;
   DataFlowSanitizer::InstrumentedABI IA;
   bool IsNativeABI;
+  bool IsForceZeroLabels;
   AllocaInst *LabelReturnAlloca = nullptr;
   AllocaInst *OriginReturnAlloca = nullptr;
   DenseMap<Value *, Value *> ValShadowMap;
@@ -571,8 +582,10 @@ struct DFSanFunction {
   DenseMap<Value *, Value *> CachedCollapsedShadows;
   DenseMap<Value *, std::set<Value *>> ShadowElements;
 
-  DFSanFunction(DataFlowSanitizer &DFS, Function *F, bool IsNativeABI)
-      : DFS(DFS), F(F), IA(DFS.getInstrumentedABI()), IsNativeABI(IsNativeABI) {
+  DFSanFunction(DataFlowSanitizer &DFS, Function *F, bool IsNativeABI,
+                bool IsForceZeroLabels)
+      : DFS(DFS), F(F), IA(DFS.getInstrumentedABI()), IsNativeABI(IsNativeABI),
+        IsForceZeroLabels(IsForceZeroLabels) {
     DT.recalculate(*F);
   }
 
@@ -1107,6 +1120,10 @@ bool DataFlowSanitizer::isInstrumented(const GlobalAlias *GA) {
   return !ABIList.isIn(*GA, "uninstrumented");
 }
 
+bool DataFlowSanitizer::isForceZeroLabels(const Function *F) {
+  return ABIList.isIn(*F, "force_zero_labels");
+}
+
 DataFlowSanitizer::InstrumentedABI DataFlowSanitizer::getInstrumentedABI() {
   return ClArgsABI ? IA_Args : IA_TLS;
 }
@@ -1197,7 +1214,8 @@ Constant *DataFlowSanitizer::getOrBuildTrampolineFunction(FunctionType *FT,
 
     // F is called by a wrapped custom function with primitive shadows. So
     // its arguments and return value need conversion.
-    DFSanFunction DFSF(*this, F, /*IsNativeABI=*/true);
+    DFSanFunction DFSF(*this, F, /*IsNativeABI=*/true,
+                       /*ForceZeroLabels=*/false);
     Function::arg_iterator ValAI = F->arg_begin(), ShadowAI = AI;
     ++ValAI;
     for (unsigned N = FT->getNumParams(); N != 0; ++ValAI, ++ShadowAI, --N) {
@@ -1399,6 +1417,7 @@ bool DataFlowSanitizer::runImpl(Module &M) {
 
   std::vector<Function *> FnsToInstrument;
   SmallPtrSet<Function *, 2> FnsWithNativeABI;
+  SmallPtrSet<Function *, 2> FnsWithForceZeroLabel;
   for (Function &F : M)
     if (!F.isIntrinsic() && !DFSanRuntimeFunctions.contains(&F))
       FnsToInstrument.push_back(&F);
@@ -1446,6 +1465,9 @@ bool DataFlowSanitizer::runImpl(Module &M) {
                               FT->getReturnType()->isVoidTy());
 
     if (isInstrumented(&F)) {
+      if (isForceZeroLabels(&F))
+        FnsWithForceZeroLabel.insert(&F);
+
       // Instrumented functions get a '.dfsan' suffix.  This allows us to more
       // easily identify cases of mismatching ABIs. This naming scheme is
       // mangling-compatible (see Itanium ABI), using a vendor-specific suffix.
@@ -1541,7 +1563,8 @@ bool DataFlowSanitizer::runImpl(Module &M) {
 
     removeUnreachableBlocks(*F);
 
-    DFSanFunction DFSF(*this, F, FnsWithNativeABI.count(F));
+    DFSanFunction DFSF(*this, F, FnsWithNativeABI.count(F),
+                       FnsWithForceZeroLabel.count(F));
 
     // DFSanVisitor may create new basic blocks, which confuses df_iterator.
     // Build a copy of the list before iterating over it.
@@ -1705,6 +1728,8 @@ Value *DFSanFunction::getShadowForTLSArgument(Argument *A) {
 Value *DFSanFunction::getShadow(Value *V) {
   if (!isa<Argument>(V) && !isa<Instruction>(V))
     return DFS.getZeroShadow(V);
+  if (IsForceZeroLabels)
+    return DFS.getZeroShadow(V);
   Value *&Shadow = ValShadowMap[V];
   if (!Shadow) {
     if (Argument *A = dyn_cast<Argument>(V)) {

diff  --git a/llvm/test/Instrumentation/DataFlowSanitizer/Inputs/abilist.txt b/llvm/test/Instrumentation/DataFlowSanitizer/Inputs/abilist.txt
index 712440e633a1b..712c9dbceea7e 100644
--- a/llvm/test/Instrumentation/DataFlowSanitizer/Inputs/abilist.txt
+++ b/llvm/test/Instrumentation/DataFlowSanitizer/Inputs/abilist.txt
@@ -8,3 +8,5 @@ fun:custom*=uninstrumented
 fun:custom*=custom
 
 fun:uninstrumented*=uninstrumented
+
+fun:function_to_force_zero=force_zero_labels

diff  --git a/llvm/test/Instrumentation/DataFlowSanitizer/force_zero.ll b/llvm/test/Instrumentation/DataFlowSanitizer/force_zero.ll
new file mode 100644
index 0000000000000..18232557064cd
--- /dev/null
+++ b/llvm/test/Instrumentation/DataFlowSanitizer/force_zero.ll
@@ -0,0 +1,16 @@
+; RUN: opt < %s -dfsan -dfsan-abilist=%S/Inputs/abilist.txt -S | FileCheck %s -DSHADOW_XOR_MASK=87960930222080
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-linux-gnu"
+
+define i32 @function_to_force_zero(i32 %0, i32* %1) {
+  ; CHECK-LABEL: define i32 @function_to_force_zero.dfsan
+  ; CHECK: %[[#SHADOW_XOR:]] = xor i64 {{.*}}, [[SHADOW_XOR_MASK]]
+  ; CHECK: %[[#SHADOW_PTR:]] = inttoptr i64 %[[#SHADOW_XOR]] to i8*
+  ; CHECK: %[[#SHADOW_BITCAST:]] = bitcast i8* %[[#SHADOW_PTR]] to i32*
+  ; CHECK: store i32 0, i32* %[[#SHADOW_BITCAST]]
+  ; CHECK: store i32 %{{.*}}
+  store i32 %0, i32* %1, align 4
+  ; CHECK: store i8 0, {{.*}}@__dfsan_retval_tls
+  ; CHECK: ret i32
+  ret i32 %0
+}


        


More information about the llvm-commits mailing list