This patch adds a function to get an exported function in a remote process.
We need this implementation to address Bug 1604008, Bug 1608645, and Bug 1610790.
When `WindowsDllInterceptor` detours a function in a remote process, we used the
native `GetProcAddress` locally, and then detours the returned address in the
target process. The problem is if the caller's export table was modified, the
address returned from `GetProcAddress` might be invalid in the target process,
which is Bug 1604008.
I implemented `GetProcAddress` depending on both local and remote process image,
but it caused two regressions Bug 1608645 and Bug 1610790 because multiple
applications modify firefox's export table in multiple ways, such as replacing
an entry of EAT, replacing an RVA to Export section, or etc.
With this patch, we can use `PEExportSection<MMPolicy>::GetProcAddress` to get
an exported function in a remote process without relying on any local data so
that it's not impacted by modification of the local export table.
Differential Revision: https://phabricator.services.mozilla.com//D62315
Depends on D62314
This patch changes the entrypoint of test programs under mozglue/tests so that
a coming test program can handle a command string easily.
Differential Revision: https://phabricator.services.mozilla.com//D62314
This patch adds a function to get an exported function in a remote process.
We need this implementation to address Bug 1604008, Bug 1608645, and Bug 1610790.
When `WindowsDllInterceptor` detours a function in a remote process, we used the
native `GetProcAddress` locally, and then detours the returned address in the
target process. The problem is if the caller's export table was modified, the
address returned from `GetProcAddress` might be invalid in the target process,
which is Bug 1604008.
I implemented `GetProcAddress` depending on both local and remote process image,
but it caused two regressions Bug 1608645 and Bug 1610790 because multiple
applications modify firefox's export table in multiple ways, such as replacing
an entry of EAT, replacing an RVA to Export section, or etc.
With this patch, we can use `PEExportSection<MMPolicy>::GetProcAddress` to get
an exported function in a remote process without relying on any local data so
that it's not impacted by modification of the local export table.
Differential Revision: https://phabricator.services.mozilla.com/D62315
Depends on D62314
--HG--
extra : rebase_source : 3088f5997a2097ef22ce8567783375e5f7866ab2
This patch changes the entrypoint of test programs under mozglue/tests so that
a coming test program can handle a command string easily.
Differential Revision: https://phabricator.services.mozilla.com/D62314
--HG--
extra : rebase_source : a180de844700bbee60a6491a35da33da84aa12ed
We had a thread-local varialbe `ModuleLoadFrame::sTopFrame` to track the topmost
stack frame of `LdrLoadDll`. However, our hook function `patched_LdrLoadDll` can
be called even before TLS is initialized. In such a case, accessing `sTopFrame`
causes AV.
This patch introduces `SafeThreadLocal` to safely access a thread-local varialbe.
If TLS is not initialized, it falls back to a global variable because in that
early stage there is only a single thread running.
Differential Revision: https://phabricator.services.mozilla.com/D55870
--HG--
extra : moz-landing-system : lando
We had a thread-local varialbe `ModuleLoadFrame::sTopFrame` to track the topmost
stack frame of `LdrLoadDll`. However, our hook function `patched_LdrLoadDll` can
be called even before TLS is initialized. In such a case, accessing `sTopFrame`
causes AV.
This patch introduces `SafeThreadLocal` to safely access a thread-local varialbe.
If TLS is not initialized, it falls back to a global variable because in that
early stage there is only a single thread running.
Differential Revision: https://phabricator.services.mozilla.com/D55870
--HG--
extra : moz-landing-system : lando
The "(null)" printing behavior is a glibc extension and the specified behavior
in the standard is undefined
Differential Revision: https://phabricator.services.mozilla.com/D61071
--HG--
extra : moz-landing-system : lando
A third-party application can modify the export directory, the export address/name/ordinal
tables, or an entry in those tables. If that happens, we will see an RVA is located outside
the mapped image and `RVAToPtr` returns null. This patch makes sure we don't hit null AV
when modification is detected.
`FindExportAddressTableEntry` should not return a pointer to the modified table entry because
we dereference it in another process to cross-process detour.
Differential Revision: https://phabricator.services.mozilla.com/D59738
--HG--
extra : moz-landing-system : lando
When `WindowsDllInterceptor` detours a function in a remote process, it calculates
a target address via `GetProcAddress` in the caller's process first, and detours
that address in the target process. If the caller's export table was modified, the
target address might be invalid in the target process.
With this patch, `WindowsDllInterceptor` uses the target process's export table to
calculate a target function address.
Differential Revision: https://phabricator.services.mozilla.com/D58305
--HG--
extra : moz-landing-system : lando
`GetProcessTimes` is based on QPC, while `GetSystemTime` is based on clock
interruption whose accuracy is lower than QPC. This means in a process's early
stage, `GetSystemTime` may return a timestamp earlier than creation timestamp.
If this happens we'll keep a negative process uptime which causes overflow in
telemetry processing.
Win8+ has a handy API `GetSystemTimePreciseAsFileTime` that solves everything.
On Win7, `GetSystemTimeAsFileTime` still solves this issue. In the worst case,
it returns the exact same timestamp as process creation, but it's ok.
Because the system time is stored as a `FILETIME` in `KUSER`, converting it to
a `SYSTEMTIME` with `GetSystemTime` drops accuracy. We should avoid it unless
needed.
This patch also moves the call to `GetProcessTimes` before getting the current
timestamp in case clock interruption happens in between those two function calls.
Differential Revision: https://phabricator.services.mozilla.com/D56273
--HG--
extra : moz-landing-system : lando
Our detour allocates a trampoline with `PAGE_EXECUTE_READ` first, and then makes
it writable before use. If the dynamic code policy is enabled after allocation,
we fail to change the attribute, and crash the process because we try to write
data into a readonly page. We need to check the validity of a trampoline before
writing data.
Differential Revision: https://phabricator.services.mozilla.com/D56983
--HG--
extra : moz-landing-system : lando
This is a pretty straightforward patch; we add `WindowsIATPatcher` to
implement the actual IAT patching, and use a partial specialization of
`FuncHook` to account for the underlying differences in implementation vs our
existing interceptor code.
Differential Revision: https://phabricator.services.mozilla.com/D57831
--HG--
extra : moz-landing-system : lando
This is a pretty straightforward patch; we add `WindowsIATPatcher` to
implement the actual IAT patching, and use a partial specialization of
`FuncHook` to account for the underlying differences in implementation vs our
existing interceptor code.
Differential Revision: https://phabricator.services.mozilla.com/D57831
--HG--
extra : moz-landing-system : lando
SetWindowLong*/SetWindowLongPtr* was being intercepted so that we could override windowprocs in windowed plugins on Windows. We no longer support windowed plugins so these functions are never intercepted.
Differential Revision: https://phabricator.services.mozilla.com/D55536
--HG--
extra : moz-landing-system : lando
Our detour cannot handle assembly patterns which is injected by the code coverage
instrumentation. We need to skip them in CCov build.
Differential Revision: https://phabricator.services.mozilla.com/D54745
--HG--
extra : moz-landing-system : lando
This patch adds the following pattern to our x64 detour so that we can hook APIs
even though a target is already detoured by another application.
```
mov rax, imm64
push rax
ret
```
We already have `PatchIfTargetIsRecognizedTrampoline` to detour the pattern
`mov; jmp`. There is another variation using `push rax;ret` to jump.
Differential Revision: https://phabricator.services.mozilla.com/D53877
--HG--
extra : moz-landing-system : lando
Passing a dummy object to `NtQueryFullAttributesFile` to avoid AV on WOW64.
Differential Revision: https://phabricator.services.mozilla.com/D53876
--HG--
extra : moz-landing-system : lando
We were keeping nsDocShell::mHistoryId and nsDocShell::mOSHE as keys. They
weren't quite good because:
1. While loading an iframe, they were being registered twice with the same
ids(for about:blank and the real URL) sometimes.
2. It wasn't possible to access to the parent mHistoryId and mOSHE from a child
processes if the parent is in a different process. That may not be the case for
now, but it will be after fission.
So we had to find other IDs to:
1. Determine the Tab of the frames.
2. Determine the URLs of the frames.
For the first use case, we were using nsDocShell::mHistoryId for that purpose
but that was wrong. The closest thing that we can get to a tab ID is
BrowsingContext ID because they don't change after a navigation. But iframes
have different BrowsingContext's, so we still need to create a tree to
construct a tab content. That can be either in the front-end or capture time.
For the second use case, we were using a key pair of mHistoryId and mOSHE. We
now chose to keep inner window IDs for that purpose. Inner window IDs are
unique for each navigation loads because inner window correspond to each JS
window global objects. That's why we can use that without any problem. But one
problem is that we cannot handle `history.pushState` and `history.replaceState`
changes with that change since window global objects won't change during those.
But that was the best thing we can do after fission. So this will be a small
sacrifice for us to keep that functionality working after fission.
In that patch we also remove the registration/unregistration calls. We are
going to add those calls in the next patch.
Differential Revision: https://phabricator.services.mozilla.com/D47065
--HG--
extra : moz-landing-system : lando
`BlocksRingBuffer` had an "entry destructor" to make it a more generic
container, and it was useful during early prototyping of the new profiler
storage (so that we could store owning pointers).
But this entry destructor is stored in an `std::function`, which gets marked as
a potential GC caller by the js rooting hazard analyzer; and as this bug found,
it's not obvious where to place `JS::AutoSuppressGCAnalysis`, because profiler
entries (including stacks) could be added on one thread while GC happens
elsewhere, which triggers the embedded `AutoAssertNoGC` check.
Since we don't actually use the entry destructor facility in the profiler, it's
easier to just get rid of it. As a bonus, it's a small optimization.
Tests that were using an entry destructor now use the `State` instead, to verify
that entries are pushed and cleared as expected.
If needed in the future outside of the profiler, `BlocksRingBuffer` could again
include an entry destructor, but it would have to be through templating, so that
the class used in the profiler wouldn't contain an `std::function`.
Differential Revision: https://phabricator.services.mozilla.com/D46738
--HG--
extra : moz-landing-system : lando
This patch adds the following:
* The `AllocatedUnicodeString` class which encapsulates a `UNICODE_STRING` and
owns its buffer. The buffers are null-terminated so that they may be used as
C-style strings without modification.
** We do not allow either creation or copying within XUL
* `RtlGetCurrentThreadId` and a test to validate it, so that we may obtain the
current thread ID directly from the `TEB` when we do not yet have access to
kernel32.
* An implementation of `SRWLock` that uses Rtl instead of Win32 so that we may
use them before we have access to Win32 DLLs.
* A memory allocation policy that uses Rtl heap functions so that we may use
MFBT `Vector` in code that might not yet have access to Win32 heap functions.
Differential Revision: https://phabricator.services.mozilla.com/D43155
--HG--
extra : moz-landing-system : lando
This patch adds the following:
* The `AllocatedUnicodeString` class which encapsulates a `UNICODE_STRING` and
owns its buffer. The buffers are null-terminated so that they may be used as
C-style strings without modification.
** We do not allow either creation or copying within XUL
* `RtlGetCurrentThreadId` and a test to validate it, so that we may obtain the
current thread ID directly from the `TEB` when we do not yet have access to
kernel32.
* An implementation of `SRWLock` that uses Rtl instead of Win32 so that we may
use them before we have access to Win32 DLLs.
* A memory allocation policy that uses Rtl heap functions so that we may use
MFBT `Vector` in code that might not yet have access to Win32 heap functions.
Differential Revision: https://phabricator.services.mozilla.com/D43155
--HG--
extra : moz-landing-system : lando
This patch adds the following:
* The `AllocatedUnicodeString` class which encapsulates a `UNICODE_STRING` and
owns its buffer. The buffers are null-terminated so that they may be used as
C-style strings without modification.
** We do not allow either creation or copying within XUL
* `RtlGetCurrentThreadId` and a test to validate it, so that we may obtain the
current thread ID directly from the `TEB` when we do not yet have access to
kernel32.
* An implementation of `SRWLock` that uses Rtl instead of Win32 so that we may
use them before we have access to Win32 DLLs.
* A memory allocation policy that uses Rtl heap functions so that we may use
MFBT `Vector` in code that might not yet have access to Win32 heap functions.
Differential Revision: https://phabricator.services.mozilla.com/D43155
--HG--
extra : moz-landing-system : lando
This patch adds the following:
* The `AllocatedUnicodeString` class which encapsulates a `UNICODE_STRING` and
owns its buffer. The buffers are null-terminated so that they may be used as
C-style strings without modification.
** We do not allow either creation or copying within XUL
* `RtlGetCurrentThreadId` and a test to validate it, so that we may obtain the
current thread ID directly from the `TEB` when we do not yet have access to
kernel32.
* An implementation of `SRWLock` that uses Rtl instead of Win32 so that we may
use them before we have access to Win32 DLLs.
* A memory allocation policy that uses Rtl heap functions so that we may use
MFBT `Vector` in code that might not yet have access to Win32 heap functions.
Differential Revision: https://phabricator.services.mozilla.com/D43155
--HG--
extra : moz-landing-system : lando
Some objects are copied byte-by-byte to/from `ModuloBuffer`s.
E.g., serialized `BlocksRingBuffer`s, or duplicate stacks. (And more to come.)
`Iterator::ReadInto(Iterator&)` optimizes these copies by using the minimum
number of `memcpy`s possible.
Differential Revision: https://phabricator.services.mozilla.com/D45838
--HG--
extra : moz-landing-system : lando
Since payloads are not kept alive long after they have been serialized, we can
just create them on the stack and pass a reference to their base (or pointer,
`nullptr` representing "no payloads") to `profiler_add_marker()`.
Differential Revision: https://phabricator.services.mozilla.com/D43430
--HG--
extra : moz-landing-system : lando
Copy the full contents of BlocksRingBuffer into another one.
This is mainly useful to use a temporary buffer to store some data without
contentions, and then integrate the temporary buffer into the main one.
Differential Revision: https://phabricator.services.mozilla.com/D45306
--HG--
extra : moz-landing-system : lando
Payloads will serialize themselves into a `BlocksRingBuffer` entry when first
captured.
Later they will be deserialized, to stream JSON for the output profile.
Differential Revision: https://phabricator.services.mozilla.com/D43428
--HG--
extra : moz-landing-system : lando
Add basic testing of `profiler_get_backtrace` before working on serializing it.
Differential Revision: https://phabricator.services.mozilla.com/D43424
--HG--
extra : moz-landing-system : lando
In some situations we will *need* to use a `BlocksRingBuffer` that absolutely
does not use a mutex -- In particular in the critical section of
`SamplerThread::Run()`, when a thread is suspended, because any action on any
mutex (even a private one that no-one else interacts with) can result in a hang.
As a bonus, `BlocksRingBuffer`s that are known not to be used in multi-thread
situations (e.g., backtraces, extracted stacks for duplication, etc.) will waste
less resources trying to lock/unlock their mutex.
Differential Revision: https://phabricator.services.mozilla.com/D45305
--HG--
extra : moz-landing-system : lando
Some objects are copied byte-by-byte to/from `ModuloBuffer`s.
E.g., serialized `BlocksRingBuffer`s, or duplicate stacks. (And more to come.)
`Iterator::ReadInto(Iterator&)` optimizes these copies by using the minimum
number of `memcpy`s possible.
Differential Revision: https://phabricator.services.mozilla.com/D45838
--HG--
extra : moz-landing-system : lando
Since payloads are not kept alive long after they have been serialized, we can
just create them on the stack and pass a reference to their base (or pointer,
`nullptr` representing "no payloads") to `profiler_add_marker()`.
Differential Revision: https://phabricator.services.mozilla.com/D43430
--HG--
extra : moz-landing-system : lando
Copy the full contents of BlocksRingBuffer into another one.
This is mainly useful to use a temporary buffer to store some data without
contentions, and then integrate the temporary buffer into the main one.
Differential Revision: https://phabricator.services.mozilla.com/D45306
--HG--
extra : moz-landing-system : lando
Payloads will serialize themselves into a `BlocksRingBuffer` entry when first
captured.
Later they will be deserialized, to stream JSON for the output profile.
Differential Revision: https://phabricator.services.mozilla.com/D43428
--HG--
extra : moz-landing-system : lando
Add basic testing of `profiler_get_backtrace` before working on serializing it.
Differential Revision: https://phabricator.services.mozilla.com/D43424
--HG--
extra : moz-landing-system : lando
In some situations we will *need* to use a `BlocksRingBuffer` that absolutely
does not use a mutex -- In particular in the critical section of
`SamplerThread::Run()`, when a thread is suspended, because any action on any
mutex (even a private one that no-one else interacts with) can result in a hang.
As a bonus, `BlocksRingBuffer`s that are known not to be used in multi-thread
situations (e.g., backtraces, extracted stacks for duplication, etc.) will waste
less resources trying to lock/unlock their mutex.
Differential Revision: https://phabricator.services.mozilla.com/D45305
--HG--
extra : moz-landing-system : lando
Backtraces (that are kept in some marker payloads) are stored in a small
ProfileBuffer, we will need to store that data, which will happen to be inside
a BlockRingBuffer, so BlockRingBuffer needs to be able to (de)serialize itself!
This is done by storing the contents in the active buffer range, and some extra
data, to later reconstruct a BlocksRingBuffer that looks like the original.
Depends on D42496
Differential Revision: https://phabricator.services.mozilla.com/D42634
--HG--
extra : moz-landing-system : lando
Markers and their payloads contain all kinds of objects that we'll need to
serialize into a BlocksRingBuffer (new ProfileBuffer storage).
This patch will add functions to:
- Compute the size needed to store objects,
- Write multiple objects into a BlockRingBuffer entry,
- Read objects back from an entry.
And it will provide a number of useful de/serialization helpers for:
- Trivially-copyable objects,
- Strings of different types,
- Raw pointers (with some safety guards to avoid surprises),
- Tuples (to store multiple sub-objects),
- Spans,
- Maybe (for optional objects),
- Variant.
This should be enough to store most kinds of data. Further specializations
can&will be written as necessary for more complex or obscure types.
Differential Revision: https://phabricator.services.mozilla.com/D42496
--HG--
extra : moz-landing-system : lando
This allows its use in std algorithms and types that require a real iterator
(like `template <typename InputIt> std::string::string(InputIt, InputIt)`).
Differential Revision: https://phabricator.services.mozilla.com/D42452
--HG--
extra : moz-landing-system : lando
`Reader::At()` can be used to get a `BlockIterator` at a given `BlockIndex`,
clamped between `begin()` and `end()`.
This will be useful when we want to iterate starting at a given index, e.g.,
when duplicating stacks.
Differential Revision: https://phabricator.services.mozilla.com/D42449
--HG--
extra : moz-landing-system : lando