Runtime support for CFI
Control Flow Integrity support in bionic.
General design:
http://clang.llvm.org/docs/ControlFlowIntegrityDesign.html#shared-library-support
This CL implements subsections "CFI Shadow" and "CFI_SlowPath" in the above document.
Bug: 22033465
Test: bionic device tests
Change-Id: I14dfea630de468eb5620e7f55f92b1397ba06217
diff --git a/libc/include/dlfcn.h b/libc/include/dlfcn.h
index 9aa4a1f..b8f3cec 100644
--- a/libc/include/dlfcn.h
+++ b/libc/include/dlfcn.h
@@ -29,6 +29,7 @@
#ifndef __DLFCN_H__
#define __DLFCN_H__
+#include <stdint.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
diff --git a/libc/private/CFIShadow.h b/libc/private/CFIShadow.h
new file mode 100644
index 0000000..26351db
--- /dev/null
+++ b/libc/private/CFIShadow.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CFI_SHADOW_H
+#define CFI_SHADOW_H
+
+#include <stdint.h>
+
+#include "private/bionic_page.h"
+#include "private/bionic_macros.h"
+
+constexpr unsigned kLibraryAlignmentBits = 18;
+constexpr size_t kLibraryAlignment = 1UL << kLibraryAlignmentBits;
+
+// This class defines format of the shadow region for Control Flow Integrity support.
+// See documentation in http://clang.llvm.org/docs/ControlFlowIntegrityDesign.html#shared-library-support.
+//
+// CFI shadow is effectively a very fast and specialized implementation of dladdr: given an address that
+// belongs to a shared library or an executable, it can find the address of a specific export in that
+// library (a function called "__cfi_check"). This is only guaranteed to work for
+// addresses of possible CFI targets inside a library: indirectly called functions and virtual
+// tables. A random address inside a library may not work in the future (but it does in the current
+// implementation).
+//
+// Implementation is a sparse array of uint16_t where each element describes the location of
+// __cfi_check for a 2**kShadowGranularity range of memory. Array elements (called "shadow values"
+// below) are interpreted as follows.
+//
+// For an address P and corresponding shadow value V, the address of __cfi_check is calculated as
+// align_up(P, 2**kShadowGranularity) - (V - 2) * (2 ** kCfiCheckGranularity)
+//
+// Special shadow values:
+// 0 = kInvalidShadow, this memory range has no valid CFI targets.
+// 1 = kUncheckedShadow, any address is this memory range is a valid CFI target
+//
+// Loader requirement: each aligned 2**kShadowGranularity region of address space may contain at
+// most one DSO.
+// Compiler requirement: __cfi_check is aligned at kCfiCheckGranularity.
+// Compiler requirement: __cfi_check for a given DSO is located below any CFI target for that DSO.
+class CFIShadow {
+ public:
+ static constexpr uintptr_t kShadowGranularity = kLibraryAlignmentBits;
+ static constexpr uintptr_t kCfiCheckGranularity = 12;
+
+ // Each uint16_t element of the shadow corresponds to this much application memory.
+ static constexpr uintptr_t kShadowAlign = 1UL << kShadowGranularity;
+
+ // Alignment of __cfi_check.
+ static constexpr uintptr_t kCfiCheckAlign = 1UL << kCfiCheckGranularity; // 4K
+
+#if defined(__aarch64__)
+ static constexpr uintptr_t kMaxTargetAddr = 0x7fffffffff;
+#elif defined (__LP64__)
+ static constexpr uintptr_t kMaxTargetAddr = 0x7fffffffffff;
+#else
+ static constexpr uintptr_t kMaxTargetAddr = 0xffffffff;
+#endif
+
+ // Shadow is 2 -> 2**kShadowGranularity.
+ static constexpr uintptr_t kShadowSize =
+ align_up((kMaxTargetAddr >> (kShadowGranularity - 1)), PAGE_SIZE);
+
+ // Returns offset inside the shadow region for an address.
+ static constexpr uintptr_t MemToShadowOffset(uintptr_t x) {
+ return (x >> kShadowGranularity) << 1;
+ }
+
+ typedef int (*CFICheckFn)(uint64_t, void *, void *);
+
+ public:
+ enum ShadowValues : uint16_t {
+ kInvalidShadow = 0, // Not a valid CFI target.
+ kUncheckedShadow = 1, // Unchecked, valid CFI target.
+ kRegularShadowMin = 2 // This and all higher values encode a negative offset to __cfi_check in
+ // the units of kCfiCheckGranularity, starting with 0 at
+ // kRegularShadowMin.
+ };
+};
+
+#endif // CFI_SHADOW_H
diff --git a/libc/private/bionic_macros.h b/libc/private/bionic_macros.h
index d5c5b9c..303218e 100644
--- a/libc/private/bionic_macros.h
+++ b/libc/private/bionic_macros.h
@@ -48,11 +48,11 @@
? (1UL << (64 - __builtin_clzl(static_cast<unsigned long>(value)))) \
: (1UL << (32 - __builtin_clz(static_cast<unsigned int>(value)))))
-static inline uintptr_t align_down(uintptr_t p, size_t align) {
+static constexpr uintptr_t align_down(uintptr_t p, size_t align) {
return p & ~(align - 1);
}
-static inline uintptr_t align_up(uintptr_t p, size_t align) {
+static constexpr uintptr_t align_up(uintptr_t p, size_t align) {
return (p + align - 1) & ~(align - 1);
}