Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/plugins/ipc/FunctionHook.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef dom_plugins_ipc_functionhook_h
8
#define dom_plugins_ipc_functionhook_h 1
9
10
#include "IpdlTuple.h"
11
#include "base/process.h"
12
#include "mozilla/Atomics.h"
13
14
#if defined(XP_WIN)
15
#include "nsWindowsDllInterceptor.h"
16
#endif
17
18
namespace mozilla {
19
namespace plugins {
20
21
// "PluginHooks" logging helpers
22
extern mozilla::LazyLogModule sPluginHooksLog;
23
#define HOOK_LOG(lvl, msg) MOZ_LOG(mozilla::plugins::sPluginHooksLog, lvl, msg);
24
0
inline const char *SuccessMsg(bool aVal) { return aVal ? "succeeded" : "failed";  }
25
26
class FunctionHook;
27
class FunctionHookArray;
28
29
class FunctionHook
30
{
31
public:
32
0
  virtual ~FunctionHook() {}
33
34
  virtual FunctionHookId FunctionId() const = 0;
35
36
  /**
37
   * Register to hook the function represented by this class.
38
   * Returns false if we should have hooked but didn't.
39
   */
40
  virtual bool Register(int aQuirks) = 0;
41
42
  /**
43
   * Run the original function with parameters stored in a tuple.
44
   * This is only supported on server-side and for auto-brokered methods.
45
   */
46
  virtual bool RunOriginalFunction(base::ProcessId aClientId,
47
                                   const IPC::IpdlTuple &aInTuple,
48
                                   IPC::IpdlTuple *aOutTuple) const = 0;
49
50
  /**
51
   * Hook the Win32 methods needed by the plugin process.
52
   */
53
  static void HookFunctions(int aQuirks);
54
55
  static FunctionHookArray* GetHooks();
56
57
#if defined(XP_WIN)
58
  /**
59
   * Special handler for hooking some kernel32.dll methods that we use to
60
   * disable Flash protected mode.
61
   */
62
  static void HookProtectedMode();
63
64
  /**
65
   * Get the WindowsDllInterceptor for the given module.  Creates a cache of
66
   * WindowsDllInterceptors by name.
67
   */
68
  static WindowsDllInterceptor* GetDllInterceptorFor(const char* aModuleName);
69
70
  /**
71
   * Must be called to clear the cache created by calls to GetDllInterceptorFor.
72
   */
73
  static void ClearDllInterceptorCache();
74
#endif // defined(XP_WIN)
75
76
private:
77
  static StaticAutoPtr<FunctionHookArray> sFunctionHooks;
78
  static void AddFunctionHooks(FunctionHookArray& aHooks);
79
};
80
81
// The FunctionHookArray deletes its FunctionHook objects when freed.
82
class FunctionHookArray : public nsTArray<FunctionHook*> {
83
public:
84
  ~FunctionHookArray()
85
0
  {
86
0
    for (uint32_t idx = 0; idx < Length(); ++idx) {
87
0
      FunctionHook* elt = ElementAt(idx);
88
0
      MOZ_ASSERT(elt);
89
0
      delete elt;
90
0
    }
91
0
  }
92
};
93
94
// Type of function that returns true if a function should be hooked according to quirks.
95
typedef bool(ShouldHookFunc)(int aQuirks);
96
97
template<FunctionHookId functionId, typename FunctionType>
98
class BasicFunctionHook : public FunctionHook
99
{
100
#if defined(XP_WIN)
101
  using FuncHookType = WindowsDllInterceptor::FuncHookType<FunctionType*>;
102
#endif // defined(XP_WIN)
103
104
public:
105
  BasicFunctionHook(const char* aModuleName,
106
                    const char* aFunctionName, FunctionType* aOldFunction,
107
                    FunctionType* aNewFunction)
108
    : mOldFunction(aOldFunction)
109
    , mRegistration(UNREGISTERED)
110
    , mModuleName(aModuleName)
111
    , mFunctionName(aFunctionName)
112
    , mNewFunction(aNewFunction)
113
  {
114
    MOZ_ASSERT(mOldFunction);
115
    MOZ_ASSERT(mNewFunction);
116
  }
117
118
  /**
119
   * Hooks the function if we haven't already and if ShouldHook() says to.
120
   */
121
  bool Register(int aQuirks) override;
122
123
  /**
124
   * Can be specialized to perform "extra" operations when running the
125
   * function on the server side.
126
   */
127
  bool RunOriginalFunction(base::ProcessId aClientId,
128
                           const IPC::IpdlTuple &aInTuple,
129
                           IPC::IpdlTuple *aOutTuple) const override { return false; }
130
131
  FunctionHookId FunctionId() const override { return functionId; }
132
133
  FunctionType* OriginalFunction() const { return mOldFunction; }
134
135
protected:
136
  // Once the function is hooked, this field will take the value of a pointer to
137
  // a function that performs the old behavior.  Before that, it is a pointer to
138
  // the original function.
139
  Atomic<FunctionType*> mOldFunction;
140
#if defined(XP_WIN)
141
  FuncHookType mStub;
142
#endif // defined(XP_WIN)
143
144
  enum RegistrationStatus { UNREGISTERED, FAILED, SUCCEEDED };
145
  RegistrationStatus mRegistration;
146
147
  // The name of the module containing the function to hook.  E.g. "user32.dll".
148
  const nsCString mModuleName;
149
  // The name of the function in the module.
150
  const nsCString mFunctionName;
151
  // The function that we should replace functionName with.  The signature of
152
  // newFunction must match that of functionName.
153
  FunctionType* const mNewFunction;
154
  static ShouldHookFunc* const mShouldHook;
155
};
156
157
// Default behavior is to hook every registered function.
158
extern bool AlwaysHook(int);
159
template<FunctionHookId functionId, typename FunctionType>
160
ShouldHookFunc* const BasicFunctionHook<functionId, FunctionType>::mShouldHook = AlwaysHook;
161
162
template <FunctionHookId functionId, typename FunctionType>
163
bool
164
BasicFunctionHook<functionId, FunctionType>::Register(int aQuirks)
165
{
166
  MOZ_RELEASE_ASSERT(XRE_IsPluginProcess());
167
168
  // If we have already attempted to hook this function or if quirks tell us
169
  // not to then don't hook.
170
  if (mRegistration != UNREGISTERED || !mShouldHook(aQuirks)) {
171
    return true;
172
  }
173
174
  bool isHooked = false;
175
  mRegistration = FAILED;
176
177
#if defined(XP_WIN)
178
  WindowsDllInterceptor* dllInterceptor =
179
    FunctionHook::GetDllInterceptorFor(mModuleName.Data());
180
  if (!dllInterceptor) {
181
    return false;
182
  }
183
184
  isHooked = mStub.Set(*dllInterceptor, mFunctionName.Data(), mNewFunction);
185
#endif
186
187
  if (isHooked) {
188
#if defined(XP_WIN)
189
    mOldFunction = mStub.GetStub();
190
#endif
191
    mRegistration = SUCCEEDED;
192
  }
193
194
  HOOK_LOG(LogLevel::Debug,
195
           ("Registering to intercept function '%s' : '%s'", mFunctionName.Data(),
196
            SuccessMsg(isHooked)));
197
198
  return isHooked;
199
}
200
201
}
202
}
203
204
#endif // dom_plugins_ipc_functionhook_h