|  | // Copyright 2017 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | // Helper routines to call function pointers stored in protected memory with | 
|  | // Control Flow Integrity indirect call checking disabled. Some indirect calls, | 
|  | // e.g. dynamically resolved symbols in another DSO, can not be accounted for by | 
|  | // CFI-icall. These routines allow those symbols to be called without CFI-icall | 
|  | // checking safely by ensuring that they are placed in protected memory. | 
|  |  | 
|  | #ifndef BASE_MEMORY_PROTECTED_MEMORY_CFI_H_ | 
|  | #define BASE_MEMORY_PROTECTED_MEMORY_CFI_H_ | 
|  |  | 
|  | #include <utility> | 
|  |  | 
|  | #include "base/compiler_specific.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/memory/protected_memory.h" | 
|  | #include "build/build_config.h" | 
|  |  | 
|  | namespace base { | 
|  | namespace internal { | 
|  |  | 
|  | // This class is used to exempt calls to function pointers stored in | 
|  | // ProtectedMemory from cfi-icall checking. It's not secure to use directly, it | 
|  | // should only be used by the UnsanitizedCfiCall() functions below. Given an | 
|  | // UnsanitizedCfiCall object, you can use operator() to call the encapsulated | 
|  | // function pointer without cfi-icall checking. | 
|  | template <typename FunctionType> | 
|  | class UnsanitizedCfiCall { | 
|  | public: | 
|  | explicit UnsanitizedCfiCall(FunctionType function) : function_(function) {} | 
|  | UnsanitizedCfiCall(UnsanitizedCfiCall&&) = default; | 
|  |  | 
|  | template <typename... Args> | 
|  | NO_SANITIZE("cfi-icall") | 
|  | auto operator()(Args&&... args) { | 
|  | return function_(std::forward<Args>(args)...); | 
|  | } | 
|  |  | 
|  | private: | 
|  | FunctionType function_; | 
|  |  | 
|  | DISALLOW_IMPLICIT_CONSTRUCTORS(UnsanitizedCfiCall); | 
|  | }; | 
|  |  | 
|  | }  // namespace internal | 
|  |  | 
|  | // These functions can be used to call function pointers in ProtectedMemory | 
|  | // without cfi-icall checking. They are intended to be used to create an | 
|  | // UnsanitizedCfiCall object and immediately call it. UnsanitizedCfiCall objects | 
|  | // should not initialized directly or stored because they hold a function | 
|  | // pointer that will be called without CFI-icall checking in mutable memory. The | 
|  | // functions can be used as shown below: | 
|  |  | 
|  | // ProtectedMemory<void (*)(int)> p; | 
|  | // UnsanitizedCfiCall(p)(5); /* In place of (*p)(5); */ | 
|  |  | 
|  | template <typename T> | 
|  | auto UnsanitizedCfiCall(const ProtectedMemory<T>& PM) { | 
|  | #if PROTECTED_MEMORY_ENABLED | 
|  | DCHECK(&PM >= ProtectedMemoryStart && &PM < ProtectedMemoryEnd); | 
|  | #endif  // PROTECTED_MEMORY_ENABLED | 
|  | return internal::UnsanitizedCfiCall<T>(*PM); | 
|  | } | 
|  |  | 
|  | // struct S { void (*fp)(int); } s; | 
|  | // ProtectedMemory<S> p; | 
|  | // UnsanitizedCfiCall(p, &S::fp)(5); /* In place of p->fp(5); */ | 
|  |  | 
|  | template <typename T, typename Member> | 
|  | auto UnsanitizedCfiCall(const ProtectedMemory<T>& PM, Member member) { | 
|  | #if PROTECTED_MEMORY_ENABLED | 
|  | DCHECK(&PM >= ProtectedMemoryStart && &PM < ProtectedMemoryEnd); | 
|  | #endif  // PROTECTED_MEMORY_ENABLED | 
|  | return internal::UnsanitizedCfiCall<decltype(*PM.*member)>(*PM.*member); | 
|  | } | 
|  |  | 
|  | }  // namespace base | 
|  |  | 
|  | #endif  // BASE_MEMORY_PROTECTED_MEMORY_CFI_H_ |