| // 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/cfi_buildflags.h" | 
 | #include "base/compiler_specific.h" | 
 | #include "base/macros.h" | 
 | #include "base/memory/protected_memory.h" | 
 | #include "build/build_config.h" | 
 |  | 
 | #if BUILDFLAG(CFI_ICALL_CHECK) && !PROTECTED_MEMORY_ENABLED | 
 | #error "CFI-icall enabled for platform without protected memory support" | 
 | #endif  // BUILDFLAG(CFI_ICALL_CHECK) && !PROTECTED_MEMORY_ENABLED | 
 |  | 
 | 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_ |