[compiler-rt] a11cb10 - [dfsan] Add function that prints origin stack trace to buffer

George Balatsouras via llvm-commits llvm-commits at lists.llvm.org
Mon May 24 11:09:24 PDT 2021


Author: George Balatsouras
Date: 2021-05-24T11:09:03-07:00
New Revision: a11cb10a3691ea569ab3390052cfec48ce350f27

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

LOG: [dfsan] Add function that prints origin stack trace to buffer

Reviewed By: stephan.yichao.zhao

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

Added: 
    

Modified: 
    compiler-rt/include/sanitizer/dfsan_interface.h
    compiler-rt/lib/dfsan/dfsan.cpp
    compiler-rt/lib/dfsan/done_abilist.txt
    compiler-rt/test/dfsan/origin_stack_trace.c

Removed: 
    


################################################################################
diff  --git a/compiler-rt/include/sanitizer/dfsan_interface.h b/compiler-rt/include/sanitizer/dfsan_interface.h
index 40f9379b5579c..34b0b6378d653 100644
--- a/compiler-rt/include/sanitizer/dfsan_interface.h
+++ b/compiler-rt/include/sanitizer/dfsan_interface.h
@@ -123,6 +123,43 @@ void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2,
 /// on, or the address is not labeled, it prints nothing.
 void dfsan_print_origin_trace(const void *addr, const char *description);
 
+/// Prints the origin trace of the label at the address \p addr to a
+/// pre-allocated output buffer. If origin tracking is not on, or the address is
+/// not labeled, it prints nothing.
+///
+/// Typical usage:
+/// \code
+///   char kDescription[] = "...";
+///   char buf[1024];
+///   dfsan_sprint_origin_trace(&tainted_var, kDescription, buf, sizeof(buf));
+/// \endcode
+///
+/// Typical usage that handles truncation:
+/// \code
+///   char buf[1024];
+///   int len = dfsan_sprint_origin_trace(&var, nullptr, buf, sizeof(buf));
+///
+///   if (len < sizeof(buf)) {
+///     ProcessOriginTrace(tmpbuf);
+///   else {
+///     char *tmpbuf = new char[len + 1];
+///     dfsan_sprint_origin_trace(&var, nullptr, tmpbuf, len + 1);
+///     ProcessOriginTrace(tmpbuf);
+///     delete[] tmpbuf;
+///   }
+/// \endcode
+///
+/// \param addr The tainted memory address whose origin we are printing.
+/// \param description A description printed at the beginning of the trace.
+/// \param [out] out_buf The output buffer to write the results to.
+/// \param out_buf_size The size of \p out_buf.
+///
+/// \returns The number of symbols that should have been written to \p out_buf
+/// (not including trailing null byte '\0'). Thus, the string is truncated iff
+/// return value is not less than \p out_buf_size.
+size_t dfsan_sprint_origin_trace(const void *addr, const char *description,
+                                 char *out_buf, size_t out_buf_size);
+
 /// Retrieves the very first origin associated with the data at the given
 /// address.
 dfsan_origin dfsan_get_init_origin(const void *addr);

diff  --git a/compiler-rt/lib/dfsan/dfsan.cpp b/compiler-rt/lib/dfsan/dfsan.cpp
index fb162e22f6b74..124ff97b03b3f 100644
--- a/compiler-rt/lib/dfsan/dfsan.cpp
+++ b/compiler-rt/lib/dfsan/dfsan.cpp
@@ -842,49 +842,123 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator {
   const char *Origin() const { return Magenta(); }
 };
 
-extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_print_origin_trace(
-    const void *addr, const char *description) {
+namespace {
+
+void PrintNoOriginTrackingWarning() {
   Decorator d;
+  Printf(
+      "  %sDFSan: origin tracking is not enabled. Did you specify the "
+      "-dfsan-track-origins=1 option?%s\n",
+      d.Warning(), d.Default());
+}
 
-  if (!__dfsan_get_track_origins()) {
-    Printf(
-        "  %sDFSan: origin tracking is not enabled. Did you specify the "
-        "-dfsan-track-origins=1 option?%s\n",
-        d.Warning(), d.Default());
-    return;
-  }
+void PrintNoTaintWarning(const void *address) {
+  Decorator d;
+  Printf("  %sDFSan: no tainted value at %x%s\n", d.Warning(), address,
+         d.Default());
+}
+
+void PrintInvalidOriginWarning(dfsan_label label, const void *address) {
+  Decorator d;
+  Printf(
+      "  %sTaint value 0x%x (at %p) has invalid origin tracking. This can "
+      "be a DFSan bug.%s\n",
+      d.Warning(), label, address, d.Default());
+}
+
+bool PrintOriginTraceToStr(const void *addr, const char *description,
+                           InternalScopedString *out) {
+  CHECK(out);
+  CHECK(__dfsan_get_track_origins());
+  Decorator d;
 
   const dfsan_label label = *__dfsan::shadow_for(addr);
-  if (!label) {
-    Printf("  %sDFSan: no tainted value at %x%s\n", d.Warning(), addr,
-           d.Default());
-    return;
-  }
+  CHECK(label);
 
   const dfsan_origin origin = *__dfsan::origin_for(addr);
 
-  Printf("  %sTaint value 0x%x (at %p) origin tracking (%s)%s\n", d.Origin(),
-         label, addr, description ? description : "", d.Default());
+  out->append("  %sTaint value 0x%x (at %p) origin tracking (%s)%s\n",
+              d.Origin(), label, addr, description ? description : "",
+              d.Default());
+
   Origin o = Origin::FromRawId(origin);
   bool found = false;
+
   while (o.isChainedOrigin()) {
     StackTrace stack;
     dfsan_origin origin_id = o.raw_id();
     o = o.getNextChainedOrigin(&stack);
     if (o.isChainedOrigin())
-      Printf("  %sOrigin value: 0x%x, Taint value was stored to memory at%s\n",
-             d.Origin(), origin_id, d.Default());
+      out->append(
+          "  %sOrigin value: 0x%x, Taint value was stored to memory at%s\n",
+          d.Origin(), origin_id, d.Default());
     else
-      Printf("  %sOrigin value: 0x%x, Taint value was created at%s\n",
-             d.Origin(), origin_id, d.Default());
-    stack.Print();
+      out->append("  %sOrigin value: 0x%x, Taint value was created at%s\n",
+                  d.Origin(), origin_id, d.Default());
+
+    // Includes a trailing newline, so no need to add it again.
+    stack.PrintTo(out);
     found = true;
   }
-  if (!found)
-    Printf(
-        "  %sTaint value 0x%x (at %p) has invalid origin tracking. This can "
-        "be a DFSan bug.%s\n",
-        d.Warning(), label, addr, d.Default());
+
+  return found;
+}
+
+}  // namespace
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_print_origin_trace(
+    const void *addr, const char *description) {
+  if (!__dfsan_get_track_origins()) {
+    PrintNoOriginTrackingWarning();
+    return;
+  }
+
+  const dfsan_label label = *__dfsan::shadow_for(addr);
+  if (!label) {
+    PrintNoTaintWarning(addr);
+    return;
+  }
+
+  InternalScopedString trace;
+  bool success = PrintOriginTraceToStr(addr, description, &trace);
+
+  if (trace.length())
+    Printf("%s", trace.data());
+
+  if (!success)
+    PrintInvalidOriginWarning(label, addr);
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE size_t
+dfsan_sprint_origin_trace(const void *addr, const char *description,
+                          char *out_buf, size_t out_buf_size) {
+  CHECK(out_buf);
+
+  if (!__dfsan_get_track_origins()) {
+    PrintNoOriginTrackingWarning();
+    return 0;
+  }
+
+  const dfsan_label label = *__dfsan::shadow_for(addr);
+  if (!label) {
+    PrintNoTaintWarning(addr);
+    return 0;
+  }
+
+  InternalScopedString trace;
+  bool success = PrintOriginTraceToStr(addr, description, &trace);
+
+  if (!success) {
+    PrintInvalidOriginWarning(label, addr);
+    return 0;
+  }
+
+  if (out_buf_size) {
+    internal_strncpy(out_buf, trace.data(), out_buf_size - 1);
+    out_buf[out_buf_size - 1] = '\0';
+  }
+
+  return trace.length();
 }
 
 extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin

diff  --git a/compiler-rt/lib/dfsan/done_abilist.txt b/compiler-rt/lib/dfsan/done_abilist.txt
index d41ee33203c91..9694af0b95fb4 100644
--- a/compiler-rt/lib/dfsan/done_abilist.txt
+++ b/compiler-rt/lib/dfsan/done_abilist.txt
@@ -30,6 +30,8 @@ fun:dfsan_flush=uninstrumented
 fun:dfsan_flush=discard
 fun:dfsan_print_origin_trace=uninstrumented
 fun:dfsan_print_origin_trace=discard
+fun:dfsan_sprint_origin_trace=uninstrumented
+fun:dfsan_sprint_origin_trace=discard
 fun:dfsan_get_origin=uninstrumented
 fun:dfsan_get_origin=custom
 fun:dfsan_get_init_origin=uninstrumented

diff  --git a/compiler-rt/test/dfsan/origin_stack_trace.c b/compiler-rt/test/dfsan/origin_stack_trace.c
index 40a51e374fd14..c7018a54d7215 100644
--- a/compiler-rt/test/dfsan/origin_stack_trace.c
+++ b/compiler-rt/test/dfsan/origin_stack_trace.c
@@ -1,14 +1,16 @@
 // RUN: %clang_dfsan -gmlt -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=CHECK < %t.out
+// RUN: FileCheck %s < %t.out
 //
 // RUN: %clang_dfsan -gmlt -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true -mllvm -dfsan-instrument-with-call-threshold=0 %s -o %t && \
 // RUN:     %run %t >%t.out 2>&1
-// RUN: FileCheck %s --check-prefix=CHECK < %t.out
+// RUN: FileCheck %s < %t.out
 //
 // REQUIRES: x86_64-target-arch
 
 #include <sanitizer/dfsan_interface.h>
+#include <stdio.h>
+#include <string.h>
 
 #define NOINLINE __attribute__((noinline))
 
@@ -32,13 +34,67 @@ int main(int argc, char *argv[]) {
   baz(8, &a, sizeof(a));
   int c = foo(a, b);
   dfsan_print_origin_trace(&c, NULL);
-}
+  // CHECK: Taint value 0x1 {{.*}} origin tracking ()
+  // CHECK: Origin value: {{.*}}, Taint value was stored to memory at
+  // CHECK: #0 {{.*}} in main {{.*}}origin_stack_trace.c:[[@LINE-4]]
+
+  // CHECK: Origin value: {{.*}}, Taint value was created at
+  // CHECK: #0 {{.*}} in dfs$bar {{.*}}origin_stack_trace.c:[[@LINE-19]]
+  // CHECK-COUNT-8: #{{[0-9]+}} {{.*}} in dfs$bar {{.*}}origin_stack_trace.c:[[@LINE-22]]
+  // CHECK: #9 {{.*}} in dfs$baz {{.*}}origin_stack_trace.c:[[@LINE-16]]
+
+  char buf[3000];
+  size_t length = dfsan_sprint_origin_trace(&c, NULL, buf, sizeof(buf));
+
+  printf("==OUTPUT==\n\n%s==EOS==\n", buf);
+  // CHECK: ==OUTPUT==
+  // CHECK: Taint value 0x1 {{.*}} origin tracking ()
+  // CHECK: Origin value: {{.*}}, Taint value was stored to memory at
+  // CHECK: #0 {{.*}} in main {{.*}}origin_stack_trace.c:[[@LINE-18]]
+
+  // CHECK: Origin value: {{.*}}, Taint value was created at
+  // CHECK: #0 {{.*}} in dfs$bar {{.*}}origin_stack_trace.c:[[@LINE-33]]
+  // CHECK-COUNT-8: #{{[0-9]+}} {{.*}} in dfs$bar {{.*}}origin_stack_trace.c:[[@LINE-36]]
+  // CHECK: #9 {{.*}} in dfs$baz {{.*}}origin_stack_trace.c:[[@LINE-30]]
+  // CHECK: ==EOS==
+
+  char tinybuf[18];
+  size_t same_length = dfsan_sprint_origin_trace(&c, NULL, tinybuf, sizeof(tinybuf));
+
+  printf("==TRUNCATED OUTPUT==\n\n%s==EOS==\n", tinybuf);
+  // CHECK: ==TRUNCATED OUTPUT==
+  // CHECK: Taint value 0x1==EOS==
 
-// CHECK: Taint value 0x1 {{.*}} origin tracking ()
-// CHECK: Origin value: {{.*}}, Taint value was stored to memory at
-// CHECK: #0 {{.*}} in main {{.*}}origin_stack_trace.c:[[@LINE-6]]
+  printf("Returned length: %zu\n", length);
+  printf("Actual length: %zu\n", strlen(buf));
+  printf("Returned length with truncation: %zu\n", same_length);
 
-// CHECK: Origin value: {{.*}}, Taint value was created at
-// CHECK: #0 {{.*}} in dfs$bar {{.*}}origin_stack_trace.c:[[@LINE-21]]
-// CHECK-COUNT-8: #{{[0-9]+}} {{.*}} in dfs$bar {{.*}}origin_stack_trace.c:[[@LINE-24]]
-// CHECK: #9 {{.*}} in dfs$baz {{.*}}origin_stack_trace.c:[[@LINE-18]]
+  // CHECK: Returned length: [[#LEN:]]
+  // CHECK: Actual length: [[#LEN]]
+  // CHECK: Returned length with truncation: [[#LEN]]
+
+  size_t length_with_desc = dfsan_sprint_origin_trace(&c, "DESCRIPTION", buf, sizeof(buf));
+
+  printf("==OUTPUT==\n\n%s==EOS==\n", buf);
+  // CHECK: ==OUTPUT==
+  // CHECK: Taint value 0x1 {{.*}} origin tracking (DESCRIPTION)
+  // CHECK: Origin value: {{.*}}, Taint value was stored to memory at
+  // CHECK: #0 {{.*}} in main {{.*}}origin_stack_trace.c:[[@LINE-47]]
+
+  // CHECK: Origin value: {{.*}}, Taint value was created at
+  // CHECK: #0 {{.*}} in dfs$bar {{.*}}origin_stack_trace.c:[[@LINE-62]]
+  // CHECK-COUNT-8: #{{[0-9]+}} {{.*}} in dfs$bar {{.*}}origin_stack_trace.c:[[@LINE-65]]
+  // CHECK: #9 {{.*}} in dfs$baz {{.*}}origin_stack_trace.c:[[@LINE-59]]
+  // CHECK: ==EOS==
+
+  printf("Returned length: %zu\n", length_with_desc);
+  // COMM: Message length is increased by 11: the length of "DESCRIPTION".
+  // CHECK: Returned length: [[#LEN + 11]]
+
+  buf[0] = '\0';
+  length = dfsan_sprint_origin_trace(&c, NULL, buf, 0);
+  printf("Output=\"%s\"\n", buf);
+  printf("Returned length: %zu\n", length);
+  // CHECK: Output=""
+  // CHECK: Returned length: [[#LEN]]
+}


        


More information about the llvm-commits mailing list