vlad.tsyrklevich created this revision.
vlad.tsyrklevich added a reviewer: pcc.
Herald added a subscriber: cfe-commits.

Add support for the -fsanitize=shadow-call-stack flag which causes clang
to add ShadowCallStack attribute to functions compiled with that flag
enabled.


Repository:
  rC Clang

https://reviews.llvm.org/D44801

Files:
  docs/ShadowCallStack.rst
  docs/index.rst
  include/clang/Basic/Sanitizers.def
  lib/CodeGen/CGDeclCXX.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/Driver/SanitizerArgs.cpp
  lib/Driver/ToolChain.cpp
  lib/Lex/PPMacroExpansion.cpp
  test/CodeGen/shadowcallstack-attr.c

Index: test/CodeGen/shadowcallstack-attr.c
===================================================================
--- /dev/null
+++ test/CodeGen/shadowcallstack-attr.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple x86_64-linux-unknown -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck %s
+
+__attribute__((no_sanitize("shadow-call-stack")))
+int foo(int *a) { return *a; }
+
+ int bar(int *a) { return *a; }
+
+// CHECK: define i32 @foo(i32* %a) #[[FOO_ATTR:[0-9]+]] {
+// CHECK: define i32 @bar(i32* %a) #[[BAR_ATTR:[0-9]+]] {
+
+// CHECK-NOT: attributes #[[FOO_ATTR]] = { {{.*}}shadowcallstack{{.*}} }
+// CHECK: attributes #[[BAR_ATTR]] = { {{.*}}shadowcallstack{{.*}} }
Index: lib/Lex/PPMacroExpansion.cpp
===================================================================
--- lib/Lex/PPMacroExpansion.cpp
+++ lib/Lex/PPMacroExpansion.cpp
@@ -1275,6 +1275,8 @@
       .Case("is_union", LangOpts.CPlusPlus)
       .Case("modules", LangOpts.Modules)
       .Case("safe_stack", LangOpts.Sanitize.has(SanitizerKind::SafeStack))
+      .Case("shadow_call_stack",
+            LangOpts.Sanitize.has(SanitizerKind::ShadowCallStack))
       .Case("tls", PP.getTargetInfo().isTLSSupported())
       .Case("underlying_type", LangOpts.CPlusPlus)
       .Default(false);
Index: lib/Driver/ToolChain.cpp
===================================================================
--- lib/Driver/ToolChain.cpp
+++ lib/Driver/ToolChain.cpp
@@ -814,6 +814,8 @@
       getTriple().getArch() == llvm::Triple::wasm32 ||
       getTriple().getArch() == llvm::Triple::wasm64)
     Res |= CFIICall;
+  if (getTriple().getArch() == llvm::Triple::x86_64)
+    Res |= ShadowCallStack;
   return Res;
 }
 
Index: lib/Driver/SanitizerArgs.cpp
===================================================================
--- lib/Driver/SanitizerArgs.cpp
+++ lib/Driver/SanitizerArgs.cpp
@@ -343,7 +343,10 @@
       std::make_pair(Scudo, Address | HWAddress | Leak | Thread | Memory |
                                 KernelAddress | Efficiency),
       std::make_pair(SafeStack, Address | HWAddress | Leak | Thread | Memory |
-                                    KernelAddress | Efficiency)};
+                                    KernelAddress | Efficiency),
+      std::make_pair(ShadowCallStack, Address | HWAddress | Leak | Thread |
+                                          Memory | KernelAddress | Efficiency |
+                                          SafeStack)};
 
   // Enable toolchain specific default sanitizers if not explicitly disabled.
   SanitizerMask Default = TC.getDefaultSanitizers() & ~AllRemove;
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -861,6 +861,8 @@
     Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
   if (SanOpts.has(SanitizerKind::SafeStack))
     Fn->addFnAttr(llvm::Attribute::SafeStack);
+  if (SanOpts.has(SanitizerKind::ShadowCallStack))
+    Fn->addFnAttr(llvm::Attribute::ShadowCallStack);
 
   // Ignore TSan memory acesses from within ObjC/ObjC++ dealloc, initialize,
   // .cxx_destruct, __destroy_helper_block_ and all of their calees at run time.
