xpcom/build/PoisonIOInterposerWin.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 ci et: */
     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/. */
     7 #include "PoisonIOInterposer.h"
     9 #include <algorithm>
    10 #include <stdio.h>
    11 #include <vector>
    13 #include <io.h>
    14 #include <windows.h>
    15 #include <winternl.h>
    17 #include "mozilla/Assertions.h"
    18 #include "mozilla/FileUtilsWin.h"
    19 #include "mozilla/IOInterposer.h"
    20 #include "mozilla/Mutex.h"
    21 #include "mozilla/TimeStamp.h"
    22 #include "nsTArray.h"
    23 #include "nsWindowsDllInterceptor.h"
    24 #include "plstr.h"
    26 using namespace mozilla;
    28 namespace {
    30 // Keep track of poisoned state. Notice that there is no reason to lock access
    31 // to this variable as it's only changed in InitPoisonIOInterposer and
    32 // ClearPoisonIOInterposer which may only be called on the main-thread when no
    33 // other threads are running.
    34 static bool sIOPoisoned = false;
    36 /************************ Internal NT API Declarations ************************/
    38 /*
    39  * Function pointer declaration for internal NT routine to create/open files.
    40  * For documentation on the NtCreateFile routine, see MSDN.
    41  */
    42 typedef NTSTATUS (NTAPI *NtCreateFileFn)(
    43   OUT   PHANDLE                 aFileHandle,
    44   IN    ACCESS_MASK             aDesiredAccess,
    45   IN    POBJECT_ATTRIBUTES      aObjectAttributes,
    46   OUT   PIO_STATUS_BLOCK        aIoStatusBlock,
    47   IN    PLARGE_INTEGER          aAllocationSize,
    48   IN    ULONG                   aFileAttributes,
    49   IN    ULONG                   aShareAccess,
    50   IN    ULONG                   aCreateDisposition,
    51   IN    ULONG                   aCreateOptions,
    52   IN    PVOID                   aEaBuffer,
    53   IN    ULONG                   aEaLength
    54 );
    56 /**
    57  * Function pointer declaration for internal NT routine to read data from file.
    58  * For documentation on the NtReadFile routine, see ZwReadFile on MSDN.
    59  */
    60 typedef NTSTATUS (NTAPI *NtReadFileFn)(
    61   IN    HANDLE                  aFileHandle,
    62   IN    HANDLE                  aEvent,
    63   IN    PIO_APC_ROUTINE         aApc,
    64   IN    PVOID                   aApcCtx,
    65   OUT   PIO_STATUS_BLOCK        aIoStatus,
    66   OUT   PVOID                   aBuffer,
    67   IN    ULONG                   aLength,
    68   IN    PLARGE_INTEGER          aOffset,
    69   IN    PULONG                  aKey
    70 );
    72 /**
    73  * Function pointer declaration for internal NT routine to read data from file.
    74  * No documentation exists, see wine sources for details.
    75  */
    76 typedef NTSTATUS (NTAPI* NtReadFileScatterFn)(
    77   IN    HANDLE                  aFileHandle,
    78   IN    HANDLE                  aEvent,
    79   IN    PIO_APC_ROUTINE         aApc,
    80   IN    PVOID                   aApcCtx,
    81   OUT   PIO_STATUS_BLOCK        aIoStatus,
    82   IN    FILE_SEGMENT_ELEMENT*   aSegments,
    83   IN    ULONG                   aLength,
    84   IN    PLARGE_INTEGER          aOffset,
    85   IN    PULONG                  aKey
    86 );
    88 /**
    89  * Function pointer declaration for internal NT routine to write data to file.
    90  * For documentation on the NtWriteFile routine, see ZwWriteFile on MSDN.
    91  */
    92 typedef NTSTATUS (NTAPI *NtWriteFileFn)(
    93   IN    HANDLE                  aFileHandle,
    94   IN    HANDLE                  aEvent,
    95   IN    PIO_APC_ROUTINE         aApc,
    96   IN    PVOID                   aApcCtx,
    97   OUT   PIO_STATUS_BLOCK        aIoStatus,
    98   IN    PVOID                   aBuffer,
    99   IN    ULONG                   aLength,
   100   IN    PLARGE_INTEGER          aOffset,
   101   IN    PULONG                  aKey
   102 );
   104 /**
   105  * Function pointer declaration for internal NT routine to write data to file.
   106  * No documentation exists, see wine sources for details.
   107  */
   108 typedef NTSTATUS (NTAPI *NtWriteFileGatherFn)(
   109   IN    HANDLE                  aFileHandle,
   110   IN    HANDLE                  aEvent,
   111   IN    PIO_APC_ROUTINE         aApc,
   112   IN    PVOID                   aApcCtx,
   113   OUT   PIO_STATUS_BLOCK        aIoStatus,
   114   IN    FILE_SEGMENT_ELEMENT*   aSegments,
   115   IN    ULONG                   aLength,
   116   IN    PLARGE_INTEGER          aOffset,
   117   IN    PULONG                  aKey
   118 );
   120 /**
   121  * Function pointer declaration for internal NT routine to flush to disk.
   122  * For documentation on the NtFlushBuffersFile routine, see ZwFlushBuffersFile
   123  * on MSDN.
   124  */
   125 typedef NTSTATUS (NTAPI *NtFlushBuffersFileFn)(
   126   IN    HANDLE                  aFileHandle,
   127   OUT   PIO_STATUS_BLOCK        aIoStatusBlock
   128 );
   130 typedef struct _FILE_NETWORK_OPEN_INFORMATION* PFILE_NETWORK_OPEN_INFORMATION;
   131 /**
   132  * Function pointer delaration for internal NT routine to query file attributes.
   133  * (equivalent to stat)
   134  */
   135 typedef NTSTATUS (NTAPI *NtQueryFullAttributesFileFn)(
   136   IN    POBJECT_ATTRIBUTES      aObjectAttributes,
   137   OUT   PFILE_NETWORK_OPEN_INFORMATION  aFileInformation
   138 );
   140 /*************************** Auxiliary Declarations ***************************/
   142 /**
   143  * RAII class for timing the duration of an I/O call and reporting the result
   144  * to the IOInterposeObserver API.
   145  */
   146 class WinIOAutoObservation : public IOInterposeObserver::Observation
   147 {
   148 public:
   149   WinIOAutoObservation(IOInterposeObserver::Operation aOp,
   150                        HANDLE aFileHandle, const LARGE_INTEGER* aOffset)
   151     : IOInterposeObserver::Observation(aOp, sReference,
   152                                        !IsDebugFile(reinterpret_cast<intptr_t>(
   153                                            aFileHandle)))
   154     , mFileHandle(aFileHandle)
   155     , mHasQueriedFilename(false)
   156     , mFilename(nullptr)
   157   {
   158     if (mShouldReport) {
   159       mOffset.QuadPart = aOffset ? aOffset->QuadPart : 0;
   160     }
   161   }
   163   WinIOAutoObservation(IOInterposeObserver::Operation aOp, nsAString& aFilename)
   164     : IOInterposeObserver::Observation(aOp, sReference)
   165     , mFileHandle(nullptr)
   166     , mHasQueriedFilename(false)
   167     , mFilename(nullptr)
   168   {
   169     if (mShouldReport) {
   170       nsAutoString dosPath;
   171       if (NtPathToDosPath(aFilename, dosPath)) {
   172         mFilename = ToNewUnicode(dosPath);
   173         mHasQueriedFilename = true;
   174       }
   175       mOffset.QuadPart = 0;
   176     }
   177   }
   179   // Custom implementation of IOInterposeObserver::Observation::Filename
   180   const char16_t* Filename() MOZ_OVERRIDE;
   182   ~WinIOAutoObservation()
   183   {
   184     Report();
   185     if (mFilename) {
   186       MOZ_ASSERT(mHasQueriedFilename);
   187       NS_Free(mFilename);
   188       mFilename = nullptr;
   189     }
   190   }
   192 private:
   193   HANDLE              mFileHandle;
   194   LARGE_INTEGER       mOffset;
   195   bool                mHasQueriedFilename;
   196   char16_t*           mFilename;
   197   static const char*  sReference;
   198 };
   200 const char* WinIOAutoObservation::sReference = "PoisonIOInterposer";
   202 // Get filename for this observation
   203 const char16_t* WinIOAutoObservation::Filename()
   204 {
   205   // If mHasQueriedFilename is true, then filename is already stored in mFilename
   206   if (mHasQueriedFilename) {
   207     return mFilename;
   208   }
   210   nsAutoString utf16Filename;
   211   if (HandleToFilename(mFileHandle, mOffset, utf16Filename)) {
   212     // Heap allocate with leakable memory
   213     mFilename = ToNewUnicode(utf16Filename);
   214   }
   215   mHasQueriedFilename = true;
   217   // Return filename
   218   return mFilename;
   219 }
   221 /*************************** IO Interposing Methods ***************************/
   223 // Function pointers to original functions
   224 static NtCreateFileFn         gOriginalNtCreateFile;
   225 static NtReadFileFn           gOriginalNtReadFile;
   226 static NtReadFileScatterFn    gOriginalNtReadFileScatter;
   227 static NtWriteFileFn          gOriginalNtWriteFile;
   228 static NtWriteFileGatherFn    gOriginalNtWriteFileGather;
   229 static NtFlushBuffersFileFn   gOriginalNtFlushBuffersFile;
   230 static NtQueryFullAttributesFileFn gOriginalNtQueryFullAttributesFile;
   232 static NTSTATUS NTAPI InterposedNtCreateFile(
   233   PHANDLE                 aFileHandle,
   234   ACCESS_MASK             aDesiredAccess,
   235   POBJECT_ATTRIBUTES      aObjectAttributes,
   236   PIO_STATUS_BLOCK        aIoStatusBlock,
   237   PLARGE_INTEGER          aAllocationSize,
   238   ULONG                   aFileAttributes,
   239   ULONG                   aShareAccess,
   240   ULONG                   aCreateDisposition,
   241   ULONG                   aCreateOptions,
   242   PVOID                   aEaBuffer,
   243   ULONG                   aEaLength
   244 )
   245 {
   246   // Report IO
   247   const wchar_t* buf = aObjectAttributes ?
   248                          aObjectAttributes->ObjectName->Buffer :
   249                          L"";
   250   uint32_t len = aObjectAttributes ?
   251                    aObjectAttributes->ObjectName->Length / sizeof(WCHAR) :
   252                    0;
   253   nsDependentSubstring filename(buf, len);
   254   WinIOAutoObservation timer(IOInterposeObserver::OpCreateOrOpen, filename);
   256   // Something is badly wrong if this function is undefined
   257   MOZ_ASSERT(gOriginalNtCreateFile);
   259   // Execute original function
   260   return gOriginalNtCreateFile(
   261     aFileHandle,
   262     aDesiredAccess,
   263     aObjectAttributes,
   264     aIoStatusBlock,
   265     aAllocationSize,
   266     aFileAttributes,
   267     aShareAccess,
   268     aCreateDisposition,
   269     aCreateOptions,
   270     aEaBuffer,
   271     aEaLength
   272   );
   273 }
   275 static NTSTATUS NTAPI InterposedNtReadFile(
   276   HANDLE                  aFileHandle,
   277   HANDLE                  aEvent,
   278   PIO_APC_ROUTINE         aApc,
   279   PVOID                   aApcCtx,
   280   PIO_STATUS_BLOCK        aIoStatus,
   281   PVOID                   aBuffer,
   282   ULONG                   aLength,
   283   PLARGE_INTEGER          aOffset,
   284   PULONG                  aKey)
   285 {
   286   // Report IO
   287   WinIOAutoObservation timer(IOInterposeObserver::OpRead, aFileHandle, aOffset);
   289   // Something is badly wrong if this function is undefined
   290   MOZ_ASSERT(gOriginalNtReadFile);
   292   // Execute original function
   293   return gOriginalNtReadFile(
   294     aFileHandle,
   295     aEvent,
   296     aApc,
   297     aApcCtx,
   298     aIoStatus,
   299     aBuffer,
   300     aLength,
   301     aOffset,
   302     aKey
   303   );
   304 }
   306 static NTSTATUS NTAPI InterposedNtReadFileScatter(
   307   HANDLE                  aFileHandle,
   308   HANDLE                  aEvent,
   309   PIO_APC_ROUTINE         aApc,
   310   PVOID                   aApcCtx,
   311   PIO_STATUS_BLOCK        aIoStatus,
   312   FILE_SEGMENT_ELEMENT*   aSegments,
   313   ULONG                   aLength,
   314   PLARGE_INTEGER          aOffset,
   315   PULONG                  aKey)
   316 {
   317   // Report IO
   318   WinIOAutoObservation timer(IOInterposeObserver::OpRead, aFileHandle, aOffset);
   320   // Something is badly wrong if this function is undefined
   321   MOZ_ASSERT(gOriginalNtReadFileScatter);
   323   // Execute original function
   324   return gOriginalNtReadFileScatter(
   325     aFileHandle,
   326     aEvent,
   327     aApc,
   328     aApcCtx,
   329     aIoStatus,
   330     aSegments,
   331     aLength,
   332     aOffset,
   333     aKey
   334   );
   335 }
   337 // Interposed NtWriteFile function
   338 static NTSTATUS NTAPI InterposedNtWriteFile(
   339   HANDLE                        aFileHandle,
   340   HANDLE                        aEvent,
   341   PIO_APC_ROUTINE               aApc,
   342   PVOID                         aApcCtx,
   343   PIO_STATUS_BLOCK              aIoStatus,
   344   PVOID                         aBuffer,
   345   ULONG                         aLength,
   346   PLARGE_INTEGER                aOffset,
   347   PULONG                        aKey)
   348 {
   349   // Report IO
   350   WinIOAutoObservation timer(IOInterposeObserver::OpWrite, aFileHandle,
   351                              aOffset);
   353   // Something is badly wrong if this function is undefined
   354   MOZ_ASSERT(gOriginalNtWriteFile);
   356   // Execute original function
   357   return gOriginalNtWriteFile(
   358     aFileHandle,
   359     aEvent,
   360     aApc,
   361     aApcCtx,
   362     aIoStatus,
   363     aBuffer,
   364     aLength,
   365     aOffset,
   366     aKey
   367   );
   368 }
   370 // Interposed NtWriteFileGather function
   371 static NTSTATUS NTAPI InterposedNtWriteFileGather(
   372   HANDLE                        aFileHandle,
   373   HANDLE                        aEvent,
   374   PIO_APC_ROUTINE               aApc,
   375   PVOID                         aApcCtx,
   376   PIO_STATUS_BLOCK              aIoStatus,
   377   FILE_SEGMENT_ELEMENT*         aSegments,
   378   ULONG                         aLength,
   379   PLARGE_INTEGER                aOffset,
   380   PULONG                        aKey)
   381 {
   382   // Report IO
   383   WinIOAutoObservation timer(IOInterposeObserver::OpWrite, aFileHandle,
   384                              aOffset);
   386   // Something is badly wrong if this function is undefined
   387   MOZ_ASSERT(gOriginalNtWriteFileGather);
   389   // Execute original function
   390   return gOriginalNtWriteFileGather(
   391     aFileHandle,
   392     aEvent,
   393     aApc,
   394     aApcCtx,
   395     aIoStatus,
   396     aSegments,
   397     aLength,
   398     aOffset,
   399     aKey
   400   );
   401 }
   403 static NTSTATUS NTAPI InterposedNtFlushBuffersFile(
   404   HANDLE                          aFileHandle,
   405   PIO_STATUS_BLOCK                aIoStatusBlock)
   406 {
   407   // Report IO
   408   WinIOAutoObservation timer(IOInterposeObserver::OpFSync, aFileHandle,
   409                              nullptr);
   411   // Something is badly wrong if this function is undefined
   412   MOZ_ASSERT(gOriginalNtFlushBuffersFile);
   414   // Execute original function
   415   return gOriginalNtFlushBuffersFile(
   416     aFileHandle,
   417     aIoStatusBlock
   418   );
   419 }
   421 static NTSTATUS NTAPI InterposedNtQueryFullAttributesFile(
   422   POBJECT_ATTRIBUTES              aObjectAttributes,
   423   PFILE_NETWORK_OPEN_INFORMATION  aFileInformation)
   424 {
   425   // Report IO
   426   const wchar_t* buf = aObjectAttributes ?
   427                          aObjectAttributes->ObjectName->Buffer :
   428                          L"";
   429   uint32_t len = aObjectAttributes ?
   430                    aObjectAttributes->ObjectName->Length / sizeof(WCHAR) :
   431                    0;
   432   nsDependentSubstring filename(buf, len);
   433   WinIOAutoObservation timer(IOInterposeObserver::OpStat, filename);
   435   // Something is badly wrong if this function is undefined
   436   MOZ_ASSERT(gOriginalNtQueryFullAttributesFile);
   438   // Execute original function
   439   return gOriginalNtQueryFullAttributesFile(
   440     aObjectAttributes,
   441     aFileInformation
   442   );
   443 }
   445 } // anonymous namespace
   447 /******************************** IO Poisoning ********************************/
   449 // Windows DLL interceptor
   450 static WindowsDllInterceptor sNtDllInterceptor;
   452 namespace mozilla {
   454 void InitPoisonIOInterposer() {
   455   // Don't poison twice... as this function may only be invoked on the main
   456   // thread when no other threads are running, it safe to allow multiple calls
   457   // to InitPoisonIOInterposer() without complaining (ie. failing assertions).
   458   if (sIOPoisoned) {
   459     return;
   460   }
   461   sIOPoisoned = true;
   463   // Stdout and Stderr are OK.
   464   MozillaRegisterDebugFD(1);
   465   MozillaRegisterDebugFD(2);
   467   // Initialize dll interceptor and add hooks
   468   sNtDllInterceptor.Init("ntdll.dll");
   469   sNtDllInterceptor.AddHook(
   470     "NtCreateFile",
   471     reinterpret_cast<intptr_t>(InterposedNtCreateFile),
   472     reinterpret_cast<void**>(&gOriginalNtCreateFile)
   473   );
   474   sNtDllInterceptor.AddHook(
   475     "NtReadFile",
   476     reinterpret_cast<intptr_t>(InterposedNtReadFile),
   477     reinterpret_cast<void**>(&gOriginalNtReadFile)
   478   );
   479   sNtDllInterceptor.AddHook(
   480     "NtReadFileScatter",
   481     reinterpret_cast<intptr_t>(InterposedNtReadFileScatter),
   482     reinterpret_cast<void**>(&gOriginalNtReadFileScatter)
   483   );
   484   sNtDllInterceptor.AddHook(
   485     "NtWriteFile",
   486     reinterpret_cast<intptr_t>(InterposedNtWriteFile),
   487     reinterpret_cast<void**>(&gOriginalNtWriteFile)
   488   );
   489   sNtDllInterceptor.AddHook(
   490     "NtWriteFileGather",
   491     reinterpret_cast<intptr_t>(InterposedNtWriteFileGather),
   492     reinterpret_cast<void**>(&gOriginalNtWriteFileGather)
   493   );
   494   sNtDllInterceptor.AddHook(
   495     "NtFlushBuffersFile",
   496     reinterpret_cast<intptr_t>(InterposedNtFlushBuffersFile),
   497     reinterpret_cast<void**>(&gOriginalNtFlushBuffersFile)
   498   );
   499   sNtDllInterceptor.AddHook(
   500     "NtQueryFullAttributesFile",
   501     reinterpret_cast<intptr_t>(InterposedNtQueryFullAttributesFile),
   502     reinterpret_cast<void**>(&gOriginalNtQueryFullAttributesFile)
   503   );
   504 }
   506 void ClearPoisonIOInterposer() {
   507   MOZ_ASSERT(false);
   508   if (sIOPoisoned) {
   509     // Destroy the DLL interceptor
   510     sIOPoisoned = false;
   511     sNtDllInterceptor = WindowsDllInterceptor();
   512   }
   513 }
   515 } // namespace mozilla

mercurial