зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1588245 - Collect the assembly pattern of a target function on detour failure. r=mhowell
Many instances of the launcher failure ping indicate hooking NtMapViewOfSection or LdrLoadDll failed. This is most likely caused by a third-party application applying a hook onto the same target earlier than we do. This patch is to add a new field "detour_orig_bytes" in the laucnher failure ping to collect the first sixteen bytes of a detour target function. With this, we can know whether those detour failures were caused by a third-party hook or not, and if yes, what was the actual binary pattern. Differential Revision: https://phabricator.services.mozilla.com/D89836
This commit is contained in:
Родитель
355702c4f3
Коммит
b45fd9fde1
|
@ -70,13 +70,13 @@ static LauncherVoidResultWithLineInfo InitializeDllBlocklistOOPInternal(
|
||||||
aChildProcess, intcpt, "NtMapViewOfSection",
|
aChildProcess, intcpt, "NtMapViewOfSection",
|
||||||
&freestanding::patched_NtMapViewOfSection);
|
&freestanding::patched_NtMapViewOfSection);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return LAUNCHER_ERROR_GENERIC();
|
return LAUNCHER_ERROR_GENERIC_WITH_DETOUR_ERROR(intcpt.GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = freestanding::stub_LdrLoadDll.SetDetour(
|
ok = freestanding::stub_LdrLoadDll.SetDetour(
|
||||||
aChildProcess, intcpt, "LdrLoadDll", &freestanding::patched_LdrLoadDll);
|
aChildProcess, intcpt, "LdrLoadDll", &freestanding::patched_LdrLoadDll);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return LAUNCHER_ERROR_GENERIC();
|
return LAUNCHER_ERROR_GENERIC_WITH_DETOUR_ERROR(intcpt.GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Because aChildProcess has just been created in a suspended state, its
|
// Because aChildProcess has just been created in a suspended state, its
|
||||||
|
|
|
@ -579,6 +579,21 @@ static bool PrepPing(const PingThreadContext& aContext, const std::wstring& aId,
|
||||||
|
|
||||||
aJson.IntProperty("source_line", aContext.mLauncherError.mLine);
|
aJson.IntProperty("source_line", aContext.mLauncherError.mLine);
|
||||||
aJson.IntProperty("hresult", aContext.mLauncherError.mError.AsHResult());
|
aJson.IntProperty("hresult", aContext.mLauncherError.mError.AsHResult());
|
||||||
|
|
||||||
|
# if defined(NIGHTLY_BUILD)
|
||||||
|
if (aContext.mLauncherError.mDetourError.isSome()) {
|
||||||
|
static const char* kHexMap = "0123456789abcdef";
|
||||||
|
char hexStr[sizeof(mozilla::DetourError::mOrigBytes) * 2 + 1];
|
||||||
|
int cnt = 0;
|
||||||
|
for (uint8_t byte : aContext.mLauncherError.mDetourError->mOrigBytes) {
|
||||||
|
hexStr[cnt++] = kHexMap[(byte >> 4) & 0x0f];
|
||||||
|
hexStr[cnt++] = kHexMap[byte & 0x0f];
|
||||||
|
}
|
||||||
|
hexStr[cnt] = 0;
|
||||||
|
aJson.StringProperty("detour_orig_bytes", hexStr);
|
||||||
|
}
|
||||||
|
# endif // defined(NIGHTLY_BUILD)
|
||||||
|
|
||||||
aJson.EndObject();
|
aJson.EndObject();
|
||||||
|
|
||||||
# if !defined(__MINGW32__)
|
# if !defined(__MINGW32__)
|
||||||
|
|
|
@ -128,6 +128,10 @@ class WindowsDllDetourPatcher final
|
||||||
using PrimitiveT = WindowsDllDetourPatcherPrimitive<MMPolicyT>;
|
using PrimitiveT = WindowsDllDetourPatcherPrimitive<MMPolicyT>;
|
||||||
Maybe<DetourFlags> mFlags;
|
Maybe<DetourFlags> mFlags;
|
||||||
|
|
||||||
|
#if defined(NIGHTLY_BUILD)
|
||||||
|
Maybe<DetourError> mLastError;
|
||||||
|
#endif // defined(NIGHTLY_BUILD)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
explicit WindowsDllDetourPatcher(Args&&... aArgs)
|
explicit WindowsDllDetourPatcher(Args&&... aArgs)
|
||||||
|
@ -140,6 +144,10 @@ class WindowsDllDetourPatcher final
|
||||||
WindowsDllDetourPatcher& operator=(const WindowsDllDetourPatcher&) = delete;
|
WindowsDllDetourPatcher& operator=(const WindowsDllDetourPatcher&) = delete;
|
||||||
WindowsDllDetourPatcher& operator=(WindowsDllDetourPatcher&&) = delete;
|
WindowsDllDetourPatcher& operator=(WindowsDllDetourPatcher&&) = delete;
|
||||||
|
|
||||||
|
#if defined(NIGHTLY_BUILD)
|
||||||
|
const Maybe<DetourError>& GetLastError() const { return mLastError; }
|
||||||
|
#endif // defined(NIGHTLY_BUILD)
|
||||||
|
|
||||||
void Clear() {
|
void Clear() {
|
||||||
if (!this->mVMPolicy.ShouldUnhookUponDestruction()) {
|
if (!this->mVMPolicy.ShouldUnhookUponDestruction()) {
|
||||||
return;
|
return;
|
||||||
|
@ -898,17 +906,29 @@ class WindowsDllDetourPatcher final
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto clearInstanceOnFailure = MakeScopeExit([aOutTramp, &tramp]() -> void {
|
auto clearInstanceOnFailure = MakeScopeExit([this, aOutTramp, &tramp,
|
||||||
|
&origBytes]() -> void {
|
||||||
// *aOutTramp is not set until CreateTrampoline has completed
|
// *aOutTramp is not set until CreateTrampoline has completed
|
||||||
// successfully, so we can use that to check for success.
|
// successfully, so we can use that to check for success.
|
||||||
if (*aOutTramp) {
|
if (*aOutTramp) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the instance pointer so that we don't try to reset a nonexistent
|
// Clear the instance pointer so that we don't try to reset a
|
||||||
// hook.
|
// nonexistent hook.
|
||||||
tramp.Rewind();
|
tramp.Rewind();
|
||||||
tramp.WriteEncodedPointer(nullptr);
|
tramp.WriteEncodedPointer(nullptr);
|
||||||
|
|
||||||
|
#if defined(NIGHTLY_BUILD)
|
||||||
|
origBytes.Rewind();
|
||||||
|
mLastError = Some(DetourError());
|
||||||
|
size_t bytesToCapture = std::min(
|
||||||
|
ArrayLength(mLastError->mOrigBytes),
|
||||||
|
static_cast<size_t>(PrimitiveT::GetWorstCaseRequiredBytesToPatch()));
|
||||||
|
for (size_t i = 0; i < bytesToCapture; ++i) {
|
||||||
|
mLastError->mOrigBytes[i] = origBytes[i];
|
||||||
|
}
|
||||||
|
#endif // defined(NIGHTLY_BUILD)
|
||||||
});
|
});
|
||||||
|
|
||||||
tramp.WritePointer(origBytes.AsEncodedPtr());
|
tramp.WritePointer(origBytes.AsEncodedPtr());
|
||||||
|
|
|
@ -361,6 +361,12 @@ class WindowsDllInterceptor final
|
||||||
// NB: We intentionally leak mModule
|
// NB: We intentionally leak mModule
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(NIGHTLY_BUILD)
|
||||||
|
const Maybe<DetourError>& GetLastError() const {
|
||||||
|
return mDetourPatcher.GetLastError();
|
||||||
|
}
|
||||||
|
#endif // defined(NIGHTLY_BUILD)
|
||||||
|
|
||||||
constexpr static uint32_t GetWorstCaseRequiredBytesToPatch() {
|
constexpr static uint32_t GetWorstCaseRequiredBytesToPatch() {
|
||||||
return WindowsDllDetourPatcherPrimitive<
|
return WindowsDllDetourPatcherPrimitive<
|
||||||
typename VMPolicy::MMPolicyT>::GetWorstCaseRequiredBytesToPatch();
|
typename VMPolicy::MMPolicyT>::GetWorstCaseRequiredBytesToPatch();
|
||||||
|
|
|
@ -48,7 +48,10 @@ Structure:
|
||||||
// The line number of the source file where the error was raised
|
// The line number of the source file where the error was raised
|
||||||
"source_line": <int>,
|
"source_line": <int>,
|
||||||
// The HRESULT error code of the error that was raised
|
// The HRESULT error code of the error that was raised
|
||||||
"hresult": <int>
|
"hresult": <int>,
|
||||||
|
// First sixteen bytes of a function that we failed to hook (Nightly-only).
|
||||||
|
// This field is added only on detour failures.
|
||||||
|
"detour_orig_bytes": <string>
|
||||||
},
|
},
|
||||||
"security": {
|
"security": {
|
||||||
// A list of names of installed antivirus products
|
// A list of names of installed antivirus products
|
||||||
|
@ -87,6 +90,7 @@ Structure:
|
||||||
Version History
|
Version History
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
- Firefox 82: Added ``detour_orig_bytes`` (`bug 1588245 <https://bugzilla.mozilla.org/show_bug.cgi?id=1588245>`_).
|
||||||
- Firefox 82: Added ``process_type`` (`bug 1630444 <https://bugzilla.mozilla.org/show_bug.cgi?id=1630444>`_).
|
- Firefox 82: Added ``process_type`` (`bug 1630444 <https://bugzilla.mozilla.org/show_bug.cgi?id=1630444>`_).
|
||||||
- Firefox 71: Added ``is_admin_without_uac`` (`bug 1567605 <https://bugzilla.mozilla.org/show_bug.cgi?id=1567605>`_).
|
- Firefox 71: Added ``is_admin_without_uac`` (`bug 1567605 <https://bugzilla.mozilla.org/show_bug.cgi?id=1567605>`_).
|
||||||
- Firefox 67: Initial release (`bug 1460433 <https://bugzilla.mozilla.org/show_bug.cgi?id=1460433>`_).
|
- Firefox 67: Initial release (`bug 1460433 <https://bugzilla.mozilla.org/show_bug.cgi?id=1460433>`_).
|
||||||
|
|
|
@ -204,6 +204,15 @@ class WindowsError final {
|
||||||
HRESULT mHResult;
|
HRESULT mHResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(NIGHTLY_BUILD)
|
||||||
|
struct DetourError {
|
||||||
|
// We have a 16-bytes buffer, but only minimum bytes to detour per
|
||||||
|
// architecture are copied. See CreateTrampoline in PatcherDetour.h.
|
||||||
|
uint8_t mOrigBytes[16];
|
||||||
|
DetourError() : mOrigBytes{} {}
|
||||||
|
};
|
||||||
|
#endif // defined(NIGHTLY_BUILD)
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using WindowsErrorResult = Result<T, WindowsError>;
|
using WindowsErrorResult = Result<T, WindowsError>;
|
||||||
|
|
||||||
|
@ -211,9 +220,22 @@ struct LauncherError {
|
||||||
LauncherError(const char* aFile, int aLine, WindowsError aWin32Error)
|
LauncherError(const char* aFile, int aLine, WindowsError aWin32Error)
|
||||||
: mFile(aFile), mLine(aLine), mError(aWin32Error) {}
|
: mFile(aFile), mLine(aLine), mError(aWin32Error) {}
|
||||||
|
|
||||||
|
#if defined(NIGHTLY_BUILD)
|
||||||
|
template <typename... Args>
|
||||||
|
LauncherError(const char* aFile, int aLine, WindowsError aWin32Error,
|
||||||
|
const Maybe<DetourError>& aDetourError)
|
||||||
|
: mFile(aFile),
|
||||||
|
mLine(aLine),
|
||||||
|
mError(aWin32Error),
|
||||||
|
mDetourError(aDetourError) {}
|
||||||
|
#endif // defined(NIGHTLY_BUILD)
|
||||||
|
|
||||||
const char* mFile;
|
const char* mFile;
|
||||||
int mLine;
|
int mLine;
|
||||||
WindowsError mError;
|
WindowsError mError;
|
||||||
|
#if defined(NIGHTLY_BUILD)
|
||||||
|
Maybe<DetourError> mDetourError;
|
||||||
|
#endif // defined(NIGHTLY_BUILD)
|
||||||
|
|
||||||
bool operator==(const LauncherError& aOther) const {
|
bool operator==(const LauncherError& aOther) const {
|
||||||
return mError == aOther.mError;
|
return mError == aOther.mError;
|
||||||
|
@ -260,6 +282,16 @@ using LauncherVoidResultWithLineInfo = LauncherResultWithLineInfo<Ok>;
|
||||||
::mozilla::Err(::mozilla::LauncherError( \
|
::mozilla::Err(::mozilla::LauncherError( \
|
||||||
__FILE__, __LINE__, ::mozilla::WindowsError::CreateGeneric()))
|
__FILE__, __LINE__, ::mozilla::WindowsError::CreateGeneric()))
|
||||||
|
|
||||||
|
# if defined(NIGHTLY_BUILD)
|
||||||
|
# define LAUNCHER_ERROR_GENERIC_WITH_DETOUR_ERROR(...) \
|
||||||
|
::mozilla::Err(::mozilla::LauncherError( \
|
||||||
|
__FILE__, __LINE__, ::mozilla::WindowsError::CreateGeneric(), \
|
||||||
|
__VA_ARGS__))
|
||||||
|
# else
|
||||||
|
# define LAUNCHER_ERROR_GENERIC_WITH_DETOUR_ERROR(...) \
|
||||||
|
LAUNCHER_ERROR_GENERIC()
|
||||||
|
# endif // defined(NIGHTLY_BUILD)
|
||||||
|
|
||||||
# define LAUNCHER_ERROR_FROM_WIN32(err) \
|
# define LAUNCHER_ERROR_FROM_WIN32(err) \
|
||||||
::mozilla::Err(::mozilla::LauncherError( \
|
::mozilla::Err(::mozilla::LauncherError( \
|
||||||
__FILE__, __LINE__, ::mozilla::WindowsError::FromWin32Error(err)))
|
__FILE__, __LINE__, ::mozilla::WindowsError::FromWin32Error(err)))
|
||||||
|
@ -285,6 +317,8 @@ using LauncherVoidResultWithLineInfo = LauncherResultWithLineInfo<Ok>;
|
||||||
# define LAUNCHER_ERROR_GENERIC() \
|
# define LAUNCHER_ERROR_GENERIC() \
|
||||||
::mozilla::Err(::mozilla::WindowsError::CreateGeneric())
|
::mozilla::Err(::mozilla::WindowsError::CreateGeneric())
|
||||||
|
|
||||||
|
# define LAUNCHER_ERROR_GENERIC_WITH_DETOUR_ERROR(...) LAUNCHER_ERROR_GENERIC()
|
||||||
|
|
||||||
# define LAUNCHER_ERROR_FROM_WIN32(err) \
|
# define LAUNCHER_ERROR_FROM_WIN32(err) \
|
||||||
::mozilla::Err(::mozilla::WindowsError::FromWin32Error(err))
|
::mozilla::Err(::mozilla::WindowsError::FromWin32Error(err))
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче