[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