diff --git a/compiler-rt/test/dfsan/origin_memcpy.c b/compiler-rt/test/dfsan/origin_memcpy.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/dfsan/origin_memcpy.c @@ -0,0 +1,67 @@ +// RUN: %clang_dfsan -gmlt -DOFFSET=0 -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \ +// RUN: %run %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK0 < %t.out + +// RUN: %clang_dfsan -gmlt -DOFFSET=10 -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \ +// RUN: %run %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK10 < %t.out + +#include + +#include + +int xx[10000]; +int yy[10000]; +volatile int idx = 30; + +__attribute__((noinline)) +void fn_g(int a, int b) { + xx[idx] = a; xx[idx + 10] = b; +} + +__attribute__((noinline)) +void fn_f(int a, int b) { + fn_g(a, b); +} + +__attribute__((noinline)) +void fn_h() { + memcpy(&yy, &xx, sizeof(xx)); +} + +int main(int argc, char *argv[]) { + int volatile z1 = 0; + int volatile z2 = 0; + dfsan_set_label(8, (void *)&z1, sizeof(z1)); + dfsan_set_label(16, (void *)&z2, sizeof(z2)); + fn_f(z1, z2); + fn_h(); + dfsan_print_origin_trace(&yy[idx + OFFSET], NULL); + return 0; +} + +// CHECK0: Taint value 0x8 {{.*}} origin tracking () +// CHECK0: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK0: #0 {{.*}} in dfs$fn_h {{.*}}origin_memcpy.c:[[@LINE-16]] +// CHECK0: #1 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-8]] + +// CHECK0: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK0: #0 {{.*}} in dfs$fn_g {{.*}}origin_memcpy.c:[[@LINE-30]] +// CHECK0: #1 {{.*}} in dfs$fn_f {{.*}}origin_memcpy.c:[[@LINE-26]] +// CHECK0: #2 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-14]] + +// CHECK0: Origin value: {{.*}}, Taint value was created at +// CHECK0: #0 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-19]] + +// CHECK10: Taint value 0x10 {{.*}} origin tracking () +// CHECK10: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK10: #0 {{.*}} in dfs$fn_h {{.*}}origin_memcpy.c:[[@LINE-29]] +// CHECK10: #1 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-21]] + +// CHECK10: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK10: #0 {{.*}} in dfs$fn_g {{.*}}origin_memcpy.c:[[@LINE-43]] +// CHECK10: #1 {{.*}} in dfs$fn_f {{.*}}origin_memcpy.c:[[@LINE-39]] +// CHECK10: #2 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-27]] + +// CHECK10: Origin value: {{.*}}, Taint value was created at +// CHECK10: #0 {{.*}} in main {{.*}}origin_memcpy.c:[[@LINE-31]] diff --git a/compiler-rt/test/dfsan/origin_memmove.c b/compiler-rt/test/dfsan/origin_memmove.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/dfsan/origin_memmove.c @@ -0,0 +1,67 @@ +// RUN: %clang_dfsan -gmlt -DOFFSET=0 -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \ +// RUN: %run %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK0 < %t.out + +// RUN: %clang_dfsan -gmlt -DOFFSET=10 -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \ +// RUN: %run %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK10 < %t.out + +#include + +#include + +int xx[10000]; + +volatile int idx = 30; + +__attribute__((noinline)) +void fn_g(int a, int b) { + xx[idx] = a; xx[idx + 10] = b; +} + +__attribute__((noinline)) +void fn_f(int a, int b) { + fn_g(a, b); +} + +__attribute__((noinline)) +void fn_h() { + memmove(&xx[24], &xx, 7500); +} + +int main(int argc, char *argv[]) { + int volatile z1 = 0; + int volatile z2 = 0; + dfsan_set_label(8, (void *)&z1, sizeof(z1)); + dfsan_set_label(16, (void *)&z2, sizeof(z2)); + fn_f(z1, z2); + fn_h(); + dfsan_print_origin_trace(&xx[24 + idx + OFFSET], NULL); + return 0; +} + +// CHECK0: Taint value 0x8 {{.*}} origin tracking () +// CHECK0: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK0: #0 {{.*}} in dfs$fn_h {{.*}}origin_memmove.c:[[@LINE-16]] +// CHECK0: #1 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-8]] + +// CHECK0: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK0: #0 {{.*}} in dfs$fn_g {{.*}}origin_memmove.c:[[@LINE-30]] +// CHECK0: #1 {{.*}} in dfs$fn_f {{.*}}origin_memmove.c:[[@LINE-26]] +// CHECK0: #2 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-14]] + +// CHECK0: Origin value: {{.*}}, Taint value was created at +// CHECK0: #0 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-19]] + +// CHECK10: Taint value 0x10 {{.*}} origin tracking () +// CHECK10: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK10: #0 {{.*}} in dfs$fn_h {{.*}}origin_memmove.c:[[@LINE-29]] +// CHECK10: #1 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-21]] + +// CHECK10: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK10: #0 {{.*}} in dfs$fn_g {{.*}}origin_memmove.c:[[@LINE-43]] +// CHECK10: #1 {{.*}} in dfs$fn_f {{.*}}origin_memmove.c:[[@LINE-39]] +// CHECK10: #2 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-27]] + +// CHECK10: Origin value: {{.*}}, Taint value was created at +// CHECK10: #0 {{.*}} in main {{.*}}origin_memmove.c:[[@LINE-31]] diff --git a/compiler-rt/test/dfsan/origin_unaligned_memtrans.c b/compiler-rt/test/dfsan/origin_unaligned_memtrans.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/dfsan/origin_unaligned_memtrans.c @@ -0,0 +1,78 @@ +// RUN: %clang_dfsan -gmlt -DOFFSET=0 -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \ +// RUN: %run %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK0 < %t.out + +// RUN: %clang_dfsan -gmlt -DOFFSET=10 -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \ +// RUN: %run %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK10 < %t.out + +#include + +#include + +char xx[10000]; +char yy[10000]; +volatile int idx = 30; + +__attribute__((noinline)) void fn_g(char a, char b) { + xx[idx] = a; xx[idx + 10] = b; +} + +__attribute__((noinline)) void fn_f(char a, char b) { + fn_g(a, b); +} + +__attribute__((noinline)) void fn_h() { + memcpy(&yy[2], &xx[2], sizeof(xx) - 4); +} + +__attribute__((noinline)) void fn_i() { + memmove(&yy[25], &yy, 7500); +} + +int main(int argc, char *argv[]) { + char volatile z1 = 0; + int volatile buffer = 0; + char volatile z2 = 0; + dfsan_set_label(8, (void *)&z1, sizeof(z1)); + dfsan_set_label(16, (void *)&z2, sizeof(z2)); + fn_f(z1, z2); + fn_h(); + fn_i(); + dfsan_print_origin_trace(&yy[25 + idx + OFFSET], NULL); + return 0; +} + +// CHECK0: Taint value 0x8 {{.*}} origin tracking () +// CHECK0: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK0: #0 {{.*}} in dfs$fn_i {{.*}}origin_unaligned_memtrans.c:[[@LINE-18]] +// CHECK0: #1 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-8]] + +// CHECK0: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK0: #0 {{.*}} in dfs$fn_h {{.*}}origin_unaligned_memtrans.c:[[@LINE-26]] +// CHECK0: #1 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-13]] + +// CHECK0: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK0: #0 {{.*}} in dfs$fn_g {{.*}}origin_unaligned_memtrans.c:[[@LINE-38]] +// CHECK0: #1 {{.*}} in dfs$fn_f {{.*}}origin_unaligned_memtrans.c:[[@LINE-35]] +// CHECK0: #2 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-19]] + +// CHECK0: Origin value: {{.*}}, Taint value was created at +// CHECK0: #0 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-24]] + +// CHECK10: Taint value 0x10 {{.*}} origin tracking +// CHECK10: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK10: #0 {{.*}} in dfs$fn_i {{.*}}origin_unaligned_memtrans.c:[[@LINE-35]] +// CHECK10: #1 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-25]] + +// CHECK10: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK10: #0 {{.*}} in dfs$fn_h {{.*}}origin_unaligned_memtrans.c:[[@LINE-43]] +// CHECK10: #1 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-30]] + +// CHECK10: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK10: #0 {{.*}} in dfs$fn_g {{.*}}origin_unaligned_memtrans.c:[[@LINE-55]] +// CHECK10: #1 {{.*}} in dfs$fn_f {{.*}}origin_unaligned_memtrans.c:[[@LINE-52]] +// CHECK10: #2 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-36]] + +// CHECK10: Origin value: {{.*}}, Taint value was created at +// CHECK10: #0 {{.*}} in main {{.*}}origin_unaligned_memtrans.c:[[@LINE-40]] diff --git a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp @@ -2492,9 +2492,8 @@ PrimitiveShadow = DFSF.collapseToPrimitiveShadow(Shadow, &SI); } Value *Origin = nullptr; - if (ShouldTrackOrigins) { + if (ShouldTrackOrigins) Origin = DFSF.combineOrigins(Shadows, Origins, &SI); - } DFSF.storePrimitiveShadowOrigin(SI.getPointerOperand(), Size, SI.getAlign(), PrimitiveShadow, Origin, &SI); if (ClEventCallbacks) { @@ -2693,6 +2692,17 @@ void DFSanVisitor::visitMemTransferInst(MemTransferInst &I) { IRBuilder<> IRB(&I); + + // CopyOrMoveOrigin transfers origins by refering to their shadows. So we + // need to move origins before moving shadows. + if (DFSF.DFS.shouldTrackOrigins()) { + IRB.CreateCall( + DFSF.DFS.DFSanMemOriginTransferFn, + {IRB.CreatePointerCast(I.getArgOperand(0), IRB.getInt8PtrTy()), + IRB.CreatePointerCast(I.getArgOperand(1), IRB.getInt8PtrTy()), + IRB.CreateIntCast(I.getArgOperand(2), DFSF.DFS.IntptrTy, false)}); + } + Value *RawDestShadow = DFSF.DFS.getShadowAddress(I.getDest(), &I); Value *SrcShadow = DFSF.DFS.getShadowAddress(I.getSource(), &I); Value *LenShadow = diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/origin_mem_intrinsic.ll b/llvm/test/Instrumentation/DataFlowSanitizer/origin_mem_intrinsic.ll --- a/llvm/test/Instrumentation/DataFlowSanitizer/origin_mem_intrinsic.ll +++ b/llvm/test/Instrumentation/DataFlowSanitizer/origin_mem_intrinsic.ll @@ -2,13 +2,40 @@ 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-S128" target triple = "x86_64-unknown-linux-gnu" +; CHECK: @__dfsan_shadow_width_bits = weak_odr constant i32 [[#SBITS:]] +; CHECK: @__dfsan_shadow_width_bytes = weak_odr constant i32 [[#SBYTES:]] + +declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) +declare void @llvm.memmove.p0i8.p0i8.i32(i8*, i8*, i32, i1) declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i1) +define void @memcpy(i8* %d, i8* %s, i32 %l) { + ; CHECK: @"dfs$memcpy" + ; CHECK: [[L64:%.*]] = zext i32 %l to i64 + ; CHECK: call void @__dfsan_mem_origin_transfer(i8* %d, i8* %s, i64 [[L64]]) + ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 2 {{.*}}, i8* align 2 {{.*}}, i32 {{.*}}, i1 false) + ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %d, i8* %s, i32 %l, i1 false) + + call void @llvm.memcpy.p0i8.p0i8.i32(i8* %d, i8* %s, i32 %l, i1 0) + ret void +} + +define void @memmove(i8* %d, i8* %s, i32 %l) { + ; CHECK: @"dfs$memmove" + ; CHECK: [[L64:%.*]] = zext i32 %l to i64 + ; CHECK: call void @__dfsan_mem_origin_transfer(i8* %d, i8* %s, i64 [[L64]]) + ; CHECK: call void @llvm.memmove.p0i8.p0i8.i32(i8* align 2 {{.*}}, i8* align 2 {{.*}}, i32 {{.*}}, i1 false) + ; CHECK: call void @llvm.memmove.p0i8.p0i8.i32(i8* %d, i8* %s, i32 %l, i1 false) + + call void @llvm.memmove.p0i8.p0i8.i32(i8* %d, i8* %s, i32 %l, i1 0) + ret void +} + define void @memset(i8* %p, i8 %v) { ; CHECK: @"dfs$memset" ; CHECK: [[O:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 1), align 4 - ; CHECK: [[S:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 2) to i16*), align 2 - ; CHECK: call void @__dfsan_set_label(i16 [[S]], i32 [[O]], i8* %p, i64 1) + ; CHECK: [[S:%.*]] = load i[[#SBITS]], i[[#SBITS]]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 2) to i[[#SBITS]]*), align [[#SBYTES]] + ; CHECK: call void @__dfsan_set_label(i[[#SBITS]] [[S]], i32 [[O]], i8* %p, i64 1) call void @llvm.memset.p0i8.i64(i8* %p, i8 %v, i64 1, i1 1) ret void } \ No newline at end of file