summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2018-07-20 19:24:11 +0000
committerH.J. Lu <hjl.tools@gmail.com>2018-07-20 19:24:11 +0000
commitc3554027940f5d19133a3a335e5ef667d3a251e2 (patch)
treeb587957f1e2d2b09d71fb194986085c70aa31183
parent517b6132810b6ceb8ea6d45174d8986e1b023461 (diff)
downloadcompiler-rt-c3554027940f5d19133a3a335e5ef667d3a251e2.tar.gz
Mark REAL(swapcontext) with indirect_return attribute on x86
When shadow stack from Intel CET is enabled, the first instruction of all indirect branch targets must be a special instruction, ENDBR. lib/asan/asan_interceptors.cc has ... int res = REAL(swapcontext)(oucp, ucp); ... REAL(swapcontext) is a function pointer to swapcontext in libc. Since swapcontext may return via indirect branch on x86 when shadow stack is enabled, as in this case, int res = REAL(swapcontext)(oucp, ucp); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This function may be returned via an indirect branch. Here compiler must insert ENDBR after call, like call *bar(%rip) endbr64 I opened an LLVM bug: https://bugs.llvm.org/show_bug.cgi?id=38207 to add the indirect_return attribute so that it can be used to inform compiler to insert ENDBR after REAL(swapcontext) call. We mark REAL(swapcontext) with the indirect_return attribute if it is available. This fixed: https://bugs.llvm.org/show_bug.cgi?id=38249 Reviewed By: eugenis Differential Revision: https://reviews.llvm.org/D49608 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@337603 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/asan/asan_interceptors.cc8
-rw-r--r--lib/sanitizer_common/sanitizer_internal_defs.h5
2 files changed, 13 insertions, 0 deletions
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index 3f8bb5bd3..aac2bb8a6 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/lib/asan/asan_interceptors.cc
@@ -275,7 +275,15 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
uptr stack, ssize;
ReadContextStack(ucp, &stack, &ssize);
ClearShadowMemoryForContextStack(stack, ssize);
+#if __has_attribute(__indirect_return__) && \
+ (defined(__x86_64__) || defined(__i386__))
+ int (*real_swapcontext)(struct ucontext_t *, struct ucontext_t *)
+ __attribute__((__indirect_return__))
+ = REAL(swapcontext);
+ int res = real_swapcontext(oucp, ucp);
+#else
int res = REAL(swapcontext)(oucp, ucp);
+#endif
// swapcontext technically does not return, but program may swap context to
// "oucp" later, that would look as if swapcontext() returned 0.
// We need to clear shadow for ucp once again, as it may be in arbitrary
diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h
index e4aa07b25..f8a405ba6 100644
--- a/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -122,6 +122,11 @@
# define __has_feature(x) 0
#endif
+// Older GCCs do not understand __has_attribute.
+#if !defined(__has_attribute)
+# define __has_attribute(x) 0
+#endif
+
// For portability reasons we do not include stddef.h, stdint.h or any other
// system header, but we do need some basic types that are not defined
// in a portable way by the language itself.