Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/plugins/ipc/FunctionHook.cpp
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
#include "FunctionHook.h"
8
#include "FunctionBroker.h"
9
#include "nsClassHashtable.h"
10
#include "mozilla/ClearOnShutdown.h"
11
12
#if defined(XP_WIN)
13
#include <shlobj.h>
14
#endif
15
16
namespace mozilla {
17
namespace plugins {
18
19
StaticAutoPtr<FunctionHookArray> FunctionHook::sFunctionHooks;
20
21
0
bool AlwaysHook(int) { return true; }
22
23
FunctionHookArray*
24
FunctionHook::GetHooks()
25
0
{
26
0
  if (sFunctionHooks) {
27
0
    return sFunctionHooks;
28
0
  }
29
0
30
0
  // sFunctionHooks is the StaticAutoPtr to the singleton array of FunctionHook
31
0
  // objects.  We free it by clearing the StaticAutoPtr on shutdown.
32
0
  sFunctionHooks = new FunctionHookArray();
33
0
  ClearOnShutdown(&sFunctionHooks);
34
0
  sFunctionHooks->SetLength(ID_FunctionHookCount);
35
0
36
0
  AddFunctionHooks(*sFunctionHooks);
37
0
  AddBrokeredFunctionHooks(*sFunctionHooks);
38
0
  return sFunctionHooks;
39
0
}
40
41
void
42
FunctionHook::HookFunctions(int aQuirks)
43
0
{
44
0
  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Plugin);
45
0
  FunctionHookArray* hooks = FunctionHook::GetHooks();
46
0
  MOZ_ASSERT(hooks);
47
0
  for(size_t i=0; i < hooks->Length(); ++i) {
48
0
    FunctionHook* mhb = hooks->ElementAt(i);
49
0
    // Check that the FunctionHook array is in the same order as the
50
0
    // FunctionHookId enum.
51
0
    MOZ_ASSERT((size_t)mhb->FunctionId() == i);
52
0
    mhb->Register(aQuirks);
53
0
  }
54
0
}
55
56
#if defined(XP_WIN)
57
58
// This cache is created when a DLL is registered with a FunctionHook.
59
// It is cleared on a call to ClearDllInterceptorCache().  It
60
// must be freed before exit to avoid leaks.
61
typedef nsClassHashtable<nsStringHashKey, WindowsDllInterceptor> DllInterceptors;
62
DllInterceptors* sDllInterceptorCache = nullptr;
63
64
WindowsDllInterceptor*
65
FunctionHook::GetDllInterceptorFor(const char* aModuleName)
66
{
67
  if (!sDllInterceptorCache) {
68
    sDllInterceptorCache = new DllInterceptors();
69
  }
70
71
  MOZ_ASSERT(NS_IsAscii(aModuleName), "Non-ASCII module names are not supported");
72
  NS_ConvertASCIItoUTF16 moduleName(aModuleName);
73
74
  WindowsDllInterceptor* ret =
75
    sDllInterceptorCache->LookupOrAdd(moduleName);
76
  MOZ_ASSERT(ret);
77
  ret->Init(moduleName.get());
78
  return ret;
79
}
80
81
void
82
FunctionHook::ClearDllInterceptorCache()
83
{
84
  delete sDllInterceptorCache;
85
  sDllInterceptorCache = nullptr;
86
}
87
88
/* GetWindowInfo */
89
90
typedef BasicFunctionHook<ID_GetWindowInfo, decltype(GetWindowInfo)> GetWindowInfoFH;
91
92
template<>
93
ShouldHookFunc* const
94
GetWindowInfoFH::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_GETWINDOWINFO>;
95
96
static const wchar_t * kMozillaWindowClass = L"MozillaWindowClass";
97
static HWND sBrowserHwnd = nullptr;
98
99
100
BOOL WINAPI
101
GetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi)
102
{
103
  if (!pwi) {
104
    return FALSE;
105
  }
106
107
  MOZ_ASSERT(ID_GetWindowInfo < FunctionHook::GetHooks()->Length());
108
  GetWindowInfoFH* functionHook =
109
    static_cast<GetWindowInfoFH*>(FunctionHook::GetHooks()->ElementAt(ID_GetWindowInfo));
110
  if (!functionHook->OriginalFunction()) {
111
    NS_ASSERTION(FALSE, "Something is horribly wrong in PHGetWindowInfoHook!");
112
    return FALSE;
113
  }
114
115
  if (!sBrowserHwnd) {
116
    wchar_t szClass[20];
117
    // GetClassNameW returns the length it copied w/o null terminator.
118
    // Therefore, if the name and null-terminator fit then it returns a
119
    // value less than the buffer's length.
120
    int nameLen = GetClassNameW(hWnd, szClass, ArrayLength(szClass));
121
    if ((nameLen < (int)ArrayLength(szClass)) &&
122
        !wcscmp(szClass, kMozillaWindowClass)) {
123
      sBrowserHwnd = hWnd;
124
    }
125
  }
126
127
  // Oddity: flash does strange rect comparisons for mouse input destined for
128
  // it's internal settings window. Post removing sub widgets for tabs, touch
129
  // this up so they get the rect they expect.
130
  // XXX potentially tie this to a specific major version?
131
  typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi);
