From 09a107bc24cb812e5bcb0d2ea121a8707d7b89ba Mon Sep 17 00:00:00 2001 From: Gijs Kruitbosch Date: Fri, 22 Jun 2018 15:41:39 +0100 Subject: [PATCH 01/57] Bug 1469916, r=ckerschb,jkt --HG-- extra : rebase_source : 180442deeef92f0e9202d76c5e4e46b630072d99 extra : source : be11a32900298eb6fd4d18ad21b9a699995254c3 --- browser/base/content/nsContextMenu.js | 22 ++++- browser/base/content/pageinfo/pageInfo.js | 3 +- browser/base/content/utilityOverlay.js | 3 +- .../components/shell/nsMacShellService.cpp | 2 +- devtools/shared/gcli/commands/screenshot.js | 3 +- devtools/startup/devtools-startup.js | 22 ++++- dom/base/nsContentAreaDragDrop.cpp | 8 +- dom/base/nsContentAreaDragDrop.h | 1 + dom/tests/browser/browser.ini | 4 + dom/tests/browser/browser_persist_cookies.js | 94 +++++++++++++++++++ dom/tests/browser/mimeme.sjs | 26 +++++ .../set-samesite-cookies-and-redirect.sjs | 33 +++++++ .../PWebBrowserPersistDocument.ipdl | 2 + .../WebBrowserPersistDocumentChild.cpp | 5 + .../WebBrowserPersistLocalDocument.cpp | 8 ++ .../WebBrowserPersistRemoteDocument.cpp | 13 +++ .../WebBrowserPersistRemoteDocument.h | 3 + .../nsIWebBrowserPersist.idl | 15 ++- .../nsIWebBrowserPersistDocument.idl | 2 + dom/webbrowserpersist/nsWebBrowserPersist.cpp | 45 ++++----- dom/webbrowserpersist/nsWebBrowserPersist.h | 3 +- toolkit/components/browser/nsWebBrowser.cpp | 12 ++- .../components/downloads/test/unit/head.js | 3 +- .../viewsource/content/viewSourceUtils.js | 6 +- toolkit/content/contentAreaUtils.js | 28 ++++-- .../tests/browser/browser_saveImageURL.js | 3 +- .../extensions/LightweightThemeManager.jsm | 3 +- 27 files changed, 313 insertions(+), 59 deletions(-) create mode 100644 dom/tests/browser/browser_persist_cookies.js create mode 100644 dom/tests/browser/mimeme.sjs create mode 100644 dom/tests/browser/set-samesite-cookies-and-redirect.sjs diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 7cfe6224ac19..637cdc578e0b 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -995,12 +995,22 @@ nsContextMenu.prototype = { target: this.target, }); + // Cache this because we fetch the data async + let {documentURIObject} = gContextMenuContentData; + let onMessage = (message) => { mm.removeMessageListener("ContextMenu:SaveVideoFrameAsImage:Result", onMessage); + // FIXME can we switch this to a blob URL? let dataURL = message.data.dataURL; - saveImageURL(dataURL, name, "SaveImageTitle", true, false, - document.documentURIObject, null, null, null, - isPrivate); + saveImageURL(dataURL, name, "SaveImageTitle", + true, // bypass cache + false, // don't skip prompt for where to save + documentURIObject, // referrer + null, // document + null, // content type + null, // content disposition + isPrivate, + this.principal); }; mm.addMessageListener("ContextMenu:SaveVideoFrameAsImage:Result", onMessage); }, @@ -1238,13 +1248,15 @@ nsContextMenu.prototype = { this._canvasToBlobURL(this.target).then(function(blobURL) { saveImageURL(blobURL, "canvas.png", "SaveImageTitle", true, false, referrerURI, null, null, null, - isPrivate); + isPrivate, + document.nodePrincipal /* system, because blob: */); }, Cu.reportError); } else if (this.onImage) { urlSecurityCheck(this.mediaURL, this.principal); saveImageURL(this.mediaURL, null, "SaveImageTitle", false, false, referrerURI, null, gContextMenuContentData.contentType, - gContextMenuContentData.contentDisposition, isPrivate); + gContextMenuContentData.contentDisposition, isPrivate, + this.principal); } else if (this.onVideo || this.onAudio) { var dialogTitle = this.onVideo ? "SaveVideoTitle" : "SaveAudioTitle"; this.saveHelper(this.mediaURL, null, dialogTitle, false, doc, referrerURI, diff --git a/browser/base/content/pageinfo/pageInfo.js b/browser/base/content/pageinfo/pageInfo.js index 89811df0916b..bfe6f8664a29 100644 --- a/browser/base/content/pageinfo/pageInfo.js +++ b/browser/base/content/pageinfo/pageInfo.js @@ -689,7 +689,8 @@ function saveMedia() { var saveAnImage = function(aURIString, aChosenData, aBaseURI) { uniqueFile(aChosenData.file); internalSave(aURIString, null, null, null, null, false, "SaveImageTitle", - aChosenData, aBaseURI, null, false, null, gDocInfo.isContentWindowPrivate); + aChosenData, aBaseURI, null, false, null, + gDocInfo.isContentWindowPrivate, gDocInfo.principal); }; for (var i = 0; i < rowArray.length; i++) { diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js index e7a079325018..c67eaf52b131 100644 --- a/browser/base/content/utilityOverlay.js +++ b/browser/base/content/utilityOverlay.js @@ -305,7 +305,8 @@ function openLinkIn(url, where, params) { // ContentClick.jsm passes isContentWindowPrivate for saveURL instead of passing a CPOW initiatingDoc if ("isContentWindowPrivate" in params) { - saveURL(url, null, null, true, true, aNoReferrer ? null : aReferrerURI, null, params.isContentWindowPrivate); + saveURL(url, null, null, true, true, aNoReferrer ? null : aReferrerURI, + null, params.isContentWindowPrivate, aPrincipal); } else { if (!aInitiatingDoc) { Cu.reportError("openUILink/openLinkIn was called with " + diff --git a/browser/components/shell/nsMacShellService.cpp b/browser/components/shell/nsMacShellService.cpp index 30894acb3383..a3b19cfd6be1 100644 --- a/browser/components/shell/nsMacShellService.cpp +++ b/browser/components/shell/nsMacShellService.cpp @@ -153,7 +153,7 @@ nsMacShellService::SetDesktopBackground(Element* aElement, loadContext = do_QueryInterface(docShell); } - return wbp->SaveURI(imageURI, 0, + return wbp->SaveURI(imageURI, aElement->NodePrincipal(), 0, docURI, aElement->OwnerDoc()->GetReferrerPolicy(), nullptr, nullptr, mBackgroundFile, loadContext); diff --git a/devtools/shared/gcli/commands/screenshot.js b/devtools/shared/gcli/commands/screenshot.js index caacb73f98ee..2f7247721ebd 100644 --- a/devtools/shared/gcli/commands/screenshot.js +++ b/devtools/shared/gcli/commands/screenshot.js @@ -554,7 +554,6 @@ var saveToFile = Task.async(function* (context, reply) { // the downloads toolbar button when the save is done. const nsIWBP = Ci.nsIWebBrowserPersist; const flags = nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES | - nsIWBP.PERSIST_FLAGS_FORCE_ALLOW_COOKIES | nsIWBP.PERSIST_FLAGS_BYPASS_CACHE | nsIWBP.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION; const isPrivate = @@ -573,7 +572,9 @@ var saveToFile = Task.async(function* (context, reply) { isPrivate); const listener = new DownloadListener(window, tr); persist.progressListener = listener; + const principal = Services.scriptSecurityManager.getSystemPrincipal(); persist.savePrivacyAwareURI(sourceURI, + principal, 0, document.documentURIObject, Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, diff --git a/devtools/startup/devtools-startup.js b/devtools/startup/devtools-startup.js index 3fe555e79ca8..6787773014b2 100644 --- a/devtools/startup/devtools-startup.js +++ b/devtools/startup/devtools-startup.js @@ -40,6 +40,8 @@ ChromeUtils.defineModuleGetter(this, "CustomizableUI", "resource:///modules/CustomizableUI.jsm"); ChromeUtils.defineModuleGetter(this, "CustomizableWidgets", "resource:///modules/CustomizableWidgets.jsm"); +ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils", + "resource://gre/modules/PrivateBrowsingUtils.jsm"); // We don't want to spend time initializing the full loader here so we create // our own lazy require. @@ -948,16 +950,32 @@ const JsonView = { // Save original contents chrome.saveBrowser(browser); } else { + if (!message.data.startsWith("blob:null") || !browser.contentPrincipal.isNullPrincipal) { + Cu.reportError("Got invalid request to save JSON data"); + return; + } // The following code emulates saveBrowser, but: // - Uses the given blob URL containing the custom contents to save. // - Obtains the file name from the URL of the document, not the blob. + // - avoids passing the document and explicitly passes system principal. + // We have a blob created by a null principal to save, and the null + // principal is from the child. Null principals don't survive crossing + // over IPC, so there's no other principal that'll work. const persistable = browser.frameLoader; persistable.startPersistence(0, { onDocumentReady(doc) { const uri = chrome.makeURI(doc.documentURI, doc.characterSet); const filename = chrome.getDefaultFileName(undefined, uri, doc, null); - chrome.internalSave(message.data, doc, filename, null, doc.contentType, - false, null, null, null, doc, false, null, undefined); + chrome.internalSave(message.data, null, filename, null, doc.contentType, + false /* bypass cache */, + null, /* filepicker title key */ + null, /* file chosen */ + null, /* referrer */ + null, /* initiating document */ + false, /* don't skip prompt for a location */ + null, /* cache key */ + PrivateBrowsingUtils.isBrowserPrivate(browser), /* private browsing ? */ + Services.scriptSecurityManager.getSystemPrincipal()); }, onError(status) { throw new Error("JSON Viewer's onSave failed in startPersistence"); diff --git a/dom/base/nsContentAreaDragDrop.cpp b/dom/base/nsContentAreaDragDrop.cpp index abeb06b5e59d..57569528b816 100644 --- a/dom/base/nsContentAreaDragDrop.cpp +++ b/dom/base/nsContentAreaDragDrop.cpp @@ -141,6 +141,7 @@ NS_IMPL_ISUPPORTS(nsContentAreaDragDropDataProvider, nsIFlavorDataProvider) // into the file system nsresult nsContentAreaDragDropDataProvider::SaveURIToFile(nsIURI* inSourceURI, + nsIPrincipal* inTriggeringPrincipal, nsIFile* inDestFile, bool isPrivate) { @@ -162,7 +163,8 @@ nsContentAreaDragDropDataProvider::SaveURIToFile(nsIURI* inSourceURI, persist->SetPersistFlags(nsIWebBrowserPersist::PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION); // referrer policy can be anything since the referrer is nullptr - return persist->SavePrivacyAwareURI(inSourceURI, 0, nullptr, + return persist->SavePrivacyAwareURI(inSourceURI, + inTriggeringPrincipal, 0, nullptr, mozilla::net::RP_Unset, nullptr, nullptr, inDestFile, isPrivate); @@ -342,7 +344,9 @@ nsContentAreaDragDropDataProvider::GetFlavorData(nsITransferable *aTransferable, bool isPrivate; aTransferable->GetIsPrivateData(&isPrivate); - rv = SaveURIToFile(sourceURI, file, isPrivate); + nsCOMPtr principal; + aTransferable->GetRequestingPrincipal(getter_AddRefs(principal)); + rv = SaveURIToFile(sourceURI, principal, file, isPrivate); // send back an nsIFile if (NS_SUCCEEDED(rv)) { CallQueryInterface(file, aData); diff --git a/dom/base/nsContentAreaDragDrop.h b/dom/base/nsContentAreaDragDrop.h index df2d038625d1..272a80705f77 100644 --- a/dom/base/nsContentAreaDragDrop.h +++ b/dom/base/nsContentAreaDragDrop.h @@ -77,6 +77,7 @@ public: NS_DECL_NSIFLAVORDATAPROVIDER nsresult SaveURIToFile(nsIURI* inSourceURI, + nsIPrincipal* inTriggeringPrincipal, nsIFile* inDestFile, bool isPrivate); }; diff --git a/dom/tests/browser/browser.ini b/dom/tests/browser/browser.ini index a770fa1fa6a3..5c470cdc2339 100644 --- a/dom/tests/browser/browser.ini +++ b/dom/tests/browser/browser.ini @@ -57,6 +57,10 @@ skip-if = !e10s || (os == "win" && processor == "x86") || (verify && debug && (o [browser_localStorage_e10s.js] skip-if = !e10s || verify # This is a test of e10s functionality. [browser_localStorage_privatestorageevent.js] +[browser_persist_cookies.js] +support-files = + set-samesite-cookies-and-redirect.sjs + mimeme.sjs [browser_test_focus_after_modal_state.js] skip-if = verify support-files = diff --git a/dom/tests/browser/browser_persist_cookies.js b/dom/tests/browser/browser_persist_cookies.js new file mode 100644 index 000000000000..78f3966f3bbc --- /dev/null +++ b/dom/tests/browser/browser_persist_cookies.js @@ -0,0 +1,94 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const TEST_PATH = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.org"); +const TEST_PATH2 = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com"); + +var MockFilePicker = SpecialPowers.MockFilePicker; +MockFilePicker.init(window); + +registerCleanupFunction(async function() { + info("Running the cleanup code"); + MockFilePicker.cleanup(); + Services.obs.removeObserver(checkRequest, "http-on-modify-request"); + if (gTestDir && gTestDir.exists()) { + // On Windows, sometimes nsIFile.remove() throws, probably because we're + // still writing to the directory we're trying to remove, despite + // waiting for the download to complete. Just retry a bit later... + let succeeded = false; + while (!succeeded) { + try { + gTestDir.remove(true); + succeeded = true; + } catch (ex) { + await new Promise(requestAnimationFrame); + } + } + } +}); + +let gTestDir = null; + + +function checkRequest(subject) { + let httpChannel = subject.QueryInterface(Ci.nsIHttpChannel); + let spec = httpChannel.URI.spec; + // Ignore initial requests for page that sets cookies and its favicon, which may not have + // cookies. + if (httpChannel.URI.host == "example.org" && !spec.endsWith("favicon.ico") && !spec.includes("redirect.sjs")) { + let cookie = httpChannel.getRequestHeader("cookie"); + is(cookie.trim(), "normalCookie=true", "Should have correct cookie in request for " + spec); + } +} + +function createTemporarySaveDirectory() { + var saveDir = Services.dirsvc.get("TmpD", Ci.nsIFile); + saveDir.append("testsavedir"); + if (!saveDir.exists()) { + info("create testsavedir!"); + saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755); + } + info("return from createTempSaveDir: " + saveDir.path); + return saveDir; +} + +add_task(async function() { + await BrowserTestUtils.withNewTab("about:blank", async function(browser) { + Services.obs.addObserver(checkRequest, "http-on-modify-request"); + BrowserTestUtils.loadURI(browser, TEST_PATH + "set-samesite-cookies-and-redirect.sjs"); + // Test that the original document load doesn't send same-site cookies. + await BrowserTestUtils.browserLoaded(browser, true, TEST_PATH2 + "set-samesite-cookies-and-redirect.sjs"); + // Now check the saved page. + // Create the folder the link will be saved into. + gTestDir = createTemporarySaveDirectory(); + let destFile = gTestDir.clone(); + + MockFilePicker.displayDirectory = gTestDir; + let fileName; + MockFilePicker.showCallback = function(fp) { + info("showCallback"); + fileName = fp.defaultString; + info("fileName: " + fileName); + destFile.append(fileName); + info("path: " + destFile.path); + MockFilePicker.setFiles([destFile]); + MockFilePicker.filterIndex = 0; // kSaveAsType_Complete + info("done showCallback"); + }; + saveBrowser(browser); + await new Promise(async (resolve) => { + let dls = await Downloads.getList(Downloads.PUBLIC); + dls.addView({ + onDownloadChanged(download) { + if (download.succeeded) { + dls.removeView(this); + dls.removeFinished(); + resolve(); + } + } + }); + }); + }); +}); diff --git a/dom/tests/browser/mimeme.sjs b/dom/tests/browser/mimeme.sjs new file mode 100644 index 000000000000..9b92548f041d --- /dev/null +++ b/dom/tests/browser/mimeme.sjs @@ -0,0 +1,26 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +function handleRequest(request, response) { + let mimeType = request.queryString.match(/type=([a-z]*)/)[1]; + switch (mimeType) { + case "css": + response.setHeader("Content-Type", "text/css"); + response.write("#hi {color: red}"); + break; + case "js": + response.setHeader("Content-Type", "application/javascript"); + response.write("var foo;"); + break; + case "png": + response.setHeader("Content-Type", "image/png"); + response.write(""); + break; + case "html": + response.setHeader("Content-Type", "text/html"); + response.write("I am a subframe"); + break; + } +} diff --git a/dom/tests/browser/set-samesite-cookies-and-redirect.sjs b/dom/tests/browser/set-samesite-cookies-and-redirect.sjs new file mode 100644 index 000000000000..74a494db9dbc --- /dev/null +++ b/dom/tests/browser/set-samesite-cookies-and-redirect.sjs @@ -0,0 +1,33 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +function handleRequest(request, response) { + // Set cookies and redirect for .org: + if (request.host.endsWith(".org")) { + response.setHeader("Set-Cookie", "normalCookie=true; path=/;", true); + response.setHeader("Set-Cookie", "laxHeader=true; path=/; SameSite=Lax", true); + response.setHeader("Set-Cookie", "strictHeader=true; path=/; SameSite=Strict", true); + response.write(` + + + + + + + `); + } else { + let baseURI = "https://example.org/" + request.path.replace(/[a-z-]*\.sjs/, "mimeme.sjs?type="); + response.write(` + + + + + `); + } +} diff --git a/dom/webbrowserpersist/PWebBrowserPersistDocument.ipdl b/dom/webbrowserpersist/PWebBrowserPersistDocument.ipdl index ad6332763e68..7c2fc64c53d2 100644 --- a/dom/webbrowserpersist/PWebBrowserPersistDocument.ipdl +++ b/dom/webbrowserpersist/PWebBrowserPersistDocument.ipdl @@ -10,6 +10,7 @@ include protocol PFileDescriptorSet; include protocol PChildToParentStream; //FIXME: bug #792908 include protocol PParentToChildStream; //FIXME: bug #792908 +include PBackgroundSharedTypes; include IPCStream; namespace mozilla { @@ -29,6 +30,7 @@ struct WebBrowserPersistDocumentAttrs { nsString contentDisposition; uint32_t cacheKey; uint32_t persistFlags; + PrincipalInfo principal; }; // IPDL doesn't have tuples, so this gives the pair of strings from diff --git a/dom/webbrowserpersist/WebBrowserPersistDocumentChild.cpp b/dom/webbrowserpersist/WebBrowserPersistDocumentChild.cpp index 4a8e31b6f4eb..7b893d145f7a 100644 --- a/dom/webbrowserpersist/WebBrowserPersistDocumentChild.cpp +++ b/dom/webbrowserpersist/WebBrowserPersistDocumentChild.cpp @@ -41,6 +41,7 @@ WebBrowserPersistDocumentChild::Start(nsIWebBrowserPersistDocument* aDocument) return; } + nsCOMPtr principal; WebBrowserPersistDocumentAttrs attrs; nsCOMPtr postDataStream; #define ENSURE(e) do { \ @@ -60,6 +61,10 @@ WebBrowserPersistDocumentChild::Start(nsIWebBrowserPersistDocument* aDocument) ENSURE(aDocument->GetContentDisposition(attrs.contentDisposition())); ENSURE(aDocument->GetCacheKey(&(attrs.cacheKey()))); ENSURE(aDocument->GetPersistFlags(&(attrs.persistFlags()))); + + ENSURE(aDocument->GetPrincipal(getter_AddRefs(principal))); + ENSURE(ipc::PrincipalToPrincipalInfo(principal, &(attrs.principal()))); + ENSURE(aDocument->GetPostData(getter_AddRefs(postDataStream))); #undef ENSURE diff --git a/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp b/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp index 2027151e1d06..3a0be5bf444b 100644 --- a/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp +++ b/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp @@ -184,6 +184,14 @@ WebBrowserPersistLocalDocument::GetPostData(nsIInputStream** aStream) return history->GetPostData(aStream); } +NS_IMETHODIMP +WebBrowserPersistLocalDocument::GetPrincipal(nsIPrincipal** aPrincipal) +{ + nsCOMPtr nodePrincipal = mDocument->NodePrincipal(); + nodePrincipal.forget(aPrincipal); + return NS_OK; +} + already_AddRefed WebBrowserPersistLocalDocument::GetHistory() { diff --git a/dom/webbrowserpersist/WebBrowserPersistRemoteDocument.cpp b/dom/webbrowserpersist/WebBrowserPersistRemoteDocument.cpp index 9ea3204c1278..70ed305a4c5e 100644 --- a/dom/webbrowserpersist/WebBrowserPersistRemoteDocument.cpp +++ b/dom/webbrowserpersist/WebBrowserPersistRemoteDocument.cpp @@ -9,6 +9,9 @@ #include "WebBrowserPersistResourcesParent.h" #include "WebBrowserPersistSerializeParent.h" #include "mozilla/Unused.h" +#include "mozilla/ipc/BackgroundUtils.h" + +#include "nsIPrincipal.h" namespace mozilla { @@ -23,6 +26,8 @@ WebBrowserPersistRemoteDocument , mAttrs(aAttrs) , mPostData(aPostData) { + nsresult rv; + mPrincipal = ipc::PrincipalInfoToPrincipal(mAttrs.principal(), &rv); } WebBrowserPersistRemoteDocument::~WebBrowserPersistRemoteDocument() @@ -132,6 +137,14 @@ WebBrowserPersistRemoteDocument::GetPostData(nsIInputStream** aStream) return NS_OK; } +NS_IMETHODIMP +WebBrowserPersistRemoteDocument::GetPrincipal(nsIPrincipal** aPrincipal) +{ + nsCOMPtr nodePrincipal = mPrincipal; + nodePrincipal.forget(aPrincipal); + return NS_OK; +} + NS_IMETHODIMP WebBrowserPersistRemoteDocument::ReadResources(nsIWebBrowserPersistResourceVisitor* aVisitor) { diff --git a/dom/webbrowserpersist/WebBrowserPersistRemoteDocument.h b/dom/webbrowserpersist/WebBrowserPersistRemoteDocument.h index 08d435903843..2808ac4b53c0 100644 --- a/dom/webbrowserpersist/WebBrowserPersistRemoteDocument.h +++ b/dom/webbrowserpersist/WebBrowserPersistRemoteDocument.h @@ -13,6 +13,8 @@ #include "nsIWebBrowserPersistDocument.h" #include "nsIInputStream.h" +class nsIPrincipal; + // This class is the XPCOM half of the glue between the // nsIWebBrowserPersistDocument interface and a remote document; it is // created by WebBrowserPersistDocumentParent when (and if) it @@ -40,6 +42,7 @@ private: WebBrowserPersistDocumentParent* mActor; Attrs mAttrs; nsCOMPtr mPostData; + nsCOMPtr mPrincipal; friend class WebBrowserPersistDocumentParent; WebBrowserPersistRemoteDocument(WebBrowserPersistDocumentParent* aActor, diff --git a/dom/webbrowserpersist/nsIWebBrowserPersist.idl b/dom/webbrowserpersist/nsIWebBrowserPersist.idl index ad923ebb1d50..3b3e4adcc065 100644 --- a/dom/webbrowserpersist/nsIWebBrowserPersist.idl +++ b/dom/webbrowserpersist/nsIWebBrowserPersist.idl @@ -12,6 +12,7 @@ interface nsIWebProgressListener; interface nsIFile; interface nsIChannel; interface nsILoadContext; +interface nsIPrincipal; /** * Interface for persisting DOM documents and URIs to local or remote storage. @@ -65,12 +66,6 @@ interface nsIWebBrowserPersist : nsICancelable */ const unsigned long PERSIST_FLAGS_APPEND_TO_FILE = 32768; - /** - * Force relevant cookies to be sent with this load even if normally they - * wouldn't be. - */ - const unsigned long PERSIST_FLAGS_FORCE_ALLOW_COOKIES = 65536; - /** * Flags governing how data is fetched and saved from the network. * It is best to set this value explicitly unless you are prepared @@ -116,6 +111,8 @@ interface nsIWebBrowserPersist : nsICancelable * @param aURI URI to save to file. Some implementations of this interface * may also support nullptr to imply the currently * loaded URI. + * @param aTriggeringPrincipal + * The triggering principal for the URI we're saving. * @param aCacheKey The necko cache key integer. * @param aReferrer The referrer URI to pass with an HTTP request or * nullptr. @@ -142,7 +139,8 @@ interface nsIWebBrowserPersist : nsICancelable * * @throws NS_ERROR_INVALID_ARG One or more arguments was invalid. */ - void saveURI(in nsIURI aURI, in unsigned long aCacheKey, + void saveURI(in nsIURI aURI, in nsIPrincipal aTriggeringPrincipal, + in unsigned long aCacheKey, in nsIURI aReferrer, in unsigned long aReferrerPolicy, in nsIInputStream aPostData, in string aExtraHeaders, in nsISupports aFile, @@ -154,7 +152,8 @@ interface nsIWebBrowserPersist : nsICancelable * of intermediate data, etc.) * @see saveURI for all other parameter descriptions */ - void savePrivacyAwareURI(in nsIURI aURI, in unsigned long aCacheKey, + void savePrivacyAwareURI(in nsIURI aURI, + in nsIPrincipal aTriggeringPrincipal, in unsigned long aCacheKey, in nsIURI aReferrer, in unsigned long aReferrerPolicy, in nsIInputStream aPostData, in string aExtraHeaders, in nsISupports aFile, diff --git a/dom/webbrowserpersist/nsIWebBrowserPersistDocument.idl b/dom/webbrowserpersist/nsIWebBrowserPersistDocument.idl index d497218cc4af..a6777f6d0f1e 100644 --- a/dom/webbrowserpersist/nsIWebBrowserPersistDocument.idl +++ b/dom/webbrowserpersist/nsIWebBrowserPersistDocument.idl @@ -8,6 +8,7 @@ interface nsIInputStream; interface nsIOutputStream; +interface nsIPrincipal; interface nsITabParent; interface nsIWebBrowserPersistResourceVisitor; interface nsIWebBrowserPersistWriteCompletion; @@ -60,6 +61,7 @@ interface nsIWebBrowserPersistDocument : nsISupports readonly attribute AString referrer; readonly attribute AString contentDisposition; readonly attribute nsIInputStream postData; + readonly attribute nsIPrincipal principal; /** * The cache key. Unlike in nsISHEntry, where it's wrapped in an diff --git a/dom/webbrowserpersist/nsWebBrowserPersist.cpp b/dom/webbrowserpersist/nsWebBrowserPersist.cpp index 5dbdbdc5b022..12229ae3b274 100644 --- a/dom/webbrowserpersist/nsWebBrowserPersist.cpp +++ b/dom/webbrowserpersist/nsWebBrowserPersist.cpp @@ -83,6 +83,7 @@ struct nsWebBrowserPersist::DocData nsCOMPtr mBaseURI; nsCOMPtr mDocument; nsCOMPtr mFile; + nsCOMPtr mPrincipal; nsCString mCharset; }; @@ -413,18 +414,20 @@ NS_IMETHODIMP nsWebBrowserPersist::SetProgressListener( } NS_IMETHODIMP nsWebBrowserPersist::SaveURI( - nsIURI *aURI, uint32_t aCacheKey, + nsIURI *aURI, nsIPrincipal *aPrincipal, uint32_t aCacheKey, nsIURI *aReferrer, uint32_t aReferrerPolicy, nsIInputStream *aPostData, const char *aExtraHeaders, nsISupports *aFile, nsILoadContext* aPrivacyContext) { - return SavePrivacyAwareURI(aURI, aCacheKey, aReferrer, aReferrerPolicy, - aPostData, aExtraHeaders, aFile, - aPrivacyContext && aPrivacyContext->UsePrivateBrowsing()); + bool isPrivate = + aPrivacyContext && aPrivacyContext->UsePrivateBrowsing(); + return SavePrivacyAwareURI(aURI, aPrincipal, aCacheKey, + aReferrer, aReferrerPolicy, + aPostData, aExtraHeaders, aFile, isPrivate); } NS_IMETHODIMP nsWebBrowserPersist::SavePrivacyAwareURI( - nsIURI *aURI, uint32_t aCacheKey, + nsIURI *aURI, nsIPrincipal *aPrincipal, uint32_t aCacheKey, nsIURI *aReferrer, uint32_t aReferrerPolicy, nsIInputStream *aPostData, const char *aExtraHeaders, nsISupports *aFile, bool aIsPrivate) @@ -439,8 +442,10 @@ NS_IMETHODIMP nsWebBrowserPersist::SavePrivacyAwareURI( // SaveURI doesn't like broken uris. mPersistFlags |= PERSIST_FLAGS_FAIL_ON_BROKEN_LINKS; - rv = SaveURIInternal(aURI, aCacheKey, aReferrer, aReferrerPolicy, - aPostData, aExtraHeaders, fileAsURI, false, aIsPrivate); + rv = SaveURIInternal(aURI, aPrincipal, aCacheKey, + aReferrer, aReferrerPolicy, + aPostData, aExtraHeaders, fileAsURI, + false, aIsPrivate); return NS_FAILED(rv) ? rv : NS_OK; } @@ -599,6 +604,13 @@ nsWebBrowserPersist::SerializeNextFile() } if (urisToPersist > 0) { + nsCOMPtr docPrincipal; + //XXXgijs I *think* this is already always true, but let's be sure. + MOZ_ASSERT(mDocList.Length() > 0, + "Should have the document for any walked URIs to persist!"); + nsresult rv = mDocList.ElementAt(0)->mDocument-> + GetPrincipal(getter_AddRefs(docPrincipal)); + NS_ENSURE_SUCCESS_VOID(rv); // Persist each file in the uri map. The document(s) // will be saved after the last one of these is saved. for (auto iter = mURIMap.Iter(); !iter.Done(); iter.Next()) { @@ -608,8 +620,6 @@ nsWebBrowserPersist::SerializeNextFile() continue; } - nsresult rv; - // Create a URI from the key. nsCOMPtr uri; rv = NS_NewURI(getter_AddRefs(uri), iter.Key(), @@ -627,7 +637,7 @@ nsWebBrowserPersist::SerializeNextFile() // The Referrer Policy doesn't matter here since the referrer is // nullptr. - rv = SaveURIInternal(uri, 0, nullptr, + rv = SaveURIInternal(uri, docPrincipal, 0, nullptr, mozilla::net::RP_Unset, nullptr, nullptr, fileAsURI, true, mIsPrivate); // If SaveURIInternal fails, then it will have called EndDownload, @@ -1324,7 +1334,8 @@ nsWebBrowserPersist::AppendPathToURI(nsIURI *aURI, const nsAString & aPath, nsCO } nsresult nsWebBrowserPersist::SaveURIInternal( - nsIURI *aURI, uint32_t aCacheKey, nsIURI *aReferrer, + nsIURI *aURI, nsIPrincipal* aTriggeringPrincipal, + uint32_t aCacheKey, nsIURI *aReferrer, uint32_t aReferrerPolicy, nsIInputStream *aPostData, const char *aExtraHeaders, nsIURI *aFile, bool aCalcFileExt, bool aIsPrivate) @@ -1350,7 +1361,7 @@ nsresult nsWebBrowserPersist::SaveURIInternal( nsCOMPtr inputChannel; rv = NS_NewChannel(getter_AddRefs(inputChannel), aURI, - nsContentUtils::GetSystemPrincipal(), + aTriggeringPrincipal, nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, nsIContentPolicy::TYPE_OTHER, nullptr, // aPerformanceStorage @@ -1380,16 +1391,6 @@ nsresult nsWebBrowserPersist::SaveURIInternal( } } - if (mPersistFlags & PERSIST_FLAGS_FORCE_ALLOW_COOKIES) - { - nsCOMPtr httpChannelInternal = - do_QueryInterface(inputChannel); - if (httpChannelInternal) { - rv = httpChannelInternal->SetThirdPartyFlags(nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - } - } - // Set the referrer, post data and headers if any nsCOMPtr httpChannel(do_QueryInterface(inputChannel)); if (httpChannel) diff --git a/dom/webbrowserpersist/nsWebBrowserPersist.h b/dom/webbrowserpersist/nsWebBrowserPersist.h index 209363f3efde..24932fa149ea 100644 --- a/dom/webbrowserpersist/nsWebBrowserPersist.h +++ b/dom/webbrowserpersist/nsWebBrowserPersist.h @@ -57,7 +57,8 @@ public: private: virtual ~nsWebBrowserPersist(); nsresult SaveURIInternal( - nsIURI *aURI, uint32_t aCacheKey, nsIURI *aReferrer, + nsIURI *aURI, nsIPrincipal* aTriggeringPrincipal, + uint32_t aCacheKey, nsIURI *aReferrer, uint32_t aReferrerPolicy, nsIInputStream *aPostData, const char *aExtraHeaders, nsIURI *aFile, bool aCalcFileExt, bool aIsPrivate); diff --git a/toolkit/components/browser/nsWebBrowser.cpp b/toolkit/components/browser/nsWebBrowser.cpp index 4485afd5ce1d..dbc34f380a24 100644 --- a/toolkit/components/browser/nsWebBrowser.cpp +++ b/toolkit/components/browser/nsWebBrowser.cpp @@ -986,6 +986,7 @@ nsWebBrowser::SetProgressListener(nsIWebProgressListener* aProgressListener) NS_IMETHODIMP nsWebBrowser::SaveURI(nsIURI* aURI, + nsIPrincipal* aPrincipal, uint32_t aCacheKey, nsIURI* aReferrer, uint32_t aReferrerPolicy, @@ -995,12 +996,14 @@ nsWebBrowser::SaveURI(nsIURI* aURI, nsILoadContext* aPrivacyContext) { return SavePrivacyAwareURI( - aURI, aCacheKey, aReferrer, aReferrerPolicy, aPostData, aExtraHeaders, - aFile, aPrivacyContext && aPrivacyContext->UsePrivateBrowsing()); + aURI, aPrincipal, aCacheKey, aReferrer, aReferrerPolicy, aPostData, + aExtraHeaders, aFile, + aPrivacyContext && aPrivacyContext->UsePrivateBrowsing()); } NS_IMETHODIMP nsWebBrowser::SavePrivacyAwareURI(nsIURI* aURI, + nsIPrincipal* aPrincipal, uint32_t aCacheKey, nsIURI* aReferrer, uint32_t aReferrerPolicy, @@ -1038,8 +1041,9 @@ nsWebBrowser::SavePrivacyAwareURI(nsIURI* aURI, mPersist->SetPersistFlags(mPersistFlags); mPersist->GetCurrentState(&mPersistCurrentState); - rv = mPersist->SavePrivacyAwareURI(uri, aCacheKey, aReferrer, aReferrerPolicy, - aPostData, aExtraHeaders, aFile, aIsPrivate); + rv = mPersist->SavePrivacyAwareURI(uri, aPrincipal, aCacheKey, + aReferrer, aReferrerPolicy, aPostData, + aExtraHeaders, aFile, aIsPrivate); if (NS_FAILED(rv)) { mPersist = nullptr; } diff --git a/toolkit/components/downloads/test/unit/head.js b/toolkit/components/downloads/test/unit/head.js index 69380c1ba686..1ee8a9ffb566 100644 --- a/toolkit/components/downloads/test/unit/head.js +++ b/toolkit/components/downloads/test/unit/head.js @@ -283,7 +283,8 @@ function promiseStartLegacyDownload(aSourceUrl, aOptions) { // Start the actual download process. persist.savePrivacyAwareURI( - sourceURI, 0, referrer, Ci.nsIHttpChannel.REFERRER_POLICY_UNSAFE_URL, + sourceURI, Services.scriptSecurityManager.getSystemPrincipal(), + 0, referrer, Ci.nsIHttpChannel.REFERRER_POLICY_UNSAFE_URL, null, null, targetFile, isPrivate); }).catch(do_report_unexpected_exception); diff --git a/toolkit/components/viewsource/content/viewSourceUtils.js b/toolkit/components/viewsource/content/viewSourceUtils.js index 1a73f97f3250..68728f72c280 100644 --- a/toolkit/components/viewsource/content/viewSourceUtils.js +++ b/toolkit/components/viewsource/content/viewSourceUtils.js @@ -226,7 +226,11 @@ var gViewSourceUtils = { webBrowserPersist.persistFlags = this.mnsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES; webBrowserPersist.progressListener = this.viewSourceProgressListener; let referrerPolicy = Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER; - webBrowserPersist.savePrivacyAwareURI(uri, null, null, referrerPolicy, null, null, file, data.isPrivate); + let ssm = Services.scriptSecurityManager; + let principal = ssm.createCodebasePrincipal(data.uri, + browser.contentPrincipal.originAttributes); + webBrowserPersist.savePrivacyAwareURI(uri, principal, null, null, + referrerPolicy, null, null, file, data.isPrivate); let helperService = Cc["@mozilla.org/uriloader/external-helper-app-service;1"] .getService(Ci.nsPIExternalAppLauncher); diff --git a/toolkit/content/contentAreaUtils.js b/toolkit/content/contentAreaUtils.js index dc758c89731e..0324e743fa7d 100644 --- a/toolkit/content/contentAreaUtils.js +++ b/toolkit/content/contentAreaUtils.js @@ -62,14 +62,15 @@ function forbidCPOW(arg, func, argname) { // - A linked document using Alt-click Save Link As... // function saveURL(aURL, aFileName, aFilePickerTitleKey, aShouldBypassCache, - aSkipPrompt, aReferrer, aSourceDocument, aIsContentWindowPrivate) { + aSkipPrompt, aReferrer, aSourceDocument, + aIsContentWindowPrivate, aPrincipal) { forbidCPOW(aURL, "saveURL", "aURL"); forbidCPOW(aReferrer, "saveURL", "aReferrer"); // Allow aSourceDocument to be a CPOW. internalSave(aURL, null, aFileName, null, null, aShouldBypassCache, aFilePickerTitleKey, null, aReferrer, aSourceDocument, - aSkipPrompt, null, aIsContentWindowPrivate); + aSkipPrompt, null, aIsContentWindowPrivate, aPrincipal); } // Just like saveURL, but will get some info off the image before @@ -112,7 +113,7 @@ const nsISupportsCString = Ci.nsISupportsCString; */ function saveImageURL(aURL, aFileName, aFilePickerTitleKey, aShouldBypassCache, aSkipPrompt, aReferrer, aDoc, aContentType, aContentDisp, - aIsContentWindowPrivate) { + aIsContentWindowPrivate, aPrincipal) { forbidCPOW(aURL, "saveImageURL", "aURL"); forbidCPOW(aReferrer, "saveImageURL", "aReferrer"); @@ -156,7 +157,7 @@ function saveImageURL(aURL, aFileName, aFilePickerTitleKey, aShouldBypassCache, internalSave(aURL, null, aFileName, aContentDisp, aContentType, aShouldBypassCache, aFilePickerTitleKey, null, aReferrer, - null, aSkipPrompt, null, aIsContentWindowPrivate); + aDoc, aSkipPrompt, null, aIsContentWindowPrivate, aPrincipal); } // This is like saveDocument, but takes any browser/frame-like element @@ -331,11 +332,15 @@ XPCOMUtils.defineConstant(this, "kSaveAsType_Text", kSaveAsType_Text); * This parameter is provided when the aInitiatingDocument is not a * real document object. Stores whether aInitiatingDocument.defaultView * was private or not. + * @param aPrincipal [optional] + * This parameter is provided when neither aDocument nor + * aInitiatingDocument is provided. Used to determine what level of + * privilege to load the URI with. */ function internalSave(aURL, aDocument, aDefaultFileName, aContentDisposition, aContentType, aShouldBypassCache, aFilePickerTitleKey, aChosenData, aReferrer, aInitiatingDocument, aSkipPrompt, - aCacheKey, aIsContentWindowPrivate) { + aCacheKey, aIsContentWindowPrivate, aPrincipal) { forbidCPOW(aURL, "internalSave", "aURL"); forbidCPOW(aReferrer, "internalSave", "aReferrer"); forbidCPOW(aCacheKey, "internalSave", "aCacheKey"); @@ -411,8 +416,17 @@ function internalSave(aURL, aDocument, aDefaultFileName, aContentDisposition, : aInitiatingDocument.isPrivate; } + // We have to cover the cases here where we were either passed an explicit + // principal, or a 'real' document (with a nodePrincipal property), or an + // nsIWebBrowserPersistDocument which has a principal property. + let sourcePrincipal = + aPrincipal || + (aDocument && (aDocument.nodePrincipal || aDocument.principal)) || + (aInitiatingDocument && aInitiatingDocument.nodePrincipal); + var persistArgs = { sourceURI, + sourcePrincipal, sourceReferrer: aReferrer, sourceDocument: useSaveDocument ? aDocument : null, targetContentType: (saveAsType == kSaveAsType_Text) ? "text/plain" : null, @@ -463,8 +477,7 @@ function internalPersist(persistArgs) { // Calculate persist flags. const nsIWBP = Ci.nsIWebBrowserPersist; - const flags = nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES | - nsIWBP.PERSIST_FLAGS_FORCE_ALLOW_COOKIES; + const flags = nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES; if (persistArgs.bypassCache) persist.persistFlags = flags | nsIWBP.PERSIST_FLAGS_BYPASS_CACHE; else @@ -511,6 +524,7 @@ function internalPersist(persistArgs) { persistArgs.targetContentType, encodingFlags, kWrapColumn); } else { persist.savePrivacyAwareURI(persistArgs.sourceURI, + persistArgs.sourcePrincipal, persistArgs.sourceCacheKey, persistArgs.sourceReferrer, Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, diff --git a/toolkit/content/tests/browser/browser_saveImageURL.js b/toolkit/content/tests/browser/browser_saveImageURL.js index 4250b4d19ba8..7841cbaac08f 100644 --- a/toolkit/content/tests/browser/browser_saveImageURL.js +++ b/toolkit/content/tests/browser/browser_saveImageURL.js @@ -36,7 +36,8 @@ add_task(async function preferred_API() { return image.href; }); - saveImageURL(url, "image.jpg", null, true, false, null, null, null, null, false); + saveImageURL(url, "image.jpg", null, true, false, null, null, null, null, + false, gBrowser.contentPrincipal); let channel = gBrowser.contentDocumentAsCPOW.docShell.currentDocumentChannel; if (channel) { ok(true, channel.QueryInterface(Ci.nsIHttpChannelInternal) diff --git a/toolkit/mozapps/extensions/LightweightThemeManager.jsm b/toolkit/mozapps/extensions/LightweightThemeManager.jsm index 5bef89db59e8..3f5479c68e4a 100644 --- a/toolkit/mozapps/extensions/LightweightThemeManager.jsm +++ b/toolkit/mozapps/extensions/LightweightThemeManager.jsm @@ -971,7 +971,8 @@ function _persistImage(sourceURL, localFileName, successCallback) { persist.progressListener = new _persistProgressListener(successCallback); - persist.saveURI(sourceURI, 0, + let sourcePrincipal = Services.scriptSecurityManager.createCodebasePrincipal(sourceURI, {}); + persist.saveURI(sourceURI, sourcePrincipal, 0, null, Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, null, null, targetURI, null); } From 7f6794045e1f91cd16662b9920ee4c400818e4aa Mon Sep 17 00:00:00 2001 From: Bas Schouten Date: Tue, 3 Jul 2018 20:26:40 +0000 Subject: [PATCH 02/57] Bug 1472830: Reuse the work from ApplyOpacityToChildren when possible. r=mattwoodrow --- .../painting/RetainedDisplayListBuilder.cpp | 2 ++ layout/painting/nsDisplayList.cpp | 13 +++++--- layout/painting/nsDisplayList.h | 31 +++++++++++++++---- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/layout/painting/RetainedDisplayListBuilder.cpp b/layout/painting/RetainedDisplayListBuilder.cpp index 96aa5d1ab880..33dc1202570f 100644 --- a/layout/painting/RetainedDisplayListBuilder.cpp +++ b/layout/painting/RetainedDisplayListBuilder.cpp @@ -297,6 +297,7 @@ public: aNewItem->GetChildren(), containerASRForChildren, aNewItem->GetPerFrameKey())) { + aNewItem->InvalidateCachedChildInfo(); mResultIsModified = true; } @@ -401,6 +402,7 @@ public: nsDisplayList empty; if (mBuilder->MergeDisplayLists(&empty, item->GetChildren(), item->GetChildren(), containerASRForChildren, item->GetPerFrameKey())) { + item->InvalidateCachedChildInfo(); mResultIsModified = true; } UpdateASR(item, containerASRForChildren); diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index 628c0a0a825c..18f7f46d72bd 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -6241,7 +6241,7 @@ nsDisplayOpacity::nsDisplayOpacity(nsDisplayListBuilder* aBuilder, : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, true) , mOpacity(aFrame->StyleEffects()->mOpacity) , mForEventsAndPluginsOnly(aForEventsAndPluginsOnly) - , mOpacityAppliedToChildren(false) + , mChildOpacityState(ChildOpacityState::Unknown) { MOZ_COUNT_CTOR(nsDisplayOpacity); mState.mOpacity = mOpacity; @@ -6378,6 +6378,10 @@ CollectItemsWithOpacity(nsDisplayList* aList, bool nsDisplayOpacity::ApplyOpacityToChildren(nsDisplayListBuilder* aBuilder) { + if (mChildOpacityState == ChildOpacityState::Deferred) { + return false; + } + // Only try folding our opacity down if we have at most kMaxChildCount // children that don't overlap and can all apply the opacity to themselves. static const size_t kMaxChildCount = 3; @@ -6386,6 +6390,7 @@ nsDisplayOpacity::ApplyOpacityToChildren(nsDisplayListBuilder* aBuilder) // child display item pointers to a temporary list. AutoTArray items; if (!CollectItemsWithOpacity(&mList, items, kMaxChildCount)) { + mChildOpacityState = ChildOpacityState::Deferred; return false; } @@ -6405,6 +6410,7 @@ nsDisplayOpacity::ApplyOpacityToChildren(nsDisplayListBuilder* aBuilder) for (size_t i = 0; i < childCount; i++) { for (size_t j = i+1; j < childCount; j++) { if (children[i].bounds.Intersects(children[j].bounds)) { + mChildOpacityState = ChildOpacityState::Deferred; return false; } } @@ -6414,16 +6420,13 @@ nsDisplayOpacity::ApplyOpacityToChildren(nsDisplayListBuilder* aBuilder) children[i].item->ApplyOpacity(aBuilder, mOpacity, mClipChain); } - mOpacityAppliedToChildren = true; + mChildOpacityState = ChildOpacityState::Applied; return true; } bool nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder) { - // ShouldFlattenAway() should be called only once during painting. - MOZ_ASSERT(!mOpacityAppliedToChildren); - if (mFrame->GetPrevContinuation() || mFrame->GetNextContinuation() || mFrame->HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)) { // If we've been split, then we might need to merge, so diff --git a/layout/painting/nsDisplayList.h b/layout/painting/nsDisplayList.h index 7ff49e8f66b7..1a0c1aa5d7eb 100644 --- a/layout/painting/nsDisplayList.h +++ b/layout/painting/nsDisplayList.h @@ -2372,6 +2372,12 @@ public: } } + /** + * This function is called when an item's list of children has been omdified + * by RetaineDisplayListBuilder. + */ + virtual void InvalidateCachedChildInfo() {} + /** * @param aSnap set to true if the edges of the rectangles of the opaque * region would be snapped to device pixels when drawing @@ -5122,10 +5128,10 @@ public: : nsDisplayWrapList(aBuilder, aOther) , mOpacity(aOther.mOpacity) , mForEventsAndPluginsOnly(aOther.mForEventsAndPluginsOnly) - , mOpacityAppliedToChildren(false) + , mChildOpacityState(ChildOpacityState::Unknown) { // We should not try to merge flattened opacities. - MOZ_ASSERT(!aOther.mOpacityAppliedToChildren); + MOZ_ASSERT(aOther.mChildOpacityState != ChildOpacityState::Applied); } #ifdef NS_BUILD_REFCNT_LOGGING @@ -5136,7 +5142,6 @@ public: { nsDisplayItem::RestoreState(); mOpacity = mState.mOpacity; - mOpacityAppliedToChildren = false; } virtual nsDisplayWrapList* Clone(nsDisplayListBuilder* aBuilder) const override @@ -5145,6 +5150,8 @@ public: return MakeDisplayItem(aBuilder, *this); } + virtual void InvalidateCachedChildInfo() override { mChildOpacityState = ChildOpacityState::Unknown; } + virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap) const override; virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, @@ -5189,7 +5196,7 @@ public: /** * Returns true if ShouldFlattenAway() applied opacity to children. */ - bool OpacityAppliedToChildren() const { return mOpacityAppliedToChildren; } + bool OpacityAppliedToChildren() const { return mChildOpacityState == ChildOpacityState::Applied; } static bool NeedsActiveLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame); NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY) @@ -5209,8 +5216,20 @@ private: bool ApplyOpacityToChildren(nsDisplayListBuilder* aBuilder); float mOpacity; - bool mForEventsAndPluginsOnly; - bool mOpacityAppliedToChildren; + bool mForEventsAndPluginsOnly : 1; + enum class ChildOpacityState : uint8_t { + // Our child list has changed since the last time ApplyOpacityToChildren was called. + Unknown, + // Our children defer opacity handling to us. + Deferred, + // Opacity is applied to our children. + Applied + }; +#ifndef __GNUC__ + ChildOpacityState mChildOpacityState : 2; +#else + ChildOpacityState mChildOpacityState; +#endif struct { float mOpacity; From 0b0f08aedbad19beaea23d871bf04767e919bbf9 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Tue, 3 Jul 2018 17:04:27 -0400 Subject: [PATCH 03/57] Bug 1472806 - fix -Wpessimizing-move warnings in Interceptor.cpp; r=aklotz There's no need to invoke std::move here, because Get() is already returning a temporary that can be moved into the RefPtr. --- ipc/mscom/Interceptor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipc/mscom/Interceptor.cpp b/ipc/mscom/Interceptor.cpp index de351478fd94..fc989cd68907 100644 --- a/ipc/mscom/Interceptor.cpp +++ b/ipc/mscom/Interceptor.cpp @@ -244,7 +244,7 @@ Interceptor::Create(STAUniquePtr aTarget, IInterceptorSink* aSink, detail::LiveSetAutoLock lock(GetLiveSet()); - RefPtr existingWeak(std::move(GetLiveSet().Get(aTarget.get()))); + RefPtr existingWeak(GetLiveSet().Get(aTarget.get())); if (existingWeak) { RefPtr existingStrong; if (SUCCEEDED(existingWeak->ToStrongRef(getter_AddRefs(existingStrong)))) { @@ -891,7 +891,7 @@ Interceptor::DisconnectRemotesForTarget(IUnknown* aTarget) // It is not an error if the interceptor doesn't exist, so we return // S_FALSE instead of an error in that case. - RefPtr existingWeak(std::move(GetLiveSet().Get(aTarget))); + RefPtr existingWeak(GetLiveSet().Get(aTarget)); if (!existingWeak) { return S_FALSE; } From 00e534b498946f74c3c2c167d712fd09ed577da8 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Tue, 3 Jul 2018 17:04:26 -0400 Subject: [PATCH 04/57] Bug 1472806 - fix microsoft template lookup extensions in interceptor code; r=aklotz clang-cl complains about things like: z:/build/build/src/obj-firefox/dist/include/mozilla/interceptor/VMSharingPolicies.h(53,50): warning: use of identifier 'GetLocalView' found via unqualified lookup into dependent bases of class templates is a Microsoft extension [-Wmicrosoft-template] return TrampolineCollection(*this, GetLocalView(), GetRemoteView(), ^ in various files in interceptor/, and since the warnings are in headers, rather than in sources, they're rather annoying. Let's fix this to be standards-complaint and make clang-cl stop complaining. --- mozglue/misc/interceptor/PatcherDetour.h | 16 ++++++++-------- mozglue/misc/interceptor/VMSharingPolicies.h | 9 +++++---- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/mozglue/misc/interceptor/PatcherDetour.h b/mozglue/misc/interceptor/PatcherDetour.h index 1a81597a1dae..e0d760afda17 100644 --- a/mozglue/misc/interceptor/PatcherDetour.h +++ b/mozglue/misc/interceptor/PatcherDetour.h @@ -42,7 +42,7 @@ public: void Clear() { - if (!mVMPolicy.ShouldUnhookUponDestruction()) { + if (!this->mVMPolicy.ShouldUnhookUponDestruction()) { return; } @@ -54,7 +54,7 @@ public: #error "Unknown processor type" #endif - const auto& tramps = mVMPolicy.Items(); + const auto& tramps = this->mVMPolicy.Items(); for (auto&& tramp : tramps) { // First we read the pointer to the interceptor instance. Maybe instance = tramp.ReadEncodedPointer(); @@ -80,7 +80,7 @@ public: continue; } - WritableTargetFunction origBytes(mVMPolicy, + WritableTargetFunction origBytes(this->mVMPolicy, interceptedFn.value(), nBytes); if (!origBytes) { continue; @@ -135,7 +135,7 @@ public: origBytes.Commit(); } - mVMPolicy.Clear(); + this->mVMPolicy.Clear(); } void Init(int aNumHooks = 0) @@ -148,20 +148,20 @@ public: // Win32 allocates VM addresses at a 64KiB granularity, so by default we // might as well utilize that entire 64KiB reservation instead of // artifically constraining ourselves to the page size. - aNumHooks = mVMPolicy.GetAllocGranularity() / kHookSize; + aNumHooks = this->mVMPolicy.GetAllocGranularity() / kHookSize; } - mVMPolicy.Reserve(aNumHooks); + this->mVMPolicy.Reserve(aNumHooks); } bool Initialized() const { - return !!mVMPolicy; + return !!this->mVMPolicy; } bool AddHook(FARPROC aTargetFn, intptr_t aHookDest, void** aOrigFunc) { - ReadOnlyTargetFunction target(ResolveRedirectedAddress(aTargetFn)); + ReadOnlyTargetFunction target(this->ResolveRedirectedAddress(aTargetFn)); CreateTrampoline(target, aHookDest, aOrigFunc); if (!*aOrigFunc) { diff --git a/mozglue/misc/interceptor/VMSharingPolicies.h b/mozglue/misc/interceptor/VMSharingPolicies.h index 8ceab3be8ab5..139eb9c8ef8d 100644 --- a/mozglue/misc/interceptor/VMSharingPolicies.h +++ b/mozglue/misc/interceptor/VMSharingPolicies.h @@ -34,13 +34,13 @@ public: Trampoline GetNextTrampoline() { uint32_t offset = mNextChunkIndex * kChunkSize; - if (!MaybeCommitNextPage(offset, kChunkSize)) { + if (!this->MaybeCommitNextPage(offset, kChunkSize)) { return nullptr; } - Trampoline result(this, GetLocalView() + offset, - GetRemoteView() + offset, kChunkSize); + Trampoline result(this, this->GetLocalView() + offset, + this->GetRemoteView() + offset, kChunkSize); if (!!result) { ++mNextChunkIndex; } @@ -50,7 +50,8 @@ public: TrampolineCollection Items() const { - return TrampolineCollection(*this, GetLocalView(), GetRemoteView(), + return TrampolineCollection(*this, this->GetLocalView(), + this->GetRemoteView(), kChunkSize, mNextChunkIndex); } From b07d6639b83e65970a2f32f6ebd275aa7e941c69 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Tue, 3 Jul 2018 17:04:26 -0400 Subject: [PATCH 05/57] Bug 1472806 - fix missing typename warning in COMPtrHolder.h; r=aklotz MSVC permits the missing `typename` as an extension, whereas clang-cl warns. This is easy to fix, so let's fix the warning noise. --- ipc/mscom/COMPtrHolder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipc/mscom/COMPtrHolder.h b/ipc/mscom/COMPtrHolder.h index 350b5c025845..bbb7b52634cf 100644 --- a/ipc/mscom/COMPtrHolder.h +++ b/ipc/mscom/COMPtrHolder.h @@ -162,7 +162,7 @@ struct ParamTraits> const bool sIsStreamPreservationNeeded = false; #endif // defined(MOZ_CONTENT_SANDBOX) - paramType::EnvType env; + typename paramType::EnvType env; mozilla::mscom::ProxyStreamFlags flags = sIsStreamPreservationNeeded ? mozilla::mscom::ProxyStreamFlags::ePreservable : From 5ca70b4c61ab64b98d5935710a2e50c76e121fb5 Mon Sep 17 00:00:00 2001 From: Ryan Hunt Date: Tue, 26 Jun 2018 13:37:31 -0500 Subject: [PATCH 06/57] Bug 1470528 - Add IsRootWebrenderBridgeParent method. r=kats This commit adds a helper function for determining if the WebRenderBridgeParent is for a content process and replaces uses with it appropriately. MozReview-Commit-ID: 6YZhjYEYS3P --HG-- extra : rebase_source : 8ecb1f9146376ac84b84680a5a3454200c940d6a --- gfx/layers/wr/WebRenderBridgeParent.cpp | 32 +++++++++++++++---------- gfx/layers/wr/WebRenderBridgeParent.h | 2 ++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp index bb66f7b3cbd2..6ec04bc373a2 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -183,7 +183,7 @@ WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompos MOZ_ASSERT(mAsyncImageManager); MOZ_ASSERT(mAnimStorage); mAsyncImageManager->AddPipeline(mPipelineId); - if (mWidget) { + if (IsRootWebRenderBridgeParent()) { MOZ_ASSERT(!mCompositorScheduler); mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget); } @@ -501,6 +501,12 @@ WebRenderBridgeParent::RemoveEpochDataPriorTo(const wr::Epoch& aRenderedEpoch) } } +bool +WebRenderBridgeParent::IsRootWebRenderBridgeParent() const +{ + return !!mWidget; +} + CompositorBridgeParent* WebRenderBridgeParent::GetRootCompositorBridgeParent() const { @@ -508,7 +514,7 @@ WebRenderBridgeParent::GetRootCompositorBridgeParent() const return nullptr; } - if (mWidget) { + if (IsRootWebRenderBridgeParent()) { // This WebRenderBridgeParent is attached to the root // CompositorBridgeParent. return static_cast(mCompositorBridge); @@ -658,7 +664,7 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize, // because the tab just moved to a new window. // In that case do not send the commands to webrender. if (mIdNamespace == aIdNamespace) { - if (mWidget) { + if (IsRootWebRenderBridgeParent()) { LayoutDeviceIntSize widgetSize = mWidget->GetClientSize(); LayoutDeviceIntRect docRect(LayoutDeviceIntPoint(), widgetSize); txn.SetWindowParameters(widgetSize, docRect); @@ -894,7 +900,7 @@ void WebRenderBridgeParent::FlushFrameGeneration() { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - MOZ_ASSERT(mWidget); // This function is only useful on the root WRBP + MOZ_ASSERT(IsRootWebRenderBridgeParent()); // This function is only useful on the root WRBP // This forces a new GenerateFrame transaction to be sent to the render // backend thread, if one is pending. This doesn't block on any other threads. @@ -929,7 +935,7 @@ WebRenderBridgeParent::RecvGetSnapshot(PTextureParent* aTexture) // but it will have no effect because CompositeToTarget (which reads the // flag) only gets invoked in the root WRBP. So we assert that this is the // root WRBP (i.e. has a non-null mWidget) to catch violations of this rule. - MOZ_ASSERT(mWidget); + MOZ_ASSERT(IsRootWebRenderBridgeParent()); RefPtr texture = TextureHost::AsTextureHost(aTexture); if (!texture) { @@ -1124,7 +1130,7 @@ WebRenderBridgeParent::UpdateWebRender(CompositorVsyncScheduler* aScheduler, CompositorAnimationStorage* aAnimStorage, const TextureFactoryIdentifier& aTextureFactoryIdentifier) { - MOZ_ASSERT(!mWidget); + MOZ_ASSERT(!IsRootWebRenderBridgeParent()); MOZ_ASSERT(aScheduler); MOZ_ASSERT(aApi); MOZ_ASSERT(aImageMgr); @@ -1378,7 +1384,7 @@ void WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect) { // This function should only get called in the root WRBP - MOZ_ASSERT(mWidget); + MOZ_ASSERT(IsRootWebRenderBridgeParent()); // The two arguments are part of the CompositorVsyncSchedulerOwner API but in // this implementation they should never be non-null. @@ -1552,9 +1558,9 @@ WebRenderBridgeParent::FlushRenderingAsync() void WebRenderBridgeParent::Pause() { - MOZ_ASSERT(mWidget); + MOZ_ASSERT(IsRootWebRenderBridgeParent()); #ifdef MOZ_WIDGET_ANDROID - if (!mWidget || mDestroyed) { + if (!IsRootWebRenderBridgeParent() || mDestroyed) { return; } mApi->Pause(); @@ -1565,9 +1571,9 @@ WebRenderBridgeParent::Pause() bool WebRenderBridgeParent::Resume() { - MOZ_ASSERT(mWidget); + MOZ_ASSERT(IsRootWebRenderBridgeParent()); #ifdef MOZ_WIDGET_ANDROID - if (!mWidget || mDestroyed) { + if (!IsRootWebRenderBridgeParent() || mDestroyed) { return false; } @@ -1623,7 +1629,7 @@ WebRenderBridgeParent::ClearResources() mActiveAnimations.clear(); std::queue().swap(mCompositorAnimationsToDelete); // clear queue - if (mWidget) { + if (IsRootWebRenderBridgeParent()) { mCompositorScheduler->Destroy(); } @@ -1739,7 +1745,7 @@ WebRenderBridgeParent::GetNextWrEpoch() void WebRenderBridgeParent::ExtractImageCompositeNotifications(nsTArray* aNotifications) { - MOZ_ASSERT(mWidget); + MOZ_ASSERT(IsRootWebRenderBridgeParent()); if (mDestroyed) { return; } diff --git a/gfx/layers/wr/WebRenderBridgeParent.h b/gfx/layers/wr/WebRenderBridgeParent.h index 180e9c273b8c..e2d71d6ef0c0 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.h +++ b/gfx/layers/wr/WebRenderBridgeParent.h @@ -230,6 +230,8 @@ private: bool SampleAnimations(nsTArray& aOpacityArray, nsTArray& aTransformArray); + bool IsRootWebRenderBridgeParent() const; + CompositorBridgeParent* GetRootCompositorBridgeParent() const; RefPtr GetRootWebRenderBridgeParent() const; From d34e6c84a0ff89e24edfd748f11577f72fbc9803 Mon Sep 17 00:00:00 2001 From: Ryan Hunt Date: Tue, 26 Jun 2018 13:40:10 -0500 Subject: [PATCH 07/57] Bug 1470528 - Implement CONTENT_FRAME_TIME for the non-webrender codepath. r=sotaro This commit adds the CONTENT_FRAME_TIME metric which tracks the time from the beginning of a paint in the content process until it is presented in the compositor. There is existing logging for frame latency which tracks from the beginning of a refresh tick until the frame is presented. This is undesirable for this probe as javascript and layout can run in this time period. So this probe uses the existing infrastructure for logging frame latency, but uses a start time from BeginTransaction in layer manager. MozReview-Commit-ID: 5z9LS3tsZTY --HG-- extra : rebase_source : cecb7149f50b2abe7a827dc20f1e8b8ade199258 extra : histedit_source : 581f8f38fc8335575d7275b903a8e1d6a9e5a369 --- gfx/layers/client/ClientLayerManager.cpp | 16 ++++++++------ gfx/layers/ipc/CompositorBridgeParent.cpp | 12 +++++----- gfx/layers/ipc/CompositorBridgeParent.h | 1 + .../CrossProcessCompositorBridgeParent.cpp | 7 +++--- gfx/layers/ipc/LayerTransactionParent.cpp | 22 ++++++++++++++----- gfx/layers/ipc/LayerTransactionParent.h | 12 ++++++++-- gfx/layers/ipc/LayersMessages.ipdlh | 1 + gfx/layers/ipc/ShadowLayers.cpp | 2 ++ gfx/layers/ipc/ShadowLayers.h | 1 + toolkit/components/telemetry/Histograms.json | 10 +++++++++ 10 files changed, 62 insertions(+), 22 deletions(-) diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp index cf96da0f092e..df6e2a345d9a 100644 --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -436,9 +436,15 @@ ClientLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback, if (mRepeatTransaction) { mRepeatTransaction = false; mIsRepeatTransaction = true; + + // BeginTransaction will reset the transaction start time, but we + // would like to keep the original time for telemetry purposes. + TimeStamp transactionStart = mTransactionStart; if (BeginTransaction()) { + mTransactionStart = transactionStart; ClientLayerManager::EndTransaction(aCallback, aCallbackData, aFlags); } + mIsRepeatTransaction = false; } else { MakeSnapshotIfRequired(); @@ -755,12 +761,7 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite) mPhase = PHASE_FORWARD; mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(!mIsRepeatTransaction); - TimeStamp transactionStart; - if (!mTransactionIdAllocator->GetTransactionStart().IsNull()) { - transactionStart = mTransactionIdAllocator->GetTransactionStart(); - } else { - transactionStart = mTransactionStart; - } + TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart(); if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) { mForwarder->SendPaintTime(mLatestTransactionId, mLastPaintTime); @@ -770,7 +771,8 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite) bool sent = false; bool ok = mForwarder->EndTransaction( mRegionToClear, mLatestTransactionId, aScheduleComposite, - mPaintSequenceNumber, mIsRepeatTransaction, transactionStart, + mPaintSequenceNumber, mIsRepeatTransaction, + refreshStart, mTransactionStart, &sent); if (ok) { if (sent) { diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index 1b267a502ed2..581a511629d3 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -1328,6 +1328,7 @@ CompositorBridgeParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree, // Otherwise, it should be continually increasing. MOZ_ASSERT(aInfo.id() == TransactionId{1} || aInfo.id() > mPendingTransaction); mPendingTransaction = aInfo.id(); + mRefreshStartTime = aInfo.refreshStart(); mTxnStartTime = aInfo.transactionStart(); mFwdTime = aInfo.fwdTime(); @@ -1636,14 +1637,14 @@ CompositorBridgeParent::AllocPLayerTransactionParent(const nsTArrayAddIPDLReference(); return p; } mCompositionManager = new AsyncCompositionManager(this, mLayerManager); - LayerTransactionParent* p = new LayerTransactionParent(mLayerManager, this, GetAnimationStorage(), mRootLayerTreeID); + LayerTransactionParent* p = new LayerTransactionParent(mLayerManager, this, GetAnimationStorage(), mRootLayerTreeID, mVsyncRate); p->AddIPDLReference(); return p; } @@ -2131,15 +2132,16 @@ CompositorBridgeParent::DidComposite(TimeStamp& aCompositeStart, NotifyDidComposite(mPendingTransaction, aCompositeStart, aCompositeEnd); #if defined(ENABLE_FRAME_LATENCY_LOG) if (mPendingTransaction.IsValid()) { - if (mTxnStartTime) { - uint32_t latencyMs = round((aCompositeEnd - mTxnStartTime).ToMilliseconds()); + if (mRefreshStartTime) { + int32_t latencyMs = lround((aCompositeEnd - mRefreshStartTime).ToMilliseconds()); printf_stderr("From transaction start to end of generate frame latencyMs %d this %p\n", latencyMs, this); } if (mFwdTime) { - uint32_t latencyMs = round((aCompositeEnd - mFwdTime).ToMilliseconds()); + int32_t latencyMs = lround((aCompositeEnd - mFwdTime).ToMilliseconds()); printf_stderr("From forwarding transaction to end of generate frame latencyMs %d this %p\n", latencyMs, this); } } + mRefreshStartTime = TimeStamp(); mTxnStartTime = TimeStamp(); mFwdTime = TimeStamp(); #endif diff --git a/gfx/layers/ipc/CompositorBridgeParent.h b/gfx/layers/ipc/CompositorBridgeParent.h index 9833621870db..436d8e6b56b1 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.h +++ b/gfx/layers/ipc/CompositorBridgeParent.h @@ -601,6 +601,7 @@ protected: TimeDuration mVsyncRate; TransactionId mPendingTransaction; + TimeStamp mRefreshStartTime; TimeStamp mTxnStartTime; TimeStamp mFwdTime; diff --git a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp index 1b2b16d231f9..a74cb716af9d 100644 --- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp @@ -94,14 +94,15 @@ CrossProcessCompositorBridgeParent::AllocPLayerTransactionParent( state->mCrossProcessParent = this; HostLayerManager* lm = state->mLayerManager; CompositorAnimationStorage* animStorage = state->mParent ? state->mParent->GetAnimationStorage() : nullptr; - LayerTransactionParent* p = new LayerTransactionParent(lm, this, animStorage, aId); + TimeDuration vsyncRate = state->mParent ? state->mParent->GetVsyncInterval() : TimeDuration(); + LayerTransactionParent* p = new LayerTransactionParent(lm, this, animStorage, aId, vsyncRate); p->AddIPDLReference(); sIndirectLayerTrees[aId].mLayerTree = p; return p; } NS_WARNING("Created child without a matching parent?"); - LayerTransactionParent* p = new LayerTransactionParent(/* aManager */ nullptr, this, /* aAnimStorage */ nullptr, aId); + LayerTransactionParent* p = new LayerTransactionParent(/* aManager */ nullptr, this, /* aAnimStorage */ nullptr, aId, TimeDuration()); p->AddIPDLReference(); return p; } @@ -372,7 +373,7 @@ CrossProcessCompositorBridgeParent::ShadowLayersUpdated( Unused << state->mParent->SendObserveLayerUpdate(id, aLayerTree->GetChildEpoch(), true); } - aLayerTree->SetPendingTransactionId(aInfo.id(), aInfo.transactionStart(), aInfo.fwdTime()); + aLayerTree->SetPendingTransactionId(aInfo.id(), aInfo.refreshStart(), aInfo.transactionStart(), aInfo.fwdTime()); } void diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp index dc9e53d5575a..f0130f5da6c9 100644 --- a/gfx/layers/ipc/LayerTransactionParent.cpp +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -26,6 +26,7 @@ #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL #include "mozilla/layers/PaintedLayerComposite.h" #include "mozilla/mozalloc.h" // for operator delete, etc +#include "mozilla/Telemetry.h" #include "mozilla/Unused.h" #include "nsCoord.h" // for NSAppUnitsToFloatPixels #include "nsISupportsImpl.h" // for Layer::Release, etc @@ -48,13 +49,15 @@ namespace layers { LayerTransactionParent::LayerTransactionParent(HostLayerManager* aManager, CompositorBridgeParentBase* aBridge, CompositorAnimationStorage* aAnimStorage, - LayersId aId) + LayersId aId, + TimeDuration aVsyncRate) : mLayerManager(aManager) , mCompositorBridge(aBridge) , mAnimStorage(aAnimStorage) , mId(aId) , mChildEpoch(0) , mParentEpoch(0) + , mVsyncRate(aVsyncRate) , mPendingTransaction{0} , mDestroyed(false) , mIPCOpen(false) @@ -959,20 +962,29 @@ bool LayerTransactionParent::IsSameProcess() const TransactionId LayerTransactionParent::FlushTransactionId(TimeStamp& aCompositeEnd) { + if (mId.IsValid() && mPendingTransaction.IsValid() && !mVsyncRate.IsZero()) { + double latencyMs = (aCompositeEnd - mTxnStartTime).ToMilliseconds(); + double latencyNorm = latencyMs / mVsyncRate.ToMilliseconds(); + int32_t fracLatencyNorm = lround(latencyNorm * 100.0); + Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME, fracLatencyNorm); + } + #if defined(ENABLE_FRAME_LATENCY_LOG) if (mPendingTransaction.IsValid()) { - if (mTxnStartTime) { - uint32_t latencyMs = round((aCompositeEnd - mTxnStartTime).ToMilliseconds()); + if (mRefreshStartTime) { + int32_t latencyMs = lround((aCompositeEnd - mRefreshStartTime).ToMilliseconds()); printf_stderr("From transaction start to end of generate frame latencyMs %d this %p\n", latencyMs, this); } if (mFwdTime) { - uint32_t latencyMs = round((aCompositeEnd - mFwdTime).ToMilliseconds()); + int32_t latencyMs = lround((aCompositeEnd - mFwdTime).ToMilliseconds()); printf_stderr("From forwarding transaction to end of generate frame latencyMs %d this %p\n", latencyMs, this); } } +#endif + + mRefreshStartTime = TimeStamp(); mTxnStartTime = TimeStamp(); mFwdTime = TimeStamp(); -#endif TransactionId id = mPendingTransaction; mPendingTransaction = TransactionId{0}; return id; diff --git a/gfx/layers/ipc/LayerTransactionParent.h b/gfx/layers/ipc/LayerTransactionParent.h index 271d65042305..49e65732f252 100644 --- a/gfx/layers/ipc/LayerTransactionParent.h +++ b/gfx/layers/ipc/LayerTransactionParent.h @@ -48,7 +48,8 @@ public: LayerTransactionParent(HostLayerManager* aManager, CompositorBridgeParentBase* aBridge, CompositorAnimationStorage* aAnimStorage, - LayersId aId); + LayersId aId, + TimeDuration aVsyncRate); protected: ~LayerTransactionParent(); @@ -79,9 +80,13 @@ public: bool IsSameProcess() const override; const TransactionId& GetPendingTransactionId() { return mPendingTransaction; } - void SetPendingTransactionId(TransactionId aId, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime) + void SetPendingTransactionId(TransactionId aId, + const TimeStamp& aRefreshStartTime, + const TimeStamp& aTxnStartTime, + const TimeStamp& aFwdTime) { mPendingTransaction = aId; + mRefreshStartTime = aRefreshStartTime; mTxnStartTime = aTxnStartTime; mFwdTime = aFwdTime; } @@ -196,7 +201,10 @@ private: uint64_t mChildEpoch; uint64_t mParentEpoch; + TimeDuration mVsyncRate; + TransactionId mPendingTransaction; + TimeStamp mRefreshStartTime; TimeStamp mTxnStartTime; TimeStamp mFwdTime; diff --git a/gfx/layers/ipc/LayersMessages.ipdlh b/gfx/layers/ipc/LayersMessages.ipdlh index 1058b2db71ff..a54e6d33099a 100644 --- a/gfx/layers/ipc/LayersMessages.ipdlh +++ b/gfx/layers/ipc/LayersMessages.ipdlh @@ -572,6 +572,7 @@ struct TransactionInfo bool scheduleComposite; uint32_t paintSequenceNumber; bool isRepeatTransaction; + TimeStamp refreshStart; TimeStamp transactionStart; TimeStamp fwdTime; }; diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index ecc5393bf17d..3f051f91010c 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -604,6 +604,7 @@ ShadowLayerForwarder::EndTransaction(const nsIntRegion& aRegionToClear, bool aScheduleComposite, uint32_t aPaintSequenceNumber, bool aIsRepeatTransaction, + const mozilla::TimeStamp& aRefreshStart, const mozilla::TimeStamp& aTransactionStart, bool* aSent) { @@ -745,6 +746,7 @@ ShadowLayerForwarder::EndTransaction(const nsIntRegion& aRegionToClear, info.scheduleComposite() = aScheduleComposite; info.paintSequenceNumber() = aPaintSequenceNumber; info.isRepeatTransaction() = aIsRepeatTransaction; + info.refreshStart() = aRefreshStart; info.transactionStart() = aTransactionStart; #if defined(ENABLE_FRAME_LATENCY_LOG) info.fwdTime() = TimeStamp::Now(); diff --git a/gfx/layers/ipc/ShadowLayers.h b/gfx/layers/ipc/ShadowLayers.h index 644057b1e1fa..b1a40b9822b3 100644 --- a/gfx/layers/ipc/ShadowLayers.h +++ b/gfx/layers/ipc/ShadowLayers.h @@ -258,6 +258,7 @@ public: bool aScheduleComposite, uint32_t aPaintSequenceNumber, bool aIsRepeatTransaction, + const mozilla::TimeStamp& aRefreshStart, const mozilla::TimeStamp& aTransactionStart, bool* aSent); diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 0ea5794a41c1..12eac0eba10a 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -12801,6 +12801,16 @@ "n_buckets": 50, "description": "Time spent in the paint pipeline for content in milliseconds." }, + "CONTENT_FRAME_TIME": { + "record_in_processes": ["main", "gpu"], + "alert_emails": ["rhunt@mozilla.com","gfx-telemetry-alerts@mozilla.com"], + "bug_numbers": [1470528], + "expires_in_version": "66", + "kind": "exponential", + "high": 5000, + "n_buckets": 50, + "description": "The time, in percentage of a vsync interval, spent from beginning a paint in the content process until that frame is presented in the compositor." + }, "CONTENT_LARGE_PAINT_PHASE_WEIGHT": { "record_in_processes": ["main", "content"], "alert_emails": ["mwoodrow@mozilla.com","gfx-telemetry-alerts@mozilla.com"], From c284332e41890cbb4bb3415d2ad4f22144119c3c Mon Sep 17 00:00:00 2001 From: Ryan Hunt Date: Tue, 26 Jun 2018 13:43:14 -0500 Subject: [PATCH 08/57] Bug 1470528 - Implement CONTENT_FRAME_TIME for the webrender codepath. r=sotaro This commit implements the CONTENT_FRAME_TIME metric for the webrender code path. It follows the same structure as the previous commit implementing it for the non-webrender code path. MozReview-Commit-ID: 6aI5uISjgge --HG-- extra : rebase_source : acbf83d0071e8932b5e96016e6e39e27a7b4da8c extra : histedit_source : a0f93f80441e5f45c0113244d15400d0f53d9c92 --- gfx/layers/ipc/CompositorBridgeParent.cpp | 2 +- .../CrossProcessCompositorBridgeParent.cpp | 2 +- gfx/layers/ipc/PWebRenderBridge.ipdl | 4 +-- gfx/layers/wr/WebRenderBridgeChild.cpp | 6 ++-- gfx/layers/wr/WebRenderBridgeChild.h | 2 ++ gfx/layers/wr/WebRenderBridgeParent.cpp | 32 +++++++++++++++---- gfx/layers/wr/WebRenderBridgeParent.h | 15 +++++++-- gfx/layers/wr/WebRenderLayerManager.cpp | 14 +++++--- gfx/layers/wr/WebRenderLayerManager.h | 1 + 9 files changed, 59 insertions(+), 19 deletions(-) diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index 581a511629d3..f69c2f83e7ad 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -1874,7 +1874,7 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipel txn.SetRootPipeline(aPipelineId); api->SendTransaction(txn); RefPtr animStorage = GetAnimationStorage(); - mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, nullptr, std::move(api), std::move(asyncMgr), std::move(animStorage)); + mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, nullptr, std::move(api), std::move(asyncMgr), std::move(animStorage), mVsyncRate); mWrBridge.get()->AddRef(); // IPDL reference *aIdNamespace = mWrBridge->GetIdNamespace(); diff --git a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp index a74cb716af9d..15d72ac19d07 100644 --- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp @@ -244,7 +244,7 @@ CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::Pipeli RefPtr holder = root->AsyncImageManager(); RefPtr animStorage = cbp->GetAnimationStorage(); WebRenderBridgeParent* parent = new WebRenderBridgeParent( - this, aPipelineId, nullptr, root->CompositorScheduler(), std::move(api), std::move(holder), std::move(animStorage)); + this, aPipelineId, nullptr, root->CompositorScheduler(), std::move(api), std::move(holder), std::move(animStorage), cbp->GetVsyncInterval()); parent->AddRef(); // IPDL reference { // scope lock diff --git a/gfx/layers/ipc/PWebRenderBridge.ipdl b/gfx/layers/ipc/PWebRenderBridge.ipdl index d7168e4feb5f..58c8e182aa07 100644 --- a/gfx/layers/ipc/PWebRenderBridge.ipdl +++ b/gfx/layers/ipc/PWebRenderBridge.ipdl @@ -43,10 +43,10 @@ parent: LayoutSize aContentSize, ByteBuf aDL, BuiltDisplayListDescriptor aDLDesc, WebRenderScrollData aScrollData, OpUpdateResource[] aResourceUpdates, RefCountedShmem[] aSmallShmems, Shmem[] aLargeShmems, - IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime); + IdNamespace aIdNamespace, TimeStamp refreshStartTime, TimeStamp txnStartTime, TimeStamp fwdTime); async EmptyTransaction(FocusTarget focusTarget, ScrollUpdatesMap scrollUpdates, uint32_t aPaintSequenceNumber, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, TransactionId transactionId, - IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime); + IdNamespace aIdNamespace, TimeStamp refreshStartTime, TimeStamp txnStartTime, TimeStamp fwdTime); async SetFocusTarget(FocusTarget focusTarget); async UpdateResources(OpUpdateResource[] aResourceUpdates, RefCountedShmem[] aSmallShmems, Shmem[] aLargeShmems); async ParentCommands(WebRenderParentCommand[] commands); diff --git a/gfx/layers/wr/WebRenderBridgeChild.cpp b/gfx/layers/wr/WebRenderBridgeChild.cpp index 73e85bd82580..ed29556e6318 100644 --- a/gfx/layers/wr/WebRenderBridgeChild.cpp +++ b/gfx/layers/wr/WebRenderBridgeChild.cpp @@ -122,6 +122,7 @@ WebRenderBridgeChild::EndTransaction(const wr::LayoutSize& aContentSize, const gfx::IntSize& aSize, TransactionId aTransactionId, const WebRenderScrollData& aScrollData, + const mozilla::TimeStamp& aRefreshStartTime, const mozilla::TimeStamp& aTxnStartTime) { MOZ_ASSERT(!mDestroyed); @@ -145,7 +146,7 @@ WebRenderBridgeChild::EndTransaction(const wr::LayoutSize& aContentSize, GetFwdTransactionId(), aTransactionId, aContentSize, dlData, aDL.dl_desc, aScrollData, std::move(resourceUpdates), std::move(smallShmems), largeShmems, - mIdNamespace, aTxnStartTime, fwdTime); + mIdNamespace, aRefreshStartTime, aTxnStartTime, fwdTime); mParentCommands.Clear(); mDestroyedActors.Clear(); @@ -157,6 +158,7 @@ WebRenderBridgeChild::EndEmptyTransaction(const FocusTarget& aFocusTarget, const ScrollUpdatesMap& aUpdates, uint32_t aPaintSequenceNumber, TransactionId aTransactionId, + const mozilla::TimeStamp& aRefreshStartTime, const mozilla::TimeStamp& aTxnStartTime) { MOZ_ASSERT(!mDestroyed); @@ -170,7 +172,7 @@ WebRenderBridgeChild::EndEmptyTransaction(const FocusTarget& aFocusTarget, this->SendEmptyTransaction(aFocusTarget, aUpdates, aPaintSequenceNumber, mParentCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId, - mIdNamespace, aTxnStartTime, fwdTime); + mIdNamespace, aRefreshStartTime, aTxnStartTime, fwdTime); mParentCommands.Clear(); mDestroyedActors.Clear(); mIsInTransaction = false; diff --git a/gfx/layers/wr/WebRenderBridgeChild.h b/gfx/layers/wr/WebRenderBridgeChild.h index eeabdacb3c55..4346ca66d264 100644 --- a/gfx/layers/wr/WebRenderBridgeChild.h +++ b/gfx/layers/wr/WebRenderBridgeChild.h @@ -74,11 +74,13 @@ public: const gfx::IntSize& aSize, TransactionId aTransactionId, const WebRenderScrollData& aScrollData, + const mozilla::TimeStamp& aRefreshStartTime, const mozilla::TimeStamp& aTxnStartTime); void EndEmptyTransaction(const FocusTarget& aFocusTarget, const ScrollUpdatesMap& aUpdates, uint32_t aPaintSequenceNumber, TransactionId aTransactionId, + const mozilla::TimeStamp& aRefreshStartTime, const mozilla::TimeStamp& aTxnStartTime); void ProcessWebRenderParentCommands(); diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp index 6ec04bc373a2..5b86aba2da64 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -29,6 +29,7 @@ #include "mozilla/layers/AsyncImagePipelineManager.h" #include "mozilla/layers/WebRenderImageHost.h" #include "mozilla/layers/WebRenderTextureHost.h" +#include "mozilla/Telemetry.h" #include "mozilla/TimeStamp.h" #include "mozilla/Unused.h" #include "mozilla/webrender/RenderThread.h" @@ -163,7 +164,8 @@ WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompos CompositorVsyncScheduler* aScheduler, RefPtr&& aApi, RefPtr&& aImageMgr, - RefPtr&& aAnimStorage) + RefPtr&& aAnimStorage, + TimeDuration aVsyncRate) : mCompositorBridge(aCompositorBridge) , mPipelineId(aPipelineId) , mWidget(aWidget) @@ -179,6 +181,7 @@ WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompos , mDestroyed(false) , mForceRendering(false) , mReceivedDisplayList(false) + , mVsyncRate(aVsyncRate) { MOZ_ASSERT(mAsyncImageManager); MOZ_ASSERT(mAnimStorage); @@ -617,6 +620,7 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize, nsTArray&& aSmallShmems, nsTArray&& aLargeShmems, const wr::IdNamespace& aIdNamespace, + const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime) { @@ -690,7 +694,7 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize, } } - HoldPendingTransactionId(wrEpoch, aTransactionId, aTxnStartTime, aFwdTime); + HoldPendingTransactionId(wrEpoch, aTransactionId, aRefreshStartTime, aTxnStartTime, aFwdTime); if (mIdNamespace != aIdNamespace) { // Pretend we composited since someone is wating for this event, @@ -717,6 +721,7 @@ WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget, const uint64_t& aFwdTransactionId, const TransactionId& aTransactionId, const wr::IdNamespace& aIdNamespace, + const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime) { @@ -768,7 +773,7 @@ WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget, sendDidComposite = false; } - HoldPendingTransactionId(WrEpoch(), aTransactionId, aTxnStartTime, aFwdTime); + HoldPendingTransactionId(WrEpoch(), aTransactionId, aRefreshStartTime, aTxnStartTime, aFwdTime); if (scheduleComposite) { ScheduleGenerateFrame(); @@ -1466,11 +1471,16 @@ WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::In void WebRenderBridgeParent::HoldPendingTransactionId(const wr::Epoch& aWrEpoch, TransactionId aTransactionId, + const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime) { MOZ_ASSERT(aTransactionId > LastPendingTransactionId()); - mPendingTransactionIds.push(PendingTransactionId(aWrEpoch, aTransactionId, aTxnStartTime, aFwdTime)); + mPendingTransactionIds.push(PendingTransactionId(aWrEpoch, + aTransactionId, + aRefreshStartTime, + aTxnStartTime, + aFwdTime)); } TransactionId @@ -1502,13 +1512,21 @@ WebRenderBridgeParent::FlushTransactionIdsForEpoch(const wr::Epoch& aEpoch, cons if (aEpoch.mHandle < mPendingTransactionIds.front().mEpoch.mHandle) { break; } + + if (!IsRootWebRenderBridgeParent() && !mVsyncRate.IsZero()) { + double latencyMs = (aEndTime - mPendingTransactionIds.front().mTxnStartTime).ToMilliseconds(); + double latencyNorm = latencyMs / mVsyncRate.ToMilliseconds(); + int32_t fracLatencyNorm = lround(latencyNorm * 100.0); + Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME, fracLatencyNorm); + } + #if defined(ENABLE_FRAME_LATENCY_LOG) - if (mPendingTransactionIds.front().mTxnStartTime) { - uint32_t latencyMs = round((aEndTime - mPendingTransactionIds.front().mTxnStartTime).ToMilliseconds()); + if (mPendingTransactionIds.front().mRefreshStartTime) { + int32_t latencyMs = lround((aEndTime - mPendingTransactionIds.front().mRefreshStartTime).ToMilliseconds()); printf_stderr("From transaction start to end of generate frame latencyMs %d this %p\n", latencyMs, this); } if (mPendingTransactionIds.front().mFwdTime) { - uint32_t latencyMs = round((aEndTime - mPendingTransactionIds.front().mFwdTime).ToMilliseconds()); + int32_t latencyMs = lround((aEndTime - mPendingTransactionIds.front().mFwdTime).ToMilliseconds()); printf_stderr("From forwarding transaction to end of generate frame latencyMs %d this %p\n", latencyMs, this); } #endif diff --git a/gfx/layers/wr/WebRenderBridgeParent.h b/gfx/layers/wr/WebRenderBridgeParent.h index e2d71d6ef0c0..784f5b013a79 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.h +++ b/gfx/layers/wr/WebRenderBridgeParent.h @@ -53,7 +53,8 @@ public: CompositorVsyncScheduler* aScheduler, RefPtr&& aApi, RefPtr&& aImageMgr, - RefPtr&& aAnimStorage); + RefPtr&& aAnimStorage, + TimeDuration aVsyncRate); static WebRenderBridgeParent* CreateDestroyed(const wr::PipelineId& aPipelineId); @@ -87,6 +88,7 @@ public: nsTArray&& aSmallShmems, nsTArray&& aLargeShmems, const wr::IdNamespace& aIdNamespace, + const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime) override; mozilla::ipc::IPCResult RecvEmptyTransaction(const FocusTarget& aFocusTarget, @@ -97,6 +99,7 @@ public: const uint64_t& aFwdTransactionId, const TransactionId& aTransactionId, const wr::IdNamespace& aIdNamespace, + const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime) override; mozilla::ipc::IPCResult RecvSetFocusTarget(const FocusTarget& aFocusTarget) override; @@ -150,6 +153,7 @@ public: void HoldPendingTransactionId(const wr::Epoch& aWrEpoch, TransactionId aTransactionId, + const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime); TransactionId LastPendingTransactionId(); @@ -247,14 +251,20 @@ private: private: struct PendingTransactionId { - PendingTransactionId(const wr::Epoch& aEpoch, TransactionId aId, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime) + PendingTransactionId(const wr::Epoch& aEpoch, + TransactionId aId, + const TimeStamp& aRefreshStartTime, + const TimeStamp& aTxnStartTime, + const TimeStamp& aFwdTime) : mEpoch(aEpoch) , mId(aId) + , mRefreshStartTime(aRefreshStartTime) , mTxnStartTime(aTxnStartTime) , mFwdTime(aFwdTime) {} wr::Epoch mEpoch; TransactionId mId; + TimeStamp mRefreshStartTime; TimeStamp mTxnStartTime; TimeStamp mFwdTime; }; @@ -284,6 +294,7 @@ private: nsDataHashtable> mExternalImageIds; nsTHashtable mSharedSurfaceIds; + TimeDuration mVsyncRate; TimeStamp mPreviousFrameTimeStamp; // These fields keep track of the latest layer observer epoch values in the child and the // parent. mChildLayerObserverEpoch is the latest epoch value received from the child. diff --git a/gfx/layers/wr/WebRenderLayerManager.cpp b/gfx/layers/wr/WebRenderLayerManager.cpp index 29bcbb62636e..82567ab42dfc 100644 --- a/gfx/layers/wr/WebRenderLayerManager.cpp +++ b/gfx/layers/wr/WebRenderLayerManager.cpp @@ -168,6 +168,8 @@ WebRenderLayerManager::BeginTransaction() return false; } + mTransactionStart = TimeStamp::Now(); + // Increment the paint sequence number even if test logging isn't // enabled in this process; it may be enabled in the parent process, // and the parent process expects unique sequence numbers. @@ -208,7 +210,7 @@ WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) mWebRenderCommandBuilder.EmptyTransaction(); mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(/*aThrottle*/ true); - TimeStamp transactionStart = mTransactionIdAllocator->GetTransactionStart(); + TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart(); // Skip the synchronization for buffer since we also skip the painting during // device-reset status. @@ -220,9 +222,11 @@ WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) } WrBridge()->EndEmptyTransaction(mFocusTarget, mPendingScrollUpdates, - mPaintSequenceNumber, mLatestTransactionId, transactionStart); + mPaintSequenceNumber, mLatestTransactionId, refreshStart, mTransactionStart); ClearPendingScrollInfoUpdate(); + mTransactionStart = TimeStamp(); + MakeSnapshotIfRequired(size); return true; } @@ -308,7 +312,7 @@ WebRenderLayerManager::EndTransactionWithoutLayer(nsDisplayList* aDisplayList, ClearPendingScrollInfoUpdate(); mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(/*aThrottle*/ true); - TimeStamp transactionStart = mTransactionIdAllocator->GetTransactionStart(); + TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart(); for (const auto& key : mImageKeysToDelete) { resourceUpdates.DeleteImage(key); @@ -337,9 +341,11 @@ WebRenderLayerManager::EndTransactionWithoutLayer(nsDisplayList* aDisplayList, { AUTO_PROFILER_TRACING("Paint", "ForwardDPTransaction"); WrBridge()->EndTransaction(contentSize, dl, resourceUpdates, size.ToUnknownSize(), - mLatestTransactionId, mScrollData, transactionStart); + mLatestTransactionId, mScrollData, refreshStart, mTransactionStart); } + mTransactionStart = TimeStamp(); + MakeSnapshotIfRequired(size); mNeedsComposite = false; } diff --git a/gfx/layers/wr/WebRenderLayerManager.h b/gfx/layers/wr/WebRenderLayerManager.h index f7e1f4be3bf8..2ca5aa2f0e8c 100644 --- a/gfx/layers/wr/WebRenderLayerManager.h +++ b/gfx/layers/wr/WebRenderLayerManager.h @@ -212,6 +212,7 @@ private: // See equivalent field in ClientLayerManager APZTestData mApzTestData; + TimeStamp mTransactionStart; WebRenderCommandBuilder mWebRenderCommandBuilder; size_t mLastDisplayListSize; From 04b49251705cafb92e2a399d8cc7b14f7794b71b Mon Sep 17 00:00:00 2001 From: Narcis Beleuzu Date: Wed, 4 Jul 2018 00:41:14 +0300 Subject: [PATCH 09/57] Backed out 3 changesets (bug 1470528) for build bustages on WebRenderBridgeParent. CLOSED TREE Backed out changeset 90513daef576 (bug 1470528) Backed out changeset e438548991db (bug 1470528) Backed out changeset f859daf8d8d9 (bug 1470528) --- gfx/layers/client/ClientLayerManager.cpp | 16 ++--- gfx/layers/ipc/CompositorBridgeParent.cpp | 14 ++-- gfx/layers/ipc/CompositorBridgeParent.h | 1 - .../CrossProcessCompositorBridgeParent.cpp | 9 ++- gfx/layers/ipc/LayerTransactionParent.cpp | 22 ++----- gfx/layers/ipc/LayerTransactionParent.h | 12 +--- gfx/layers/ipc/LayersMessages.ipdlh | 1 - gfx/layers/ipc/PWebRenderBridge.ipdl | 4 +- gfx/layers/ipc/ShadowLayers.cpp | 2 - gfx/layers/ipc/ShadowLayers.h | 1 - gfx/layers/wr/WebRenderBridgeChild.cpp | 6 +- gfx/layers/wr/WebRenderBridgeChild.h | 2 - gfx/layers/wr/WebRenderBridgeParent.cpp | 64 ++++++------------- gfx/layers/wr/WebRenderBridgeParent.h | 17 +---- gfx/layers/wr/WebRenderLayerManager.cpp | 14 ++-- gfx/layers/wr/WebRenderLayerManager.h | 1 - toolkit/components/telemetry/Histograms.json | 10 --- 17 files changed, 54 insertions(+), 142 deletions(-) diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp index df6e2a345d9a..cf96da0f092e 100644 --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -436,15 +436,9 @@ ClientLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback, if (mRepeatTransaction) { mRepeatTransaction = false; mIsRepeatTransaction = true; - - // BeginTransaction will reset the transaction start time, but we - // would like to keep the original time for telemetry purposes. - TimeStamp transactionStart = mTransactionStart; if (BeginTransaction()) { - mTransactionStart = transactionStart; ClientLayerManager::EndTransaction(aCallback, aCallbackData, aFlags); } - mIsRepeatTransaction = false; } else { MakeSnapshotIfRequired(); @@ -761,7 +755,12 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite) mPhase = PHASE_FORWARD; mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(!mIsRepeatTransaction); - TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart(); + TimeStamp transactionStart; + if (!mTransactionIdAllocator->GetTransactionStart().IsNull()) { + transactionStart = mTransactionIdAllocator->GetTransactionStart(); + } else { + transactionStart = mTransactionStart; + } if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) { mForwarder->SendPaintTime(mLatestTransactionId, mLastPaintTime); @@ -771,8 +770,7 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite) bool sent = false; bool ok = mForwarder->EndTransaction( mRegionToClear, mLatestTransactionId, aScheduleComposite, - mPaintSequenceNumber, mIsRepeatTransaction, - refreshStart, mTransactionStart, + mPaintSequenceNumber, mIsRepeatTransaction, transactionStart, &sent); if (ok) { if (sent) { diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index f69c2f83e7ad..1b267a502ed2 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -1328,7 +1328,6 @@ CompositorBridgeParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree, // Otherwise, it should be continually increasing. MOZ_ASSERT(aInfo.id() == TransactionId{1} || aInfo.id() > mPendingTransaction); mPendingTransaction = aInfo.id(); - mRefreshStartTime = aInfo.refreshStart(); mTxnStartTime = aInfo.transactionStart(); mFwdTime = aInfo.fwdTime(); @@ -1637,14 +1636,14 @@ CompositorBridgeParent::AllocPLayerTransactionParent(const nsTArrayAddIPDLReference(); return p; } mCompositionManager = new AsyncCompositionManager(this, mLayerManager); - LayerTransactionParent* p = new LayerTransactionParent(mLayerManager, this, GetAnimationStorage(), mRootLayerTreeID, mVsyncRate); + LayerTransactionParent* p = new LayerTransactionParent(mLayerManager, this, GetAnimationStorage(), mRootLayerTreeID); p->AddIPDLReference(); return p; } @@ -1874,7 +1873,7 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipel txn.SetRootPipeline(aPipelineId); api->SendTransaction(txn); RefPtr animStorage = GetAnimationStorage(); - mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, nullptr, std::move(api), std::move(asyncMgr), std::move(animStorage), mVsyncRate); + mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, nullptr, std::move(api), std::move(asyncMgr), std::move(animStorage)); mWrBridge.get()->AddRef(); // IPDL reference *aIdNamespace = mWrBridge->GetIdNamespace(); @@ -2132,16 +2131,15 @@ CompositorBridgeParent::DidComposite(TimeStamp& aCompositeStart, NotifyDidComposite(mPendingTransaction, aCompositeStart, aCompositeEnd); #if defined(ENABLE_FRAME_LATENCY_LOG) if (mPendingTransaction.IsValid()) { - if (mRefreshStartTime) { - int32_t latencyMs = lround((aCompositeEnd - mRefreshStartTime).ToMilliseconds()); + if (mTxnStartTime) { + uint32_t latencyMs = round((aCompositeEnd - mTxnStartTime).ToMilliseconds()); printf_stderr("From transaction start to end of generate frame latencyMs %d this %p\n", latencyMs, this); } if (mFwdTime) { - int32_t latencyMs = lround((aCompositeEnd - mFwdTime).ToMilliseconds()); + uint32_t latencyMs = round((aCompositeEnd - mFwdTime).ToMilliseconds()); printf_stderr("From forwarding transaction to end of generate frame latencyMs %d this %p\n", latencyMs, this); } } - mRefreshStartTime = TimeStamp(); mTxnStartTime = TimeStamp(); mFwdTime = TimeStamp(); #endif diff --git a/gfx/layers/ipc/CompositorBridgeParent.h b/gfx/layers/ipc/CompositorBridgeParent.h index 436d8e6b56b1..9833621870db 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.h +++ b/gfx/layers/ipc/CompositorBridgeParent.h @@ -601,7 +601,6 @@ protected: TimeDuration mVsyncRate; TransactionId mPendingTransaction; - TimeStamp mRefreshStartTime; TimeStamp mTxnStartTime; TimeStamp mFwdTime; diff --git a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp index 15d72ac19d07..1b2b16d231f9 100644 --- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp @@ -94,15 +94,14 @@ CrossProcessCompositorBridgeParent::AllocPLayerTransactionParent( state->mCrossProcessParent = this; HostLayerManager* lm = state->mLayerManager; CompositorAnimationStorage* animStorage = state->mParent ? state->mParent->GetAnimationStorage() : nullptr; - TimeDuration vsyncRate = state->mParent ? state->mParent->GetVsyncInterval() : TimeDuration(); - LayerTransactionParent* p = new LayerTransactionParent(lm, this, animStorage, aId, vsyncRate); + LayerTransactionParent* p = new LayerTransactionParent(lm, this, animStorage, aId); p->AddIPDLReference(); sIndirectLayerTrees[aId].mLayerTree = p; return p; } NS_WARNING("Created child without a matching parent?"); - LayerTransactionParent* p = new LayerTransactionParent(/* aManager */ nullptr, this, /* aAnimStorage */ nullptr, aId, TimeDuration()); + LayerTransactionParent* p = new LayerTransactionParent(/* aManager */ nullptr, this, /* aAnimStorage */ nullptr, aId); p->AddIPDLReference(); return p; } @@ -244,7 +243,7 @@ CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::Pipeli RefPtr holder = root->AsyncImageManager(); RefPtr animStorage = cbp->GetAnimationStorage(); WebRenderBridgeParent* parent = new WebRenderBridgeParent( - this, aPipelineId, nullptr, root->CompositorScheduler(), std::move(api), std::move(holder), std::move(animStorage), cbp->GetVsyncInterval()); + this, aPipelineId, nullptr, root->CompositorScheduler(), std::move(api), std::move(holder), std::move(animStorage)); parent->AddRef(); // IPDL reference { // scope lock @@ -373,7 +372,7 @@ CrossProcessCompositorBridgeParent::ShadowLayersUpdated( Unused << state->mParent->SendObserveLayerUpdate(id, aLayerTree->GetChildEpoch(), true); } - aLayerTree->SetPendingTransactionId(aInfo.id(), aInfo.refreshStart(), aInfo.transactionStart(), aInfo.fwdTime()); + aLayerTree->SetPendingTransactionId(aInfo.id(), aInfo.transactionStart(), aInfo.fwdTime()); } void diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp index f0130f5da6c9..dc9e53d5575a 100644 --- a/gfx/layers/ipc/LayerTransactionParent.cpp +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -26,7 +26,6 @@ #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL #include "mozilla/layers/PaintedLayerComposite.h" #include "mozilla/mozalloc.h" // for operator delete, etc -#include "mozilla/Telemetry.h" #include "mozilla/Unused.h" #include "nsCoord.h" // for NSAppUnitsToFloatPixels #include "nsISupportsImpl.h" // for Layer::Release, etc @@ -49,15 +48,13 @@ namespace layers { LayerTransactionParent::LayerTransactionParent(HostLayerManager* aManager, CompositorBridgeParentBase* aBridge, CompositorAnimationStorage* aAnimStorage, - LayersId aId, - TimeDuration aVsyncRate) + LayersId aId) : mLayerManager(aManager) , mCompositorBridge(aBridge) , mAnimStorage(aAnimStorage) , mId(aId) , mChildEpoch(0) , mParentEpoch(0) - , mVsyncRate(aVsyncRate) , mPendingTransaction{0} , mDestroyed(false) , mIPCOpen(false) @@ -962,29 +959,20 @@ bool LayerTransactionParent::IsSameProcess() const TransactionId LayerTransactionParent::FlushTransactionId(TimeStamp& aCompositeEnd) { - if (mId.IsValid() && mPendingTransaction.IsValid() && !mVsyncRate.IsZero()) { - double latencyMs = (aCompositeEnd - mTxnStartTime).ToMilliseconds(); - double latencyNorm = latencyMs / mVsyncRate.ToMilliseconds(); - int32_t fracLatencyNorm = lround(latencyNorm * 100.0); - Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME, fracLatencyNorm); - } - #if defined(ENABLE_FRAME_LATENCY_LOG) if (mPendingTransaction.IsValid()) { - if (mRefreshStartTime) { - int32_t latencyMs = lround((aCompositeEnd - mRefreshStartTime).ToMilliseconds()); + if (mTxnStartTime) { + uint32_t latencyMs = round((aCompositeEnd - mTxnStartTime).ToMilliseconds()); printf_stderr("From transaction start to end of generate frame latencyMs %d this %p\n", latencyMs, this); } if (mFwdTime) { - int32_t latencyMs = lround((aCompositeEnd - mFwdTime).ToMilliseconds()); + uint32_t latencyMs = round((aCompositeEnd - mFwdTime).ToMilliseconds()); printf_stderr("From forwarding transaction to end of generate frame latencyMs %d this %p\n", latencyMs, this); } } -#endif - - mRefreshStartTime = TimeStamp(); mTxnStartTime = TimeStamp(); mFwdTime = TimeStamp(); +#endif TransactionId id = mPendingTransaction; mPendingTransaction = TransactionId{0}; return id; diff --git a/gfx/layers/ipc/LayerTransactionParent.h b/gfx/layers/ipc/LayerTransactionParent.h index 49e65732f252..271d65042305 100644 --- a/gfx/layers/ipc/LayerTransactionParent.h +++ b/gfx/layers/ipc/LayerTransactionParent.h @@ -48,8 +48,7 @@ public: LayerTransactionParent(HostLayerManager* aManager, CompositorBridgeParentBase* aBridge, CompositorAnimationStorage* aAnimStorage, - LayersId aId, - TimeDuration aVsyncRate); + LayersId aId); protected: ~LayerTransactionParent(); @@ -80,13 +79,9 @@ public: bool IsSameProcess() const override; const TransactionId& GetPendingTransactionId() { return mPendingTransaction; } - void SetPendingTransactionId(TransactionId aId, - const TimeStamp& aRefreshStartTime, - const TimeStamp& aTxnStartTime, - const TimeStamp& aFwdTime) + void SetPendingTransactionId(TransactionId aId, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime) { mPendingTransaction = aId; - mRefreshStartTime = aRefreshStartTime; mTxnStartTime = aTxnStartTime; mFwdTime = aFwdTime; } @@ -201,10 +196,7 @@ private: uint64_t mChildEpoch; uint64_t mParentEpoch; - TimeDuration mVsyncRate; - TransactionId mPendingTransaction; - TimeStamp mRefreshStartTime; TimeStamp mTxnStartTime; TimeStamp mFwdTime; diff --git a/gfx/layers/ipc/LayersMessages.ipdlh b/gfx/layers/ipc/LayersMessages.ipdlh index a54e6d33099a..1058b2db71ff 100644 --- a/gfx/layers/ipc/LayersMessages.ipdlh +++ b/gfx/layers/ipc/LayersMessages.ipdlh @@ -572,7 +572,6 @@ struct TransactionInfo bool scheduleComposite; uint32_t paintSequenceNumber; bool isRepeatTransaction; - TimeStamp refreshStart; TimeStamp transactionStart; TimeStamp fwdTime; }; diff --git a/gfx/layers/ipc/PWebRenderBridge.ipdl b/gfx/layers/ipc/PWebRenderBridge.ipdl index 58c8e182aa07..d7168e4feb5f 100644 --- a/gfx/layers/ipc/PWebRenderBridge.ipdl +++ b/gfx/layers/ipc/PWebRenderBridge.ipdl @@ -43,10 +43,10 @@ parent: LayoutSize aContentSize, ByteBuf aDL, BuiltDisplayListDescriptor aDLDesc, WebRenderScrollData aScrollData, OpUpdateResource[] aResourceUpdates, RefCountedShmem[] aSmallShmems, Shmem[] aLargeShmems, - IdNamespace aIdNamespace, TimeStamp refreshStartTime, TimeStamp txnStartTime, TimeStamp fwdTime); + IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime); async EmptyTransaction(FocusTarget focusTarget, ScrollUpdatesMap scrollUpdates, uint32_t aPaintSequenceNumber, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, TransactionId transactionId, - IdNamespace aIdNamespace, TimeStamp refreshStartTime, TimeStamp txnStartTime, TimeStamp fwdTime); + IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime); async SetFocusTarget(FocusTarget focusTarget); async UpdateResources(OpUpdateResource[] aResourceUpdates, RefCountedShmem[] aSmallShmems, Shmem[] aLargeShmems); async ParentCommands(WebRenderParentCommand[] commands); diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index 3f051f91010c..ecc5393bf17d 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -604,7 +604,6 @@ ShadowLayerForwarder::EndTransaction(const nsIntRegion& aRegionToClear, bool aScheduleComposite, uint32_t aPaintSequenceNumber, bool aIsRepeatTransaction, - const mozilla::TimeStamp& aRefreshStart, const mozilla::TimeStamp& aTransactionStart, bool* aSent) { @@ -746,7 +745,6 @@ ShadowLayerForwarder::EndTransaction(const nsIntRegion& aRegionToClear, info.scheduleComposite() = aScheduleComposite; info.paintSequenceNumber() = aPaintSequenceNumber; info.isRepeatTransaction() = aIsRepeatTransaction; - info.refreshStart() = aRefreshStart; info.transactionStart() = aTransactionStart; #if defined(ENABLE_FRAME_LATENCY_LOG) info.fwdTime() = TimeStamp::Now(); diff --git a/gfx/layers/ipc/ShadowLayers.h b/gfx/layers/ipc/ShadowLayers.h index b1a40b9822b3..644057b1e1fa 100644 --- a/gfx/layers/ipc/ShadowLayers.h +++ b/gfx/layers/ipc/ShadowLayers.h @@ -258,7 +258,6 @@ public: bool aScheduleComposite, uint32_t aPaintSequenceNumber, bool aIsRepeatTransaction, - const mozilla::TimeStamp& aRefreshStart, const mozilla::TimeStamp& aTransactionStart, bool* aSent); diff --git a/gfx/layers/wr/WebRenderBridgeChild.cpp b/gfx/layers/wr/WebRenderBridgeChild.cpp index ed29556e6318..73e85bd82580 100644 --- a/gfx/layers/wr/WebRenderBridgeChild.cpp +++ b/gfx/layers/wr/WebRenderBridgeChild.cpp @@ -122,7 +122,6 @@ WebRenderBridgeChild::EndTransaction(const wr::LayoutSize& aContentSize, const gfx::IntSize& aSize, TransactionId aTransactionId, const WebRenderScrollData& aScrollData, - const mozilla::TimeStamp& aRefreshStartTime, const mozilla::TimeStamp& aTxnStartTime) { MOZ_ASSERT(!mDestroyed); @@ -146,7 +145,7 @@ WebRenderBridgeChild::EndTransaction(const wr::LayoutSize& aContentSize, GetFwdTransactionId(), aTransactionId, aContentSize, dlData, aDL.dl_desc, aScrollData, std::move(resourceUpdates), std::move(smallShmems), largeShmems, - mIdNamespace, aRefreshStartTime, aTxnStartTime, fwdTime); + mIdNamespace, aTxnStartTime, fwdTime); mParentCommands.Clear(); mDestroyedActors.Clear(); @@ -158,7 +157,6 @@ WebRenderBridgeChild::EndEmptyTransaction(const FocusTarget& aFocusTarget, const ScrollUpdatesMap& aUpdates, uint32_t aPaintSequenceNumber, TransactionId aTransactionId, - const mozilla::TimeStamp& aRefreshStartTime, const mozilla::TimeStamp& aTxnStartTime) { MOZ_ASSERT(!mDestroyed); @@ -172,7 +170,7 @@ WebRenderBridgeChild::EndEmptyTransaction(const FocusTarget& aFocusTarget, this->SendEmptyTransaction(aFocusTarget, aUpdates, aPaintSequenceNumber, mParentCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId, - mIdNamespace, aRefreshStartTime, aTxnStartTime, fwdTime); + mIdNamespace, aTxnStartTime, fwdTime); mParentCommands.Clear(); mDestroyedActors.Clear(); mIsInTransaction = false; diff --git a/gfx/layers/wr/WebRenderBridgeChild.h b/gfx/layers/wr/WebRenderBridgeChild.h index 4346ca66d264..eeabdacb3c55 100644 --- a/gfx/layers/wr/WebRenderBridgeChild.h +++ b/gfx/layers/wr/WebRenderBridgeChild.h @@ -74,13 +74,11 @@ public: const gfx::IntSize& aSize, TransactionId aTransactionId, const WebRenderScrollData& aScrollData, - const mozilla::TimeStamp& aRefreshStartTime, const mozilla::TimeStamp& aTxnStartTime); void EndEmptyTransaction(const FocusTarget& aFocusTarget, const ScrollUpdatesMap& aUpdates, uint32_t aPaintSequenceNumber, TransactionId aTransactionId, - const mozilla::TimeStamp& aRefreshStartTime, const mozilla::TimeStamp& aTxnStartTime); void ProcessWebRenderParentCommands(); diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp index 5b86aba2da64..bb66f7b3cbd2 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -29,7 +29,6 @@ #include "mozilla/layers/AsyncImagePipelineManager.h" #include "mozilla/layers/WebRenderImageHost.h" #include "mozilla/layers/WebRenderTextureHost.h" -#include "mozilla/Telemetry.h" #include "mozilla/TimeStamp.h" #include "mozilla/Unused.h" #include "mozilla/webrender/RenderThread.h" @@ -164,8 +163,7 @@ WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompos CompositorVsyncScheduler* aScheduler, RefPtr&& aApi, RefPtr&& aImageMgr, - RefPtr&& aAnimStorage, - TimeDuration aVsyncRate) + RefPtr&& aAnimStorage) : mCompositorBridge(aCompositorBridge) , mPipelineId(aPipelineId) , mWidget(aWidget) @@ -181,12 +179,11 @@ WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompos , mDestroyed(false) , mForceRendering(false) , mReceivedDisplayList(false) - , mVsyncRate(aVsyncRate) { MOZ_ASSERT(mAsyncImageManager); MOZ_ASSERT(mAnimStorage); mAsyncImageManager->AddPipeline(mPipelineId); - if (IsRootWebRenderBridgeParent()) { + if (mWidget) { MOZ_ASSERT(!mCompositorScheduler); mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget); } @@ -504,12 +501,6 @@ WebRenderBridgeParent::RemoveEpochDataPriorTo(const wr::Epoch& aRenderedEpoch) } } -bool -WebRenderBridgeParent::IsRootWebRenderBridgeParent() const -{ - return !!mWidget; -} - CompositorBridgeParent* WebRenderBridgeParent::GetRootCompositorBridgeParent() const { @@ -517,7 +508,7 @@ WebRenderBridgeParent::GetRootCompositorBridgeParent() const return nullptr; } - if (IsRootWebRenderBridgeParent()) { + if (mWidget) { // This WebRenderBridgeParent is attached to the root // CompositorBridgeParent. return static_cast(mCompositorBridge); @@ -620,7 +611,6 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize, nsTArray&& aSmallShmems, nsTArray&& aLargeShmems, const wr::IdNamespace& aIdNamespace, - const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime) { @@ -668,7 +658,7 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize, // because the tab just moved to a new window. // In that case do not send the commands to webrender. if (mIdNamespace == aIdNamespace) { - if (IsRootWebRenderBridgeParent()) { + if (mWidget) { LayoutDeviceIntSize widgetSize = mWidget->GetClientSize(); LayoutDeviceIntRect docRect(LayoutDeviceIntPoint(), widgetSize); txn.SetWindowParameters(widgetSize, docRect); @@ -694,7 +684,7 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize, } } - HoldPendingTransactionId(wrEpoch, aTransactionId, aRefreshStartTime, aTxnStartTime, aFwdTime); + HoldPendingTransactionId(wrEpoch, aTransactionId, aTxnStartTime, aFwdTime); if (mIdNamespace != aIdNamespace) { // Pretend we composited since someone is wating for this event, @@ -721,7 +711,6 @@ WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget, const uint64_t& aFwdTransactionId, const TransactionId& aTransactionId, const wr::IdNamespace& aIdNamespace, - const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime) { @@ -773,7 +762,7 @@ WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget, sendDidComposite = false; } - HoldPendingTransactionId(WrEpoch(), aTransactionId, aRefreshStartTime, aTxnStartTime, aFwdTime); + HoldPendingTransactionId(WrEpoch(), aTransactionId, aTxnStartTime, aFwdTime); if (scheduleComposite) { ScheduleGenerateFrame(); @@ -905,7 +894,7 @@ void WebRenderBridgeParent::FlushFrameGeneration() { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - MOZ_ASSERT(IsRootWebRenderBridgeParent()); // This function is only useful on the root WRBP + MOZ_ASSERT(mWidget); // This function is only useful on the root WRBP // This forces a new GenerateFrame transaction to be sent to the render // backend thread, if one is pending. This doesn't block on any other threads. @@ -940,7 +929,7 @@ WebRenderBridgeParent::RecvGetSnapshot(PTextureParent* aTexture) // but it will have no effect because CompositeToTarget (which reads the // flag) only gets invoked in the root WRBP. So we assert that this is the // root WRBP (i.e. has a non-null mWidget) to catch violations of this rule. - MOZ_ASSERT(IsRootWebRenderBridgeParent()); + MOZ_ASSERT(mWidget); RefPtr texture = TextureHost::AsTextureHost(aTexture); if (!texture) { @@ -1135,7 +1124,7 @@ WebRenderBridgeParent::UpdateWebRender(CompositorVsyncScheduler* aScheduler, CompositorAnimationStorage* aAnimStorage, const TextureFactoryIdentifier& aTextureFactoryIdentifier) { - MOZ_ASSERT(!IsRootWebRenderBridgeParent()); + MOZ_ASSERT(!mWidget); MOZ_ASSERT(aScheduler); MOZ_ASSERT(aApi); MOZ_ASSERT(aImageMgr); @@ -1389,7 +1378,7 @@ void WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect) { // This function should only get called in the root WRBP - MOZ_ASSERT(IsRootWebRenderBridgeParent()); + MOZ_ASSERT(mWidget); // The two arguments are part of the CompositorVsyncSchedulerOwner API but in // this implementation they should never be non-null. @@ -1471,16 +1460,11 @@ WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::In void WebRenderBridgeParent::HoldPendingTransactionId(const wr::Epoch& aWrEpoch, TransactionId aTransactionId, - const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime) { MOZ_ASSERT(aTransactionId > LastPendingTransactionId()); - mPendingTransactionIds.push(PendingTransactionId(aWrEpoch, - aTransactionId, - aRefreshStartTime, - aTxnStartTime, - aFwdTime)); + mPendingTransactionIds.push(PendingTransactionId(aWrEpoch, aTransactionId, aTxnStartTime, aFwdTime)); } TransactionId @@ -1512,21 +1496,13 @@ WebRenderBridgeParent::FlushTransactionIdsForEpoch(const wr::Epoch& aEpoch, cons if (aEpoch.mHandle < mPendingTransactionIds.front().mEpoch.mHandle) { break; } - - if (!IsRootWebRenderBridgeParent() && !mVsyncRate.IsZero()) { - double latencyMs = (aEndTime - mPendingTransactionIds.front().mTxnStartTime).ToMilliseconds(); - double latencyNorm = latencyMs / mVsyncRate.ToMilliseconds(); - int32_t fracLatencyNorm = lround(latencyNorm * 100.0); - Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME, fracLatencyNorm); - } - #if defined(ENABLE_FRAME_LATENCY_LOG) - if (mPendingTransactionIds.front().mRefreshStartTime) { - int32_t latencyMs = lround((aEndTime - mPendingTransactionIds.front().mRefreshStartTime).ToMilliseconds()); + if (mPendingTransactionIds.front().mTxnStartTime) { + uint32_t latencyMs = round((aEndTime - mPendingTransactionIds.front().mTxnStartTime).ToMilliseconds()); printf_stderr("From transaction start to end of generate frame latencyMs %d this %p\n", latencyMs, this); } if (mPendingTransactionIds.front().mFwdTime) { - int32_t latencyMs = lround((aEndTime - mPendingTransactionIds.front().mFwdTime).ToMilliseconds()); + uint32_t latencyMs = round((aEndTime - mPendingTransactionIds.front().mFwdTime).ToMilliseconds()); printf_stderr("From forwarding transaction to end of generate frame latencyMs %d this %p\n", latencyMs, this); } #endif @@ -1576,9 +1552,9 @@ WebRenderBridgeParent::FlushRenderingAsync() void WebRenderBridgeParent::Pause() { - MOZ_ASSERT(IsRootWebRenderBridgeParent()); + MOZ_ASSERT(mWidget); #ifdef MOZ_WIDGET_ANDROID - if (!IsRootWebRenderBridgeParent() || mDestroyed) { + if (!mWidget || mDestroyed) { return; } mApi->Pause(); @@ -1589,9 +1565,9 @@ WebRenderBridgeParent::Pause() bool WebRenderBridgeParent::Resume() { - MOZ_ASSERT(IsRootWebRenderBridgeParent()); + MOZ_ASSERT(mWidget); #ifdef MOZ_WIDGET_ANDROID - if (!IsRootWebRenderBridgeParent() || mDestroyed) { + if (!mWidget || mDestroyed) { return false; } @@ -1647,7 +1623,7 @@ WebRenderBridgeParent::ClearResources() mActiveAnimations.clear(); std::queue().swap(mCompositorAnimationsToDelete); // clear queue - if (IsRootWebRenderBridgeParent()) { + if (mWidget) { mCompositorScheduler->Destroy(); } @@ -1763,7 +1739,7 @@ WebRenderBridgeParent::GetNextWrEpoch() void WebRenderBridgeParent::ExtractImageCompositeNotifications(nsTArray* aNotifications) { - MOZ_ASSERT(IsRootWebRenderBridgeParent()); + MOZ_ASSERT(mWidget); if (mDestroyed) { return; } diff --git a/gfx/layers/wr/WebRenderBridgeParent.h b/gfx/layers/wr/WebRenderBridgeParent.h index 784f5b013a79..180e9c273b8c 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.h +++ b/gfx/layers/wr/WebRenderBridgeParent.h @@ -53,8 +53,7 @@ public: CompositorVsyncScheduler* aScheduler, RefPtr&& aApi, RefPtr&& aImageMgr, - RefPtr&& aAnimStorage, - TimeDuration aVsyncRate); + RefPtr&& aAnimStorage); static WebRenderBridgeParent* CreateDestroyed(const wr::PipelineId& aPipelineId); @@ -88,7 +87,6 @@ public: nsTArray&& aSmallShmems, nsTArray&& aLargeShmems, const wr::IdNamespace& aIdNamespace, - const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime) override; mozilla::ipc::IPCResult RecvEmptyTransaction(const FocusTarget& aFocusTarget, @@ -99,7 +97,6 @@ public: const uint64_t& aFwdTransactionId, const TransactionId& aTransactionId, const wr::IdNamespace& aIdNamespace, - const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime) override; mozilla::ipc::IPCResult RecvSetFocusTarget(const FocusTarget& aFocusTarget) override; @@ -153,7 +150,6 @@ public: void HoldPendingTransactionId(const wr::Epoch& aWrEpoch, TransactionId aTransactionId, - const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime); TransactionId LastPendingTransactionId(); @@ -234,8 +230,6 @@ private: bool SampleAnimations(nsTArray& aOpacityArray, nsTArray& aTransformArray); - bool IsRootWebRenderBridgeParent() const; - CompositorBridgeParent* GetRootCompositorBridgeParent() const; RefPtr GetRootWebRenderBridgeParent() const; @@ -251,20 +245,14 @@ private: private: struct PendingTransactionId { - PendingTransactionId(const wr::Epoch& aEpoch, - TransactionId aId, - const TimeStamp& aRefreshStartTime, - const TimeStamp& aTxnStartTime, - const TimeStamp& aFwdTime) + PendingTransactionId(const wr::Epoch& aEpoch, TransactionId aId, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime) : mEpoch(aEpoch) , mId(aId) - , mRefreshStartTime(aRefreshStartTime) , mTxnStartTime(aTxnStartTime) , mFwdTime(aFwdTime) {} wr::Epoch mEpoch; TransactionId mId; - TimeStamp mRefreshStartTime; TimeStamp mTxnStartTime; TimeStamp mFwdTime; }; @@ -294,7 +282,6 @@ private: nsDataHashtable> mExternalImageIds; nsTHashtable mSharedSurfaceIds; - TimeDuration mVsyncRate; TimeStamp mPreviousFrameTimeStamp; // These fields keep track of the latest layer observer epoch values in the child and the // parent. mChildLayerObserverEpoch is the latest epoch value received from the child. diff --git a/gfx/layers/wr/WebRenderLayerManager.cpp b/gfx/layers/wr/WebRenderLayerManager.cpp index 82567ab42dfc..29bcbb62636e 100644 --- a/gfx/layers/wr/WebRenderLayerManager.cpp +++ b/gfx/layers/wr/WebRenderLayerManager.cpp @@ -168,8 +168,6 @@ WebRenderLayerManager::BeginTransaction() return false; } - mTransactionStart = TimeStamp::Now(); - // Increment the paint sequence number even if test logging isn't // enabled in this process; it may be enabled in the parent process, // and the parent process expects unique sequence numbers. @@ -210,7 +208,7 @@ WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) mWebRenderCommandBuilder.EmptyTransaction(); mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(/*aThrottle*/ true); - TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart(); + TimeStamp transactionStart = mTransactionIdAllocator->GetTransactionStart(); // Skip the synchronization for buffer since we also skip the painting during // device-reset status. @@ -222,11 +220,9 @@ WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) } WrBridge()->EndEmptyTransaction(mFocusTarget, mPendingScrollUpdates, - mPaintSequenceNumber, mLatestTransactionId, refreshStart, mTransactionStart); + mPaintSequenceNumber, mLatestTransactionId, transactionStart); ClearPendingScrollInfoUpdate(); - mTransactionStart = TimeStamp(); - MakeSnapshotIfRequired(size); return true; } @@ -312,7 +308,7 @@ WebRenderLayerManager::EndTransactionWithoutLayer(nsDisplayList* aDisplayList, ClearPendingScrollInfoUpdate(); mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(/*aThrottle*/ true); - TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart(); + TimeStamp transactionStart = mTransactionIdAllocator->GetTransactionStart(); for (const auto& key : mImageKeysToDelete) { resourceUpdates.DeleteImage(key); @@ -341,11 +337,9 @@ WebRenderLayerManager::EndTransactionWithoutLayer(nsDisplayList* aDisplayList, { AUTO_PROFILER_TRACING("Paint", "ForwardDPTransaction"); WrBridge()->EndTransaction(contentSize, dl, resourceUpdates, size.ToUnknownSize(), - mLatestTransactionId, mScrollData, refreshStart, mTransactionStart); + mLatestTransactionId, mScrollData, transactionStart); } - mTransactionStart = TimeStamp(); - MakeSnapshotIfRequired(size); mNeedsComposite = false; } diff --git a/gfx/layers/wr/WebRenderLayerManager.h b/gfx/layers/wr/WebRenderLayerManager.h index 2ca5aa2f0e8c..f7e1f4be3bf8 100644 --- a/gfx/layers/wr/WebRenderLayerManager.h +++ b/gfx/layers/wr/WebRenderLayerManager.h @@ -212,7 +212,6 @@ private: // See equivalent field in ClientLayerManager APZTestData mApzTestData; - TimeStamp mTransactionStart; WebRenderCommandBuilder mWebRenderCommandBuilder; size_t mLastDisplayListSize; diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 12eac0eba10a..0ea5794a41c1 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -12801,16 +12801,6 @@ "n_buckets": 50, "description": "Time spent in the paint pipeline for content in milliseconds." }, - "CONTENT_FRAME_TIME": { - "record_in_processes": ["main", "gpu"], - "alert_emails": ["rhunt@mozilla.com","gfx-telemetry-alerts@mozilla.com"], - "bug_numbers": [1470528], - "expires_in_version": "66", - "kind": "exponential", - "high": 5000, - "n_buckets": 50, - "description": "The time, in percentage of a vsync interval, spent from beginning a paint in the content process until that frame is presented in the compositor." - }, "CONTENT_LARGE_PAINT_PHASE_WEIGHT": { "record_in_processes": ["main", "content"], "alert_emails": ["mwoodrow@mozilla.com","gfx-telemetry-alerts@mozilla.com"], From 96d0b4cc2e482aecf1750c02043e232ff8672399 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Tue, 3 Jul 2018 17:48:53 -0400 Subject: [PATCH 10/57] Bug 1472829. Add use counters for document.open. r=smaug The idea is to count non-no-op document.open and to count how many times that's done with the replace argument set to "replace". --- dom/base/UseCounters.conf | 4 ++++ dom/html/nsHTMLDocument.cpp | 11 +++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/dom/base/UseCounters.conf b/dom/base/UseCounters.conf index 3bdbfb45e8a8..bd06d3075c8e 100644 --- a/dom/base/UseCounters.conf +++ b/dom/base/UseCounters.conf @@ -115,3 +115,7 @@ method console.exception method console.timeStamp method console.profile method console.profileEnd + +// document.open information +custom DocumentOpen calls document.open in a way that creates a new Window object +custom DocumentOpenReplace calls document.open in a way that creates a new Window object and replaces the old history entry. diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp index fd1ca5e806e2..b1b80dcd6ce3 100644 --- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -1339,6 +1339,14 @@ nsHTMLDocument::Open(JSContext* cx, return nullptr; } + // At this point we know this is a valid-enough document.open() call + // and not a no-op. Increment our use counters. + SetDocumentAndPageUseCounter(eUseCounter_custom_DocumentOpen); + bool isReplace = aReplace.LowerCaseEqualsLiteral("replace"); + if (isReplace) { + SetDocumentAndPageUseCounter(eUseCounter_custom_DocumentOpenReplace); + } + // Stop current loads targeted at the window this document is in. if (mScriptGlobalObject) { nsCOMPtr cv; @@ -1567,8 +1575,7 @@ nsHTMLDocument::Open(JSContext* cx, // so, we need to tell the docshell to not create a new history // entry for this load. Otherwise, make sure that we're doing a normal load, // not whatever type of load was previously done on this docshell. - shell->SetLoadType(aReplace.LowerCaseEqualsLiteral("replace") ? - LOAD_NORMAL_REPLACE : LOAD_NORMAL); + shell->SetLoadType(isReplace ? LOAD_NORMAL_REPLACE : LOAD_NORMAL); nsCOMPtr cv; shell->GetContentViewer(getter_AddRefs(cv)); From 2a544047c67a28771b1f700c954b0d21f8aa4c70 Mon Sep 17 00:00:00 2001 From: Rok Garbas Date: Tue, 3 Jul 2018 15:35:58 -0700 Subject: [PATCH 11/57] Bug 1471541 - switch to new tooltool url, r=jlund --HG-- extra : rebase_source : 85cd6f1e78ec293d5c9fba8d41b31b5ca8bc521e --- python/mozboot/bin/bootstrap-msys2.vbs | 2 +- testing/mozharness/configs/android/android_hw.py | 2 +- testing/mozharness/configs/repackage/win32_partner.py | 2 +- testing/mozharness/configs/repackage/win64_partner.py | 2 +- tools/lint/eslint/eslint-plugin-mozilla/update.sh | 8 ++++---- tools/lint/eslint/update.sh | 8 ++++---- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/python/mozboot/bin/bootstrap-msys2.vbs b/python/mozboot/bin/bootstrap-msys2.vbs index 9d1d5ee871aa..2573d3765bfc 100644 --- a/python/mozboot/bin/bootstrap-msys2.vbs +++ b/python/mozboot/bin/bootstrap-msys2.vbs @@ -69,7 +69,7 @@ On Error GoTo 0 ' Download installer On Error Resume Next Download "https://conemu.github.io/install2.ps1", "install2.ps1" -conemuSettingsURI = "https://api.pub.build.mozilla.org/tooltool/sha512/9aa384ecc8025a974999e913c83064b3b797e05d19806e62ef558c8300e4c3f72967e9464ace59759f76216fc2fc66f338a1e5cdea3b9aa264529487f091d929" +conemuSettingsURI = "https://tooltool.mozilla-releng.net/sha512/9aa384ecc8025a974999e913c83064b3b797e05d19806e62ef558c8300e4c3f72967e9464ace59759f76216fc2fc66f338a1e5cdea3b9aa264529487f091d929" ' Run installer errorCode = shell.Run("powershell.exe -NoProfile -ExecutionPolicy Unrestricted set dst '" & conemuPath & "'; set ver 'stable'; set lnk 'Mozilla Development Shell'; set xml '" & conemuSettingsURI & "'; set run $FALSE; .\install2.ps1", 0, true) ' Delete ConEmu installer diff --git a/testing/mozharness/configs/android/android_hw.py b/testing/mozharness/configs/android/android_hw.py index e7d0f47e5cfb..80b8176db8cb 100644 --- a/testing/mozharness/configs/android/android_hw.py +++ b/testing/mozharness/configs/android/android_hw.py @@ -23,7 +23,7 @@ config = { # from android_common.py "download_tooltool": True, "download_minidump_stackwalk": True, - "tooltool_servers": ['https://api.pub.build.mozilla.org/tooltool/'], + "tooltool_servers": ['https://tooltool.mozilla-releng.net/'], # minidump_tooltool_manifest_path is relative to workspace/build/tests/ "minidump_tooltool_manifest_path": "config/tooltool-manifests/linux64/releng.manifest", "xpcshell_extra": "--remoteTestRoot=/data/local/tests", diff --git a/testing/mozharness/configs/repackage/win32_partner.py b/testing/mozharness/configs/repackage/win32_partner.py index 5289d6dfc188..6e42bf727de9 100644 --- a/testing/mozharness/configs/repackage/win32_partner.py +++ b/testing/mozharness/configs/repackage/win32_partner.py @@ -29,7 +29,7 @@ config = { # ToolTool "tooltool_manifest_src": 'browser\\config\\tooltool-manifests\\{}\\releng.manifest'.format(platform), - 'tooltool_url': 'https://api.pub.build.mozilla.org/tooltool/', + 'tooltool_url': 'https://tooltool.mozilla-releng.net/', 'tooltool_cache': os.environ.get('TOOLTOOL_CACHE'), 'run_configure': False, diff --git a/testing/mozharness/configs/repackage/win64_partner.py b/testing/mozharness/configs/repackage/win64_partner.py index 8978111ece63..504346098c5e 100644 --- a/testing/mozharness/configs/repackage/win64_partner.py +++ b/testing/mozharness/configs/repackage/win64_partner.py @@ -29,7 +29,7 @@ config = { # ToolTool "tooltool_manifest_src": 'browser\\config\\tooltool-manifests\\{}\\releng.manifest'.format(platform), - 'tooltool_url': 'https://api.pub.build.mozilla.org/tooltool/', + 'tooltool_url': 'https://tooltool.mozilla-releng.net/', 'tooltool_cache': os.environ.get('TOOLTOOL_CACHE'), 'run_configure': False, diff --git a/tools/lint/eslint/eslint-plugin-mozilla/update.sh b/tools/lint/eslint/eslint-plugin-mozilla/update.sh index c6a106ba5acf..d8ee4098ec5e 100755 --- a/tools/lint/eslint/eslint-plugin-mozilla/update.sh +++ b/tools/lint/eslint/eslint-plugin-mozilla/update.sh @@ -6,7 +6,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $DIR -echo "To complete this script you will need the following tokens from https://api.pub.build.mozilla.org/tokenauth/" +echo "To complete this script you will need the following tokens from https://mozilla-releng.net/tokens" echo " - tooltool.upload.public" echo " - tooltool.download.public" echo "" @@ -14,7 +14,7 @@ read -p "Are these tokens visible at the above URL (y/n)?" choice case "$choice" in y|Y ) echo "" - echo "1. Go to https://api.pub.build.mozilla.org/" + echo "1. Go to https://mozilla-releng.net" echo "2. Log in using your Mozilla LDAP account." echo "3. Click on \"Tokens.\"" echo "4. Issue a user token with the permissions tooltool.upload.public and tooltool.download.public." @@ -49,10 +49,10 @@ tar cvz -f eslint-plugin-mozilla.tar.gz node_modules echo "Adding eslint-plugin-mozilla.tar.gz to tooltool..." rm -f manifest.tt -../../../../python/mozbuild/mozbuild/action/tooltool.py add --visibility public --unpack eslint-plugin-mozilla.tar.gz --url="https://api.pub.build.mozilla.org/tooltool/" +../../../../python/mozbuild/mozbuild/action/tooltool.py add --visibility public --unpack eslint-plugin-mozilla.tar.gz --url="https://tooltool.mozilla-releng.net/" echo "Uploading eslint-plugin-mozilla.tar.gz to tooltool..." -../../../../python/mozbuild/mozbuild/action/tooltool.py upload --authentication-file=~/.tooltool-token --message "node_modules folder update for tools/lint/eslint/eslint-plugin-mozilla" --url="https://api.pub.build.mozilla.org/tooltool/" +../../../../python/mozbuild/mozbuild/action/tooltool.py upload --authentication-file=~/.tooltool-token --message "node_modules folder update for tools/lint/eslint/eslint-plugin-mozilla" --url="https://tooltool.mozilla-releng.net/" echo "Cleaning up..." rm eslint-plugin-mozilla.tar.gz diff --git a/tools/lint/eslint/update.sh b/tools/lint/eslint/update.sh index f1251cb2f9cd..dbf9e40e9036 100755 --- a/tools/lint/eslint/update.sh +++ b/tools/lint/eslint/update.sh @@ -6,7 +6,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $DIR -echo "To complete this script you will need the following tokens from https://api.pub.build.mozilla.org/tokenauth/" +echo "To complete this script you will need the following tokens from https://mozilla-releng.net/tokens" echo " - tooltool.upload.public" echo " - tooltool.download.public" echo "" @@ -14,7 +14,7 @@ read -p "Are these tokens visible at the above URL (y/n)?" choice case "$choice" in y|Y ) echo "" - echo "1. Go to https://api.pub.build.mozilla.org/" + echo "1. Go to https://mozilla-releng.net" echo "2. Log in using your Mozilla LDAP account." echo "3. Click on \"Tokens.\"" echo "4. Issue a user token with the permissions tooltool.upload.public and tooltool.download.public." @@ -56,10 +56,10 @@ tar cvz --exclude=eslint-plugin-mozilla --exclude=eslint-plugin-spidermonkey-js echo "Adding eslint.tar.gz to tooltool..." rm tools/lint/eslint/manifest.tt -./python/mozbuild/mozbuild/action/tooltool.py add --visibility public --unpack eslint.tar.gz --url="https://api.pub.build.mozilla.org/tooltool/" +./python/mozbuild/mozbuild/action/tooltool.py add --visibility public --unpack eslint.tar.gz --url="https://tooltool.mozilla-releng.net/" echo "Uploading eslint.tar.gz to tooltool..." -./python/mozbuild/mozbuild/action/tooltool.py upload --authentication-file=~/.tooltool-token --message "node_modules folder update for tools/lint/eslint" --url="https://api.pub.build.mozilla.org/tooltool/" +./python/mozbuild/mozbuild/action/tooltool.py upload --authentication-file=~/.tooltool-token --message "node_modules folder update for tools/lint/eslint" --url="https://tooltool.mozilla-releng.net/" echo "Cleaning up..." mv manifest.tt tools/lint/eslint/manifest.tt From a95db7c11a1eb1d47342dce9e711b49666a22213 Mon Sep 17 00:00:00 2001 From: Bas Schouten Date: Tue, 3 Jul 2018 23:07:44 +0000 Subject: [PATCH 12/57] Bug 1473136: Cache mNeedsActiveLayer once for nsDisplayOpacity. r=mattwoodrow --- layout/generic/nsFrame.cpp | 9 ++++++--- layout/painting/nsDisplayList.cpp | 8 +++++--- layout/painting/nsDisplayList.h | 5 ++++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 6cb197a40047..52cc283ef2f5 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -2952,6 +2952,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, aBuilder->EnterSVGEffectsContents(&hoistedScrollInfoItemsStorage); } + + bool needsActiveOpacityLayer = false; // We build an opacity item if it's not going to be drawn by SVG content, or // SVG effects. SVG effects won't handle the opacity if we want an active // layer (for async animations), see @@ -2959,7 +2961,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, // nsSVGIntegrationsUtils::PaintFilter. bool useOpacity = HasVisualOpacity(effectSet) && !nsSVGUtils::CanOptimizeOpacity(this) && - (!usingSVGEffects || nsDisplayOpacity::NeedsActiveLayer(aBuilder, this)); + ((needsActiveOpacityLayer = nsDisplayOpacity::NeedsActiveLayer(aBuilder, this)) || !usingSVGEffects); bool useBlendMode = effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL; bool useStickyPosition = disp->mPosition == NS_STYLE_POSITION_STICKY && IsScrollFrameActive(aBuilder, @@ -3259,9 +3261,10 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, // all descendant content, but some should not be clipped. DisplayListClipState::AutoSaveRestore opacityClipState(aBuilder); resultList.AppendToTop( - MakeDisplayItem(aBuilder, this, &resultList, + MakeDisplayItem(aBuilder, this, &resultList, containerItemASR, - opacityItemForEventsAndPluginsOnly)); + opacityItemForEventsAndPluginsOnly, + needsActiveOpacityLayer)); if (aCreatedContainerItem) { *aCreatedContainerItem = true; } diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index 18f7f46d72bd..6a71834d58ee 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -6237,10 +6237,12 @@ nsresult nsDisplayWrapper::WrapListsInPlace(nsDisplayListBuilder* aBuilder, nsDisplayOpacity::nsDisplayOpacity(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList, const ActiveScrolledRoot* aActiveScrolledRoot, - bool aForEventsAndPluginsOnly) + bool aForEventsAndPluginsOnly, + bool aNeedsActiveLayer) : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, true) , mOpacity(aFrame->StyleEffects()->mOpacity) , mForEventsAndPluginsOnly(aForEventsAndPluginsOnly) + , mNeedsActiveLayer(aNeedsActiveLayer) , mChildOpacityState(ChildOpacityState::Unknown) { MOZ_COUNT_CTOR(nsDisplayOpacity); @@ -6434,7 +6436,7 @@ nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder) return false; } - if (NeedsActiveLayer(aBuilder, mFrame) || mOpacity == 0.0) { + if (mNeedsActiveLayer || mOpacity == 0.0) { // If our opacity is zero then we'll discard all descendant display items // except for layer event regions, so there's no point in doing this // optimization (and if we do do it, then invalidations of those descendants @@ -6464,7 +6466,7 @@ nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder, return LAYER_INACTIVE; } - if (NeedsActiveLayer(aBuilder, mFrame)) { + if (mNeedsActiveLayer) { // Returns LAYER_ACTIVE_FORCE to avoid flatterning the layer for async // animations. return LAYER_ACTIVE_FORCE; diff --git a/layout/painting/nsDisplayList.h b/layout/painting/nsDisplayList.h index 1a0c1aa5d7eb..3a948ffcbd5b 100644 --- a/layout/painting/nsDisplayList.h +++ b/layout/painting/nsDisplayList.h @@ -5121,13 +5121,15 @@ public: nsDisplayOpacity(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList, const ActiveScrolledRoot* aActiveScrolledRoot, - bool aForEventsAndPluginsOnly); + bool aForEventsAndPluginsOnly, + bool aNeedsActiveLayer); nsDisplayOpacity(nsDisplayListBuilder* aBuilder, const nsDisplayOpacity& aOther) : nsDisplayWrapList(aBuilder, aOther) , mOpacity(aOther.mOpacity) , mForEventsAndPluginsOnly(aOther.mForEventsAndPluginsOnly) + , mNeedsActiveLayer(aOther.mNeedsActiveLayer) , mChildOpacityState(ChildOpacityState::Unknown) { // We should not try to merge flattened opacities. @@ -5225,6 +5227,7 @@ private: // Opacity is applied to our children. Applied }; + bool mNeedsActiveLayer : 1; #ifndef __GNUC__ ChildOpacityState mChildOpacityState : 2; #else From 4cb1d86ef09413ccf4294419430484b1251a750d Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:48:05 -0600 Subject: [PATCH 13/57] Bug 1460022: Part 1 - Modify DLL interceptor to use one-time initialization when setting hooks; r=handyman This patch makes the interceptor's AddHook functions private, and converts the stubs from simple function pointers into objects containing both the stub function pointer, plus a INIT_ONCE sentinel. Setting a hook now requires calling Set or SetDetour on the stub, which ensures that the hook attempt happens once and only once. The constructor for the new object is constexpr, so it should not generate static initializers if it is declared statically. Note that, as a corollary of the new behaviour, we no longer need to set guards around any hook setting code. I have removed those when present. --HG-- extra : rebase_source : 260ec9f99839468d9994186fddd7cf2b33e6c87d --- mozglue/misc/nsWindowsDllInterceptor.h | 153 ++++++++++++++++++++++++- 1 file changed, 151 insertions(+), 2 deletions(-) diff --git a/mozglue/misc/nsWindowsDllInterceptor.h b/mozglue/misc/nsWindowsDllInterceptor.h index 3020f795fede..4ae504257b56 100644 --- a/mozglue/misc/nsWindowsDllInterceptor.h +++ b/mozglue/misc/nsWindowsDllInterceptor.h @@ -8,10 +8,12 @@ #define NS_WINDOWS_DLL_INTERCEPTOR_H_ #include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" #include "mozilla/ArrayUtils.h" #include "mozilla/CheckedInt.h" #include "mozilla/DebugOnly.h" -#include "mozilla/NotNull.h" +#include "mozilla/Move.h" +#include "mozilla/Tuple.h" #include "mozilla/TypeTraits.h" #include "mozilla/Types.h" #include "mozilla/UniquePtr.h" @@ -82,6 +84,143 @@ namespace mozilla { namespace interceptor { +template +class FuncHook final +{ + template + struct OriginalFunctionPtrTraits; + + template + struct OriginalFunctionPtrTraits + { + using ReturnType = R; + }; + +#if defined(_M_IX86) + template + struct OriginalFunctionPtrTraits + { + using ReturnType = R; + }; + + template + struct OriginalFunctionPtrTraits + { + using ReturnType = R; + }; +#endif // defined(_M_IX86) + +public: + using ThisType = FuncHook; + using ReturnType = typename OriginalFunctionPtrTraits::ReturnType; + + constexpr FuncHook() + : mOrigFunc(nullptr) + , mInitOnce(INIT_ONCE_STATIC_INIT) + { + } + + ~FuncHook() = default; + + bool Set(InterceptorT& aInterceptor, const char* aName, + FuncPtrT aHookDest) + { + LPVOID addHookOk; + InitOnceContext ctx(this, &aInterceptor, aName, aHookDest, false); + + return ::InitOnceExecuteOnce(&mInitOnce, &InitOnceCallback, &ctx, + &addHookOk) && addHookOk; + } + + bool SetDetour(InterceptorT& aInterceptor, const char* aName, + FuncPtrT aHookDest) + { + LPVOID addHookOk; + InitOnceContext ctx(this, &aInterceptor, aName, aHookDest, true); + + return ::InitOnceExecuteOnce(&mInitOnce, &InitOnceCallback, &ctx, + &addHookOk) && addHookOk; + } + + explicit operator bool() const + { + return !!mOrigFunc; + } + + template + ReturnType operator()(ArgsType... aArgs) const + { + return mOrigFunc(std::forward(aArgs)...); + } + + FuncPtrT GetStub() const + { + return mOrigFunc; + } + + // One-time init stuff cannot be moved or copied + FuncHook(const FuncHook&) = delete; + FuncHook(FuncHook&&) = delete; + FuncHook& operator=(const FuncHook&) = delete; + FuncHook& operator=(FuncHook&& aOther) = delete; + +private: + struct MOZ_RAII InitOnceContext final + { + InitOnceContext(ThisType* aHook, InterceptorT* aInterceptor, + const char* aName, void* aHookDest, bool aForceDetour) + : mHook(aHook) + , mInterceptor(aInterceptor) + , mName(aName) + , mHookDest(aHookDest) + , mForceDetour(aForceDetour) + { + } + + ThisType* mHook; + InterceptorT* mInterceptor; + const char* mName; + void* mHookDest; + bool mForceDetour; + }; + +private: + bool Apply(InterceptorT* aInterceptor, const char* aName, void* aHookDest) + { + return aInterceptor->AddHook(aName, reinterpret_cast(aHookDest), + reinterpret_cast(&mOrigFunc)); + } + + bool ApplyDetour(InterceptorT* aInterceptor, const char* aName, + void* aHookDest) + { + return aInterceptor->AddDetour(aName, reinterpret_cast(aHookDest), + reinterpret_cast(&mOrigFunc)); + } + + static BOOL CALLBACK + InitOnceCallback(PINIT_ONCE aInitOnce, PVOID aParam, PVOID* aOutContext) + { + MOZ_ASSERT(aOutContext); + + bool result; + auto ctx = reinterpret_cast(aParam); + if (ctx->mForceDetour) { + result = ctx->mHook->ApplyDetour(ctx->mInterceptor, ctx->mName, + ctx->mHookDest); + } else { + result = ctx->mHook->Apply(ctx->mInterceptor, ctx->mName, ctx->mHookDest); + } + + *aOutContext = result ? reinterpret_cast(1U << INIT_ONCE_CTX_RESERVED_BITS) : nullptr; + return TRUE; + } + +private: + FuncPtrT mOrigFunc; + INIT_ONCE mInitOnce; +}; + enum { kDefaultTrampolineSize = 128 @@ -92,6 +231,8 @@ template > class WindowsDllInterceptor final { + typedef WindowsDllInterceptor ThisType; + interceptor::WindowsDllDetourPatcher mDetourPatcher; #if defined(_M_IX86) interceptor::WindowsDllNopSpacePatcher mNopSpacePatcher; @@ -160,6 +301,7 @@ public: // NB: We intentionally leak mModule } +private: /** * Hook/detour the method aName from the DLL we set in Init so that it calls * aHookDest instead. Returns the original method pointer in aOrigFunc @@ -219,7 +361,6 @@ public: return AddDetour(proc, aHookDest, aOrigFunc); } -private: bool AddDetour(FARPROC aProc, intptr_t aHookDest, void** aOrigFunc) { MOZ_ASSERT(mModule && aProc); @@ -230,6 +371,14 @@ private: return mDetourPatcher.AddHook(aProc, aHookDest, aOrigFunc); } + +public: + template + using FuncHookType = FuncHook; + +private: + template + friend class FuncHook; }; } // namespace interceptor From 9c86a6adcd08848e120dd9d2968c07bbc2dbf2c0 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:48:28 -0600 Subject: [PATCH 14/57] Bug 1460022: Part 2 - Update TestDllInterceptor to use new DLL interceptor interface; r=handyman In addition to updating the interface, this patch also significantly alters the structure of this test. In particular, it removes the Test* functions in favour of using template magic. I did this because I noticed that, in the majority of cases, the stub function was being called with all zero arguments, and then we check for the expected error code. I thought that maybe we could replace that repetition with some templates that instantiate a blank tuple that may then be applied to a callable object. See the (MAYBE_)TEST_HOOK* and TEST_DETOUR* macro definitions for detailed information about how to use these things. The test successfully completes with both 32-bit and 64-bit builds. --HG-- extra : rebase_source : 95e9a3386c0a6c5f9f78b1e8fa5a88c1c30e9b51 --- .../tests/interceptor/TestDllInterceptor.cpp | 857 +++++++----------- 1 file changed, 330 insertions(+), 527 deletions(-) diff --git a/mozglue/tests/interceptor/TestDllInterceptor.cpp b/mozglue/tests/interceptor/TestDllInterceptor.cpp index 6007a8995201..989ee97d0b28 100644 --- a/mozglue/tests/interceptor/TestDllInterceptor.cpp +++ b/mozglue/tests/interceptor/TestDllInterceptor.cpp @@ -10,10 +10,33 @@ #include #include +#include "mozilla/TypeTraits.h" +#include "mozilla/UniquePtr.h" #include "mozilla/WindowsVersion.h" #include "nsWindowsDllInterceptor.h" #include "nsWindowsHelpers.h" +NTSTATUS NTAPI NtFlushBuffersFile(HANDLE, PIO_STATUS_BLOCK); +NTSTATUS NTAPI NtReadFile(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PVOID, ULONG, + PLARGE_INTEGER, PULONG); +NTSTATUS NTAPI NtReadFileScatter(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, + PLARGE_INTEGER, PULONG); +NTSTATUS NTAPI NtWriteFile(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PVOID, ULONG, + PLARGE_INTEGER, PULONG); +NTSTATUS NTAPI NtWriteFileGather(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, + PLARGE_INTEGER, PULONG); +NTSTATUS NTAPI NtQueryFullAttributesFile(POBJECT_ATTRIBUTES, PVOID); +NTSTATUS NTAPI LdrLoadDll(PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle); +NTSTATUS NTAPI LdrUnloadDll(HMODULE); +// These pointers are disguised as PVOID to avoid pulling in obscure headers +PVOID NTAPI LdrResolveDelayLoadedAPI(PVOID, PVOID, PVOID, PVOID, PVOID, ULONG); +void CALLBACK ProcessCaretEvents(HWINEVENTHOOK, DWORD, HWND, LONG, LONG, DWORD, DWORD); +void __fastcall BaseThreadInitThunk(BOOL aIsInitialThread, void* aStartAddress, void* aThreadParam); + using namespace mozilla; struct payload { @@ -38,7 +61,8 @@ extern "C" __declspec(dllexport) __declspec(noinline) payload rotatePayload(payl static bool patched_func_called = false; -static payload (*orig_rotatePayload)(payload); +static WindowsDllInterceptor::FuncHookType + orig_rotatePayload; static payload patched_rotatePayload(payload p) @@ -47,11 +71,61 @@ patched_rotatePayload(payload p) return orig_rotatePayload(p); } -typedef bool(*HookTestFunc)(void*); -bool CheckHook(HookTestFunc aHookTestFunc, void* aOrigFunc, - const char* aDllName, const char* aFuncName) +// Invoke aFunc by taking aArg's contents and using them as aFunc's arguments +template , size_t... Indices> +decltype(auto) Apply(CallableT&& aFunc, ArgTuple&& aArgs, std::index_sequence) { - if (aHookTestFunc(aOrigFunc)) { + return std::forward(aFunc)(Get(std::forward(aArgs))...); +} + +template +bool TestFunction(CallableT aFunc); + +#define DEFINE_TEST_FUNCTION(calling_convention) \ + template \ + bool TestFunction(WindowsDllInterceptor::FuncHookType&& aFunc, \ + bool (* aPred)(R), TestArgs... aArgs) \ + { \ + using FuncHookType = WindowsDllInterceptor::FuncHookType; \ + using ArgTuple = Tuple; \ + using Indices = std::index_sequence_for; \ + ArgTuple fakeArgs{ std::forward(aArgs)... }; \ + return aPred(Apply(std::forward(aFunc), std::forward(fakeArgs), Indices())); \ + } \ + \ + /* Specialization for functions returning void */ \ + template \ + bool TestFunction(WindowsDllInterceptor::FuncHookType&& aFunc, \ + PredicateT&& aPred, TestArgs... aArgs) \ + { \ + using FuncHookType = WindowsDllInterceptor::FuncHookType; \ + using ArgTuple = Tuple; \ + using Indices = std::index_sequence_for; \ + ArgTuple fakeArgs{ std::forward(aArgs)... }; \ + Apply(std::forward(aFunc), std::forward(fakeArgs), Indices()); \ + return true; \ + } + +// C++11 allows empty arguments to macros. clang works just fine. MSVC does the +// right thing, but it also throws up warning C4003. +#if defined(_MSC_VER) && !defined(__clang__) +DEFINE_TEST_FUNCTION(__cdecl) +#else +DEFINE_TEST_FUNCTION() +#endif + +#ifdef _M_IX86 +DEFINE_TEST_FUNCTION(__stdcall) +DEFINE_TEST_FUNCTION(__fastcall) +#endif // _M_IX86 + +// Test the hooked function against the supplied predicate +template +bool CheckHook(WindowsDllInterceptor::FuncHookType &aOrigFunc, + const char* aDllName, const char* aFuncName, PredicateT&& aPred, + Args... aArgs) +{ + if (TestFunction(std::forward>(aOrigFunc), std::forward(aPred), std::forward(aArgs)...)) { printf("TEST-PASS | WindowsDllInterceptor | " "Executed hooked function %s from %s\n", aFuncName, aDllName); return true; @@ -61,57 +135,235 @@ bool CheckHook(HookTestFunc aHookTestFunc, void* aOrigFunc, return false; } -template -bool TestHook(HookTestFunc funcTester, const char (&dll)[N], const char *func) +// Hook the function and optionally attempt calling it +template +bool TestHook(const char (&dll)[N], const char *func, PredicateT&& aPred, Args... aArgs) { - void *orig_func; + auto orig_func(mozilla::MakeUnique>()); + bool successful = false; { WindowsDllInterceptor TestIntercept; TestIntercept.Init(dll); - successful = TestIntercept.AddHook(func, 0, &orig_func); + successful = orig_func->Set(TestIntercept, func, nullptr); } if (successful) { printf("TEST-PASS | WindowsDllInterceptor | Could hook %s from %s\n", func, dll); - return CheckHook(funcTester, orig_func, dll, func); + if (!aPred) { + printf("TEST-SKIPPED | WindowsDllInterceptor | " + "Will not attempt to execute patched %s.\n", func); + return true; + } + + return CheckHook(*orig_func, dll, func, std::forward(aPred), std::forward(aArgs)...); } else { printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to hook %s from %s\n", func, dll); return false; } } -template -bool TestDetour(const char (&dll)[N], const char *func) +// Detour the function and optionally attempt calling it +template +bool TestDetour(const char (&dll)[N], const char *func, PredicateT&& aPred) { - void *orig_func; + auto orig_func(mozilla::MakeUnique>()); + bool successful = false; { WindowsDllInterceptor TestIntercept; TestIntercept.Init(dll); - successful = TestIntercept.AddDetour(func, 0, &orig_func); + successful = orig_func->SetDetour(TestIntercept, func, nullptr); } if (successful) { printf("TEST-PASS | WindowsDllInterceptor | Could detour %s from %s\n", func, dll); - return true; + if (!aPred) { + printf("TEST-SKIPPED | WindowsDllInterceptor | " + "Will not attempt to execute patched %s.\n", func); + return true; + } + + return CheckHook(*orig_func, dll, func, std::forward(aPred)); } else { printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to detour %s from %s\n", func, dll); return false; } } -template -bool MaybeTestHook(const bool cond, HookTestFunc funcTester, const char (&dll)[N], const char* func) +// If a function pointer's type returns void*, this template converts that type +// to return uintptr_t instead, for the purposes of predicates. +template +struct SubstituteForVoidPtr +{ + using Type = FuncT; +}; + +template +struct SubstituteForVoidPtr +{ + using Type = uintptr_t (*)(Args...); +}; + +#ifdef _M_IX86 +template +struct SubstituteForVoidPtr +{ + using Type = uintptr_t (__stdcall*)(Args...); +}; + +template +struct SubstituteForVoidPtr +{ + using Type = uintptr_t (__fastcall*)(Args...); +}; +#endif // _M_IX86 + +// Determines the function's return type +template +struct ReturnType; + +template +struct ReturnType +{ + using Type = R; +}; + +#ifdef _M_IX86 +template +struct ReturnType +{ + using Type = R; +}; + +template +struct ReturnType +{ + using Type = R; +}; +#endif // _M_IX86 + +// Predicates that may be supplied during tests +template +struct Predicates +{ + using ArgType = typename ReturnType::Type; + + template + static bool Equals(ArgType aValue) + { + return CompVal == aValue; + } + + template + static bool NotEquals(ArgType aValue) + { + return CompVal != aValue; + } + + template + static bool Ignore(ArgType aValue) + { + return true; + } +}; + +// Functions that return void should be ignored, so we specialize the +// Ignore predicate for that case. Use nullptr as the value to compare against. +template +struct Predicates +{ + template + static bool Ignore() + { + return true; + } +}; + +#ifdef _M_IX86 +template +struct Predicates +{ + template + static bool Ignore() + { + return true; + } +}; + +template +struct Predicates +{ + template + static bool Ignore() + { + return true; + } +}; +#endif // _M_IX86 + +// The standard test. Hook |func|, and then try executing it with all zero +// arguments, using |pred| and |comp| to determine whether the call successfully +// executed. In general, you want set pred and comp such that they return true +// when the function is returning whatever value is expected with all-zero +// arguments. +// +// Note: When |func| returns void, you must supply |Ignore| and |nullptr| as the +// |pred| and |comp| arguments, respectively. +#define TEST_HOOK(dll, func, pred, comp) \ + TestHook(#dll, #func, &Predicates::pred) + +// We need to special-case functions that return INVALID_HANDLE_VALUE +// (ie, CreateFile). Our template machinery for comparing values doesn't work +// with integer constants passed as pointers (well, it works on MSVC, but not +// clang, because that is not standard-compliant). +#define TEST_HOOK_FOR_INVALID_HANDLE_VALUE(dll, func) \ + TestHook::Type>(#dll, #func, &Predicates::Type>::Equals) + +// This variant allows you to explicitly supply arguments to the hooked function +// during testing. You want to provide arguments that produce the conditions that +// induce the function to return a value that is accepted by your predicate. +#define TEST_HOOK_PARAMS(dll, func, pred, comp, ...) \ + TestHook(#dll, #func, &Predicates::pred, __VA_ARGS__) + +// This is for cases when we want to hook |func|, but it is unsafe to attempt +// to execute the function in the context of a test. +#define TEST_HOOK_SKIP_EXEC(dll, func) \ + TestHook(#dll, #func, reinterpret_cast::Type)>(NULL)) + +// The following three variants are identical to the previous macros, +// however the forcibly use a Detour on 32-bit Windows. On 64-bit Windows, +// these macros are identical to their TEST_HOOK variants. +#define TEST_DETOUR(dll, func, pred, comp) \ + TestDetour(#dll, #func, &Predicates::pred) + +#define TEST_DETOUR_PARAMS(dll, func, pred, comp, ...) \ + TestDetour(#dll, #func, &Predicates::pred, __VA_ARGS__) + +#define TEST_DETOUR_SKIP_EXEC(dll, func) \ + TestDetour(#dll, #func, reinterpret_cast::Type)>(NULL)) + +template +bool MaybeTestHook(const bool cond, const char (&dll)[N], const char *func, PredicateT&& aPred, Args... aArgs) { if (!cond) { printf("TEST-SKIPPED | WindowsDllInterceptor | Skipped hook test for %s from %s\n", func, dll); return true; } - return TestHook(funcTester, dll, func); + return TestHook(dll, func, std::forward(aPred), std::forward(aArgs)...); } +// Like TEST_HOOK, but the test is only executed when cond is true. +#define MAYBE_TEST_HOOK(cond, dll, func, pred, comp) \ + MaybeTestHook(cond, #dll, #func, &Predicates::pred) + +#define MAYBE_TEST_HOOK_PARAMS(cond, dll, func, pred, comp, ...) \ + MaybeTestHook(cond, #dll, #func, &Predicates::pred, __VA_ARGS__) + +#define MAYBE_TEST_HOOK_SKIP_EXEC(cond, dll, func) \ + MaybeTestHook(cond, #dll, #func, reinterpret_cast::Type)>(NULL)) + bool ShouldTestTipTsf() { if (!IsWin8OrLater()) { @@ -147,455 +399,6 @@ bool ShouldTestTipTsf() return true; } -// These test the patched function returned by the DLL -// interceptor. They check that the patched assembler preamble does -// something sane. The parameter is a pointer to the patched function. -bool TestGetWindowInfo(void* aFunc) -{ - auto patchedGetWindowInfo = - reinterpret_cast(aFunc); - return patchedGetWindowInfo(0, 0) == FALSE; -} - -bool TestSetWindowLongPtr(void* aFunc) -{ - auto patchedSetWindowLongPtr = - reinterpret_cast(aFunc); - return patchedSetWindowLongPtr(0, 0, 0) == 0; -} - -bool TestSetWindowLong(void* aFunc) -{ - auto patchedSetWindowLong = - reinterpret_cast(aFunc); - return patchedSetWindowLong(0, 0, 0) == 0; -} - -bool TestTrackPopupMenu(void* aFunc) -{ - auto patchedTrackPopupMenu = - reinterpret_cast(aFunc); - return patchedTrackPopupMenu(0, 0, 0, 0, 0, 0, 0) == 0; -} - -bool TestNtFlushBuffersFile(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtFlushBuffersFileType)(HANDLE, PIO_STATUS_BLOCK); - auto patchedNtFlushBuffersFile = - reinterpret_cast(aFunc); - patchedNtFlushBuffersFile(0, 0); - return true; -} - -bool TestNtCreateFile(void* aFunc) -{ - auto patchedNtCreateFile = - reinterpret_cast(aFunc); - return patchedNtCreateFile(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; -} - -bool TestNtReadFile(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtReadFileType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PVOID, ULONG, - PLARGE_INTEGER, PULONG); - auto patchedNtReadFile = - reinterpret_cast(aFunc); - return patchedNtReadFile(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; -} - -bool TestNtReadFileScatter(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtReadFileScatterType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, - PLARGE_INTEGER, PULONG); - auto patchedNtReadFileScatter = - reinterpret_cast(aFunc); - return patchedNtReadFileScatter(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; -} - -bool TestNtWriteFile(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtWriteFileType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PVOID, ULONG, - PLARGE_INTEGER, PULONG); - auto patchedNtWriteFile = - reinterpret_cast(aFunc); - return patchedNtWriteFile(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; -} - -bool TestNtWriteFileGather(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtWriteFileGatherType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, - PLARGE_INTEGER, PULONG); - auto patchedNtWriteFileGather = - reinterpret_cast(aFunc); - return patchedNtWriteFileGather(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; -} - -bool TestNtQueryFullAttributesFile(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtQueryFullAttributesFileType)(POBJECT_ATTRIBUTES, - PVOID); - auto patchedNtQueryFullAttributesFile = - reinterpret_cast(aFunc); - return patchedNtQueryFullAttributesFile(0, 0) != 0; -} - -bool TestLdrUnloadDll(void* aFunc) -{ - typedef NTSTATUS (NTAPI *LdrUnloadDllType)(HMODULE); - auto patchedLdrUnloadDll = reinterpret_cast(aFunc); - return patchedLdrUnloadDll(0) != 0; -} - -bool TestLdrResolveDelayLoadedAPI(void* aFunc) -{ - // These pointers are disguised as PVOID to avoid pulling in obscure headers - typedef PVOID (WINAPI *LdrResolveDelayLoadedAPIType)(PVOID, PVOID, PVOID, - PVOID, PVOID, ULONG); - auto patchedLdrResolveDelayLoadedAPI = - reinterpret_cast(aFunc); - // No idea how to call this API. Flags==99 is just an arbitrary number that - // doesn't crash when the other params are null. - return patchedLdrResolveDelayLoadedAPI(0, 0, 0, 0, 0, 99) == 0; -} - -#ifdef _M_AMD64 -bool TestRtlInstallFunctionTableCallback(void* aFunc) -{ - auto patchedRtlInstallFunctionTableCallback = - reinterpret_cast(aFunc); - - return patchedRtlInstallFunctionTableCallback(0, 0, 0, 0, 0, 0) == FALSE; -} -#endif - -bool TestSetUnhandledExceptionFilter(void* aFunc) -{ - auto patchedSetUnhandledExceptionFilter = - reinterpret_cast(aFunc); - // Retrieve the current filter as we set the new filter to null, then restore the current filter. - LPTOP_LEVEL_EXCEPTION_FILTER current = patchedSetUnhandledExceptionFilter(0); - patchedSetUnhandledExceptionFilter(current); - return true; -} - -bool TestVirtualAlloc(void* aFunc) -{ - auto patchedVirtualAlloc = - reinterpret_cast(aFunc); - return patchedVirtualAlloc(0, 0, 0, 0) == 0; -} - -bool TestMapViewOfFile(void* aFunc) -{ - auto patchedMapViewOfFile = - reinterpret_cast(aFunc); - return patchedMapViewOfFile(0, 0, 0, 0, 0) == 0; -} - -bool TestCreateDIBSection(void* aFunc) -{ - auto patchedCreateDIBSection = - reinterpret_cast(aFunc); - // MSDN is wrong here. This does not return ERROR_INVALID_PARAMETER. It - // sets the value of GetLastError to ERROR_INVALID_PARAMETER. - // CreateDIBSection returns 0 on error. - return patchedCreateDIBSection(0, 0, 0, 0, 0, 0) == 0; -} - -bool TestCreateFileW(void* aFunc) -{ - auto patchedCreateFileW = - reinterpret_cast(aFunc); - return patchedCreateFileW(0, 0, 0, 0, 0, 0, 0) == INVALID_HANDLE_VALUE; -} - -bool TestCreateFileA(void* aFunc) -{ - auto patchedCreateFileA = - reinterpret_cast(aFunc); -// return patchedCreateFileA(0, 0, 0, 0, 0, 0, 0) == INVALID_HANDLE_VALUE; - printf("TEST-SKIPPED | WindowsDllInterceptor | " - "Will not attempt to execute patched CreateFileA -- patched method is known to fail.\n"); - return true; -} - -bool TestQueryDosDeviceW(void* aFunc) -{ - auto patchedQueryDosDeviceW = - reinterpret_cast(aFunc); - return patchedQueryDosDeviceW(nullptr, nullptr, 0) == 0; -} - -bool TestInSendMessageEx(void* aFunc) -{ - auto patchedInSendMessageEx = - reinterpret_cast(aFunc); - patchedInSendMessageEx(0); - return true; -} - -bool TestImmGetContext(void* aFunc) -{ - auto patchedImmGetContext = - reinterpret_cast(aFunc); - patchedImmGetContext(0); - return true; -} - -bool TestImmGetCompositionStringW(void* aFunc) -{ - auto patchedImmGetCompositionStringW = - reinterpret_cast(aFunc); - patchedImmGetCompositionStringW(0, 0, 0, 0); - return true; -} - -bool TestImmSetCandidateWindow(void* aFunc) -{ - auto patchedImmSetCandidateWindow = - reinterpret_cast(aFunc); -// return patchedImmSetCandidateWindow(0, 0) == 0; - // ImmSetCandidateWindow crashes if given bad parameters. - printf("TEST-SKIPPED | WindowsDllInterceptor | " - "Will not attempt to execute patched ImmSetCandidateWindow.\n"); - return true; -} - -bool TestImmNotifyIME(void* aFunc) -{ - auto patchedImmNotifyIME = - reinterpret_cast(aFunc); - return patchedImmNotifyIME(0, 0, 0, 0) == 0; -} - -bool TestGetSaveFileNameW(void* aFunc) -{ - auto patchedGetSaveFileNameWType = - reinterpret_cast(aFunc); - patchedGetSaveFileNameWType(0); - return true; -} - -bool TestGetOpenFileNameW(void* aFunc) -{ - auto patchedGetOpenFileNameWType = - reinterpret_cast(aFunc); - patchedGetOpenFileNameWType(0); - return true; -} - -bool TestGetKeyState(void* aFunc) -{ - auto patchedGetKeyState = - reinterpret_cast(aFunc); - patchedGetKeyState(0); - return true; -} - -bool TestSendMessageTimeoutW(void* aFunc) -{ - auto patchedSendMessageTimeoutW = - reinterpret_cast(aFunc); - return patchedSendMessageTimeoutW(0, 0, 0, 0, 0, 0, 0) == 0; -} - -bool TestProcessCaretEvents(void* aFunc) -{ - auto patchedProcessCaretEvents = - reinterpret_cast(aFunc); - patchedProcessCaretEvents(0, 0, 0, 0, 0, 0, 0); - return true; -} - -bool TestSetCursorPos(void* aFunc) -{ - // SetCursorPos has some issues in automation -- see bug 1368033. - // For that reason, we don't check the return value -- we only - // check that the method runs without producing an exception. - auto patchedSetCursorPos = - reinterpret_cast(aFunc); - patchedSetCursorPos(512, 512); - return true; -} - -static DWORD sTlsIndex = 0; - -bool TestTlsAlloc(void* aFunc) -{ - auto patchedTlsAlloc = - reinterpret_cast(aFunc); - sTlsIndex = patchedTlsAlloc(); - return sTlsIndex != TLS_OUT_OF_INDEXES; -} - -bool TestTlsFree(void* aFunc) -{ - auto patchedTlsFree = - reinterpret_cast(aFunc); - return sTlsIndex != 0 && patchedTlsFree(sTlsIndex); -} - -bool TestCloseHandle(void* aFunc) -{ - auto patchedCloseHandle = - reinterpret_cast(aFunc); - return patchedCloseHandle(0) == FALSE; -} - -bool TestDuplicateHandle(void* aFunc) -{ - auto patchedDuplicateHandle = - reinterpret_cast(aFunc); - return patchedDuplicateHandle(0, 0, 0, 0, 0, 0, 0) == FALSE; -} - -bool TestPrintDlgW(void* aFunc) -{ - auto patchedPrintDlgW = - reinterpret_cast(aFunc); - patchedPrintDlgW(0); - return true; -} - -bool TestInternetConnectA(void* aFunc) -{ - auto patchedInternetConnectA = - reinterpret_cast(aFunc); - return patchedInternetConnectA(0, 0, 0, 0, 0, 0, 0, 0) == 0; -} - -HINTERNET sInternet = 0; - -bool TestInternetOpenA(void* aFunc) -{ - auto patchedInternetOpenA = - reinterpret_cast(aFunc); - sInternet = patchedInternetOpenA(0, 0, 0, 0, 0); - return sInternet != 0; -} - -bool TestInternetCloseHandle(void* aFunc) -{ - auto patchedInternetCloseHandle = - reinterpret_cast(aFunc); - return patchedInternetCloseHandle(sInternet); -} - -bool TestInternetQueryDataAvailable(void* aFunc) -{ - auto patchedInternetQueryDataAvailable = - reinterpret_cast(aFunc); - return patchedInternetQueryDataAvailable(0, 0, 0, 0) == FALSE; -} - -bool TestInternetReadFile(void* aFunc) -{ - auto patchedInternetReadFile = - reinterpret_cast(aFunc); - return patchedInternetReadFile(0, 0, 0, 0) == FALSE; -} - -bool TestInternetWriteFile(void* aFunc) -{ - auto patchedInternetWriteFile = - reinterpret_cast(aFunc); - return patchedInternetWriteFile(0, 0, 0, 0) == FALSE; -} - -bool TestInternetSetOptionA(void* aFunc) -{ - auto patchedInternetSetOptionA = - reinterpret_cast(aFunc); - return patchedInternetSetOptionA(0, 0, 0, 0) == FALSE; -} - -bool TestHttpAddRequestHeadersA(void* aFunc) -{ - auto patchedHttpAddRequestHeadersA = - reinterpret_cast(aFunc); - return patchedHttpAddRequestHeadersA(0, 0, 0, 0) == FALSE; -} - -bool TestHttpOpenRequestA(void* aFunc) -{ - auto patchedHttpOpenRequestA = - reinterpret_cast(aFunc); - return patchedHttpOpenRequestA(0, 0, 0, 0, 0, 0, 0, 0) == 0; -} - -bool TestHttpQueryInfoA(void* aFunc) -{ - auto patchedHttpQueryInfoA = - reinterpret_cast(aFunc); - return patchedHttpQueryInfoA(0, 0, 0, 0, 0) == FALSE; -} - -bool TestHttpSendRequestA(void* aFunc) -{ - auto patchedHttpSendRequestA = - reinterpret_cast(aFunc); - return patchedHttpSendRequestA(0, 0, 0, 0, 0) == FALSE; -} - -bool TestHttpSendRequestExA(void* aFunc) -{ - auto patchedHttpSendRequestExA = - reinterpret_cast(aFunc); - return patchedHttpSendRequestExA(0, 0, 0, 0, 0) == FALSE; -} - -bool TestHttpEndRequestA(void* aFunc) -{ - auto patchedHttpEndRequestA = - reinterpret_cast(aFunc); - return patchedHttpEndRequestA(0, 0, 0, 0) == FALSE; -} - -bool TestInternetQueryOptionA(void* aFunc) -{ - auto patchedInternetQueryOptionA = - reinterpret_cast(aFunc); - return patchedInternetQueryOptionA(0, 0, 0, 0) == FALSE; -} - -bool TestInternetErrorDlg(void* aFunc) -{ - auto patchedInternetErrorDlg = - reinterpret_cast(aFunc); - return patchedInternetErrorDlg(0, 0, 0, 0, 0) == ERROR_INVALID_HANDLE; -} - -CredHandle sCredHandle; - -bool TestAcquireCredentialsHandleA(void* aFunc) -{ - auto patchedAcquireCredentialsHandleA = - reinterpret_cast(aFunc); - SCHANNEL_CRED cred; - memset(&cred, 0, sizeof(cred)); - cred.dwVersion = SCHANNEL_CRED_VERSION; - return patchedAcquireCredentialsHandleA(0, UNISP_NAME, SECPKG_CRED_OUTBOUND, - 0, &cred, 0, 0, &sCredHandle, 0) == S_OK; -} - -bool TestQueryCredentialsAttributesA(void* aFunc) -{ - auto patchedQueryCredentialsAttributesA = - reinterpret_cast(aFunc); - return patchedQueryCredentialsAttributesA(&sCredHandle, 0, 0) == SEC_E_UNSUPPORTED_FUNCTION; -} - -bool TestFreeCredentialsHandle(void* aFunc) -{ - auto patchedFreeCredentialsHandle = - reinterpret_cast(aFunc); - return patchedFreeCredentialsHandle(&sCredHandle) == S_OK; -} - int main() { LARGE_INTEGER start; @@ -615,7 +418,7 @@ int main() { WindowsDllInterceptor ExeIntercept; ExeIntercept.Init("TestDllInterceptor.exe"); - if (ExeIntercept.AddHook("rotatePayload", reinterpret_cast(patched_rotatePayload), (void**) &orig_rotatePayload)) { + if (orig_rotatePayload.Set(ExeIntercept, "rotatePayload", &patched_rotatePayload)) { printf("TEST-PASS | WindowsDllInterceptor | Hook added\n"); } else { printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to add hook\n"); @@ -659,85 +462,85 @@ int main() } #endif - if (TestHook(TestGetWindowInfo, "user32.dll", "GetWindowInfo") && + if (TEST_HOOK(user32.dll, GetWindowInfo, Equals, FALSE) && #ifdef _WIN64 - TestHook(TestSetWindowLongPtr, "user32.dll", "SetWindowLongPtrA") && - TestHook(TestSetWindowLongPtr, "user32.dll", "SetWindowLongPtrW") && + TEST_HOOK(user32.dll, SetWindowLongPtrA, Equals, 0) && + TEST_HOOK(user32.dll, SetWindowLongPtrW, Equals, 0) && #else - TestHook(TestSetWindowLong, "user32.dll", "SetWindowLongA") && - TestHook(TestSetWindowLong, "user32.dll", "SetWindowLongW") && + TEST_HOOK(user32.dll, SetWindowLongA, Equals, 0) && + TEST_HOOK(user32.dll, SetWindowLongW, Equals, 0) && #endif - TestHook(TestTrackPopupMenu, "user32.dll", "TrackPopupMenu") && + TEST_HOOK(user32.dll, TrackPopupMenu, Equals, FALSE) && #ifdef _M_IX86 // We keep this test to hook complex code on x86. (Bug 850957) - TestHook(TestNtFlushBuffersFile, "ntdll.dll", "NtFlushBuffersFile") && + TEST_HOOK(ntdll.dll, NtFlushBuffersFile, NotEquals, 0) && #endif - TestHook(TestNtCreateFile, "ntdll.dll", "NtCreateFile") && - TestHook(TestNtReadFile, "ntdll.dll", "NtReadFile") && - TestHook(TestNtReadFileScatter, "ntdll.dll", "NtReadFileScatter") && - TestHook(TestNtWriteFile, "ntdll.dll", "NtWriteFile") && - TestHook(TestNtWriteFileGather, "ntdll.dll", "NtWriteFileGather") && - TestHook(TestNtQueryFullAttributesFile, "ntdll.dll", "NtQueryFullAttributesFile") && + TEST_HOOK(ntdll.dll, NtCreateFile, NotEquals, 0) && + TEST_HOOK(ntdll.dll, NtReadFile, NotEquals, 0) && + TEST_HOOK(ntdll.dll, NtReadFileScatter, NotEquals, 0) && + TEST_HOOK(ntdll.dll, NtWriteFile, NotEquals, 0) && + TEST_HOOK(ntdll.dll, NtWriteFileGather, NotEquals, 0) && + TEST_HOOK(ntdll.dll, NtQueryFullAttributesFile, NotEquals, 0) && #ifndef MOZ_ASAN // Bug 733892: toolkit/crashreporter/nsExceptionHandler.cpp // This fails on ASan because the ASan runtime already hooked this function - TestHook(TestSetUnhandledExceptionFilter, "kernel32.dll", "SetUnhandledExceptionFilter") && + TEST_HOOK(kernel32.dll, SetUnhandledExceptionFilter, Ignore, nullptr) && #endif #ifdef _M_IX86 // Bug 670967: xpcom/base/AvailableMemoryTracker.cpp - TestHook(TestVirtualAlloc, "kernel32.dll", "VirtualAlloc") && - TestHook(TestMapViewOfFile, "kernel32.dll", "MapViewOfFile") && - TestHook(TestCreateDIBSection, "gdi32.dll", "CreateDIBSection") && - TestHook(TestCreateFileW, "kernel32.dll", "CreateFileW") && // see Bug 1316415 + TEST_HOOK(kernel32.dll, VirtualAlloc, Equals, nullptr) && + TEST_HOOK(kernel32.dll, MapViewOfFile, Equals, nullptr) && + TEST_HOOK(gdi32.dll, CreateDIBSection, Equals, nullptr) && + TEST_HOOK_FOR_INVALID_HANDLE_VALUE(kernel32.dll, CreateFileW) && #endif - TestHook(TestCreateFileA, "kernel32.dll", "CreateFileA") && - TestHook(TestQueryDosDeviceW, "kernelbase.dll", "QueryDosDeviceW") && - TestDetour("user32.dll", "CreateWindowExW") && - TestHook(TestInSendMessageEx, "user32.dll", "InSendMessageEx") && - TestHook(TestImmGetContext, "imm32.dll", "ImmGetContext") && - TestHook(TestImmGetCompositionStringW, "imm32.dll", "ImmGetCompositionStringW") && - TestHook(TestImmSetCandidateWindow, "imm32.dll", "ImmSetCandidateWindow") && - TestHook(TestImmNotifyIME, "imm32.dll", "ImmNotifyIME") && - TestHook(TestGetSaveFileNameW, "comdlg32.dll", "GetSaveFileNameW") && - TestHook(TestGetOpenFileNameW, "comdlg32.dll", "GetOpenFileNameW") && + TEST_HOOK_FOR_INVALID_HANDLE_VALUE(kernel32.dll, CreateFileA) && + TEST_HOOK(kernelbase.dll, QueryDosDeviceW, Equals, 0) && + TEST_DETOUR(user32.dll, CreateWindowExW, Equals, nullptr) && + TEST_HOOK(user32.dll, InSendMessageEx, Equals, ISMEX_NOSEND) && + TEST_HOOK(imm32.dll, ImmGetContext, Equals, nullptr) && + TEST_HOOK(imm32.dll, ImmGetCompositionStringW, Ignore, 0) && + TEST_HOOK_SKIP_EXEC(imm32.dll, ImmSetCandidateWindow) && + TEST_HOOK(imm32.dll, ImmNotifyIME, Equals, 0) && + TEST_HOOK(comdlg32.dll, GetSaveFileNameW, Ignore, FALSE) && + TEST_HOOK(comdlg32.dll, GetOpenFileNameW, Ignore, FALSE) && #ifdef _M_X64 - TestHook(TestGetKeyState, "user32.dll", "GetKeyState") && // see Bug 1316415 - TestHook(TestLdrUnloadDll, "ntdll.dll", "LdrUnloadDll") && - MaybeTestHook(IsWin8OrLater(), TestLdrResolveDelayLoadedAPI, "ntdll.dll", "LdrResolveDelayLoadedAPI") && - MaybeTestHook(!IsWin8OrLater(), TestRtlInstallFunctionTableCallback, "kernel32.dll", "RtlInstallFunctionTableCallback") && - TestHook(TestPrintDlgW, "comdlg32.dll", "PrintDlgW") && + TEST_HOOK(user32.dll, GetKeyState, Ignore, 0) && // see Bug 1316415 + TEST_HOOK(ntdll.dll, LdrUnloadDll, NotEquals, 0) && + MAYBE_TEST_HOOK_SKIP_EXEC(IsWin8OrLater(), ntdll.dll, LdrResolveDelayLoadedAPI) && + MAYBE_TEST_HOOK(!IsWin8OrLater(), kernel32.dll, RtlInstallFunctionTableCallback, Equals, FALSE) && + TEST_HOOK(comdlg32.dll, PrintDlgW, Ignore, 0) && #endif - MaybeTestHook(ShouldTestTipTsf(), TestProcessCaretEvents, "tiptsf.dll", "ProcessCaretEvents") && + MAYBE_TEST_HOOK(ShouldTestTipTsf(), tiptsf.dll, ProcessCaretEvents, Ignore, nullptr) && #ifdef _M_IX86 - TestHook(TestSendMessageTimeoutW, "user32.dll", "SendMessageTimeoutW") && + TEST_HOOK(user32.dll, SendMessageTimeoutW, Equals, 0) && #endif - TestHook(TestSetCursorPos, "user32.dll", "SetCursorPos") && - TestHook(TestTlsAlloc, "kernel32.dll", "TlsAlloc") && - TestHook(TestTlsFree, "kernel32.dll", "TlsFree") && - TestHook(TestCloseHandle, "kernel32.dll", "CloseHandle") && - TestHook(TestDuplicateHandle, "kernel32.dll", "DuplicateHandle") && + TEST_HOOK(user32.dll, SetCursorPos, NotEquals, FALSE) && + TEST_HOOK(kernel32.dll, TlsAlloc, NotEquals, TLS_OUT_OF_INDEXES) && + TEST_HOOK_PARAMS(kernel32.dll, TlsFree, Equals, FALSE, TLS_OUT_OF_INDEXES) && + TEST_HOOK(kernel32.dll, CloseHandle, Equals, FALSE) && + TEST_HOOK(kernel32.dll, DuplicateHandle, Equals, FALSE) && - TestHook(TestInternetOpenA, "wininet.dll", "InternetOpenA") && - TestHook(TestInternetCloseHandle, "wininet.dll", "InternetCloseHandle") && - TestHook(TestInternetConnectA, "wininet.dll", "InternetConnectA") && - TestHook(TestInternetQueryDataAvailable, "wininet.dll", "InternetQueryDataAvailable") && - TestHook(TestInternetReadFile, "wininet.dll", "InternetReadFile") && - TestHook(TestInternetWriteFile, "wininet.dll", "InternetWriteFile") && - TestHook(TestInternetSetOptionA, "wininet.dll", "InternetSetOptionA") && - TestHook(TestHttpAddRequestHeadersA, "wininet.dll", "HttpAddRequestHeadersA") && - TestHook(TestHttpOpenRequestA, "wininet.dll", "HttpOpenRequestA") && - TestHook(TestHttpQueryInfoA, "wininet.dll", "HttpQueryInfoA") && - TestHook(TestHttpSendRequestA, "wininet.dll", "HttpSendRequestA") && - TestHook(TestHttpSendRequestExA, "wininet.dll", "HttpSendRequestExA") && - TestHook(TestHttpEndRequestA, "wininet.dll", "HttpEndRequestA") && - TestHook(TestInternetQueryOptionA, "wininet.dll", "InternetQueryOptionA") && + TEST_HOOK(wininet.dll, InternetOpenA, NotEquals, nullptr) && + TEST_HOOK(wininet.dll, InternetCloseHandle, Equals, FALSE) && + TEST_HOOK(wininet.dll, InternetConnectA, Equals, nullptr) && + TEST_HOOK(wininet.dll, InternetQueryDataAvailable, Equals, FALSE) && + TEST_HOOK(wininet.dll, InternetReadFile, Equals, FALSE) && + TEST_HOOK(wininet.dll, InternetWriteFile, Equals, FALSE) && + TEST_HOOK(wininet.dll, InternetSetOptionA, Equals, FALSE) && + TEST_HOOK(wininet.dll, HttpAddRequestHeadersA, Equals, FALSE) && + TEST_HOOK(wininet.dll, HttpOpenRequestA, Equals, nullptr) && + TEST_HOOK(wininet.dll, HttpQueryInfoA, Equals, FALSE) && + TEST_HOOK(wininet.dll, HttpSendRequestA, Equals, FALSE) && + TEST_HOOK(wininet.dll, HttpSendRequestExA, Equals, FALSE) && + TEST_HOOK(wininet.dll, HttpEndRequestA, Equals, FALSE) && + TEST_HOOK(wininet.dll, InternetQueryOptionA, Equals, FALSE) && - TestHook(TestAcquireCredentialsHandleA, "sspicli.dll", "AcquireCredentialsHandleA") && - TestHook(TestQueryCredentialsAttributesA, "sspicli.dll", "QueryCredentialsAttributesA") && - TestHook(TestFreeCredentialsHandle, "sspicli.dll", "FreeCredentialsHandle") && + TEST_HOOK(sspicli.dll, AcquireCredentialsHandleA, NotEquals, SEC_E_OK) && + TEST_HOOK(sspicli.dll, QueryCredentialsAttributesA, NotEquals, SEC_E_OK) && + TEST_HOOK(sspicli.dll, FreeCredentialsHandle, NotEquals, SEC_E_OK) && - TestDetour("kernel32.dll", "BaseThreadInitThunk") && - TestDetour("ntdll.dll", "LdrLoadDll")) { + TEST_DETOUR_SKIP_EXEC(kernel32.dll, BaseThreadInitThunk) && + TEST_DETOUR_SKIP_EXEC(ntdll.dll, LdrLoadDll)) { printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n"); LARGE_INTEGER end, freq; From 0ff30867ea191876da06059cc0527a1893e26eb4 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:48:45 -0600 Subject: [PATCH 15/57] Bug 1460022: Part 3 - Update TestDllInterceptorCrossProcess to reflect new interceptor interface; r=handyman --HG-- extra : rebase_source : 208380bdaaf2c394c5d93cf2f0f8cb2a117b3e66 --- .../interceptor/TestDllInterceptorCrossProcess.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp b/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp index 95cf37821043..c29d132ba9b0 100644 --- a/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp +++ b/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp @@ -11,19 +11,19 @@ using std::wstring; -static void* gOrigReturnResult; - extern "C" __declspec(dllexport) int ReturnResult() { return 2; } +static mozilla::CrossProcessDllInterceptor::FuncHookType + gOrigReturnResult; + static int ReturnResultHook() { - auto origFn = reinterpret_cast(gOrigReturnResult); - if (origFn() != 2) { + if (gOrigReturnResult() != 2) { return 3; } @@ -73,9 +73,7 @@ int ParentMain() mozilla::CrossProcessDllInterceptor intcpt(childProcess.get()); intcpt.Init("TestDllInterceptorCrossProcess.exe"); - if (!intcpt.AddHook("ReturnResult", - reinterpret_cast(&ReturnResultHook), - &gOrigReturnResult)) { + if (!gOrigReturnResult.Set(intcpt, "ReturnResult", &ReturnResultHook)) { printf("TEST-UNEXPECTED-FAIL | DllInterceptorCrossProcess | Failed to add hook\n"); return 1; } From 63e70eee769555ebabcc4c7b751062efe5aa62fa Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:49:17 -0600 Subject: [PATCH 16/57] Bug 1460022: Part 4 - Update a11y code to reflect new interface for DLL interceptor; r=Jamie --HG-- extra : rebase_source : ada28438a506edcd4a122ec2c99a742503baa945 --- accessible/windows/msaa/Compatibility.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/accessible/windows/msaa/Compatibility.cpp b/accessible/windows/msaa/Compatibility.cpp index 6446f19805c0..f4434f37c0b5 100644 --- a/accessible/windows/msaa/Compatibility.cpp +++ b/accessible/windows/msaa/Compatibility.cpp @@ -95,7 +95,8 @@ Compatibility::IsModuleVersionLessThan(HMODULE aModuleHandle, //////////////////////////////////////////////////////////////////////////////// static WindowsDllInterceptor sUser32Interceptor; -static decltype(&InSendMessageEx) sInSendMessageExStub = nullptr; +static WindowsDllInterceptor::FuncHookType + sInSendMessageExStub; static bool sInSendMessageExHackEnabled = false; static PVOID sVectoredExceptionHandler = nullptr; @@ -267,11 +268,9 @@ Compatibility::Init() if ((sConsumers & (~(UIAUTOMATION | NVDA))) && BrowserTabsRemoteAutostart()) { sUser32Interceptor.Init("user32.dll"); - if (!sInSendMessageExStub) { - sUser32Interceptor.AddHook("InSendMessageEx", - reinterpret_cast(&InSendMessageExHook), - (void**)&sInSendMessageExStub); - } + sInSendMessageExStub.Set(sUser32Interceptor, "InSendMessageEx", + &InSendMessageExHook); + // The vectored exception handler allows us to catch exceptions ahead of any // SEH handlers. if (!sVectoredExceptionHandler) { From b90ed7ab5d5c50882c8e31878a1fcccf7aecd4fd Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:49:30 -0600 Subject: [PATCH 17/57] Bug 1460022: Part 5 - Update launcher process to work with new DLL interceptor interface; r=mhowell --HG-- extra : rebase_source : 6b0f7abb908993afb77f3c90b57cb870e630f778 --- browser/app/winlauncher/DllBlocklistWin.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/browser/app/winlauncher/DllBlocklistWin.cpp b/browser/app/winlauncher/DllBlocklistWin.cpp index 82e1d77d3722..a88a0747348f 100644 --- a/browser/app/winlauncher/DllBlocklistWin.cpp +++ b/browser/app/winlauncher/DllBlocklistWin.cpp @@ -246,7 +246,8 @@ IsDllAllowed(const UNICODE_STRING& aLeafName, void* aBaseAddress) } typedef decltype(&NtMapViewOfSection) NtMapViewOfSection_func; -static NtMapViewOfSection_func stub_NtMapViewOfSection; +static mozilla::CrossProcessDllInterceptor::FuncHookType + stub_NtMapViewOfSection; static NTSTATUS NTAPI patched_NtMapViewOfSection(HANDLE aSection, HANDLE aProcess, PVOID* aBaseAddress, @@ -356,9 +357,8 @@ InitializeDllBlocklistOOP(HANDLE aChildProcess) { mozilla::CrossProcessDllInterceptor intcpt(aChildProcess); intcpt.Init(L"ntdll.dll"); - bool ok = intcpt.AddDetour("NtMapViewOfSection", - reinterpret_cast(&patched_NtMapViewOfSection), - (void**) &stub_NtMapViewOfSection); + bool ok = stub_NtMapViewOfSection.SetDetour(intcpt, "NtMapViewOfSection", + &patched_NtMapViewOfSection); if (!ok) { return false; } From ee74c34ce25d3d5a02b7bdb1ce13121c472c586d Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:49:49 -0600 Subject: [PATCH 18/57] Bug 1460022: Part 6 - Update GMP code to work with new DLL interceptor interface; r=cpearce --HG-- extra : rebase_source : 17d7f30e7fc971fd8d2d3729c7d262cdc6a4c343 --- dom/media/gmp/ChromiumCDMAdapter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dom/media/gmp/ChromiumCDMAdapter.cpp b/dom/media/gmp/ChromiumCDMAdapter.cpp index b8fbe7a2f9da..e1946dee5106 100644 --- a/dom/media/gmp/ChromiumCDMAdapter.cpp +++ b/dom/media/gmp/ChromiumCDMAdapter.cpp @@ -197,7 +197,8 @@ typedef DWORD(WINAPI* QueryDosDeviceWFnPtr)(_In_opt_ LPCWSTR lpDeviceName, _Out_ LPWSTR lpTargetPath, _In_ DWORD ucchMax); -static QueryDosDeviceWFnPtr sOriginalQueryDosDeviceWFnPtr = nullptr; +static WindowsDllInterceptor::FuncHookType + sOriginalQueryDosDeviceWFnPtr; static std::unordered_map* sDeviceNames = nullptr; @@ -276,9 +277,8 @@ InitializeHooks() } sKernel32Intercept.Init("kernelbase.dll"); - sKernel32Intercept.AddHook("QueryDosDeviceW", - reinterpret_cast(QueryDosDeviceWHook), - (void**)(&sOriginalQueryDosDeviceWFnPtr)); + sOriginalQueryDosDeviceWFnPtr.Set(sKernel32Intercept, "QueryDosDeviceW", + &QueryDosDeviceWHook); } #endif From cc80cb14e0c93100b5a3115be42e87bb63056c21 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:50:50 -0600 Subject: [PATCH 19/57] Bug 1460022: Part 7 - Update plugin code to work with revised DLL interceptor interface; r=handyman --HG-- extra : rebase_source : 277e237e80b513b055b55ef7fb5cace7f240ea95 --- dom/plugins/base/nsPluginNativeWindowWin.cpp | 36 ++++---- dom/plugins/ipc/FunctionHook.cpp | 21 +---- dom/plugins/ipc/FunctionHook.h | 21 +++-- dom/plugins/ipc/PluginInstanceChild.cpp | 97 +++++++------------- 4 files changed, 67 insertions(+), 108 deletions(-) diff --git a/dom/plugins/base/nsPluginNativeWindowWin.cpp b/dom/plugins/base/nsPluginNativeWindowWin.cpp index fc7f0ea72345..570b99e52610 100644 --- a/dom/plugins/base/nsPluginNativeWindowWin.cpp +++ b/dom/plugins/base/nsPluginNativeWindowWin.cpp @@ -357,8 +357,10 @@ typedef LONG_PTR (WINAPI *User32SetWindowLongPtrW)(HWND hWnd, int nIndex, LONG_PTR dwNewLong); -static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = nullptr; -static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = nullptr; +static WindowsDllInterceptor::FuncHookType + sUser32SetWindowLongAHookStub; +static WindowsDllInterceptor::FuncHookType + sUser32SetWindowLongWHookStub; #else typedef LONG (WINAPI *User32SetWindowLongA)(HWND hWnd, @@ -368,8 +370,10 @@ typedef LONG (WINAPI *User32SetWindowLongW)(HWND hWnd, int nIndex, LONG dwNewLong); -static User32SetWindowLongA sUser32SetWindowLongAHookStub = nullptr; -static User32SetWindowLongW sUser32SetWindowLongWHookStub = nullptr; +static WindowsDllInterceptor::FuncHookType + sUser32SetWindowLongAHookStub; +static WindowsDllInterceptor::FuncHookType + sUser32SetWindowLongWHookStub; #endif static inline bool SetWindowLongHookCheck(HWND hWnd, @@ -448,23 +452,15 @@ HookSetWindowLongPtr() { sUser32Intercept.Init("user32.dll"); #ifdef _WIN64 - if (!sUser32SetWindowLongAHookStub) - sUser32Intercept.AddHook("SetWindowLongPtrA", - reinterpret_cast(SetWindowLongPtrAHook), - (void**) &sUser32SetWindowLongAHookStub); - if (!sUser32SetWindowLongWHookStub) - sUser32Intercept.AddHook("SetWindowLongPtrW", - reinterpret_cast(SetWindowLongPtrWHook), - (void**) &sUser32SetWindowLongWHookStub); + sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongPtrA", + &SetWindowLongPtrAHook); + sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongPtrW", + &SetWindowLongPtrWHook); #else - if (!sUser32SetWindowLongAHookStub) - sUser32Intercept.AddHook("SetWindowLongA", - reinterpret_cast(SetWindowLongAHook), - (void**) &sUser32SetWindowLongAHookStub); - if (!sUser32SetWindowLongWHookStub) - sUser32Intercept.AddHook("SetWindowLongW", - reinterpret_cast(SetWindowLongWHook), - (void**) &sUser32SetWindowLongWHookStub); + sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongA", + &SetWindowLongAHook); + sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongW", + &SetWindowLongWHook); #endif } diff --git a/dom/plugins/ipc/FunctionHook.cpp b/dom/plugins/ipc/FunctionHook.cpp index d5e29ec14f18..3d4733a19277 100644 --- a/dom/plugins/ipc/FunctionHook.cpp +++ b/dom/plugins/ipc/FunctionHook.cpp @@ -168,13 +168,13 @@ typedef HANDLE (WINAPI *CreateFileWPtr)(LPCWSTR aFname, DWORD aAccess, LPSECURITY_ATTRIBUTES aSecurity, DWORD aCreation, DWORD aFlags, HANDLE aFTemplate); -static CreateFileWPtr sCreateFileWStub = nullptr; +static WindowsDllInterceptor::FuncHookType sCreateFileWStub; typedef HANDLE (WINAPI *CreateFileAPtr)(LPCSTR aFname, DWORD aAccess, DWORD aShare, LPSECURITY_ATTRIBUTES aSecurity, DWORD aCreation, DWORD aFlags, HANDLE aFTemplate); -static CreateFileAPtr sCreateFileAStub = nullptr; +static WindowsDllInterceptor::FuncHookType sCreateFileAStub; // Windows 8 RTM (kernelbase's version is 6.2.9200.16384) doesn't call // CreateFileW from CreateFileA. @@ -263,7 +263,7 @@ CreateFileWHookFn(LPCWSTR aFname, DWORD aAccess, DWORD aShare, aSecurity, TRUNCATE_EXISTING, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, - NULL); + nullptr); if (replacement == INVALID_HANDLE_VALUE) { break; } @@ -300,23 +300,12 @@ CreateFileWHookFn(LPCWSTR aFname, DWORD aAccess, DWORD aShare, void FunctionHook::HookProtectedMode() { - // Make sure we only do this once. - static bool sRunOnce = false; - if (sRunOnce) { - return; - } - sRunOnce = true; - // Legacy code. Uses the nsWindowsDLLInterceptor directly instead of // using the FunctionHook sKernel32Intercept.Init("kernel32.dll"); MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Plugin); - sKernel32Intercept.AddHook("CreateFileW", - reinterpret_cast(CreateFileWHookFn), - (void**) &sCreateFileWStub); - sKernel32Intercept.AddHook("CreateFileA", - reinterpret_cast(CreateFileAHookFn), - (void**) &sCreateFileAStub); + sCreateFileWStub.Set(sKernel32Intercept, "CreateFileW", &CreateFileWHookFn); + sCreateFileAStub.Set(sKernel32Intercept, "CreateFileA", &CreateFileAHookFn); } #endif // defined(XP_WIN) diff --git a/dom/plugins/ipc/FunctionHook.h b/dom/plugins/ipc/FunctionHook.h index c9b30dd0643a..169cc86adefc 100644 --- a/dom/plugins/ipc/FunctionHook.h +++ b/dom/plugins/ipc/FunctionHook.h @@ -9,6 +9,7 @@ #include "IpdlTuple.h" #include "base/process.h" +#include "mozilla/Atomics.h" #if defined(XP_WIN) #include "nsWindowsDllInterceptor.h" @@ -96,12 +97,17 @@ typedef bool(ShouldHookFunc)(int aQuirks); template class BasicFunctionHook : public FunctionHook { + using FuncHookType = WindowsDllInterceptor::FuncHookType; + public: BasicFunctionHook(const char* aModuleName, const char* aFunctionName, FunctionType* aOldFunction, - FunctionType* aNewFunction) : - mOldFunction(aOldFunction), mRegistration(UNREGISTERED), mModuleName(aModuleName), - mFunctionName(aFunctionName), mNewFunction(aNewFunction) + FunctionType* aNewFunction) + : mOldFunction(aOldFunction) + , mRegistration(UNREGISTERED) + , mModuleName(aModuleName) + , mFunctionName(aFunctionName) + , mNewFunction(aNewFunction) { MOZ_ASSERT(mOldFunction); MOZ_ASSERT(mNewFunction); @@ -128,7 +134,8 @@ protected: // Once the function is hooked, this field will take the value of a pointer to // a function that performs the old behavior. Before that, it is a pointer to // the original function. - FunctionType* mOldFunction; + Atomic mOldFunction; + FuncHookType mStub; enum RegistrationStatus { UNREGISTERED, FAILED, SUCCEEDED }; RegistrationStatus mRegistration; @@ -170,14 +177,14 @@ BasicFunctionHook::Register(int aQuirks) return false; } - isHooked = - dllInterceptor->AddHook(mFunctionName.Data(), reinterpret_cast(mNewFunction), - reinterpret_cast(&mOldFunction)); + isHooked = mStub.Set(*dllInterceptor, mFunctionName.Data(), mNewFunction); #endif if (isHooked) { + mOldFunction = mStub.GetStub(); mRegistration = SUCCEEDED; } + HOOK_LOG(LogLevel::Debug, ("Registering to intercept function '%s' : '%s'", mFunctionName.Data(), SuccessMsg(isHooked))); diff --git a/dom/plugins/ipc/PluginInstanceChild.cpp b/dom/plugins/ipc/PluginInstanceChild.cpp index 47e779a6072c..bab3067be6ee 100644 --- a/dom/plugins/ipc/PluginInstanceChild.cpp +++ b/dom/plugins/ipc/PluginInstanceChild.cpp @@ -73,21 +73,17 @@ typedef BOOL (WINAPI *User32TrackPopupMenu)(HMENU hMenu, CONST RECT *prcRect); static WindowsDllInterceptor sUser32Intercept; static HWND sWinlessPopupSurrogateHWND = nullptr; -static User32TrackPopupMenu sUser32TrackPopupMenuStub = nullptr; +static WindowsDllInterceptor::FuncHookType sUser32TrackPopupMenuStub; static WindowsDllInterceptor sImm32Intercept; -static decltype(ImmGetContext)* sImm32ImmGetContextStub = nullptr; -static decltype(ImmGetCompositionStringW)* sImm32ImmGetCompositionStringStub = - nullptr; -static decltype(ImmSetCandidateWindow)* sImm32ImmSetCandidateWindowStub = - nullptr; -static decltype(ImmNotifyIME)* sImm32ImmNotifyIME = nullptr; -static decltype(ImmAssociateContextEx)* sImm32ImmAssociateContextExStub = - nullptr; +static WindowsDllInterceptor::FuncHookType sImm32ImmGetContextStub; +static WindowsDllInterceptor::FuncHookType sImm32ImmGetCompositionStringStub; +static WindowsDllInterceptor::FuncHookType sImm32ImmSetCandidateWindowStub; +static WindowsDllInterceptor::FuncHookType sImm32ImmNotifyIME; +static WindowsDllInterceptor::FuncHookType sImm32ImmAssociateContextExStub; + static PluginInstanceChild* sCurrentPluginInstance = nullptr; static const HIMC sHookIMC = (const HIMC)0xefefefef; -static bool sPopupMenuHookSet; -static bool sSetWindowLongHookSet; using mozilla::gfx::SharedDIB; @@ -1793,8 +1789,8 @@ typedef LONG_PTR (WINAPI *User32SetWindowLongPtrW)(HWND hWnd, int nIndex, LONG_PTR dwNewLong); -static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = nullptr; -static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = nullptr; +static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongAHookStub; +static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongWHookStub; #else typedef LONG (WINAPI *User32SetWindowLongA)(HWND hWnd, @@ -1804,8 +1800,8 @@ typedef LONG (WINAPI *User32SetWindowLongW)(HWND hWnd, int nIndex, LONG dwNewLong); -static User32SetWindowLongA sUser32SetWindowLongAHookStub = nullptr; -static User32SetWindowLongW sUser32SetWindowLongWHookStub = nullptr; +static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongAHookStub; +static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongWHookStub; #endif extern LRESULT CALLBACK @@ -1915,27 +1911,17 @@ PluginInstanceChild::HookSetWindowLongPtr() return; } - // Only pass through here once - if (sSetWindowLongHookSet) { - return; - } - sSetWindowLongHookSet = true; - sUser32Intercept.Init("user32.dll"); #ifdef _WIN64 - if (!sUser32SetWindowLongAHookStub) - sUser32Intercept.AddHook("SetWindowLongPtrA", reinterpret_cast(SetWindowLongPtrAHook), - (void**) &sUser32SetWindowLongAHookStub); - if (!sUser32SetWindowLongWHookStub) - sUser32Intercept.AddHook("SetWindowLongPtrW", reinterpret_cast(SetWindowLongPtrWHook), - (void**) &sUser32SetWindowLongWHookStub); + sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongPtrA", + &SetWindowLongPtrAHook); + sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongPtrW", + &SetWindowLongPtrWHook); #else - if (!sUser32SetWindowLongAHookStub) - sUser32Intercept.AddHook("SetWindowLongA", reinterpret_cast(SetWindowLongAHook), - (void**) &sUser32SetWindowLongAHookStub); - if (!sUser32SetWindowLongWHookStub) - sUser32Intercept.AddHook("SetWindowLongW", reinterpret_cast(SetWindowLongWHook), - (void**) &sUser32SetWindowLongWHookStub); + sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongA", + &SetWindowLongAHook); + sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongW", + &SetWindowLongWHook); #endif } @@ -2003,19 +1989,13 @@ PluginInstanceChild::InitPopupMenuHook() return; } - // Only pass through here once - if (sPopupMenuHookSet) { - return; - } - sPopupMenuHookSet = true; - // Note, once WindowsDllInterceptor is initialized for a module, // it remains initialized for that particular module for it's // lifetime. Additional instances are needed if other modules need // to be hooked. sUser32Intercept.Init("user32.dll"); - sUser32Intercept.AddHook("TrackPopupMenu", reinterpret_cast(TrackPopupHookProc), - (void**) &sUser32TrackPopupMenuStub); + sUser32TrackPopupMenuStub.Set(sUser32Intercept, "TrackPopupMenu", + &TrackPopupHookProc); } void @@ -2157,36 +2137,23 @@ PluginInstanceChild::InitImm32Hook() return; } - if (sImm32ImmGetContextStub) { - return; - } - // When using windowless plugin, IMM API won't work due ot OOP. // // ImmReleaseContext on Windows 7+ just returns TRUE only, so we don't // need to hook this. sImm32Intercept.Init("imm32.dll"); - sImm32Intercept.AddHook( - "ImmGetContext", - reinterpret_cast(ImmGetContextProc), - (void**)&sImm32ImmGetContextStub); - sImm32Intercept.AddHook( - "ImmGetCompositionStringW", - reinterpret_cast(ImmGetCompositionStringProc), - (void**)&sImm32ImmGetCompositionStringStub); - sImm32Intercept.AddHook( - "ImmSetCandidateWindow", - reinterpret_cast(ImmSetCandidateWindowProc), - (void**)&sImm32ImmSetCandidateWindowStub); - sImm32Intercept.AddHook( - "ImmNotifyIME", - reinterpret_cast(ImmNotifyIME), - (void**)&sImm32ImmNotifyIME); - sImm32Intercept.AddHook( - "ImmAssociateContextEx", - reinterpret_cast(ImmAssociateContextExProc), - (void**)&sImm32ImmAssociateContextExStub); + sImm32ImmGetContextStub.Set(sImm32Intercept, "ImmGetContext", + &ImmGetContextProc); + sImm32ImmGetCompositionStringStub.Set(sImm32Intercept, + "ImmGetCompositionStringW", + &ImmGetCompositionStringProc); + sImm32ImmSetCandidateWindowStub.Set(sImm32Intercept, + "ImmSetCandidateWindow", + &ImmSetCandidateWindowProc); + sImm32ImmNotifyIME.Set(sImm32Intercept, "ImmNotifyIME", &ImmNotifyIME); + sImm32ImmAssociateContextExStub.Set(sImm32Intercept, "ImmAssociateContextEx", + &ImmAssociateContextExProc); } void From ecd4916dce7b7629be07ad14292c9b559587ea7b Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:51:10 -0600 Subject: [PATCH 20/57] Bug 1460022: Part 8 - Update DLL blocklist to work with revised DLL interceptor interface; r=mhowell --HG-- extra : rebase_source : 04e2f3c3ea6916f43e54a7f8c992f6cbb4fb3286 --- mozglue/build/WindowsDllBlocklist.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/mozglue/build/WindowsDllBlocklist.cpp b/mozglue/build/WindowsDllBlocklist.cpp index 6071e4241986..4b7a6f7ecf6a 100644 --- a/mozglue/build/WindowsDllBlocklist.cpp +++ b/mozglue/build/WindowsDllBlocklist.cpp @@ -90,14 +90,14 @@ printf_stderr(const char *fmt, ...) typedef MOZ_NORETURN_PTR void (__fastcall* BaseThreadInitThunk_func)(BOOL aIsInitialThread, void* aStartAddress, void* aThreadParam); -static BaseThreadInitThunk_func stub_BaseThreadInitThunk = nullptr; +static WindowsDllInterceptor::FuncHookType stub_BaseThreadInitThunk; typedef NTSTATUS (NTAPI *LdrLoadDll_func) (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle); -static LdrLoadDll_func stub_LdrLoadDll; +static WindowsDllInterceptor::FuncHookType stub_LdrLoadDll; #ifdef _M_AMD64 typedef decltype(RtlInstallFunctionTableCallback)* RtlInstallFunctionTableCallback_func; -static RtlInstallFunctionTableCallback_func stub_RtlInstallFunctionTableCallback; +static WindowsDllInterceptor::FuncHookType stub_RtlInstallFunctionTableCallback; extern uint8_t* sMsMpegJitCodeRegionStart; extern size_t sMsMpegJitCodeRegionSize; @@ -662,7 +662,8 @@ DllBlocklist_Initialize(uint32_t aInitFlags) // We specifically use a detour, because there are cases where external // code also tries to hook LdrLoadDll, and doesn't know how to relocate our // nop space patches. (Bug 951827) - bool ok = NtDllIntercept.AddDetour("LdrLoadDll", reinterpret_cast(patched_LdrLoadDll), (void**) &stub_LdrLoadDll); + bool ok = stub_LdrLoadDll.SetDetour(NtDllIntercept, "LdrLoadDll", + &patched_LdrLoadDll); if (!ok) { sBlocklistInitFailed = true; @@ -683,18 +684,18 @@ DllBlocklist_Initialize(uint32_t aInitFlags) #ifdef _M_AMD64 if (!IsWin8OrLater()) { // The crash that this hook works around is only seen on Win7. - Kernel32Intercept.AddHook("RtlInstallFunctionTableCallback", - reinterpret_cast(patched_RtlInstallFunctionTableCallback), - (void**)&stub_RtlInstallFunctionTableCallback); + stub_RtlInstallFunctionTableCallback.Set(Kernel32Intercept, + "RtlInstallFunctionTableCallback", + &patched_RtlInstallFunctionTableCallback); } #endif // Bug 1361410: WRusr.dll will overwrite our hook and cause a crash. // Workaround: If we detect WRusr.dll, don't hook. if (!GetModuleHandleW(L"WRusr.dll")) { - if(!Kernel32Intercept.AddDetour("BaseThreadInitThunk", - reinterpret_cast(patched_BaseThreadInitThunk), - (void**) &stub_BaseThreadInitThunk)) { + if (!stub_BaseThreadInitThunk.SetDetour(Kernel32Intercept, + "BaseThreadInitThunk", + &patched_BaseThreadInitThunk)) { #ifdef DEBUG printf_stderr("BaseThreadInitThunk hook failed\n"); #endif From ca2a5b7f5d08dd48c3087446a7d3ec09da48877c Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:51:29 -0600 Subject: [PATCH 21/57] Bug 1460022: Part 9 - Update sandboxing code to work with revised DLL interceptor interface; r=bobowen --HG-- extra : rebase_source : 03daf9a71dbeb6e27699dad0030a8baf831cbb56 --- security/sandbox/win/SandboxInitialization.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/security/sandbox/win/SandboxInitialization.cpp b/security/sandbox/win/SandboxInitialization.cpp index 8e27b87dd2f4..8a4a5e858072 100644 --- a/security/sandbox/win/SandboxInitialization.cpp +++ b/security/sandbox/win/SandboxInitialization.cpp @@ -15,7 +15,7 @@ namespace mozilla { namespace sandboxing { typedef BOOL(WINAPI* CloseHandle_func) (HANDLE hObject); -static CloseHandle_func stub_CloseHandle = nullptr; +static WindowsDllInterceptor::FuncHookType stub_CloseHandle; typedef BOOL(WINAPI* DuplicateHandle_func)(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, @@ -24,7 +24,8 @@ typedef BOOL(WINAPI* DuplicateHandle_func)(HANDLE hSourceProcessHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions); -static DuplicateHandle_func stub_DuplicateHandle = nullptr; +static WindowsDllInterceptor::FuncHookType + stub_DuplicateHandle; static BOOL WINAPI patched_CloseHandle(HANDLE hObject) @@ -62,17 +63,14 @@ EnableHandleCloseMonitoring() { Kernel32Intercept.Init("kernel32.dll"); bool hooked = - Kernel32Intercept.AddHook("CloseHandle", - reinterpret_cast(patched_CloseHandle), - (void**)&stub_CloseHandle); + stub_CloseHandle.Set(Kernel32Intercept, "CloseHandle", &patched_CloseHandle); if (!hooked) { return false; } hooked = - Kernel32Intercept.AddHook("DuplicateHandle", - reinterpret_cast(patched_DuplicateHandle), - (void**)&stub_DuplicateHandle); + stub_DuplicateHandle.Set(Kernel32Intercept, "DuplicateHandle", + &patched_DuplicateHandle); if (!hooked) { return false; } From 991d4389a0338986a05e00bb247b71c02e3c6ed0 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:51:40 -0600 Subject: [PATCH 22/57] Bug 1460022: Part 10 - Update crash reporter to work with revised DLL interceptor interface; r=dmajor --HG-- extra : rebase_source : 58d231679430ee151f9adf9f6aec59f7e0be3019 --- toolkit/crashreporter/nsExceptionHandler.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp index 7f42278ef244..319f78f27cc0 100644 --- a/toolkit/crashreporter/nsExceptionHandler.cpp +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -338,7 +338,8 @@ nsTArray >* gDelayedAnnotations; // reporter is loaded instead (in case it became unloaded somehow) typedef LPTOP_LEVEL_EXCEPTION_FILTER (WINAPI *SetUnhandledExceptionFilter_func) (LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); -static SetUnhandledExceptionFilter_func stub_SetUnhandledExceptionFilter = 0; +static WindowsDllInterceptor::FuncHookType + stub_SetUnhandledExceptionFilter; static LPTOP_LEVEL_EXCEPTION_FILTER previousUnhandledExceptionFilter = nullptr; static WindowsDllInterceptor gKernel32Intercept; static bool gBlockUnhandledExceptionFilter = true; @@ -1639,9 +1640,9 @@ nsresult SetExceptionHandler(nsIFile* aXREDirectory, // protect the crash reporter from being unloaded gBlockUnhandledExceptionFilter = true; gKernel32Intercept.Init("kernel32.dll"); - bool ok = gKernel32Intercept.AddHook("SetUnhandledExceptionFilter", - reinterpret_cast(patched_SetUnhandledExceptionFilter), - (void**) &stub_SetUnhandledExceptionFilter); + bool ok = stub_SetUnhandledExceptionFilter.Set(gKernel32Intercept, + "SetUnhandledExceptionFilter", + &patched_SetUnhandledExceptionFilter); #ifdef DEBUG if (!ok) From 2a9cc69e857c6e923366d60c0c412f1b8f1c1d6f Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:52:01 -0600 Subject: [PATCH 23/57] Bug 1460022: Part 11 - Update Win32 nsWindow to work with revised DLL interceptor interface; r=mhowell --HG-- extra : rebase_source : 273ea15e8379a8ff51ab6d37d210c86a9d72b78c --- widget/windows/nsWindow.cpp | 46 ++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index db0389563b1e..f15691569075 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -352,9 +352,6 @@ static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); // General purpose user32.dll hook object static WindowsDllInterceptor sUser32Intercept; -// AddHook success checks -static mozilla::Maybe sHookedGetWindowInfo; - // 2 pixel offset for eTransparencyBorderlessGlass which equals the size of // the default window border Windows paints. Glass will be extended inward // this distance to remove the border. @@ -461,17 +458,17 @@ private: if (!IsWin10OrLater() && GetModuleHandle(L"tiptsf.dll") && !sProcessCaretEventsStub) { sTipTsfInterceptor.Init("tiptsf.dll"); - DebugOnly ok = sTipTsfInterceptor.AddHook("ProcessCaretEvents", - reinterpret_cast(&ProcessCaretEventsHook), - (void**) &sProcessCaretEventsStub); + DebugOnly ok = sProcessCaretEventsStub.Set(sTipTsfInterceptor, + "ProcessCaretEvents", + &ProcessCaretEventsHook); MOZ_ASSERT(ok); } if (!sSendMessageTimeoutWStub) { sUser32Intercept.Init("user32.dll"); - DebugOnly hooked = sUser32Intercept.AddHook("SendMessageTimeoutW", - reinterpret_cast(&SendMessageTimeoutWHook), - (void**) &sSendMessageTimeoutWStub); + DebugOnly hooked = sSendMessageTimeoutWStub.Set(sUser32Intercept, + "SendMessageTimeoutW", + &SendMessageTimeoutWHook); MOZ_ASSERT(hooked); } } @@ -556,8 +553,10 @@ private: } static WindowsDllInterceptor sTipTsfInterceptor; - static WINEVENTPROC sProcessCaretEventsStub; - static decltype(&SendMessageTimeoutW) sSendMessageTimeoutWStub; + static WindowsDllInterceptor::FuncHookType + sProcessCaretEventsStub; + static WindowsDllInterceptor::FuncHookType + sSendMessageTimeoutWStub; static StaticAutoPtr sInstance; HHOOK mHook; @@ -566,8 +565,10 @@ private: }; WindowsDllInterceptor TIPMessageHandler::sTipTsfInterceptor; -WINEVENTPROC TIPMessageHandler::sProcessCaretEventsStub; -decltype(&SendMessageTimeoutW) TIPMessageHandler::sSendMessageTimeoutWStub; +WindowsDllInterceptor::FuncHookType + TIPMessageHandler::sProcessCaretEventsStub; +WindowsDllInterceptor::FuncHookType + TIPMessageHandler::sSendMessageTimeoutWStub; StaticAutoPtr TIPMessageHandler::sInstance; } // namespace mozilla @@ -2472,7 +2473,7 @@ nsWindow::ResetLayout() // margins are set. static const wchar_t kManageWindowInfoProperty[] = L"ManageWindowInfoProperty"; typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi); -static GetWindowInfoPtr sGetWindowInfoPtrStub = nullptr; +static WindowsDllInterceptor::FuncHookType sGetWindowInfoPtrStub; BOOL WINAPI GetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi) @@ -2500,18 +2501,15 @@ nsWindow::UpdateGetWindowInfoCaptionStatus(bool aActiveCaption) if (!mWnd) return; - if (sHookedGetWindowInfo.isNothing()) { - sUser32Intercept.Init("user32.dll"); - sHookedGetWindowInfo = - Some(sUser32Intercept.AddHook("GetWindowInfo", - reinterpret_cast(GetWindowInfoHook), - (void**) &sGetWindowInfoPtrStub)); - if (!sHookedGetWindowInfo.value()) { - return; - } + sUser32Intercept.Init("user32.dll"); + sGetWindowInfoPtrStub.Set(sUser32Intercept, "GetWindowInfo", + &GetWindowInfoHook); + if (!sGetWindowInfoPtrStub) { + return; } + // Update our internally tracked caption status - SetPropW(mWnd, kManageWindowInfoProperty, + SetPropW(mWnd, kManageWindowInfoProperty, reinterpret_cast(static_cast(aActiveCaption) + 1)); } From b46c6289f668ca4eb33730a8bf3ac7c3bb71dbfc Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:52:18 -0600 Subject: [PATCH 24/57] Bug 1460022: Part 12 - Update XPCOM to use revised DLL interceptor interface; r=froydnj --HG-- extra : rebase_source : ab4c0b267175365b6f33b23f0f67185738e471ae --- xpcom/base/AvailableMemoryTracker.cpp | 27 +++++------ xpcom/build/PoisonIOInterposerWin.cpp | 64 ++++++++++++--------------- 2 files changed, 39 insertions(+), 52 deletions(-) diff --git a/xpcom/base/AvailableMemoryTracker.cpp b/xpcom/base/AvailableMemoryTracker.cpp index 678566087eda..02265da2c6f1 100644 --- a/xpcom/base/AvailableMemoryTracker.cpp +++ b/xpcom/base/AvailableMemoryTracker.cpp @@ -84,16 +84,14 @@ volatile PRIntervalTime sLastLowMemoryNotificationTime; // These are function pointers to the functions we wrap in Init(). -void* (WINAPI* sVirtualAllocOrig)(LPVOID aAddress, SIZE_T aSize, - DWORD aAllocationType, DWORD aProtect); +static WindowsDllInterceptor::FuncHookType + sVirtualAllocOrig; -void* (WINAPI* sMapViewOfFileOrig)(HANDLE aFileMappingObject, - DWORD aDesiredAccess, DWORD aFileOffsetHigh, - DWORD aFileOffsetLow, SIZE_T aNumBytesToMap); +static WindowsDllInterceptor::FuncHookType + sMapViewOfFileOrig; -HBITMAP(WINAPI* sCreateDIBSectionOrig)(HDC aDC, const BITMAPINFO* aBitmapInfo, - UINT aUsage, VOID** aBits, - HANDLE aSection, DWORD aOffset); +static WindowsDllInterceptor::FuncHookType + sCreateDIBSectionOrig; /** * Fire a memory pressure event if we were not under memory pressure yet, or @@ -645,17 +643,12 @@ Init() // VirtualAllocHook from reentering itself. if (!PR_GetEnv("MOZ_PGO_INSTRUMENTED")) { sKernel32Intercept.Init("Kernel32.dll"); - sKernel32Intercept.AddHook("VirtualAlloc", - reinterpret_cast(VirtualAllocHook), - reinterpret_cast(&sVirtualAllocOrig)); - sKernel32Intercept.AddHook("MapViewOfFile", - reinterpret_cast(MapViewOfFileHook), - reinterpret_cast(&sMapViewOfFileOrig)); + sVirtualAllocOrig.Set(sKernel32Intercept, "VirtualAlloc", &VirtualAllocHook); + sMapViewOfFileOrig.Set(sKernel32Intercept, "MapViewOfFile", &MapViewOfFileHook); sGdi32Intercept.Init("Gdi32.dll"); - sGdi32Intercept.AddHook("CreateDIBSection", - reinterpret_cast(CreateDIBSectionHook), - reinterpret_cast(&sCreateDIBSectionOrig)); + sCreateDIBSectionOrig.Set(sGdi32Intercept, "CreateDIBSection", + &CreateDIBSectionHook); } sInitialized = true; diff --git a/xpcom/build/PoisonIOInterposerWin.cpp b/xpcom/build/PoisonIOInterposerWin.cpp index 6d8bc0a01233..5f2aaec25e28 100644 --- a/xpcom/build/PoisonIOInterposerWin.cpp +++ b/xpcom/build/PoisonIOInterposerWin.cpp @@ -209,13 +209,20 @@ WinIOAutoObservation::Filename(nsAString& aFilename) /*************************** IO Interposing Methods ***************************/ // Function pointers to original functions -static NtCreateFileFn gOriginalNtCreateFile; -static NtReadFileFn gOriginalNtReadFile; -static NtReadFileScatterFn gOriginalNtReadFileScatter; -static NtWriteFileFn gOriginalNtWriteFile; -static NtWriteFileGatherFn gOriginalNtWriteFileGather; -static NtFlushBuffersFileFn gOriginalNtFlushBuffersFile; -static NtQueryFullAttributesFileFn gOriginalNtQueryFullAttributesFile; +static WindowsDllInterceptor::FuncHookType + gOriginalNtCreateFile; +static WindowsDllInterceptor::FuncHookType + gOriginalNtReadFile; +static WindowsDllInterceptor::FuncHookType + gOriginalNtReadFileScatter; +static WindowsDllInterceptor::FuncHookType + gOriginalNtWriteFile; +static WindowsDllInterceptor::FuncHookType + gOriginalNtWriteFileGather; +static WindowsDllInterceptor::FuncHookType + gOriginalNtFlushBuffersFile; +static WindowsDllInterceptor::FuncHookType + gOriginalNtQueryFullAttributesFile; static NTSTATUS NTAPI InterposedNtCreateFile(PHANDLE aFileHandle, @@ -448,34 +455,21 @@ InitPoisonIOInterposer() // Initialize dll interceptor and add hooks sNtDllInterceptor.Init("ntdll.dll"); - sNtDllInterceptor.AddHook( - "NtCreateFile", - reinterpret_cast(InterposedNtCreateFile), - reinterpret_cast(&gOriginalNtCreateFile)); - sNtDllInterceptor.AddHook( - "NtReadFile", - reinterpret_cast(InterposedNtReadFile), - reinterpret_cast(&gOriginalNtReadFile)); - sNtDllInterceptor.AddHook( - "NtReadFileScatter", - reinterpret_cast(InterposedNtReadFileScatter), - reinterpret_cast(&gOriginalNtReadFileScatter)); - sNtDllInterceptor.AddHook( - "NtWriteFile", - reinterpret_cast(InterposedNtWriteFile), - reinterpret_cast(&gOriginalNtWriteFile)); - sNtDllInterceptor.AddHook( - "NtWriteFileGather", - reinterpret_cast(InterposedNtWriteFileGather), - reinterpret_cast(&gOriginalNtWriteFileGather)); - sNtDllInterceptor.AddHook( - "NtFlushBuffersFile", - reinterpret_cast(InterposedNtFlushBuffersFile), - reinterpret_cast(&gOriginalNtFlushBuffersFile)); - sNtDllInterceptor.AddHook( - "NtQueryFullAttributesFile", - reinterpret_cast(InterposedNtQueryFullAttributesFile), - reinterpret_cast(&gOriginalNtQueryFullAttributesFile)); + gOriginalNtCreateFile.Set(sNtDllInterceptor, "NtCreateFile", + &InterposedNtCreateFile); + gOriginalNtReadFile.Set(sNtDllInterceptor, "NtReadFile", + &InterposedNtReadFile); + gOriginalNtReadFileScatter.Set(sNtDllInterceptor, "NtReadFileScatter", + &InterposedNtReadFileScatter); + gOriginalNtWriteFile.Set(sNtDllInterceptor, "NtWriteFile", + &InterposedNtWriteFile); + gOriginalNtWriteFileGather.Set(sNtDllInterceptor, "NtWriteFileGather", + &InterposedNtWriteFileGather); + gOriginalNtFlushBuffersFile.Set(sNtDllInterceptor, "NtFlushBuffersFile", + &InterposedNtFlushBuffersFile); + gOriginalNtQueryFullAttributesFile.Set(sNtDllInterceptor, + "NtQueryFullAttributesFile", + &InterposedNtQueryFullAttributesFile); } void From 9bd593b66dbc98c24a11b3a0dbdb2e88038ca4ee Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 14:23:29 -0600 Subject: [PATCH 25/57] Bug 1460022: Part 13 - Update profiler to use revised DLL interceptor interface; r=njn --HG-- extra : rebase_source : de4708af590df72ce53196712dbb15b57f57dd2e --- tools/profiler/core/platform-win32.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/tools/profiler/core/platform-win32.cpp b/tools/profiler/core/platform-win32.cpp index ee17d1a68b73..04a56fbdf133 100644 --- a/tools/profiler/core/platform-win32.cpp +++ b/tools/profiler/core/platform-win32.cpp @@ -303,7 +303,8 @@ Registers::SyncPopulate() static WindowsDllInterceptor NtDllIntercept; typedef NTSTATUS (NTAPI *LdrUnloadDll_func)(HMODULE module); -static LdrUnloadDll_func stub_LdrUnloadDll; +static WindowsDllInterceptor::FuncHookType + stub_LdrUnloadDll; static NTSTATUS NTAPI patched_LdrUnloadDll(HMODULE module) @@ -318,7 +319,8 @@ patched_LdrUnloadDll(HMODULE module) typedef PVOID (WINAPI *LdrResolveDelayLoadedAPI_func)(PVOID ParentModuleBase, PVOID DelayloadDescriptor, PVOID FailureDllHook, PVOID FailureSystemHook, PVOID ThunkAddress, ULONG Flags); -static LdrResolveDelayLoadedAPI_func stub_LdrResolveDelayLoadedAPI; +static WindowsDllInterceptor::FuncHookType + stub_LdrResolveDelayLoadedAPI; static PVOID WINAPI patched_LdrResolveDelayLoadedAPI(PVOID ParentModuleBase, @@ -336,20 +338,12 @@ patched_LdrResolveDelayLoadedAPI(PVOID ParentModuleBase, void InitializeWin64ProfilerHooks() { - static bool initialized = false; - if (initialized) { - return; - } - initialized = true; - NtDllIntercept.Init("ntdll.dll"); - NtDllIntercept.AddHook("LdrUnloadDll", - reinterpret_cast(patched_LdrUnloadDll), - (void**)&stub_LdrUnloadDll); + stub_LdrUnloadDll.Set(NtDllIntercept, "LdrUnloadDll", &patched_LdrUnloadDll); if (IsWin8OrLater()) { // LdrResolveDelayLoadedAPI was introduced in Win8 - NtDllIntercept.AddHook("LdrResolveDelayLoadedAPI", - reinterpret_cast(patched_LdrResolveDelayLoadedAPI), - (void**)&stub_LdrResolveDelayLoadedAPI); + stub_LdrResolveDelayLoadedAPI.Set(NtDllIntercept, + "LdrResolveDelayLoadedAPI", + &patched_LdrResolveDelayLoadedAPI); } } #endif // defined(GP_PLAT_amd64_windows) From dcc88f33f9bdd0385416805e33cf77cec29d44f5 Mon Sep 17 00:00:00 2001 From: shindli Date: Wed, 4 Jul 2018 02:49:24 +0300 Subject: [PATCH 26/57] Backed out 13 changesets (bug 1460022) for bustages in builds/worker/workspace/build/src/dom/plugins/ipc/FunctionHook.h:100:24 on a CLOSED TREE Backed out changeset 0734142a3f35 (bug 1460022) Backed out changeset 18fbfa7ca685 (bug 1460022) Backed out changeset 2df129bd5692 (bug 1460022) Backed out changeset 02a7ed68933f (bug 1460022) Backed out changeset 221137d1c2de (bug 1460022) Backed out changeset 9cb0b7a15402 (bug 1460022) Backed out changeset 18f8f85c0307 (bug 1460022) Backed out changeset 867a1351efff (bug 1460022) Backed out changeset 933e0b698f8e (bug 1460022) Backed out changeset 09da660071e1 (bug 1460022) Backed out changeset 8bb5142d3f53 (bug 1460022) Backed out changeset 0ddf581bdaac (bug 1460022) Backed out changeset 1cd5f9b4a6af (bug 1460022) --- accessible/windows/msaa/Compatibility.cpp | 11 +- browser/app/winlauncher/DllBlocklistWin.cpp | 8 +- dom/media/gmp/ChromiumCDMAdapter.cpp | 8 +- dom/plugins/base/nsPluginNativeWindowWin.cpp | 36 +- dom/plugins/ipc/FunctionHook.cpp | 21 +- dom/plugins/ipc/FunctionHook.h | 21 +- dom/plugins/ipc/PluginInstanceChild.cpp | 97 +- mozglue/build/WindowsDllBlocklist.cpp | 21 +- mozglue/misc/nsWindowsDllInterceptor.h | 153 +--- .../tests/interceptor/TestDllInterceptor.cpp | 857 +++++++++++------- .../TestDllInterceptorCrossProcess.cpp | 12 +- .../sandbox/win/SandboxInitialization.cpp | 14 +- toolkit/crashreporter/nsExceptionHandler.cpp | 9 +- tools/profiler/core/platform-win32.cpp | 22 +- widget/windows/nsWindow.cpp | 46 +- xpcom/base/AvailableMemoryTracker.cpp | 27 +- xpcom/build/PoisonIOInterposerWin.cpp | 64 +- 17 files changed, 770 insertions(+), 657 deletions(-) diff --git a/accessible/windows/msaa/Compatibility.cpp b/accessible/windows/msaa/Compatibility.cpp index f4434f37c0b5..6446f19805c0 100644 --- a/accessible/windows/msaa/Compatibility.cpp +++ b/accessible/windows/msaa/Compatibility.cpp @@ -95,8 +95,7 @@ Compatibility::IsModuleVersionLessThan(HMODULE aModuleHandle, //////////////////////////////////////////////////////////////////////////////// static WindowsDllInterceptor sUser32Interceptor; -static WindowsDllInterceptor::FuncHookType - sInSendMessageExStub; +static decltype(&InSendMessageEx) sInSendMessageExStub = nullptr; static bool sInSendMessageExHackEnabled = false; static PVOID sVectoredExceptionHandler = nullptr; @@ -268,9 +267,11 @@ Compatibility::Init() if ((sConsumers & (~(UIAUTOMATION | NVDA))) && BrowserTabsRemoteAutostart()) { sUser32Interceptor.Init("user32.dll"); - sInSendMessageExStub.Set(sUser32Interceptor, "InSendMessageEx", - &InSendMessageExHook); - + if (!sInSendMessageExStub) { + sUser32Interceptor.AddHook("InSendMessageEx", + reinterpret_cast(&InSendMessageExHook), + (void**)&sInSendMessageExStub); + } // The vectored exception handler allows us to catch exceptions ahead of any // SEH handlers. if (!sVectoredExceptionHandler) { diff --git a/browser/app/winlauncher/DllBlocklistWin.cpp b/browser/app/winlauncher/DllBlocklistWin.cpp index a88a0747348f..82e1d77d3722 100644 --- a/browser/app/winlauncher/DllBlocklistWin.cpp +++ b/browser/app/winlauncher/DllBlocklistWin.cpp @@ -246,8 +246,7 @@ IsDllAllowed(const UNICODE_STRING& aLeafName, void* aBaseAddress) } typedef decltype(&NtMapViewOfSection) NtMapViewOfSection_func; -static mozilla::CrossProcessDllInterceptor::FuncHookType - stub_NtMapViewOfSection; +static NtMapViewOfSection_func stub_NtMapViewOfSection; static NTSTATUS NTAPI patched_NtMapViewOfSection(HANDLE aSection, HANDLE aProcess, PVOID* aBaseAddress, @@ -357,8 +356,9 @@ InitializeDllBlocklistOOP(HANDLE aChildProcess) { mozilla::CrossProcessDllInterceptor intcpt(aChildProcess); intcpt.Init(L"ntdll.dll"); - bool ok = stub_NtMapViewOfSection.SetDetour(intcpt, "NtMapViewOfSection", - &patched_NtMapViewOfSection); + bool ok = intcpt.AddDetour("NtMapViewOfSection", + reinterpret_cast(&patched_NtMapViewOfSection), + (void**) &stub_NtMapViewOfSection); if (!ok) { return false; } diff --git a/dom/media/gmp/ChromiumCDMAdapter.cpp b/dom/media/gmp/ChromiumCDMAdapter.cpp index e1946dee5106..b8fbe7a2f9da 100644 --- a/dom/media/gmp/ChromiumCDMAdapter.cpp +++ b/dom/media/gmp/ChromiumCDMAdapter.cpp @@ -197,8 +197,7 @@ typedef DWORD(WINAPI* QueryDosDeviceWFnPtr)(_In_opt_ LPCWSTR lpDeviceName, _Out_ LPWSTR lpTargetPath, _In_ DWORD ucchMax); -static WindowsDllInterceptor::FuncHookType - sOriginalQueryDosDeviceWFnPtr; +static QueryDosDeviceWFnPtr sOriginalQueryDosDeviceWFnPtr = nullptr; static std::unordered_map* sDeviceNames = nullptr; @@ -277,8 +276,9 @@ InitializeHooks() } sKernel32Intercept.Init("kernelbase.dll"); - sOriginalQueryDosDeviceWFnPtr.Set(sKernel32Intercept, "QueryDosDeviceW", - &QueryDosDeviceWHook); + sKernel32Intercept.AddHook("QueryDosDeviceW", + reinterpret_cast(QueryDosDeviceWHook), + (void**)(&sOriginalQueryDosDeviceWFnPtr)); } #endif diff --git a/dom/plugins/base/nsPluginNativeWindowWin.cpp b/dom/plugins/base/nsPluginNativeWindowWin.cpp index 570b99e52610..fc7f0ea72345 100644 --- a/dom/plugins/base/nsPluginNativeWindowWin.cpp +++ b/dom/plugins/base/nsPluginNativeWindowWin.cpp @@ -357,10 +357,8 @@ typedef LONG_PTR (WINAPI *User32SetWindowLongPtrW)(HWND hWnd, int nIndex, LONG_PTR dwNewLong); -static WindowsDllInterceptor::FuncHookType - sUser32SetWindowLongAHookStub; -static WindowsDllInterceptor::FuncHookType - sUser32SetWindowLongWHookStub; +static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = nullptr; +static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = nullptr; #else typedef LONG (WINAPI *User32SetWindowLongA)(HWND hWnd, @@ -370,10 +368,8 @@ typedef LONG (WINAPI *User32SetWindowLongW)(HWND hWnd, int nIndex, LONG dwNewLong); -static WindowsDllInterceptor::FuncHookType - sUser32SetWindowLongAHookStub; -static WindowsDllInterceptor::FuncHookType - sUser32SetWindowLongWHookStub; +static User32SetWindowLongA sUser32SetWindowLongAHookStub = nullptr; +static User32SetWindowLongW sUser32SetWindowLongWHookStub = nullptr; #endif static inline bool SetWindowLongHookCheck(HWND hWnd, @@ -452,15 +448,23 @@ HookSetWindowLongPtr() { sUser32Intercept.Init("user32.dll"); #ifdef _WIN64 - sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongPtrA", - &SetWindowLongPtrAHook); - sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongPtrW", - &SetWindowLongPtrWHook); + if (!sUser32SetWindowLongAHookStub) + sUser32Intercept.AddHook("SetWindowLongPtrA", + reinterpret_cast(SetWindowLongPtrAHook), + (void**) &sUser32SetWindowLongAHookStub); + if (!sUser32SetWindowLongWHookStub) + sUser32Intercept.AddHook("SetWindowLongPtrW", + reinterpret_cast(SetWindowLongPtrWHook), + (void**) &sUser32SetWindowLongWHookStub); #else - sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongA", - &SetWindowLongAHook); - sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongW", - &SetWindowLongWHook); + if (!sUser32SetWindowLongAHookStub) + sUser32Intercept.AddHook("SetWindowLongA", + reinterpret_cast(SetWindowLongAHook), + (void**) &sUser32SetWindowLongAHookStub); + if (!sUser32SetWindowLongWHookStub) + sUser32Intercept.AddHook("SetWindowLongW", + reinterpret_cast(SetWindowLongWHook), + (void**) &sUser32SetWindowLongWHookStub); #endif } diff --git a/dom/plugins/ipc/FunctionHook.cpp b/dom/plugins/ipc/FunctionHook.cpp index 3d4733a19277..d5e29ec14f18 100644 --- a/dom/plugins/ipc/FunctionHook.cpp +++ b/dom/plugins/ipc/FunctionHook.cpp @@ -168,13 +168,13 @@ typedef HANDLE (WINAPI *CreateFileWPtr)(LPCWSTR aFname, DWORD aAccess, LPSECURITY_ATTRIBUTES aSecurity, DWORD aCreation, DWORD aFlags, HANDLE aFTemplate); -static WindowsDllInterceptor::FuncHookType sCreateFileWStub; +static CreateFileWPtr sCreateFileWStub = nullptr; typedef HANDLE (WINAPI *CreateFileAPtr)(LPCSTR aFname, DWORD aAccess, DWORD aShare, LPSECURITY_ATTRIBUTES aSecurity, DWORD aCreation, DWORD aFlags, HANDLE aFTemplate); -static WindowsDllInterceptor::FuncHookType sCreateFileAStub; +static CreateFileAPtr sCreateFileAStub = nullptr; // Windows 8 RTM (kernelbase's version is 6.2.9200.16384) doesn't call // CreateFileW from CreateFileA. @@ -263,7 +263,7 @@ CreateFileWHookFn(LPCWSTR aFname, DWORD aAccess, DWORD aShare, aSecurity, TRUNCATE_EXISTING, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, - nullptr); + NULL); if (replacement == INVALID_HANDLE_VALUE) { break; } @@ -300,12 +300,23 @@ CreateFileWHookFn(LPCWSTR aFname, DWORD aAccess, DWORD aShare, void FunctionHook::HookProtectedMode() { + // Make sure we only do this once. + static bool sRunOnce = false; + if (sRunOnce) { + return; + } + sRunOnce = true; + // Legacy code. Uses the nsWindowsDLLInterceptor directly instead of // using the FunctionHook sKernel32Intercept.Init("kernel32.dll"); MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Plugin); - sCreateFileWStub.Set(sKernel32Intercept, "CreateFileW", &CreateFileWHookFn); - sCreateFileAStub.Set(sKernel32Intercept, "CreateFileA", &CreateFileAHookFn); + sKernel32Intercept.AddHook("CreateFileW", + reinterpret_cast(CreateFileWHookFn), + (void**) &sCreateFileWStub); + sKernel32Intercept.AddHook("CreateFileA", + reinterpret_cast(CreateFileAHookFn), + (void**) &sCreateFileAStub); } #endif // defined(XP_WIN) diff --git a/dom/plugins/ipc/FunctionHook.h b/dom/plugins/ipc/FunctionHook.h index 169cc86adefc..c9b30dd0643a 100644 --- a/dom/plugins/ipc/FunctionHook.h +++ b/dom/plugins/ipc/FunctionHook.h @@ -9,7 +9,6 @@ #include "IpdlTuple.h" #include "base/process.h" -#include "mozilla/Atomics.h" #if defined(XP_WIN) #include "nsWindowsDllInterceptor.h" @@ -97,17 +96,12 @@ typedef bool(ShouldHookFunc)(int aQuirks); template class BasicFunctionHook : public FunctionHook { - using FuncHookType = WindowsDllInterceptor::FuncHookType; - public: BasicFunctionHook(const char* aModuleName, const char* aFunctionName, FunctionType* aOldFunction, - FunctionType* aNewFunction) - : mOldFunction(aOldFunction) - , mRegistration(UNREGISTERED) - , mModuleName(aModuleName) - , mFunctionName(aFunctionName) - , mNewFunction(aNewFunction) + FunctionType* aNewFunction) : + mOldFunction(aOldFunction), mRegistration(UNREGISTERED), mModuleName(aModuleName), + mFunctionName(aFunctionName), mNewFunction(aNewFunction) { MOZ_ASSERT(mOldFunction); MOZ_ASSERT(mNewFunction); @@ -134,8 +128,7 @@ protected: // Once the function is hooked, this field will take the value of a pointer to // a function that performs the old behavior. Before that, it is a pointer to // the original function. - Atomic mOldFunction; - FuncHookType mStub; + FunctionType* mOldFunction; enum RegistrationStatus { UNREGISTERED, FAILED, SUCCEEDED }; RegistrationStatus mRegistration; @@ -177,14 +170,14 @@ BasicFunctionHook::Register(int aQuirks) return false; } - isHooked = mStub.Set(*dllInterceptor, mFunctionName.Data(), mNewFunction); + isHooked = + dllInterceptor->AddHook(mFunctionName.Data(), reinterpret_cast(mNewFunction), + reinterpret_cast(&mOldFunction)); #endif if (isHooked) { - mOldFunction = mStub.GetStub(); mRegistration = SUCCEEDED; } - HOOK_LOG(LogLevel::Debug, ("Registering to intercept function '%s' : '%s'", mFunctionName.Data(), SuccessMsg(isHooked))); diff --git a/dom/plugins/ipc/PluginInstanceChild.cpp b/dom/plugins/ipc/PluginInstanceChild.cpp index bab3067be6ee..47e779a6072c 100644 --- a/dom/plugins/ipc/PluginInstanceChild.cpp +++ b/dom/plugins/ipc/PluginInstanceChild.cpp @@ -73,17 +73,21 @@ typedef BOOL (WINAPI *User32TrackPopupMenu)(HMENU hMenu, CONST RECT *prcRect); static WindowsDllInterceptor sUser32Intercept; static HWND sWinlessPopupSurrogateHWND = nullptr; -static WindowsDllInterceptor::FuncHookType sUser32TrackPopupMenuStub; +static User32TrackPopupMenu sUser32TrackPopupMenuStub = nullptr; static WindowsDllInterceptor sImm32Intercept; -static WindowsDllInterceptor::FuncHookType sImm32ImmGetContextStub; -static WindowsDllInterceptor::FuncHookType sImm32ImmGetCompositionStringStub; -static WindowsDllInterceptor::FuncHookType sImm32ImmSetCandidateWindowStub; -static WindowsDllInterceptor::FuncHookType sImm32ImmNotifyIME; -static WindowsDllInterceptor::FuncHookType sImm32ImmAssociateContextExStub; - +static decltype(ImmGetContext)* sImm32ImmGetContextStub = nullptr; +static decltype(ImmGetCompositionStringW)* sImm32ImmGetCompositionStringStub = + nullptr; +static decltype(ImmSetCandidateWindow)* sImm32ImmSetCandidateWindowStub = + nullptr; +static decltype(ImmNotifyIME)* sImm32ImmNotifyIME = nullptr; +static decltype(ImmAssociateContextEx)* sImm32ImmAssociateContextExStub = + nullptr; static PluginInstanceChild* sCurrentPluginInstance = nullptr; static const HIMC sHookIMC = (const HIMC)0xefefefef; +static bool sPopupMenuHookSet; +static bool sSetWindowLongHookSet; using mozilla::gfx::SharedDIB; @@ -1789,8 +1793,8 @@ typedef LONG_PTR (WINAPI *User32SetWindowLongPtrW)(HWND hWnd, int nIndex, LONG_PTR dwNewLong); -static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongAHookStub; -static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongWHookStub; +static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = nullptr; +static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = nullptr; #else typedef LONG (WINAPI *User32SetWindowLongA)(HWND hWnd, @@ -1800,8 +1804,8 @@ typedef LONG (WINAPI *User32SetWindowLongW)(HWND hWnd, int nIndex, LONG dwNewLong); -static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongAHookStub; -static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongWHookStub; +static User32SetWindowLongA sUser32SetWindowLongAHookStub = nullptr; +static User32SetWindowLongW sUser32SetWindowLongWHookStub = nullptr; #endif extern LRESULT CALLBACK @@ -1911,17 +1915,27 @@ PluginInstanceChild::HookSetWindowLongPtr() return; } + // Only pass through here once + if (sSetWindowLongHookSet) { + return; + } + sSetWindowLongHookSet = true; + sUser32Intercept.Init("user32.dll"); #ifdef _WIN64 - sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongPtrA", - &SetWindowLongPtrAHook); - sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongPtrW", - &SetWindowLongPtrWHook); + if (!sUser32SetWindowLongAHookStub) + sUser32Intercept.AddHook("SetWindowLongPtrA", reinterpret_cast(SetWindowLongPtrAHook), + (void**) &sUser32SetWindowLongAHookStub); + if (!sUser32SetWindowLongWHookStub) + sUser32Intercept.AddHook("SetWindowLongPtrW", reinterpret_cast(SetWindowLongPtrWHook), + (void**) &sUser32SetWindowLongWHookStub); #else - sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongA", - &SetWindowLongAHook); - sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongW", - &SetWindowLongWHook); + if (!sUser32SetWindowLongAHookStub) + sUser32Intercept.AddHook("SetWindowLongA", reinterpret_cast(SetWindowLongAHook), + (void**) &sUser32SetWindowLongAHookStub); + if (!sUser32SetWindowLongWHookStub) + sUser32Intercept.AddHook("SetWindowLongW", reinterpret_cast(SetWindowLongWHook), + (void**) &sUser32SetWindowLongWHookStub); #endif } @@ -1989,13 +2003,19 @@ PluginInstanceChild::InitPopupMenuHook() return; } + // Only pass through here once + if (sPopupMenuHookSet) { + return; + } + sPopupMenuHookSet = true; + // Note, once WindowsDllInterceptor is initialized for a module, // it remains initialized for that particular module for it's // lifetime. Additional instances are needed if other modules need // to be hooked. sUser32Intercept.Init("user32.dll"); - sUser32TrackPopupMenuStub.Set(sUser32Intercept, "TrackPopupMenu", - &TrackPopupHookProc); + sUser32Intercept.AddHook("TrackPopupMenu", reinterpret_cast(TrackPopupHookProc), + (void**) &sUser32TrackPopupMenuStub); } void @@ -2137,23 +2157,36 @@ PluginInstanceChild::InitImm32Hook() return; } + if (sImm32ImmGetContextStub) { + return; + } + // When using windowless plugin, IMM API won't work due ot OOP. // // ImmReleaseContext on Windows 7+ just returns TRUE only, so we don't // need to hook this. sImm32Intercept.Init("imm32.dll"); - sImm32ImmGetContextStub.Set(sImm32Intercept, "ImmGetContext", - &ImmGetContextProc); - sImm32ImmGetCompositionStringStub.Set(sImm32Intercept, - "ImmGetCompositionStringW", - &ImmGetCompositionStringProc); - sImm32ImmSetCandidateWindowStub.Set(sImm32Intercept, - "ImmSetCandidateWindow", - &ImmSetCandidateWindowProc); - sImm32ImmNotifyIME.Set(sImm32Intercept, "ImmNotifyIME", &ImmNotifyIME); - sImm32ImmAssociateContextExStub.Set(sImm32Intercept, "ImmAssociateContextEx", - &ImmAssociateContextExProc); + sImm32Intercept.AddHook( + "ImmGetContext", + reinterpret_cast(ImmGetContextProc), + (void**)&sImm32ImmGetContextStub); + sImm32Intercept.AddHook( + "ImmGetCompositionStringW", + reinterpret_cast(ImmGetCompositionStringProc), + (void**)&sImm32ImmGetCompositionStringStub); + sImm32Intercept.AddHook( + "ImmSetCandidateWindow", + reinterpret_cast(ImmSetCandidateWindowProc), + (void**)&sImm32ImmSetCandidateWindowStub); + sImm32Intercept.AddHook( + "ImmNotifyIME", + reinterpret_cast(ImmNotifyIME), + (void**)&sImm32ImmNotifyIME); + sImm32Intercept.AddHook( + "ImmAssociateContextEx", + reinterpret_cast(ImmAssociateContextExProc), + (void**)&sImm32ImmAssociateContextExStub); } void diff --git a/mozglue/build/WindowsDllBlocklist.cpp b/mozglue/build/WindowsDllBlocklist.cpp index 4b7a6f7ecf6a..6071e4241986 100644 --- a/mozglue/build/WindowsDllBlocklist.cpp +++ b/mozglue/build/WindowsDllBlocklist.cpp @@ -90,14 +90,14 @@ printf_stderr(const char *fmt, ...) typedef MOZ_NORETURN_PTR void (__fastcall* BaseThreadInitThunk_func)(BOOL aIsInitialThread, void* aStartAddress, void* aThreadParam); -static WindowsDllInterceptor::FuncHookType stub_BaseThreadInitThunk; +static BaseThreadInitThunk_func stub_BaseThreadInitThunk = nullptr; typedef NTSTATUS (NTAPI *LdrLoadDll_func) (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle); -static WindowsDllInterceptor::FuncHookType stub_LdrLoadDll; +static LdrLoadDll_func stub_LdrLoadDll; #ifdef _M_AMD64 typedef decltype(RtlInstallFunctionTableCallback)* RtlInstallFunctionTableCallback_func; -static WindowsDllInterceptor::FuncHookType stub_RtlInstallFunctionTableCallback; +static RtlInstallFunctionTableCallback_func stub_RtlInstallFunctionTableCallback; extern uint8_t* sMsMpegJitCodeRegionStart; extern size_t sMsMpegJitCodeRegionSize; @@ -662,8 +662,7 @@ DllBlocklist_Initialize(uint32_t aInitFlags) // We specifically use a detour, because there are cases where external // code also tries to hook LdrLoadDll, and doesn't know how to relocate our // nop space patches. (Bug 951827) - bool ok = stub_LdrLoadDll.SetDetour(NtDllIntercept, "LdrLoadDll", - &patched_LdrLoadDll); + bool ok = NtDllIntercept.AddDetour("LdrLoadDll", reinterpret_cast(patched_LdrLoadDll), (void**) &stub_LdrLoadDll); if (!ok) { sBlocklistInitFailed = true; @@ -684,18 +683,18 @@ DllBlocklist_Initialize(uint32_t aInitFlags) #ifdef _M_AMD64 if (!IsWin8OrLater()) { // The crash that this hook works around is only seen on Win7. - stub_RtlInstallFunctionTableCallback.Set(Kernel32Intercept, - "RtlInstallFunctionTableCallback", - &patched_RtlInstallFunctionTableCallback); + Kernel32Intercept.AddHook("RtlInstallFunctionTableCallback", + reinterpret_cast(patched_RtlInstallFunctionTableCallback), + (void**)&stub_RtlInstallFunctionTableCallback); } #endif // Bug 1361410: WRusr.dll will overwrite our hook and cause a crash. // Workaround: If we detect WRusr.dll, don't hook. if (!GetModuleHandleW(L"WRusr.dll")) { - if (!stub_BaseThreadInitThunk.SetDetour(Kernel32Intercept, - "BaseThreadInitThunk", - &patched_BaseThreadInitThunk)) { + if(!Kernel32Intercept.AddDetour("BaseThreadInitThunk", + reinterpret_cast(patched_BaseThreadInitThunk), + (void**) &stub_BaseThreadInitThunk)) { #ifdef DEBUG printf_stderr("BaseThreadInitThunk hook failed\n"); #endif diff --git a/mozglue/misc/nsWindowsDllInterceptor.h b/mozglue/misc/nsWindowsDllInterceptor.h index 4ae504257b56..3020f795fede 100644 --- a/mozglue/misc/nsWindowsDllInterceptor.h +++ b/mozglue/misc/nsWindowsDllInterceptor.h @@ -8,12 +8,10 @@ #define NS_WINDOWS_DLL_INTERCEPTOR_H_ #include "mozilla/Assertions.h" -#include "mozilla/Attributes.h" #include "mozilla/ArrayUtils.h" #include "mozilla/CheckedInt.h" #include "mozilla/DebugOnly.h" -#include "mozilla/Move.h" -#include "mozilla/Tuple.h" +#include "mozilla/NotNull.h" #include "mozilla/TypeTraits.h" #include "mozilla/Types.h" #include "mozilla/UniquePtr.h" @@ -84,143 +82,6 @@ namespace mozilla { namespace interceptor { -template -class FuncHook final -{ - template - struct OriginalFunctionPtrTraits; - - template - struct OriginalFunctionPtrTraits - { - using ReturnType = R; - }; - -#if defined(_M_IX86) - template - struct OriginalFunctionPtrTraits - { - using ReturnType = R; - }; - - template - struct OriginalFunctionPtrTraits - { - using ReturnType = R; - }; -#endif // defined(_M_IX86) - -public: - using ThisType = FuncHook; - using ReturnType = typename OriginalFunctionPtrTraits::ReturnType; - - constexpr FuncHook() - : mOrigFunc(nullptr) - , mInitOnce(INIT_ONCE_STATIC_INIT) - { - } - - ~FuncHook() = default; - - bool Set(InterceptorT& aInterceptor, const char* aName, - FuncPtrT aHookDest) - { - LPVOID addHookOk; - InitOnceContext ctx(this, &aInterceptor, aName, aHookDest, false); - - return ::InitOnceExecuteOnce(&mInitOnce, &InitOnceCallback, &ctx, - &addHookOk) && addHookOk; - } - - bool SetDetour(InterceptorT& aInterceptor, const char* aName, - FuncPtrT aHookDest) - { - LPVOID addHookOk; - InitOnceContext ctx(this, &aInterceptor, aName, aHookDest, true); - - return ::InitOnceExecuteOnce(&mInitOnce, &InitOnceCallback, &ctx, - &addHookOk) && addHookOk; - } - - explicit operator bool() const - { - return !!mOrigFunc; - } - - template - ReturnType operator()(ArgsType... aArgs) const - { - return mOrigFunc(std::forward(aArgs)...); - } - - FuncPtrT GetStub() const - { - return mOrigFunc; - } - - // One-time init stuff cannot be moved or copied - FuncHook(const FuncHook&) = delete; - FuncHook(FuncHook&&) = delete; - FuncHook& operator=(const FuncHook&) = delete; - FuncHook& operator=(FuncHook&& aOther) = delete; - -private: - struct MOZ_RAII InitOnceContext final - { - InitOnceContext(ThisType* aHook, InterceptorT* aInterceptor, - const char* aName, void* aHookDest, bool aForceDetour) - : mHook(aHook) - , mInterceptor(aInterceptor) - , mName(aName) - , mHookDest(aHookDest) - , mForceDetour(aForceDetour) - { - } - - ThisType* mHook; - InterceptorT* mInterceptor; - const char* mName; - void* mHookDest; - bool mForceDetour; - }; - -private: - bool Apply(InterceptorT* aInterceptor, const char* aName, void* aHookDest) - { - return aInterceptor->AddHook(aName, reinterpret_cast(aHookDest), - reinterpret_cast(&mOrigFunc)); - } - - bool ApplyDetour(InterceptorT* aInterceptor, const char* aName, - void* aHookDest) - { - return aInterceptor->AddDetour(aName, reinterpret_cast(aHookDest), - reinterpret_cast(&mOrigFunc)); - } - - static BOOL CALLBACK - InitOnceCallback(PINIT_ONCE aInitOnce, PVOID aParam, PVOID* aOutContext) - { - MOZ_ASSERT(aOutContext); - - bool result; - auto ctx = reinterpret_cast(aParam); - if (ctx->mForceDetour) { - result = ctx->mHook->ApplyDetour(ctx->mInterceptor, ctx->mName, - ctx->mHookDest); - } else { - result = ctx->mHook->Apply(ctx->mInterceptor, ctx->mName, ctx->mHookDest); - } - - *aOutContext = result ? reinterpret_cast(1U << INIT_ONCE_CTX_RESERVED_BITS) : nullptr; - return TRUE; - } - -private: - FuncPtrT mOrigFunc; - INIT_ONCE mInitOnce; -}; - enum { kDefaultTrampolineSize = 128 @@ -231,8 +92,6 @@ template > class WindowsDllInterceptor final { - typedef WindowsDllInterceptor ThisType; - interceptor::WindowsDllDetourPatcher mDetourPatcher; #if defined(_M_IX86) interceptor::WindowsDllNopSpacePatcher mNopSpacePatcher; @@ -301,7 +160,6 @@ public: // NB: We intentionally leak mModule } -private: /** * Hook/detour the method aName from the DLL we set in Init so that it calls * aHookDest instead. Returns the original method pointer in aOrigFunc @@ -361,6 +219,7 @@ private: return AddDetour(proc, aHookDest, aOrigFunc); } +private: bool AddDetour(FARPROC aProc, intptr_t aHookDest, void** aOrigFunc) { MOZ_ASSERT(mModule && aProc); @@ -371,14 +230,6 @@ private: return mDetourPatcher.AddHook(aProc, aHookDest, aOrigFunc); } - -public: - template - using FuncHookType = FuncHook; - -private: - template - friend class FuncHook; }; } // namespace interceptor diff --git a/mozglue/tests/interceptor/TestDllInterceptor.cpp b/mozglue/tests/interceptor/TestDllInterceptor.cpp index 989ee97d0b28..6007a8995201 100644 --- a/mozglue/tests/interceptor/TestDllInterceptor.cpp +++ b/mozglue/tests/interceptor/TestDllInterceptor.cpp @@ -10,33 +10,10 @@ #include #include -#include "mozilla/TypeTraits.h" -#include "mozilla/UniquePtr.h" #include "mozilla/WindowsVersion.h" #include "nsWindowsDllInterceptor.h" #include "nsWindowsHelpers.h" -NTSTATUS NTAPI NtFlushBuffersFile(HANDLE, PIO_STATUS_BLOCK); -NTSTATUS NTAPI NtReadFile(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PVOID, ULONG, - PLARGE_INTEGER, PULONG); -NTSTATUS NTAPI NtReadFileScatter(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, - PLARGE_INTEGER, PULONG); -NTSTATUS NTAPI NtWriteFile(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PVOID, ULONG, - PLARGE_INTEGER, PULONG); -NTSTATUS NTAPI NtWriteFileGather(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, - PLARGE_INTEGER, PULONG); -NTSTATUS NTAPI NtQueryFullAttributesFile(POBJECT_ATTRIBUTES, PVOID); -NTSTATUS NTAPI LdrLoadDll(PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle); -NTSTATUS NTAPI LdrUnloadDll(HMODULE); -// These pointers are disguised as PVOID to avoid pulling in obscure headers -PVOID NTAPI LdrResolveDelayLoadedAPI(PVOID, PVOID, PVOID, PVOID, PVOID, ULONG); -void CALLBACK ProcessCaretEvents(HWINEVENTHOOK, DWORD, HWND, LONG, LONG, DWORD, DWORD); -void __fastcall BaseThreadInitThunk(BOOL aIsInitialThread, void* aStartAddress, void* aThreadParam); - using namespace mozilla; struct payload { @@ -61,8 +38,7 @@ extern "C" __declspec(dllexport) __declspec(noinline) payload rotatePayload(payl static bool patched_func_called = false; -static WindowsDllInterceptor::FuncHookType - orig_rotatePayload; +static payload (*orig_rotatePayload)(payload); static payload patched_rotatePayload(payload p) @@ -71,61 +47,11 @@ patched_rotatePayload(payload p) return orig_rotatePayload(p); } -// Invoke aFunc by taking aArg's contents and using them as aFunc's arguments -template , size_t... Indices> -decltype(auto) Apply(CallableT&& aFunc, ArgTuple&& aArgs, std::index_sequence) +typedef bool(*HookTestFunc)(void*); +bool CheckHook(HookTestFunc aHookTestFunc, void* aOrigFunc, + const char* aDllName, const char* aFuncName) { - return std::forward(aFunc)(Get(std::forward(aArgs))...); -} - -template -bool TestFunction(CallableT aFunc); - -#define DEFINE_TEST_FUNCTION(calling_convention) \ - template \ - bool TestFunction(WindowsDllInterceptor::FuncHookType&& aFunc, \ - bool (* aPred)(R), TestArgs... aArgs) \ - { \ - using FuncHookType = WindowsDllInterceptor::FuncHookType; \ - using ArgTuple = Tuple; \ - using Indices = std::index_sequence_for; \ - ArgTuple fakeArgs{ std::forward(aArgs)... }; \ - return aPred(Apply(std::forward(aFunc), std::forward(fakeArgs), Indices())); \ - } \ - \ - /* Specialization for functions returning void */ \ - template \ - bool TestFunction(WindowsDllInterceptor::FuncHookType&& aFunc, \ - PredicateT&& aPred, TestArgs... aArgs) \ - { \ - using FuncHookType = WindowsDllInterceptor::FuncHookType; \ - using ArgTuple = Tuple; \ - using Indices = std::index_sequence_for; \ - ArgTuple fakeArgs{ std::forward(aArgs)... }; \ - Apply(std::forward(aFunc), std::forward(fakeArgs), Indices()); \ - return true; \ - } - -// C++11 allows empty arguments to macros. clang works just fine. MSVC does the -// right thing, but it also throws up warning C4003. -#if defined(_MSC_VER) && !defined(__clang__) -DEFINE_TEST_FUNCTION(__cdecl) -#else -DEFINE_TEST_FUNCTION() -#endif - -#ifdef _M_IX86 -DEFINE_TEST_FUNCTION(__stdcall) -DEFINE_TEST_FUNCTION(__fastcall) -#endif // _M_IX86 - -// Test the hooked function against the supplied predicate -template -bool CheckHook(WindowsDllInterceptor::FuncHookType &aOrigFunc, - const char* aDllName, const char* aFuncName, PredicateT&& aPred, - Args... aArgs) -{ - if (TestFunction(std::forward>(aOrigFunc), std::forward(aPred), std::forward(aArgs)...)) { + if (aHookTestFunc(aOrigFunc)) { printf("TEST-PASS | WindowsDllInterceptor | " "Executed hooked function %s from %s\n", aFuncName, aDllName); return true; @@ -135,235 +61,57 @@ bool CheckHook(WindowsDllInterceptor::FuncHookType &aOrigFunc, return false; } -// Hook the function and optionally attempt calling it -template -bool TestHook(const char (&dll)[N], const char *func, PredicateT&& aPred, Args... aArgs) +template +bool TestHook(HookTestFunc funcTester, const char (&dll)[N], const char *func) { - auto orig_func(mozilla::MakeUnique>()); - + void *orig_func; bool successful = false; { WindowsDllInterceptor TestIntercept; TestIntercept.Init(dll); - successful = orig_func->Set(TestIntercept, func, nullptr); + successful = TestIntercept.AddHook(func, 0, &orig_func); } if (successful) { printf("TEST-PASS | WindowsDllInterceptor | Could hook %s from %s\n", func, dll); - if (!aPred) { - printf("TEST-SKIPPED | WindowsDllInterceptor | " - "Will not attempt to execute patched %s.\n", func); - return true; - } - - return CheckHook(*orig_func, dll, func, std::forward(aPred), std::forward(aArgs)...); + return CheckHook(funcTester, orig_func, dll, func); } else { printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to hook %s from %s\n", func, dll); return false; } } -// Detour the function and optionally attempt calling it -template -bool TestDetour(const char (&dll)[N], const char *func, PredicateT&& aPred) +template +bool TestDetour(const char (&dll)[N], const char *func) { - auto orig_func(mozilla::MakeUnique>()); - + void *orig_func; bool successful = false; { WindowsDllInterceptor TestIntercept; TestIntercept.Init(dll); - successful = orig_func->SetDetour(TestIntercept, func, nullptr); + successful = TestIntercept.AddDetour(func, 0, &orig_func); } if (successful) { printf("TEST-PASS | WindowsDllInterceptor | Could detour %s from %s\n", func, dll); - if (!aPred) { - printf("TEST-SKIPPED | WindowsDllInterceptor | " - "Will not attempt to execute patched %s.\n", func); - return true; - } - - return CheckHook(*orig_func, dll, func, std::forward(aPred)); + return true; } else { printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to detour %s from %s\n", func, dll); return false; } } -// If a function pointer's type returns void*, this template converts that type -// to return uintptr_t instead, for the purposes of predicates. -template -struct SubstituteForVoidPtr -{ - using Type = FuncT; -}; - -template -struct SubstituteForVoidPtr -{ - using Type = uintptr_t (*)(Args...); -}; - -#ifdef _M_IX86 -template -struct SubstituteForVoidPtr -{ - using Type = uintptr_t (__stdcall*)(Args...); -}; - -template -struct SubstituteForVoidPtr -{ - using Type = uintptr_t (__fastcall*)(Args...); -}; -#endif // _M_IX86 - -// Determines the function's return type -template -struct ReturnType; - -template -struct ReturnType -{ - using Type = R; -}; - -#ifdef _M_IX86 -template -struct ReturnType -{ - using Type = R; -}; - -template -struct ReturnType -{ - using Type = R; -}; -#endif // _M_IX86 - -// Predicates that may be supplied during tests -template -struct Predicates -{ - using ArgType = typename ReturnType::Type; - - template - static bool Equals(ArgType aValue) - { - return CompVal == aValue; - } - - template - static bool NotEquals(ArgType aValue) - { - return CompVal != aValue; - } - - template - static bool Ignore(ArgType aValue) - { - return true; - } -}; - -// Functions that return void should be ignored, so we specialize the -// Ignore predicate for that case. Use nullptr as the value to compare against. -template -struct Predicates -{ - template - static bool Ignore() - { - return true; - } -}; - -#ifdef _M_IX86 -template -struct Predicates -{ - template - static bool Ignore() - { - return true; - } -}; - -template -struct Predicates -{ - template - static bool Ignore() - { - return true; - } -}; -#endif // _M_IX86 - -// The standard test. Hook |func|, and then try executing it with all zero -// arguments, using |pred| and |comp| to determine whether the call successfully -// executed. In general, you want set pred and comp such that they return true -// when the function is returning whatever value is expected with all-zero -// arguments. -// -// Note: When |func| returns void, you must supply |Ignore| and |nullptr| as the -// |pred| and |comp| arguments, respectively. -#define TEST_HOOK(dll, func, pred, comp) \ - TestHook(#dll, #func, &Predicates::pred) - -// We need to special-case functions that return INVALID_HANDLE_VALUE -// (ie, CreateFile). Our template machinery for comparing values doesn't work -// with integer constants passed as pointers (well, it works on MSVC, but not -// clang, because that is not standard-compliant). -#define TEST_HOOK_FOR_INVALID_HANDLE_VALUE(dll, func) \ - TestHook::Type>(#dll, #func, &Predicates::Type>::Equals) - -// This variant allows you to explicitly supply arguments to the hooked function -// during testing. You want to provide arguments that produce the conditions that -// induce the function to return a value that is accepted by your predicate. -#define TEST_HOOK_PARAMS(dll, func, pred, comp, ...) \ - TestHook(#dll, #func, &Predicates::pred, __VA_ARGS__) - -// This is for cases when we want to hook |func|, but it is unsafe to attempt -// to execute the function in the context of a test. -#define TEST_HOOK_SKIP_EXEC(dll, func) \ - TestHook(#dll, #func, reinterpret_cast::Type)>(NULL)) - -// The following three variants are identical to the previous macros, -// however the forcibly use a Detour on 32-bit Windows. On 64-bit Windows, -// these macros are identical to their TEST_HOOK variants. -#define TEST_DETOUR(dll, func, pred, comp) \ - TestDetour(#dll, #func, &Predicates::pred) - -#define TEST_DETOUR_PARAMS(dll, func, pred, comp, ...) \ - TestDetour(#dll, #func, &Predicates::pred, __VA_ARGS__) - -#define TEST_DETOUR_SKIP_EXEC(dll, func) \ - TestDetour(#dll, #func, reinterpret_cast::Type)>(NULL)) - -template -bool MaybeTestHook(const bool cond, const char (&dll)[N], const char *func, PredicateT&& aPred, Args... aArgs) +template +bool MaybeTestHook(const bool cond, HookTestFunc funcTester, const char (&dll)[N], const char* func) { if (!cond) { printf("TEST-SKIPPED | WindowsDllInterceptor | Skipped hook test for %s from %s\n", func, dll); return true; } - return TestHook(dll, func, std::forward(aPred), std::forward(aArgs)...); + return TestHook(funcTester, dll, func); } -// Like TEST_HOOK, but the test is only executed when cond is true. -#define MAYBE_TEST_HOOK(cond, dll, func, pred, comp) \ - MaybeTestHook(cond, #dll, #func, &Predicates::pred) - -#define MAYBE_TEST_HOOK_PARAMS(cond, dll, func, pred, comp, ...) \ - MaybeTestHook(cond, #dll, #func, &Predicates::pred, __VA_ARGS__) - -#define MAYBE_TEST_HOOK_SKIP_EXEC(cond, dll, func) \ - MaybeTestHook(cond, #dll, #func, reinterpret_cast::Type)>(NULL)) - bool ShouldTestTipTsf() { if (!IsWin8OrLater()) { @@ -399,6 +147,455 @@ bool ShouldTestTipTsf() return true; } +// These test the patched function returned by the DLL +// interceptor. They check that the patched assembler preamble does +// something sane. The parameter is a pointer to the patched function. +bool TestGetWindowInfo(void* aFunc) +{ + auto patchedGetWindowInfo = + reinterpret_cast(aFunc); + return patchedGetWindowInfo(0, 0) == FALSE; +} + +bool TestSetWindowLongPtr(void* aFunc) +{ + auto patchedSetWindowLongPtr = + reinterpret_cast(aFunc); + return patchedSetWindowLongPtr(0, 0, 0) == 0; +} + +bool TestSetWindowLong(void* aFunc) +{ + auto patchedSetWindowLong = + reinterpret_cast(aFunc); + return patchedSetWindowLong(0, 0, 0) == 0; +} + +bool TestTrackPopupMenu(void* aFunc) +{ + auto patchedTrackPopupMenu = + reinterpret_cast(aFunc); + return patchedTrackPopupMenu(0, 0, 0, 0, 0, 0, 0) == 0; +} + +bool TestNtFlushBuffersFile(void* aFunc) +{ + typedef NTSTATUS(WINAPI *NtFlushBuffersFileType)(HANDLE, PIO_STATUS_BLOCK); + auto patchedNtFlushBuffersFile = + reinterpret_cast(aFunc); + patchedNtFlushBuffersFile(0, 0); + return true; +} + +bool TestNtCreateFile(void* aFunc) +{ + auto patchedNtCreateFile = + reinterpret_cast(aFunc); + return patchedNtCreateFile(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; +} + +bool TestNtReadFile(void* aFunc) +{ + typedef NTSTATUS(WINAPI *NtReadFileType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PVOID, ULONG, + PLARGE_INTEGER, PULONG); + auto patchedNtReadFile = + reinterpret_cast(aFunc); + return patchedNtReadFile(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; +} + +bool TestNtReadFileScatter(void* aFunc) +{ + typedef NTSTATUS(WINAPI *NtReadFileScatterType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, + PLARGE_INTEGER, PULONG); + auto patchedNtReadFileScatter = + reinterpret_cast(aFunc); + return patchedNtReadFileScatter(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; +} + +bool TestNtWriteFile(void* aFunc) +{ + typedef NTSTATUS(WINAPI *NtWriteFileType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PVOID, ULONG, + PLARGE_INTEGER, PULONG); + auto patchedNtWriteFile = + reinterpret_cast(aFunc); + return patchedNtWriteFile(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; +} + +bool TestNtWriteFileGather(void* aFunc) +{ + typedef NTSTATUS(WINAPI *NtWriteFileGatherType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, + PLARGE_INTEGER, PULONG); + auto patchedNtWriteFileGather = + reinterpret_cast(aFunc); + return patchedNtWriteFileGather(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; +} + +bool TestNtQueryFullAttributesFile(void* aFunc) +{ + typedef NTSTATUS(WINAPI *NtQueryFullAttributesFileType)(POBJECT_ATTRIBUTES, + PVOID); + auto patchedNtQueryFullAttributesFile = + reinterpret_cast(aFunc); + return patchedNtQueryFullAttributesFile(0, 0) != 0; +} + +bool TestLdrUnloadDll(void* aFunc) +{ + typedef NTSTATUS (NTAPI *LdrUnloadDllType)(HMODULE); + auto patchedLdrUnloadDll = reinterpret_cast(aFunc); + return patchedLdrUnloadDll(0) != 0; +} + +bool TestLdrResolveDelayLoadedAPI(void* aFunc) +{ + // These pointers are disguised as PVOID to avoid pulling in obscure headers + typedef PVOID (WINAPI *LdrResolveDelayLoadedAPIType)(PVOID, PVOID, PVOID, + PVOID, PVOID, ULONG); + auto patchedLdrResolveDelayLoadedAPI = + reinterpret_cast(aFunc); + // No idea how to call this API. Flags==99 is just an arbitrary number that + // doesn't crash when the other params are null. + return patchedLdrResolveDelayLoadedAPI(0, 0, 0, 0, 0, 99) == 0; +} + +#ifdef _M_AMD64 +bool TestRtlInstallFunctionTableCallback(void* aFunc) +{ + auto patchedRtlInstallFunctionTableCallback = + reinterpret_cast(aFunc); + + return patchedRtlInstallFunctionTableCallback(0, 0, 0, 0, 0, 0) == FALSE; +} +#endif + +bool TestSetUnhandledExceptionFilter(void* aFunc) +{ + auto patchedSetUnhandledExceptionFilter = + reinterpret_cast(aFunc); + // Retrieve the current filter as we set the new filter to null, then restore the current filter. + LPTOP_LEVEL_EXCEPTION_FILTER current = patchedSetUnhandledExceptionFilter(0); + patchedSetUnhandledExceptionFilter(current); + return true; +} + +bool TestVirtualAlloc(void* aFunc) +{ + auto patchedVirtualAlloc = + reinterpret_cast(aFunc); + return patchedVirtualAlloc(0, 0, 0, 0) == 0; +} + +bool TestMapViewOfFile(void* aFunc) +{ + auto patchedMapViewOfFile = + reinterpret_cast(aFunc); + return patchedMapViewOfFile(0, 0, 0, 0, 0) == 0; +} + +bool TestCreateDIBSection(void* aFunc) +{ + auto patchedCreateDIBSection = + reinterpret_cast(aFunc); + // MSDN is wrong here. This does not return ERROR_INVALID_PARAMETER. It + // sets the value of GetLastError to ERROR_INVALID_PARAMETER. + // CreateDIBSection returns 0 on error. + return patchedCreateDIBSection(0, 0, 0, 0, 0, 0) == 0; +} + +bool TestCreateFileW(void* aFunc) +{ + auto patchedCreateFileW = + reinterpret_cast(aFunc); + return patchedCreateFileW(0, 0, 0, 0, 0, 0, 0) == INVALID_HANDLE_VALUE; +} + +bool TestCreateFileA(void* aFunc) +{ + auto patchedCreateFileA = + reinterpret_cast(aFunc); +// return patchedCreateFileA(0, 0, 0, 0, 0, 0, 0) == INVALID_HANDLE_VALUE; + printf("TEST-SKIPPED | WindowsDllInterceptor | " + "Will not attempt to execute patched CreateFileA -- patched method is known to fail.\n"); + return true; +} + +bool TestQueryDosDeviceW(void* aFunc) +{ + auto patchedQueryDosDeviceW = + reinterpret_cast(aFunc); + return patchedQueryDosDeviceW(nullptr, nullptr, 0) == 0; +} + +bool TestInSendMessageEx(void* aFunc) +{ + auto patchedInSendMessageEx = + reinterpret_cast(aFunc); + patchedInSendMessageEx(0); + return true; +} + +bool TestImmGetContext(void* aFunc) +{ + auto patchedImmGetContext = + reinterpret_cast(aFunc); + patchedImmGetContext(0); + return true; +} + +bool TestImmGetCompositionStringW(void* aFunc) +{ + auto patchedImmGetCompositionStringW = + reinterpret_cast(aFunc); + patchedImmGetCompositionStringW(0, 0, 0, 0); + return true; +} + +bool TestImmSetCandidateWindow(void* aFunc) +{ + auto patchedImmSetCandidateWindow = + reinterpret_cast(aFunc); +// return patchedImmSetCandidateWindow(0, 0) == 0; + // ImmSetCandidateWindow crashes if given bad parameters. + printf("TEST-SKIPPED | WindowsDllInterceptor | " + "Will not attempt to execute patched ImmSetCandidateWindow.\n"); + return true; +} + +bool TestImmNotifyIME(void* aFunc) +{ + auto patchedImmNotifyIME = + reinterpret_cast(aFunc); + return patchedImmNotifyIME(0, 0, 0, 0) == 0; +} + +bool TestGetSaveFileNameW(void* aFunc) +{ + auto patchedGetSaveFileNameWType = + reinterpret_cast(aFunc); + patchedGetSaveFileNameWType(0); + return true; +} + +bool TestGetOpenFileNameW(void* aFunc) +{ + auto patchedGetOpenFileNameWType = + reinterpret_cast(aFunc); + patchedGetOpenFileNameWType(0); + return true; +} + +bool TestGetKeyState(void* aFunc) +{ + auto patchedGetKeyState = + reinterpret_cast(aFunc); + patchedGetKeyState(0); + return true; +} + +bool TestSendMessageTimeoutW(void* aFunc) +{ + auto patchedSendMessageTimeoutW = + reinterpret_cast(aFunc); + return patchedSendMessageTimeoutW(0, 0, 0, 0, 0, 0, 0) == 0; +} + +bool TestProcessCaretEvents(void* aFunc) +{ + auto patchedProcessCaretEvents = + reinterpret_cast(aFunc); + patchedProcessCaretEvents(0, 0, 0, 0, 0, 0, 0); + return true; +} + +bool TestSetCursorPos(void* aFunc) +{ + // SetCursorPos has some issues in automation -- see bug 1368033. + // For that reason, we don't check the return value -- we only + // check that the method runs without producing an exception. + auto patchedSetCursorPos = + reinterpret_cast(aFunc); + patchedSetCursorPos(512, 512); + return true; +} + +static DWORD sTlsIndex = 0; + +bool TestTlsAlloc(void* aFunc) +{ + auto patchedTlsAlloc = + reinterpret_cast(aFunc); + sTlsIndex = patchedTlsAlloc(); + return sTlsIndex != TLS_OUT_OF_INDEXES; +} + +bool TestTlsFree(void* aFunc) +{ + auto patchedTlsFree = + reinterpret_cast(aFunc); + return sTlsIndex != 0 && patchedTlsFree(sTlsIndex); +} + +bool TestCloseHandle(void* aFunc) +{ + auto patchedCloseHandle = + reinterpret_cast(aFunc); + return patchedCloseHandle(0) == FALSE; +} + +bool TestDuplicateHandle(void* aFunc) +{ + auto patchedDuplicateHandle = + reinterpret_cast(aFunc); + return patchedDuplicateHandle(0, 0, 0, 0, 0, 0, 0) == FALSE; +} + +bool TestPrintDlgW(void* aFunc) +{ + auto patchedPrintDlgW = + reinterpret_cast(aFunc); + patchedPrintDlgW(0); + return true; +} + +bool TestInternetConnectA(void* aFunc) +{ + auto patchedInternetConnectA = + reinterpret_cast(aFunc); + return patchedInternetConnectA(0, 0, 0, 0, 0, 0, 0, 0) == 0; +} + +HINTERNET sInternet = 0; + +bool TestInternetOpenA(void* aFunc) +{ + auto patchedInternetOpenA = + reinterpret_cast(aFunc); + sInternet = patchedInternetOpenA(0, 0, 0, 0, 0); + return sInternet != 0; +} + +bool TestInternetCloseHandle(void* aFunc) +{ + auto patchedInternetCloseHandle = + reinterpret_cast(aFunc); + return patchedInternetCloseHandle(sInternet); +} + +bool TestInternetQueryDataAvailable(void* aFunc) +{ + auto patchedInternetQueryDataAvailable = + reinterpret_cast(aFunc); + return patchedInternetQueryDataAvailable(0, 0, 0, 0) == FALSE; +} + +bool TestInternetReadFile(void* aFunc) +{ + auto patchedInternetReadFile = + reinterpret_cast(aFunc); + return patchedInternetReadFile(0, 0, 0, 0) == FALSE; +} + +bool TestInternetWriteFile(void* aFunc) +{ + auto patchedInternetWriteFile = + reinterpret_cast(aFunc); + return patchedInternetWriteFile(0, 0, 0, 0) == FALSE; +} + +bool TestInternetSetOptionA(void* aFunc) +{ + auto patchedInternetSetOptionA = + reinterpret_cast(aFunc); + return patchedInternetSetOptionA(0, 0, 0, 0) == FALSE; +} + +bool TestHttpAddRequestHeadersA(void* aFunc) +{ + auto patchedHttpAddRequestHeadersA = + reinterpret_cast(aFunc); + return patchedHttpAddRequestHeadersA(0, 0, 0, 0) == FALSE; +} + +bool TestHttpOpenRequestA(void* aFunc) +{ + auto patchedHttpOpenRequestA = + reinterpret_cast(aFunc); + return patchedHttpOpenRequestA(0, 0, 0, 0, 0, 0, 0, 0) == 0; +} + +bool TestHttpQueryInfoA(void* aFunc) +{ + auto patchedHttpQueryInfoA = + reinterpret_cast(aFunc); + return patchedHttpQueryInfoA(0, 0, 0, 0, 0) == FALSE; +} + +bool TestHttpSendRequestA(void* aFunc) +{ + auto patchedHttpSendRequestA = + reinterpret_cast(aFunc); + return patchedHttpSendRequestA(0, 0, 0, 0, 0) == FALSE; +} + +bool TestHttpSendRequestExA(void* aFunc) +{ + auto patchedHttpSendRequestExA = + reinterpret_cast(aFunc); + return patchedHttpSendRequestExA(0, 0, 0, 0, 0) == FALSE; +} + +bool TestHttpEndRequestA(void* aFunc) +{ + auto patchedHttpEndRequestA = + reinterpret_cast(aFunc); + return patchedHttpEndRequestA(0, 0, 0, 0) == FALSE; +} + +bool TestInternetQueryOptionA(void* aFunc) +{ + auto patchedInternetQueryOptionA = + reinterpret_cast(aFunc); + return patchedInternetQueryOptionA(0, 0, 0, 0) == FALSE; +} + +bool TestInternetErrorDlg(void* aFunc) +{ + auto patchedInternetErrorDlg = + reinterpret_cast(aFunc); + return patchedInternetErrorDlg(0, 0, 0, 0, 0) == ERROR_INVALID_HANDLE; +} + +CredHandle sCredHandle; + +bool TestAcquireCredentialsHandleA(void* aFunc) +{ + auto patchedAcquireCredentialsHandleA = + reinterpret_cast(aFunc); + SCHANNEL_CRED cred; + memset(&cred, 0, sizeof(cred)); + cred.dwVersion = SCHANNEL_CRED_VERSION; + return patchedAcquireCredentialsHandleA(0, UNISP_NAME, SECPKG_CRED_OUTBOUND, + 0, &cred, 0, 0, &sCredHandle, 0) == S_OK; +} + +bool TestQueryCredentialsAttributesA(void* aFunc) +{ + auto patchedQueryCredentialsAttributesA = + reinterpret_cast(aFunc); + return patchedQueryCredentialsAttributesA(&sCredHandle, 0, 0) == SEC_E_UNSUPPORTED_FUNCTION; +} + +bool TestFreeCredentialsHandle(void* aFunc) +{ + auto patchedFreeCredentialsHandle = + reinterpret_cast(aFunc); + return patchedFreeCredentialsHandle(&sCredHandle) == S_OK; +} + int main() { LARGE_INTEGER start; @@ -418,7 +615,7 @@ int main() { WindowsDllInterceptor ExeIntercept; ExeIntercept.Init("TestDllInterceptor.exe"); - if (orig_rotatePayload.Set(ExeIntercept, "rotatePayload", &patched_rotatePayload)) { + if (ExeIntercept.AddHook("rotatePayload", reinterpret_cast(patched_rotatePayload), (void**) &orig_rotatePayload)) { printf("TEST-PASS | WindowsDllInterceptor | Hook added\n"); } else { printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to add hook\n"); @@ -462,85 +659,85 @@ int main() } #endif - if (TEST_HOOK(user32.dll, GetWindowInfo, Equals, FALSE) && + if (TestHook(TestGetWindowInfo, "user32.dll", "GetWindowInfo") && #ifdef _WIN64 - TEST_HOOK(user32.dll, SetWindowLongPtrA, Equals, 0) && - TEST_HOOK(user32.dll, SetWindowLongPtrW, Equals, 0) && + TestHook(TestSetWindowLongPtr, "user32.dll", "SetWindowLongPtrA") && + TestHook(TestSetWindowLongPtr, "user32.dll", "SetWindowLongPtrW") && #else - TEST_HOOK(user32.dll, SetWindowLongA, Equals, 0) && - TEST_HOOK(user32.dll, SetWindowLongW, Equals, 0) && + TestHook(TestSetWindowLong, "user32.dll", "SetWindowLongA") && + TestHook(TestSetWindowLong, "user32.dll", "SetWindowLongW") && #endif - TEST_HOOK(user32.dll, TrackPopupMenu, Equals, FALSE) && + TestHook(TestTrackPopupMenu, "user32.dll", "TrackPopupMenu") && #ifdef _M_IX86 // We keep this test to hook complex code on x86. (Bug 850957) - TEST_HOOK(ntdll.dll, NtFlushBuffersFile, NotEquals, 0) && + TestHook(TestNtFlushBuffersFile, "ntdll.dll", "NtFlushBuffersFile") && #endif - TEST_HOOK(ntdll.dll, NtCreateFile, NotEquals, 0) && - TEST_HOOK(ntdll.dll, NtReadFile, NotEquals, 0) && - TEST_HOOK(ntdll.dll, NtReadFileScatter, NotEquals, 0) && - TEST_HOOK(ntdll.dll, NtWriteFile, NotEquals, 0) && - TEST_HOOK(ntdll.dll, NtWriteFileGather, NotEquals, 0) && - TEST_HOOK(ntdll.dll, NtQueryFullAttributesFile, NotEquals, 0) && + TestHook(TestNtCreateFile, "ntdll.dll", "NtCreateFile") && + TestHook(TestNtReadFile, "ntdll.dll", "NtReadFile") && + TestHook(TestNtReadFileScatter, "ntdll.dll", "NtReadFileScatter") && + TestHook(TestNtWriteFile, "ntdll.dll", "NtWriteFile") && + TestHook(TestNtWriteFileGather, "ntdll.dll", "NtWriteFileGather") && + TestHook(TestNtQueryFullAttributesFile, "ntdll.dll", "NtQueryFullAttributesFile") && #ifndef MOZ_ASAN // Bug 733892: toolkit/crashreporter/nsExceptionHandler.cpp // This fails on ASan because the ASan runtime already hooked this function - TEST_HOOK(kernel32.dll, SetUnhandledExceptionFilter, Ignore, nullptr) && + TestHook(TestSetUnhandledExceptionFilter, "kernel32.dll", "SetUnhandledExceptionFilter") && #endif #ifdef _M_IX86 // Bug 670967: xpcom/base/AvailableMemoryTracker.cpp - TEST_HOOK(kernel32.dll, VirtualAlloc, Equals, nullptr) && - TEST_HOOK(kernel32.dll, MapViewOfFile, Equals, nullptr) && - TEST_HOOK(gdi32.dll, CreateDIBSection, Equals, nullptr) && - TEST_HOOK_FOR_INVALID_HANDLE_VALUE(kernel32.dll, CreateFileW) && + TestHook(TestVirtualAlloc, "kernel32.dll", "VirtualAlloc") && + TestHook(TestMapViewOfFile, "kernel32.dll", "MapViewOfFile") && + TestHook(TestCreateDIBSection, "gdi32.dll", "CreateDIBSection") && + TestHook(TestCreateFileW, "kernel32.dll", "CreateFileW") && // see Bug 1316415 #endif - TEST_HOOK_FOR_INVALID_HANDLE_VALUE(kernel32.dll, CreateFileA) && - TEST_HOOK(kernelbase.dll, QueryDosDeviceW, Equals, 0) && - TEST_DETOUR(user32.dll, CreateWindowExW, Equals, nullptr) && - TEST_HOOK(user32.dll, InSendMessageEx, Equals, ISMEX_NOSEND) && - TEST_HOOK(imm32.dll, ImmGetContext, Equals, nullptr) && - TEST_HOOK(imm32.dll, ImmGetCompositionStringW, Ignore, 0) && - TEST_HOOK_SKIP_EXEC(imm32.dll, ImmSetCandidateWindow) && - TEST_HOOK(imm32.dll, ImmNotifyIME, Equals, 0) && - TEST_HOOK(comdlg32.dll, GetSaveFileNameW, Ignore, FALSE) && - TEST_HOOK(comdlg32.dll, GetOpenFileNameW, Ignore, FALSE) && + TestHook(TestCreateFileA, "kernel32.dll", "CreateFileA") && + TestHook(TestQueryDosDeviceW, "kernelbase.dll", "QueryDosDeviceW") && + TestDetour("user32.dll", "CreateWindowExW") && + TestHook(TestInSendMessageEx, "user32.dll", "InSendMessageEx") && + TestHook(TestImmGetContext, "imm32.dll", "ImmGetContext") && + TestHook(TestImmGetCompositionStringW, "imm32.dll", "ImmGetCompositionStringW") && + TestHook(TestImmSetCandidateWindow, "imm32.dll", "ImmSetCandidateWindow") && + TestHook(TestImmNotifyIME, "imm32.dll", "ImmNotifyIME") && + TestHook(TestGetSaveFileNameW, "comdlg32.dll", "GetSaveFileNameW") && + TestHook(TestGetOpenFileNameW, "comdlg32.dll", "GetOpenFileNameW") && #ifdef _M_X64 - TEST_HOOK(user32.dll, GetKeyState, Ignore, 0) && // see Bug 1316415 - TEST_HOOK(ntdll.dll, LdrUnloadDll, NotEquals, 0) && - MAYBE_TEST_HOOK_SKIP_EXEC(IsWin8OrLater(), ntdll.dll, LdrResolveDelayLoadedAPI) && - MAYBE_TEST_HOOK(!IsWin8OrLater(), kernel32.dll, RtlInstallFunctionTableCallback, Equals, FALSE) && - TEST_HOOK(comdlg32.dll, PrintDlgW, Ignore, 0) && + TestHook(TestGetKeyState, "user32.dll", "GetKeyState") && // see Bug 1316415 + TestHook(TestLdrUnloadDll, "ntdll.dll", "LdrUnloadDll") && + MaybeTestHook(IsWin8OrLater(), TestLdrResolveDelayLoadedAPI, "ntdll.dll", "LdrResolveDelayLoadedAPI") && + MaybeTestHook(!IsWin8OrLater(), TestRtlInstallFunctionTableCallback, "kernel32.dll", "RtlInstallFunctionTableCallback") && + TestHook(TestPrintDlgW, "comdlg32.dll", "PrintDlgW") && #endif - MAYBE_TEST_HOOK(ShouldTestTipTsf(), tiptsf.dll, ProcessCaretEvents, Ignore, nullptr) && + MaybeTestHook(ShouldTestTipTsf(), TestProcessCaretEvents, "tiptsf.dll", "ProcessCaretEvents") && #ifdef _M_IX86 - TEST_HOOK(user32.dll, SendMessageTimeoutW, Equals, 0) && + TestHook(TestSendMessageTimeoutW, "user32.dll", "SendMessageTimeoutW") && #endif - TEST_HOOK(user32.dll, SetCursorPos, NotEquals, FALSE) && - TEST_HOOK(kernel32.dll, TlsAlloc, NotEquals, TLS_OUT_OF_INDEXES) && - TEST_HOOK_PARAMS(kernel32.dll, TlsFree, Equals, FALSE, TLS_OUT_OF_INDEXES) && - TEST_HOOK(kernel32.dll, CloseHandle, Equals, FALSE) && - TEST_HOOK(kernel32.dll, DuplicateHandle, Equals, FALSE) && + TestHook(TestSetCursorPos, "user32.dll", "SetCursorPos") && + TestHook(TestTlsAlloc, "kernel32.dll", "TlsAlloc") && + TestHook(TestTlsFree, "kernel32.dll", "TlsFree") && + TestHook(TestCloseHandle, "kernel32.dll", "CloseHandle") && + TestHook(TestDuplicateHandle, "kernel32.dll", "DuplicateHandle") && - TEST_HOOK(wininet.dll, InternetOpenA, NotEquals, nullptr) && - TEST_HOOK(wininet.dll, InternetCloseHandle, Equals, FALSE) && - TEST_HOOK(wininet.dll, InternetConnectA, Equals, nullptr) && - TEST_HOOK(wininet.dll, InternetQueryDataAvailable, Equals, FALSE) && - TEST_HOOK(wininet.dll, InternetReadFile, Equals, FALSE) && - TEST_HOOK(wininet.dll, InternetWriteFile, Equals, FALSE) && - TEST_HOOK(wininet.dll, InternetSetOptionA, Equals, FALSE) && - TEST_HOOK(wininet.dll, HttpAddRequestHeadersA, Equals, FALSE) && - TEST_HOOK(wininet.dll, HttpOpenRequestA, Equals, nullptr) && - TEST_HOOK(wininet.dll, HttpQueryInfoA, Equals, FALSE) && - TEST_HOOK(wininet.dll, HttpSendRequestA, Equals, FALSE) && - TEST_HOOK(wininet.dll, HttpSendRequestExA, Equals, FALSE) && - TEST_HOOK(wininet.dll, HttpEndRequestA, Equals, FALSE) && - TEST_HOOK(wininet.dll, InternetQueryOptionA, Equals, FALSE) && + TestHook(TestInternetOpenA, "wininet.dll", "InternetOpenA") && + TestHook(TestInternetCloseHandle, "wininet.dll", "InternetCloseHandle") && + TestHook(TestInternetConnectA, "wininet.dll", "InternetConnectA") && + TestHook(TestInternetQueryDataAvailable, "wininet.dll", "InternetQueryDataAvailable") && + TestHook(TestInternetReadFile, "wininet.dll", "InternetReadFile") && + TestHook(TestInternetWriteFile, "wininet.dll", "InternetWriteFile") && + TestHook(TestInternetSetOptionA, "wininet.dll", "InternetSetOptionA") && + TestHook(TestHttpAddRequestHeadersA, "wininet.dll", "HttpAddRequestHeadersA") && + TestHook(TestHttpOpenRequestA, "wininet.dll", "HttpOpenRequestA") && + TestHook(TestHttpQueryInfoA, "wininet.dll", "HttpQueryInfoA") && + TestHook(TestHttpSendRequestA, "wininet.dll", "HttpSendRequestA") && + TestHook(TestHttpSendRequestExA, "wininet.dll", "HttpSendRequestExA") && + TestHook(TestHttpEndRequestA, "wininet.dll", "HttpEndRequestA") && + TestHook(TestInternetQueryOptionA, "wininet.dll", "InternetQueryOptionA") && - TEST_HOOK(sspicli.dll, AcquireCredentialsHandleA, NotEquals, SEC_E_OK) && - TEST_HOOK(sspicli.dll, QueryCredentialsAttributesA, NotEquals, SEC_E_OK) && - TEST_HOOK(sspicli.dll, FreeCredentialsHandle, NotEquals, SEC_E_OK) && + TestHook(TestAcquireCredentialsHandleA, "sspicli.dll", "AcquireCredentialsHandleA") && + TestHook(TestQueryCredentialsAttributesA, "sspicli.dll", "QueryCredentialsAttributesA") && + TestHook(TestFreeCredentialsHandle, "sspicli.dll", "FreeCredentialsHandle") && - TEST_DETOUR_SKIP_EXEC(kernel32.dll, BaseThreadInitThunk) && - TEST_DETOUR_SKIP_EXEC(ntdll.dll, LdrLoadDll)) { + TestDetour("kernel32.dll", "BaseThreadInitThunk") && + TestDetour("ntdll.dll", "LdrLoadDll")) { printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n"); LARGE_INTEGER end, freq; diff --git a/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp b/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp index c29d132ba9b0..95cf37821043 100644 --- a/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp +++ b/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp @@ -11,19 +11,19 @@ using std::wstring; +static void* gOrigReturnResult; + extern "C" __declspec(dllexport) int ReturnResult() { return 2; } -static mozilla::CrossProcessDllInterceptor::FuncHookType - gOrigReturnResult; - static int ReturnResultHook() { - if (gOrigReturnResult() != 2) { + auto origFn = reinterpret_cast(gOrigReturnResult); + if (origFn() != 2) { return 3; } @@ -73,7 +73,9 @@ int ParentMain() mozilla::CrossProcessDllInterceptor intcpt(childProcess.get()); intcpt.Init("TestDllInterceptorCrossProcess.exe"); - if (!gOrigReturnResult.Set(intcpt, "ReturnResult", &ReturnResultHook)) { + if (!intcpt.AddHook("ReturnResult", + reinterpret_cast(&ReturnResultHook), + &gOrigReturnResult)) { printf("TEST-UNEXPECTED-FAIL | DllInterceptorCrossProcess | Failed to add hook\n"); return 1; } diff --git a/security/sandbox/win/SandboxInitialization.cpp b/security/sandbox/win/SandboxInitialization.cpp index 8a4a5e858072..8e27b87dd2f4 100644 --- a/security/sandbox/win/SandboxInitialization.cpp +++ b/security/sandbox/win/SandboxInitialization.cpp @@ -15,7 +15,7 @@ namespace mozilla { namespace sandboxing { typedef BOOL(WINAPI* CloseHandle_func) (HANDLE hObject); -static WindowsDllInterceptor::FuncHookType stub_CloseHandle; +static CloseHandle_func stub_CloseHandle = nullptr; typedef BOOL(WINAPI* DuplicateHandle_func)(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, @@ -24,8 +24,7 @@ typedef BOOL(WINAPI* DuplicateHandle_func)(HANDLE hSourceProcessHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions); -static WindowsDllInterceptor::FuncHookType - stub_DuplicateHandle; +static DuplicateHandle_func stub_DuplicateHandle = nullptr; static BOOL WINAPI patched_CloseHandle(HANDLE hObject) @@ -63,14 +62,17 @@ EnableHandleCloseMonitoring() { Kernel32Intercept.Init("kernel32.dll"); bool hooked = - stub_CloseHandle.Set(Kernel32Intercept, "CloseHandle", &patched_CloseHandle); + Kernel32Intercept.AddHook("CloseHandle", + reinterpret_cast(patched_CloseHandle), + (void**)&stub_CloseHandle); if (!hooked) { return false; } hooked = - stub_DuplicateHandle.Set(Kernel32Intercept, "DuplicateHandle", - &patched_DuplicateHandle); + Kernel32Intercept.AddHook("DuplicateHandle", + reinterpret_cast(patched_DuplicateHandle), + (void**)&stub_DuplicateHandle); if (!hooked) { return false; } diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp index 319f78f27cc0..7f42278ef244 100644 --- a/toolkit/crashreporter/nsExceptionHandler.cpp +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -338,8 +338,7 @@ nsTArray >* gDelayedAnnotations; // reporter is loaded instead (in case it became unloaded somehow) typedef LPTOP_LEVEL_EXCEPTION_FILTER (WINAPI *SetUnhandledExceptionFilter_func) (LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); -static WindowsDllInterceptor::FuncHookType - stub_SetUnhandledExceptionFilter; +static SetUnhandledExceptionFilter_func stub_SetUnhandledExceptionFilter = 0; static LPTOP_LEVEL_EXCEPTION_FILTER previousUnhandledExceptionFilter = nullptr; static WindowsDllInterceptor gKernel32Intercept; static bool gBlockUnhandledExceptionFilter = true; @@ -1640,9 +1639,9 @@ nsresult SetExceptionHandler(nsIFile* aXREDirectory, // protect the crash reporter from being unloaded gBlockUnhandledExceptionFilter = true; gKernel32Intercept.Init("kernel32.dll"); - bool ok = stub_SetUnhandledExceptionFilter.Set(gKernel32Intercept, - "SetUnhandledExceptionFilter", - &patched_SetUnhandledExceptionFilter); + bool ok = gKernel32Intercept.AddHook("SetUnhandledExceptionFilter", + reinterpret_cast(patched_SetUnhandledExceptionFilter), + (void**) &stub_SetUnhandledExceptionFilter); #ifdef DEBUG if (!ok) diff --git a/tools/profiler/core/platform-win32.cpp b/tools/profiler/core/platform-win32.cpp index 04a56fbdf133..ee17d1a68b73 100644 --- a/tools/profiler/core/platform-win32.cpp +++ b/tools/profiler/core/platform-win32.cpp @@ -303,8 +303,7 @@ Registers::SyncPopulate() static WindowsDllInterceptor NtDllIntercept; typedef NTSTATUS (NTAPI *LdrUnloadDll_func)(HMODULE module); -static WindowsDllInterceptor::FuncHookType - stub_LdrUnloadDll; +static LdrUnloadDll_func stub_LdrUnloadDll; static NTSTATUS NTAPI patched_LdrUnloadDll(HMODULE module) @@ -319,8 +318,7 @@ patched_LdrUnloadDll(HMODULE module) typedef PVOID (WINAPI *LdrResolveDelayLoadedAPI_func)(PVOID ParentModuleBase, PVOID DelayloadDescriptor, PVOID FailureDllHook, PVOID FailureSystemHook, PVOID ThunkAddress, ULONG Flags); -static WindowsDllInterceptor::FuncHookType - stub_LdrResolveDelayLoadedAPI; +static LdrResolveDelayLoadedAPI_func stub_LdrResolveDelayLoadedAPI; static PVOID WINAPI patched_LdrResolveDelayLoadedAPI(PVOID ParentModuleBase, @@ -338,12 +336,20 @@ patched_LdrResolveDelayLoadedAPI(PVOID ParentModuleBase, void InitializeWin64ProfilerHooks() { + static bool initialized = false; + if (initialized) { + return; + } + initialized = true; + NtDllIntercept.Init("ntdll.dll"); - stub_LdrUnloadDll.Set(NtDllIntercept, "LdrUnloadDll", &patched_LdrUnloadDll); + NtDllIntercept.AddHook("LdrUnloadDll", + reinterpret_cast(patched_LdrUnloadDll), + (void**)&stub_LdrUnloadDll); if (IsWin8OrLater()) { // LdrResolveDelayLoadedAPI was introduced in Win8 - stub_LdrResolveDelayLoadedAPI.Set(NtDllIntercept, - "LdrResolveDelayLoadedAPI", - &patched_LdrResolveDelayLoadedAPI); + NtDllIntercept.AddHook("LdrResolveDelayLoadedAPI", + reinterpret_cast(patched_LdrResolveDelayLoadedAPI), + (void**)&stub_LdrResolveDelayLoadedAPI); } } #endif // defined(GP_PLAT_amd64_windows) diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index f15691569075..db0389563b1e 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -352,6 +352,9 @@ static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); // General purpose user32.dll hook object static WindowsDllInterceptor sUser32Intercept; +// AddHook success checks +static mozilla::Maybe sHookedGetWindowInfo; + // 2 pixel offset for eTransparencyBorderlessGlass which equals the size of // the default window border Windows paints. Glass will be extended inward // this distance to remove the border. @@ -458,17 +461,17 @@ private: if (!IsWin10OrLater() && GetModuleHandle(L"tiptsf.dll") && !sProcessCaretEventsStub) { sTipTsfInterceptor.Init("tiptsf.dll"); - DebugOnly ok = sProcessCaretEventsStub.Set(sTipTsfInterceptor, - "ProcessCaretEvents", - &ProcessCaretEventsHook); + DebugOnly ok = sTipTsfInterceptor.AddHook("ProcessCaretEvents", + reinterpret_cast(&ProcessCaretEventsHook), + (void**) &sProcessCaretEventsStub); MOZ_ASSERT(ok); } if (!sSendMessageTimeoutWStub) { sUser32Intercept.Init("user32.dll"); - DebugOnly hooked = sSendMessageTimeoutWStub.Set(sUser32Intercept, - "SendMessageTimeoutW", - &SendMessageTimeoutWHook); + DebugOnly hooked = sUser32Intercept.AddHook("SendMessageTimeoutW", + reinterpret_cast(&SendMessageTimeoutWHook), + (void**) &sSendMessageTimeoutWStub); MOZ_ASSERT(hooked); } } @@ -553,10 +556,8 @@ private: } static WindowsDllInterceptor sTipTsfInterceptor; - static WindowsDllInterceptor::FuncHookType - sProcessCaretEventsStub; - static WindowsDllInterceptor::FuncHookType - sSendMessageTimeoutWStub; + static WINEVENTPROC sProcessCaretEventsStub; + static decltype(&SendMessageTimeoutW) sSendMessageTimeoutWStub; static StaticAutoPtr sInstance; HHOOK mHook; @@ -565,10 +566,8 @@ private: }; WindowsDllInterceptor TIPMessageHandler::sTipTsfInterceptor; -WindowsDllInterceptor::FuncHookType - TIPMessageHandler::sProcessCaretEventsStub; -WindowsDllInterceptor::FuncHookType - TIPMessageHandler::sSendMessageTimeoutWStub; +WINEVENTPROC TIPMessageHandler::sProcessCaretEventsStub; +decltype(&SendMessageTimeoutW) TIPMessageHandler::sSendMessageTimeoutWStub; StaticAutoPtr TIPMessageHandler::sInstance; } // namespace mozilla @@ -2473,7 +2472,7 @@ nsWindow::ResetLayout() // margins are set. static const wchar_t kManageWindowInfoProperty[] = L"ManageWindowInfoProperty"; typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi); -static WindowsDllInterceptor::FuncHookType sGetWindowInfoPtrStub; +static GetWindowInfoPtr sGetWindowInfoPtrStub = nullptr; BOOL WINAPI GetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi) @@ -2501,15 +2500,18 @@ nsWindow::UpdateGetWindowInfoCaptionStatus(bool aActiveCaption) if (!mWnd) return; - sUser32Intercept.Init("user32.dll"); - sGetWindowInfoPtrStub.Set(sUser32Intercept, "GetWindowInfo", - &GetWindowInfoHook); - if (!sGetWindowInfoPtrStub) { - return; + if (sHookedGetWindowInfo.isNothing()) { + sUser32Intercept.Init("user32.dll"); + sHookedGetWindowInfo = + Some(sUser32Intercept.AddHook("GetWindowInfo", + reinterpret_cast(GetWindowInfoHook), + (void**) &sGetWindowInfoPtrStub)); + if (!sHookedGetWindowInfo.value()) { + return; + } } - // Update our internally tracked caption status - SetPropW(mWnd, kManageWindowInfoProperty, + SetPropW(mWnd, kManageWindowInfoProperty, reinterpret_cast(static_cast(aActiveCaption) + 1)); } diff --git a/xpcom/base/AvailableMemoryTracker.cpp b/xpcom/base/AvailableMemoryTracker.cpp index 02265da2c6f1..678566087eda 100644 --- a/xpcom/base/AvailableMemoryTracker.cpp +++ b/xpcom/base/AvailableMemoryTracker.cpp @@ -84,14 +84,16 @@ volatile PRIntervalTime sLastLowMemoryNotificationTime; // These are function pointers to the functions we wrap in Init(). -static WindowsDllInterceptor::FuncHookType - sVirtualAllocOrig; +void* (WINAPI* sVirtualAllocOrig)(LPVOID aAddress, SIZE_T aSize, + DWORD aAllocationType, DWORD aProtect); -static WindowsDllInterceptor::FuncHookType - sMapViewOfFileOrig; +void* (WINAPI* sMapViewOfFileOrig)(HANDLE aFileMappingObject, + DWORD aDesiredAccess, DWORD aFileOffsetHigh, + DWORD aFileOffsetLow, SIZE_T aNumBytesToMap); -static WindowsDllInterceptor::FuncHookType - sCreateDIBSectionOrig; +HBITMAP(WINAPI* sCreateDIBSectionOrig)(HDC aDC, const BITMAPINFO* aBitmapInfo, + UINT aUsage, VOID** aBits, + HANDLE aSection, DWORD aOffset); /** * Fire a memory pressure event if we were not under memory pressure yet, or @@ -643,12 +645,17 @@ Init() // VirtualAllocHook from reentering itself. if (!PR_GetEnv("MOZ_PGO_INSTRUMENTED")) { sKernel32Intercept.Init("Kernel32.dll"); - sVirtualAllocOrig.Set(sKernel32Intercept, "VirtualAlloc", &VirtualAllocHook); - sMapViewOfFileOrig.Set(sKernel32Intercept, "MapViewOfFile", &MapViewOfFileHook); + sKernel32Intercept.AddHook("VirtualAlloc", + reinterpret_cast(VirtualAllocHook), + reinterpret_cast(&sVirtualAllocOrig)); + sKernel32Intercept.AddHook("MapViewOfFile", + reinterpret_cast(MapViewOfFileHook), + reinterpret_cast(&sMapViewOfFileOrig)); sGdi32Intercept.Init("Gdi32.dll"); - sCreateDIBSectionOrig.Set(sGdi32Intercept, "CreateDIBSection", - &CreateDIBSectionHook); + sGdi32Intercept.AddHook("CreateDIBSection", + reinterpret_cast(CreateDIBSectionHook), + reinterpret_cast(&sCreateDIBSectionOrig)); } sInitialized = true; diff --git a/xpcom/build/PoisonIOInterposerWin.cpp b/xpcom/build/PoisonIOInterposerWin.cpp index 5f2aaec25e28..6d8bc0a01233 100644 --- a/xpcom/build/PoisonIOInterposerWin.cpp +++ b/xpcom/build/PoisonIOInterposerWin.cpp @@ -209,20 +209,13 @@ WinIOAutoObservation::Filename(nsAString& aFilename) /*************************** IO Interposing Methods ***************************/ // Function pointers to original functions -static WindowsDllInterceptor::FuncHookType - gOriginalNtCreateFile; -static WindowsDllInterceptor::FuncHookType - gOriginalNtReadFile; -static WindowsDllInterceptor::FuncHookType - gOriginalNtReadFileScatter; -static WindowsDllInterceptor::FuncHookType - gOriginalNtWriteFile; -static WindowsDllInterceptor::FuncHookType - gOriginalNtWriteFileGather; -static WindowsDllInterceptor::FuncHookType - gOriginalNtFlushBuffersFile; -static WindowsDllInterceptor::FuncHookType - gOriginalNtQueryFullAttributesFile; +static NtCreateFileFn gOriginalNtCreateFile; +static NtReadFileFn gOriginalNtReadFile; +static NtReadFileScatterFn gOriginalNtReadFileScatter; +static NtWriteFileFn gOriginalNtWriteFile; +static NtWriteFileGatherFn gOriginalNtWriteFileGather; +static NtFlushBuffersFileFn gOriginalNtFlushBuffersFile; +static NtQueryFullAttributesFileFn gOriginalNtQueryFullAttributesFile; static NTSTATUS NTAPI InterposedNtCreateFile(PHANDLE aFileHandle, @@ -455,21 +448,34 @@ InitPoisonIOInterposer() // Initialize dll interceptor and add hooks sNtDllInterceptor.Init("ntdll.dll"); - gOriginalNtCreateFile.Set(sNtDllInterceptor, "NtCreateFile", - &InterposedNtCreateFile); - gOriginalNtReadFile.Set(sNtDllInterceptor, "NtReadFile", - &InterposedNtReadFile); - gOriginalNtReadFileScatter.Set(sNtDllInterceptor, "NtReadFileScatter", - &InterposedNtReadFileScatter); - gOriginalNtWriteFile.Set(sNtDllInterceptor, "NtWriteFile", - &InterposedNtWriteFile); - gOriginalNtWriteFileGather.Set(sNtDllInterceptor, "NtWriteFileGather", - &InterposedNtWriteFileGather); - gOriginalNtFlushBuffersFile.Set(sNtDllInterceptor, "NtFlushBuffersFile", - &InterposedNtFlushBuffersFile); - gOriginalNtQueryFullAttributesFile.Set(sNtDllInterceptor, - "NtQueryFullAttributesFile", - &InterposedNtQueryFullAttributesFile); + sNtDllInterceptor.AddHook( + "NtCreateFile", + reinterpret_cast(InterposedNtCreateFile), + reinterpret_cast(&gOriginalNtCreateFile)); + sNtDllInterceptor.AddHook( + "NtReadFile", + reinterpret_cast(InterposedNtReadFile), + reinterpret_cast(&gOriginalNtReadFile)); + sNtDllInterceptor.AddHook( + "NtReadFileScatter", + reinterpret_cast(InterposedNtReadFileScatter), + reinterpret_cast(&gOriginalNtReadFileScatter)); + sNtDllInterceptor.AddHook( + "NtWriteFile", + reinterpret_cast(InterposedNtWriteFile), + reinterpret_cast(&gOriginalNtWriteFile)); + sNtDllInterceptor.AddHook( + "NtWriteFileGather", + reinterpret_cast(InterposedNtWriteFileGather), + reinterpret_cast(&gOriginalNtWriteFileGather)); + sNtDllInterceptor.AddHook( + "NtFlushBuffersFile", + reinterpret_cast(InterposedNtFlushBuffersFile), + reinterpret_cast(&gOriginalNtFlushBuffersFile)); + sNtDllInterceptor.AddHook( + "NtQueryFullAttributesFile", + reinterpret_cast(InterposedNtQueryFullAttributesFile), + reinterpret_cast(&gOriginalNtQueryFullAttributesFile)); } void From 984eed33716dc0a5487d56c26257b7f72eed624b Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:48:05 -0600 Subject: [PATCH 27/57] Bug 1460022: Part 1 - Modify DLL interceptor to use one-time initialization when setting hooks; r=handyman This patch makes the interceptor's AddHook functions private, and converts the stubs from simple function pointers into objects containing both the stub function pointer, plus a INIT_ONCE sentinel. Setting a hook now requires calling Set or SetDetour on the stub, which ensures that the hook attempt happens once and only once. The constructor for the new object is constexpr, so it should not generate static initializers if it is declared statically. Note that, as a corollary of the new behaviour, we no longer need to set guards around any hook setting code. I have removed those when present. --- mozglue/misc/nsWindowsDllInterceptor.h | 153 ++++++++++++++++++++++++- 1 file changed, 151 insertions(+), 2 deletions(-) diff --git a/mozglue/misc/nsWindowsDllInterceptor.h b/mozglue/misc/nsWindowsDllInterceptor.h index 3020f795fede..4ae504257b56 100644 --- a/mozglue/misc/nsWindowsDllInterceptor.h +++ b/mozglue/misc/nsWindowsDllInterceptor.h @@ -8,10 +8,12 @@ #define NS_WINDOWS_DLL_INTERCEPTOR_H_ #include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" #include "mozilla/ArrayUtils.h" #include "mozilla/CheckedInt.h" #include "mozilla/DebugOnly.h" -#include "mozilla/NotNull.h" +#include "mozilla/Move.h" +#include "mozilla/Tuple.h" #include "mozilla/TypeTraits.h" #include "mozilla/Types.h" #include "mozilla/UniquePtr.h" @@ -82,6 +84,143 @@ namespace mozilla { namespace interceptor { +template +class FuncHook final +{ + template + struct OriginalFunctionPtrTraits; + + template + struct OriginalFunctionPtrTraits + { + using ReturnType = R; + }; + +#if defined(_M_IX86) + template + struct OriginalFunctionPtrTraits + { + using ReturnType = R; + }; + + template + struct OriginalFunctionPtrTraits + { + using ReturnType = R; + }; +#endif // defined(_M_IX86) + +public: + using ThisType = FuncHook; + using ReturnType = typename OriginalFunctionPtrTraits::ReturnType; + + constexpr FuncHook() + : mOrigFunc(nullptr) + , mInitOnce(INIT_ONCE_STATIC_INIT) + { + } + + ~FuncHook() = default; + + bool Set(InterceptorT& aInterceptor, const char* aName, + FuncPtrT aHookDest) + { + LPVOID addHookOk; + InitOnceContext ctx(this, &aInterceptor, aName, aHookDest, false); + + return ::InitOnceExecuteOnce(&mInitOnce, &InitOnceCallback, &ctx, + &addHookOk) && addHookOk; + } + + bool SetDetour(InterceptorT& aInterceptor, const char* aName, + FuncPtrT aHookDest) + { + LPVOID addHookOk; + InitOnceContext ctx(this, &aInterceptor, aName, aHookDest, true); + + return ::InitOnceExecuteOnce(&mInitOnce, &InitOnceCallback, &ctx, + &addHookOk) && addHookOk; + } + + explicit operator bool() const + { + return !!mOrigFunc; + } + + template + ReturnType operator()(ArgsType... aArgs) const + { + return mOrigFunc(std::forward(aArgs)...); + } + + FuncPtrT GetStub() const + { + return mOrigFunc; + } + + // One-time init stuff cannot be moved or copied + FuncHook(const FuncHook&) = delete; + FuncHook(FuncHook&&) = delete; + FuncHook& operator=(const FuncHook&) = delete; + FuncHook& operator=(FuncHook&& aOther) = delete; + +private: + struct MOZ_RAII InitOnceContext final + { + InitOnceContext(ThisType* aHook, InterceptorT* aInterceptor, + const char* aName, void* aHookDest, bool aForceDetour) + : mHook(aHook) + , mInterceptor(aInterceptor) + , mName(aName) + , mHookDest(aHookDest) + , mForceDetour(aForceDetour) + { + } + + ThisType* mHook; + InterceptorT* mInterceptor; + const char* mName; + void* mHookDest; + bool mForceDetour; + }; + +private: + bool Apply(InterceptorT* aInterceptor, const char* aName, void* aHookDest) + { + return aInterceptor->AddHook(aName, reinterpret_cast(aHookDest), + reinterpret_cast(&mOrigFunc)); + } + + bool ApplyDetour(InterceptorT* aInterceptor, const char* aName, + void* aHookDest) + { + return aInterceptor->AddDetour(aName, reinterpret_cast(aHookDest), + reinterpret_cast(&mOrigFunc)); + } + + static BOOL CALLBACK + InitOnceCallback(PINIT_ONCE aInitOnce, PVOID aParam, PVOID* aOutContext) + { + MOZ_ASSERT(aOutContext); + + bool result; + auto ctx = reinterpret_cast(aParam); + if (ctx->mForceDetour) { + result = ctx->mHook->ApplyDetour(ctx->mInterceptor, ctx->mName, + ctx->mHookDest); + } else { + result = ctx->mHook->Apply(ctx->mInterceptor, ctx->mName, ctx->mHookDest); + } + + *aOutContext = result ? reinterpret_cast(1U << INIT_ONCE_CTX_RESERVED_BITS) : nullptr; + return TRUE; + } + +private: + FuncPtrT mOrigFunc; + INIT_ONCE mInitOnce; +}; + enum { kDefaultTrampolineSize = 128 @@ -92,6 +231,8 @@ template > class WindowsDllInterceptor final { + typedef WindowsDllInterceptor ThisType; + interceptor::WindowsDllDetourPatcher mDetourPatcher; #if defined(_M_IX86) interceptor::WindowsDllNopSpacePatcher mNopSpacePatcher; @@ -160,6 +301,7 @@ public: // NB: We intentionally leak mModule } +private: /** * Hook/detour the method aName from the DLL we set in Init so that it calls * aHookDest instead. Returns the original method pointer in aOrigFunc @@ -219,7 +361,6 @@ public: return AddDetour(proc, aHookDest, aOrigFunc); } -private: bool AddDetour(FARPROC aProc, intptr_t aHookDest, void** aOrigFunc) { MOZ_ASSERT(mModule && aProc); @@ -230,6 +371,14 @@ private: return mDetourPatcher.AddHook(aProc, aHookDest, aOrigFunc); } + +public: + template + using FuncHookType = FuncHook; + +private: + template + friend class FuncHook; }; } // namespace interceptor From 1c39ff82df99f5626105f6e31cd7b0213d56779e Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:48:28 -0600 Subject: [PATCH 28/57] Bug 1460022: Part 2 - Update TestDllInterceptor to use new DLL interceptor interface; r=handyman In addition to updating the interface, this patch also significantly alters the structure of this test. In particular, it removes the Test* functions in favour of using template magic. I did this because I noticed that, in the majority of cases, the stub function was being called with all zero arguments, and then we check for the expected error code. I thought that maybe we could replace that repetition with some templates that instantiate a blank tuple that may then be applied to a callable object. See the (MAYBE_)TEST_HOOK* and TEST_DETOUR* macro definitions for detailed information about how to use these things. The test successfully completes with both 32-bit and 64-bit builds. --- .../tests/interceptor/TestDllInterceptor.cpp | 854 +++++++----------- 1 file changed, 327 insertions(+), 527 deletions(-) diff --git a/mozglue/tests/interceptor/TestDllInterceptor.cpp b/mozglue/tests/interceptor/TestDllInterceptor.cpp index 6007a8995201..729501f37147 100644 --- a/mozglue/tests/interceptor/TestDllInterceptor.cpp +++ b/mozglue/tests/interceptor/TestDllInterceptor.cpp @@ -10,10 +10,33 @@ #include #include +#include "mozilla/TypeTraits.h" +#include "mozilla/UniquePtr.h" #include "mozilla/WindowsVersion.h" #include "nsWindowsDllInterceptor.h" #include "nsWindowsHelpers.h" +NTSTATUS NTAPI NtFlushBuffersFile(HANDLE, PIO_STATUS_BLOCK); +NTSTATUS NTAPI NtReadFile(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PVOID, ULONG, + PLARGE_INTEGER, PULONG); +NTSTATUS NTAPI NtReadFileScatter(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, + PLARGE_INTEGER, PULONG); +NTSTATUS NTAPI NtWriteFile(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PVOID, ULONG, + PLARGE_INTEGER, PULONG); +NTSTATUS NTAPI NtWriteFileGather(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, + PLARGE_INTEGER, PULONG); +NTSTATUS NTAPI NtQueryFullAttributesFile(POBJECT_ATTRIBUTES, PVOID); +NTSTATUS NTAPI LdrLoadDll(PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle); +NTSTATUS NTAPI LdrUnloadDll(HMODULE); +// These pointers are disguised as PVOID to avoid pulling in obscure headers +PVOID NTAPI LdrResolveDelayLoadedAPI(PVOID, PVOID, PVOID, PVOID, PVOID, ULONG); +void CALLBACK ProcessCaretEvents(HWINEVENTHOOK, DWORD, HWND, LONG, LONG, DWORD, DWORD); +void __fastcall BaseThreadInitThunk(BOOL aIsInitialThread, void* aStartAddress, void* aThreadParam); + using namespace mozilla; struct payload { @@ -38,7 +61,8 @@ extern "C" __declspec(dllexport) __declspec(noinline) payload rotatePayload(payl static bool patched_func_called = false; -static payload (*orig_rotatePayload)(payload); +static WindowsDllInterceptor::FuncHookType + orig_rotatePayload; static payload patched_rotatePayload(payload p) @@ -47,11 +71,58 @@ patched_rotatePayload(payload p) return orig_rotatePayload(p); } -typedef bool(*HookTestFunc)(void*); -bool CheckHook(HookTestFunc aHookTestFunc, void* aOrigFunc, - const char* aDllName, const char* aFuncName) +// Invoke aFunc by taking aArg's contents and using them as aFunc's arguments +template , size_t... Indices> +decltype(auto) Apply(CallableT&& aFunc, ArgTuple&& aArgs, std::index_sequence) { - if (aHookTestFunc(aOrigFunc)) { + return std::forward(aFunc)(Get(std::forward(aArgs))...); +} + +template +bool TestFunction(CallableT aFunc); + +#define DEFINE_TEST_FUNCTION(calling_convention) \ + template \ + bool TestFunction(WindowsDllInterceptor::FuncHookType&& aFunc, \ + bool (* aPred)(R), TestArgs... aArgs) \ + { \ + using FuncHookType = WindowsDllInterceptor::FuncHookType; \ + using ArgTuple = Tuple; \ + using Indices = std::index_sequence_for; \ + ArgTuple fakeArgs{ std::forward(aArgs)... }; \ + return aPred(Apply(std::forward(aFunc), std::forward(fakeArgs), Indices())); \ + } \ + \ + /* Specialization for functions returning void */ \ + template \ + bool TestFunction(WindowsDllInterceptor::FuncHookType&& aFunc, \ + PredicateT&& aPred, TestArgs... aArgs) \ + { \ + using FuncHookType = WindowsDllInterceptor::FuncHookType; \ + using ArgTuple = Tuple; \ + using Indices = std::index_sequence_for; \ + ArgTuple fakeArgs{ std::forward(aArgs)... }; \ + Apply(std::forward(aFunc), std::forward(fakeArgs), Indices()); \ + return true; \ + } + +// C++11 allows empty arguments to macros. clang works just fine. MSVC does the +// right thing, but it also throws up warning C4003. We'll suppress that +// behavior here. +#pragma warning(suppress: 4003) +DEFINE_TEST_FUNCTION() +#ifdef _M_IX86 +DEFINE_TEST_FUNCTION(__stdcall) +DEFINE_TEST_FUNCTION(__fastcall) +#endif // _M_IX86 + +// Test the hooked function against the supplied predicate +template +bool CheckHook(WindowsDllInterceptor::FuncHookType &aOrigFunc, + const char* aDllName, const char* aFuncName, PredicateT&& aPred, + Args... aArgs) +{ + if (TestFunction(std::forward>(aOrigFunc), std::forward(aPred), std::forward(aArgs)...)) { printf("TEST-PASS | WindowsDllInterceptor | " "Executed hooked function %s from %s\n", aFuncName, aDllName); return true; @@ -61,57 +132,235 @@ bool CheckHook(HookTestFunc aHookTestFunc, void* aOrigFunc, return false; } -template -bool TestHook(HookTestFunc funcTester, const char (&dll)[N], const char *func) +// Hook the function and optionally attempt calling it +template +bool TestHook(const char (&dll)[N], const char *func, PredicateT&& aPred, Args... aArgs) { - void *orig_func; + auto orig_func(mozilla::MakeUnique>()); + bool successful = false; { WindowsDllInterceptor TestIntercept; TestIntercept.Init(dll); - successful = TestIntercept.AddHook(func, 0, &orig_func); + successful = orig_func->Set(TestIntercept, func, nullptr); } if (successful) { printf("TEST-PASS | WindowsDllInterceptor | Could hook %s from %s\n", func, dll); - return CheckHook(funcTester, orig_func, dll, func); + if (!aPred) { + printf("TEST-SKIPPED | WindowsDllInterceptor | " + "Will not attempt to execute patched %s.\n", func); + return true; + } + + return CheckHook(*orig_func, dll, func, std::forward(aPred), std::forward(aArgs)...); } else { printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to hook %s from %s\n", func, dll); return false; } } -template -bool TestDetour(const char (&dll)[N], const char *func) +// Detour the function and optionally attempt calling it +template +bool TestDetour(const char (&dll)[N], const char *func, PredicateT&& aPred) { - void *orig_func; + auto orig_func(mozilla::MakeUnique>()); + bool successful = false; { WindowsDllInterceptor TestIntercept; TestIntercept.Init(dll); - successful = TestIntercept.AddDetour(func, 0, &orig_func); + successful = orig_func->SetDetour(TestIntercept, func, nullptr); } if (successful) { printf("TEST-PASS | WindowsDllInterceptor | Could detour %s from %s\n", func, dll); - return true; + if (!aPred) { + printf("TEST-SKIPPED | WindowsDllInterceptor | " + "Will not attempt to execute patched %s.\n", func); + return true; + } + + return CheckHook(*orig_func, dll, func, std::forward(aPred)); } else { printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to detour %s from %s\n", func, dll); return false; } } -template -bool MaybeTestHook(const bool cond, HookTestFunc funcTester, const char (&dll)[N], const char* func) +// If a function pointer's type returns void*, this template converts that type +// to return uintptr_t instead, for the purposes of predicates. +template +struct SubstituteForVoidPtr +{ + using Type = FuncT; +}; + +template +struct SubstituteForVoidPtr +{ + using Type = uintptr_t (*)(Args...); +}; + +#ifdef _M_IX86 +template +struct SubstituteForVoidPtr +{ + using Type = uintptr_t (__stdcall*)(Args...); +}; + +template +struct SubstituteForVoidPtr +{ + using Type = uintptr_t (__fastcall*)(Args...); +}; +#endif // _M_IX86 + +// Determines the function's return type +template +struct ReturnType; + +template +struct ReturnType +{ + using Type = R; +}; + +#ifdef _M_IX86 +template +struct ReturnType +{ + using Type = R; +}; + +template +struct ReturnType +{ + using Type = R; +}; +#endif // _M_IX86 + +// Predicates that may be supplied during tests +template +struct Predicates +{ + using ArgType = typename ReturnType::Type; + + template + static bool Equals(ArgType aValue) + { + return CompVal == aValue; + } + + template + static bool NotEquals(ArgType aValue) + { + return CompVal != aValue; + } + + template + static bool Ignore(ArgType aValue) + { + return true; + } +}; + +// Functions that return void should be ignored, so we specialize the +// Ignore predicate for that case. Use nullptr as the value to compare against. +template +struct Predicates +{ + template + static bool Ignore() + { + return true; + } +}; + +#ifdef _M_IX86 +template +struct Predicates +{ + template + static bool Ignore() + { + return true; + } +}; + +template +struct Predicates +{ + template + static bool Ignore() + { + return true; + } +}; +#endif // _M_IX86 + +// The standard test. Hook |func|, and then try executing it with all zero +// arguments, using |pred| and |comp| to determine whether the call successfully +// executed. In general, you want set pred and comp such that they return true +// when the function is returning whatever value is expected with all-zero +// arguments. +// +// Note: When |func| returns void, you must supply |Ignore| and |nullptr| as the +// |pred| and |comp| arguments, respectively. +#define TEST_HOOK(dll, func, pred, comp) \ + TestHook(#dll, #func, &Predicates::pred) + +// We need to special-case functions that return INVALID_HANDLE_VALUE +// (ie, CreateFile). Our template machinery for comparing values doesn't work +// with integer constants passed as pointers (well, it works on MSVC, but not +// clang, because that is not standard-compliant). +#define TEST_HOOK_FOR_INVALID_HANDLE_VALUE(dll, func) \ + TestHook::Type>(#dll, #func, &Predicates::Type>::Equals) + +// This variant allows you to explicitly supply arguments to the hooked function +// during testing. You want to provide arguments that produce the conditions that +// induce the function to return a value that is accepted by your predicate. +#define TEST_HOOK_PARAMS(dll, func, pred, comp, ...) \ + TestHook(#dll, #func, &Predicates::pred, __VA_ARGS__) + +// This is for cases when we want to hook |func|, but it is unsafe to attempt +// to execute the function in the context of a test. +#define TEST_HOOK_SKIP_EXEC(dll, func) \ + TestHook(#dll, #func, reinterpret_cast::Type)>(NULL)) + +// The following three variants are identical to the previous macros, +// however the forcibly use a Detour on 32-bit Windows. On 64-bit Windows, +// these macros are identical to their TEST_HOOK variants. +#define TEST_DETOUR(dll, func, pred, comp) \ + TestDetour(#dll, #func, &Predicates::pred) + +#define TEST_DETOUR_PARAMS(dll, func, pred, comp, ...) \ + TestDetour(#dll, #func, &Predicates::pred, __VA_ARGS__) + +#define TEST_DETOUR_SKIP_EXEC(dll, func) \ + TestDetour(#dll, #func, reinterpret_cast::Type)>(NULL)) + +template +bool MaybeTestHook(const bool cond, const char (&dll)[N], const char *func, PredicateT&& aPred, Args... aArgs) { if (!cond) { printf("TEST-SKIPPED | WindowsDllInterceptor | Skipped hook test for %s from %s\n", func, dll); return true; } - return TestHook(funcTester, dll, func); + return TestHook(dll, func, std::forward(aPred), std::forward(aArgs)...); } +// Like TEST_HOOK, but the test is only executed when cond is true. +#define MAYBE_TEST_HOOK(cond, dll, func, pred, comp) \ + MaybeTestHook(cond, #dll, #func, &Predicates::pred) + +#define MAYBE_TEST_HOOK_PARAMS(cond, dll, func, pred, comp, ...) \ + MaybeTestHook(cond, #dll, #func, &Predicates::pred, __VA_ARGS__) + +#define MAYBE_TEST_HOOK_SKIP_EXEC(cond, dll, func) \ + MaybeTestHook(cond, #dll, #func, reinterpret_cast::Type)>(NULL)) + bool ShouldTestTipTsf() { if (!IsWin8OrLater()) { @@ -147,455 +396,6 @@ bool ShouldTestTipTsf() return true; } -// These test the patched function returned by the DLL -// interceptor. They check that the patched assembler preamble does -// something sane. The parameter is a pointer to the patched function. -bool TestGetWindowInfo(void* aFunc) -{ - auto patchedGetWindowInfo = - reinterpret_cast(aFunc); - return patchedGetWindowInfo(0, 0) == FALSE; -} - -bool TestSetWindowLongPtr(void* aFunc) -{ - auto patchedSetWindowLongPtr = - reinterpret_cast(aFunc); - return patchedSetWindowLongPtr(0, 0, 0) == 0; -} - -bool TestSetWindowLong(void* aFunc) -{ - auto patchedSetWindowLong = - reinterpret_cast(aFunc); - return patchedSetWindowLong(0, 0, 0) == 0; -} - -bool TestTrackPopupMenu(void* aFunc) -{ - auto patchedTrackPopupMenu = - reinterpret_cast(aFunc); - return patchedTrackPopupMenu(0, 0, 0, 0, 0, 0, 0) == 0; -} - -bool TestNtFlushBuffersFile(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtFlushBuffersFileType)(HANDLE, PIO_STATUS_BLOCK); - auto patchedNtFlushBuffersFile = - reinterpret_cast(aFunc); - patchedNtFlushBuffersFile(0, 0); - return true; -} - -bool TestNtCreateFile(void* aFunc) -{ - auto patchedNtCreateFile = - reinterpret_cast(aFunc); - return patchedNtCreateFile(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; -} - -bool TestNtReadFile(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtReadFileType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PVOID, ULONG, - PLARGE_INTEGER, PULONG); - auto patchedNtReadFile = - reinterpret_cast(aFunc); - return patchedNtReadFile(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; -} - -bool TestNtReadFileScatter(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtReadFileScatterType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, - PLARGE_INTEGER, PULONG); - auto patchedNtReadFileScatter = - reinterpret_cast(aFunc); - return patchedNtReadFileScatter(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; -} - -bool TestNtWriteFile(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtWriteFileType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PVOID, ULONG, - PLARGE_INTEGER, PULONG); - auto patchedNtWriteFile = - reinterpret_cast(aFunc); - return patchedNtWriteFile(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; -} - -bool TestNtWriteFileGather(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtWriteFileGatherType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, - PLARGE_INTEGER, PULONG); - auto patchedNtWriteFileGather = - reinterpret_cast(aFunc); - return patchedNtWriteFileGather(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; -} - -bool TestNtQueryFullAttributesFile(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtQueryFullAttributesFileType)(POBJECT_ATTRIBUTES, - PVOID); - auto patchedNtQueryFullAttributesFile = - reinterpret_cast(aFunc); - return patchedNtQueryFullAttributesFile(0, 0) != 0; -} - -bool TestLdrUnloadDll(void* aFunc) -{ - typedef NTSTATUS (NTAPI *LdrUnloadDllType)(HMODULE); - auto patchedLdrUnloadDll = reinterpret_cast(aFunc); - return patchedLdrUnloadDll(0) != 0; -} - -bool TestLdrResolveDelayLoadedAPI(void* aFunc) -{ - // These pointers are disguised as PVOID to avoid pulling in obscure headers - typedef PVOID (WINAPI *LdrResolveDelayLoadedAPIType)(PVOID, PVOID, PVOID, - PVOID, PVOID, ULONG); - auto patchedLdrResolveDelayLoadedAPI = - reinterpret_cast(aFunc); - // No idea how to call this API. Flags==99 is just an arbitrary number that - // doesn't crash when the other params are null. - return patchedLdrResolveDelayLoadedAPI(0, 0, 0, 0, 0, 99) == 0; -} - -#ifdef _M_AMD64 -bool TestRtlInstallFunctionTableCallback(void* aFunc) -{ - auto patchedRtlInstallFunctionTableCallback = - reinterpret_cast(aFunc); - - return patchedRtlInstallFunctionTableCallback(0, 0, 0, 0, 0, 0) == FALSE; -} -#endif - -bool TestSetUnhandledExceptionFilter(void* aFunc) -{ - auto patchedSetUnhandledExceptionFilter = - reinterpret_cast(aFunc); - // Retrieve the current filter as we set the new filter to null, then restore the current filter. - LPTOP_LEVEL_EXCEPTION_FILTER current = patchedSetUnhandledExceptionFilter(0); - patchedSetUnhandledExceptionFilter(current); - return true; -} - -bool TestVirtualAlloc(void* aFunc) -{ - auto patchedVirtualAlloc = - reinterpret_cast(aFunc); - return patchedVirtualAlloc(0, 0, 0, 0) == 0; -} - -bool TestMapViewOfFile(void* aFunc) -{ - auto patchedMapViewOfFile = - reinterpret_cast(aFunc); - return patchedMapViewOfFile(0, 0, 0, 0, 0) == 0; -} - -bool TestCreateDIBSection(void* aFunc) -{ - auto patchedCreateDIBSection = - reinterpret_cast(aFunc); - // MSDN is wrong here. This does not return ERROR_INVALID_PARAMETER. It - // sets the value of GetLastError to ERROR_INVALID_PARAMETER. - // CreateDIBSection returns 0 on error. - return patchedCreateDIBSection(0, 0, 0, 0, 0, 0) == 0; -} - -bool TestCreateFileW(void* aFunc) -{ - auto patchedCreateFileW = - reinterpret_cast(aFunc); - return patchedCreateFileW(0, 0, 0, 0, 0, 0, 0) == INVALID_HANDLE_VALUE; -} - -bool TestCreateFileA(void* aFunc) -{ - auto patchedCreateFileA = - reinterpret_cast(aFunc); -// return patchedCreateFileA(0, 0, 0, 0, 0, 0, 0) == INVALID_HANDLE_VALUE; - printf("TEST-SKIPPED | WindowsDllInterceptor | " - "Will not attempt to execute patched CreateFileA -- patched method is known to fail.\n"); - return true; -} - -bool TestQueryDosDeviceW(void* aFunc) -{ - auto patchedQueryDosDeviceW = - reinterpret_cast(aFunc); - return patchedQueryDosDeviceW(nullptr, nullptr, 0) == 0; -} - -bool TestInSendMessageEx(void* aFunc) -{ - auto patchedInSendMessageEx = - reinterpret_cast(aFunc); - patchedInSendMessageEx(0); - return true; -} - -bool TestImmGetContext(void* aFunc) -{ - auto patchedImmGetContext = - reinterpret_cast(aFunc); - patchedImmGetContext(0); - return true; -} - -bool TestImmGetCompositionStringW(void* aFunc) -{ - auto patchedImmGetCompositionStringW = - reinterpret_cast(aFunc); - patchedImmGetCompositionStringW(0, 0, 0, 0); - return true; -} - -bool TestImmSetCandidateWindow(void* aFunc) -{ - auto patchedImmSetCandidateWindow = - reinterpret_cast(aFunc); -// return patchedImmSetCandidateWindow(0, 0) == 0; - // ImmSetCandidateWindow crashes if given bad parameters. - printf("TEST-SKIPPED | WindowsDllInterceptor | " - "Will not attempt to execute patched ImmSetCandidateWindow.\n"); - return true; -} - -bool TestImmNotifyIME(void* aFunc) -{ - auto patchedImmNotifyIME = - reinterpret_cast(aFunc); - return patchedImmNotifyIME(0, 0, 0, 0) == 0; -} - -bool TestGetSaveFileNameW(void* aFunc) -{ - auto patchedGetSaveFileNameWType = - reinterpret_cast(aFunc); - patchedGetSaveFileNameWType(0); - return true; -} - -bool TestGetOpenFileNameW(void* aFunc) -{ - auto patchedGetOpenFileNameWType = - reinterpret_cast(aFunc); - patchedGetOpenFileNameWType(0); - return true; -} - -bool TestGetKeyState(void* aFunc) -{ - auto patchedGetKeyState = - reinterpret_cast(aFunc); - patchedGetKeyState(0); - return true; -} - -bool TestSendMessageTimeoutW(void* aFunc) -{ - auto patchedSendMessageTimeoutW = - reinterpret_cast(aFunc); - return patchedSendMessageTimeoutW(0, 0, 0, 0, 0, 0, 0) == 0; -} - -bool TestProcessCaretEvents(void* aFunc) -{ - auto patchedProcessCaretEvents = - reinterpret_cast(aFunc); - patchedProcessCaretEvents(0, 0, 0, 0, 0, 0, 0); - return true; -} - -bool TestSetCursorPos(void* aFunc) -{ - // SetCursorPos has some issues in automation -- see bug 1368033. - // For that reason, we don't check the return value -- we only - // check that the method runs without producing an exception. - auto patchedSetCursorPos = - reinterpret_cast(aFunc); - patchedSetCursorPos(512, 512); - return true; -} - -static DWORD sTlsIndex = 0; - -bool TestTlsAlloc(void* aFunc) -{ - auto patchedTlsAlloc = - reinterpret_cast(aFunc); - sTlsIndex = patchedTlsAlloc(); - return sTlsIndex != TLS_OUT_OF_INDEXES; -} - -bool TestTlsFree(void* aFunc) -{ - auto patchedTlsFree = - reinterpret_cast(aFunc); - return sTlsIndex != 0 && patchedTlsFree(sTlsIndex); -} - -bool TestCloseHandle(void* aFunc) -{ - auto patchedCloseHandle = - reinterpret_cast(aFunc); - return patchedCloseHandle(0) == FALSE; -} - -bool TestDuplicateHandle(void* aFunc) -{ - auto patchedDuplicateHandle = - reinterpret_cast(aFunc); - return patchedDuplicateHandle(0, 0, 0, 0, 0, 0, 0) == FALSE; -} - -bool TestPrintDlgW(void* aFunc) -{ - auto patchedPrintDlgW = - reinterpret_cast(aFunc); - patchedPrintDlgW(0); - return true; -} - -bool TestInternetConnectA(void* aFunc) -{ - auto patchedInternetConnectA = - reinterpret_cast(aFunc); - return patchedInternetConnectA(0, 0, 0, 0, 0, 0, 0, 0) == 0; -} - -HINTERNET sInternet = 0; - -bool TestInternetOpenA(void* aFunc) -{ - auto patchedInternetOpenA = - reinterpret_cast(aFunc); - sInternet = patchedInternetOpenA(0, 0, 0, 0, 0); - return sInternet != 0; -} - -bool TestInternetCloseHandle(void* aFunc) -{ - auto patchedInternetCloseHandle = - reinterpret_cast(aFunc); - return patchedInternetCloseHandle(sInternet); -} - -bool TestInternetQueryDataAvailable(void* aFunc) -{ - auto patchedInternetQueryDataAvailable = - reinterpret_cast(aFunc); - return patchedInternetQueryDataAvailable(0, 0, 0, 0) == FALSE; -} - -bool TestInternetReadFile(void* aFunc) -{ - auto patchedInternetReadFile = - reinterpret_cast(aFunc); - return patchedInternetReadFile(0, 0, 0, 0) == FALSE; -} - -bool TestInternetWriteFile(void* aFunc) -{ - auto patchedInternetWriteFile = - reinterpret_cast(aFunc); - return patchedInternetWriteFile(0, 0, 0, 0) == FALSE; -} - -bool TestInternetSetOptionA(void* aFunc) -{ - auto patchedInternetSetOptionA = - reinterpret_cast(aFunc); - return patchedInternetSetOptionA(0, 0, 0, 0) == FALSE; -} - -bool TestHttpAddRequestHeadersA(void* aFunc) -{ - auto patchedHttpAddRequestHeadersA = - reinterpret_cast(aFunc); - return patchedHttpAddRequestHeadersA(0, 0, 0, 0) == FALSE; -} - -bool TestHttpOpenRequestA(void* aFunc) -{ - auto patchedHttpOpenRequestA = - reinterpret_cast(aFunc); - return patchedHttpOpenRequestA(0, 0, 0, 0, 0, 0, 0, 0) == 0; -} - -bool TestHttpQueryInfoA(void* aFunc) -{ - auto patchedHttpQueryInfoA = - reinterpret_cast(aFunc); - return patchedHttpQueryInfoA(0, 0, 0, 0, 0) == FALSE; -} - -bool TestHttpSendRequestA(void* aFunc) -{ - auto patchedHttpSendRequestA = - reinterpret_cast(aFunc); - return patchedHttpSendRequestA(0, 0, 0, 0, 0) == FALSE; -} - -bool TestHttpSendRequestExA(void* aFunc) -{ - auto patchedHttpSendRequestExA = - reinterpret_cast(aFunc); - return patchedHttpSendRequestExA(0, 0, 0, 0, 0) == FALSE; -} - -bool TestHttpEndRequestA(void* aFunc) -{ - auto patchedHttpEndRequestA = - reinterpret_cast(aFunc); - return patchedHttpEndRequestA(0, 0, 0, 0) == FALSE; -} - -bool TestInternetQueryOptionA(void* aFunc) -{ - auto patchedInternetQueryOptionA = - reinterpret_cast(aFunc); - return patchedInternetQueryOptionA(0, 0, 0, 0) == FALSE; -} - -bool TestInternetErrorDlg(void* aFunc) -{ - auto patchedInternetErrorDlg = - reinterpret_cast(aFunc); - return patchedInternetErrorDlg(0, 0, 0, 0, 0) == ERROR_INVALID_HANDLE; -} - -CredHandle sCredHandle; - -bool TestAcquireCredentialsHandleA(void* aFunc) -{ - auto patchedAcquireCredentialsHandleA = - reinterpret_cast(aFunc); - SCHANNEL_CRED cred; - memset(&cred, 0, sizeof(cred)); - cred.dwVersion = SCHANNEL_CRED_VERSION; - return patchedAcquireCredentialsHandleA(0, UNISP_NAME, SECPKG_CRED_OUTBOUND, - 0, &cred, 0, 0, &sCredHandle, 0) == S_OK; -} - -bool TestQueryCredentialsAttributesA(void* aFunc) -{ - auto patchedQueryCredentialsAttributesA = - reinterpret_cast(aFunc); - return patchedQueryCredentialsAttributesA(&sCredHandle, 0, 0) == SEC_E_UNSUPPORTED_FUNCTION; -} - -bool TestFreeCredentialsHandle(void* aFunc) -{ - auto patchedFreeCredentialsHandle = - reinterpret_cast(aFunc); - return patchedFreeCredentialsHandle(&sCredHandle) == S_OK; -} - int main() { LARGE_INTEGER start; @@ -615,7 +415,7 @@ int main() { WindowsDllInterceptor ExeIntercept; ExeIntercept.Init("TestDllInterceptor.exe"); - if (ExeIntercept.AddHook("rotatePayload", reinterpret_cast(patched_rotatePayload), (void**) &orig_rotatePayload)) { + if (orig_rotatePayload.Set(ExeIntercept, "rotatePayload", &patched_rotatePayload)) { printf("TEST-PASS | WindowsDllInterceptor | Hook added\n"); } else { printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to add hook\n"); @@ -659,85 +459,85 @@ int main() } #endif - if (TestHook(TestGetWindowInfo, "user32.dll", "GetWindowInfo") && + if (TEST_HOOK(user32.dll, GetWindowInfo, Equals, FALSE) && #ifdef _WIN64 - TestHook(TestSetWindowLongPtr, "user32.dll", "SetWindowLongPtrA") && - TestHook(TestSetWindowLongPtr, "user32.dll", "SetWindowLongPtrW") && + TEST_HOOK(user32.dll, SetWindowLongPtrA, Equals, 0) && + TEST_HOOK(user32.dll, SetWindowLongPtrW, Equals, 0) && #else - TestHook(TestSetWindowLong, "user32.dll", "SetWindowLongA") && - TestHook(TestSetWindowLong, "user32.dll", "SetWindowLongW") && + TEST_HOOK(user32.dll, SetWindowLongA, Equals, 0) && + TEST_HOOK(user32.dll, SetWindowLongW, Equals, 0) && #endif - TestHook(TestTrackPopupMenu, "user32.dll", "TrackPopupMenu") && + TEST_HOOK(user32.dll, TrackPopupMenu, Equals, FALSE) && #ifdef _M_IX86 // We keep this test to hook complex code on x86. (Bug 850957) - TestHook(TestNtFlushBuffersFile, "ntdll.dll", "NtFlushBuffersFile") && + TEST_HOOK(ntdll.dll, NtFlushBuffersFile, NotEquals, 0) && #endif - TestHook(TestNtCreateFile, "ntdll.dll", "NtCreateFile") && - TestHook(TestNtReadFile, "ntdll.dll", "NtReadFile") && - TestHook(TestNtReadFileScatter, "ntdll.dll", "NtReadFileScatter") && - TestHook(TestNtWriteFile, "ntdll.dll", "NtWriteFile") && - TestHook(TestNtWriteFileGather, "ntdll.dll", "NtWriteFileGather") && - TestHook(TestNtQueryFullAttributesFile, "ntdll.dll", "NtQueryFullAttributesFile") && + TEST_HOOK(ntdll.dll, NtCreateFile, NotEquals, 0) && + TEST_HOOK(ntdll.dll, NtReadFile, NotEquals, 0) && + TEST_HOOK(ntdll.dll, NtReadFileScatter, NotEquals, 0) && + TEST_HOOK(ntdll.dll, NtWriteFile, NotEquals, 0) && + TEST_HOOK(ntdll.dll, NtWriteFileGather, NotEquals, 0) && + TEST_HOOK(ntdll.dll, NtQueryFullAttributesFile, NotEquals, 0) && #ifndef MOZ_ASAN // Bug 733892: toolkit/crashreporter/nsExceptionHandler.cpp // This fails on ASan because the ASan runtime already hooked this function - TestHook(TestSetUnhandledExceptionFilter, "kernel32.dll", "SetUnhandledExceptionFilter") && + TEST_HOOK(kernel32.dll, SetUnhandledExceptionFilter, Ignore, nullptr) && #endif #ifdef _M_IX86 // Bug 670967: xpcom/base/AvailableMemoryTracker.cpp - TestHook(TestVirtualAlloc, "kernel32.dll", "VirtualAlloc") && - TestHook(TestMapViewOfFile, "kernel32.dll", "MapViewOfFile") && - TestHook(TestCreateDIBSection, "gdi32.dll", "CreateDIBSection") && - TestHook(TestCreateFileW, "kernel32.dll", "CreateFileW") && // see Bug 1316415 + TEST_HOOK(kernel32.dll, VirtualAlloc, Equals, nullptr) && + TEST_HOOK(kernel32.dll, MapViewOfFile, Equals, nullptr) && + TEST_HOOK(gdi32.dll, CreateDIBSection, Equals, nullptr) && + TEST_HOOK_FOR_INVALID_HANDLE_VALUE(kernel32.dll, CreateFileW) && #endif - TestHook(TestCreateFileA, "kernel32.dll", "CreateFileA") && - TestHook(TestQueryDosDeviceW, "kernelbase.dll", "QueryDosDeviceW") && - TestDetour("user32.dll", "CreateWindowExW") && - TestHook(TestInSendMessageEx, "user32.dll", "InSendMessageEx") && - TestHook(TestImmGetContext, "imm32.dll", "ImmGetContext") && - TestHook(TestImmGetCompositionStringW, "imm32.dll", "ImmGetCompositionStringW") && - TestHook(TestImmSetCandidateWindow, "imm32.dll", "ImmSetCandidateWindow") && - TestHook(TestImmNotifyIME, "imm32.dll", "ImmNotifyIME") && - TestHook(TestGetSaveFileNameW, "comdlg32.dll", "GetSaveFileNameW") && - TestHook(TestGetOpenFileNameW, "comdlg32.dll", "GetOpenFileNameW") && + TEST_HOOK_FOR_INVALID_HANDLE_VALUE(kernel32.dll, CreateFileA) && + TEST_HOOK(kernelbase.dll, QueryDosDeviceW, Equals, 0) && + TEST_DETOUR(user32.dll, CreateWindowExW, Equals, nullptr) && + TEST_HOOK(user32.dll, InSendMessageEx, Equals, ISMEX_NOSEND) && + TEST_HOOK(imm32.dll, ImmGetContext, Equals, nullptr) && + TEST_HOOK(imm32.dll, ImmGetCompositionStringW, Ignore, 0) && + TEST_HOOK_SKIP_EXEC(imm32.dll, ImmSetCandidateWindow) && + TEST_HOOK(imm32.dll, ImmNotifyIME, Equals, 0) && + TEST_HOOK(comdlg32.dll, GetSaveFileNameW, Ignore, FALSE) && + TEST_HOOK(comdlg32.dll, GetOpenFileNameW, Ignore, FALSE) && #ifdef _M_X64 - TestHook(TestGetKeyState, "user32.dll", "GetKeyState") && // see Bug 1316415 - TestHook(TestLdrUnloadDll, "ntdll.dll", "LdrUnloadDll") && - MaybeTestHook(IsWin8OrLater(), TestLdrResolveDelayLoadedAPI, "ntdll.dll", "LdrResolveDelayLoadedAPI") && - MaybeTestHook(!IsWin8OrLater(), TestRtlInstallFunctionTableCallback, "kernel32.dll", "RtlInstallFunctionTableCallback") && - TestHook(TestPrintDlgW, "comdlg32.dll", "PrintDlgW") && + TEST_HOOK(user32.dll, GetKeyState, Ignore, 0) && // see Bug 1316415 + TEST_HOOK(ntdll.dll, LdrUnloadDll, NotEquals, 0) && + MAYBE_TEST_HOOK_SKIP_EXEC(IsWin8OrLater(), ntdll.dll, LdrResolveDelayLoadedAPI) && + MAYBE_TEST_HOOK(!IsWin8OrLater(), kernel32.dll, RtlInstallFunctionTableCallback, Equals, FALSE) && + TEST_HOOK(comdlg32.dll, PrintDlgW, Ignore, 0) && #endif - MaybeTestHook(ShouldTestTipTsf(), TestProcessCaretEvents, "tiptsf.dll", "ProcessCaretEvents") && + MAYBE_TEST_HOOK(ShouldTestTipTsf(), tiptsf.dll, ProcessCaretEvents, Ignore, nullptr) && #ifdef _M_IX86 - TestHook(TestSendMessageTimeoutW, "user32.dll", "SendMessageTimeoutW") && + TEST_HOOK(user32.dll, SendMessageTimeoutW, Equals, 0) && #endif - TestHook(TestSetCursorPos, "user32.dll", "SetCursorPos") && - TestHook(TestTlsAlloc, "kernel32.dll", "TlsAlloc") && - TestHook(TestTlsFree, "kernel32.dll", "TlsFree") && - TestHook(TestCloseHandle, "kernel32.dll", "CloseHandle") && - TestHook(TestDuplicateHandle, "kernel32.dll", "DuplicateHandle") && + TEST_HOOK(user32.dll, SetCursorPos, NotEquals, FALSE) && + TEST_HOOK(kernel32.dll, TlsAlloc, NotEquals, TLS_OUT_OF_INDEXES) && + TEST_HOOK_PARAMS(kernel32.dll, TlsFree, Equals, FALSE, TLS_OUT_OF_INDEXES) && + TEST_HOOK(kernel32.dll, CloseHandle, Equals, FALSE) && + TEST_HOOK(kernel32.dll, DuplicateHandle, Equals, FALSE) && - TestHook(TestInternetOpenA, "wininet.dll", "InternetOpenA") && - TestHook(TestInternetCloseHandle, "wininet.dll", "InternetCloseHandle") && - TestHook(TestInternetConnectA, "wininet.dll", "InternetConnectA") && - TestHook(TestInternetQueryDataAvailable, "wininet.dll", "InternetQueryDataAvailable") && - TestHook(TestInternetReadFile, "wininet.dll", "InternetReadFile") && - TestHook(TestInternetWriteFile, "wininet.dll", "InternetWriteFile") && - TestHook(TestInternetSetOptionA, "wininet.dll", "InternetSetOptionA") && - TestHook(TestHttpAddRequestHeadersA, "wininet.dll", "HttpAddRequestHeadersA") && - TestHook(TestHttpOpenRequestA, "wininet.dll", "HttpOpenRequestA") && - TestHook(TestHttpQueryInfoA, "wininet.dll", "HttpQueryInfoA") && - TestHook(TestHttpSendRequestA, "wininet.dll", "HttpSendRequestA") && - TestHook(TestHttpSendRequestExA, "wininet.dll", "HttpSendRequestExA") && - TestHook(TestHttpEndRequestA, "wininet.dll", "HttpEndRequestA") && - TestHook(TestInternetQueryOptionA, "wininet.dll", "InternetQueryOptionA") && + TEST_HOOK(wininet.dll, InternetOpenA, NotEquals, nullptr) && + TEST_HOOK(wininet.dll, InternetCloseHandle, Equals, FALSE) && + TEST_HOOK(wininet.dll, InternetConnectA, Equals, nullptr) && + TEST_HOOK(wininet.dll, InternetQueryDataAvailable, Equals, FALSE) && + TEST_HOOK(wininet.dll, InternetReadFile, Equals, FALSE) && + TEST_HOOK(wininet.dll, InternetWriteFile, Equals, FALSE) && + TEST_HOOK(wininet.dll, InternetSetOptionA, Equals, FALSE) && + TEST_HOOK(wininet.dll, HttpAddRequestHeadersA, Equals, FALSE) && + TEST_HOOK(wininet.dll, HttpOpenRequestA, Equals, nullptr) && + TEST_HOOK(wininet.dll, HttpQueryInfoA, Equals, FALSE) && + TEST_HOOK(wininet.dll, HttpSendRequestA, Equals, FALSE) && + TEST_HOOK(wininet.dll, HttpSendRequestExA, Equals, FALSE) && + TEST_HOOK(wininet.dll, HttpEndRequestA, Equals, FALSE) && + TEST_HOOK(wininet.dll, InternetQueryOptionA, Equals, FALSE) && - TestHook(TestAcquireCredentialsHandleA, "sspicli.dll", "AcquireCredentialsHandleA") && - TestHook(TestQueryCredentialsAttributesA, "sspicli.dll", "QueryCredentialsAttributesA") && - TestHook(TestFreeCredentialsHandle, "sspicli.dll", "FreeCredentialsHandle") && + TEST_HOOK(sspicli.dll, AcquireCredentialsHandleA, NotEquals, SEC_E_OK) && + TEST_HOOK(sspicli.dll, QueryCredentialsAttributesA, NotEquals, SEC_E_OK) && + TEST_HOOK(sspicli.dll, FreeCredentialsHandle, NotEquals, SEC_E_OK) && - TestDetour("kernel32.dll", "BaseThreadInitThunk") && - TestDetour("ntdll.dll", "LdrLoadDll")) { + TEST_DETOUR_SKIP_EXEC(kernel32.dll, BaseThreadInitThunk) && + TEST_DETOUR_SKIP_EXEC(ntdll.dll, LdrLoadDll)) { printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n"); LARGE_INTEGER end, freq; From ef8970296d0caea05cdf39247baf594ab55c5a56 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:48:45 -0600 Subject: [PATCH 29/57] Bug 1460022: Part 3 - Update TestDllInterceptorCrossProcess to reflect new interceptor interface; r=handyman --- .../interceptor/TestDllInterceptorCrossProcess.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp b/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp index 95cf37821043..c29d132ba9b0 100644 --- a/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp +++ b/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp @@ -11,19 +11,19 @@ using std::wstring; -static void* gOrigReturnResult; - extern "C" __declspec(dllexport) int ReturnResult() { return 2; } +static mozilla::CrossProcessDllInterceptor::FuncHookType + gOrigReturnResult; + static int ReturnResultHook() { - auto origFn = reinterpret_cast(gOrigReturnResult); - if (origFn() != 2) { + if (gOrigReturnResult() != 2) { return 3; } @@ -73,9 +73,7 @@ int ParentMain() mozilla::CrossProcessDllInterceptor intcpt(childProcess.get()); intcpt.Init("TestDllInterceptorCrossProcess.exe"); - if (!intcpt.AddHook("ReturnResult", - reinterpret_cast(&ReturnResultHook), - &gOrigReturnResult)) { + if (!gOrigReturnResult.Set(intcpt, "ReturnResult", &ReturnResultHook)) { printf("TEST-UNEXPECTED-FAIL | DllInterceptorCrossProcess | Failed to add hook\n"); return 1; } From 349c64cd00768d07b5ac1ebfe1f6ce30761b20f3 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:49:17 -0600 Subject: [PATCH 30/57] Bug 1460022: Part 4 - Update a11y code to reflect new interface for DLL interceptor; r=Jamie --- accessible/windows/msaa/Compatibility.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/accessible/windows/msaa/Compatibility.cpp b/accessible/windows/msaa/Compatibility.cpp index 6446f19805c0..f4434f37c0b5 100644 --- a/accessible/windows/msaa/Compatibility.cpp +++ b/accessible/windows/msaa/Compatibility.cpp @@ -95,7 +95,8 @@ Compatibility::IsModuleVersionLessThan(HMODULE aModuleHandle, //////////////////////////////////////////////////////////////////////////////// static WindowsDllInterceptor sUser32Interceptor; -static decltype(&InSendMessageEx) sInSendMessageExStub = nullptr; +static WindowsDllInterceptor::FuncHookType + sInSendMessageExStub; static bool sInSendMessageExHackEnabled = false; static PVOID sVectoredExceptionHandler = nullptr; @@ -267,11 +268,9 @@ Compatibility::Init() if ((sConsumers & (~(UIAUTOMATION | NVDA))) && BrowserTabsRemoteAutostart()) { sUser32Interceptor.Init("user32.dll"); - if (!sInSendMessageExStub) { - sUser32Interceptor.AddHook("InSendMessageEx", - reinterpret_cast(&InSendMessageExHook), - (void**)&sInSendMessageExStub); - } + sInSendMessageExStub.Set(sUser32Interceptor, "InSendMessageEx", + &InSendMessageExHook); + // The vectored exception handler allows us to catch exceptions ahead of any // SEH handlers. if (!sVectoredExceptionHandler) { From 6ed3d9c74febd8870815e8a5947fec017d95201c Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:49:30 -0600 Subject: [PATCH 31/57] Bug 1460022: Part 5 - Update launcher process to work with new DLL interceptor interface; r=mhowell --- browser/app/winlauncher/DllBlocklistWin.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/browser/app/winlauncher/DllBlocklistWin.cpp b/browser/app/winlauncher/DllBlocklistWin.cpp index 82e1d77d3722..a88a0747348f 100644 --- a/browser/app/winlauncher/DllBlocklistWin.cpp +++ b/browser/app/winlauncher/DllBlocklistWin.cpp @@ -246,7 +246,8 @@ IsDllAllowed(const UNICODE_STRING& aLeafName, void* aBaseAddress) } typedef decltype(&NtMapViewOfSection) NtMapViewOfSection_func; -static NtMapViewOfSection_func stub_NtMapViewOfSection; +static mozilla::CrossProcessDllInterceptor::FuncHookType + stub_NtMapViewOfSection; static NTSTATUS NTAPI patched_NtMapViewOfSection(HANDLE aSection, HANDLE aProcess, PVOID* aBaseAddress, @@ -356,9 +357,8 @@ InitializeDllBlocklistOOP(HANDLE aChildProcess) { mozilla::CrossProcessDllInterceptor intcpt(aChildProcess); intcpt.Init(L"ntdll.dll"); - bool ok = intcpt.AddDetour("NtMapViewOfSection", - reinterpret_cast(&patched_NtMapViewOfSection), - (void**) &stub_NtMapViewOfSection); + bool ok = stub_NtMapViewOfSection.SetDetour(intcpt, "NtMapViewOfSection", + &patched_NtMapViewOfSection); if (!ok) { return false; } From 6d8cf290f73c28375444bbc7df27d47ae7fc5ce9 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:49:49 -0600 Subject: [PATCH 32/57] Bug 1460022: Part 6 - Update GMP code to work with new DLL interceptor interface; r=cpearce --- dom/media/gmp/ChromiumCDMAdapter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dom/media/gmp/ChromiumCDMAdapter.cpp b/dom/media/gmp/ChromiumCDMAdapter.cpp index b8fbe7a2f9da..e1946dee5106 100644 --- a/dom/media/gmp/ChromiumCDMAdapter.cpp +++ b/dom/media/gmp/ChromiumCDMAdapter.cpp @@ -197,7 +197,8 @@ typedef DWORD(WINAPI* QueryDosDeviceWFnPtr)(_In_opt_ LPCWSTR lpDeviceName, _Out_ LPWSTR lpTargetPath, _In_ DWORD ucchMax); -static QueryDosDeviceWFnPtr sOriginalQueryDosDeviceWFnPtr = nullptr; +static WindowsDllInterceptor::FuncHookType + sOriginalQueryDosDeviceWFnPtr; static std::unordered_map* sDeviceNames = nullptr; @@ -276,9 +277,8 @@ InitializeHooks() } sKernel32Intercept.Init("kernelbase.dll"); - sKernel32Intercept.AddHook("QueryDosDeviceW", - reinterpret_cast(QueryDosDeviceWHook), - (void**)(&sOriginalQueryDosDeviceWFnPtr)); + sOriginalQueryDosDeviceWFnPtr.Set(sKernel32Intercept, "QueryDosDeviceW", + &QueryDosDeviceWHook); } #endif From 0f899ac198b1ba90f6cba3680b5ee956037d71b6 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:50:50 -0600 Subject: [PATCH 33/57] Bug 1460022: Part 7 - Update plugin code to work with revised DLL interceptor interface; r=handyman --- dom/plugins/base/nsPluginNativeWindowWin.cpp | 36 ++++---- dom/plugins/ipc/FunctionHook.cpp | 21 +---- dom/plugins/ipc/FunctionHook.h | 27 ++++-- dom/plugins/ipc/PluginInstanceChild.cpp | 97 +++++++------------- 4 files changed, 73 insertions(+), 108 deletions(-) diff --git a/dom/plugins/base/nsPluginNativeWindowWin.cpp b/dom/plugins/base/nsPluginNativeWindowWin.cpp index fc7f0ea72345..570b99e52610 100644 --- a/dom/plugins/base/nsPluginNativeWindowWin.cpp +++ b/dom/plugins/base/nsPluginNativeWindowWin.cpp @@ -357,8 +357,10 @@ typedef LONG_PTR (WINAPI *User32SetWindowLongPtrW)(HWND hWnd, int nIndex, LONG_PTR dwNewLong); -static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = nullptr; -static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = nullptr; +static WindowsDllInterceptor::FuncHookType + sUser32SetWindowLongAHookStub; +static WindowsDllInterceptor::FuncHookType + sUser32SetWindowLongWHookStub; #else typedef LONG (WINAPI *User32SetWindowLongA)(HWND hWnd, @@ -368,8 +370,10 @@ typedef LONG (WINAPI *User32SetWindowLongW)(HWND hWnd, int nIndex, LONG dwNewLong); -static User32SetWindowLongA sUser32SetWindowLongAHookStub = nullptr; -static User32SetWindowLongW sUser32SetWindowLongWHookStub = nullptr; +static WindowsDllInterceptor::FuncHookType + sUser32SetWindowLongAHookStub; +static WindowsDllInterceptor::FuncHookType + sUser32SetWindowLongWHookStub; #endif static inline bool SetWindowLongHookCheck(HWND hWnd, @@ -448,23 +452,15 @@ HookSetWindowLongPtr() { sUser32Intercept.Init("user32.dll"); #ifdef _WIN64 - if (!sUser32SetWindowLongAHookStub) - sUser32Intercept.AddHook("SetWindowLongPtrA", - reinterpret_cast(SetWindowLongPtrAHook), - (void**) &sUser32SetWindowLongAHookStub); - if (!sUser32SetWindowLongWHookStub) - sUser32Intercept.AddHook("SetWindowLongPtrW", - reinterpret_cast(SetWindowLongPtrWHook), - (void**) &sUser32SetWindowLongWHookStub); + sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongPtrA", + &SetWindowLongPtrAHook); + sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongPtrW", + &SetWindowLongPtrWHook); #else - if (!sUser32SetWindowLongAHookStub) - sUser32Intercept.AddHook("SetWindowLongA", - reinterpret_cast(SetWindowLongAHook), - (void**) &sUser32SetWindowLongAHookStub); - if (!sUser32SetWindowLongWHookStub) - sUser32Intercept.AddHook("SetWindowLongW", - reinterpret_cast(SetWindowLongWHook), - (void**) &sUser32SetWindowLongWHookStub); + sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongA", + &SetWindowLongAHook); + sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongW", + &SetWindowLongWHook); #endif } diff --git a/dom/plugins/ipc/FunctionHook.cpp b/dom/plugins/ipc/FunctionHook.cpp index d5e29ec14f18..3d4733a19277 100644 --- a/dom/plugins/ipc/FunctionHook.cpp +++ b/dom/plugins/ipc/FunctionHook.cpp @@ -168,13 +168,13 @@ typedef HANDLE (WINAPI *CreateFileWPtr)(LPCWSTR aFname, DWORD aAccess, LPSECURITY_ATTRIBUTES aSecurity, DWORD aCreation, DWORD aFlags, HANDLE aFTemplate); -static CreateFileWPtr sCreateFileWStub = nullptr; +static WindowsDllInterceptor::FuncHookType sCreateFileWStub; typedef HANDLE (WINAPI *CreateFileAPtr)(LPCSTR aFname, DWORD aAccess, DWORD aShare, LPSECURITY_ATTRIBUTES aSecurity, DWORD aCreation, DWORD aFlags, HANDLE aFTemplate); -static CreateFileAPtr sCreateFileAStub = nullptr; +static WindowsDllInterceptor::FuncHookType sCreateFileAStub; // Windows 8 RTM (kernelbase's version is 6.2.9200.16384) doesn't call // CreateFileW from CreateFileA. @@ -263,7 +263,7 @@ CreateFileWHookFn(LPCWSTR aFname, DWORD aAccess, DWORD aShare, aSecurity, TRUNCATE_EXISTING, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, - NULL); + nullptr); if (replacement == INVALID_HANDLE_VALUE) { break; } @@ -300,23 +300,12 @@ CreateFileWHookFn(LPCWSTR aFname, DWORD aAccess, DWORD aShare, void FunctionHook::HookProtectedMode() { - // Make sure we only do this once. - static bool sRunOnce = false; - if (sRunOnce) { - return; - } - sRunOnce = true; - // Legacy code. Uses the nsWindowsDLLInterceptor directly instead of // using the FunctionHook sKernel32Intercept.Init("kernel32.dll"); MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Plugin); - sKernel32Intercept.AddHook("CreateFileW", - reinterpret_cast(CreateFileWHookFn), - (void**) &sCreateFileWStub); - sKernel32Intercept.AddHook("CreateFileA", - reinterpret_cast(CreateFileAHookFn), - (void**) &sCreateFileAStub); + sCreateFileWStub.Set(sKernel32Intercept, "CreateFileW", &CreateFileWHookFn); + sCreateFileAStub.Set(sKernel32Intercept, "CreateFileA", &CreateFileAHookFn); } #endif // defined(XP_WIN) diff --git a/dom/plugins/ipc/FunctionHook.h b/dom/plugins/ipc/FunctionHook.h index c9b30dd0643a..06baf6acdad8 100644 --- a/dom/plugins/ipc/FunctionHook.h +++ b/dom/plugins/ipc/FunctionHook.h @@ -9,6 +9,7 @@ #include "IpdlTuple.h" #include "base/process.h" +#include "mozilla/Atomics.h" #if defined(XP_WIN) #include "nsWindowsDllInterceptor.h" @@ -96,12 +97,19 @@ typedef bool(ShouldHookFunc)(int aQuirks); template class BasicFunctionHook : public FunctionHook { +#if defined(XP_WIN) + using FuncHookType = WindowsDllInterceptor::FuncHookType; +#endif // defined(XP_WIN) + public: BasicFunctionHook(const char* aModuleName, const char* aFunctionName, FunctionType* aOldFunction, - FunctionType* aNewFunction) : - mOldFunction(aOldFunction), mRegistration(UNREGISTERED), mModuleName(aModuleName), - mFunctionName(aFunctionName), mNewFunction(aNewFunction) + FunctionType* aNewFunction) + : mOldFunction(aOldFunction) + , mRegistration(UNREGISTERED) + , mModuleName(aModuleName) + , mFunctionName(aFunctionName) + , mNewFunction(aNewFunction) { MOZ_ASSERT(mOldFunction); MOZ_ASSERT(mNewFunction); @@ -128,7 +136,10 @@ protected: // Once the function is hooked, this field will take the value of a pointer to // a function that performs the old behavior. Before that, it is a pointer to // the original function. - FunctionType* mOldFunction; + Atomic mOldFunction; +#if defined(XP_WIN) + FuncHookType mStub; +#endif // defined(XP_WIN) enum RegistrationStatus { UNREGISTERED, FAILED, SUCCEEDED }; RegistrationStatus mRegistration; @@ -170,14 +181,16 @@ BasicFunctionHook::Register(int aQuirks) return false; } - isHooked = - dllInterceptor->AddHook(mFunctionName.Data(), reinterpret_cast(mNewFunction), - reinterpret_cast(&mOldFunction)); + isHooked = mStub.Set(*dllInterceptor, mFunctionName.Data(), mNewFunction); #endif if (isHooked) { +#if defined(XP_WIN) + mOldFunction = mStub.GetStub(); +#endif mRegistration = SUCCEEDED; } + HOOK_LOG(LogLevel::Debug, ("Registering to intercept function '%s' : '%s'", mFunctionName.Data(), SuccessMsg(isHooked))); diff --git a/dom/plugins/ipc/PluginInstanceChild.cpp b/dom/plugins/ipc/PluginInstanceChild.cpp index 47e779a6072c..bab3067be6ee 100644 --- a/dom/plugins/ipc/PluginInstanceChild.cpp +++ b/dom/plugins/ipc/PluginInstanceChild.cpp @@ -73,21 +73,17 @@ typedef BOOL (WINAPI *User32TrackPopupMenu)(HMENU hMenu, CONST RECT *prcRect); static WindowsDllInterceptor sUser32Intercept; static HWND sWinlessPopupSurrogateHWND = nullptr; -static User32TrackPopupMenu sUser32TrackPopupMenuStub = nullptr; +static WindowsDllInterceptor::FuncHookType sUser32TrackPopupMenuStub; static WindowsDllInterceptor sImm32Intercept; -static decltype(ImmGetContext)* sImm32ImmGetContextStub = nullptr; -static decltype(ImmGetCompositionStringW)* sImm32ImmGetCompositionStringStub = - nullptr; -static decltype(ImmSetCandidateWindow)* sImm32ImmSetCandidateWindowStub = - nullptr; -static decltype(ImmNotifyIME)* sImm32ImmNotifyIME = nullptr; -static decltype(ImmAssociateContextEx)* sImm32ImmAssociateContextExStub = - nullptr; +static WindowsDllInterceptor::FuncHookType sImm32ImmGetContextStub; +static WindowsDllInterceptor::FuncHookType sImm32ImmGetCompositionStringStub; +static WindowsDllInterceptor::FuncHookType sImm32ImmSetCandidateWindowStub; +static WindowsDllInterceptor::FuncHookType sImm32ImmNotifyIME; +static WindowsDllInterceptor::FuncHookType sImm32ImmAssociateContextExStub; + static PluginInstanceChild* sCurrentPluginInstance = nullptr; static const HIMC sHookIMC = (const HIMC)0xefefefef; -static bool sPopupMenuHookSet; -static bool sSetWindowLongHookSet; using mozilla::gfx::SharedDIB; @@ -1793,8 +1789,8 @@ typedef LONG_PTR (WINAPI *User32SetWindowLongPtrW)(HWND hWnd, int nIndex, LONG_PTR dwNewLong); -static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = nullptr; -static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = nullptr; +static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongAHookStub; +static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongWHookStub; #else typedef LONG (WINAPI *User32SetWindowLongA)(HWND hWnd, @@ -1804,8 +1800,8 @@ typedef LONG (WINAPI *User32SetWindowLongW)(HWND hWnd, int nIndex, LONG dwNewLong); -static User32SetWindowLongA sUser32SetWindowLongAHookStub = nullptr; -static User32SetWindowLongW sUser32SetWindowLongWHookStub = nullptr; +static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongAHookStub; +static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongWHookStub; #endif extern LRESULT CALLBACK @@ -1915,27 +1911,17 @@ PluginInstanceChild::HookSetWindowLongPtr() return; } - // Only pass through here once - if (sSetWindowLongHookSet) { - return; - } - sSetWindowLongHookSet = true; - sUser32Intercept.Init("user32.dll"); #ifdef _WIN64 - if (!sUser32SetWindowLongAHookStub) - sUser32Intercept.AddHook("SetWindowLongPtrA", reinterpret_cast(SetWindowLongPtrAHook), - (void**) &sUser32SetWindowLongAHookStub); - if (!sUser32SetWindowLongWHookStub) - sUser32Intercept.AddHook("SetWindowLongPtrW", reinterpret_cast(SetWindowLongPtrWHook), - (void**) &sUser32SetWindowLongWHookStub); + sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongPtrA", + &SetWindowLongPtrAHook); + sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongPtrW", + &SetWindowLongPtrWHook); #else - if (!sUser32SetWindowLongAHookStub) - sUser32Intercept.AddHook("SetWindowLongA", reinterpret_cast(SetWindowLongAHook), - (void**) &sUser32SetWindowLongAHookStub); - if (!sUser32SetWindowLongWHookStub) - sUser32Intercept.AddHook("SetWindowLongW", reinterpret_cast(SetWindowLongWHook), - (void**) &sUser32SetWindowLongWHookStub); + sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongA", + &SetWindowLongAHook); + sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongW", + &SetWindowLongWHook); #endif } @@ -2003,19 +1989,13 @@ PluginInstanceChild::InitPopupMenuHook() return; } - // Only pass through here once - if (sPopupMenuHookSet) { - return; - } - sPopupMenuHookSet = true; - // Note, once WindowsDllInterceptor is initialized for a module, // it remains initialized for that particular module for it's // lifetime. Additional instances are needed if other modules need // to be hooked. sUser32Intercept.Init("user32.dll"); - sUser32Intercept.AddHook("TrackPopupMenu", reinterpret_cast(TrackPopupHookProc), - (void**) &sUser32TrackPopupMenuStub); + sUser32TrackPopupMenuStub.Set(sUser32Intercept, "TrackPopupMenu", + &TrackPopupHookProc); } void @@ -2157,36 +2137,23 @@ PluginInstanceChild::InitImm32Hook() return; } - if (sImm32ImmGetContextStub) { - return; - } - // When using windowless plugin, IMM API won't work due ot OOP. // // ImmReleaseContext on Windows 7+ just returns TRUE only, so we don't // need to hook this. sImm32Intercept.Init("imm32.dll"); - sImm32Intercept.AddHook( - "ImmGetContext", - reinterpret_cast(ImmGetContextProc), - (void**)&sImm32ImmGetContextStub); - sImm32Intercept.AddHook( - "ImmGetCompositionStringW", - reinterpret_cast(ImmGetCompositionStringProc), - (void**)&sImm32ImmGetCompositionStringStub); - sImm32Intercept.AddHook( - "ImmSetCandidateWindow", - reinterpret_cast(ImmSetCandidateWindowProc), - (void**)&sImm32ImmSetCandidateWindowStub); - sImm32Intercept.AddHook( - "ImmNotifyIME", - reinterpret_cast(ImmNotifyIME), - (void**)&sImm32ImmNotifyIME); - sImm32Intercept.AddHook( - "ImmAssociateContextEx", - reinterpret_cast(ImmAssociateContextExProc), - (void**)&sImm32ImmAssociateContextExStub); + sImm32ImmGetContextStub.Set(sImm32Intercept, "ImmGetContext", + &ImmGetContextProc); + sImm32ImmGetCompositionStringStub.Set(sImm32Intercept, + "ImmGetCompositionStringW", + &ImmGetCompositionStringProc); + sImm32ImmSetCandidateWindowStub.Set(sImm32Intercept, + "ImmSetCandidateWindow", + &ImmSetCandidateWindowProc); + sImm32ImmNotifyIME.Set(sImm32Intercept, "ImmNotifyIME", &ImmNotifyIME); + sImm32ImmAssociateContextExStub.Set(sImm32Intercept, "ImmAssociateContextEx", + &ImmAssociateContextExProc); } void From 87175de9228e3e8cc665d1072cd0c502e13638ee Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:51:10 -0600 Subject: [PATCH 34/57] Bug 1460022: Part 8 - Update DLL blocklist to work with revised DLL interceptor interface; r=mhowell --- mozglue/build/WindowsDllBlocklist.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/mozglue/build/WindowsDllBlocklist.cpp b/mozglue/build/WindowsDllBlocklist.cpp index 6071e4241986..4b7a6f7ecf6a 100644 --- a/mozglue/build/WindowsDllBlocklist.cpp +++ b/mozglue/build/WindowsDllBlocklist.cpp @@ -90,14 +90,14 @@ printf_stderr(const char *fmt, ...) typedef MOZ_NORETURN_PTR void (__fastcall* BaseThreadInitThunk_func)(BOOL aIsInitialThread, void* aStartAddress, void* aThreadParam); -static BaseThreadInitThunk_func stub_BaseThreadInitThunk = nullptr; +static WindowsDllInterceptor::FuncHookType stub_BaseThreadInitThunk; typedef NTSTATUS (NTAPI *LdrLoadDll_func) (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle); -static LdrLoadDll_func stub_LdrLoadDll; +static WindowsDllInterceptor::FuncHookType stub_LdrLoadDll; #ifdef _M_AMD64 typedef decltype(RtlInstallFunctionTableCallback)* RtlInstallFunctionTableCallback_func; -static RtlInstallFunctionTableCallback_func stub_RtlInstallFunctionTableCallback; +static WindowsDllInterceptor::FuncHookType stub_RtlInstallFunctionTableCallback; extern uint8_t* sMsMpegJitCodeRegionStart; extern size_t sMsMpegJitCodeRegionSize; @@ -662,7 +662,8 @@ DllBlocklist_Initialize(uint32_t aInitFlags) // We specifically use a detour, because there are cases where external // code also tries to hook LdrLoadDll, and doesn't know how to relocate our // nop space patches. (Bug 951827) - bool ok = NtDllIntercept.AddDetour("LdrLoadDll", reinterpret_cast(patched_LdrLoadDll), (void**) &stub_LdrLoadDll); + bool ok = stub_LdrLoadDll.SetDetour(NtDllIntercept, "LdrLoadDll", + &patched_LdrLoadDll); if (!ok) { sBlocklistInitFailed = true; @@ -683,18 +684,18 @@ DllBlocklist_Initialize(uint32_t aInitFlags) #ifdef _M_AMD64 if (!IsWin8OrLater()) { // The crash that this hook works around is only seen on Win7. - Kernel32Intercept.AddHook("RtlInstallFunctionTableCallback", - reinterpret_cast(patched_RtlInstallFunctionTableCallback), - (void**)&stub_RtlInstallFunctionTableCallback); + stub_RtlInstallFunctionTableCallback.Set(Kernel32Intercept, + "RtlInstallFunctionTableCallback", + &patched_RtlInstallFunctionTableCallback); } #endif // Bug 1361410: WRusr.dll will overwrite our hook and cause a crash. // Workaround: If we detect WRusr.dll, don't hook. if (!GetModuleHandleW(L"WRusr.dll")) { - if(!Kernel32Intercept.AddDetour("BaseThreadInitThunk", - reinterpret_cast(patched_BaseThreadInitThunk), - (void**) &stub_BaseThreadInitThunk)) { + if (!stub_BaseThreadInitThunk.SetDetour(Kernel32Intercept, + "BaseThreadInitThunk", + &patched_BaseThreadInitThunk)) { #ifdef DEBUG printf_stderr("BaseThreadInitThunk hook failed\n"); #endif From a65c046384f7342ef697f5bb26cd0aa3167c8da0 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:51:29 -0600 Subject: [PATCH 35/57] Bug 1460022: Part 9 - Update sandboxing code to work with revised DLL interceptor interface; r=bobowen --- security/sandbox/win/SandboxInitialization.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/security/sandbox/win/SandboxInitialization.cpp b/security/sandbox/win/SandboxInitialization.cpp index 8e27b87dd2f4..8a4a5e858072 100644 --- a/security/sandbox/win/SandboxInitialization.cpp +++ b/security/sandbox/win/SandboxInitialization.cpp @@ -15,7 +15,7 @@ namespace mozilla { namespace sandboxing { typedef BOOL(WINAPI* CloseHandle_func) (HANDLE hObject); -static CloseHandle_func stub_CloseHandle = nullptr; +static WindowsDllInterceptor::FuncHookType stub_CloseHandle; typedef BOOL(WINAPI* DuplicateHandle_func)(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, @@ -24,7 +24,8 @@ typedef BOOL(WINAPI* DuplicateHandle_func)(HANDLE hSourceProcessHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions); -static DuplicateHandle_func stub_DuplicateHandle = nullptr; +static WindowsDllInterceptor::FuncHookType + stub_DuplicateHandle; static BOOL WINAPI patched_CloseHandle(HANDLE hObject) @@ -62,17 +63,14 @@ EnableHandleCloseMonitoring() { Kernel32Intercept.Init("kernel32.dll"); bool hooked = - Kernel32Intercept.AddHook("CloseHandle", - reinterpret_cast(patched_CloseHandle), - (void**)&stub_CloseHandle); + stub_CloseHandle.Set(Kernel32Intercept, "CloseHandle", &patched_CloseHandle); if (!hooked) { return false; } hooked = - Kernel32Intercept.AddHook("DuplicateHandle", - reinterpret_cast(patched_DuplicateHandle), - (void**)&stub_DuplicateHandle); + stub_DuplicateHandle.Set(Kernel32Intercept, "DuplicateHandle", + &patched_DuplicateHandle); if (!hooked) { return false; } From 390fdc316e329a968ded7b937938d394e8835fb6 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:51:40 -0600 Subject: [PATCH 36/57] Bug 1460022: Part 10 - Update crash reporter to work with revised DLL interceptor interface; r=dmajor --- toolkit/crashreporter/nsExceptionHandler.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp index 7f42278ef244..319f78f27cc0 100644 --- a/toolkit/crashreporter/nsExceptionHandler.cpp +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -338,7 +338,8 @@ nsTArray >* gDelayedAnnotations; // reporter is loaded instead (in case it became unloaded somehow) typedef LPTOP_LEVEL_EXCEPTION_FILTER (WINAPI *SetUnhandledExceptionFilter_func) (LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); -static SetUnhandledExceptionFilter_func stub_SetUnhandledExceptionFilter = 0; +static WindowsDllInterceptor::FuncHookType + stub_SetUnhandledExceptionFilter; static LPTOP_LEVEL_EXCEPTION_FILTER previousUnhandledExceptionFilter = nullptr; static WindowsDllInterceptor gKernel32Intercept; static bool gBlockUnhandledExceptionFilter = true; @@ -1639,9 +1640,9 @@ nsresult SetExceptionHandler(nsIFile* aXREDirectory, // protect the crash reporter from being unloaded gBlockUnhandledExceptionFilter = true; gKernel32Intercept.Init("kernel32.dll"); - bool ok = gKernel32Intercept.AddHook("SetUnhandledExceptionFilter", - reinterpret_cast(patched_SetUnhandledExceptionFilter), - (void**) &stub_SetUnhandledExceptionFilter); + bool ok = stub_SetUnhandledExceptionFilter.Set(gKernel32Intercept, + "SetUnhandledExceptionFilter", + &patched_SetUnhandledExceptionFilter); #ifdef DEBUG if (!ok) From f6d3eb0eb2f6df8af9885f0ca3901aed433f13e1 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:52:01 -0600 Subject: [PATCH 37/57] Bug 1460022: Part 11 - Update Win32 nsWindow to work with revised DLL interceptor interface; r=mhowell --- widget/windows/nsWindow.cpp | 46 ++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index db0389563b1e..f15691569075 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -352,9 +352,6 @@ static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); // General purpose user32.dll hook object static WindowsDllInterceptor sUser32Intercept; -// AddHook success checks -static mozilla::Maybe sHookedGetWindowInfo; - // 2 pixel offset for eTransparencyBorderlessGlass which equals the size of // the default window border Windows paints. Glass will be extended inward // this distance to remove the border. @@ -461,17 +458,17 @@ private: if (!IsWin10OrLater() && GetModuleHandle(L"tiptsf.dll") && !sProcessCaretEventsStub) { sTipTsfInterceptor.Init("tiptsf.dll"); - DebugOnly ok = sTipTsfInterceptor.AddHook("ProcessCaretEvents", - reinterpret_cast(&ProcessCaretEventsHook), - (void**) &sProcessCaretEventsStub); + DebugOnly ok = sProcessCaretEventsStub.Set(sTipTsfInterceptor, + "ProcessCaretEvents", + &ProcessCaretEventsHook); MOZ_ASSERT(ok); } if (!sSendMessageTimeoutWStub) { sUser32Intercept.Init("user32.dll"); - DebugOnly hooked = sUser32Intercept.AddHook("SendMessageTimeoutW", - reinterpret_cast(&SendMessageTimeoutWHook), - (void**) &sSendMessageTimeoutWStub); + DebugOnly hooked = sSendMessageTimeoutWStub.Set(sUser32Intercept, + "SendMessageTimeoutW", + &SendMessageTimeoutWHook); MOZ_ASSERT(hooked); } } @@ -556,8 +553,10 @@ private: } static WindowsDllInterceptor sTipTsfInterceptor; - static WINEVENTPROC sProcessCaretEventsStub; - static decltype(&SendMessageTimeoutW) sSendMessageTimeoutWStub; + static WindowsDllInterceptor::FuncHookType + sProcessCaretEventsStub; + static WindowsDllInterceptor::FuncHookType + sSendMessageTimeoutWStub; static StaticAutoPtr sInstance; HHOOK mHook; @@ -566,8 +565,10 @@ private: }; WindowsDllInterceptor TIPMessageHandler::sTipTsfInterceptor; -WINEVENTPROC TIPMessageHandler::sProcessCaretEventsStub; -decltype(&SendMessageTimeoutW) TIPMessageHandler::sSendMessageTimeoutWStub; +WindowsDllInterceptor::FuncHookType + TIPMessageHandler::sProcessCaretEventsStub; +WindowsDllInterceptor::FuncHookType + TIPMessageHandler::sSendMessageTimeoutWStub; StaticAutoPtr TIPMessageHandler::sInstance; } // namespace mozilla @@ -2472,7 +2473,7 @@ nsWindow::ResetLayout() // margins are set. static const wchar_t kManageWindowInfoProperty[] = L"ManageWindowInfoProperty"; typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi); -static GetWindowInfoPtr sGetWindowInfoPtrStub = nullptr; +static WindowsDllInterceptor::FuncHookType sGetWindowInfoPtrStub; BOOL WINAPI GetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi) @@ -2500,18 +2501,15 @@ nsWindow::UpdateGetWindowInfoCaptionStatus(bool aActiveCaption) if (!mWnd) return; - if (sHookedGetWindowInfo.isNothing()) { - sUser32Intercept.Init("user32.dll"); - sHookedGetWindowInfo = - Some(sUser32Intercept.AddHook("GetWindowInfo", - reinterpret_cast(GetWindowInfoHook), - (void**) &sGetWindowInfoPtrStub)); - if (!sHookedGetWindowInfo.value()) { - return; - } + sUser32Intercept.Init("user32.dll"); + sGetWindowInfoPtrStub.Set(sUser32Intercept, "GetWindowInfo", + &GetWindowInfoHook); + if (!sGetWindowInfoPtrStub) { + return; } + // Update our internally tracked caption status - SetPropW(mWnd, kManageWindowInfoProperty, + SetPropW(mWnd, kManageWindowInfoProperty, reinterpret_cast(static_cast(aActiveCaption) + 1)); } From 576052018bc25757ba50e420e1db610e1bfab6e3 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:52:18 -0600 Subject: [PATCH 38/57] Bug 1460022: Part 12 - Update XPCOM to use revised DLL interceptor interface; r=froydnj --- xpcom/base/AvailableMemoryTracker.cpp | 27 +++++------ xpcom/build/PoisonIOInterposerWin.cpp | 64 ++++++++++++--------------- 2 files changed, 39 insertions(+), 52 deletions(-) diff --git a/xpcom/base/AvailableMemoryTracker.cpp b/xpcom/base/AvailableMemoryTracker.cpp index 678566087eda..02265da2c6f1 100644 --- a/xpcom/base/AvailableMemoryTracker.cpp +++ b/xpcom/base/AvailableMemoryTracker.cpp @@ -84,16 +84,14 @@ volatile PRIntervalTime sLastLowMemoryNotificationTime; // These are function pointers to the functions we wrap in Init(). -void* (WINAPI* sVirtualAllocOrig)(LPVOID aAddress, SIZE_T aSize, - DWORD aAllocationType, DWORD aProtect); +static WindowsDllInterceptor::FuncHookType + sVirtualAllocOrig; -void* (WINAPI* sMapViewOfFileOrig)(HANDLE aFileMappingObject, - DWORD aDesiredAccess, DWORD aFileOffsetHigh, - DWORD aFileOffsetLow, SIZE_T aNumBytesToMap); +static WindowsDllInterceptor::FuncHookType + sMapViewOfFileOrig; -HBITMAP(WINAPI* sCreateDIBSectionOrig)(HDC aDC, const BITMAPINFO* aBitmapInfo, - UINT aUsage, VOID** aBits, - HANDLE aSection, DWORD aOffset); +static WindowsDllInterceptor::FuncHookType + sCreateDIBSectionOrig; /** * Fire a memory pressure event if we were not under memory pressure yet, or @@ -645,17 +643,12 @@ Init() // VirtualAllocHook from reentering itself. if (!PR_GetEnv("MOZ_PGO_INSTRUMENTED")) { sKernel32Intercept.Init("Kernel32.dll"); - sKernel32Intercept.AddHook("VirtualAlloc", - reinterpret_cast(VirtualAllocHook), - reinterpret_cast(&sVirtualAllocOrig)); - sKernel32Intercept.AddHook("MapViewOfFile", - reinterpret_cast(MapViewOfFileHook), - reinterpret_cast(&sMapViewOfFileOrig)); + sVirtualAllocOrig.Set(sKernel32Intercept, "VirtualAlloc", &VirtualAllocHook); + sMapViewOfFileOrig.Set(sKernel32Intercept, "MapViewOfFile", &MapViewOfFileHook); sGdi32Intercept.Init("Gdi32.dll"); - sGdi32Intercept.AddHook("CreateDIBSection", - reinterpret_cast(CreateDIBSectionHook), - reinterpret_cast(&sCreateDIBSectionOrig)); + sCreateDIBSectionOrig.Set(sGdi32Intercept, "CreateDIBSection", + &CreateDIBSectionHook); } sInitialized = true; diff --git a/xpcom/build/PoisonIOInterposerWin.cpp b/xpcom/build/PoisonIOInterposerWin.cpp index 6d8bc0a01233..5f2aaec25e28 100644 --- a/xpcom/build/PoisonIOInterposerWin.cpp +++ b/xpcom/build/PoisonIOInterposerWin.cpp @@ -209,13 +209,20 @@ WinIOAutoObservation::Filename(nsAString& aFilename) /*************************** IO Interposing Methods ***************************/ // Function pointers to original functions -static NtCreateFileFn gOriginalNtCreateFile; -static NtReadFileFn gOriginalNtReadFile; -static NtReadFileScatterFn gOriginalNtReadFileScatter; -static NtWriteFileFn gOriginalNtWriteFile; -static NtWriteFileGatherFn gOriginalNtWriteFileGather; -static NtFlushBuffersFileFn gOriginalNtFlushBuffersFile; -static NtQueryFullAttributesFileFn gOriginalNtQueryFullAttributesFile; +static WindowsDllInterceptor::FuncHookType + gOriginalNtCreateFile; +static WindowsDllInterceptor::FuncHookType + gOriginalNtReadFile; +static WindowsDllInterceptor::FuncHookType + gOriginalNtReadFileScatter; +static WindowsDllInterceptor::FuncHookType + gOriginalNtWriteFile; +static WindowsDllInterceptor::FuncHookType + gOriginalNtWriteFileGather; +static WindowsDllInterceptor::FuncHookType + gOriginalNtFlushBuffersFile; +static WindowsDllInterceptor::FuncHookType + gOriginalNtQueryFullAttributesFile; static NTSTATUS NTAPI InterposedNtCreateFile(PHANDLE aFileHandle, @@ -448,34 +455,21 @@ InitPoisonIOInterposer() // Initialize dll interceptor and add hooks sNtDllInterceptor.Init("ntdll.dll"); - sNtDllInterceptor.AddHook( - "NtCreateFile", - reinterpret_cast(InterposedNtCreateFile), - reinterpret_cast(&gOriginalNtCreateFile)); - sNtDllInterceptor.AddHook( - "NtReadFile", - reinterpret_cast(InterposedNtReadFile), - reinterpret_cast(&gOriginalNtReadFile)); - sNtDllInterceptor.AddHook( - "NtReadFileScatter", - reinterpret_cast(InterposedNtReadFileScatter), - reinterpret_cast(&gOriginalNtReadFileScatter)); - sNtDllInterceptor.AddHook( - "NtWriteFile", - reinterpret_cast(InterposedNtWriteFile), - reinterpret_cast(&gOriginalNtWriteFile)); - sNtDllInterceptor.AddHook( - "NtWriteFileGather", - reinterpret_cast(InterposedNtWriteFileGather), - reinterpret_cast(&gOriginalNtWriteFileGather)); - sNtDllInterceptor.AddHook( - "NtFlushBuffersFile", - reinterpret_cast(InterposedNtFlushBuffersFile), - reinterpret_cast(&gOriginalNtFlushBuffersFile)); - sNtDllInterceptor.AddHook( - "NtQueryFullAttributesFile", - reinterpret_cast(InterposedNtQueryFullAttributesFile), - reinterpret_cast(&gOriginalNtQueryFullAttributesFile)); + gOriginalNtCreateFile.Set(sNtDllInterceptor, "NtCreateFile", + &InterposedNtCreateFile); + gOriginalNtReadFile.Set(sNtDllInterceptor, "NtReadFile", + &InterposedNtReadFile); + gOriginalNtReadFileScatter.Set(sNtDllInterceptor, "NtReadFileScatter", + &InterposedNtReadFileScatter); + gOriginalNtWriteFile.Set(sNtDllInterceptor, "NtWriteFile", + &InterposedNtWriteFile); + gOriginalNtWriteFileGather.Set(sNtDllInterceptor, "NtWriteFileGather", + &InterposedNtWriteFileGather); + gOriginalNtFlushBuffersFile.Set(sNtDllInterceptor, "NtFlushBuffersFile", + &InterposedNtFlushBuffersFile); + gOriginalNtQueryFullAttributesFile.Set(sNtDllInterceptor, + "NtQueryFullAttributesFile", + &InterposedNtQueryFullAttributesFile); } void From 6cc49d76d950ddf1db3241269461554c253e16d8 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 14:23:29 -0600 Subject: [PATCH 39/57] Bug 1460022: Part 13 - Update profiler to use revised DLL interceptor interface; r=njn --- tools/profiler/core/platform-win32.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/tools/profiler/core/platform-win32.cpp b/tools/profiler/core/platform-win32.cpp index ee17d1a68b73..04a56fbdf133 100644 --- a/tools/profiler/core/platform-win32.cpp +++ b/tools/profiler/core/platform-win32.cpp @@ -303,7 +303,8 @@ Registers::SyncPopulate() static WindowsDllInterceptor NtDllIntercept; typedef NTSTATUS (NTAPI *LdrUnloadDll_func)(HMODULE module); -static LdrUnloadDll_func stub_LdrUnloadDll; +static WindowsDllInterceptor::FuncHookType + stub_LdrUnloadDll; static NTSTATUS NTAPI patched_LdrUnloadDll(HMODULE module) @@ -318,7 +319,8 @@ patched_LdrUnloadDll(HMODULE module) typedef PVOID (WINAPI *LdrResolveDelayLoadedAPI_func)(PVOID ParentModuleBase, PVOID DelayloadDescriptor, PVOID FailureDllHook, PVOID FailureSystemHook, PVOID ThunkAddress, ULONG Flags); -static LdrResolveDelayLoadedAPI_func stub_LdrResolveDelayLoadedAPI; +static WindowsDllInterceptor::FuncHookType + stub_LdrResolveDelayLoadedAPI; static PVOID WINAPI patched_LdrResolveDelayLoadedAPI(PVOID ParentModuleBase, @@ -336,20 +338,12 @@ patched_LdrResolveDelayLoadedAPI(PVOID ParentModuleBase, void InitializeWin64ProfilerHooks() { - static bool initialized = false; - if (initialized) { - return; - } - initialized = true; - NtDllIntercept.Init("ntdll.dll"); - NtDllIntercept.AddHook("LdrUnloadDll", - reinterpret_cast(patched_LdrUnloadDll), - (void**)&stub_LdrUnloadDll); + stub_LdrUnloadDll.Set(NtDllIntercept, "LdrUnloadDll", &patched_LdrUnloadDll); if (IsWin8OrLater()) { // LdrResolveDelayLoadedAPI was introduced in Win8 - NtDllIntercept.AddHook("LdrResolveDelayLoadedAPI", - reinterpret_cast(patched_LdrResolveDelayLoadedAPI), - (void**)&stub_LdrResolveDelayLoadedAPI); + stub_LdrResolveDelayLoadedAPI.Set(NtDllIntercept, + "LdrResolveDelayLoadedAPI", + &patched_LdrResolveDelayLoadedAPI); } } #endif // defined(GP_PLAT_amd64_windows) From 92953ed0367e78e11a92374b39ec97ae2c300422 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Tue, 3 Jul 2018 20:09:37 -0400 Subject: [PATCH 40/57] Bug 1472789 - make the windows crashreporter not dependent on libxul files; r=ted.mielczarek This makes one less place where we link code compiled for libxul into a place that doesn't link mozglue, and is cleaner to boot. We don't need the BREAKPAD_NO_TERMINATE_THREAD define that breakpad-windows-libxul defines because we're not including the handler code in the crashreporter binary. --- .../crashreporter/breakpad-windows-libxul/moz.build | 6 ------ toolkit/crashreporter/client/moz.build | 12 +++++++++++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/toolkit/crashreporter/breakpad-windows-libxul/moz.build b/toolkit/crashreporter/breakpad-windows-libxul/moz.build index 2e52b5adb462..f2521ea015f5 100644 --- a/toolkit/crashreporter/breakpad-windows-libxul/moz.build +++ b/toolkit/crashreporter/breakpad-windows-libxul/moz.build @@ -4,10 +4,6 @@ # 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/. -SOURCES += [ - '../google-breakpad/src/common/windows/http_upload.cc', -] - Library('google_breakpad_libxul_s') FINAL_LIBRARY = 'xul' @@ -22,14 +18,12 @@ LOCAL_INCLUDES += [ include('/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild') include('/toolkit/crashreporter/breakpad-client/windows/handler/objs.mozbuild') -include('/toolkit/crashreporter/breakpad-client/windows/sender/objs.mozbuild') include('/toolkit/crashreporter/breakpad-client/windows/crash_generation/objs.mozbuild') include('/toolkit/crashreporter/breakpad-client/windows/common/objs.mozbuild') SOURCES += objs_common SOURCES += objs_crash_generation SOURCES += objs_handler -SOURCES += objs_sender SOURCES += objs_client_common DisableStlWrapping() diff --git a/toolkit/crashreporter/client/moz.build b/toolkit/crashreporter/client/moz.build index dcf0fddf96a4..55f89ef4ff23 100644 --- a/toolkit/crashreporter/client/moz.build +++ b/toolkit/crashreporter/client/moz.build @@ -24,10 +24,20 @@ if CONFIG['OS_ARCH'] == 'WINNT': UNIFIED_SOURCES += [ 'crashreporter_win.cpp', ] + include('/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild') + include('/toolkit/crashreporter/breakpad-client/windows/sender/objs.mozbuild') + include('/toolkit/crashreporter/breakpad-client/windows/crash_generation/objs.mozbuild') + include('/toolkit/crashreporter/breakpad-client/windows/common/objs.mozbuild') + SOURCES += objs_common + SOURCES += objs_sender + SOURCES += objs_crash_generation + SOURCES += objs_client_common + SOURCES += [ + '../google-breakpad/src/common/windows/http_upload.cc', + ] DEFINES['UNICODE'] = True DEFINES['_UNICODE'] = True USE_LIBS += [ - 'google_breakpad_libxul_s', 'nss', ] OS_LIBS += [ From f4b28212c5d45d3bcc25cf84022203c29cd5ebab Mon Sep 17 00:00:00 2001 From: Dragana Damjanovic Date: Tue, 3 Jul 2018 20:18:12 -0400 Subject: [PATCH 41/57] Bug 1468523 - Fix the history entry for http-equiv=refresh. r=smaug --- docshell/base/nsDocShell.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 5c4ea1257df7..ea211bd85f89 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -6219,6 +6219,8 @@ nsDocShell::ForceRefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal, int32_t aDel */ loadInfo->SetReferrer(mCurrentURI); + loadInfo->SetOriginalURI(mCurrentURI); + // Set the triggering pricipal to aPrincipal if available, or current // document's principal otherwise. nsCOMPtr principal = aPrincipal; From dd50d1646ecea7866f24c9bca2215dfbffe1f2b6 Mon Sep 17 00:00:00 2001 From: shindli Date: Wed, 4 Jul 2018 03:37:11 +0300 Subject: [PATCH 42/57] Backed out 13 changesets (bug 1460022) for bustages in :/build/build/src/mozglue/tests/interceptor/TestDllInterceptor.cpp(113) on a CLOSED TREE Backed out changeset b798c3689bbf (bug 1460022) Backed out changeset c3b3b854affd (bug 1460022) Backed out changeset ecb1b6fd3134 (bug 1460022) Backed out changeset 91fed649dd5a (bug 1460022) Backed out changeset be7032cddad2 (bug 1460022) Backed out changeset d4a036b976e6 (bug 1460022) Backed out changeset 5f3dfde41e38 (bug 1460022) Backed out changeset a16486a6f685 (bug 1460022) Backed out changeset 69eacc5c3ab8 (bug 1460022) Backed out changeset 34aa7c29b31e (bug 1460022) Backed out changeset 00b20c0a7637 (bug 1460022) Backed out changeset b8e8aea4a01f (bug 1460022) Backed out changeset 15822d9848d8 (bug 1460022) --- accessible/windows/msaa/Compatibility.cpp | 11 +- browser/app/winlauncher/DllBlocklistWin.cpp | 8 +- dom/media/gmp/ChromiumCDMAdapter.cpp | 8 +- dom/plugins/base/nsPluginNativeWindowWin.cpp | 36 +- dom/plugins/ipc/FunctionHook.cpp | 21 +- dom/plugins/ipc/FunctionHook.h | 27 +- dom/plugins/ipc/PluginInstanceChild.cpp | 97 +- mozglue/build/WindowsDllBlocklist.cpp | 21 +- mozglue/misc/nsWindowsDllInterceptor.h | 153 +--- .../tests/interceptor/TestDllInterceptor.cpp | 854 +++++++++++------- .../TestDllInterceptorCrossProcess.cpp | 12 +- .../sandbox/win/SandboxInitialization.cpp | 14 +- toolkit/crashreporter/nsExceptionHandler.cpp | 9 +- tools/profiler/core/platform-win32.cpp | 22 +- widget/windows/nsWindow.cpp | 46 +- xpcom/base/AvailableMemoryTracker.cpp | 27 +- xpcom/build/PoisonIOInterposerWin.cpp | 64 +- 17 files changed, 770 insertions(+), 660 deletions(-) diff --git a/accessible/windows/msaa/Compatibility.cpp b/accessible/windows/msaa/Compatibility.cpp index f4434f37c0b5..6446f19805c0 100644 --- a/accessible/windows/msaa/Compatibility.cpp +++ b/accessible/windows/msaa/Compatibility.cpp @@ -95,8 +95,7 @@ Compatibility::IsModuleVersionLessThan(HMODULE aModuleHandle, //////////////////////////////////////////////////////////////////////////////// static WindowsDllInterceptor sUser32Interceptor; -static WindowsDllInterceptor::FuncHookType - sInSendMessageExStub; +static decltype(&InSendMessageEx) sInSendMessageExStub = nullptr; static bool sInSendMessageExHackEnabled = false; static PVOID sVectoredExceptionHandler = nullptr; @@ -268,9 +267,11 @@ Compatibility::Init() if ((sConsumers & (~(UIAUTOMATION | NVDA))) && BrowserTabsRemoteAutostart()) { sUser32Interceptor.Init("user32.dll"); - sInSendMessageExStub.Set(sUser32Interceptor, "InSendMessageEx", - &InSendMessageExHook); - + if (!sInSendMessageExStub) { + sUser32Interceptor.AddHook("InSendMessageEx", + reinterpret_cast(&InSendMessageExHook), + (void**)&sInSendMessageExStub); + } // The vectored exception handler allows us to catch exceptions ahead of any // SEH handlers. if (!sVectoredExceptionHandler) { diff --git a/browser/app/winlauncher/DllBlocklistWin.cpp b/browser/app/winlauncher/DllBlocklistWin.cpp index a88a0747348f..82e1d77d3722 100644 --- a/browser/app/winlauncher/DllBlocklistWin.cpp +++ b/browser/app/winlauncher/DllBlocklistWin.cpp @@ -246,8 +246,7 @@ IsDllAllowed(const UNICODE_STRING& aLeafName, void* aBaseAddress) } typedef decltype(&NtMapViewOfSection) NtMapViewOfSection_func; -static mozilla::CrossProcessDllInterceptor::FuncHookType - stub_NtMapViewOfSection; +static NtMapViewOfSection_func stub_NtMapViewOfSection; static NTSTATUS NTAPI patched_NtMapViewOfSection(HANDLE aSection, HANDLE aProcess, PVOID* aBaseAddress, @@ -357,8 +356,9 @@ InitializeDllBlocklistOOP(HANDLE aChildProcess) { mozilla::CrossProcessDllInterceptor intcpt(aChildProcess); intcpt.Init(L"ntdll.dll"); - bool ok = stub_NtMapViewOfSection.SetDetour(intcpt, "NtMapViewOfSection", - &patched_NtMapViewOfSection); + bool ok = intcpt.AddDetour("NtMapViewOfSection", + reinterpret_cast(&patched_NtMapViewOfSection), + (void**) &stub_NtMapViewOfSection); if (!ok) { return false; } diff --git a/dom/media/gmp/ChromiumCDMAdapter.cpp b/dom/media/gmp/ChromiumCDMAdapter.cpp index e1946dee5106..b8fbe7a2f9da 100644 --- a/dom/media/gmp/ChromiumCDMAdapter.cpp +++ b/dom/media/gmp/ChromiumCDMAdapter.cpp @@ -197,8 +197,7 @@ typedef DWORD(WINAPI* QueryDosDeviceWFnPtr)(_In_opt_ LPCWSTR lpDeviceName, _Out_ LPWSTR lpTargetPath, _In_ DWORD ucchMax); -static WindowsDllInterceptor::FuncHookType - sOriginalQueryDosDeviceWFnPtr; +static QueryDosDeviceWFnPtr sOriginalQueryDosDeviceWFnPtr = nullptr; static std::unordered_map* sDeviceNames = nullptr; @@ -277,8 +276,9 @@ InitializeHooks() } sKernel32Intercept.Init("kernelbase.dll"); - sOriginalQueryDosDeviceWFnPtr.Set(sKernel32Intercept, "QueryDosDeviceW", - &QueryDosDeviceWHook); + sKernel32Intercept.AddHook("QueryDosDeviceW", + reinterpret_cast(QueryDosDeviceWHook), + (void**)(&sOriginalQueryDosDeviceWFnPtr)); } #endif diff --git a/dom/plugins/base/nsPluginNativeWindowWin.cpp b/dom/plugins/base/nsPluginNativeWindowWin.cpp index 570b99e52610..fc7f0ea72345 100644 --- a/dom/plugins/base/nsPluginNativeWindowWin.cpp +++ b/dom/plugins/base/nsPluginNativeWindowWin.cpp @@ -357,10 +357,8 @@ typedef LONG_PTR (WINAPI *User32SetWindowLongPtrW)(HWND hWnd, int nIndex, LONG_PTR dwNewLong); -static WindowsDllInterceptor::FuncHookType - sUser32SetWindowLongAHookStub; -static WindowsDllInterceptor::FuncHookType - sUser32SetWindowLongWHookStub; +static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = nullptr; +static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = nullptr; #else typedef LONG (WINAPI *User32SetWindowLongA)(HWND hWnd, @@ -370,10 +368,8 @@ typedef LONG (WINAPI *User32SetWindowLongW)(HWND hWnd, int nIndex, LONG dwNewLong); -static WindowsDllInterceptor::FuncHookType - sUser32SetWindowLongAHookStub; -static WindowsDllInterceptor::FuncHookType - sUser32SetWindowLongWHookStub; +static User32SetWindowLongA sUser32SetWindowLongAHookStub = nullptr; +static User32SetWindowLongW sUser32SetWindowLongWHookStub = nullptr; #endif static inline bool SetWindowLongHookCheck(HWND hWnd, @@ -452,15 +448,23 @@ HookSetWindowLongPtr() { sUser32Intercept.Init("user32.dll"); #ifdef _WIN64 - sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongPtrA", - &SetWindowLongPtrAHook); - sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongPtrW", - &SetWindowLongPtrWHook); + if (!sUser32SetWindowLongAHookStub) + sUser32Intercept.AddHook("SetWindowLongPtrA", + reinterpret_cast(SetWindowLongPtrAHook), + (void**) &sUser32SetWindowLongAHookStub); + if (!sUser32SetWindowLongWHookStub) + sUser32Intercept.AddHook("SetWindowLongPtrW", + reinterpret_cast(SetWindowLongPtrWHook), + (void**) &sUser32SetWindowLongWHookStub); #else - sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongA", - &SetWindowLongAHook); - sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongW", - &SetWindowLongWHook); + if (!sUser32SetWindowLongAHookStub) + sUser32Intercept.AddHook("SetWindowLongA", + reinterpret_cast(SetWindowLongAHook), + (void**) &sUser32SetWindowLongAHookStub); + if (!sUser32SetWindowLongWHookStub) + sUser32Intercept.AddHook("SetWindowLongW", + reinterpret_cast(SetWindowLongWHook), + (void**) &sUser32SetWindowLongWHookStub); #endif } diff --git a/dom/plugins/ipc/FunctionHook.cpp b/dom/plugins/ipc/FunctionHook.cpp index 3d4733a19277..d5e29ec14f18 100644 --- a/dom/plugins/ipc/FunctionHook.cpp +++ b/dom/plugins/ipc/FunctionHook.cpp @@ -168,13 +168,13 @@ typedef HANDLE (WINAPI *CreateFileWPtr)(LPCWSTR aFname, DWORD aAccess, LPSECURITY_ATTRIBUTES aSecurity, DWORD aCreation, DWORD aFlags, HANDLE aFTemplate); -static WindowsDllInterceptor::FuncHookType sCreateFileWStub; +static CreateFileWPtr sCreateFileWStub = nullptr; typedef HANDLE (WINAPI *CreateFileAPtr)(LPCSTR aFname, DWORD aAccess, DWORD aShare, LPSECURITY_ATTRIBUTES aSecurity, DWORD aCreation, DWORD aFlags, HANDLE aFTemplate); -static WindowsDllInterceptor::FuncHookType sCreateFileAStub; +static CreateFileAPtr sCreateFileAStub = nullptr; // Windows 8 RTM (kernelbase's version is 6.2.9200.16384) doesn't call // CreateFileW from CreateFileA. @@ -263,7 +263,7 @@ CreateFileWHookFn(LPCWSTR aFname, DWORD aAccess, DWORD aShare, aSecurity, TRUNCATE_EXISTING, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, - nullptr); + NULL); if (replacement == INVALID_HANDLE_VALUE) { break; } @@ -300,12 +300,23 @@ CreateFileWHookFn(LPCWSTR aFname, DWORD aAccess, DWORD aShare, void FunctionHook::HookProtectedMode() { + // Make sure we only do this once. + static bool sRunOnce = false; + if (sRunOnce) { + return; + } + sRunOnce = true; + // Legacy code. Uses the nsWindowsDLLInterceptor directly instead of // using the FunctionHook sKernel32Intercept.Init("kernel32.dll"); MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Plugin); - sCreateFileWStub.Set(sKernel32Intercept, "CreateFileW", &CreateFileWHookFn); - sCreateFileAStub.Set(sKernel32Intercept, "CreateFileA", &CreateFileAHookFn); + sKernel32Intercept.AddHook("CreateFileW", + reinterpret_cast(CreateFileWHookFn), + (void**) &sCreateFileWStub); + sKernel32Intercept.AddHook("CreateFileA", + reinterpret_cast(CreateFileAHookFn), + (void**) &sCreateFileAStub); } #endif // defined(XP_WIN) diff --git a/dom/plugins/ipc/FunctionHook.h b/dom/plugins/ipc/FunctionHook.h index 06baf6acdad8..c9b30dd0643a 100644 --- a/dom/plugins/ipc/FunctionHook.h +++ b/dom/plugins/ipc/FunctionHook.h @@ -9,7 +9,6 @@ #include "IpdlTuple.h" #include "base/process.h" -#include "mozilla/Atomics.h" #if defined(XP_WIN) #include "nsWindowsDllInterceptor.h" @@ -97,19 +96,12 @@ typedef bool(ShouldHookFunc)(int aQuirks); template class BasicFunctionHook : public FunctionHook { -#if defined(XP_WIN) - using FuncHookType = WindowsDllInterceptor::FuncHookType; -#endif // defined(XP_WIN) - public: BasicFunctionHook(const char* aModuleName, const char* aFunctionName, FunctionType* aOldFunction, - FunctionType* aNewFunction) - : mOldFunction(aOldFunction) - , mRegistration(UNREGISTERED) - , mModuleName(aModuleName) - , mFunctionName(aFunctionName) - , mNewFunction(aNewFunction) + FunctionType* aNewFunction) : + mOldFunction(aOldFunction), mRegistration(UNREGISTERED), mModuleName(aModuleName), + mFunctionName(aFunctionName), mNewFunction(aNewFunction) { MOZ_ASSERT(mOldFunction); MOZ_ASSERT(mNewFunction); @@ -136,10 +128,7 @@ protected: // Once the function is hooked, this field will take the value of a pointer to // a function that performs the old behavior. Before that, it is a pointer to // the original function. - Atomic mOldFunction; -#if defined(XP_WIN) - FuncHookType mStub; -#endif // defined(XP_WIN) + FunctionType* mOldFunction; enum RegistrationStatus { UNREGISTERED, FAILED, SUCCEEDED }; RegistrationStatus mRegistration; @@ -181,16 +170,14 @@ BasicFunctionHook::Register(int aQuirks) return false; } - isHooked = mStub.Set(*dllInterceptor, mFunctionName.Data(), mNewFunction); + isHooked = + dllInterceptor->AddHook(mFunctionName.Data(), reinterpret_cast(mNewFunction), + reinterpret_cast(&mOldFunction)); #endif if (isHooked) { -#if defined(XP_WIN) - mOldFunction = mStub.GetStub(); -#endif mRegistration = SUCCEEDED; } - HOOK_LOG(LogLevel::Debug, ("Registering to intercept function '%s' : '%s'", mFunctionName.Data(), SuccessMsg(isHooked))); diff --git a/dom/plugins/ipc/PluginInstanceChild.cpp b/dom/plugins/ipc/PluginInstanceChild.cpp index bab3067be6ee..47e779a6072c 100644 --- a/dom/plugins/ipc/PluginInstanceChild.cpp +++ b/dom/plugins/ipc/PluginInstanceChild.cpp @@ -73,17 +73,21 @@ typedef BOOL (WINAPI *User32TrackPopupMenu)(HMENU hMenu, CONST RECT *prcRect); static WindowsDllInterceptor sUser32Intercept; static HWND sWinlessPopupSurrogateHWND = nullptr; -static WindowsDllInterceptor::FuncHookType sUser32TrackPopupMenuStub; +static User32TrackPopupMenu sUser32TrackPopupMenuStub = nullptr; static WindowsDllInterceptor sImm32Intercept; -static WindowsDllInterceptor::FuncHookType sImm32ImmGetContextStub; -static WindowsDllInterceptor::FuncHookType sImm32ImmGetCompositionStringStub; -static WindowsDllInterceptor::FuncHookType sImm32ImmSetCandidateWindowStub; -static WindowsDllInterceptor::FuncHookType sImm32ImmNotifyIME; -static WindowsDllInterceptor::FuncHookType sImm32ImmAssociateContextExStub; - +static decltype(ImmGetContext)* sImm32ImmGetContextStub = nullptr; +static decltype(ImmGetCompositionStringW)* sImm32ImmGetCompositionStringStub = + nullptr; +static decltype(ImmSetCandidateWindow)* sImm32ImmSetCandidateWindowStub = + nullptr; +static decltype(ImmNotifyIME)* sImm32ImmNotifyIME = nullptr; +static decltype(ImmAssociateContextEx)* sImm32ImmAssociateContextExStub = + nullptr; static PluginInstanceChild* sCurrentPluginInstance = nullptr; static const HIMC sHookIMC = (const HIMC)0xefefefef; +static bool sPopupMenuHookSet; +static bool sSetWindowLongHookSet; using mozilla::gfx::SharedDIB; @@ -1789,8 +1793,8 @@ typedef LONG_PTR (WINAPI *User32SetWindowLongPtrW)(HWND hWnd, int nIndex, LONG_PTR dwNewLong); -static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongAHookStub; -static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongWHookStub; +static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = nullptr; +static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = nullptr; #else typedef LONG (WINAPI *User32SetWindowLongA)(HWND hWnd, @@ -1800,8 +1804,8 @@ typedef LONG (WINAPI *User32SetWindowLongW)(HWND hWnd, int nIndex, LONG dwNewLong); -static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongAHookStub; -static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongWHookStub; +static User32SetWindowLongA sUser32SetWindowLongAHookStub = nullptr; +static User32SetWindowLongW sUser32SetWindowLongWHookStub = nullptr; #endif extern LRESULT CALLBACK @@ -1911,17 +1915,27 @@ PluginInstanceChild::HookSetWindowLongPtr() return; } + // Only pass through here once + if (sSetWindowLongHookSet) { + return; + } + sSetWindowLongHookSet = true; + sUser32Intercept.Init("user32.dll"); #ifdef _WIN64 - sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongPtrA", - &SetWindowLongPtrAHook); - sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongPtrW", - &SetWindowLongPtrWHook); + if (!sUser32SetWindowLongAHookStub) + sUser32Intercept.AddHook("SetWindowLongPtrA", reinterpret_cast(SetWindowLongPtrAHook), + (void**) &sUser32SetWindowLongAHookStub); + if (!sUser32SetWindowLongWHookStub) + sUser32Intercept.AddHook("SetWindowLongPtrW", reinterpret_cast(SetWindowLongPtrWHook), + (void**) &sUser32SetWindowLongWHookStub); #else - sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongA", - &SetWindowLongAHook); - sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongW", - &SetWindowLongWHook); + if (!sUser32SetWindowLongAHookStub) + sUser32Intercept.AddHook("SetWindowLongA", reinterpret_cast(SetWindowLongAHook), + (void**) &sUser32SetWindowLongAHookStub); + if (!sUser32SetWindowLongWHookStub) + sUser32Intercept.AddHook("SetWindowLongW", reinterpret_cast(SetWindowLongWHook), + (void**) &sUser32SetWindowLongWHookStub); #endif } @@ -1989,13 +2003,19 @@ PluginInstanceChild::InitPopupMenuHook() return; } + // Only pass through here once + if (sPopupMenuHookSet) { + return; + } + sPopupMenuHookSet = true; + // Note, once WindowsDllInterceptor is initialized for a module, // it remains initialized for that particular module for it's // lifetime. Additional instances are needed if other modules need // to be hooked. sUser32Intercept.Init("user32.dll"); - sUser32TrackPopupMenuStub.Set(sUser32Intercept, "TrackPopupMenu", - &TrackPopupHookProc); + sUser32Intercept.AddHook("TrackPopupMenu", reinterpret_cast(TrackPopupHookProc), + (void**) &sUser32TrackPopupMenuStub); } void @@ -2137,23 +2157,36 @@ PluginInstanceChild::InitImm32Hook() return; } + if (sImm32ImmGetContextStub) { + return; + } + // When using windowless plugin, IMM API won't work due ot OOP. // // ImmReleaseContext on Windows 7+ just returns TRUE only, so we don't // need to hook this. sImm32Intercept.Init("imm32.dll"); - sImm32ImmGetContextStub.Set(sImm32Intercept, "ImmGetContext", - &ImmGetContextProc); - sImm32ImmGetCompositionStringStub.Set(sImm32Intercept, - "ImmGetCompositionStringW", - &ImmGetCompositionStringProc); - sImm32ImmSetCandidateWindowStub.Set(sImm32Intercept, - "ImmSetCandidateWindow", - &ImmSetCandidateWindowProc); - sImm32ImmNotifyIME.Set(sImm32Intercept, "ImmNotifyIME", &ImmNotifyIME); - sImm32ImmAssociateContextExStub.Set(sImm32Intercept, "ImmAssociateContextEx", - &ImmAssociateContextExProc); + sImm32Intercept.AddHook( + "ImmGetContext", + reinterpret_cast(ImmGetContextProc), + (void**)&sImm32ImmGetContextStub); + sImm32Intercept.AddHook( + "ImmGetCompositionStringW", + reinterpret_cast(ImmGetCompositionStringProc), + (void**)&sImm32ImmGetCompositionStringStub); + sImm32Intercept.AddHook( + "ImmSetCandidateWindow", + reinterpret_cast(ImmSetCandidateWindowProc), + (void**)&sImm32ImmSetCandidateWindowStub); + sImm32Intercept.AddHook( + "ImmNotifyIME", + reinterpret_cast(ImmNotifyIME), + (void**)&sImm32ImmNotifyIME); + sImm32Intercept.AddHook( + "ImmAssociateContextEx", + reinterpret_cast(ImmAssociateContextExProc), + (void**)&sImm32ImmAssociateContextExStub); } void diff --git a/mozglue/build/WindowsDllBlocklist.cpp b/mozglue/build/WindowsDllBlocklist.cpp index 4b7a6f7ecf6a..6071e4241986 100644 --- a/mozglue/build/WindowsDllBlocklist.cpp +++ b/mozglue/build/WindowsDllBlocklist.cpp @@ -90,14 +90,14 @@ printf_stderr(const char *fmt, ...) typedef MOZ_NORETURN_PTR void (__fastcall* BaseThreadInitThunk_func)(BOOL aIsInitialThread, void* aStartAddress, void* aThreadParam); -static WindowsDllInterceptor::FuncHookType stub_BaseThreadInitThunk; +static BaseThreadInitThunk_func stub_BaseThreadInitThunk = nullptr; typedef NTSTATUS (NTAPI *LdrLoadDll_func) (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle); -static WindowsDllInterceptor::FuncHookType stub_LdrLoadDll; +static LdrLoadDll_func stub_LdrLoadDll; #ifdef _M_AMD64 typedef decltype(RtlInstallFunctionTableCallback)* RtlInstallFunctionTableCallback_func; -static WindowsDllInterceptor::FuncHookType stub_RtlInstallFunctionTableCallback; +static RtlInstallFunctionTableCallback_func stub_RtlInstallFunctionTableCallback; extern uint8_t* sMsMpegJitCodeRegionStart; extern size_t sMsMpegJitCodeRegionSize; @@ -662,8 +662,7 @@ DllBlocklist_Initialize(uint32_t aInitFlags) // We specifically use a detour, because there are cases where external // code also tries to hook LdrLoadDll, and doesn't know how to relocate our // nop space patches. (Bug 951827) - bool ok = stub_LdrLoadDll.SetDetour(NtDllIntercept, "LdrLoadDll", - &patched_LdrLoadDll); + bool ok = NtDllIntercept.AddDetour("LdrLoadDll", reinterpret_cast(patched_LdrLoadDll), (void**) &stub_LdrLoadDll); if (!ok) { sBlocklistInitFailed = true; @@ -684,18 +683,18 @@ DllBlocklist_Initialize(uint32_t aInitFlags) #ifdef _M_AMD64 if (!IsWin8OrLater()) { // The crash that this hook works around is only seen on Win7. - stub_RtlInstallFunctionTableCallback.Set(Kernel32Intercept, - "RtlInstallFunctionTableCallback", - &patched_RtlInstallFunctionTableCallback); + Kernel32Intercept.AddHook("RtlInstallFunctionTableCallback", + reinterpret_cast(patched_RtlInstallFunctionTableCallback), + (void**)&stub_RtlInstallFunctionTableCallback); } #endif // Bug 1361410: WRusr.dll will overwrite our hook and cause a crash. // Workaround: If we detect WRusr.dll, don't hook. if (!GetModuleHandleW(L"WRusr.dll")) { - if (!stub_BaseThreadInitThunk.SetDetour(Kernel32Intercept, - "BaseThreadInitThunk", - &patched_BaseThreadInitThunk)) { + if(!Kernel32Intercept.AddDetour("BaseThreadInitThunk", + reinterpret_cast(patched_BaseThreadInitThunk), + (void**) &stub_BaseThreadInitThunk)) { #ifdef DEBUG printf_stderr("BaseThreadInitThunk hook failed\n"); #endif diff --git a/mozglue/misc/nsWindowsDllInterceptor.h b/mozglue/misc/nsWindowsDllInterceptor.h index 4ae504257b56..3020f795fede 100644 --- a/mozglue/misc/nsWindowsDllInterceptor.h +++ b/mozglue/misc/nsWindowsDllInterceptor.h @@ -8,12 +8,10 @@ #define NS_WINDOWS_DLL_INTERCEPTOR_H_ #include "mozilla/Assertions.h" -#include "mozilla/Attributes.h" #include "mozilla/ArrayUtils.h" #include "mozilla/CheckedInt.h" #include "mozilla/DebugOnly.h" -#include "mozilla/Move.h" -#include "mozilla/Tuple.h" +#include "mozilla/NotNull.h" #include "mozilla/TypeTraits.h" #include "mozilla/Types.h" #include "mozilla/UniquePtr.h" @@ -84,143 +82,6 @@ namespace mozilla { namespace interceptor { -template -class FuncHook final -{ - template - struct OriginalFunctionPtrTraits; - - template - struct OriginalFunctionPtrTraits - { - using ReturnType = R; - }; - -#if defined(_M_IX86) - template - struct OriginalFunctionPtrTraits - { - using ReturnType = R; - }; - - template - struct OriginalFunctionPtrTraits - { - using ReturnType = R; - }; -#endif // defined(_M_IX86) - -public: - using ThisType = FuncHook; - using ReturnType = typename OriginalFunctionPtrTraits::ReturnType; - - constexpr FuncHook() - : mOrigFunc(nullptr) - , mInitOnce(INIT_ONCE_STATIC_INIT) - { - } - - ~FuncHook() = default; - - bool Set(InterceptorT& aInterceptor, const char* aName, - FuncPtrT aHookDest) - { - LPVOID addHookOk; - InitOnceContext ctx(this, &aInterceptor, aName, aHookDest, false); - - return ::InitOnceExecuteOnce(&mInitOnce, &InitOnceCallback, &ctx, - &addHookOk) && addHookOk; - } - - bool SetDetour(InterceptorT& aInterceptor, const char* aName, - FuncPtrT aHookDest) - { - LPVOID addHookOk; - InitOnceContext ctx(this, &aInterceptor, aName, aHookDest, true); - - return ::InitOnceExecuteOnce(&mInitOnce, &InitOnceCallback, &ctx, - &addHookOk) && addHookOk; - } - - explicit operator bool() const - { - return !!mOrigFunc; - } - - template - ReturnType operator()(ArgsType... aArgs) const - { - return mOrigFunc(std::forward(aArgs)...); - } - - FuncPtrT GetStub() const - { - return mOrigFunc; - } - - // One-time init stuff cannot be moved or copied - FuncHook(const FuncHook&) = delete; - FuncHook(FuncHook&&) = delete; - FuncHook& operator=(const FuncHook&) = delete; - FuncHook& operator=(FuncHook&& aOther) = delete; - -private: - struct MOZ_RAII InitOnceContext final - { - InitOnceContext(ThisType* aHook, InterceptorT* aInterceptor, - const char* aName, void* aHookDest, bool aForceDetour) - : mHook(aHook) - , mInterceptor(aInterceptor) - , mName(aName) - , mHookDest(aHookDest) - , mForceDetour(aForceDetour) - { - } - - ThisType* mHook; - InterceptorT* mInterceptor; - const char* mName; - void* mHookDest; - bool mForceDetour; - }; - -private: - bool Apply(InterceptorT* aInterceptor, const char* aName, void* aHookDest) - { - return aInterceptor->AddHook(aName, reinterpret_cast(aHookDest), - reinterpret_cast(&mOrigFunc)); - } - - bool ApplyDetour(InterceptorT* aInterceptor, const char* aName, - void* aHookDest) - { - return aInterceptor->AddDetour(aName, reinterpret_cast(aHookDest), - reinterpret_cast(&mOrigFunc)); - } - - static BOOL CALLBACK - InitOnceCallback(PINIT_ONCE aInitOnce, PVOID aParam, PVOID* aOutContext) - { - MOZ_ASSERT(aOutContext); - - bool result; - auto ctx = reinterpret_cast(aParam); - if (ctx->mForceDetour) { - result = ctx->mHook->ApplyDetour(ctx->mInterceptor, ctx->mName, - ctx->mHookDest); - } else { - result = ctx->mHook->Apply(ctx->mInterceptor, ctx->mName, ctx->mHookDest); - } - - *aOutContext = result ? reinterpret_cast(1U << INIT_ONCE_CTX_RESERVED_BITS) : nullptr; - return TRUE; - } - -private: - FuncPtrT mOrigFunc; - INIT_ONCE mInitOnce; -}; - enum { kDefaultTrampolineSize = 128 @@ -231,8 +92,6 @@ template > class WindowsDllInterceptor final { - typedef WindowsDllInterceptor ThisType; - interceptor::WindowsDllDetourPatcher mDetourPatcher; #if defined(_M_IX86) interceptor::WindowsDllNopSpacePatcher mNopSpacePatcher; @@ -301,7 +160,6 @@ public: // NB: We intentionally leak mModule } -private: /** * Hook/detour the method aName from the DLL we set in Init so that it calls * aHookDest instead. Returns the original method pointer in aOrigFunc @@ -361,6 +219,7 @@ private: return AddDetour(proc, aHookDest, aOrigFunc); } +private: bool AddDetour(FARPROC aProc, intptr_t aHookDest, void** aOrigFunc) { MOZ_ASSERT(mModule && aProc); @@ -371,14 +230,6 @@ private: return mDetourPatcher.AddHook(aProc, aHookDest, aOrigFunc); } - -public: - template - using FuncHookType = FuncHook; - -private: - template - friend class FuncHook; }; } // namespace interceptor diff --git a/mozglue/tests/interceptor/TestDllInterceptor.cpp b/mozglue/tests/interceptor/TestDllInterceptor.cpp index 729501f37147..6007a8995201 100644 --- a/mozglue/tests/interceptor/TestDllInterceptor.cpp +++ b/mozglue/tests/interceptor/TestDllInterceptor.cpp @@ -10,33 +10,10 @@ #include #include -#include "mozilla/TypeTraits.h" -#include "mozilla/UniquePtr.h" #include "mozilla/WindowsVersion.h" #include "nsWindowsDllInterceptor.h" #include "nsWindowsHelpers.h" -NTSTATUS NTAPI NtFlushBuffersFile(HANDLE, PIO_STATUS_BLOCK); -NTSTATUS NTAPI NtReadFile(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PVOID, ULONG, - PLARGE_INTEGER, PULONG); -NTSTATUS NTAPI NtReadFileScatter(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, - PLARGE_INTEGER, PULONG); -NTSTATUS NTAPI NtWriteFile(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PVOID, ULONG, - PLARGE_INTEGER, PULONG); -NTSTATUS NTAPI NtWriteFileGather(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, - PLARGE_INTEGER, PULONG); -NTSTATUS NTAPI NtQueryFullAttributesFile(POBJECT_ATTRIBUTES, PVOID); -NTSTATUS NTAPI LdrLoadDll(PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle); -NTSTATUS NTAPI LdrUnloadDll(HMODULE); -// These pointers are disguised as PVOID to avoid pulling in obscure headers -PVOID NTAPI LdrResolveDelayLoadedAPI(PVOID, PVOID, PVOID, PVOID, PVOID, ULONG); -void CALLBACK ProcessCaretEvents(HWINEVENTHOOK, DWORD, HWND, LONG, LONG, DWORD, DWORD); -void __fastcall BaseThreadInitThunk(BOOL aIsInitialThread, void* aStartAddress, void* aThreadParam); - using namespace mozilla; struct payload { @@ -61,8 +38,7 @@ extern "C" __declspec(dllexport) __declspec(noinline) payload rotatePayload(payl static bool patched_func_called = false; -static WindowsDllInterceptor::FuncHookType - orig_rotatePayload; +static payload (*orig_rotatePayload)(payload); static payload patched_rotatePayload(payload p) @@ -71,58 +47,11 @@ patched_rotatePayload(payload p) return orig_rotatePayload(p); } -// Invoke aFunc by taking aArg's contents and using them as aFunc's arguments -template , size_t... Indices> -decltype(auto) Apply(CallableT&& aFunc, ArgTuple&& aArgs, std::index_sequence) +typedef bool(*HookTestFunc)(void*); +bool CheckHook(HookTestFunc aHookTestFunc, void* aOrigFunc, + const char* aDllName, const char* aFuncName) { - return std::forward(aFunc)(Get(std::forward(aArgs))...); -} - -template -bool TestFunction(CallableT aFunc); - -#define DEFINE_TEST_FUNCTION(calling_convention) \ - template \ - bool TestFunction(WindowsDllInterceptor::FuncHookType&& aFunc, \ - bool (* aPred)(R), TestArgs... aArgs) \ - { \ - using FuncHookType = WindowsDllInterceptor::FuncHookType; \ - using ArgTuple = Tuple; \ - using Indices = std::index_sequence_for; \ - ArgTuple fakeArgs{ std::forward(aArgs)... }; \ - return aPred(Apply(std::forward(aFunc), std::forward(fakeArgs), Indices())); \ - } \ - \ - /* Specialization for functions returning void */ \ - template \ - bool TestFunction(WindowsDllInterceptor::FuncHookType&& aFunc, \ - PredicateT&& aPred, TestArgs... aArgs) \ - { \ - using FuncHookType = WindowsDllInterceptor::FuncHookType; \ - using ArgTuple = Tuple; \ - using Indices = std::index_sequence_for; \ - ArgTuple fakeArgs{ std::forward(aArgs)... }; \ - Apply(std::forward(aFunc), std::forward(fakeArgs), Indices()); \ - return true; \ - } - -// C++11 allows empty arguments to macros. clang works just fine. MSVC does the -// right thing, but it also throws up warning C4003. We'll suppress that -// behavior here. -#pragma warning(suppress: 4003) -DEFINE_TEST_FUNCTION() -#ifdef _M_IX86 -DEFINE_TEST_FUNCTION(__stdcall) -DEFINE_TEST_FUNCTION(__fastcall) -#endif // _M_IX86 - -// Test the hooked function against the supplied predicate -template -bool CheckHook(WindowsDllInterceptor::FuncHookType &aOrigFunc, - const char* aDllName, const char* aFuncName, PredicateT&& aPred, - Args... aArgs) -{ - if (TestFunction(std::forward>(aOrigFunc), std::forward(aPred), std::forward(aArgs)...)) { + if (aHookTestFunc(aOrigFunc)) { printf("TEST-PASS | WindowsDllInterceptor | " "Executed hooked function %s from %s\n", aFuncName, aDllName); return true; @@ -132,235 +61,57 @@ bool CheckHook(WindowsDllInterceptor::FuncHookType &aOrigFunc, return false; } -// Hook the function and optionally attempt calling it -template -bool TestHook(const char (&dll)[N], const char *func, PredicateT&& aPred, Args... aArgs) +template +bool TestHook(HookTestFunc funcTester, const char (&dll)[N], const char *func) { - auto orig_func(mozilla::MakeUnique>()); - + void *orig_func; bool successful = false; { WindowsDllInterceptor TestIntercept; TestIntercept.Init(dll); - successful = orig_func->Set(TestIntercept, func, nullptr); + successful = TestIntercept.AddHook(func, 0, &orig_func); } if (successful) { printf("TEST-PASS | WindowsDllInterceptor | Could hook %s from %s\n", func, dll); - if (!aPred) { - printf("TEST-SKIPPED | WindowsDllInterceptor | " - "Will not attempt to execute patched %s.\n", func); - return true; - } - - return CheckHook(*orig_func, dll, func, std::forward(aPred), std::forward(aArgs)...); + return CheckHook(funcTester, orig_func, dll, func); } else { printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to hook %s from %s\n", func, dll); return false; } } -// Detour the function and optionally attempt calling it -template -bool TestDetour(const char (&dll)[N], const char *func, PredicateT&& aPred) +template +bool TestDetour(const char (&dll)[N], const char *func) { - auto orig_func(mozilla::MakeUnique>()); - + void *orig_func; bool successful = false; { WindowsDllInterceptor TestIntercept; TestIntercept.Init(dll); - successful = orig_func->SetDetour(TestIntercept, func, nullptr); + successful = TestIntercept.AddDetour(func, 0, &orig_func); } if (successful) { printf("TEST-PASS | WindowsDllInterceptor | Could detour %s from %s\n", func, dll); - if (!aPred) { - printf("TEST-SKIPPED | WindowsDllInterceptor | " - "Will not attempt to execute patched %s.\n", func); - return true; - } - - return CheckHook(*orig_func, dll, func, std::forward(aPred)); + return true; } else { printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to detour %s from %s\n", func, dll); return false; } } -// If a function pointer's type returns void*, this template converts that type -// to return uintptr_t instead, for the purposes of predicates. -template -struct SubstituteForVoidPtr -{ - using Type = FuncT; -}; - -template -struct SubstituteForVoidPtr -{ - using Type = uintptr_t (*)(Args...); -}; - -#ifdef _M_IX86 -template -struct SubstituteForVoidPtr -{ - using Type = uintptr_t (__stdcall*)(Args...); -}; - -template -struct SubstituteForVoidPtr -{ - using Type = uintptr_t (__fastcall*)(Args...); -}; -#endif // _M_IX86 - -// Determines the function's return type -template -struct ReturnType; - -template -struct ReturnType -{ - using Type = R; -}; - -#ifdef _M_IX86 -template -struct ReturnType -{ - using Type = R; -}; - -template -struct ReturnType -{ - using Type = R; -}; -#endif // _M_IX86 - -// Predicates that may be supplied during tests -template -struct Predicates -{ - using ArgType = typename ReturnType::Type; - - template - static bool Equals(ArgType aValue) - { - return CompVal == aValue; - } - - template - static bool NotEquals(ArgType aValue) - { - return CompVal != aValue; - } - - template - static bool Ignore(ArgType aValue) - { - return true; - } -}; - -// Functions that return void should be ignored, so we specialize the -// Ignore predicate for that case. Use nullptr as the value to compare against. -template -struct Predicates -{ - template - static bool Ignore() - { - return true; - } -}; - -#ifdef _M_IX86 -template -struct Predicates -{ - template - static bool Ignore() - { - return true; - } -}; - -template -struct Predicates -{ - template - static bool Ignore() - { - return true; - } -}; -#endif // _M_IX86 - -// The standard test. Hook |func|, and then try executing it with all zero -// arguments, using |pred| and |comp| to determine whether the call successfully -// executed. In general, you want set pred and comp such that they return true -// when the function is returning whatever value is expected with all-zero -// arguments. -// -// Note: When |func| returns void, you must supply |Ignore| and |nullptr| as the -// |pred| and |comp| arguments, respectively. -#define TEST_HOOK(dll, func, pred, comp) \ - TestHook(#dll, #func, &Predicates::pred) - -// We need to special-case functions that return INVALID_HANDLE_VALUE -// (ie, CreateFile). Our template machinery for comparing values doesn't work -// with integer constants passed as pointers (well, it works on MSVC, but not -// clang, because that is not standard-compliant). -#define TEST_HOOK_FOR_INVALID_HANDLE_VALUE(dll, func) \ - TestHook::Type>(#dll, #func, &Predicates::Type>::Equals) - -// This variant allows you to explicitly supply arguments to the hooked function -// during testing. You want to provide arguments that produce the conditions that -// induce the function to return a value that is accepted by your predicate. -#define TEST_HOOK_PARAMS(dll, func, pred, comp, ...) \ - TestHook(#dll, #func, &Predicates::pred, __VA_ARGS__) - -// This is for cases when we want to hook |func|, but it is unsafe to attempt -// to execute the function in the context of a test. -#define TEST_HOOK_SKIP_EXEC(dll, func) \ - TestHook(#dll, #func, reinterpret_cast::Type)>(NULL)) - -// The following three variants are identical to the previous macros, -// however the forcibly use a Detour on 32-bit Windows. On 64-bit Windows, -// these macros are identical to their TEST_HOOK variants. -#define TEST_DETOUR(dll, func, pred, comp) \ - TestDetour(#dll, #func, &Predicates::pred) - -#define TEST_DETOUR_PARAMS(dll, func, pred, comp, ...) \ - TestDetour(#dll, #func, &Predicates::pred, __VA_ARGS__) - -#define TEST_DETOUR_SKIP_EXEC(dll, func) \ - TestDetour(#dll, #func, reinterpret_cast::Type)>(NULL)) - -template -bool MaybeTestHook(const bool cond, const char (&dll)[N], const char *func, PredicateT&& aPred, Args... aArgs) +template +bool MaybeTestHook(const bool cond, HookTestFunc funcTester, const char (&dll)[N], const char* func) { if (!cond) { printf("TEST-SKIPPED | WindowsDllInterceptor | Skipped hook test for %s from %s\n", func, dll); return true; } - return TestHook(dll, func, std::forward(aPred), std::forward(aArgs)...); + return TestHook(funcTester, dll, func); } -// Like TEST_HOOK, but the test is only executed when cond is true. -#define MAYBE_TEST_HOOK(cond, dll, func, pred, comp) \ - MaybeTestHook(cond, #dll, #func, &Predicates::pred) - -#define MAYBE_TEST_HOOK_PARAMS(cond, dll, func, pred, comp, ...) \ - MaybeTestHook(cond, #dll, #func, &Predicates::pred, __VA_ARGS__) - -#define MAYBE_TEST_HOOK_SKIP_EXEC(cond, dll, func) \ - MaybeTestHook(cond, #dll, #func, reinterpret_cast::Type)>(NULL)) - bool ShouldTestTipTsf() { if (!IsWin8OrLater()) { @@ -396,6 +147,455 @@ bool ShouldTestTipTsf() return true; } +// These test the patched function returned by the DLL +// interceptor. They check that the patched assembler preamble does +// something sane. The parameter is a pointer to the patched function. +bool TestGetWindowInfo(void* aFunc) +{ + auto patchedGetWindowInfo = + reinterpret_cast(aFunc); + return patchedGetWindowInfo(0, 0) == FALSE; +} + +bool TestSetWindowLongPtr(void* aFunc) +{ + auto patchedSetWindowLongPtr = + reinterpret_cast(aFunc); + return patchedSetWindowLongPtr(0, 0, 0) == 0; +} + +bool TestSetWindowLong(void* aFunc) +{ + auto patchedSetWindowLong = + reinterpret_cast(aFunc); + return patchedSetWindowLong(0, 0, 0) == 0; +} + +bool TestTrackPopupMenu(void* aFunc) +{ + auto patchedTrackPopupMenu = + reinterpret_cast(aFunc); + return patchedTrackPopupMenu(0, 0, 0, 0, 0, 0, 0) == 0; +} + +bool TestNtFlushBuffersFile(void* aFunc) +{ + typedef NTSTATUS(WINAPI *NtFlushBuffersFileType)(HANDLE, PIO_STATUS_BLOCK); + auto patchedNtFlushBuffersFile = + reinterpret_cast(aFunc); + patchedNtFlushBuffersFile(0, 0); + return true; +} + +bool TestNtCreateFile(void* aFunc) +{ + auto patchedNtCreateFile = + reinterpret_cast(aFunc); + return patchedNtCreateFile(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; +} + +bool TestNtReadFile(void* aFunc) +{ + typedef NTSTATUS(WINAPI *NtReadFileType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PVOID, ULONG, + PLARGE_INTEGER, PULONG); + auto patchedNtReadFile = + reinterpret_cast(aFunc); + return patchedNtReadFile(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; +} + +bool TestNtReadFileScatter(void* aFunc) +{ + typedef NTSTATUS(WINAPI *NtReadFileScatterType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, + PLARGE_INTEGER, PULONG); + auto patchedNtReadFileScatter = + reinterpret_cast(aFunc); + return patchedNtReadFileScatter(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; +} + +bool TestNtWriteFile(void* aFunc) +{ + typedef NTSTATUS(WINAPI *NtWriteFileType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PVOID, ULONG, + PLARGE_INTEGER, PULONG); + auto patchedNtWriteFile = + reinterpret_cast(aFunc); + return patchedNtWriteFile(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; +} + +bool TestNtWriteFileGather(void* aFunc) +{ + typedef NTSTATUS(WINAPI *NtWriteFileGatherType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, + PLARGE_INTEGER, PULONG); + auto patchedNtWriteFileGather = + reinterpret_cast(aFunc); + return patchedNtWriteFileGather(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; +} + +bool TestNtQueryFullAttributesFile(void* aFunc) +{ + typedef NTSTATUS(WINAPI *NtQueryFullAttributesFileType)(POBJECT_ATTRIBUTES, + PVOID); + auto patchedNtQueryFullAttributesFile = + reinterpret_cast(aFunc); + return patchedNtQueryFullAttributesFile(0, 0) != 0; +} + +bool TestLdrUnloadDll(void* aFunc) +{ + typedef NTSTATUS (NTAPI *LdrUnloadDllType)(HMODULE); + auto patchedLdrUnloadDll = reinterpret_cast(aFunc); + return patchedLdrUnloadDll(0) != 0; +} + +bool TestLdrResolveDelayLoadedAPI(void* aFunc) +{ + // These pointers are disguised as PVOID to avoid pulling in obscure headers + typedef PVOID (WINAPI *LdrResolveDelayLoadedAPIType)(PVOID, PVOID, PVOID, + PVOID, PVOID, ULONG); + auto patchedLdrResolveDelayLoadedAPI = + reinterpret_cast(aFunc); + // No idea how to call this API. Flags==99 is just an arbitrary number that + // doesn't crash when the other params are null. + return patchedLdrResolveDelayLoadedAPI(0, 0, 0, 0, 0, 99) == 0; +} + +#ifdef _M_AMD64 +bool TestRtlInstallFunctionTableCallback(void* aFunc) +{ + auto patchedRtlInstallFunctionTableCallback = + reinterpret_cast(aFunc); + + return patchedRtlInstallFunctionTableCallback(0, 0, 0, 0, 0, 0) == FALSE; +} +#endif + +bool TestSetUnhandledExceptionFilter(void* aFunc) +{ + auto patchedSetUnhandledExceptionFilter = + reinterpret_cast(aFunc); + // Retrieve the current filter as we set the new filter to null, then restore the current filter. + LPTOP_LEVEL_EXCEPTION_FILTER current = patchedSetUnhandledExceptionFilter(0); + patchedSetUnhandledExceptionFilter(current); + return true; +} + +bool TestVirtualAlloc(void* aFunc) +{ + auto patchedVirtualAlloc = + reinterpret_cast(aFunc); + return patchedVirtualAlloc(0, 0, 0, 0) == 0; +} + +bool TestMapViewOfFile(void* aFunc) +{ + auto patchedMapViewOfFile = + reinterpret_cast(aFunc); + return patchedMapViewOfFile(0, 0, 0, 0, 0) == 0; +} + +bool TestCreateDIBSection(void* aFunc) +{ + auto patchedCreateDIBSection = + reinterpret_cast(aFunc); + // MSDN is wrong here. This does not return ERROR_INVALID_PARAMETER. It + // sets the value of GetLastError to ERROR_INVALID_PARAMETER. + // CreateDIBSection returns 0 on error. + return patchedCreateDIBSection(0, 0, 0, 0, 0, 0) == 0; +} + +bool TestCreateFileW(void* aFunc) +{ + auto patchedCreateFileW = + reinterpret_cast(aFunc); + return patchedCreateFileW(0, 0, 0, 0, 0, 0, 0) == INVALID_HANDLE_VALUE; +} + +bool TestCreateFileA(void* aFunc) +{ + auto patchedCreateFileA = + reinterpret_cast(aFunc); +// return patchedCreateFileA(0, 0, 0, 0, 0, 0, 0) == INVALID_HANDLE_VALUE; + printf("TEST-SKIPPED | WindowsDllInterceptor | " + "Will not attempt to execute patched CreateFileA -- patched method is known to fail.\n"); + return true; +} + +bool TestQueryDosDeviceW(void* aFunc) +{ + auto patchedQueryDosDeviceW = + reinterpret_cast(aFunc); + return patchedQueryDosDeviceW(nullptr, nullptr, 0) == 0; +} + +bool TestInSendMessageEx(void* aFunc) +{ + auto patchedInSendMessageEx = + reinterpret_cast(aFunc); + patchedInSendMessageEx(0); + return true; +} + +bool TestImmGetContext(void* aFunc) +{ + auto patchedImmGetContext = + reinterpret_cast(aFunc); + patchedImmGetContext(0); + return true; +} + +bool TestImmGetCompositionStringW(void* aFunc) +{ + auto patchedImmGetCompositionStringW = + reinterpret_cast(aFunc); + patchedImmGetCompositionStringW(0, 0, 0, 0); + return true; +} + +bool TestImmSetCandidateWindow(void* aFunc) +{ + auto patchedImmSetCandidateWindow = + reinterpret_cast(aFunc); +// return patchedImmSetCandidateWindow(0, 0) == 0; + // ImmSetCandidateWindow crashes if given bad parameters. + printf("TEST-SKIPPED | WindowsDllInterceptor | " + "Will not attempt to execute patched ImmSetCandidateWindow.\n"); + return true; +} + +bool TestImmNotifyIME(void* aFunc) +{ + auto patchedImmNotifyIME = + reinterpret_cast(aFunc); + return patchedImmNotifyIME(0, 0, 0, 0) == 0; +} + +bool TestGetSaveFileNameW(void* aFunc) +{ + auto patchedGetSaveFileNameWType = + reinterpret_cast(aFunc); + patchedGetSaveFileNameWType(0); + return true; +} + +bool TestGetOpenFileNameW(void* aFunc) +{ + auto patchedGetOpenFileNameWType = + reinterpret_cast(aFunc); + patchedGetOpenFileNameWType(0); + return true; +} + +bool TestGetKeyState(void* aFunc) +{ + auto patchedGetKeyState = + reinterpret_cast(aFunc); + patchedGetKeyState(0); + return true; +} + +bool TestSendMessageTimeoutW(void* aFunc) +{ + auto patchedSendMessageTimeoutW = + reinterpret_cast(aFunc); + return patchedSendMessageTimeoutW(0, 0, 0, 0, 0, 0, 0) == 0; +} + +bool TestProcessCaretEvents(void* aFunc) +{ + auto patchedProcessCaretEvents = + reinterpret_cast(aFunc); + patchedProcessCaretEvents(0, 0, 0, 0, 0, 0, 0); + return true; +} + +bool TestSetCursorPos(void* aFunc) +{ + // SetCursorPos has some issues in automation -- see bug 1368033. + // For that reason, we don't check the return value -- we only + // check that the method runs without producing an exception. + auto patchedSetCursorPos = + reinterpret_cast(aFunc); + patchedSetCursorPos(512, 512); + return true; +} + +static DWORD sTlsIndex = 0; + +bool TestTlsAlloc(void* aFunc) +{ + auto patchedTlsAlloc = + reinterpret_cast(aFunc); + sTlsIndex = patchedTlsAlloc(); + return sTlsIndex != TLS_OUT_OF_INDEXES; +} + +bool TestTlsFree(void* aFunc) +{ + auto patchedTlsFree = + reinterpret_cast(aFunc); + return sTlsIndex != 0 && patchedTlsFree(sTlsIndex); +} + +bool TestCloseHandle(void* aFunc) +{ + auto patchedCloseHandle = + reinterpret_cast(aFunc); + return patchedCloseHandle(0) == FALSE; +} + +bool TestDuplicateHandle(void* aFunc) +{ + auto patchedDuplicateHandle = + reinterpret_cast(aFunc); + return patchedDuplicateHandle(0, 0, 0, 0, 0, 0, 0) == FALSE; +} + +bool TestPrintDlgW(void* aFunc) +{ + auto patchedPrintDlgW = + reinterpret_cast(aFunc); + patchedPrintDlgW(0); + return true; +} + +bool TestInternetConnectA(void* aFunc) +{ + auto patchedInternetConnectA = + reinterpret_cast(aFunc); + return patchedInternetConnectA(0, 0, 0, 0, 0, 0, 0, 0) == 0; +} + +HINTERNET sInternet = 0; + +bool TestInternetOpenA(void* aFunc) +{ + auto patchedInternetOpenA = + reinterpret_cast(aFunc); + sInternet = patchedInternetOpenA(0, 0, 0, 0, 0); + return sInternet != 0; +} + +bool TestInternetCloseHandle(void* aFunc) +{ + auto patchedInternetCloseHandle = + reinterpret_cast(aFunc); + return patchedInternetCloseHandle(sInternet); +} + +bool TestInternetQueryDataAvailable(void* aFunc) +{ + auto patchedInternetQueryDataAvailable = + reinterpret_cast(aFunc); + return patchedInternetQueryDataAvailable(0, 0, 0, 0) == FALSE; +} + +bool TestInternetReadFile(void* aFunc) +{ + auto patchedInternetReadFile = + reinterpret_cast(aFunc); + return patchedInternetReadFile(0, 0, 0, 0) == FALSE; +} + +bool TestInternetWriteFile(void* aFunc) +{ + auto patchedInternetWriteFile = + reinterpret_cast(aFunc); + return patchedInternetWriteFile(0, 0, 0, 0) == FALSE; +} + +bool TestInternetSetOptionA(void* aFunc) +{ + auto patchedInternetSetOptionA = + reinterpret_cast(aFunc); + return patchedInternetSetOptionA(0, 0, 0, 0) == FALSE; +} + +bool TestHttpAddRequestHeadersA(void* aFunc) +{ + auto patchedHttpAddRequestHeadersA = + reinterpret_cast(aFunc); + return patchedHttpAddRequestHeadersA(0, 0, 0, 0) == FALSE; +} + +bool TestHttpOpenRequestA(void* aFunc) +{ + auto patchedHttpOpenRequestA = + reinterpret_cast(aFunc); + return patchedHttpOpenRequestA(0, 0, 0, 0, 0, 0, 0, 0) == 0; +} + +bool TestHttpQueryInfoA(void* aFunc) +{ + auto patchedHttpQueryInfoA = + reinterpret_cast(aFunc); + return patchedHttpQueryInfoA(0, 0, 0, 0, 0) == FALSE; +} + +bool TestHttpSendRequestA(void* aFunc) +{ + auto patchedHttpSendRequestA = + reinterpret_cast(aFunc); + return patchedHttpSendRequestA(0, 0, 0, 0, 0) == FALSE; +} + +bool TestHttpSendRequestExA(void* aFunc) +{ + auto patchedHttpSendRequestExA = + reinterpret_cast(aFunc); + return patchedHttpSendRequestExA(0, 0, 0, 0, 0) == FALSE; +} + +bool TestHttpEndRequestA(void* aFunc) +{ + auto patchedHttpEndRequestA = + reinterpret_cast(aFunc); + return patchedHttpEndRequestA(0, 0, 0, 0) == FALSE; +} + +bool TestInternetQueryOptionA(void* aFunc) +{ + auto patchedInternetQueryOptionA = + reinterpret_cast(aFunc); + return patchedInternetQueryOptionA(0, 0, 0, 0) == FALSE; +} + +bool TestInternetErrorDlg(void* aFunc) +{ + auto patchedInternetErrorDlg = + reinterpret_cast(aFunc); + return patchedInternetErrorDlg(0, 0, 0, 0, 0) == ERROR_INVALID_HANDLE; +} + +CredHandle sCredHandle; + +bool TestAcquireCredentialsHandleA(void* aFunc) +{ + auto patchedAcquireCredentialsHandleA = + reinterpret_cast(aFunc); + SCHANNEL_CRED cred; + memset(&cred, 0, sizeof(cred)); + cred.dwVersion = SCHANNEL_CRED_VERSION; + return patchedAcquireCredentialsHandleA(0, UNISP_NAME, SECPKG_CRED_OUTBOUND, + 0, &cred, 0, 0, &sCredHandle, 0) == S_OK; +} + +bool TestQueryCredentialsAttributesA(void* aFunc) +{ + auto patchedQueryCredentialsAttributesA = + reinterpret_cast(aFunc); + return patchedQueryCredentialsAttributesA(&sCredHandle, 0, 0) == SEC_E_UNSUPPORTED_FUNCTION; +} + +bool TestFreeCredentialsHandle(void* aFunc) +{ + auto patchedFreeCredentialsHandle = + reinterpret_cast(aFunc); + return patchedFreeCredentialsHandle(&sCredHandle) == S_OK; +} + int main() { LARGE_INTEGER start; @@ -415,7 +615,7 @@ int main() { WindowsDllInterceptor ExeIntercept; ExeIntercept.Init("TestDllInterceptor.exe"); - if (orig_rotatePayload.Set(ExeIntercept, "rotatePayload", &patched_rotatePayload)) { + if (ExeIntercept.AddHook("rotatePayload", reinterpret_cast(patched_rotatePayload), (void**) &orig_rotatePayload)) { printf("TEST-PASS | WindowsDllInterceptor | Hook added\n"); } else { printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to add hook\n"); @@ -459,85 +659,85 @@ int main() } #endif - if (TEST_HOOK(user32.dll, GetWindowInfo, Equals, FALSE) && + if (TestHook(TestGetWindowInfo, "user32.dll", "GetWindowInfo") && #ifdef _WIN64 - TEST_HOOK(user32.dll, SetWindowLongPtrA, Equals, 0) && - TEST_HOOK(user32.dll, SetWindowLongPtrW, Equals, 0) && + TestHook(TestSetWindowLongPtr, "user32.dll", "SetWindowLongPtrA") && + TestHook(TestSetWindowLongPtr, "user32.dll", "SetWindowLongPtrW") && #else - TEST_HOOK(user32.dll, SetWindowLongA, Equals, 0) && - TEST_HOOK(user32.dll, SetWindowLongW, Equals, 0) && + TestHook(TestSetWindowLong, "user32.dll", "SetWindowLongA") && + TestHook(TestSetWindowLong, "user32.dll", "SetWindowLongW") && #endif - TEST_HOOK(user32.dll, TrackPopupMenu, Equals, FALSE) && + TestHook(TestTrackPopupMenu, "user32.dll", "TrackPopupMenu") && #ifdef _M_IX86 // We keep this test to hook complex code on x86. (Bug 850957) - TEST_HOOK(ntdll.dll, NtFlushBuffersFile, NotEquals, 0) && + TestHook(TestNtFlushBuffersFile, "ntdll.dll", "NtFlushBuffersFile") && #endif - TEST_HOOK(ntdll.dll, NtCreateFile, NotEquals, 0) && - TEST_HOOK(ntdll.dll, NtReadFile, NotEquals, 0) && - TEST_HOOK(ntdll.dll, NtReadFileScatter, NotEquals, 0) && - TEST_HOOK(ntdll.dll, NtWriteFile, NotEquals, 0) && - TEST_HOOK(ntdll.dll, NtWriteFileGather, NotEquals, 0) && - TEST_HOOK(ntdll.dll, NtQueryFullAttributesFile, NotEquals, 0) && + TestHook(TestNtCreateFile, "ntdll.dll", "NtCreateFile") && + TestHook(TestNtReadFile, "ntdll.dll", "NtReadFile") && + TestHook(TestNtReadFileScatter, "ntdll.dll", "NtReadFileScatter") && + TestHook(TestNtWriteFile, "ntdll.dll", "NtWriteFile") && + TestHook(TestNtWriteFileGather, "ntdll.dll", "NtWriteFileGather") && + TestHook(TestNtQueryFullAttributesFile, "ntdll.dll", "NtQueryFullAttributesFile") && #ifndef MOZ_ASAN // Bug 733892: toolkit/crashreporter/nsExceptionHandler.cpp // This fails on ASan because the ASan runtime already hooked this function - TEST_HOOK(kernel32.dll, SetUnhandledExceptionFilter, Ignore, nullptr) && + TestHook(TestSetUnhandledExceptionFilter, "kernel32.dll", "SetUnhandledExceptionFilter") && #endif #ifdef _M_IX86 // Bug 670967: xpcom/base/AvailableMemoryTracker.cpp - TEST_HOOK(kernel32.dll, VirtualAlloc, Equals, nullptr) && - TEST_HOOK(kernel32.dll, MapViewOfFile, Equals, nullptr) && - TEST_HOOK(gdi32.dll, CreateDIBSection, Equals, nullptr) && - TEST_HOOK_FOR_INVALID_HANDLE_VALUE(kernel32.dll, CreateFileW) && + TestHook(TestVirtualAlloc, "kernel32.dll", "VirtualAlloc") && + TestHook(TestMapViewOfFile, "kernel32.dll", "MapViewOfFile") && + TestHook(TestCreateDIBSection, "gdi32.dll", "CreateDIBSection") && + TestHook(TestCreateFileW, "kernel32.dll", "CreateFileW") && // see Bug 1316415 #endif - TEST_HOOK_FOR_INVALID_HANDLE_VALUE(kernel32.dll, CreateFileA) && - TEST_HOOK(kernelbase.dll, QueryDosDeviceW, Equals, 0) && - TEST_DETOUR(user32.dll, CreateWindowExW, Equals, nullptr) && - TEST_HOOK(user32.dll, InSendMessageEx, Equals, ISMEX_NOSEND) && - TEST_HOOK(imm32.dll, ImmGetContext, Equals, nullptr) && - TEST_HOOK(imm32.dll, ImmGetCompositionStringW, Ignore, 0) && - TEST_HOOK_SKIP_EXEC(imm32.dll, ImmSetCandidateWindow) && - TEST_HOOK(imm32.dll, ImmNotifyIME, Equals, 0) && - TEST_HOOK(comdlg32.dll, GetSaveFileNameW, Ignore, FALSE) && - TEST_HOOK(comdlg32.dll, GetOpenFileNameW, Ignore, FALSE) && + TestHook(TestCreateFileA, "kernel32.dll", "CreateFileA") && + TestHook(TestQueryDosDeviceW, "kernelbase.dll", "QueryDosDeviceW") && + TestDetour("user32.dll", "CreateWindowExW") && + TestHook(TestInSendMessageEx, "user32.dll", "InSendMessageEx") && + TestHook(TestImmGetContext, "imm32.dll", "ImmGetContext") && + TestHook(TestImmGetCompositionStringW, "imm32.dll", "ImmGetCompositionStringW") && + TestHook(TestImmSetCandidateWindow, "imm32.dll", "ImmSetCandidateWindow") && + TestHook(TestImmNotifyIME, "imm32.dll", "ImmNotifyIME") && + TestHook(TestGetSaveFileNameW, "comdlg32.dll", "GetSaveFileNameW") && + TestHook(TestGetOpenFileNameW, "comdlg32.dll", "GetOpenFileNameW") && #ifdef _M_X64 - TEST_HOOK(user32.dll, GetKeyState, Ignore, 0) && // see Bug 1316415 - TEST_HOOK(ntdll.dll, LdrUnloadDll, NotEquals, 0) && - MAYBE_TEST_HOOK_SKIP_EXEC(IsWin8OrLater(), ntdll.dll, LdrResolveDelayLoadedAPI) && - MAYBE_TEST_HOOK(!IsWin8OrLater(), kernel32.dll, RtlInstallFunctionTableCallback, Equals, FALSE) && - TEST_HOOK(comdlg32.dll, PrintDlgW, Ignore, 0) && + TestHook(TestGetKeyState, "user32.dll", "GetKeyState") && // see Bug 1316415 + TestHook(TestLdrUnloadDll, "ntdll.dll", "LdrUnloadDll") && + MaybeTestHook(IsWin8OrLater(), TestLdrResolveDelayLoadedAPI, "ntdll.dll", "LdrResolveDelayLoadedAPI") && + MaybeTestHook(!IsWin8OrLater(), TestRtlInstallFunctionTableCallback, "kernel32.dll", "RtlInstallFunctionTableCallback") && + TestHook(TestPrintDlgW, "comdlg32.dll", "PrintDlgW") && #endif - MAYBE_TEST_HOOK(ShouldTestTipTsf(), tiptsf.dll, ProcessCaretEvents, Ignore, nullptr) && + MaybeTestHook(ShouldTestTipTsf(), TestProcessCaretEvents, "tiptsf.dll", "ProcessCaretEvents") && #ifdef _M_IX86 - TEST_HOOK(user32.dll, SendMessageTimeoutW, Equals, 0) && + TestHook(TestSendMessageTimeoutW, "user32.dll", "SendMessageTimeoutW") && #endif - TEST_HOOK(user32.dll, SetCursorPos, NotEquals, FALSE) && - TEST_HOOK(kernel32.dll, TlsAlloc, NotEquals, TLS_OUT_OF_INDEXES) && - TEST_HOOK_PARAMS(kernel32.dll, TlsFree, Equals, FALSE, TLS_OUT_OF_INDEXES) && - TEST_HOOK(kernel32.dll, CloseHandle, Equals, FALSE) && - TEST_HOOK(kernel32.dll, DuplicateHandle, Equals, FALSE) && + TestHook(TestSetCursorPos, "user32.dll", "SetCursorPos") && + TestHook(TestTlsAlloc, "kernel32.dll", "TlsAlloc") && + TestHook(TestTlsFree, "kernel32.dll", "TlsFree") && + TestHook(TestCloseHandle, "kernel32.dll", "CloseHandle") && + TestHook(TestDuplicateHandle, "kernel32.dll", "DuplicateHandle") && - TEST_HOOK(wininet.dll, InternetOpenA, NotEquals, nullptr) && - TEST_HOOK(wininet.dll, InternetCloseHandle, Equals, FALSE) && - TEST_HOOK(wininet.dll, InternetConnectA, Equals, nullptr) && - TEST_HOOK(wininet.dll, InternetQueryDataAvailable, Equals, FALSE) && - TEST_HOOK(wininet.dll, InternetReadFile, Equals, FALSE) && - TEST_HOOK(wininet.dll, InternetWriteFile, Equals, FALSE) && - TEST_HOOK(wininet.dll, InternetSetOptionA, Equals, FALSE) && - TEST_HOOK(wininet.dll, HttpAddRequestHeadersA, Equals, FALSE) && - TEST_HOOK(wininet.dll, HttpOpenRequestA, Equals, nullptr) && - TEST_HOOK(wininet.dll, HttpQueryInfoA, Equals, FALSE) && - TEST_HOOK(wininet.dll, HttpSendRequestA, Equals, FALSE) && - TEST_HOOK(wininet.dll, HttpSendRequestExA, Equals, FALSE) && - TEST_HOOK(wininet.dll, HttpEndRequestA, Equals, FALSE) && - TEST_HOOK(wininet.dll, InternetQueryOptionA, Equals, FALSE) && + TestHook(TestInternetOpenA, "wininet.dll", "InternetOpenA") && + TestHook(TestInternetCloseHandle, "wininet.dll", "InternetCloseHandle") && + TestHook(TestInternetConnectA, "wininet.dll", "InternetConnectA") && + TestHook(TestInternetQueryDataAvailable, "wininet.dll", "InternetQueryDataAvailable") && + TestHook(TestInternetReadFile, "wininet.dll", "InternetReadFile") && + TestHook(TestInternetWriteFile, "wininet.dll", "InternetWriteFile") && + TestHook(TestInternetSetOptionA, "wininet.dll", "InternetSetOptionA") && + TestHook(TestHttpAddRequestHeadersA, "wininet.dll", "HttpAddRequestHeadersA") && + TestHook(TestHttpOpenRequestA, "wininet.dll", "HttpOpenRequestA") && + TestHook(TestHttpQueryInfoA, "wininet.dll", "HttpQueryInfoA") && + TestHook(TestHttpSendRequestA, "wininet.dll", "HttpSendRequestA") && + TestHook(TestHttpSendRequestExA, "wininet.dll", "HttpSendRequestExA") && + TestHook(TestHttpEndRequestA, "wininet.dll", "HttpEndRequestA") && + TestHook(TestInternetQueryOptionA, "wininet.dll", "InternetQueryOptionA") && - TEST_HOOK(sspicli.dll, AcquireCredentialsHandleA, NotEquals, SEC_E_OK) && - TEST_HOOK(sspicli.dll, QueryCredentialsAttributesA, NotEquals, SEC_E_OK) && - TEST_HOOK(sspicli.dll, FreeCredentialsHandle, NotEquals, SEC_E_OK) && + TestHook(TestAcquireCredentialsHandleA, "sspicli.dll", "AcquireCredentialsHandleA") && + TestHook(TestQueryCredentialsAttributesA, "sspicli.dll", "QueryCredentialsAttributesA") && + TestHook(TestFreeCredentialsHandle, "sspicli.dll", "FreeCredentialsHandle") && - TEST_DETOUR_SKIP_EXEC(kernel32.dll, BaseThreadInitThunk) && - TEST_DETOUR_SKIP_EXEC(ntdll.dll, LdrLoadDll)) { + TestDetour("kernel32.dll", "BaseThreadInitThunk") && + TestDetour("ntdll.dll", "LdrLoadDll")) { printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n"); LARGE_INTEGER end, freq; diff --git a/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp b/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp index c29d132ba9b0..95cf37821043 100644 --- a/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp +++ b/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp @@ -11,19 +11,19 @@ using std::wstring; +static void* gOrigReturnResult; + extern "C" __declspec(dllexport) int ReturnResult() { return 2; } -static mozilla::CrossProcessDllInterceptor::FuncHookType - gOrigReturnResult; - static int ReturnResultHook() { - if (gOrigReturnResult() != 2) { + auto origFn = reinterpret_cast(gOrigReturnResult); + if (origFn() != 2) { return 3; } @@ -73,7 +73,9 @@ int ParentMain() mozilla::CrossProcessDllInterceptor intcpt(childProcess.get()); intcpt.Init("TestDllInterceptorCrossProcess.exe"); - if (!gOrigReturnResult.Set(intcpt, "ReturnResult", &ReturnResultHook)) { + if (!intcpt.AddHook("ReturnResult", + reinterpret_cast(&ReturnResultHook), + &gOrigReturnResult)) { printf("TEST-UNEXPECTED-FAIL | DllInterceptorCrossProcess | Failed to add hook\n"); return 1; } diff --git a/security/sandbox/win/SandboxInitialization.cpp b/security/sandbox/win/SandboxInitialization.cpp index 8a4a5e858072..8e27b87dd2f4 100644 --- a/security/sandbox/win/SandboxInitialization.cpp +++ b/security/sandbox/win/SandboxInitialization.cpp @@ -15,7 +15,7 @@ namespace mozilla { namespace sandboxing { typedef BOOL(WINAPI* CloseHandle_func) (HANDLE hObject); -static WindowsDllInterceptor::FuncHookType stub_CloseHandle; +static CloseHandle_func stub_CloseHandle = nullptr; typedef BOOL(WINAPI* DuplicateHandle_func)(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, @@ -24,8 +24,7 @@ typedef BOOL(WINAPI* DuplicateHandle_func)(HANDLE hSourceProcessHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions); -static WindowsDllInterceptor::FuncHookType - stub_DuplicateHandle; +static DuplicateHandle_func stub_DuplicateHandle = nullptr; static BOOL WINAPI patched_CloseHandle(HANDLE hObject) @@ -63,14 +62,17 @@ EnableHandleCloseMonitoring() { Kernel32Intercept.Init("kernel32.dll"); bool hooked = - stub_CloseHandle.Set(Kernel32Intercept, "CloseHandle", &patched_CloseHandle); + Kernel32Intercept.AddHook("CloseHandle", + reinterpret_cast(patched_CloseHandle), + (void**)&stub_CloseHandle); if (!hooked) { return false; } hooked = - stub_DuplicateHandle.Set(Kernel32Intercept, "DuplicateHandle", - &patched_DuplicateHandle); + Kernel32Intercept.AddHook("DuplicateHandle", + reinterpret_cast(patched_DuplicateHandle), + (void**)&stub_DuplicateHandle); if (!hooked) { return false; } diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp index 319f78f27cc0..7f42278ef244 100644 --- a/toolkit/crashreporter/nsExceptionHandler.cpp +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -338,8 +338,7 @@ nsTArray >* gDelayedAnnotations; // reporter is loaded instead (in case it became unloaded somehow) typedef LPTOP_LEVEL_EXCEPTION_FILTER (WINAPI *SetUnhandledExceptionFilter_func) (LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); -static WindowsDllInterceptor::FuncHookType - stub_SetUnhandledExceptionFilter; +static SetUnhandledExceptionFilter_func stub_SetUnhandledExceptionFilter = 0; static LPTOP_LEVEL_EXCEPTION_FILTER previousUnhandledExceptionFilter = nullptr; static WindowsDllInterceptor gKernel32Intercept; static bool gBlockUnhandledExceptionFilter = true; @@ -1640,9 +1639,9 @@ nsresult SetExceptionHandler(nsIFile* aXREDirectory, // protect the crash reporter from being unloaded gBlockUnhandledExceptionFilter = true; gKernel32Intercept.Init("kernel32.dll"); - bool ok = stub_SetUnhandledExceptionFilter.Set(gKernel32Intercept, - "SetUnhandledExceptionFilter", - &patched_SetUnhandledExceptionFilter); + bool ok = gKernel32Intercept.AddHook("SetUnhandledExceptionFilter", + reinterpret_cast(patched_SetUnhandledExceptionFilter), + (void**) &stub_SetUnhandledExceptionFilter); #ifdef DEBUG if (!ok) diff --git a/tools/profiler/core/platform-win32.cpp b/tools/profiler/core/platform-win32.cpp index 04a56fbdf133..ee17d1a68b73 100644 --- a/tools/profiler/core/platform-win32.cpp +++ b/tools/profiler/core/platform-win32.cpp @@ -303,8 +303,7 @@ Registers::SyncPopulate() static WindowsDllInterceptor NtDllIntercept; typedef NTSTATUS (NTAPI *LdrUnloadDll_func)(HMODULE module); -static WindowsDllInterceptor::FuncHookType - stub_LdrUnloadDll; +static LdrUnloadDll_func stub_LdrUnloadDll; static NTSTATUS NTAPI patched_LdrUnloadDll(HMODULE module) @@ -319,8 +318,7 @@ patched_LdrUnloadDll(HMODULE module) typedef PVOID (WINAPI *LdrResolveDelayLoadedAPI_func)(PVOID ParentModuleBase, PVOID DelayloadDescriptor, PVOID FailureDllHook, PVOID FailureSystemHook, PVOID ThunkAddress, ULONG Flags); -static WindowsDllInterceptor::FuncHookType - stub_LdrResolveDelayLoadedAPI; +static LdrResolveDelayLoadedAPI_func stub_LdrResolveDelayLoadedAPI; static PVOID WINAPI patched_LdrResolveDelayLoadedAPI(PVOID ParentModuleBase, @@ -338,12 +336,20 @@ patched_LdrResolveDelayLoadedAPI(PVOID ParentModuleBase, void InitializeWin64ProfilerHooks() { + static bool initialized = false; + if (initialized) { + return; + } + initialized = true; + NtDllIntercept.Init("ntdll.dll"); - stub_LdrUnloadDll.Set(NtDllIntercept, "LdrUnloadDll", &patched_LdrUnloadDll); + NtDllIntercept.AddHook("LdrUnloadDll", + reinterpret_cast(patched_LdrUnloadDll), + (void**)&stub_LdrUnloadDll); if (IsWin8OrLater()) { // LdrResolveDelayLoadedAPI was introduced in Win8 - stub_LdrResolveDelayLoadedAPI.Set(NtDllIntercept, - "LdrResolveDelayLoadedAPI", - &patched_LdrResolveDelayLoadedAPI); + NtDllIntercept.AddHook("LdrResolveDelayLoadedAPI", + reinterpret_cast(patched_LdrResolveDelayLoadedAPI), + (void**)&stub_LdrResolveDelayLoadedAPI); } } #endif // defined(GP_PLAT_amd64_windows) diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index f15691569075..db0389563b1e 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -352,6 +352,9 @@ static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); // General purpose user32.dll hook object static WindowsDllInterceptor sUser32Intercept; +// AddHook success checks +static mozilla::Maybe sHookedGetWindowInfo; + // 2 pixel offset for eTransparencyBorderlessGlass which equals the size of // the default window border Windows paints. Glass will be extended inward // this distance to remove the border. @@ -458,17 +461,17 @@ private: if (!IsWin10OrLater() && GetModuleHandle(L"tiptsf.dll") && !sProcessCaretEventsStub) { sTipTsfInterceptor.Init("tiptsf.dll"); - DebugOnly ok = sProcessCaretEventsStub.Set(sTipTsfInterceptor, - "ProcessCaretEvents", - &ProcessCaretEventsHook); + DebugOnly ok = sTipTsfInterceptor.AddHook("ProcessCaretEvents", + reinterpret_cast(&ProcessCaretEventsHook), + (void**) &sProcessCaretEventsStub); MOZ_ASSERT(ok); } if (!sSendMessageTimeoutWStub) { sUser32Intercept.Init("user32.dll"); - DebugOnly hooked = sSendMessageTimeoutWStub.Set(sUser32Intercept, - "SendMessageTimeoutW", - &SendMessageTimeoutWHook); + DebugOnly hooked = sUser32Intercept.AddHook("SendMessageTimeoutW", + reinterpret_cast(&SendMessageTimeoutWHook), + (void**) &sSendMessageTimeoutWStub); MOZ_ASSERT(hooked); } } @@ -553,10 +556,8 @@ private: } static WindowsDllInterceptor sTipTsfInterceptor; - static WindowsDllInterceptor::FuncHookType - sProcessCaretEventsStub; - static WindowsDllInterceptor::FuncHookType - sSendMessageTimeoutWStub; + static WINEVENTPROC sProcessCaretEventsStub; + static decltype(&SendMessageTimeoutW) sSendMessageTimeoutWStub; static StaticAutoPtr sInstance; HHOOK mHook; @@ -565,10 +566,8 @@ private: }; WindowsDllInterceptor TIPMessageHandler::sTipTsfInterceptor; -WindowsDllInterceptor::FuncHookType - TIPMessageHandler::sProcessCaretEventsStub; -WindowsDllInterceptor::FuncHookType - TIPMessageHandler::sSendMessageTimeoutWStub; +WINEVENTPROC TIPMessageHandler::sProcessCaretEventsStub; +decltype(&SendMessageTimeoutW) TIPMessageHandler::sSendMessageTimeoutWStub; StaticAutoPtr TIPMessageHandler::sInstance; } // namespace mozilla @@ -2473,7 +2472,7 @@ nsWindow::ResetLayout() // margins are set. static const wchar_t kManageWindowInfoProperty[] = L"ManageWindowInfoProperty"; typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi); -static WindowsDllInterceptor::FuncHookType sGetWindowInfoPtrStub; +static GetWindowInfoPtr sGetWindowInfoPtrStub = nullptr; BOOL WINAPI GetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi) @@ -2501,15 +2500,18 @@ nsWindow::UpdateGetWindowInfoCaptionStatus(bool aActiveCaption) if (!mWnd) return; - sUser32Intercept.Init("user32.dll"); - sGetWindowInfoPtrStub.Set(sUser32Intercept, "GetWindowInfo", - &GetWindowInfoHook); - if (!sGetWindowInfoPtrStub) { - return; + if (sHookedGetWindowInfo.isNothing()) { + sUser32Intercept.Init("user32.dll"); + sHookedGetWindowInfo = + Some(sUser32Intercept.AddHook("GetWindowInfo", + reinterpret_cast(GetWindowInfoHook), + (void**) &sGetWindowInfoPtrStub)); + if (!sHookedGetWindowInfo.value()) { + return; + } } - // Update our internally tracked caption status - SetPropW(mWnd, kManageWindowInfoProperty, + SetPropW(mWnd, kManageWindowInfoProperty, reinterpret_cast(static_cast(aActiveCaption) + 1)); } diff --git a/xpcom/base/AvailableMemoryTracker.cpp b/xpcom/base/AvailableMemoryTracker.cpp index 02265da2c6f1..678566087eda 100644 --- a/xpcom/base/AvailableMemoryTracker.cpp +++ b/xpcom/base/AvailableMemoryTracker.cpp @@ -84,14 +84,16 @@ volatile PRIntervalTime sLastLowMemoryNotificationTime; // These are function pointers to the functions we wrap in Init(). -static WindowsDllInterceptor::FuncHookType - sVirtualAllocOrig; +void* (WINAPI* sVirtualAllocOrig)(LPVOID aAddress, SIZE_T aSize, + DWORD aAllocationType, DWORD aProtect); -static WindowsDllInterceptor::FuncHookType - sMapViewOfFileOrig; +void* (WINAPI* sMapViewOfFileOrig)(HANDLE aFileMappingObject, + DWORD aDesiredAccess, DWORD aFileOffsetHigh, + DWORD aFileOffsetLow, SIZE_T aNumBytesToMap); -static WindowsDllInterceptor::FuncHookType - sCreateDIBSectionOrig; +HBITMAP(WINAPI* sCreateDIBSectionOrig)(HDC aDC, const BITMAPINFO* aBitmapInfo, + UINT aUsage, VOID** aBits, + HANDLE aSection, DWORD aOffset); /** * Fire a memory pressure event if we were not under memory pressure yet, or @@ -643,12 +645,17 @@ Init() // VirtualAllocHook from reentering itself. if (!PR_GetEnv("MOZ_PGO_INSTRUMENTED")) { sKernel32Intercept.Init("Kernel32.dll"); - sVirtualAllocOrig.Set(sKernel32Intercept, "VirtualAlloc", &VirtualAllocHook); - sMapViewOfFileOrig.Set(sKernel32Intercept, "MapViewOfFile", &MapViewOfFileHook); + sKernel32Intercept.AddHook("VirtualAlloc", + reinterpret_cast(VirtualAllocHook), + reinterpret_cast(&sVirtualAllocOrig)); + sKernel32Intercept.AddHook("MapViewOfFile", + reinterpret_cast(MapViewOfFileHook), + reinterpret_cast(&sMapViewOfFileOrig)); sGdi32Intercept.Init("Gdi32.dll"); - sCreateDIBSectionOrig.Set(sGdi32Intercept, "CreateDIBSection", - &CreateDIBSectionHook); + sGdi32Intercept.AddHook("CreateDIBSection", + reinterpret_cast(CreateDIBSectionHook), + reinterpret_cast(&sCreateDIBSectionOrig)); } sInitialized = true; diff --git a/xpcom/build/PoisonIOInterposerWin.cpp b/xpcom/build/PoisonIOInterposerWin.cpp index 5f2aaec25e28..6d8bc0a01233 100644 --- a/xpcom/build/PoisonIOInterposerWin.cpp +++ b/xpcom/build/PoisonIOInterposerWin.cpp @@ -209,20 +209,13 @@ WinIOAutoObservation::Filename(nsAString& aFilename) /*************************** IO Interposing Methods ***************************/ // Function pointers to original functions -static WindowsDllInterceptor::FuncHookType - gOriginalNtCreateFile; -static WindowsDllInterceptor::FuncHookType - gOriginalNtReadFile; -static WindowsDllInterceptor::FuncHookType - gOriginalNtReadFileScatter; -static WindowsDllInterceptor::FuncHookType - gOriginalNtWriteFile; -static WindowsDllInterceptor::FuncHookType - gOriginalNtWriteFileGather; -static WindowsDllInterceptor::FuncHookType - gOriginalNtFlushBuffersFile; -static WindowsDllInterceptor::FuncHookType - gOriginalNtQueryFullAttributesFile; +static NtCreateFileFn gOriginalNtCreateFile; +static NtReadFileFn gOriginalNtReadFile; +static NtReadFileScatterFn gOriginalNtReadFileScatter; +static NtWriteFileFn gOriginalNtWriteFile; +static NtWriteFileGatherFn gOriginalNtWriteFileGather; +static NtFlushBuffersFileFn gOriginalNtFlushBuffersFile; +static NtQueryFullAttributesFileFn gOriginalNtQueryFullAttributesFile; static NTSTATUS NTAPI InterposedNtCreateFile(PHANDLE aFileHandle, @@ -455,21 +448,34 @@ InitPoisonIOInterposer() // Initialize dll interceptor and add hooks sNtDllInterceptor.Init("ntdll.dll"); - gOriginalNtCreateFile.Set(sNtDllInterceptor, "NtCreateFile", - &InterposedNtCreateFile); - gOriginalNtReadFile.Set(sNtDllInterceptor, "NtReadFile", - &InterposedNtReadFile); - gOriginalNtReadFileScatter.Set(sNtDllInterceptor, "NtReadFileScatter", - &InterposedNtReadFileScatter); - gOriginalNtWriteFile.Set(sNtDllInterceptor, "NtWriteFile", - &InterposedNtWriteFile); - gOriginalNtWriteFileGather.Set(sNtDllInterceptor, "NtWriteFileGather", - &InterposedNtWriteFileGather); - gOriginalNtFlushBuffersFile.Set(sNtDllInterceptor, "NtFlushBuffersFile", - &InterposedNtFlushBuffersFile); - gOriginalNtQueryFullAttributesFile.Set(sNtDllInterceptor, - "NtQueryFullAttributesFile", - &InterposedNtQueryFullAttributesFile); + sNtDllInterceptor.AddHook( + "NtCreateFile", + reinterpret_cast(InterposedNtCreateFile), + reinterpret_cast(&gOriginalNtCreateFile)); + sNtDllInterceptor.AddHook( + "NtReadFile", + reinterpret_cast(InterposedNtReadFile), + reinterpret_cast(&gOriginalNtReadFile)); + sNtDllInterceptor.AddHook( + "NtReadFileScatter", + reinterpret_cast(InterposedNtReadFileScatter), + reinterpret_cast(&gOriginalNtReadFileScatter)); + sNtDllInterceptor.AddHook( + "NtWriteFile", + reinterpret_cast(InterposedNtWriteFile), + reinterpret_cast(&gOriginalNtWriteFile)); + sNtDllInterceptor.AddHook( + "NtWriteFileGather", + reinterpret_cast(InterposedNtWriteFileGather), + reinterpret_cast(&gOriginalNtWriteFileGather)); + sNtDllInterceptor.AddHook( + "NtFlushBuffersFile", + reinterpret_cast(InterposedNtFlushBuffersFile), + reinterpret_cast(&gOriginalNtFlushBuffersFile)); + sNtDllInterceptor.AddHook( + "NtQueryFullAttributesFile", + reinterpret_cast(InterposedNtQueryFullAttributesFile), + reinterpret_cast(&gOriginalNtQueryFullAttributesFile)); } void From a1d1e03224b998ff20c59c044fc4a91286e177ca Mon Sep 17 00:00:00 2001 From: Jamie Nicol Date: Tue, 3 Jul 2018 17:04:51 -0400 Subject: [PATCH 43/57] Bug 1470758 - Ensure we don't merge items with the same frame. r=mattwoodrow --- layout/painting/nsDisplayList.cpp | 4 ++-- layout/painting/nsDisplayList.h | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index 6a71834d58ee..6e4275908835 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -6654,7 +6654,7 @@ nsDisplayBlendMode::CanMerge(const nsDisplayItem* aItem) const { // Items for the same content element should be merged into a single // compositing group. - if (!HasSameTypeAndClip(aItem) || !HasSameContent(aItem)) { + if (!HasDifferentFrame(aItem) || !HasSameTypeAndClip(aItem) || !HasSameContent(aItem)) { return false; } @@ -9370,7 +9370,7 @@ nsDisplayMask::CanMerge(const nsDisplayItem* aItem) const { // Items for the same content element should be merged into a single // compositing group. - if (!HasSameTypeAndClip(aItem) || !HasSameContent(aItem)) { + if (!HasDifferentFrame(aItem) || !HasSameTypeAndClip(aItem) || !HasSameContent(aItem)) { return false; } diff --git a/layout/painting/nsDisplayList.h b/layout/painting/nsDisplayList.h index 3a948ffcbd5b..b6544eeb03e7 100644 --- a/layout/painting/nsDisplayList.h +++ b/layout/painting/nsDisplayList.h @@ -2791,6 +2791,11 @@ public: return mBackfaceHidden; } + bool HasDifferentFrame(const nsDisplayItem* aOther) const + { + return mFrame != aOther->mFrame; + } + bool HasSameTypeAndClip(const nsDisplayItem* aOther) const { return GetPerFrameKey() == aOther->GetPerFrameKey() && @@ -4973,6 +4978,7 @@ public: virtual void Merge(const nsDisplayItem* aItem) override { MOZ_ASSERT(CanMerge(aItem)); + MOZ_ASSERT(Frame() != aItem->Frame()); MergeFromTrackingMergedFrames(static_cast(aItem)); } @@ -5170,7 +5176,7 @@ public: // items for the same content element should be merged into a single // compositing group // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity - return HasSameTypeAndClip(aItem) && HasSameContent(aItem); + return HasDifferentFrame(aItem) && HasSameTypeAndClip(aItem) && HasSameContent(aItem); } virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override @@ -5403,7 +5409,7 @@ public: { // Items for the same content element should be merged into a single // compositing group. - return HasSameTypeAndClip(aItem) && HasSameContent(aItem) + return HasDifferentFrame(aItem) && HasSameTypeAndClip(aItem) && HasSameContent(aItem) && mIsForBackground == static_cast(aItem)->mIsForBackground; } @@ -6158,7 +6164,7 @@ public: { // Items for the same content element should be merged into a single // compositing group. - return HasSameTypeAndClip(aItem) && HasSameContent(aItem); + return HasDifferentFrame(aItem) && HasSameTypeAndClip(aItem) && HasSameContent(aItem); } virtual void Merge(const nsDisplayItem* aItem) override From f978fedf9003cc373faaa890fe3ea78dc3f33b1c Mon Sep 17 00:00:00 2001 From: Narcis Beleuzu Date: Wed, 4 Jul 2018 04:49:52 +0300 Subject: [PATCH 44/57] Backed out 1 changesets (bug 1468523) for mochitest failures on test_bug475636.html. CLOSED TREE Backed out changeset 93540ca16c31 (bug 1468523) --- docshell/base/nsDocShell.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index ea211bd85f89..5c4ea1257df7 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -6219,8 +6219,6 @@ nsDocShell::ForceRefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal, int32_t aDel */ loadInfo->SetReferrer(mCurrentURI); - loadInfo->SetOriginalURI(mCurrentURI); - // Set the triggering pricipal to aPrincipal if available, or current // document's principal otherwise. nsCOMPtr principal = aPrincipal; From 4572b1b56172d51152acae0248df46b4edb0ac74 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:48:05 -0600 Subject: [PATCH 45/57] Bug 1460022: Part 1 - Modify DLL interceptor to use one-time initialization when setting hooks; r=handyman This patch makes the interceptor's AddHook functions private, and converts the stubs from simple function pointers into objects containing both the stub function pointer, plus a INIT_ONCE sentinel. Setting a hook now requires calling Set or SetDetour on the stub, which ensures that the hook attempt happens once and only once. The constructor for the new object is constexpr, so it should not generate static initializers if it is declared statically. Note that, as a corollary of the new behaviour, we no longer need to set guards around any hook setting code. I have removed those when present. --- mozglue/misc/nsWindowsDllInterceptor.h | 153 ++++++++++++++++++++++++- 1 file changed, 151 insertions(+), 2 deletions(-) diff --git a/mozglue/misc/nsWindowsDllInterceptor.h b/mozglue/misc/nsWindowsDllInterceptor.h index 3020f795fede..4ae504257b56 100644 --- a/mozglue/misc/nsWindowsDllInterceptor.h +++ b/mozglue/misc/nsWindowsDllInterceptor.h @@ -8,10 +8,12 @@ #define NS_WINDOWS_DLL_INTERCEPTOR_H_ #include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" #include "mozilla/ArrayUtils.h" #include "mozilla/CheckedInt.h" #include "mozilla/DebugOnly.h" -#include "mozilla/NotNull.h" +#include "mozilla/Move.h" +#include "mozilla/Tuple.h" #include "mozilla/TypeTraits.h" #include "mozilla/Types.h" #include "mozilla/UniquePtr.h" @@ -82,6 +84,143 @@ namespace mozilla { namespace interceptor { +template +class FuncHook final +{ + template + struct OriginalFunctionPtrTraits; + + template + struct OriginalFunctionPtrTraits + { + using ReturnType = R; + }; + +#if defined(_M_IX86) + template + struct OriginalFunctionPtrTraits + { + using ReturnType = R; + }; + + template + struct OriginalFunctionPtrTraits + { + using ReturnType = R; + }; +#endif // defined(_M_IX86) + +public: + using ThisType = FuncHook; + using ReturnType = typename OriginalFunctionPtrTraits::ReturnType; + + constexpr FuncHook() + : mOrigFunc(nullptr) + , mInitOnce(INIT_ONCE_STATIC_INIT) + { + } + + ~FuncHook() = default; + + bool Set(InterceptorT& aInterceptor, const char* aName, + FuncPtrT aHookDest) + { + LPVOID addHookOk; + InitOnceContext ctx(this, &aInterceptor, aName, aHookDest, false); + + return ::InitOnceExecuteOnce(&mInitOnce, &InitOnceCallback, &ctx, + &addHookOk) && addHookOk; + } + + bool SetDetour(InterceptorT& aInterceptor, const char* aName, + FuncPtrT aHookDest) + { + LPVOID addHookOk; + InitOnceContext ctx(this, &aInterceptor, aName, aHookDest, true); + + return ::InitOnceExecuteOnce(&mInitOnce, &InitOnceCallback, &ctx, + &addHookOk) && addHookOk; + } + + explicit operator bool() const + { + return !!mOrigFunc; + } + + template + ReturnType operator()(ArgsType... aArgs) const + { + return mOrigFunc(std::forward(aArgs)...); + } + + FuncPtrT GetStub() const + { + return mOrigFunc; + } + + // One-time init stuff cannot be moved or copied + FuncHook(const FuncHook&) = delete; + FuncHook(FuncHook&&) = delete; + FuncHook& operator=(const FuncHook&) = delete; + FuncHook& operator=(FuncHook&& aOther) = delete; + +private: + struct MOZ_RAII InitOnceContext final + { + InitOnceContext(ThisType* aHook, InterceptorT* aInterceptor, + const char* aName, void* aHookDest, bool aForceDetour) + : mHook(aHook) + , mInterceptor(aInterceptor) + , mName(aName) + , mHookDest(aHookDest) + , mForceDetour(aForceDetour) + { + } + + ThisType* mHook; + InterceptorT* mInterceptor; + const char* mName; + void* mHookDest; + bool mForceDetour; + }; + +private: + bool Apply(InterceptorT* aInterceptor, const char* aName, void* aHookDest) + { + return aInterceptor->AddHook(aName, reinterpret_cast(aHookDest), + reinterpret_cast(&mOrigFunc)); + } + + bool ApplyDetour(InterceptorT* aInterceptor, const char* aName, + void* aHookDest) + { + return aInterceptor->AddDetour(aName, reinterpret_cast(aHookDest), + reinterpret_cast(&mOrigFunc)); + } + + static BOOL CALLBACK + InitOnceCallback(PINIT_ONCE aInitOnce, PVOID aParam, PVOID* aOutContext) + { + MOZ_ASSERT(aOutContext); + + bool result; + auto ctx = reinterpret_cast(aParam); + if (ctx->mForceDetour) { + result = ctx->mHook->ApplyDetour(ctx->mInterceptor, ctx->mName, + ctx->mHookDest); + } else { + result = ctx->mHook->Apply(ctx->mInterceptor, ctx->mName, ctx->mHookDest); + } + + *aOutContext = result ? reinterpret_cast(1U << INIT_ONCE_CTX_RESERVED_BITS) : nullptr; + return TRUE; + } + +private: + FuncPtrT mOrigFunc; + INIT_ONCE mInitOnce; +}; + enum { kDefaultTrampolineSize = 128 @@ -92,6 +231,8 @@ template > class WindowsDllInterceptor final { + typedef WindowsDllInterceptor ThisType; + interceptor::WindowsDllDetourPatcher mDetourPatcher; #if defined(_M_IX86) interceptor::WindowsDllNopSpacePatcher mNopSpacePatcher; @@ -160,6 +301,7 @@ public: // NB: We intentionally leak mModule } +private: /** * Hook/detour the method aName from the DLL we set in Init so that it calls * aHookDest instead. Returns the original method pointer in aOrigFunc @@ -219,7 +361,6 @@ public: return AddDetour(proc, aHookDest, aOrigFunc); } -private: bool AddDetour(FARPROC aProc, intptr_t aHookDest, void** aOrigFunc) { MOZ_ASSERT(mModule && aProc); @@ -230,6 +371,14 @@ private: return mDetourPatcher.AddHook(aProc, aHookDest, aOrigFunc); } + +public: + template + using FuncHookType = FuncHook; + +private: + template + friend class FuncHook; }; } // namespace interceptor From 084151562b02da67a7e1dc72be2cd6d9e1298a15 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:48:28 -0600 Subject: [PATCH 46/57] Bug 1460022: Part 2 - Update TestDllInterceptor to use new DLL interceptor interface; r=handyman In addition to updating the interface, this patch also significantly alters the structure of this test. In particular, it removes the Test* functions in favour of using template magic. I did this because I noticed that, in the majority of cases, the stub function was being called with all zero arguments, and then we check for the expected error code. I thought that maybe we could replace that repetition with some templates that instantiate a blank tuple that may then be applied to a callable object. See the (MAYBE_)TEST_HOOK* and TEST_DETOUR* macro definitions for detailed information about how to use these things. The test successfully completes with both 32-bit and 64-bit builds. --- .../tests/interceptor/TestDllInterceptor.cpp | 857 +++++++----------- 1 file changed, 330 insertions(+), 527 deletions(-) diff --git a/mozglue/tests/interceptor/TestDllInterceptor.cpp b/mozglue/tests/interceptor/TestDllInterceptor.cpp index 6007a8995201..989ee97d0b28 100644 --- a/mozglue/tests/interceptor/TestDllInterceptor.cpp +++ b/mozglue/tests/interceptor/TestDllInterceptor.cpp @@ -10,10 +10,33 @@ #include #include +#include "mozilla/TypeTraits.h" +#include "mozilla/UniquePtr.h" #include "mozilla/WindowsVersion.h" #include "nsWindowsDllInterceptor.h" #include "nsWindowsHelpers.h" +NTSTATUS NTAPI NtFlushBuffersFile(HANDLE, PIO_STATUS_BLOCK); +NTSTATUS NTAPI NtReadFile(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PVOID, ULONG, + PLARGE_INTEGER, PULONG); +NTSTATUS NTAPI NtReadFileScatter(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, + PLARGE_INTEGER, PULONG); +NTSTATUS NTAPI NtWriteFile(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PVOID, ULONG, + PLARGE_INTEGER, PULONG); +NTSTATUS NTAPI NtWriteFileGather(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, + PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, + PLARGE_INTEGER, PULONG); +NTSTATUS NTAPI NtQueryFullAttributesFile(POBJECT_ATTRIBUTES, PVOID); +NTSTATUS NTAPI LdrLoadDll(PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle); +NTSTATUS NTAPI LdrUnloadDll(HMODULE); +// These pointers are disguised as PVOID to avoid pulling in obscure headers +PVOID NTAPI LdrResolveDelayLoadedAPI(PVOID, PVOID, PVOID, PVOID, PVOID, ULONG); +void CALLBACK ProcessCaretEvents(HWINEVENTHOOK, DWORD, HWND, LONG, LONG, DWORD, DWORD); +void __fastcall BaseThreadInitThunk(BOOL aIsInitialThread, void* aStartAddress, void* aThreadParam); + using namespace mozilla; struct payload { @@ -38,7 +61,8 @@ extern "C" __declspec(dllexport) __declspec(noinline) payload rotatePayload(payl static bool patched_func_called = false; -static payload (*orig_rotatePayload)(payload); +static WindowsDllInterceptor::FuncHookType + orig_rotatePayload; static payload patched_rotatePayload(payload p) @@ -47,11 +71,61 @@ patched_rotatePayload(payload p) return orig_rotatePayload(p); } -typedef bool(*HookTestFunc)(void*); -bool CheckHook(HookTestFunc aHookTestFunc, void* aOrigFunc, - const char* aDllName, const char* aFuncName) +// Invoke aFunc by taking aArg's contents and using them as aFunc's arguments +template , size_t... Indices> +decltype(auto) Apply(CallableT&& aFunc, ArgTuple&& aArgs, std::index_sequence) { - if (aHookTestFunc(aOrigFunc)) { + return std::forward(aFunc)(Get(std::forward(aArgs))...); +} + +template +bool TestFunction(CallableT aFunc); + +#define DEFINE_TEST_FUNCTION(calling_convention) \ + template \ + bool TestFunction(WindowsDllInterceptor::FuncHookType&& aFunc, \ + bool (* aPred)(R), TestArgs... aArgs) \ + { \ + using FuncHookType = WindowsDllInterceptor::FuncHookType; \ + using ArgTuple = Tuple; \ + using Indices = std::index_sequence_for; \ + ArgTuple fakeArgs{ std::forward(aArgs)... }; \ + return aPred(Apply(std::forward(aFunc), std::forward(fakeArgs), Indices())); \ + } \ + \ + /* Specialization for functions returning void */ \ + template \ + bool TestFunction(WindowsDllInterceptor::FuncHookType&& aFunc, \ + PredicateT&& aPred, TestArgs... aArgs) \ + { \ + using FuncHookType = WindowsDllInterceptor::FuncHookType; \ + using ArgTuple = Tuple; \ + using Indices = std::index_sequence_for; \ + ArgTuple fakeArgs{ std::forward(aArgs)... }; \ + Apply(std::forward(aFunc), std::forward(fakeArgs), Indices()); \ + return true; \ + } + +// C++11 allows empty arguments to macros. clang works just fine. MSVC does the +// right thing, but it also throws up warning C4003. +#if defined(_MSC_VER) && !defined(__clang__) +DEFINE_TEST_FUNCTION(__cdecl) +#else +DEFINE_TEST_FUNCTION() +#endif + +#ifdef _M_IX86 +DEFINE_TEST_FUNCTION(__stdcall) +DEFINE_TEST_FUNCTION(__fastcall) +#endif // _M_IX86 + +// Test the hooked function against the supplied predicate +template +bool CheckHook(WindowsDllInterceptor::FuncHookType &aOrigFunc, + const char* aDllName, const char* aFuncName, PredicateT&& aPred, + Args... aArgs) +{ + if (TestFunction(std::forward>(aOrigFunc), std::forward(aPred), std::forward(aArgs)...)) { printf("TEST-PASS | WindowsDllInterceptor | " "Executed hooked function %s from %s\n", aFuncName, aDllName); return true; @@ -61,57 +135,235 @@ bool CheckHook(HookTestFunc aHookTestFunc, void* aOrigFunc, return false; } -template -bool TestHook(HookTestFunc funcTester, const char (&dll)[N], const char *func) +// Hook the function and optionally attempt calling it +template +bool TestHook(const char (&dll)[N], const char *func, PredicateT&& aPred, Args... aArgs) { - void *orig_func; + auto orig_func(mozilla::MakeUnique>()); + bool successful = false; { WindowsDllInterceptor TestIntercept; TestIntercept.Init(dll); - successful = TestIntercept.AddHook(func, 0, &orig_func); + successful = orig_func->Set(TestIntercept, func, nullptr); } if (successful) { printf("TEST-PASS | WindowsDllInterceptor | Could hook %s from %s\n", func, dll); - return CheckHook(funcTester, orig_func, dll, func); + if (!aPred) { + printf("TEST-SKIPPED | WindowsDllInterceptor | " + "Will not attempt to execute patched %s.\n", func); + return true; + } + + return CheckHook(*orig_func, dll, func, std::forward(aPred), std::forward(aArgs)...); } else { printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to hook %s from %s\n", func, dll); return false; } } -template -bool TestDetour(const char (&dll)[N], const char *func) +// Detour the function and optionally attempt calling it +template +bool TestDetour(const char (&dll)[N], const char *func, PredicateT&& aPred) { - void *orig_func; + auto orig_func(mozilla::MakeUnique>()); + bool successful = false; { WindowsDllInterceptor TestIntercept; TestIntercept.Init(dll); - successful = TestIntercept.AddDetour(func, 0, &orig_func); + successful = orig_func->SetDetour(TestIntercept, func, nullptr); } if (successful) { printf("TEST-PASS | WindowsDllInterceptor | Could detour %s from %s\n", func, dll); - return true; + if (!aPred) { + printf("TEST-SKIPPED | WindowsDllInterceptor | " + "Will not attempt to execute patched %s.\n", func); + return true; + } + + return CheckHook(*orig_func, dll, func, std::forward(aPred)); } else { printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to detour %s from %s\n", func, dll); return false; } } -template -bool MaybeTestHook(const bool cond, HookTestFunc funcTester, const char (&dll)[N], const char* func) +// If a function pointer's type returns void*, this template converts that type +// to return uintptr_t instead, for the purposes of predicates. +template +struct SubstituteForVoidPtr +{ + using Type = FuncT; +}; + +template +struct SubstituteForVoidPtr +{ + using Type = uintptr_t (*)(Args...); +}; + +#ifdef _M_IX86 +template +struct SubstituteForVoidPtr +{ + using Type = uintptr_t (__stdcall*)(Args...); +}; + +template +struct SubstituteForVoidPtr +{ + using Type = uintptr_t (__fastcall*)(Args...); +}; +#endif // _M_IX86 + +// Determines the function's return type +template +struct ReturnType; + +template +struct ReturnType +{ + using Type = R; +}; + +#ifdef _M_IX86 +template +struct ReturnType +{ + using Type = R; +}; + +template +struct ReturnType +{ + using Type = R; +}; +#endif // _M_IX86 + +// Predicates that may be supplied during tests +template +struct Predicates +{ + using ArgType = typename ReturnType::Type; + + template + static bool Equals(ArgType aValue) + { + return CompVal == aValue; + } + + template + static bool NotEquals(ArgType aValue) + { + return CompVal != aValue; + } + + template + static bool Ignore(ArgType aValue) + { + return true; + } +}; + +// Functions that return void should be ignored, so we specialize the +// Ignore predicate for that case. Use nullptr as the value to compare against. +template +struct Predicates +{ + template + static bool Ignore() + { + return true; + } +}; + +#ifdef _M_IX86 +template +struct Predicates +{ + template + static bool Ignore() + { + return true; + } +}; + +template +struct Predicates +{ + template + static bool Ignore() + { + return true; + } +}; +#endif // _M_IX86 + +// The standard test. Hook |func|, and then try executing it with all zero +// arguments, using |pred| and |comp| to determine whether the call successfully +// executed. In general, you want set pred and comp such that they return true +// when the function is returning whatever value is expected with all-zero +// arguments. +// +// Note: When |func| returns void, you must supply |Ignore| and |nullptr| as the +// |pred| and |comp| arguments, respectively. +#define TEST_HOOK(dll, func, pred, comp) \ + TestHook(#dll, #func, &Predicates::pred) + +// We need to special-case functions that return INVALID_HANDLE_VALUE +// (ie, CreateFile). Our template machinery for comparing values doesn't work +// with integer constants passed as pointers (well, it works on MSVC, but not +// clang, because that is not standard-compliant). +#define TEST_HOOK_FOR_INVALID_HANDLE_VALUE(dll, func) \ + TestHook::Type>(#dll, #func, &Predicates::Type>::Equals) + +// This variant allows you to explicitly supply arguments to the hooked function +// during testing. You want to provide arguments that produce the conditions that +// induce the function to return a value that is accepted by your predicate. +#define TEST_HOOK_PARAMS(dll, func, pred, comp, ...) \ + TestHook(#dll, #func, &Predicates::pred, __VA_ARGS__) + +// This is for cases when we want to hook |func|, but it is unsafe to attempt +// to execute the function in the context of a test. +#define TEST_HOOK_SKIP_EXEC(dll, func) \ + TestHook(#dll, #func, reinterpret_cast::Type)>(NULL)) + +// The following three variants are identical to the previous macros, +// however the forcibly use a Detour on 32-bit Windows. On 64-bit Windows, +// these macros are identical to their TEST_HOOK variants. +#define TEST_DETOUR(dll, func, pred, comp) \ + TestDetour(#dll, #func, &Predicates::pred) + +#define TEST_DETOUR_PARAMS(dll, func, pred, comp, ...) \ + TestDetour(#dll, #func, &Predicates::pred, __VA_ARGS__) + +#define TEST_DETOUR_SKIP_EXEC(dll, func) \ + TestDetour(#dll, #func, reinterpret_cast::Type)>(NULL)) + +template +bool MaybeTestHook(const bool cond, const char (&dll)[N], const char *func, PredicateT&& aPred, Args... aArgs) { if (!cond) { printf("TEST-SKIPPED | WindowsDllInterceptor | Skipped hook test for %s from %s\n", func, dll); return true; } - return TestHook(funcTester, dll, func); + return TestHook(dll, func, std::forward(aPred), std::forward(aArgs)...); } +// Like TEST_HOOK, but the test is only executed when cond is true. +#define MAYBE_TEST_HOOK(cond, dll, func, pred, comp) \ + MaybeTestHook(cond, #dll, #func, &Predicates::pred) + +#define MAYBE_TEST_HOOK_PARAMS(cond, dll, func, pred, comp, ...) \ + MaybeTestHook(cond, #dll, #func, &Predicates::pred, __VA_ARGS__) + +#define MAYBE_TEST_HOOK_SKIP_EXEC(cond, dll, func) \ + MaybeTestHook(cond, #dll, #func, reinterpret_cast::Type)>(NULL)) + bool ShouldTestTipTsf() { if (!IsWin8OrLater()) { @@ -147,455 +399,6 @@ bool ShouldTestTipTsf() return true; } -// These test the patched function returned by the DLL -// interceptor. They check that the patched assembler preamble does -// something sane. The parameter is a pointer to the patched function. -bool TestGetWindowInfo(void* aFunc) -{ - auto patchedGetWindowInfo = - reinterpret_cast(aFunc); - return patchedGetWindowInfo(0, 0) == FALSE; -} - -bool TestSetWindowLongPtr(void* aFunc) -{ - auto patchedSetWindowLongPtr = - reinterpret_cast(aFunc); - return patchedSetWindowLongPtr(0, 0, 0) == 0; -} - -bool TestSetWindowLong(void* aFunc) -{ - auto patchedSetWindowLong = - reinterpret_cast(aFunc); - return patchedSetWindowLong(0, 0, 0) == 0; -} - -bool TestTrackPopupMenu(void* aFunc) -{ - auto patchedTrackPopupMenu = - reinterpret_cast(aFunc); - return patchedTrackPopupMenu(0, 0, 0, 0, 0, 0, 0) == 0; -} - -bool TestNtFlushBuffersFile(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtFlushBuffersFileType)(HANDLE, PIO_STATUS_BLOCK); - auto patchedNtFlushBuffersFile = - reinterpret_cast(aFunc); - patchedNtFlushBuffersFile(0, 0); - return true; -} - -bool TestNtCreateFile(void* aFunc) -{ - auto patchedNtCreateFile = - reinterpret_cast(aFunc); - return patchedNtCreateFile(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; -} - -bool TestNtReadFile(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtReadFileType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PVOID, ULONG, - PLARGE_INTEGER, PULONG); - auto patchedNtReadFile = - reinterpret_cast(aFunc); - return patchedNtReadFile(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; -} - -bool TestNtReadFileScatter(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtReadFileScatterType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, - PLARGE_INTEGER, PULONG); - auto patchedNtReadFileScatter = - reinterpret_cast(aFunc); - return patchedNtReadFileScatter(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; -} - -bool TestNtWriteFile(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtWriteFileType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PVOID, ULONG, - PLARGE_INTEGER, PULONG); - auto patchedNtWriteFile = - reinterpret_cast(aFunc); - return patchedNtWriteFile(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; -} - -bool TestNtWriteFileGather(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtWriteFileGatherType)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, - PIO_STATUS_BLOCK, PFILE_SEGMENT_ELEMENT, ULONG, - PLARGE_INTEGER, PULONG); - auto patchedNtWriteFileGather = - reinterpret_cast(aFunc); - return patchedNtWriteFileGather(0, 0, 0, 0, 0, 0, 0, 0, 0) != 0; -} - -bool TestNtQueryFullAttributesFile(void* aFunc) -{ - typedef NTSTATUS(WINAPI *NtQueryFullAttributesFileType)(POBJECT_ATTRIBUTES, - PVOID); - auto patchedNtQueryFullAttributesFile = - reinterpret_cast(aFunc); - return patchedNtQueryFullAttributesFile(0, 0) != 0; -} - -bool TestLdrUnloadDll(void* aFunc) -{ - typedef NTSTATUS (NTAPI *LdrUnloadDllType)(HMODULE); - auto patchedLdrUnloadDll = reinterpret_cast(aFunc); - return patchedLdrUnloadDll(0) != 0; -} - -bool TestLdrResolveDelayLoadedAPI(void* aFunc) -{ - // These pointers are disguised as PVOID to avoid pulling in obscure headers - typedef PVOID (WINAPI *LdrResolveDelayLoadedAPIType)(PVOID, PVOID, PVOID, - PVOID, PVOID, ULONG); - auto patchedLdrResolveDelayLoadedAPI = - reinterpret_cast(aFunc); - // No idea how to call this API. Flags==99 is just an arbitrary number that - // doesn't crash when the other params are null. - return patchedLdrResolveDelayLoadedAPI(0, 0, 0, 0, 0, 99) == 0; -} - -#ifdef _M_AMD64 -bool TestRtlInstallFunctionTableCallback(void* aFunc) -{ - auto patchedRtlInstallFunctionTableCallback = - reinterpret_cast(aFunc); - - return patchedRtlInstallFunctionTableCallback(0, 0, 0, 0, 0, 0) == FALSE; -} -#endif - -bool TestSetUnhandledExceptionFilter(void* aFunc) -{ - auto patchedSetUnhandledExceptionFilter = - reinterpret_cast(aFunc); - // Retrieve the current filter as we set the new filter to null, then restore the current filter. - LPTOP_LEVEL_EXCEPTION_FILTER current = patchedSetUnhandledExceptionFilter(0); - patchedSetUnhandledExceptionFilter(current); - return true; -} - -bool TestVirtualAlloc(void* aFunc) -{ - auto patchedVirtualAlloc = - reinterpret_cast(aFunc); - return patchedVirtualAlloc(0, 0, 0, 0) == 0; -} - -bool TestMapViewOfFile(void* aFunc) -{ - auto patchedMapViewOfFile = - reinterpret_cast(aFunc); - return patchedMapViewOfFile(0, 0, 0, 0, 0) == 0; -} - -bool TestCreateDIBSection(void* aFunc) -{ - auto patchedCreateDIBSection = - reinterpret_cast(aFunc); - // MSDN is wrong here. This does not return ERROR_INVALID_PARAMETER. It - // sets the value of GetLastError to ERROR_INVALID_PARAMETER. - // CreateDIBSection returns 0 on error. - return patchedCreateDIBSection(0, 0, 0, 0, 0, 0) == 0; -} - -bool TestCreateFileW(void* aFunc) -{ - auto patchedCreateFileW = - reinterpret_cast(aFunc); - return patchedCreateFileW(0, 0, 0, 0, 0, 0, 0) == INVALID_HANDLE_VALUE; -} - -bool TestCreateFileA(void* aFunc) -{ - auto patchedCreateFileA = - reinterpret_cast(aFunc); -// return patchedCreateFileA(0, 0, 0, 0, 0, 0, 0) == INVALID_HANDLE_VALUE; - printf("TEST-SKIPPED | WindowsDllInterceptor | " - "Will not attempt to execute patched CreateFileA -- patched method is known to fail.\n"); - return true; -} - -bool TestQueryDosDeviceW(void* aFunc) -{ - auto patchedQueryDosDeviceW = - reinterpret_cast(aFunc); - return patchedQueryDosDeviceW(nullptr, nullptr, 0) == 0; -} - -bool TestInSendMessageEx(void* aFunc) -{ - auto patchedInSendMessageEx = - reinterpret_cast(aFunc); - patchedInSendMessageEx(0); - return true; -} - -bool TestImmGetContext(void* aFunc) -{ - auto patchedImmGetContext = - reinterpret_cast(aFunc); - patchedImmGetContext(0); - return true; -} - -bool TestImmGetCompositionStringW(void* aFunc) -{ - auto patchedImmGetCompositionStringW = - reinterpret_cast(aFunc); - patchedImmGetCompositionStringW(0, 0, 0, 0); - return true; -} - -bool TestImmSetCandidateWindow(void* aFunc) -{ - auto patchedImmSetCandidateWindow = - reinterpret_cast(aFunc); -// return patchedImmSetCandidateWindow(0, 0) == 0; - // ImmSetCandidateWindow crashes if given bad parameters. - printf("TEST-SKIPPED | WindowsDllInterceptor | " - "Will not attempt to execute patched ImmSetCandidateWindow.\n"); - return true; -} - -bool TestImmNotifyIME(void* aFunc) -{ - auto patchedImmNotifyIME = - reinterpret_cast(aFunc); - return patchedImmNotifyIME(0, 0, 0, 0) == 0; -} - -bool TestGetSaveFileNameW(void* aFunc) -{ - auto patchedGetSaveFileNameWType = - reinterpret_cast(aFunc); - patchedGetSaveFileNameWType(0); - return true; -} - -bool TestGetOpenFileNameW(void* aFunc) -{ - auto patchedGetOpenFileNameWType = - reinterpret_cast(aFunc); - patchedGetOpenFileNameWType(0); - return true; -} - -bool TestGetKeyState(void* aFunc) -{ - auto patchedGetKeyState = - reinterpret_cast(aFunc); - patchedGetKeyState(0); - return true; -} - -bool TestSendMessageTimeoutW(void* aFunc) -{ - auto patchedSendMessageTimeoutW = - reinterpret_cast(aFunc); - return patchedSendMessageTimeoutW(0, 0, 0, 0, 0, 0, 0) == 0; -} - -bool TestProcessCaretEvents(void* aFunc) -{ - auto patchedProcessCaretEvents = - reinterpret_cast(aFunc); - patchedProcessCaretEvents(0, 0, 0, 0, 0, 0, 0); - return true; -} - -bool TestSetCursorPos(void* aFunc) -{ - // SetCursorPos has some issues in automation -- see bug 1368033. - // For that reason, we don't check the return value -- we only - // check that the method runs without producing an exception. - auto patchedSetCursorPos = - reinterpret_cast(aFunc); - patchedSetCursorPos(512, 512); - return true; -} - -static DWORD sTlsIndex = 0; - -bool TestTlsAlloc(void* aFunc) -{ - auto patchedTlsAlloc = - reinterpret_cast(aFunc); - sTlsIndex = patchedTlsAlloc(); - return sTlsIndex != TLS_OUT_OF_INDEXES; -} - -bool TestTlsFree(void* aFunc) -{ - auto patchedTlsFree = - reinterpret_cast(aFunc); - return sTlsIndex != 0 && patchedTlsFree(sTlsIndex); -} - -bool TestCloseHandle(void* aFunc) -{ - auto patchedCloseHandle = - reinterpret_cast(aFunc); - return patchedCloseHandle(0) == FALSE; -} - -bool TestDuplicateHandle(void* aFunc) -{ - auto patchedDuplicateHandle = - reinterpret_cast(aFunc); - return patchedDuplicateHandle(0, 0, 0, 0, 0, 0, 0) == FALSE; -} - -bool TestPrintDlgW(void* aFunc) -{ - auto patchedPrintDlgW = - reinterpret_cast(aFunc); - patchedPrintDlgW(0); - return true; -} - -bool TestInternetConnectA(void* aFunc) -{ - auto patchedInternetConnectA = - reinterpret_cast(aFunc); - return patchedInternetConnectA(0, 0, 0, 0, 0, 0, 0, 0) == 0; -} - -HINTERNET sInternet = 0; - -bool TestInternetOpenA(void* aFunc) -{ - auto patchedInternetOpenA = - reinterpret_cast(aFunc); - sInternet = patchedInternetOpenA(0, 0, 0, 0, 0); - return sInternet != 0; -} - -bool TestInternetCloseHandle(void* aFunc) -{ - auto patchedInternetCloseHandle = - reinterpret_cast(aFunc); - return patchedInternetCloseHandle(sInternet); -} - -bool TestInternetQueryDataAvailable(void* aFunc) -{ - auto patchedInternetQueryDataAvailable = - reinterpret_cast(aFunc); - return patchedInternetQueryDataAvailable(0, 0, 0, 0) == FALSE; -} - -bool TestInternetReadFile(void* aFunc) -{ - auto patchedInternetReadFile = - reinterpret_cast(aFunc); - return patchedInternetReadFile(0, 0, 0, 0) == FALSE; -} - -bool TestInternetWriteFile(void* aFunc) -{ - auto patchedInternetWriteFile = - reinterpret_cast(aFunc); - return patchedInternetWriteFile(0, 0, 0, 0) == FALSE; -} - -bool TestInternetSetOptionA(void* aFunc) -{ - auto patchedInternetSetOptionA = - reinterpret_cast(aFunc); - return patchedInternetSetOptionA(0, 0, 0, 0) == FALSE; -} - -bool TestHttpAddRequestHeadersA(void* aFunc) -{ - auto patchedHttpAddRequestHeadersA = - reinterpret_cast(aFunc); - return patchedHttpAddRequestHeadersA(0, 0, 0, 0) == FALSE; -} - -bool TestHttpOpenRequestA(void* aFunc) -{ - auto patchedHttpOpenRequestA = - reinterpret_cast(aFunc); - return patchedHttpOpenRequestA(0, 0, 0, 0, 0, 0, 0, 0) == 0; -} - -bool TestHttpQueryInfoA(void* aFunc) -{ - auto patchedHttpQueryInfoA = - reinterpret_cast(aFunc); - return patchedHttpQueryInfoA(0, 0, 0, 0, 0) == FALSE; -} - -bool TestHttpSendRequestA(void* aFunc) -{ - auto patchedHttpSendRequestA = - reinterpret_cast(aFunc); - return patchedHttpSendRequestA(0, 0, 0, 0, 0) == FALSE; -} - -bool TestHttpSendRequestExA(void* aFunc) -{ - auto patchedHttpSendRequestExA = - reinterpret_cast(aFunc); - return patchedHttpSendRequestExA(0, 0, 0, 0, 0) == FALSE; -} - -bool TestHttpEndRequestA(void* aFunc) -{ - auto patchedHttpEndRequestA = - reinterpret_cast(aFunc); - return patchedHttpEndRequestA(0, 0, 0, 0) == FALSE; -} - -bool TestInternetQueryOptionA(void* aFunc) -{ - auto patchedInternetQueryOptionA = - reinterpret_cast(aFunc); - return patchedInternetQueryOptionA(0, 0, 0, 0) == FALSE; -} - -bool TestInternetErrorDlg(void* aFunc) -{ - auto patchedInternetErrorDlg = - reinterpret_cast(aFunc); - return patchedInternetErrorDlg(0, 0, 0, 0, 0) == ERROR_INVALID_HANDLE; -} - -CredHandle sCredHandle; - -bool TestAcquireCredentialsHandleA(void* aFunc) -{ - auto patchedAcquireCredentialsHandleA = - reinterpret_cast(aFunc); - SCHANNEL_CRED cred; - memset(&cred, 0, sizeof(cred)); - cred.dwVersion = SCHANNEL_CRED_VERSION; - return patchedAcquireCredentialsHandleA(0, UNISP_NAME, SECPKG_CRED_OUTBOUND, - 0, &cred, 0, 0, &sCredHandle, 0) == S_OK; -} - -bool TestQueryCredentialsAttributesA(void* aFunc) -{ - auto patchedQueryCredentialsAttributesA = - reinterpret_cast(aFunc); - return patchedQueryCredentialsAttributesA(&sCredHandle, 0, 0) == SEC_E_UNSUPPORTED_FUNCTION; -} - -bool TestFreeCredentialsHandle(void* aFunc) -{ - auto patchedFreeCredentialsHandle = - reinterpret_cast(aFunc); - return patchedFreeCredentialsHandle(&sCredHandle) == S_OK; -} - int main() { LARGE_INTEGER start; @@ -615,7 +418,7 @@ int main() { WindowsDllInterceptor ExeIntercept; ExeIntercept.Init("TestDllInterceptor.exe"); - if (ExeIntercept.AddHook("rotatePayload", reinterpret_cast(patched_rotatePayload), (void**) &orig_rotatePayload)) { + if (orig_rotatePayload.Set(ExeIntercept, "rotatePayload", &patched_rotatePayload)) { printf("TEST-PASS | WindowsDllInterceptor | Hook added\n"); } else { printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to add hook\n"); @@ -659,85 +462,85 @@ int main() } #endif - if (TestHook(TestGetWindowInfo, "user32.dll", "GetWindowInfo") && + if (TEST_HOOK(user32.dll, GetWindowInfo, Equals, FALSE) && #ifdef _WIN64 - TestHook(TestSetWindowLongPtr, "user32.dll", "SetWindowLongPtrA") && - TestHook(TestSetWindowLongPtr, "user32.dll", "SetWindowLongPtrW") && + TEST_HOOK(user32.dll, SetWindowLongPtrA, Equals, 0) && + TEST_HOOK(user32.dll, SetWindowLongPtrW, Equals, 0) && #else - TestHook(TestSetWindowLong, "user32.dll", "SetWindowLongA") && - TestHook(TestSetWindowLong, "user32.dll", "SetWindowLongW") && + TEST_HOOK(user32.dll, SetWindowLongA, Equals, 0) && + TEST_HOOK(user32.dll, SetWindowLongW, Equals, 0) && #endif - TestHook(TestTrackPopupMenu, "user32.dll", "TrackPopupMenu") && + TEST_HOOK(user32.dll, TrackPopupMenu, Equals, FALSE) && #ifdef _M_IX86 // We keep this test to hook complex code on x86. (Bug 850957) - TestHook(TestNtFlushBuffersFile, "ntdll.dll", "NtFlushBuffersFile") && + TEST_HOOK(ntdll.dll, NtFlushBuffersFile, NotEquals, 0) && #endif - TestHook(TestNtCreateFile, "ntdll.dll", "NtCreateFile") && - TestHook(TestNtReadFile, "ntdll.dll", "NtReadFile") && - TestHook(TestNtReadFileScatter, "ntdll.dll", "NtReadFileScatter") && - TestHook(TestNtWriteFile, "ntdll.dll", "NtWriteFile") && - TestHook(TestNtWriteFileGather, "ntdll.dll", "NtWriteFileGather") && - TestHook(TestNtQueryFullAttributesFile, "ntdll.dll", "NtQueryFullAttributesFile") && + TEST_HOOK(ntdll.dll, NtCreateFile, NotEquals, 0) && + TEST_HOOK(ntdll.dll, NtReadFile, NotEquals, 0) && + TEST_HOOK(ntdll.dll, NtReadFileScatter, NotEquals, 0) && + TEST_HOOK(ntdll.dll, NtWriteFile, NotEquals, 0) && + TEST_HOOK(ntdll.dll, NtWriteFileGather, NotEquals, 0) && + TEST_HOOK(ntdll.dll, NtQueryFullAttributesFile, NotEquals, 0) && #ifndef MOZ_ASAN // Bug 733892: toolkit/crashreporter/nsExceptionHandler.cpp // This fails on ASan because the ASan runtime already hooked this function - TestHook(TestSetUnhandledExceptionFilter, "kernel32.dll", "SetUnhandledExceptionFilter") && + TEST_HOOK(kernel32.dll, SetUnhandledExceptionFilter, Ignore, nullptr) && #endif #ifdef _M_IX86 // Bug 670967: xpcom/base/AvailableMemoryTracker.cpp - TestHook(TestVirtualAlloc, "kernel32.dll", "VirtualAlloc") && - TestHook(TestMapViewOfFile, "kernel32.dll", "MapViewOfFile") && - TestHook(TestCreateDIBSection, "gdi32.dll", "CreateDIBSection") && - TestHook(TestCreateFileW, "kernel32.dll", "CreateFileW") && // see Bug 1316415 + TEST_HOOK(kernel32.dll, VirtualAlloc, Equals, nullptr) && + TEST_HOOK(kernel32.dll, MapViewOfFile, Equals, nullptr) && + TEST_HOOK(gdi32.dll, CreateDIBSection, Equals, nullptr) && + TEST_HOOK_FOR_INVALID_HANDLE_VALUE(kernel32.dll, CreateFileW) && #endif - TestHook(TestCreateFileA, "kernel32.dll", "CreateFileA") && - TestHook(TestQueryDosDeviceW, "kernelbase.dll", "QueryDosDeviceW") && - TestDetour("user32.dll", "CreateWindowExW") && - TestHook(TestInSendMessageEx, "user32.dll", "InSendMessageEx") && - TestHook(TestImmGetContext, "imm32.dll", "ImmGetContext") && - TestHook(TestImmGetCompositionStringW, "imm32.dll", "ImmGetCompositionStringW") && - TestHook(TestImmSetCandidateWindow, "imm32.dll", "ImmSetCandidateWindow") && - TestHook(TestImmNotifyIME, "imm32.dll", "ImmNotifyIME") && - TestHook(TestGetSaveFileNameW, "comdlg32.dll", "GetSaveFileNameW") && - TestHook(TestGetOpenFileNameW, "comdlg32.dll", "GetOpenFileNameW") && + TEST_HOOK_FOR_INVALID_HANDLE_VALUE(kernel32.dll, CreateFileA) && + TEST_HOOK(kernelbase.dll, QueryDosDeviceW, Equals, 0) && + TEST_DETOUR(user32.dll, CreateWindowExW, Equals, nullptr) && + TEST_HOOK(user32.dll, InSendMessageEx, Equals, ISMEX_NOSEND) && + TEST_HOOK(imm32.dll, ImmGetContext, Equals, nullptr) && + TEST_HOOK(imm32.dll, ImmGetCompositionStringW, Ignore, 0) && + TEST_HOOK_SKIP_EXEC(imm32.dll, ImmSetCandidateWindow) && + TEST_HOOK(imm32.dll, ImmNotifyIME, Equals, 0) && + TEST_HOOK(comdlg32.dll, GetSaveFileNameW, Ignore, FALSE) && + TEST_HOOK(comdlg32.dll, GetOpenFileNameW, Ignore, FALSE) && #ifdef _M_X64 - TestHook(TestGetKeyState, "user32.dll", "GetKeyState") && // see Bug 1316415 - TestHook(TestLdrUnloadDll, "ntdll.dll", "LdrUnloadDll") && - MaybeTestHook(IsWin8OrLater(), TestLdrResolveDelayLoadedAPI, "ntdll.dll", "LdrResolveDelayLoadedAPI") && - MaybeTestHook(!IsWin8OrLater(), TestRtlInstallFunctionTableCallback, "kernel32.dll", "RtlInstallFunctionTableCallback") && - TestHook(TestPrintDlgW, "comdlg32.dll", "PrintDlgW") && + TEST_HOOK(user32.dll, GetKeyState, Ignore, 0) && // see Bug 1316415 + TEST_HOOK(ntdll.dll, LdrUnloadDll, NotEquals, 0) && + MAYBE_TEST_HOOK_SKIP_EXEC(IsWin8OrLater(), ntdll.dll, LdrResolveDelayLoadedAPI) && + MAYBE_TEST_HOOK(!IsWin8OrLater(), kernel32.dll, RtlInstallFunctionTableCallback, Equals, FALSE) && + TEST_HOOK(comdlg32.dll, PrintDlgW, Ignore, 0) && #endif - MaybeTestHook(ShouldTestTipTsf(), TestProcessCaretEvents, "tiptsf.dll", "ProcessCaretEvents") && + MAYBE_TEST_HOOK(ShouldTestTipTsf(), tiptsf.dll, ProcessCaretEvents, Ignore, nullptr) && #ifdef _M_IX86 - TestHook(TestSendMessageTimeoutW, "user32.dll", "SendMessageTimeoutW") && + TEST_HOOK(user32.dll, SendMessageTimeoutW, Equals, 0) && #endif - TestHook(TestSetCursorPos, "user32.dll", "SetCursorPos") && - TestHook(TestTlsAlloc, "kernel32.dll", "TlsAlloc") && - TestHook(TestTlsFree, "kernel32.dll", "TlsFree") && - TestHook(TestCloseHandle, "kernel32.dll", "CloseHandle") && - TestHook(TestDuplicateHandle, "kernel32.dll", "DuplicateHandle") && + TEST_HOOK(user32.dll, SetCursorPos, NotEquals, FALSE) && + TEST_HOOK(kernel32.dll, TlsAlloc, NotEquals, TLS_OUT_OF_INDEXES) && + TEST_HOOK_PARAMS(kernel32.dll, TlsFree, Equals, FALSE, TLS_OUT_OF_INDEXES) && + TEST_HOOK(kernel32.dll, CloseHandle, Equals, FALSE) && + TEST_HOOK(kernel32.dll, DuplicateHandle, Equals, FALSE) && - TestHook(TestInternetOpenA, "wininet.dll", "InternetOpenA") && - TestHook(TestInternetCloseHandle, "wininet.dll", "InternetCloseHandle") && - TestHook(TestInternetConnectA, "wininet.dll", "InternetConnectA") && - TestHook(TestInternetQueryDataAvailable, "wininet.dll", "InternetQueryDataAvailable") && - TestHook(TestInternetReadFile, "wininet.dll", "InternetReadFile") && - TestHook(TestInternetWriteFile, "wininet.dll", "InternetWriteFile") && - TestHook(TestInternetSetOptionA, "wininet.dll", "InternetSetOptionA") && - TestHook(TestHttpAddRequestHeadersA, "wininet.dll", "HttpAddRequestHeadersA") && - TestHook(TestHttpOpenRequestA, "wininet.dll", "HttpOpenRequestA") && - TestHook(TestHttpQueryInfoA, "wininet.dll", "HttpQueryInfoA") && - TestHook(TestHttpSendRequestA, "wininet.dll", "HttpSendRequestA") && - TestHook(TestHttpSendRequestExA, "wininet.dll", "HttpSendRequestExA") && - TestHook(TestHttpEndRequestA, "wininet.dll", "HttpEndRequestA") && - TestHook(TestInternetQueryOptionA, "wininet.dll", "InternetQueryOptionA") && + TEST_HOOK(wininet.dll, InternetOpenA, NotEquals, nullptr) && + TEST_HOOK(wininet.dll, InternetCloseHandle, Equals, FALSE) && + TEST_HOOK(wininet.dll, InternetConnectA, Equals, nullptr) && + TEST_HOOK(wininet.dll, InternetQueryDataAvailable, Equals, FALSE) && + TEST_HOOK(wininet.dll, InternetReadFile, Equals, FALSE) && + TEST_HOOK(wininet.dll, InternetWriteFile, Equals, FALSE) && + TEST_HOOK(wininet.dll, InternetSetOptionA, Equals, FALSE) && + TEST_HOOK(wininet.dll, HttpAddRequestHeadersA, Equals, FALSE) && + TEST_HOOK(wininet.dll, HttpOpenRequestA, Equals, nullptr) && + TEST_HOOK(wininet.dll, HttpQueryInfoA, Equals, FALSE) && + TEST_HOOK(wininet.dll, HttpSendRequestA, Equals, FALSE) && + TEST_HOOK(wininet.dll, HttpSendRequestExA, Equals, FALSE) && + TEST_HOOK(wininet.dll, HttpEndRequestA, Equals, FALSE) && + TEST_HOOK(wininet.dll, InternetQueryOptionA, Equals, FALSE) && - TestHook(TestAcquireCredentialsHandleA, "sspicli.dll", "AcquireCredentialsHandleA") && - TestHook(TestQueryCredentialsAttributesA, "sspicli.dll", "QueryCredentialsAttributesA") && - TestHook(TestFreeCredentialsHandle, "sspicli.dll", "FreeCredentialsHandle") && + TEST_HOOK(sspicli.dll, AcquireCredentialsHandleA, NotEquals, SEC_E_OK) && + TEST_HOOK(sspicli.dll, QueryCredentialsAttributesA, NotEquals, SEC_E_OK) && + TEST_HOOK(sspicli.dll, FreeCredentialsHandle, NotEquals, SEC_E_OK) && - TestDetour("kernel32.dll", "BaseThreadInitThunk") && - TestDetour("ntdll.dll", "LdrLoadDll")) { + TEST_DETOUR_SKIP_EXEC(kernel32.dll, BaseThreadInitThunk) && + TEST_DETOUR_SKIP_EXEC(ntdll.dll, LdrLoadDll)) { printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n"); LARGE_INTEGER end, freq; From 9b29ad04f30b627cdb7c1501493e04bececec704 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:48:45 -0600 Subject: [PATCH 47/57] Bug 1460022: Part 3 - Update TestDllInterceptorCrossProcess to reflect new interceptor interface; r=handyman --- .../interceptor/TestDllInterceptorCrossProcess.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp b/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp index 95cf37821043..c29d132ba9b0 100644 --- a/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp +++ b/mozglue/tests/interceptor/TestDllInterceptorCrossProcess.cpp @@ -11,19 +11,19 @@ using std::wstring; -static void* gOrigReturnResult; - extern "C" __declspec(dllexport) int ReturnResult() { return 2; } +static mozilla::CrossProcessDllInterceptor::FuncHookType + gOrigReturnResult; + static int ReturnResultHook() { - auto origFn = reinterpret_cast(gOrigReturnResult); - if (origFn() != 2) { + if (gOrigReturnResult() != 2) { return 3; } @@ -73,9 +73,7 @@ int ParentMain() mozilla::CrossProcessDllInterceptor intcpt(childProcess.get()); intcpt.Init("TestDllInterceptorCrossProcess.exe"); - if (!intcpt.AddHook("ReturnResult", - reinterpret_cast(&ReturnResultHook), - &gOrigReturnResult)) { + if (!gOrigReturnResult.Set(intcpt, "ReturnResult", &ReturnResultHook)) { printf("TEST-UNEXPECTED-FAIL | DllInterceptorCrossProcess | Failed to add hook\n"); return 1; } From 902b049f4a78c876c51713e5d0b3195732b03f48 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:49:17 -0600 Subject: [PATCH 48/57] Bug 1460022: Part 4 - Update a11y code to reflect new interface for DLL interceptor; r=Jamie --- accessible/windows/msaa/Compatibility.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/accessible/windows/msaa/Compatibility.cpp b/accessible/windows/msaa/Compatibility.cpp index 6446f19805c0..f4434f37c0b5 100644 --- a/accessible/windows/msaa/Compatibility.cpp +++ b/accessible/windows/msaa/Compatibility.cpp @@ -95,7 +95,8 @@ Compatibility::IsModuleVersionLessThan(HMODULE aModuleHandle, //////////////////////////////////////////////////////////////////////////////// static WindowsDllInterceptor sUser32Interceptor; -static decltype(&InSendMessageEx) sInSendMessageExStub = nullptr; +static WindowsDllInterceptor::FuncHookType + sInSendMessageExStub; static bool sInSendMessageExHackEnabled = false; static PVOID sVectoredExceptionHandler = nullptr; @@ -267,11 +268,9 @@ Compatibility::Init() if ((sConsumers & (~(UIAUTOMATION | NVDA))) && BrowserTabsRemoteAutostart()) { sUser32Interceptor.Init("user32.dll"); - if (!sInSendMessageExStub) { - sUser32Interceptor.AddHook("InSendMessageEx", - reinterpret_cast(&InSendMessageExHook), - (void**)&sInSendMessageExStub); - } + sInSendMessageExStub.Set(sUser32Interceptor, "InSendMessageEx", + &InSendMessageExHook); + // The vectored exception handler allows us to catch exceptions ahead of any // SEH handlers. if (!sVectoredExceptionHandler) { From 6863992ec858c0bf61fa71f9ff63c13c5cf64d38 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:49:30 -0600 Subject: [PATCH 49/57] Bug 1460022: Part 5 - Update launcher process to work with new DLL interceptor interface; r=mhowell --- browser/app/winlauncher/DllBlocklistWin.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/browser/app/winlauncher/DllBlocklistWin.cpp b/browser/app/winlauncher/DllBlocklistWin.cpp index 82e1d77d3722..a88a0747348f 100644 --- a/browser/app/winlauncher/DllBlocklistWin.cpp +++ b/browser/app/winlauncher/DllBlocklistWin.cpp @@ -246,7 +246,8 @@ IsDllAllowed(const UNICODE_STRING& aLeafName, void* aBaseAddress) } typedef decltype(&NtMapViewOfSection) NtMapViewOfSection_func; -static NtMapViewOfSection_func stub_NtMapViewOfSection; +static mozilla::CrossProcessDllInterceptor::FuncHookType + stub_NtMapViewOfSection; static NTSTATUS NTAPI patched_NtMapViewOfSection(HANDLE aSection, HANDLE aProcess, PVOID* aBaseAddress, @@ -356,9 +357,8 @@ InitializeDllBlocklistOOP(HANDLE aChildProcess) { mozilla::CrossProcessDllInterceptor intcpt(aChildProcess); intcpt.Init(L"ntdll.dll"); - bool ok = intcpt.AddDetour("NtMapViewOfSection", - reinterpret_cast(&patched_NtMapViewOfSection), - (void**) &stub_NtMapViewOfSection); + bool ok = stub_NtMapViewOfSection.SetDetour(intcpt, "NtMapViewOfSection", + &patched_NtMapViewOfSection); if (!ok) { return false; } From 1a234ade51df216d71cae397ee076b69674654fc Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:49:49 -0600 Subject: [PATCH 50/57] Bug 1460022: Part 6 - Update GMP code to work with new DLL interceptor interface; r=cpearce --- dom/media/gmp/ChromiumCDMAdapter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dom/media/gmp/ChromiumCDMAdapter.cpp b/dom/media/gmp/ChromiumCDMAdapter.cpp index b8fbe7a2f9da..e1946dee5106 100644 --- a/dom/media/gmp/ChromiumCDMAdapter.cpp +++ b/dom/media/gmp/ChromiumCDMAdapter.cpp @@ -197,7 +197,8 @@ typedef DWORD(WINAPI* QueryDosDeviceWFnPtr)(_In_opt_ LPCWSTR lpDeviceName, _Out_ LPWSTR lpTargetPath, _In_ DWORD ucchMax); -static QueryDosDeviceWFnPtr sOriginalQueryDosDeviceWFnPtr = nullptr; +static WindowsDllInterceptor::FuncHookType + sOriginalQueryDosDeviceWFnPtr; static std::unordered_map* sDeviceNames = nullptr; @@ -276,9 +277,8 @@ InitializeHooks() } sKernel32Intercept.Init("kernelbase.dll"); - sKernel32Intercept.AddHook("QueryDosDeviceW", - reinterpret_cast(QueryDosDeviceWHook), - (void**)(&sOriginalQueryDosDeviceWFnPtr)); + sOriginalQueryDosDeviceWFnPtr.Set(sKernel32Intercept, "QueryDosDeviceW", + &QueryDosDeviceWHook); } #endif From 23646bdf45b7e3d29a91a8d0269f6bcbd10cfa61 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:50:50 -0600 Subject: [PATCH 51/57] Bug 1460022: Part 7 - Update plugin code to work with revised DLL interceptor interface; r=handyman --- dom/plugins/base/nsPluginNativeWindowWin.cpp | 36 ++++---- dom/plugins/ipc/FunctionHook.cpp | 21 +---- dom/plugins/ipc/FunctionHook.h | 27 ++++-- dom/plugins/ipc/PluginInstanceChild.cpp | 97 +++++++------------- 4 files changed, 73 insertions(+), 108 deletions(-) diff --git a/dom/plugins/base/nsPluginNativeWindowWin.cpp b/dom/plugins/base/nsPluginNativeWindowWin.cpp index fc7f0ea72345..570b99e52610 100644 --- a/dom/plugins/base/nsPluginNativeWindowWin.cpp +++ b/dom/plugins/base/nsPluginNativeWindowWin.cpp @@ -357,8 +357,10 @@ typedef LONG_PTR (WINAPI *User32SetWindowLongPtrW)(HWND hWnd, int nIndex, LONG_PTR dwNewLong); -static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = nullptr; -static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = nullptr; +static WindowsDllInterceptor::FuncHookType + sUser32SetWindowLongAHookStub; +static WindowsDllInterceptor::FuncHookType + sUser32SetWindowLongWHookStub; #else typedef LONG (WINAPI *User32SetWindowLongA)(HWND hWnd, @@ -368,8 +370,10 @@ typedef LONG (WINAPI *User32SetWindowLongW)(HWND hWnd, int nIndex, LONG dwNewLong); -static User32SetWindowLongA sUser32SetWindowLongAHookStub = nullptr; -static User32SetWindowLongW sUser32SetWindowLongWHookStub = nullptr; +static WindowsDllInterceptor::FuncHookType + sUser32SetWindowLongAHookStub; +static WindowsDllInterceptor::FuncHookType + sUser32SetWindowLongWHookStub; #endif static inline bool SetWindowLongHookCheck(HWND hWnd, @@ -448,23 +452,15 @@ HookSetWindowLongPtr() { sUser32Intercept.Init("user32.dll"); #ifdef _WIN64 - if (!sUser32SetWindowLongAHookStub) - sUser32Intercept.AddHook("SetWindowLongPtrA", - reinterpret_cast(SetWindowLongPtrAHook), - (void**) &sUser32SetWindowLongAHookStub); - if (!sUser32SetWindowLongWHookStub) - sUser32Intercept.AddHook("SetWindowLongPtrW", - reinterpret_cast(SetWindowLongPtrWHook), - (void**) &sUser32SetWindowLongWHookStub); + sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongPtrA", + &SetWindowLongPtrAHook); + sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongPtrW", + &SetWindowLongPtrWHook); #else - if (!sUser32SetWindowLongAHookStub) - sUser32Intercept.AddHook("SetWindowLongA", - reinterpret_cast(SetWindowLongAHook), - (void**) &sUser32SetWindowLongAHookStub); - if (!sUser32SetWindowLongWHookStub) - sUser32Intercept.AddHook("SetWindowLongW", - reinterpret_cast(SetWindowLongWHook), - (void**) &sUser32SetWindowLongWHookStub); + sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongA", + &SetWindowLongAHook); + sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongW", + &SetWindowLongWHook); #endif } diff --git a/dom/plugins/ipc/FunctionHook.cpp b/dom/plugins/ipc/FunctionHook.cpp index d5e29ec14f18..3d4733a19277 100644 --- a/dom/plugins/ipc/FunctionHook.cpp +++ b/dom/plugins/ipc/FunctionHook.cpp @@ -168,13 +168,13 @@ typedef HANDLE (WINAPI *CreateFileWPtr)(LPCWSTR aFname, DWORD aAccess, LPSECURITY_ATTRIBUTES aSecurity, DWORD aCreation, DWORD aFlags, HANDLE aFTemplate); -static CreateFileWPtr sCreateFileWStub = nullptr; +static WindowsDllInterceptor::FuncHookType sCreateFileWStub; typedef HANDLE (WINAPI *CreateFileAPtr)(LPCSTR aFname, DWORD aAccess, DWORD aShare, LPSECURITY_ATTRIBUTES aSecurity, DWORD aCreation, DWORD aFlags, HANDLE aFTemplate); -static CreateFileAPtr sCreateFileAStub = nullptr; +static WindowsDllInterceptor::FuncHookType sCreateFileAStub; // Windows 8 RTM (kernelbase's version is 6.2.9200.16384) doesn't call // CreateFileW from CreateFileA. @@ -263,7 +263,7 @@ CreateFileWHookFn(LPCWSTR aFname, DWORD aAccess, DWORD aShare, aSecurity, TRUNCATE_EXISTING, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, - NULL); + nullptr); if (replacement == INVALID_HANDLE_VALUE) { break; } @@ -300,23 +300,12 @@ CreateFileWHookFn(LPCWSTR aFname, DWORD aAccess, DWORD aShare, void FunctionHook::HookProtectedMode() { - // Make sure we only do this once. - static bool sRunOnce = false; - if (sRunOnce) { - return; - } - sRunOnce = true; - // Legacy code. Uses the nsWindowsDLLInterceptor directly instead of // using the FunctionHook sKernel32Intercept.Init("kernel32.dll"); MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Plugin); - sKernel32Intercept.AddHook("CreateFileW", - reinterpret_cast(CreateFileWHookFn), - (void**) &sCreateFileWStub); - sKernel32Intercept.AddHook("CreateFileA", - reinterpret_cast(CreateFileAHookFn), - (void**) &sCreateFileAStub); + sCreateFileWStub.Set(sKernel32Intercept, "CreateFileW", &CreateFileWHookFn); + sCreateFileAStub.Set(sKernel32Intercept, "CreateFileA", &CreateFileAHookFn); } #endif // defined(XP_WIN) diff --git a/dom/plugins/ipc/FunctionHook.h b/dom/plugins/ipc/FunctionHook.h index c9b30dd0643a..06baf6acdad8 100644 --- a/dom/plugins/ipc/FunctionHook.h +++ b/dom/plugins/ipc/FunctionHook.h @@ -9,6 +9,7 @@ #include "IpdlTuple.h" #include "base/process.h" +#include "mozilla/Atomics.h" #if defined(XP_WIN) #include "nsWindowsDllInterceptor.h" @@ -96,12 +97,19 @@ typedef bool(ShouldHookFunc)(int aQuirks); template class BasicFunctionHook : public FunctionHook { +#if defined(XP_WIN) + using FuncHookType = WindowsDllInterceptor::FuncHookType; +#endif // defined(XP_WIN) + public: BasicFunctionHook(const char* aModuleName, const char* aFunctionName, FunctionType* aOldFunction, - FunctionType* aNewFunction) : - mOldFunction(aOldFunction), mRegistration(UNREGISTERED), mModuleName(aModuleName), - mFunctionName(aFunctionName), mNewFunction(aNewFunction) + FunctionType* aNewFunction) + : mOldFunction(aOldFunction) + , mRegistration(UNREGISTERED) + , mModuleName(aModuleName) + , mFunctionName(aFunctionName) + , mNewFunction(aNewFunction) { MOZ_ASSERT(mOldFunction); MOZ_ASSERT(mNewFunction); @@ -128,7 +136,10 @@ protected: // Once the function is hooked, this field will take the value of a pointer to // a function that performs the old behavior. Before that, it is a pointer to // the original function. - FunctionType* mOldFunction; + Atomic mOldFunction; +#if defined(XP_WIN) + FuncHookType mStub; +#endif // defined(XP_WIN) enum RegistrationStatus { UNREGISTERED, FAILED, SUCCEEDED }; RegistrationStatus mRegistration; @@ -170,14 +181,16 @@ BasicFunctionHook::Register(int aQuirks) return false; } - isHooked = - dllInterceptor->AddHook(mFunctionName.Data(), reinterpret_cast(mNewFunction), - reinterpret_cast(&mOldFunction)); + isHooked = mStub.Set(*dllInterceptor, mFunctionName.Data(), mNewFunction); #endif if (isHooked) { +#if defined(XP_WIN) + mOldFunction = mStub.GetStub(); +#endif mRegistration = SUCCEEDED; } + HOOK_LOG(LogLevel::Debug, ("Registering to intercept function '%s' : '%s'", mFunctionName.Data(), SuccessMsg(isHooked))); diff --git a/dom/plugins/ipc/PluginInstanceChild.cpp b/dom/plugins/ipc/PluginInstanceChild.cpp index 47e779a6072c..bab3067be6ee 100644 --- a/dom/plugins/ipc/PluginInstanceChild.cpp +++ b/dom/plugins/ipc/PluginInstanceChild.cpp @@ -73,21 +73,17 @@ typedef BOOL (WINAPI *User32TrackPopupMenu)(HMENU hMenu, CONST RECT *prcRect); static WindowsDllInterceptor sUser32Intercept; static HWND sWinlessPopupSurrogateHWND = nullptr; -static User32TrackPopupMenu sUser32TrackPopupMenuStub = nullptr; +static WindowsDllInterceptor::FuncHookType sUser32TrackPopupMenuStub; static WindowsDllInterceptor sImm32Intercept; -static decltype(ImmGetContext)* sImm32ImmGetContextStub = nullptr; -static decltype(ImmGetCompositionStringW)* sImm32ImmGetCompositionStringStub = - nullptr; -static decltype(ImmSetCandidateWindow)* sImm32ImmSetCandidateWindowStub = - nullptr; -static decltype(ImmNotifyIME)* sImm32ImmNotifyIME = nullptr; -static decltype(ImmAssociateContextEx)* sImm32ImmAssociateContextExStub = - nullptr; +static WindowsDllInterceptor::FuncHookType sImm32ImmGetContextStub; +static WindowsDllInterceptor::FuncHookType sImm32ImmGetCompositionStringStub; +static WindowsDllInterceptor::FuncHookType sImm32ImmSetCandidateWindowStub; +static WindowsDllInterceptor::FuncHookType sImm32ImmNotifyIME; +static WindowsDllInterceptor::FuncHookType sImm32ImmAssociateContextExStub; + static PluginInstanceChild* sCurrentPluginInstance = nullptr; static const HIMC sHookIMC = (const HIMC)0xefefefef; -static bool sPopupMenuHookSet; -static bool sSetWindowLongHookSet; using mozilla::gfx::SharedDIB; @@ -1793,8 +1789,8 @@ typedef LONG_PTR (WINAPI *User32SetWindowLongPtrW)(HWND hWnd, int nIndex, LONG_PTR dwNewLong); -static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = nullptr; -static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = nullptr; +static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongAHookStub; +static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongWHookStub; #else typedef LONG (WINAPI *User32SetWindowLongA)(HWND hWnd, @@ -1804,8 +1800,8 @@ typedef LONG (WINAPI *User32SetWindowLongW)(HWND hWnd, int nIndex, LONG dwNewLong); -static User32SetWindowLongA sUser32SetWindowLongAHookStub = nullptr; -static User32SetWindowLongW sUser32SetWindowLongWHookStub = nullptr; +static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongAHookStub; +static WindowsDllInterceptor::FuncHookType sUser32SetWindowLongWHookStub; #endif extern LRESULT CALLBACK @@ -1915,27 +1911,17 @@ PluginInstanceChild::HookSetWindowLongPtr() return; } - // Only pass through here once - if (sSetWindowLongHookSet) { - return; - } - sSetWindowLongHookSet = true; - sUser32Intercept.Init("user32.dll"); #ifdef _WIN64 - if (!sUser32SetWindowLongAHookStub) - sUser32Intercept.AddHook("SetWindowLongPtrA", reinterpret_cast(SetWindowLongPtrAHook), - (void**) &sUser32SetWindowLongAHookStub); - if (!sUser32SetWindowLongWHookStub) - sUser32Intercept.AddHook("SetWindowLongPtrW", reinterpret_cast(SetWindowLongPtrWHook), - (void**) &sUser32SetWindowLongWHookStub); + sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongPtrA", + &SetWindowLongPtrAHook); + sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongPtrW", + &SetWindowLongPtrWHook); #else - if (!sUser32SetWindowLongAHookStub) - sUser32Intercept.AddHook("SetWindowLongA", reinterpret_cast(SetWindowLongAHook), - (void**) &sUser32SetWindowLongAHookStub); - if (!sUser32SetWindowLongWHookStub) - sUser32Intercept.AddHook("SetWindowLongW", reinterpret_cast(SetWindowLongWHook), - (void**) &sUser32SetWindowLongWHookStub); + sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongA", + &SetWindowLongAHook); + sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongW", + &SetWindowLongWHook); #endif } @@ -2003,19 +1989,13 @@ PluginInstanceChild::InitPopupMenuHook() return; } - // Only pass through here once - if (sPopupMenuHookSet) { - return; - } - sPopupMenuHookSet = true; - // Note, once WindowsDllInterceptor is initialized for a module, // it remains initialized for that particular module for it's // lifetime. Additional instances are needed if other modules need // to be hooked. sUser32Intercept.Init("user32.dll"); - sUser32Intercept.AddHook("TrackPopupMenu", reinterpret_cast(TrackPopupHookProc), - (void**) &sUser32TrackPopupMenuStub); + sUser32TrackPopupMenuStub.Set(sUser32Intercept, "TrackPopupMenu", + &TrackPopupHookProc); } void @@ -2157,36 +2137,23 @@ PluginInstanceChild::InitImm32Hook() return; } - if (sImm32ImmGetContextStub) { - return; - } - // When using windowless plugin, IMM API won't work due ot OOP. // // ImmReleaseContext on Windows 7+ just returns TRUE only, so we don't // need to hook this. sImm32Intercept.Init("imm32.dll"); - sImm32Intercept.AddHook( - "ImmGetContext", - reinterpret_cast(ImmGetContextProc), - (void**)&sImm32ImmGetContextStub); - sImm32Intercept.AddHook( - "ImmGetCompositionStringW", - reinterpret_cast(ImmGetCompositionStringProc), - (void**)&sImm32ImmGetCompositionStringStub); - sImm32Intercept.AddHook( - "ImmSetCandidateWindow", - reinterpret_cast(ImmSetCandidateWindowProc), - (void**)&sImm32ImmSetCandidateWindowStub); - sImm32Intercept.AddHook( - "ImmNotifyIME", - reinterpret_cast(ImmNotifyIME), - (void**)&sImm32ImmNotifyIME); - sImm32Intercept.AddHook( - "ImmAssociateContextEx", - reinterpret_cast(ImmAssociateContextExProc), - (void**)&sImm32ImmAssociateContextExStub); + sImm32ImmGetContextStub.Set(sImm32Intercept, "ImmGetContext", + &ImmGetContextProc); + sImm32ImmGetCompositionStringStub.Set(sImm32Intercept, + "ImmGetCompositionStringW", + &ImmGetCompositionStringProc); + sImm32ImmSetCandidateWindowStub.Set(sImm32Intercept, + "ImmSetCandidateWindow", + &ImmSetCandidateWindowProc); + sImm32ImmNotifyIME.Set(sImm32Intercept, "ImmNotifyIME", &ImmNotifyIME); + sImm32ImmAssociateContextExStub.Set(sImm32Intercept, "ImmAssociateContextEx", + &ImmAssociateContextExProc); } void From d88f616e248d52d87d1817538df23a14063e5048 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:51:10 -0600 Subject: [PATCH 52/57] Bug 1460022: Part 8 - Update DLL blocklist to work with revised DLL interceptor interface; r=mhowell --- mozglue/build/WindowsDllBlocklist.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/mozglue/build/WindowsDllBlocklist.cpp b/mozglue/build/WindowsDllBlocklist.cpp index 6071e4241986..4b7a6f7ecf6a 100644 --- a/mozglue/build/WindowsDllBlocklist.cpp +++ b/mozglue/build/WindowsDllBlocklist.cpp @@ -90,14 +90,14 @@ printf_stderr(const char *fmt, ...) typedef MOZ_NORETURN_PTR void (__fastcall* BaseThreadInitThunk_func)(BOOL aIsInitialThread, void* aStartAddress, void* aThreadParam); -static BaseThreadInitThunk_func stub_BaseThreadInitThunk = nullptr; +static WindowsDllInterceptor::FuncHookType stub_BaseThreadInitThunk; typedef NTSTATUS (NTAPI *LdrLoadDll_func) (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle); -static LdrLoadDll_func stub_LdrLoadDll; +static WindowsDllInterceptor::FuncHookType stub_LdrLoadDll; #ifdef _M_AMD64 typedef decltype(RtlInstallFunctionTableCallback)* RtlInstallFunctionTableCallback_func; -static RtlInstallFunctionTableCallback_func stub_RtlInstallFunctionTableCallback; +static WindowsDllInterceptor::FuncHookType stub_RtlInstallFunctionTableCallback; extern uint8_t* sMsMpegJitCodeRegionStart; extern size_t sMsMpegJitCodeRegionSize; @@ -662,7 +662,8 @@ DllBlocklist_Initialize(uint32_t aInitFlags) // We specifically use a detour, because there are cases where external // code also tries to hook LdrLoadDll, and doesn't know how to relocate our // nop space patches. (Bug 951827) - bool ok = NtDllIntercept.AddDetour("LdrLoadDll", reinterpret_cast(patched_LdrLoadDll), (void**) &stub_LdrLoadDll); + bool ok = stub_LdrLoadDll.SetDetour(NtDllIntercept, "LdrLoadDll", + &patched_LdrLoadDll); if (!ok) { sBlocklistInitFailed = true; @@ -683,18 +684,18 @@ DllBlocklist_Initialize(uint32_t aInitFlags) #ifdef _M_AMD64 if (!IsWin8OrLater()) { // The crash that this hook works around is only seen on Win7. - Kernel32Intercept.AddHook("RtlInstallFunctionTableCallback", - reinterpret_cast(patched_RtlInstallFunctionTableCallback), - (void**)&stub_RtlInstallFunctionTableCallback); + stub_RtlInstallFunctionTableCallback.Set(Kernel32Intercept, + "RtlInstallFunctionTableCallback", + &patched_RtlInstallFunctionTableCallback); } #endif // Bug 1361410: WRusr.dll will overwrite our hook and cause a crash. // Workaround: If we detect WRusr.dll, don't hook. if (!GetModuleHandleW(L"WRusr.dll")) { - if(!Kernel32Intercept.AddDetour("BaseThreadInitThunk", - reinterpret_cast(patched_BaseThreadInitThunk), - (void**) &stub_BaseThreadInitThunk)) { + if (!stub_BaseThreadInitThunk.SetDetour(Kernel32Intercept, + "BaseThreadInitThunk", + &patched_BaseThreadInitThunk)) { #ifdef DEBUG printf_stderr("BaseThreadInitThunk hook failed\n"); #endif From fab8ec82c64b0f3620516d8be96de2dafc5584ef Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:51:29 -0600 Subject: [PATCH 53/57] Bug 1460022: Part 9 - Update sandboxing code to work with revised DLL interceptor interface; r=bobowen --- security/sandbox/win/SandboxInitialization.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/security/sandbox/win/SandboxInitialization.cpp b/security/sandbox/win/SandboxInitialization.cpp index 8e27b87dd2f4..8a4a5e858072 100644 --- a/security/sandbox/win/SandboxInitialization.cpp +++ b/security/sandbox/win/SandboxInitialization.cpp @@ -15,7 +15,7 @@ namespace mozilla { namespace sandboxing { typedef BOOL(WINAPI* CloseHandle_func) (HANDLE hObject); -static CloseHandle_func stub_CloseHandle = nullptr; +static WindowsDllInterceptor::FuncHookType stub_CloseHandle; typedef BOOL(WINAPI* DuplicateHandle_func)(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, @@ -24,7 +24,8 @@ typedef BOOL(WINAPI* DuplicateHandle_func)(HANDLE hSourceProcessHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions); -static DuplicateHandle_func stub_DuplicateHandle = nullptr; +static WindowsDllInterceptor::FuncHookType + stub_DuplicateHandle; static BOOL WINAPI patched_CloseHandle(HANDLE hObject) @@ -62,17 +63,14 @@ EnableHandleCloseMonitoring() { Kernel32Intercept.Init("kernel32.dll"); bool hooked = - Kernel32Intercept.AddHook("CloseHandle", - reinterpret_cast(patched_CloseHandle), - (void**)&stub_CloseHandle); + stub_CloseHandle.Set(Kernel32Intercept, "CloseHandle", &patched_CloseHandle); if (!hooked) { return false; } hooked = - Kernel32Intercept.AddHook("DuplicateHandle", - reinterpret_cast(patched_DuplicateHandle), - (void**)&stub_DuplicateHandle); + stub_DuplicateHandle.Set(Kernel32Intercept, "DuplicateHandle", + &patched_DuplicateHandle); if (!hooked) { return false; } From c710bd6ee2f4e498c226f681c02b9c2a5dd430ee Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:51:40 -0600 Subject: [PATCH 54/57] Bug 1460022: Part 10 - Update crash reporter to work with revised DLL interceptor interface; r=dmajor --- toolkit/crashreporter/nsExceptionHandler.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp index 7f42278ef244..319f78f27cc0 100644 --- a/toolkit/crashreporter/nsExceptionHandler.cpp +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -338,7 +338,8 @@ nsTArray >* gDelayedAnnotations; // reporter is loaded instead (in case it became unloaded somehow) typedef LPTOP_LEVEL_EXCEPTION_FILTER (WINAPI *SetUnhandledExceptionFilter_func) (LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); -static SetUnhandledExceptionFilter_func stub_SetUnhandledExceptionFilter = 0; +static WindowsDllInterceptor::FuncHookType + stub_SetUnhandledExceptionFilter; static LPTOP_LEVEL_EXCEPTION_FILTER previousUnhandledExceptionFilter = nullptr; static WindowsDllInterceptor gKernel32Intercept; static bool gBlockUnhandledExceptionFilter = true; @@ -1639,9 +1640,9 @@ nsresult SetExceptionHandler(nsIFile* aXREDirectory, // protect the crash reporter from being unloaded gBlockUnhandledExceptionFilter = true; gKernel32Intercept.Init("kernel32.dll"); - bool ok = gKernel32Intercept.AddHook("SetUnhandledExceptionFilter", - reinterpret_cast(patched_SetUnhandledExceptionFilter), - (void**) &stub_SetUnhandledExceptionFilter); + bool ok = stub_SetUnhandledExceptionFilter.Set(gKernel32Intercept, + "SetUnhandledExceptionFilter", + &patched_SetUnhandledExceptionFilter); #ifdef DEBUG if (!ok) From 75d28120722b1c30f9abe0c1fad6853d999a8f7f Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:52:01 -0600 Subject: [PATCH 55/57] Bug 1460022: Part 11 - Update Win32 nsWindow to work with revised DLL interceptor interface; r=mhowell --- widget/windows/nsWindow.cpp | 46 ++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index db0389563b1e..f15691569075 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -352,9 +352,6 @@ static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); // General purpose user32.dll hook object static WindowsDllInterceptor sUser32Intercept; -// AddHook success checks -static mozilla::Maybe sHookedGetWindowInfo; - // 2 pixel offset for eTransparencyBorderlessGlass which equals the size of // the default window border Windows paints. Glass will be extended inward // this distance to remove the border. @@ -461,17 +458,17 @@ private: if (!IsWin10OrLater() && GetModuleHandle(L"tiptsf.dll") && !sProcessCaretEventsStub) { sTipTsfInterceptor.Init("tiptsf.dll"); - DebugOnly ok = sTipTsfInterceptor.AddHook("ProcessCaretEvents", - reinterpret_cast(&ProcessCaretEventsHook), - (void**) &sProcessCaretEventsStub); + DebugOnly ok = sProcessCaretEventsStub.Set(sTipTsfInterceptor, + "ProcessCaretEvents", + &ProcessCaretEventsHook); MOZ_ASSERT(ok); } if (!sSendMessageTimeoutWStub) { sUser32Intercept.Init("user32.dll"); - DebugOnly hooked = sUser32Intercept.AddHook("SendMessageTimeoutW", - reinterpret_cast(&SendMessageTimeoutWHook), - (void**) &sSendMessageTimeoutWStub); + DebugOnly hooked = sSendMessageTimeoutWStub.Set(sUser32Intercept, + "SendMessageTimeoutW", + &SendMessageTimeoutWHook); MOZ_ASSERT(hooked); } } @@ -556,8 +553,10 @@ private: } static WindowsDllInterceptor sTipTsfInterceptor; - static WINEVENTPROC sProcessCaretEventsStub; - static decltype(&SendMessageTimeoutW) sSendMessageTimeoutWStub; + static WindowsDllInterceptor::FuncHookType + sProcessCaretEventsStub; + static WindowsDllInterceptor::FuncHookType + sSendMessageTimeoutWStub; static StaticAutoPtr sInstance; HHOOK mHook; @@ -566,8 +565,10 @@ private: }; WindowsDllInterceptor TIPMessageHandler::sTipTsfInterceptor; -WINEVENTPROC TIPMessageHandler::sProcessCaretEventsStub; -decltype(&SendMessageTimeoutW) TIPMessageHandler::sSendMessageTimeoutWStub; +WindowsDllInterceptor::FuncHookType + TIPMessageHandler::sProcessCaretEventsStub; +WindowsDllInterceptor::FuncHookType + TIPMessageHandler::sSendMessageTimeoutWStub; StaticAutoPtr TIPMessageHandler::sInstance; } // namespace mozilla @@ -2472,7 +2473,7 @@ nsWindow::ResetLayout() // margins are set. static const wchar_t kManageWindowInfoProperty[] = L"ManageWindowInfoProperty"; typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi); -static GetWindowInfoPtr sGetWindowInfoPtrStub = nullptr; +static WindowsDllInterceptor::FuncHookType sGetWindowInfoPtrStub; BOOL WINAPI GetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi) @@ -2500,18 +2501,15 @@ nsWindow::UpdateGetWindowInfoCaptionStatus(bool aActiveCaption) if (!mWnd) return; - if (sHookedGetWindowInfo.isNothing()) { - sUser32Intercept.Init("user32.dll"); - sHookedGetWindowInfo = - Some(sUser32Intercept.AddHook("GetWindowInfo", - reinterpret_cast(GetWindowInfoHook), - (void**) &sGetWindowInfoPtrStub)); - if (!sHookedGetWindowInfo.value()) { - return; - } + sUser32Intercept.Init("user32.dll"); + sGetWindowInfoPtrStub.Set(sUser32Intercept, "GetWindowInfo", + &GetWindowInfoHook); + if (!sGetWindowInfoPtrStub) { + return; } + // Update our internally tracked caption status - SetPropW(mWnd, kManageWindowInfoProperty, + SetPropW(mWnd, kManageWindowInfoProperty, reinterpret_cast(static_cast(aActiveCaption) + 1)); } From 230d3ee242e25d2172345ef8bb2afd6cf291c0a3 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 11:52:18 -0600 Subject: [PATCH 56/57] Bug 1460022: Part 12 - Update XPCOM to use revised DLL interceptor interface; r=froydnj --- xpcom/base/AvailableMemoryTracker.cpp | 27 +++++------ xpcom/build/PoisonIOInterposerWin.cpp | 64 ++++++++++++--------------- 2 files changed, 39 insertions(+), 52 deletions(-) diff --git a/xpcom/base/AvailableMemoryTracker.cpp b/xpcom/base/AvailableMemoryTracker.cpp index 678566087eda..02265da2c6f1 100644 --- a/xpcom/base/AvailableMemoryTracker.cpp +++ b/xpcom/base/AvailableMemoryTracker.cpp @@ -84,16 +84,14 @@ volatile PRIntervalTime sLastLowMemoryNotificationTime; // These are function pointers to the functions we wrap in Init(). -void* (WINAPI* sVirtualAllocOrig)(LPVOID aAddress, SIZE_T aSize, - DWORD aAllocationType, DWORD aProtect); +static WindowsDllInterceptor::FuncHookType + sVirtualAllocOrig; -void* (WINAPI* sMapViewOfFileOrig)(HANDLE aFileMappingObject, - DWORD aDesiredAccess, DWORD aFileOffsetHigh, - DWORD aFileOffsetLow, SIZE_T aNumBytesToMap); +static WindowsDllInterceptor::FuncHookType + sMapViewOfFileOrig; -HBITMAP(WINAPI* sCreateDIBSectionOrig)(HDC aDC, const BITMAPINFO* aBitmapInfo, - UINT aUsage, VOID** aBits, - HANDLE aSection, DWORD aOffset); +static WindowsDllInterceptor::FuncHookType + sCreateDIBSectionOrig; /** * Fire a memory pressure event if we were not under memory pressure yet, or @@ -645,17 +643,12 @@ Init() // VirtualAllocHook from reentering itself. if (!PR_GetEnv("MOZ_PGO_INSTRUMENTED")) { sKernel32Intercept.Init("Kernel32.dll"); - sKernel32Intercept.AddHook("VirtualAlloc", - reinterpret_cast(VirtualAllocHook), - reinterpret_cast(&sVirtualAllocOrig)); - sKernel32Intercept.AddHook("MapViewOfFile", - reinterpret_cast(MapViewOfFileHook), - reinterpret_cast(&sMapViewOfFileOrig)); + sVirtualAllocOrig.Set(sKernel32Intercept, "VirtualAlloc", &VirtualAllocHook); + sMapViewOfFileOrig.Set(sKernel32Intercept, "MapViewOfFile", &MapViewOfFileHook); sGdi32Intercept.Init("Gdi32.dll"); - sGdi32Intercept.AddHook("CreateDIBSection", - reinterpret_cast(CreateDIBSectionHook), - reinterpret_cast(&sCreateDIBSectionOrig)); + sCreateDIBSectionOrig.Set(sGdi32Intercept, "CreateDIBSection", + &CreateDIBSectionHook); } sInitialized = true; diff --git a/xpcom/build/PoisonIOInterposerWin.cpp b/xpcom/build/PoisonIOInterposerWin.cpp index 6d8bc0a01233..5f2aaec25e28 100644 --- a/xpcom/build/PoisonIOInterposerWin.cpp +++ b/xpcom/build/PoisonIOInterposerWin.cpp @@ -209,13 +209,20 @@ WinIOAutoObservation::Filename(nsAString& aFilename) /*************************** IO Interposing Methods ***************************/ // Function pointers to original functions -static NtCreateFileFn gOriginalNtCreateFile; -static NtReadFileFn gOriginalNtReadFile; -static NtReadFileScatterFn gOriginalNtReadFileScatter; -static NtWriteFileFn gOriginalNtWriteFile; -static NtWriteFileGatherFn gOriginalNtWriteFileGather; -static NtFlushBuffersFileFn gOriginalNtFlushBuffersFile; -static NtQueryFullAttributesFileFn gOriginalNtQueryFullAttributesFile; +static WindowsDllInterceptor::FuncHookType + gOriginalNtCreateFile; +static WindowsDllInterceptor::FuncHookType + gOriginalNtReadFile; +static WindowsDllInterceptor::FuncHookType + gOriginalNtReadFileScatter; +static WindowsDllInterceptor::FuncHookType + gOriginalNtWriteFile; +static WindowsDllInterceptor::FuncHookType + gOriginalNtWriteFileGather; +static WindowsDllInterceptor::FuncHookType + gOriginalNtFlushBuffersFile; +static WindowsDllInterceptor::FuncHookType + gOriginalNtQueryFullAttributesFile; static NTSTATUS NTAPI InterposedNtCreateFile(PHANDLE aFileHandle, @@ -448,34 +455,21 @@ InitPoisonIOInterposer() // Initialize dll interceptor and add hooks sNtDllInterceptor.Init("ntdll.dll"); - sNtDllInterceptor.AddHook( - "NtCreateFile", - reinterpret_cast(InterposedNtCreateFile), - reinterpret_cast(&gOriginalNtCreateFile)); - sNtDllInterceptor.AddHook( - "NtReadFile", - reinterpret_cast(InterposedNtReadFile), - reinterpret_cast(&gOriginalNtReadFile)); - sNtDllInterceptor.AddHook( - "NtReadFileScatter", - reinterpret_cast(InterposedNtReadFileScatter), - reinterpret_cast(&gOriginalNtReadFileScatter)); - sNtDllInterceptor.AddHook( - "NtWriteFile", - reinterpret_cast(InterposedNtWriteFile), - reinterpret_cast(&gOriginalNtWriteFile)); - sNtDllInterceptor.AddHook( - "NtWriteFileGather", - reinterpret_cast(InterposedNtWriteFileGather), - reinterpret_cast(&gOriginalNtWriteFileGather)); - sNtDllInterceptor.AddHook( - "NtFlushBuffersFile", - reinterpret_cast(InterposedNtFlushBuffersFile), - reinterpret_cast(&gOriginalNtFlushBuffersFile)); - sNtDllInterceptor.AddHook( - "NtQueryFullAttributesFile", - reinterpret_cast(InterposedNtQueryFullAttributesFile), - reinterpret_cast(&gOriginalNtQueryFullAttributesFile)); + gOriginalNtCreateFile.Set(sNtDllInterceptor, "NtCreateFile", + &InterposedNtCreateFile); + gOriginalNtReadFile.Set(sNtDllInterceptor, "NtReadFile", + &InterposedNtReadFile); + gOriginalNtReadFileScatter.Set(sNtDllInterceptor, "NtReadFileScatter", + &InterposedNtReadFileScatter); + gOriginalNtWriteFile.Set(sNtDllInterceptor, "NtWriteFile", + &InterposedNtWriteFile); + gOriginalNtWriteFileGather.Set(sNtDllInterceptor, "NtWriteFileGather", + &InterposedNtWriteFileGather); + gOriginalNtFlushBuffersFile.Set(sNtDllInterceptor, "NtFlushBuffersFile", + &InterposedNtFlushBuffersFile); + gOriginalNtQueryFullAttributesFile.Set(sNtDllInterceptor, + "NtQueryFullAttributesFile", + &InterposedNtQueryFullAttributesFile); } void From e0e1a8b28ad2b748d7685e107e1cdb35a7f757f2 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 27 Jun 2018 14:23:29 -0600 Subject: [PATCH 57/57] Bug 1460022: Part 13 - Update profiler to use revised DLL interceptor interface; r=njn --- tools/profiler/core/platform-win32.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/tools/profiler/core/platform-win32.cpp b/tools/profiler/core/platform-win32.cpp index ee17d1a68b73..04a56fbdf133 100644 --- a/tools/profiler/core/platform-win32.cpp +++ b/tools/profiler/core/platform-win32.cpp @@ -303,7 +303,8 @@ Registers::SyncPopulate() static WindowsDllInterceptor NtDllIntercept; typedef NTSTATUS (NTAPI *LdrUnloadDll_func)(HMODULE module); -static LdrUnloadDll_func stub_LdrUnloadDll; +static WindowsDllInterceptor::FuncHookType + stub_LdrUnloadDll; static NTSTATUS NTAPI patched_LdrUnloadDll(HMODULE module) @@ -318,7 +319,8 @@ patched_LdrUnloadDll(HMODULE module) typedef PVOID (WINAPI *LdrResolveDelayLoadedAPI_func)(PVOID ParentModuleBase, PVOID DelayloadDescriptor, PVOID FailureDllHook, PVOID FailureSystemHook, PVOID ThunkAddress, ULONG Flags); -static LdrResolveDelayLoadedAPI_func stub_LdrResolveDelayLoadedAPI; +static WindowsDllInterceptor::FuncHookType + stub_LdrResolveDelayLoadedAPI; static PVOID WINAPI patched_LdrResolveDelayLoadedAPI(PVOID ParentModuleBase, @@ -336,20 +338,12 @@ patched_LdrResolveDelayLoadedAPI(PVOID ParentModuleBase, void InitializeWin64ProfilerHooks() { - static bool initialized = false; - if (initialized) { - return; - } - initialized = true; - NtDllIntercept.Init("ntdll.dll"); - NtDllIntercept.AddHook("LdrUnloadDll", - reinterpret_cast(patched_LdrUnloadDll), - (void**)&stub_LdrUnloadDll); + stub_LdrUnloadDll.Set(NtDllIntercept, "LdrUnloadDll", &patched_LdrUnloadDll); if (IsWin8OrLater()) { // LdrResolveDelayLoadedAPI was introduced in Win8 - NtDllIntercept.AddHook("LdrResolveDelayLoadedAPI", - reinterpret_cast(patched_LdrResolveDelayLoadedAPI), - (void**)&stub_LdrResolveDelayLoadedAPI); + stub_LdrResolveDelayLoadedAPI.Set(NtDllIntercept, + "LdrResolveDelayLoadedAPI", + &patched_LdrResolveDelayLoadedAPI); } } #endif // defined(GP_PLAT_amd64_windows)