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
13 #if defined(XP_WIN)
14 #include "nsWindowsDllInterceptor.h"
15 #endif
16
17 namespace mozilla {
18 namespace plugins {
19
20 // "PluginHooks" logging helpers
21 extern mozilla::LazyLogModule sPluginHooksLog;
22 #define HOOK_LOG(lvl, msg) MOZ_LOG(mozilla::plugins::sPluginHooksLog, lvl, msg);
SuccessMsg(bool aVal)23 inline const char* SuccessMsg(bool aVal) {
24 return aVal ? "succeeded" : "failed";
25 }
26
27 class FunctionHook;
28 class FunctionHookArray;
29
30 class FunctionHook {
31 public:
~FunctionHook()32 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:
~FunctionHookArray()84 ~FunctionHookArray() {
85 for (uint32_t idx = 0; idx < Length(); ++idx) {
86 FunctionHook* elt = ElementAt(idx);
87 MOZ_ASSERT(elt);
88 delete elt;
89 }
90 }
91 };
92
93 // Type of function that returns true if a function should be hooked according
94 // to quirks.
95 typedef bool(ShouldHookFunc)(int aQuirks);
96
97 template <FunctionHookId functionId, typename FunctionType>
98 class BasicFunctionHook : public FunctionHook {
99 public:
BasicFunctionHook(const char * aModuleName,const char * aFunctionName,FunctionType * aOldFunction,FunctionType * aNewFunction)100 BasicFunctionHook(const char* aModuleName, const char* aFunctionName,
101 FunctionType* aOldFunction, FunctionType* aNewFunction)
102 : mOldFunction(aOldFunction),
103 mIsHooked(false),
104 mModuleName(aModuleName),
105 mFunctionName(aFunctionName),
106 mNewFunction(aNewFunction) {
107 MOZ_ASSERT(mOldFunction);
108 MOZ_ASSERT(mNewFunction);
109 }
110
111 /**
112 * Hooks the function if we haven't already and if ShouldHook() says to.
113 */
114 bool Register(int aQuirks) override;
115
116 /**
117 * Can be specialized to perform "extra" operations when running the
118 * function on the server side.
119 */
RunOriginalFunction(base::ProcessId aClientId,const IPC::IpdlTuple & aInTuple,IPC::IpdlTuple * aOutTuple)120 bool RunOriginalFunction(base::ProcessId aClientId,
121 const IPC::IpdlTuple& aInTuple,
122 IPC::IpdlTuple* aOutTuple) const override {
123 return false;
124 }
125
FunctionId()126 FunctionHookId FunctionId() const override { return functionId; }
127
OriginalFunction()128 FunctionType* OriginalFunction() const { return mOldFunction; }
129
130 protected:
131 // Once the function is hooked, this field will take the value of a pointer to
132 // a function that performs the old behavior. Before that, it is a pointer to
133 // the original function.
134 FunctionType* mOldFunction;
135 // True if we have already hooked the function.
136 bool mIsHooked;
137
138 // The name of the module containing the function to hook. E.g. "user32.dll".
139 const nsCString mModuleName;
140 // The name of the function in the module.
141 const nsCString mFunctionName;
142 // The function that we should replace functionName with. The signature of
143 // newFunction must match that of functionName.
144 FunctionType* const mNewFunction;
145 static ShouldHookFunc* const mShouldHook;
146 };
147
148 // Default behavior is to hook every registered function.
149 extern bool AlwaysHook(int);
150 template <FunctionHookId functionId, typename FunctionType>
151 ShouldHookFunc* const BasicFunctionHook<functionId, FunctionType>::mShouldHook =
152 AlwaysHook;
153
154 template <FunctionHookId functionId, typename FunctionType>
Register(int aQuirks)155 bool BasicFunctionHook<functionId, FunctionType>::Register(int aQuirks) {
156 MOZ_RELEASE_ASSERT(XRE_IsPluginProcess());
157
158 // If we have already hooked or if quirks tell us not to then don't hook.
159 if (mIsHooked || !mShouldHook(aQuirks)) {
160 return true;
161 }
162
163 #if defined(XP_WIN)
164 WindowsDllInterceptor* dllInterceptor =
165 FunctionHook::GetDllInterceptorFor(mModuleName.Data());
166 if (!dllInterceptor) {
167 return false;
168 }
169
170 mIsHooked = dllInterceptor->AddHook(mFunctionName.Data(),
171 reinterpret_cast<intptr_t>(mNewFunction),
172 reinterpret_cast<void**>(&mOldFunction));
173 #endif
174
175 HOOK_LOG(LogLevel::Debug, ("Registering to intercept function '%s' : '%s'",
176 mFunctionName.Data(), SuccessMsg(mIsHooked)));
177
178 return mIsHooked;
179 }
180
181 } // namespace plugins
182 } // namespace mozilla
183
184 #endif // dom_plugins_ipc_functionhook_h
185