Index: lib/CodeGen/CGDeclCXX.cpp
===================================================================
--- lib/CodeGen/CGDeclCXX.cpp
+++ lib/CodeGen/CGDeclCXX.cpp
@@ -343,6 +343,10 @@
       !isInSanitizerBlacklist(SanitizerKind::SafeStack, Fn, Loc))
     Fn->addFnAttr(llvm::Attribute::SafeStack);
 
+  if (getLangOpts().Sanitize.has(SanitizerKind::ShadowCallStack) &&
+      !isInSanitizerBlacklist(SanitizerKind::ShadowCallStack, Fn, Loc))
+    Fn->addFnAttr(llvm::Attribute::ShadowCallStack);
+
   return Fn;
 }
 
Index: include/clang/Basic/Sanitizers.def
===================================================================
--- include/clang/Basic/Sanitizers.def
+++ include/clang/Basic/Sanitizers.def
@@ -110,6 +110,9 @@
 // Safe Stack
 SANITIZER("safe-stack", SafeStack)
 
+// Shadow Call Stack
+SANITIZER("shadow-call-stack", ShadowCallStack)
+
 // -fsanitize=undefined includes all the sanitizers which have low overhead, no
 // ABI or address space layout implications, and only catch undefined behavior.
 SANITIZER_GROUP("undefined", Undefined,
Index: docs/index.rst
===================================================================
--- docs/index.rst
+++ docs/index.rst
@@ -36,6 +36,7 @@
    ControlFlowIntegrity
    LTOVisibility
    SafeStack
+   ShadowCallStack
    SourceBasedCodeCoverage
    Modules
    MSVCCompatibility
Index: docs/ShadowCallStack.rst
===================================================================
--- /dev/null
+++ docs/ShadowCallStack.rst
@@ -0,0 +1,74 @@
+===============
+ShadowCallStack
+===============
+
+.. contents::
+   :local:
+
+Introduction
+============
+
+ShadowCallStack is an experimental instrumentation pass, currently only
+implemented for x86_64, that protects programs against attacks based on stack
+buffer overflows. It works by saving a function's return address to a
+separately allocated 'shadow call stack' in the function prolog and checking the
+return address on the stack against the shadow call stack in the function
+epilog. To optimize for memory consumption and cache locality, the shadow call
+stack stores an index followed by an array of return addresses. This is in
+contrast to other schemes, like :doc:`SafeStack`, that mirror the entire stack
+and trade-off consuming more memory for shorter function prologs and epilogs
+with fewer memory accesses.
+
+Compatibility
+-------------
+
+ShadowCallStack currently only supports x86_64. A runtime is not currently
+provided in compiler-rt so one must be provided by the compiled application.
+
+Security
+--------
+
+ShadowCallStack is intended to be a stronger alternative to `-fstack-protector`.
+It protects from non-linear overflows and arbitrary memory writes to the return
+address slot; however, similarly to `-fstack-protector` this protection suffers
+from race conditions because of the call-return semantics on x86_64. There is a
+short race between the call instruction and the first instruction in the
+function that reads the return address where an attacker could overwrite the
+return address and bypass ShadowCallStack. Similarly, there is a time-of-check-
+to-time-of-use race in the function prolog where an attacker could overwrite the
+return address after it has been checked and before it has been returned to.
+Modifying the call-return semantics to fix this on x86_64 would incur an
+unacceptable performance overhead.
+
+The instrumentation makes use of the `gs` segment register to reference the
+shadow call stack. This means that references to the shadow call stack do not
+have to be written to memory and attackers that can read arbitrary memory can
+not easily leak its address.
+
+Usage
+=====
+
+To enable ShadowCallStack, just pass ``-fsanitize=shadow-call-stack`` flag to
+both compile and link command lines.
+
+``__has_feature(shadow_call_stack)``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In some cases one may need to execute different code depending on whether
+ShadowCallStack is enabled. The macro ``__has_feature(shadow_call_stack)`` can
+be used for this purpose.
+
+.. code-block:: c
+
+    #if defined(__has_feature)
+    #  if __has_feature(shadow_call_stack)
+    // code that builds only under ShadowCallStack
+    #  endif
+    #endif
+
+``__attribute__((no_sanitize("shadow-call-stack")))``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Use ``__attribute__((no_sanitize("shadow-call-stack")))`` on a function
+declaration to specify that the shadow call stack instrumentation should not be
+applied to that function, even if enabled globally.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to