From 0a3637d3eb2424d8e825ad1825f843450a888406 Mon Sep 17 00:00:00 2001 From: Evgenii Stepanov Date: Wed, 6 Jul 2016 13:20:59 -0700 Subject: 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 --- libdl/Android.bp | 5 +++- libdl/libdl.arm.map | 3 ++ libdl/libdl.arm64.map | 3 ++ libdl/libdl.map.txt | 3 ++ libdl/libdl.mips.map | 3 ++ libdl/libdl.mips64.map | 3 ++ libdl/libdl.x86.map | 3 ++ libdl/libdl.x86_64.map | 3 ++ libdl/libdl_cfi.cpp | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 libdl/libdl_cfi.cpp (limited to 'libdl') 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 + +#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(p); + uintptr_t ofs = CFIShadow::MemToShadowOffset(addr); + if (ofs > CFIShadow::kShadowSize) return CFIShadow::kInvalidShadow; + return *reinterpret_cast(shadow_base_storage.v + ofs); +} + +static uintptr_t cfi_check_addr(uint16_t v, void* Ptr) { + uintptr_t addr = reinterpret_cast(Ptr); + uintptr_t aligned_addr = align_up(addr, CFIShadow::kShadowAlign); + uintptr_t p = aligned_addr - (static_cast(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(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); +} -- cgit v1.2.3