132
  GetWindowInfoPtr gwiFunc =
133
    static_cast<GetWindowInfoPtr>(functionHook->OriginalFunction());
134
  BOOL result = gwiFunc(hWnd, pwi);
135
  if (sBrowserHwnd && sBrowserHwnd == hWnd) {
136
    pwi->rcWindow = pwi->rcClient;
137
  }
138
  return result;
139
}
140
141
/* PrintDlgW */
142
143
typedef BasicFunctionHook<ID_PrintDlgW, decltype(PrintDlgW)> PrintDlgWFH;
144
145
template<>
146
ShouldHookFunc* const
147
PrintDlgWFH::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_PRINTDLGW>;
148
149
BOOL WINAPI PrintDlgWHook(LPPRINTDLGW aDlg)
150
{
151
  // Zero out the HWND supplied by the plugin.  We are sacrificing window
152
  // parentage for the ability to run in the NPAPI sandbox.
153
  HWND hwnd = aDlg->hwndOwner;
154
  aDlg->hwndOwner = 0;
155
  MOZ_ASSERT(ID_PrintDlgW < FunctionHook::GetHooks()->Length());
156
  PrintDlgWFH* functionHook =
157
    static_cast<PrintDlgWFH*>(FunctionHook::GetHooks()->ElementAt(ID_PrintDlgW));
158
  MOZ_ASSERT(functionHook);
159
  BOOL ret = functionHook->OriginalFunction()(aDlg);
160
  aDlg->hwndOwner = hwnd;
161
  return ret;
162
}
163
164
// Hooking CreateFileW for protected-mode magic
165
static WindowsDllInterceptor sKernel32Intercept;
166
typedef HANDLE (WINAPI *CreateFileWPtr)(LPCWSTR aFname, DWORD aAccess,
167
                                        DWORD aShare,
168
                                        LPSECURITY_ATTRIBUTES aSecurity,
169
                                        DWORD aCreation, DWORD aFlags,
170
                                        HANDLE aFTemplate);
171
static WindowsDllInterceptor::FuncHookType<CreateFileWPtr> sCreateFileWStub;
172
typedef HANDLE (WINAPI *CreateFileAPtr)(LPCSTR aFname, DWORD aAccess,
173
                                        DWORD aShare,
174
                                        LPSECURITY_ATTRIBUTES aSecurity,
175
                                        DWORD aCreation, DWORD aFlags,
176
                                        HANDLE aFTemplate);
177
static WindowsDllInterceptor::FuncHookType<CreateFileAPtr> sCreateFileAStub;
178
179
// Windows 8 RTM (kernelbase's version is 6.2.9200.16384) doesn't call
180
// CreateFileW from CreateFileA.
181
// So we hook CreateFileA too to use CreateFileW hook.
182
static HANDLE WINAPI
183
CreateFileAHookFn(LPCSTR aFname, DWORD aAccess, DWORD aShare,
184
                  LPSECURITY_ATTRIBUTES aSecurity, DWORD aCreation, DWORD aFlags,
185
                  HANDLE aFTemplate)
186
{
187
  while (true) { // goto out
188
    // Our hook is for mms.cfg into \Windows\System32\Macromed\Flash
189
    // We don't require supporting too long path.
190
    WCHAR unicodeName[MAX_PATH];
191
    size_t len = strlen(aFname);
192
193
    if (len >= MAX_PATH) {
194
      break;
195
    }
196
197
    // We call to CreateFileW for workaround of Windows 8 RTM
198
    int newLen = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, aFname,
199
                                     len, unicodeName, MAX_PATH);
200
    if (newLen == 0 || newLen >= MAX_PATH) {
201
      break;
202
    }
203
    unicodeName[newLen] = '\0';
204
205
    return CreateFileW(unicodeName, aAccess, aShare, aSecurity, aCreation, aFlags, aFTemplate);
206
  }
207
208
  return sCreateFileAStub(aFname, aAccess, aShare, aSecurity, aCreation, aFlags,
209
                          aFTemplate);
210
}
211
212
static bool
213
GetLocalLowTempPath(size_t aLen, LPWSTR aPath)
214
{
215
  NS_NAMED_LITERAL_STRING(tempname, "\\Temp");
216
  LPWSTR path;
217
  if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppDataLow, 0,
218
                                     nullptr, &path))) {
219
    if (wcslen(path) + tempname.Length() < aLen) {
220
        wcscpy(aPath, path);
221
        wcscat(aPath, tempname.get());
222
        CoTaskMemFree(path);
223
        return true;
224
    }
225
    CoTaskMemFree(path);
226
  }
