Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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