1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 /**
6  * LSPs are evil little bits of code that are allowed to inject into our
7  * networking stack by Windows.  Once they have wormed into our process
8  * they gnaw at our innards until we crash.  Here we force the buggers
9  * into the light by recording them in our crash information.
10  * We do the enumeration on a thread because I'm concerned about startup perf
11  * on machines with several LSPs.
12  */
13 
14 #include "nsICrashReporter.h"
15 #include "nsISupportsImpl.h"
16 #include "nsServiceManagerUtils.h"
17 #include "nsThreadUtils.h"
18 #include "nsQueryObject.h"
19 #include "nsWindowsHelpers.h"
20 #include <windows.h>
21 #include <rpc.h>
22 #include <ws2spi.h>
23 
24 namespace mozilla {
25 namespace crashreporter {
26 
27 class LSPAnnotationGatherer : public Runnable {
~LSPAnnotationGatherer()28   ~LSPAnnotationGatherer() {}
29 
30  public:
LSPAnnotationGatherer()31   LSPAnnotationGatherer() : Runnable("crashreporter::LSPAnnotationGatherer") {}
32   NS_DECL_NSIRUNNABLE
33 
34   void Annotate();
35   nsCString mString;
36 };
37 
Annotate()38 void LSPAnnotationGatherer::Annotate() {
39   nsCOMPtr<nsICrashReporter> cr =
40       do_GetService("@mozilla.org/toolkit/crash-reporter;1");
41   bool enabled;
42   if (cr && NS_SUCCEEDED(cr->GetEnabled(&enabled)) && enabled) {
43     cr->AnnotateCrashReport("Winsock_LSP"_ns, mString);
44   }
45 }
46 
47 NS_IMETHODIMP
Run()48 LSPAnnotationGatherer::Run() {
49   DWORD size = 0;
50   int err;
51   // Get the size of the buffer we need
52   if (SOCKET_ERROR != WSCEnumProtocols(nullptr, nullptr, &size, &err) ||
53       err != WSAENOBUFS) {
54     // Er, what?
55     MOZ_ASSERT_UNREACHABLE(
56         "WSCEnumProtocols succeeded when it should have "
57         "failed");
58     return NS_ERROR_FAILURE;
59   }
60 
61   auto byteArray = MakeUnique<char[]>(size);
62   WSAPROTOCOL_INFOW* providers =
63       reinterpret_cast<WSAPROTOCOL_INFOW*>(byteArray.get());
64 
65   int n = WSCEnumProtocols(nullptr, providers, &size, &err);
66   if (n == SOCKET_ERROR) {
67     // Lame. We provided the right size buffer; we'll just give up now.
68     NS_WARNING("Could not get LSP list");
69     return NS_ERROR_FAILURE;
70   }
71 
72   nsCString str;
73   for (int i = 0; i < n; i++) {
74     AppendUTF16toUTF8(nsDependentString(providers[i].szProtocol), str);
75     str.AppendLiteral(" : ");
76     str.AppendInt(providers[i].iVersion);
77     str.AppendLiteral(" : ");
78     str.AppendInt(providers[i].iAddressFamily);
79     str.AppendLiteral(" : ");
80     str.AppendInt(providers[i].iSocketType);
81     str.AppendLiteral(" : ");
82     str.AppendInt(providers[i].iProtocol);
83     str.AppendLiteral(" : ");
84     str.AppendPrintf("0x%x", providers[i].dwServiceFlags1);
85     str.AppendLiteral(" : ");
86     str.AppendPrintf("0x%x", providers[i].dwProviderFlags);
87     str.AppendLiteral(" : ");
88 
89     wchar_t path[MAX_PATH];
90     int pathLen = MAX_PATH;
91     if (!WSCGetProviderPath(&providers[i].ProviderId, path, &pathLen, &err)) {
92       AppendUTF16toUTF8(nsDependentString(path), str);
93     }
94 
95     str.AppendLiteral(" : ");
96     // Call WSCGetProviderInfo to obtain the category flags for this provider.
97     // When present, these flags inform Windows as to which order to chain the
98     // providers.
99     DWORD categoryInfo;
100     size_t categoryInfoSize = sizeof(categoryInfo);
101     if (!WSCGetProviderInfo(&providers[i].ProviderId, ProviderInfoLspCategories,
102                             (PBYTE)&categoryInfo, &categoryInfoSize, 0, &err)) {
103       str.AppendPrintf("0x%lx", categoryInfo);
104     }
105 
106     str.AppendLiteral(" : ");
107     if (providers[i].ProtocolChain.ChainLen <= BASE_PROTOCOL) {
108       // If we're dealing with a catalog entry that identifies an individual
109       // base or layer provider, log its provider GUID.
110       RPC_CSTR provIdStr = nullptr;
111       if (UuidToStringA(&providers[i].ProviderId, &provIdStr) == RPC_S_OK) {
112         str.Append(reinterpret_cast<char*>(provIdStr));
113         RpcStringFreeA(&provIdStr);
114       }
115     }
116 
117     if (i + 1 != n) {
118       str.AppendLiteral(" \n ");
119     }
120   }
121 
122   mString = str;
123   NS_DispatchToMainThread(
124       NewRunnableMethod("crashreporter::LSPAnnotationGatherer::Annotate", this,
125                         &LSPAnnotationGatherer::Annotate));
126   return NS_OK;
127 }
128 
LSPAnnotate()129 void LSPAnnotate() {
130   nsCOMPtr<nsIRunnable> runnable(new LSPAnnotationGatherer());
131   NS_DispatchBackgroundTask(runnable.forget());
132 }
133 
134 }  // namespace crashreporter
135 }  // namespace mozilla
136