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 "PoisonIOInterposer.h"
8
9 #include <algorithm>
10 #include <stdio.h>
11 #include <vector>
12
13 #include <io.h>
14 #include <windows.h>
15 #include <winternl.h>
16
17 #include "mozilla/Assertions.h"
18 #include "mozilla/ClearOnShutdown.h"
19 #include "mozilla/FileUtilsWin.h"
20 #include "mozilla/IOInterposer.h"
21 #include "mozilla/Mutex.h"
22 #include "mozilla/NativeNt.h"
23 #include "mozilla/SmallArrayLRUCache.h"
24 #include "mozilla/TimeStamp.h"
25 #include "mozilla/UniquePtr.h"
26 #include "nsTArray.h"
27 #include "nsWindowsDllInterceptor.h"
28 #include "plstr.h"
29
30 #ifdef MOZ_REPLACE_MALLOC
31 # include "replace_malloc_bridge.h"
32 #endif
33
34 namespace {
35
36 // Keep track of poisoned state. Notice that there is no reason to lock access
37 // to this variable as it's only changed in InitPoisonIOInterposer and
38 // ClearPoisonIOInterposer which may only be called on the main-thread when no
39 // other threads are running.
40 static bool sIOPoisoned = false;
41
42 /************************ Internal NT API Declarations ************************/
43
44 /*
45 * Function pointer declaration for internal NT routine to create/open files.
46 * For documentation on the NtCreateFile routine, see MSDN.
47 */
48 typedef NTSTATUS(NTAPI* NtCreateFileFn)(
49 PHANDLE aFileHandle, ACCESS_MASK aDesiredAccess,
50 POBJECT_ATTRIBUTES aObjectAttributes, PIO_STATUS_BLOCK aIoStatusBlock,
51 PLARGE_INTEGER aAllocationSize, ULONG aFileAttributes, ULONG aShareAccess,
52 ULONG aCreateDisposition, ULONG aCreateOptions, PVOID aEaBuffer,
53 ULONG aEaLength);
54
55 /**
56 * Function pointer declaration for internal NT routine to read data from file.
57 * For documentation on the NtReadFile routine, see ZwReadFile on MSDN.
58 */
59 typedef NTSTATUS(NTAPI* NtReadFileFn)(HANDLE aFileHandle, HANDLE aEvent,
60 PIO_APC_ROUTINE aApc, PVOID aApcCtx,
61 PIO_STATUS_BLOCK aIoStatus, PVOID aBuffer,
62 ULONG aLength, PLARGE_INTEGER aOffset,
63 PULONG aKey);
64
65 /**
66 * Function pointer declaration for internal NT routine to read data from file.
67 * No documentation exists, see wine sources for details.
68 */
69 typedef NTSTATUS(NTAPI* NtReadFileScatterFn)(
70 HANDLE aFileHandle, HANDLE aEvent, PIO_APC_ROUTINE aApc, PVOID aApcCtx,
71 PIO_STATUS_BLOCK aIoStatus, FILE_SEGMENT_ELEMENT* aSegments, ULONG aLength,
72 PLARGE_INTEGER aOffset, PULONG aKey);
73
74 /**
75 * Function pointer declaration for internal NT routine to write data to file.
76 * For documentation on the NtWriteFile routine, see ZwWriteFile on MSDN.
77 */
78 typedef NTSTATUS(NTAPI* NtWriteFileFn)(HANDLE aFileHandle, HANDLE aEvent,
79 PIO_APC_ROUTINE aApc, PVOID aApcCtx,
80 PIO_STATUS_BLOCK aIoStatus,
81 PVOID aBuffer, ULONG aLength,
82 PLARGE_INTEGER aOffset, PULONG aKey);
83
84 /**
85 * Function pointer declaration for internal NT routine to write data to file.
86 * No documentation exists, see wine sources for details.
87 */
88 typedef NTSTATUS(NTAPI* NtWriteFileGatherFn)(
89 HANDLE aFileHandle, HANDLE aEvent, PIO_APC_ROUTINE aApc, PVOID aApcCtx,
90 PIO_STATUS_BLOCK aIoStatus, FILE_SEGMENT_ELEMENT* aSegments, ULONG aLength,
91 PLARGE_INTEGER aOffset, PULONG aKey);
92
93 /**
94 * Function pointer declaration for internal NT routine to flush to disk.
95 * For documentation on the NtFlushBuffersFile routine, see ZwFlushBuffersFile
96 * on MSDN.
97 */
98 typedef NTSTATUS(NTAPI* NtFlushBuffersFileFn)(HANDLE aFileHandle,
99 PIO_STATUS_BLOCK aIoStatusBlock);
100
101 typedef struct _FILE_NETWORK_OPEN_INFORMATION* PFILE_NETWORK_OPEN_INFORMATION;
102 /**
103 * Function pointer delaration for internal NT routine to query file attributes.
104 * (equivalent to stat)
105 */
106 typedef NTSTATUS(NTAPI* NtQueryFullAttributesFileFn)(
107 POBJECT_ATTRIBUTES aObjectAttributes,
108 PFILE_NETWORK_OPEN_INFORMATION aFileInformation);
109
110 /*************************** Auxiliary Declarations ***************************/
111
112 // Cache of filenames associated with handles.
113 // `static` to be shared between all calls to `Filename()`.
114 // This assumes handles are not reused, at least within a windows of 32
115 // handles.
116 // Profiling showed that during startup, around half of `Filename()` calls are
117 // resolved with the first entry (best case), and 32 entries cover >95% of
118 // cases, reducing the average `Filename()` cost by 5-10x.
119 using HandleToFilenameCache = mozilla::SmallArrayLRUCache<HANDLE, nsString, 32>;
120 static mozilla::UniquePtr<HandleToFilenameCache> sHandleToFilenameCache;
121
122 /**
123 * RAII class for timing the duration of an I/O call and reporting the result
124 * to the mozilla::IOInterposeObserver API.
125 */
126 class WinIOAutoObservation : public mozilla::IOInterposeObserver::Observation {
127 public:
WinIOAutoObservation(mozilla::IOInterposeObserver::Operation aOp,HANDLE aFileHandle,const LARGE_INTEGER * aOffset)128 WinIOAutoObservation(mozilla::IOInterposeObserver::Operation aOp,
129 HANDLE aFileHandle, const LARGE_INTEGER* aOffset)
130 : mozilla::IOInterposeObserver::Observation(
131 aOp, sReference,
132 !mozilla::IsDebugFile(reinterpret_cast<intptr_t>(aFileHandle))),
133 mFileHandle(aFileHandle),
134 mFileHandleType(GetFileType(aFileHandle)),
135 mHasQueriedFilename(false) {
136 if (mShouldReport) {
137 mOffset.QuadPart = aOffset ? aOffset->QuadPart : 0;
138 }
139 }
140
WinIOAutoObservation(mozilla::IOInterposeObserver::Operation aOp,nsAString & aFilename)141 WinIOAutoObservation(mozilla::IOInterposeObserver::Operation aOp,
142 nsAString& aFilename)
143 : mozilla::IOInterposeObserver::Observation(aOp, sReference),
144 mFileHandle(nullptr),
145 mFileHandleType(FILE_TYPE_UNKNOWN),
146 mHasQueriedFilename(false) {
147 if (mShouldReport) {
148 nsAutoString dosPath;
149 if (mozilla::NtPathToDosPath(aFilename, dosPath)) {
150 mFilename = dosPath;
151 } else {
152 // If we can't get a dosPath, what we have is better than nothing.
153 mFilename = aFilename;
154 }
155 mHasQueriedFilename = true;
156 mOffset.QuadPart = 0;
157 }
158 }
159
SetHandle(HANDLE aFileHandle)160 void SetHandle(HANDLE aFileHandle) {
161 mFileHandle = aFileHandle;
162 if (aFileHandle) {
163 // Note: `GetFileType()` is fast enough that we don't need to cache it.
164 mFileHandleType = GetFileType(aFileHandle);
165
166 if (mHasQueriedFilename) {
167 // `mHasQueriedFilename` indicates we already have a filename, add it to
168 // the cache with the now-known handle.
169 sHandleToFilenameCache->Add(aFileHandle, mFilename);
170 }
171 }
172 }
173
174 const char* FileType() const override;
175
176 void Filename(nsAString& aFilename) override;
177
~WinIOAutoObservation()178 ~WinIOAutoObservation() { Report(); }
179
180 private:
181 HANDLE mFileHandle;
182 DWORD mFileHandleType;
183 LARGE_INTEGER mOffset;
184 bool mHasQueriedFilename;
185 nsString mFilename;
186 static const char* sReference;
187 };
188
189 const char* WinIOAutoObservation::sReference = "PoisonIOInterposer";
190
191 // Get filename for this observation
Filename(nsAString & aFilename)192 void WinIOAutoObservation::Filename(nsAString& aFilename) {
193 // If mHasQueriedFilename is true, then filename is already stored in
194 // mFilename
195 if (mHasQueriedFilename) {
196 aFilename = mFilename;
197 return;
198 }
199
200 if (mFileHandle) {
201 mFilename = sHandleToFilenameCache->FetchOrAdd(mFileHandle, [&]() {
202 nsString filename;
203 if (!mozilla::HandleToFilename(mFileHandle, mOffset, filename)) {
204 // HandleToFilename could fail (return false) but still have added
205 // something to `filename`, so it should be cleared in this case.
206 filename.Truncate();
207 }
208 return filename;
209 });
210 }
211 mHasQueriedFilename = true;
212
213 aFilename = mFilename;
214 }
215
FileType() const216 const char* WinIOAutoObservation::FileType() const {
217 if (mFileHandle) {
218 switch (mFileHandleType) {
219 case FILE_TYPE_CHAR:
220 return "Char";
221 case FILE_TYPE_DISK:
222 return "File";
223 case FILE_TYPE_PIPE:
224 return "Pipe";
225 case FILE_TYPE_REMOTE:
226 return "Remote";
227 case FILE_TYPE_UNKNOWN:
228 default:
229 break;
230 }
231 }
232 // Fallback to base class default implementation.
233 return mozilla::IOInterposeObserver::Observation::FileType();
234 }
235
236 /*************************** IO Interposing Methods ***************************/
237
238 // Function pointers to original functions
239 static mozilla::WindowsDllInterceptor::FuncHookType<NtCreateFileFn>
240 gOriginalNtCreateFile;
241 static mozilla::WindowsDllInterceptor::FuncHookType<NtReadFileFn>
242 gOriginalNtReadFile;
243 static mozilla::WindowsDllInterceptor::FuncHookType<NtReadFileScatterFn>
244 gOriginalNtReadFileScatter;
245 static mozilla::WindowsDllInterceptor::FuncHookType<NtWriteFileFn>
246 gOriginalNtWriteFile;
247 static mozilla::WindowsDllInterceptor::FuncHookType<NtWriteFileGatherFn>
248 gOriginalNtWriteFileGather;
249 static mozilla::WindowsDllInterceptor::FuncHookType<NtFlushBuffersFileFn>
250 gOriginalNtFlushBuffersFile;
251 static mozilla::WindowsDllInterceptor::FuncHookType<NtQueryFullAttributesFileFn>
252 gOriginalNtQueryFullAttributesFile;
253
InterposedNtCreateFile(PHANDLE aFileHandle,ACCESS_MASK aDesiredAccess,POBJECT_ATTRIBUTES aObjectAttributes,PIO_STATUS_BLOCK aIoStatusBlock,PLARGE_INTEGER aAllocationSize,ULONG aFileAttributes,ULONG aShareAccess,ULONG aCreateDisposition,ULONG aCreateOptions,PVOID aEaBuffer,ULONG aEaLength)254 static NTSTATUS NTAPI InterposedNtCreateFile(
255 PHANDLE aFileHandle, ACCESS_MASK aDesiredAccess,
256 POBJECT_ATTRIBUTES aObjectAttributes, PIO_STATUS_BLOCK aIoStatusBlock,
257 PLARGE_INTEGER aAllocationSize, ULONG aFileAttributes, ULONG aShareAccess,
258 ULONG aCreateDisposition, ULONG aCreateOptions, PVOID aEaBuffer,
259 ULONG aEaLength) {
260 // Something is badly wrong if this function is undefined
261 MOZ_ASSERT(gOriginalNtCreateFile);
262
263 if (!mozilla::nt::RtlGetThreadLocalStoragePointer()) {
264 return gOriginalNtCreateFile(
265 aFileHandle, aDesiredAccess, aObjectAttributes, aIoStatusBlock,
266 aAllocationSize, aFileAttributes, aShareAccess, aCreateDisposition,
267 aCreateOptions, aEaBuffer, aEaLength);
268 }
269
270 // Report IO
271 const wchar_t* buf =
272 aObjectAttributes ? aObjectAttributes->ObjectName->Buffer : L"";
273 uint32_t len = aObjectAttributes
274 ? aObjectAttributes->ObjectName->Length / sizeof(WCHAR)
275 : 0;
276 nsDependentSubstring filename(buf, len);
277 WinIOAutoObservation timer(mozilla::IOInterposeObserver::OpCreateOrOpen,
278 filename);
279
280 // Execute original function
281 NTSTATUS status = gOriginalNtCreateFile(
282 aFileHandle, aDesiredAccess, aObjectAttributes, aIoStatusBlock,
283 aAllocationSize, aFileAttributes, aShareAccess, aCreateDisposition,
284 aCreateOptions, aEaBuffer, aEaLength);
285 if (NT_SUCCESS(status) && aFileHandle) {
286 timer.SetHandle(*aFileHandle);
287 }
288 return status;
289 }
290
InterposedNtReadFile(HANDLE aFileHandle,HANDLE aEvent,PIO_APC_ROUTINE aApc,PVOID aApcCtx,PIO_STATUS_BLOCK aIoStatus,PVOID aBuffer,ULONG aLength,PLARGE_INTEGER aOffset,PULONG aKey)291 static NTSTATUS NTAPI InterposedNtReadFile(HANDLE aFileHandle, HANDLE aEvent,
292 PIO_APC_ROUTINE aApc, PVOID aApcCtx,
293 PIO_STATUS_BLOCK aIoStatus,
294 PVOID aBuffer, ULONG aLength,
295 PLARGE_INTEGER aOffset,
296 PULONG aKey) {
297 // Something is badly wrong if this function is undefined
298 MOZ_ASSERT(gOriginalNtReadFile);
299
300 if (!mozilla::nt::RtlGetThreadLocalStoragePointer()) {
301 return gOriginalNtReadFile(aFileHandle, aEvent, aApc, aApcCtx, aIoStatus,
302 aBuffer, aLength, aOffset, aKey);
303 }
304
305 // Report IO
306 WinIOAutoObservation timer(mozilla::IOInterposeObserver::OpRead, aFileHandle,
307 aOffset);
308
309 // Execute original function
310 return gOriginalNtReadFile(aFileHandle, aEvent, aApc, aApcCtx, aIoStatus,
311 aBuffer, aLength, aOffset, aKey);
312 }
313
InterposedNtReadFileScatter(HANDLE aFileHandle,HANDLE aEvent,PIO_APC_ROUTINE aApc,PVOID aApcCtx,PIO_STATUS_BLOCK aIoStatus,FILE_SEGMENT_ELEMENT * aSegments,ULONG aLength,PLARGE_INTEGER aOffset,PULONG aKey)314 static NTSTATUS NTAPI InterposedNtReadFileScatter(
315 HANDLE aFileHandle, HANDLE aEvent, PIO_APC_ROUTINE aApc, PVOID aApcCtx,
316 PIO_STATUS_BLOCK aIoStatus, FILE_SEGMENT_ELEMENT* aSegments, ULONG aLength,
317 PLARGE_INTEGER aOffset, PULONG aKey) {
318 // Something is badly wrong if this function is undefined
319 MOZ_ASSERT(gOriginalNtReadFileScatter);
320
321 if (!mozilla::nt::RtlGetThreadLocalStoragePointer()) {
322 return gOriginalNtReadFileScatter(aFileHandle, aEvent, aApc, aApcCtx,
323 aIoStatus, aSegments, aLength, aOffset,
324 aKey);
325 }
326
327 // Report IO
328 WinIOAutoObservation timer(mozilla::IOInterposeObserver::OpRead, aFileHandle,
329 aOffset);
330
331 // Execute original function
332 return gOriginalNtReadFileScatter(aFileHandle, aEvent, aApc, aApcCtx,
333 aIoStatus, aSegments, aLength, aOffset,
334 aKey);
335 }
336
337 // Interposed NtWriteFile function
InterposedNtWriteFile(HANDLE aFileHandle,HANDLE aEvent,PIO_APC_ROUTINE aApc,PVOID aApcCtx,PIO_STATUS_BLOCK aIoStatus,PVOID aBuffer,ULONG aLength,PLARGE_INTEGER aOffset,PULONG aKey)338 static NTSTATUS NTAPI InterposedNtWriteFile(HANDLE aFileHandle, HANDLE aEvent,
339 PIO_APC_ROUTINE aApc, PVOID aApcCtx,
340 PIO_STATUS_BLOCK aIoStatus,
341 PVOID aBuffer, ULONG aLength,
342 PLARGE_INTEGER aOffset,
343 PULONG aKey) {
344 // Something is badly wrong if this function is undefined
345 MOZ_ASSERT(gOriginalNtWriteFile);
346
347 if (!mozilla::nt::RtlGetThreadLocalStoragePointer()) {
348 return gOriginalNtWriteFile(aFileHandle, aEvent, aApc, aApcCtx, aIoStatus,
349 aBuffer, aLength, aOffset, aKey);
350 }
351
352 // Report IO
353 WinIOAutoObservation timer(mozilla::IOInterposeObserver::OpWrite, aFileHandle,
354 aOffset);
355
356 // Execute original function
357 return gOriginalNtWriteFile(aFileHandle, aEvent, aApc, aApcCtx, aIoStatus,
358 aBuffer, aLength, aOffset, aKey);
359 }
360
361 // Interposed NtWriteFileGather function
InterposedNtWriteFileGather(HANDLE aFileHandle,HANDLE aEvent,PIO_APC_ROUTINE aApc,PVOID aApcCtx,PIO_STATUS_BLOCK aIoStatus,FILE_SEGMENT_ELEMENT * aSegments,ULONG aLength,PLARGE_INTEGER aOffset,PULONG aKey)362 static NTSTATUS NTAPI InterposedNtWriteFileGather(
363 HANDLE aFileHandle, HANDLE aEvent, PIO_APC_ROUTINE aApc, PVOID aApcCtx,
364 PIO_STATUS_BLOCK aIoStatus, FILE_SEGMENT_ELEMENT* aSegments, ULONG aLength,
365 PLARGE_INTEGER aOffset, PULONG aKey) {
366 // Something is badly wrong if this function is undefined
367 MOZ_ASSERT(gOriginalNtWriteFileGather);
368
369 if (!mozilla::nt::RtlGetThreadLocalStoragePointer()) {
370 return gOriginalNtWriteFileGather(aFileHandle, aEvent, aApc, aApcCtx,
371 aIoStatus, aSegments, aLength, aOffset,
372 aKey);
373 }
374
375 // Report IO
376 WinIOAutoObservation timer(mozilla::IOInterposeObserver::OpWrite, aFileHandle,
377 aOffset);
378
379 // Execute original function
380 return gOriginalNtWriteFileGather(aFileHandle, aEvent, aApc, aApcCtx,
381 aIoStatus, aSegments, aLength, aOffset,
382 aKey);
383 }
384
InterposedNtFlushBuffersFile(HANDLE aFileHandle,PIO_STATUS_BLOCK aIoStatusBlock)385 static NTSTATUS NTAPI InterposedNtFlushBuffersFile(
386 HANDLE aFileHandle, PIO_STATUS_BLOCK aIoStatusBlock) {
387 // Something is badly wrong if this function is undefined
388 MOZ_ASSERT(gOriginalNtFlushBuffersFile);
389
390 if (!mozilla::nt::RtlGetThreadLocalStoragePointer()) {
391 return gOriginalNtFlushBuffersFile(aFileHandle, aIoStatusBlock);
392 }
393
394 // Report IO
395 WinIOAutoObservation timer(mozilla::IOInterposeObserver::OpFSync, aFileHandle,
396 nullptr);
397
398 // Execute original function
399 return gOriginalNtFlushBuffersFile(aFileHandle, aIoStatusBlock);
400 }
401
InterposedNtQueryFullAttributesFile(POBJECT_ATTRIBUTES aObjectAttributes,PFILE_NETWORK_OPEN_INFORMATION aFileInformation)402 static NTSTATUS NTAPI InterposedNtQueryFullAttributesFile(
403 POBJECT_ATTRIBUTES aObjectAttributes,
404 PFILE_NETWORK_OPEN_INFORMATION aFileInformation) {
405 // Something is badly wrong if this function is undefined
406 MOZ_ASSERT(gOriginalNtQueryFullAttributesFile);
407
408 if (!mozilla::nt::RtlGetThreadLocalStoragePointer()) {
409 return gOriginalNtQueryFullAttributesFile(aObjectAttributes,
410 aFileInformation);
411 }
412
413 // Report IO
414 const wchar_t* buf =
415 aObjectAttributes ? aObjectAttributes->ObjectName->Buffer : L"";
416 uint32_t len = aObjectAttributes
417 ? aObjectAttributes->ObjectName->Length / sizeof(WCHAR)
418 : 0;
419 nsDependentSubstring filename(buf, len);
420 WinIOAutoObservation timer(mozilla::IOInterposeObserver::OpStat, filename);
421
422 // Execute original function
423 return gOriginalNtQueryFullAttributesFile(aObjectAttributes,
424 aFileInformation);
425 }
426
427 } // namespace
428
429 /******************************** IO Poisoning ********************************/
430
431 // Windows DLL interceptor
432 static mozilla::WindowsDllInterceptor sNtDllInterceptor;
433
434 namespace mozilla {
435
InitPoisonIOInterposer()436 void InitPoisonIOInterposer() {
437 // Currently we hook the functions not early enough to precede third-party
438 // injections. Until we implement a compatible way e.g. applying a hook
439 // in the parent process (bug 1646804), we skip interposing functions under
440 // the known condition(s).
441
442 // Bug 1679741: Kingsoft Internet Security calls NtReadFile in their thread
443 // simultaneously when we're applying a hook on NtReadFile.
444 if (::GetModuleHandleW(L"kwsui64.dll")) {
445 return;
446 }
447
448 // Don't poison twice... as this function may only be invoked on the main
449 // thread when no other threads are running, it safe to allow multiple calls
450 // to InitPoisonIOInterposer() without complaining (ie. failing assertions).
451 if (sIOPoisoned) {
452 return;
453 }
454 sIOPoisoned = true;
455
456 MOZ_RELEASE_ASSERT(!sHandleToFilenameCache);
457 sHandleToFilenameCache = mozilla::MakeUnique<HandleToFilenameCache>();
458 mozilla::RunOnShutdown([]() {
459 // The interposer may still be active after the final shutdown phase
460 // (especially since ClearPoisonIOInterposer() is never called, see bug
461 // 1647107), so we cannot just reset the pointer. Instead we put the cache
462 // in shutdown mode, to clear its memory and stop caching operations.
463 sHandleToFilenameCache->Shutdown();
464 });
465
466 // Stdout and Stderr are OK.
467 MozillaRegisterDebugFD(1);
468 MozillaRegisterDebugFD(2);
469
470 #ifdef MOZ_REPLACE_MALLOC
471 // The contract with InitDebugFd is that the given registry can be used
472 // at any moment, so the instance needs to persist longer than the scope
473 // of this functions.
474 static DebugFdRegistry registry;
475 ReplaceMalloc::InitDebugFd(registry);
476 #endif
477
478 // Initialize dll interceptor and add hooks
479 sNtDllInterceptor.Init("ntdll.dll");
480 gOriginalNtCreateFile.Set(sNtDllInterceptor, "NtCreateFile",
481 &InterposedNtCreateFile);
482 gOriginalNtReadFile.Set(sNtDllInterceptor, "NtReadFile",
483 &InterposedNtReadFile);
484 gOriginalNtReadFileScatter.Set(sNtDllInterceptor, "NtReadFileScatter",
485 &InterposedNtReadFileScatter);
486 gOriginalNtWriteFile.Set(sNtDllInterceptor, "NtWriteFile",
487 &InterposedNtWriteFile);
488 gOriginalNtWriteFileGather.Set(sNtDllInterceptor, "NtWriteFileGather",
489 &InterposedNtWriteFileGather);
490 gOriginalNtFlushBuffersFile.Set(sNtDllInterceptor, "NtFlushBuffersFile",
491 &InterposedNtFlushBuffersFile);
492 gOriginalNtQueryFullAttributesFile.Set(sNtDllInterceptor,
493 "NtQueryFullAttributesFile",
494 &InterposedNtQueryFullAttributesFile);
495 }
496
ClearPoisonIOInterposer()497 void ClearPoisonIOInterposer() {
498 MOZ_ASSERT(false, "Never called! See bug 1647107");
499 if (sIOPoisoned) {
500 // Destroy the DLL interceptor
501 sIOPoisoned = false;
502 sNtDllInterceptor.Clear();
503 sHandleToFilenameCache->Clear();
504 }
505 }
506
507 } // namespace mozilla
508