forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			135 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| /**
 | |
|  * LSPs are evil little bits of code that are allowed to inject into our
 | |
|  * networking stack by Windows.  Once they have wormed into our process
 | |
|  * they gnaw at our innards until we crash.  Here we force the buggers
 | |
|  * into the light by recording them in our crash information.
 | |
|  * We do the enumeration on a thread because I'm concerned about startup perf
 | |
|  * on machines with several LSPs.
 | |
|  */
 | |
| 
 | |
| #include "nsICrashReporter.h"
 | |
| #include "nsISupportsImpl.h"
 | |
| #include "nsServiceManagerUtils.h"
 | |
| #include "nsThreadUtils.h"
 | |
| #include "nsQueryObject.h"
 | |
| #include "nsWindowsHelpers.h"
 | |
| #include <windows.h>
 | |
| #include <rpc.h>
 | |
| #include <ws2spi.h>
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace crashreporter {
 | |
| 
 | |
| class LSPAnnotationGatherer : public Runnable {
 | |
|   ~LSPAnnotationGatherer() {}
 | |
| 
 | |
|  public:
 | |
|   LSPAnnotationGatherer() : Runnable("crashreporter::LSPAnnotationGatherer") {}
 | |
|   NS_DECL_NSIRUNNABLE
 | |
| 
 | |
|   void Annotate();
 | |
|   nsCString mString;
 | |
| };
 | |
| 
 | |
| void LSPAnnotationGatherer::Annotate() {
 | |
|   nsCOMPtr<nsICrashReporter> cr =
 | |
|       do_GetService("@mozilla.org/toolkit/crash-reporter;1");
 | |
|   bool enabled;
 | |
|   if (cr && NS_SUCCEEDED(cr->GetEnabled(&enabled)) && enabled) {
 | |
|     cr->AnnotateCrashReport("Winsock_LSP"_ns, mString);
 | |
|   }
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| LSPAnnotationGatherer::Run() {
 | |
|   DWORD size = 0;
 | |
|   int err;
 | |
|   // Get the size of the buffer we need
 | |
|   if (SOCKET_ERROR != WSCEnumProtocols(nullptr, nullptr, &size, &err) ||
 | |
|       err != WSAENOBUFS) {
 | |
|     // Er, what?
 | |
|     MOZ_ASSERT_UNREACHABLE(
 | |
|         "WSCEnumProtocols succeeded when it should have "
 | |
|         "failed");
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   auto byteArray = MakeUnique<char[]>(size);
 | |
|   WSAPROTOCOL_INFOW* providers =
 | |
|       reinterpret_cast<WSAPROTOCOL_INFOW*>(byteArray.get());
 | |
| 
 | |
|   int n = WSCEnumProtocols(nullptr, providers, &size, &err);
 | |
|   if (n == SOCKET_ERROR) {
 | |
|     // Lame. We provided the right size buffer; we'll just give up now.
 | |
|     NS_WARNING("Could not get LSP list");
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   nsCString str;
 | |
|   for (int i = 0; i < n; i++) {
 | |
|     AppendUTF16toUTF8(nsDependentString(providers[i].szProtocol), str);
 | |
|     str.AppendLiteral(" : ");
 | |
|     str.AppendInt(providers[i].iVersion);
 | |
|     str.AppendLiteral(" : ");
 | |
|     str.AppendInt(providers[i].iAddressFamily);
 | |
|     str.AppendLiteral(" : ");
 | |
|     str.AppendInt(providers[i].iSocketType);
 | |
|     str.AppendLiteral(" : ");
 | |
|     str.AppendInt(providers[i].iProtocol);
 | |
|     str.AppendLiteral(" : ");
 | |
|     str.AppendPrintf("0x%x", providers[i].dwServiceFlags1);
 | |
|     str.AppendLiteral(" : ");
 | |
|     str.AppendPrintf("0x%x", providers[i].dwProviderFlags);
 | |
|     str.AppendLiteral(" : ");
 | |
| 
 | |
|     wchar_t path[MAX_PATH];
 | |
|     int pathLen = MAX_PATH;
 | |
|     if (!WSCGetProviderPath(&providers[i].ProviderId, path, &pathLen, &err)) {
 | |
|       AppendUTF16toUTF8(nsDependentString(path), str);
 | |
|     }
 | |
| 
 | |
|     str.AppendLiteral(" : ");
 | |
|     // Call WSCGetProviderInfo to obtain the category flags for this provider.
 | |
|     // When present, these flags inform Windows as to which order to chain the
 | |
|     // providers.
 | |
|     DWORD categoryInfo;
 | |
|     size_t categoryInfoSize = sizeof(categoryInfo);
 | |
|     if (!WSCGetProviderInfo(&providers[i].ProviderId, ProviderInfoLspCategories,
 | |
|                             (PBYTE)&categoryInfo, &categoryInfoSize, 0, &err)) {
 | |
|       str.AppendPrintf("0x%lx", categoryInfo);
 | |
|     }
 | |
| 
 | |
|     str.AppendLiteral(" : ");
 | |
|     if (providers[i].ProtocolChain.ChainLen <= BASE_PROTOCOL) {
 | |
|       // If we're dealing with a catalog entry that identifies an individual
 | |
|       // base or layer provider, log its provider GUID.
 | |
|       RPC_CSTR provIdStr = nullptr;
 | |
|       if (UuidToStringA(&providers[i].ProviderId, &provIdStr) == RPC_S_OK) {
 | |
|         str.Append(reinterpret_cast<char*>(provIdStr));
 | |
|         RpcStringFreeA(&provIdStr);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (i + 1 != n) {
 | |
|       str.AppendLiteral(" \n ");
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   mString = str;
 | |
|   NS_DispatchToMainThread(
 | |
|       NewRunnableMethod("crashreporter::LSPAnnotationGatherer::Annotate", this,
 | |
|                         &LSPAnnotationGatherer::Annotate));
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| void LSPAnnotate() {
 | |
|   nsCOMPtr<nsIRunnable> runnable(new LSPAnnotationGatherer());
 | |
|   NS_DispatchBackgroundTask(runnable.forget());
 | |
| }
 | |
| 
 | |
| }  // namespace crashreporter
 | |
| }  // namespace mozilla
 | 
