Disable the NtMapViewOfSection hook when printing is initiated
Due to an issue with printing drivers possibly loading third-party DLLs
that mustn't be blocked, initiating a printing operation now disables
the hook in chrome_elf for the remainder of the process' lifetime.
This is a short term solution to allow us to ship third-party blocking.
Bug: 809738, 892294
Change-Id: I0b583197c2b619226e5a4a05836451b9f30eb133
Reviewed-on: https://chromium-review.googlesource.com/c/1312166
Reviewed-by: Robert Kaplow <rkaplow@chromium.org>
Reviewed-by: Chris Hamilton <chrisha@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Patrick Monette <pmonette@chromium.org>
Cr-Commit-Position: refs/heads/master@{#610672}
diff --git a/chrome/browser/conflicts/module_database_win.cc b/chrome/browser/conflicts/module_database_win.cc
index d00e1c5..145f969 100644
--- a/chrome/browser/conflicts/module_database_win.cc
+++ b/chrome/browser/conflicts/module_database_win.cc
@@ -11,6 +11,7 @@
#include "base/files/file_path.h"
#include "base/location.h"
#include "chrome/browser/conflicts/module_database_observer_win.h"
+#include "content/public/browser/browser_task_traits.h"
#if defined(GOOGLE_CHROME_BUILD)
#include "base/feature_list.h"
@@ -22,6 +23,7 @@
#include "chrome/browser/conflicts/third_party_conflicts_manager_win.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
+#include "chrome_elf/third_party_dlls/public_api.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
@@ -263,6 +265,20 @@
return !third_party_blocking_enabled_pref->IsManaged() ||
third_party_blocking_enabled_pref->GetValue()->GetBool();
}
+
+// static
+void ModuleDatabase::DisableThirdPartyBlocking() {
+ // Immediately disable the hook. DisableHook() can be called concurrently.
+ DisableHook();
+
+ // Notify the ThirdPartyMetricsRecorder instance that the hook is disabled.
+ // Since this is meant for a heartbeat metric, the small latency introduced
+ // with the thread-hopping is perfectly acceptable.
+ base::PostTaskWithTraits(
+ FROM_HERE, {content::BrowserThread::UI}, base::BindOnce([]() {
+ ModuleDatabase::GetInstance()->third_party_metrics_.SetHookDisabled();
+ }));
+}
#endif // defined(GOOGLE_CHROME_BUILD)
// static
diff --git a/chrome/browser/conflicts/module_database_win.h b/chrome/browser/conflicts/module_database_win.h
index 70e4c37..94b87ee5 100644
--- a/chrome/browser/conflicts/module_database_win.h
+++ b/chrome/browser/conflicts/module_database_win.h
@@ -140,6 +140,15 @@
// administrative policy.
static bool IsThirdPartyBlockingPolicyEnabled();
+ // Disables the blocking of third-party modules in the browser process. It is
+ // safe to invoke this function from any thread.
+ // This function is meant to be used only as a workaround for the in-process
+ // printing code that may require that third-party DLLs be successfully
+ // loaded into the process to work correctly.
+ // TODO(pmonette): Remove this workaround when printing is moved to a utility
+ // process. See https://crbug.com/809738.
+ static void DisableThirdPartyBlocking();
+
// Accessor for the third party conflicts manager.
// Returns null if both the tracking of incompatible applications and the
// blocking of third-party modules are disabled.
diff --git a/chrome/browser/conflicts/module_load_attempt_log_listener_win.cc b/chrome/browser/conflicts/module_load_attempt_log_listener_win.cc
index 1fd45e5..8c1f504 100644
--- a/chrome/browser/conflicts/module_load_attempt_log_listener_win.cc
+++ b/chrome/browser/conflicts/module_load_attempt_log_listener_win.cc
@@ -18,8 +18,8 @@
#include "base/task/post_task.h"
#include "base/task_runner_util.h"
#include "chrome/browser/conflicts/module_blacklist_cache_util_win.h"
-#include "chrome_elf/third_party_dlls/logging_api.h"
#include "chrome_elf/third_party_dlls/packed_list_format.h"
+#include "chrome_elf/third_party_dlls/public_api.h"
namespace {
diff --git a/chrome/browser/conflicts/third_party_metrics_recorder_win.cc b/chrome/browser/conflicts/third_party_metrics_recorder_win.cc
index 5a67861..d4d1f48 100644
--- a/chrome/browser/conflicts/third_party_metrics_recorder_win.cc
+++ b/chrome/browser/conflicts/third_party_metrics_recorder_win.cc
@@ -18,11 +18,10 @@
#include "components/crash/core/common/crash_key.h"
#if defined(GOOGLE_CHROME_BUILD)
-#include "chrome_elf/third_party_dlls/logging_api.h"
+#include "chrome_elf/third_party_dlls/public_api.h"
#endif
namespace {
-
// Returns true if the module is signed by Google.
bool IsGoogleModule(base::StringPiece16 subject) {
static const wchar_t kGoogle[] = L"Google Inc";
@@ -157,15 +156,23 @@
"ThirdPartyModules.Heartbeat.UniqueBlockedModulesCount",
GetUniqueBlockedModulesCount());
- uint32_t blocked_modules_count = GetBlockedModulesCount();
- UMA_HISTOGRAM_COUNTS_1M("ThirdPartyModules.Heartbeat.BlockedModulesCount",
- blocked_modules_count);
+ if (record_blocked_modules_count_) {
+ uint32_t blocked_modules_count = GetBlockedModulesCount();
+ UMA_HISTOGRAM_COUNTS_1M("ThirdPartyModules.Heartbeat.BlockedModulesCount",
+ blocked_modules_count);
- // Stop recording when |blocked_modules_count| gets too high. This is to avoid
- // dealing with the possible integer overflow that would result in emitting
- // wrong values. The exact cutoff point is not important but it must be higher
- // than the max value for the histogram (1M in this case).
- if (blocked_modules_count > std::numeric_limits<uint32_t>::max() / 2)
- heartbeat_metrics_timer_.Reset();
+ // Stop recording when |blocked_modules_count| gets too high. This is to
+ // avoid dealing with the possible integer overflow that would result in
+ // emitting wrong values. The exact cutoff point is not important but it
+ // must be higher than the max value for the histogram (1M in this case).
+ // It's ok to continue logging the count of unique blocked modules because
+ // there's no expectation that this count can reach a high value.
+ if (blocked_modules_count > std::numeric_limits<uint32_t>::max() / 2)
+ record_blocked_modules_count_ = false;
+ }
+
+ UMA_HISTOGRAM_BOOLEAN(
+ "ThirdPartyModules.Heartbeat.PrintingWorkaround.BlockingEnabled",
+ hook_enabled_);
}
#endif
diff --git a/chrome/browser/conflicts/third_party_metrics_recorder_win.h b/chrome/browser/conflicts/third_party_metrics_recorder_win.h
index f367f39a..7507671 100644
--- a/chrome/browser/conflicts/third_party_metrics_recorder_win.h
+++ b/chrome/browser/conflicts/third_party_metrics_recorder_win.h
@@ -29,6 +29,10 @@
const ModuleInfoData& module_data) override;
void OnModuleDatabaseIdle() override;
+#if defined(GOOGLE_CHROME_BUILD)
+ void SetHookDisabled() { hook_enabled_ = false; }
+#endif
+
private:
// The size of the unsigned modules crash keys.
static constexpr size_t kCrashKeySize = 256;
@@ -47,6 +51,15 @@
// Timer that controls when heartbeat metrics are recorded.
base::RepeatingTimer heartbeat_metrics_timer_;
+
+ // Indicates if the ThirdPartyModules.Heartbeat.BlockedModulesCount heartbeat
+ // metric is being recorded.
+ bool record_blocked_modules_count_ = true;
+
+ // Indicates if the blocking of third-party DLLs is still enabled or if it
+ // was disabled because in-process printing was invoked.
+ // See ModuleDatabase::DisableThirdPartyBlocking().
+ bool hook_enabled_ = true;
#endif
// The index of the crash key that is currently being updated.
diff --git a/chrome/browser/printing/DEPS b/chrome/browser/printing/DEPS
index f5a9247..43cad55e 100644
--- a/chrome/browser/printing/DEPS
+++ b/chrome/browser/printing/DEPS
@@ -1,3 +1,4 @@
include_rules = [
+ "+chrome_elf/third_party_dlls/public_api.h",
"+pdf/pdf.h", # Test only.
]
diff --git a/chrome/browser/printing/print_preview_dialog_controller.cc b/chrome/browser/printing/print_preview_dialog_controller.cc
index 2b7cd45..2283ce8c 100644
--- a/chrome/browser/printing/print_preview_dialog_controller.cc
+++ b/chrome/browser/printing/print_preview_dialog_controller.cc
@@ -43,6 +43,10 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/web_dialogs/web_dialog_delegate.h"
+#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#include "chrome/browser/conflicts/module_database_win.h"
+#endif
+
using content::NavigationController;
using content::WebContents;
using content::WebUIMessageHandler;
@@ -166,6 +170,10 @@
// static
void PrintPreviewDialogController::PrintPreview(WebContents* initiator) {
+#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+ ModuleDatabase::GetInstance()->DisableThirdPartyBlocking();
+#endif
+
if (initiator->ShowingInterstitialPage() || initiator->IsCrashed())
return;
diff --git a/chrome/browser/printing/printing_message_filter.cc b/chrome/browser/printing/printing_message_filter.cc
index b21042e..e415483 100644
--- a/chrome/browser/printing/printing_message_filter.cc
+++ b/chrome/browser/printing/printing_message_filter.cc
@@ -37,6 +37,10 @@
#include "chrome/browser/printing/print_view_manager_basic.h"
#endif
+#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+#include "chrome/browser/conflicts/module_database_win.h"
+#endif
+
using content::BrowserThread;
namespace printing {
@@ -237,6 +241,10 @@
void PrintingMessageFilter::OnScriptedPrint(
const PrintHostMsg_ScriptedPrint_Params& params,
IPC::Message* reply_msg) {
+#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+ ModuleDatabase::GetInstance()->DisableThirdPartyBlocking();
+#endif
+
scoped_refptr<PrinterQuery> printer_query =
queue_->PopPrinterQuery(params.cookie);
if (!printer_query.get()) {
diff --git a/chrome_elf/BUILD.gn b/chrome_elf/BUILD.gn
index 7f780b5..61efc526 100644
--- a/chrome_elf/BUILD.gn
+++ b/chrome_elf/BUILD.gn
@@ -256,10 +256,10 @@
source_set("third_party_shared_defines") {
sources = [
"sha1/sha1.h",
- "third_party_dlls/logging_api.cc",
- "third_party_dlls/logging_api.h",
"third_party_dlls/packed_list_format.cc",
"third_party_dlls/packed_list_format.h",
+ "third_party_dlls/public_api.cc",
+ "third_party_dlls/public_api.h",
"third_party_dlls/status_codes.cc",
"third_party_dlls/status_codes.h",
]
diff --git a/chrome_elf/chrome_elf_test_stubs.cc b/chrome_elf/chrome_elf_test_stubs.cc
index 23b1120..f163dab 100644
--- a/chrome_elf/chrome_elf_test_stubs.cc
+++ b/chrome_elf/chrome_elf_test_stubs.cc
@@ -10,7 +10,7 @@
#include "base/win/windows_types.h"
#include "chrome/common/chrome_switches.h"
#include "chrome_elf/chrome_elf_main.h"
-#include "chrome_elf/third_party_dlls/logging_api.h"
+#include "chrome_elf/third_party_dlls/public_api.h"
// This function is a temporary workaround for https://crbug.com/655788. We
// need to come up with a better way to initialize crash reporting that can
@@ -43,7 +43,7 @@
//------------------------------------------------------------------------------
// chrome_elf\third_party_dlls export test stubs.
// - For use by \\chrome\browser\conflicts\* testing.
-// - Stubs should shadow third_party_dlls\logging_api.h and logs_unittest.cc.
+// - Stubs should shadow third_party_dlls\public_api.h and logs_unittest.cc.
//------------------------------------------------------------------------------
struct TestLogEntry {
@@ -104,3 +104,5 @@
uint32_t GetUniqueBlockedModulesCount() {
return 0;
}
+
+void DisableHook() {}
diff --git a/chrome_elf/chrome_elf_x64.def b/chrome_elf/chrome_elf_x64.def
index 1ba7006..19c0eb2 100644
--- a/chrome_elf/chrome_elf_x64.def
+++ b/chrome_elf/chrome_elf_x64.def
@@ -42,3 +42,6 @@
RegisterLogNotification
GetBlockedModulesCount
GetUniqueBlockedModulesCount
+
+ ; From chrome_elf/third_party_dlls/hook.cc
+ DisableHook
diff --git a/chrome_elf/chrome_elf_x86.def b/chrome_elf/chrome_elf_x86.def
index 9145a482..d9c900b 100644
--- a/chrome_elf/chrome_elf_x86.def
+++ b/chrome_elf/chrome_elf_x86.def
@@ -38,3 +38,6 @@
RegisterLogNotification
GetBlockedModulesCount
GetUniqueBlockedModulesCount
+
+ ; From chrome_elf/third_party_dlls/hook.cc
+ DisableHook
diff --git a/chrome_elf/third_party_dlls/hook.cc b/chrome_elf/third_party_dlls/hook.cc
index 68db6ab2..5d3ac75 100644
--- a/chrome_elf/third_party_dlls/hook.cc
+++ b/chrome_elf/third_party_dlls/hook.cc
@@ -4,6 +4,7 @@
#include "chrome_elf/third_party_dlls/hook.h"
+#include <atomic>
#include <limits>
#include <memory>
@@ -18,6 +19,7 @@
#include "chrome_elf/third_party_dlls/main.h"
#include "chrome_elf/third_party_dlls/packed_list_file.h"
#include "chrome_elf/third_party_dlls/packed_list_format.h"
+#include "chrome_elf/third_party_dlls/public_api.h"
#include "sandbox/win/src/interception_internal.h"
#include "sandbox/win/src/internal_types.h"
#include "sandbox/win/src/nt_internals.h"
@@ -49,6 +51,9 @@
// Set if and when ApplyHook() has been successfully executed.
bool g_hook_active = false;
+// Indicates if the hook was disabled after the hook was activated.
+std::atomic<bool> g_hook_disabled(false);
+
// Set up NTDLL function pointers.
bool InitImports() {
HMODULE ntdll = ::GetModuleHandleW(sandbox::kNtdllName);
@@ -267,6 +272,9 @@
commit_size, offset, view_size, inherit,
allocation_type, protect);
+ if (g_hook_disabled.load(std::memory_order_relaxed))
+ return ret;
+
// If there was an OS-level failure, if the mapping target is NOT this
// process, or if the section is not a (valid) Portable Executable,
// we're not interested. Return the OS-level result code.
@@ -485,3 +493,9 @@
}
} // namespace third_party_dlls
+
+using namespace third_party_dlls;
+
+void DisableHook() {
+ g_hook_disabled.store(true, std::memory_order_relaxed);
+}
diff --git a/chrome_elf/third_party_dlls/logs.h b/chrome_elf/third_party_dlls/logs.h
index 48bb657..f6e2704 100644
--- a/chrome_elf/third_party_dlls/logs.h
+++ b/chrome_elf/third_party_dlls/logs.h
@@ -11,7 +11,7 @@
#include <string>
-#include "chrome_elf/third_party_dlls/logging_api.h"
+#include "chrome_elf/third_party_dlls/public_api.h"
#include "chrome_elf/third_party_dlls/status_codes.h"
namespace third_party_dlls {
diff --git a/chrome_elf/third_party_dlls/logs_unittest.cc b/chrome_elf/third_party_dlls/logs_unittest.cc
index 3aea400..23ddfd0 100644
--- a/chrome_elf/third_party_dlls/logs_unittest.cc
+++ b/chrome_elf/third_party_dlls/logs_unittest.cc
@@ -14,7 +14,7 @@
#include "base/synchronization/waitable_event.h"
#include "base/time/time.h"
#include "chrome_elf/sha1/sha1.h"
-#include "chrome_elf/third_party_dlls/logging_api.h"
+#include "chrome_elf/third_party_dlls/public_api.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace third_party_dlls {
diff --git a/chrome_elf/third_party_dlls/main_unittest_exe.cc b/chrome_elf/third_party_dlls/main_unittest_exe.cc
index f2acb80..e33ac26 100644
--- a/chrome_elf/third_party_dlls/main_unittest_exe.cc
+++ b/chrome_elf/third_party_dlls/main_unittest_exe.cc
@@ -17,9 +17,9 @@
#include "chrome/install_static/install_util.h"
#include "chrome/install_static/product_install_details.h"
#include "chrome_elf/nt_registry/nt_registry.h"
-#include "chrome_elf/third_party_dlls/logging_api.h"
#include "chrome_elf/third_party_dlls/main.h"
#include "chrome_elf/third_party_dlls/packed_list_file.h"
+#include "chrome_elf/third_party_dlls/public_api.h"
using namespace third_party_dlls::main_unittest_exe;
diff --git a/chrome_elf/third_party_dlls/logging_api.cc b/chrome_elf/third_party_dlls/public_api.cc
similarity index 91%
rename from chrome_elf/third_party_dlls/logging_api.cc
rename to chrome_elf/third_party_dlls/public_api.cc
index 107bca6a..8a912b4 100644
--- a/chrome_elf/third_party_dlls/logging_api.cc
+++ b/chrome_elf/third_party_dlls/public_api.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome_elf/third_party_dlls/logging_api.h"
+#include "chrome_elf/third_party_dlls/public_api.h"
#include <stddef.h>
diff --git a/chrome_elf/third_party_dlls/logging_api.h b/chrome_elf/third_party_dlls/public_api.h
similarity index 88%
rename from chrome_elf/third_party_dlls/logging_api.h
rename to chrome_elf/third_party_dlls/public_api.h
index 3a1778b..a2b2e01b 100644
--- a/chrome_elf/third_party_dlls/logging_api.h
+++ b/chrome_elf/third_party_dlls/public_api.h
@@ -6,9 +6,10 @@
// 1. The packed-data format used to pass information from chrome.dll
// to chrome_elf.dll across restarts.
// 2. The APIs exported by chrome_elf.dll to share logs of module load attempts.
+// 3. The API used to disable the NtMapViewOfSection hook.
-#ifndef CHROME_ELF_THIRD_PARTY_DLLS_LOGGING_API_H_
-#define CHROME_ELF_THIRD_PARTY_DLLS_LOGGING_API_H_
+#ifndef CHROME_ELF_THIRD_PARTY_DLLS_PUBLIC_API_H_
+#define CHROME_ELF_THIRD_PARTY_DLLS_PUBLIC_API_H_
#include <windows.h>
@@ -89,4 +90,8 @@
// Returns the number of unique modules that have been blocked.
extern "C" uint32_t GetUniqueBlockedModulesCount();
-#endif // CHROME_ELF_THIRD_PARTY_DLLS_LOGGING_API_H_
+// Disables the hook for NtMapViewOfSection. This function does not remove the
+// hook but merely makes the hook forward the call to the original function.
+extern "C" void DisableHook();
+
+#endif // CHROME_ELF_THIRD_PARTY_DLLS_PUBLIC_API_H_
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index c6312e1..161ced4 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -113745,6 +113745,17 @@
</summary>
</histogram>
+<histogram
+ name="ThirdPartyModules.Heartbeat.PrintingWorkaround.BlockingEnabled"
+ enum="BooleanEnabled">
+ <owner>pmonette@chromium.org</owner>
+ <summary>
+ Records whether or not Chrome is still blocking third-party DLLs. This is a
+ bit that turns to false when the in-process printing is invoked. Recorded
+ every 5 minutes.
+ </summary>
+</histogram>
+
<histogram name="ThirdPartyModules.Heartbeat.UniqueBlockedModulesCount"
units="modules">
<owner>pmonette@chromium.org</owner>