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