aboutsummaryrefslogtreecommitdiffstats
path: root/libdl
diff options
context:
space:
mode:
authorEvgenii Stepanov <eugenis@google.com>2016-07-06 13:20:59 -0700
committerEvgenii Stepanov <eugenis@google.com>2017-01-18 13:13:52 -0800
commit0a3637d3eb2424d8e825ad1825f843450a888406 (patch)
treedc0d4c31cddc2ff06902fcbdf4233f7759258764 /libdl
parent1b2975d54b9c17ced29883aef24490773a4a9fe6 (diff)
downloadandroid_bionic-0a3637d3eb2424d8e825ad1825f843450a888406.tar.gz
android_bionic-0a3637d3eb2424d8e825ad1825f843450a888406.tar.bz2
android_bionic-0a3637d3eb2424d8e825ad1825f843450a888406.zip
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
Diffstat (limited to 'libdl')
-rw-r--r--libdl/Android.bp5
-rw-r--r--libdl/libdl.arm.map3
-rw-r--r--libdl/libdl.arm64.map3
-rw-r--r--libdl/libdl.map.txt3
-rw-r--r--libdl/libdl.mips.map3
-rw-r--r--libdl/libdl.mips64.map3
-rw-r--r--libdl/libdl.x86.map3
-rw-r--r--libdl/libdl.x86_64.map3
-rw-r--r--libdl/libdl_cfi.cpp77
9 files changed, 102 insertions, 1 deletions
diff --git a/libdl/Android.bp b/libdl/Android.bp
index a0aeeffb5..013554a9d 100644
--- a/libdl/Android.bp
+++ b/libdl/Android.bp
@@ -44,7 +44,7 @@ cc_library {
version_script: "libdl.x86_64.map",
},
},
- srcs: ["libdl.c"],
+ srcs: ["libdl.c", "libdl_cfi.cpp"],
cflags: [
"-Wall",
"-Wextra",
@@ -61,6 +61,9 @@ cc_library {
allow_undefined_symbols: true,
system_shared_libs: [],
+ // For private/CFIShadow.h.
+ include_dirs: ["bionic/libc"],
+
// This is placeholder library the actual implementation is (currently)
// provided by the linker.
shared_libs: [ "ld-android" ],
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index 1fdc1a7f1..f452641ee 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -36,6 +36,9 @@ LIBC_N {
LIBC_PLATFORM {
global:
+ __cfi_init;
+ __cfi_slowpath;
+ __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index 28d261362..62f5ff45a 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -35,6 +35,9 @@ LIBC_N {
LIBC_PLATFORM {
global:
+ __cfi_init;
+ __cfi_slowpath;
+ __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index 0a82a2e7c..cc044fe3f 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -35,6 +35,9 @@ LIBC_N {
LIBC_PLATFORM {
global:
+ __cfi_init;
+ __cfi_slowpath;
+ __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index 28d261362..62f5ff45a 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -35,6 +35,9 @@ LIBC_N {
LIBC_PLATFORM {
global:
+ __cfi_init;
+ __cfi_slowpath;
+ __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index 28d261362..62f5ff45a 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -35,6 +35,9 @@ LIBC_N {
LIBC_PLATFORM {
global:
+ __cfi_init;
+ __cfi_slowpath;
+ __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index 28d261362..62f5ff45a 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -35,6 +35,9 @@ LIBC_N {
LIBC_PLATFORM {
global:
+ __cfi_init;
+ __cfi_slowpath;
+ __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index 28d261362..62f5ff45a 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -35,6 +35,9 @@ LIBC_N {
LIBC_PLATFORM {
global:
+ __cfi_init;
+ __cfi_slowpath;
+ __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
diff --git a/libdl/libdl_cfi.cpp b/libdl/libdl_cfi.cpp
new file mode 100644
index 000000000..362b093fa
--- /dev/null
+++ b/libdl/libdl_cfi.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#include <sys/mman.h>
+
+#include "private/CFIShadow.h"
+
+__attribute__((__weak__, visibility("default"))) extern "C" void __loader_cfi_fail(
+ uint64_t CallSiteTypeId, void* Ptr, void* DiagData, void* CallerPc);
+
+// Base address of the CFI shadow. Passed down from the linker in __cfi_init()
+// and does not change after that. The contents of the shadow change in
+// dlopen/dlclose.
+static struct {
+ uintptr_t v;
+ char padding[PAGE_SIZE - sizeof(v)];
+} shadow_base_storage alignas(PAGE_SIZE);
+
+extern "C" uintptr_t* __cfi_init(uintptr_t shadow_base) {
+ shadow_base_storage.v = shadow_base;
+ static_assert(sizeof(shadow_base_storage) == PAGE_SIZE, "");
+ mprotect(&shadow_base_storage, PAGE_SIZE, PROT_READ);
+ return &shadow_base_storage.v;
+}
+
+static uint16_t shadow_load(void* p) {
+ uintptr_t addr = reinterpret_cast<uintptr_t>(p);
+ uintptr_t ofs = CFIShadow::MemToShadowOffset(addr);
+ if (ofs > CFIShadow::kShadowSize) return CFIShadow::kInvalidShadow;
+ return *reinterpret_cast<uint16_t*>(shadow_base_storage.v + ofs);
+}
+
+static uintptr_t cfi_check_addr(uint16_t v, void* Ptr) {
+ uintptr_t addr = reinterpret_cast<uintptr_t>(Ptr);
+ uintptr_t aligned_addr = align_up(addr, CFIShadow::kShadowAlign);
+ uintptr_t p = aligned_addr - (static_cast<uintptr_t>(v - CFIShadow::kRegularShadowMin)
+ << CFIShadow::kCfiCheckGranularity);
+#ifdef __arm__
+ // Assume Thumb encoding. FIXME: force thumb at compile time?
+ p++;
+#endif
+ return p;
+}
+
+static inline void cfi_slowpath_common(uint64_t CallSiteTypeId, void* Ptr, void* DiagData) {
+ uint16_t v = shadow_load(Ptr);
+ switch (v) {
+ case CFIShadow::kInvalidShadow:
+ __loader_cfi_fail(CallSiteTypeId, Ptr, DiagData, __builtin_return_address(0));
+ break;
+ case CFIShadow::kUncheckedShadow:
+ break;
+ default:
+ reinterpret_cast<CFIShadow::CFICheckFn>(cfi_check_addr(v, Ptr))(CallSiteTypeId, Ptr, DiagData);
+ }
+}
+
+extern "C" void __cfi_slowpath(uint64_t CallSiteTypeId, void* Ptr) {
+ cfi_slowpath_common(CallSiteTypeId, Ptr, nullptr);
+}
+
+extern "C" void __cfi_slowpath_diag(uint64_t CallSiteTypeId, void* Ptr, void* DiagData) {
+ cfi_slowpath_common(CallSiteTypeId, Ptr, DiagData);
+}