227
228
  // XP doesn't support SHGetKnownFolderPath and LocalLow
229
  if (!GetTempPathW(aLen, aPath)) {
230
    return false;
231
  }
232
  return true;
233
}
234
235
HANDLE WINAPI
236
CreateFileWHookFn(LPCWSTR aFname, DWORD aAccess, DWORD aShare,
237
                  LPSECURITY_ATTRIBUTES aSecurity, DWORD aCreation, DWORD aFlags,
238
                  HANDLE aFTemplate)
239
{
240
  static const WCHAR kConfigFile[] = L"mms.cfg";
241
  static const size_t kConfigLength = ArrayLength(kConfigFile) - 1;
242
243
  while (true) { // goto out, in sheep's clothing
244
    size_t len = wcslen(aFname);
245
    if (len < kConfigLength) {
246
      break;
247
    }
248
    if (wcscmp(aFname + len - kConfigLength, kConfigFile) != 0) {
249
      break;
250
    }
251
252
    // This is the config file we want to rewrite
253
    WCHAR tempPath[MAX_PATH+1];
254
    if (GetLocalLowTempPath(MAX_PATH, tempPath) == 0) {
255
      break;
256
    }
257
    WCHAR tempFile[MAX_PATH+1];
258
    if (GetTempFileNameW(tempPath, L"fx", 0, tempFile) == 0) {
259
      break;
260
    }
261
    HANDLE replacement =
262
      sCreateFileWStub(tempFile, GENERIC_READ | GENERIC_WRITE, aShare,
263
                       aSecurity, TRUNCATE_EXISTING,
264
                       FILE_ATTRIBUTE_TEMPORARY |
265
                         FILE_FLAG_DELETE_ON_CLOSE,
266
                       nullptr);
267
    if (replacement == INVALID_HANDLE_VALUE) {
268
      break;
269
    }
270
271
    HANDLE original = sCreateFileWStub(aFname, aAccess, aShare, aSecurity,
272
                                       aCreation, aFlags, aFTemplate);
273
    if (original != INVALID_HANDLE_VALUE) {
274
      // copy original to replacement
275
      static const size_t kBufferSize = 1024;
276
      char buffer[kBufferSize];
277
      DWORD bytes;
278
      while (ReadFile(original, buffer, kBufferSize, &bytes, NULL)) {
279
        if (bytes == 0) {
280
          break;
281
        }
282
        DWORD wbytes;
283
        WriteFile(replacement, buffer, bytes, &wbytes, NULL);
284
        if (bytes < kBufferSize) {
285
          break;
286
        }
287
      }
288
      CloseHandle(original);
289
    }
290
    static const char kSettingString[] = "\nProtectedMode=0\n";
291
    DWORD wbytes;
292
    WriteFile(replacement, static_cast<const void*>(kSettingString),
293
              sizeof(kSettingString) - 1, &wbytes, NULL);
294
    SetFilePointer(replacement, 0, NULL, FILE_BEGIN);
295
    return replacement;
296
  }
297
  return sCreateFileWStub(aFname, aAccess, aShare, aSecurity, aCreation, aFlags,
298
                          aFTemplate);
299
}
300
301
void FunctionHook::HookProtectedMode()
302
{
303
  // Legacy code.  Uses the nsWindowsDLLInterceptor directly instead of
304
  // using the FunctionHook
305
  sKernel32Intercept.Init("kernel32.dll");
306
  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Plugin);
307
  sCreateFileWStub.Set(sKernel32Intercept, "CreateFileW", &CreateFileWHookFn);
308
  sCreateFileAStub.Set(sKernel32Intercept, "CreateFileA", &CreateFileAHookFn);
309
}
310
311
#endif // defined(XP_WIN)
312
313
#define FUN_HOOK(x) static_cast<FunctionHook*>(x)
314
315
void
316
FunctionHook::AddFunctionHooks(FunctionHookArray& aHooks)
317
0
{
318
0
  // We transfer ownership of the FunctionHook objects to the array.
319
#if defined(XP_WIN)
320
  aHooks[ID_GetWindowInfo] =
321
    FUN_HOOK(new GetWindowInfoFH("user32.dll", "GetWindowInfo",
322
                                 &GetWindowInfo, &GetWindowInfoHook));
323
  aHooks[ID_PrintDlgW] =
324
    FUN_HOOK(new PrintDlgWFH("comdlg32.dll", "PrintDlgW", &PrintDlgW,
325
                             PrintDlgWHook));
326
#endif // defined(XP_WIN)
327
}
328
329
#undef FUN_HOOK
330
331
} // namespace plugins
332
} // namespace mozilla