mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-28 00:06:09 +03:00
88 lines
3.2 KiB
C++
88 lines
3.2 KiB
C++
// 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_flags.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>
|
|
#if !defined(COMPILER_MSVC)
|
|
__attribute__((no_sanitize("cfi-icall")))
|
|
#endif // !defined(COMPILER_MSVC)
|
|
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_
|