Commit eb4a6ff5 authored by Will Harris's avatar Will Harris Committed by Commit Bot

Add Heap corruption chrome URLs.

chrome://heapcorruptioncrash/ to crash a child renderer process.
chrome://inducebrowserheapcorruption/ to crash a browser process.

BUG=865632

Change-Id: I69caa1c80cd1775f416d656312222b9b4856f682
Reviewed-on: https://chromium-review.googlesource.com/1129628
Commit-Queue: Will Harris <wfh@chromium.org>
Reviewed-by: default avatarMark Mentovai <mark@chromium.org>
Reviewed-by: default avatarJohn Abd-El-Malek <jam@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577989}
parent 4b7e2572
...@@ -319,6 +319,8 @@ jumbo_component("base") { ...@@ -319,6 +319,8 @@ jumbo_component("base") {
"debug/dump_without_crashing.h", "debug/dump_without_crashing.h",
"debug/gdi_debug_util_win.cc", "debug/gdi_debug_util_win.cc",
"debug/gdi_debug_util_win.h", "debug/gdi_debug_util_win.h",
"debug/invalid_access_win.cc",
"debug/invalid_access_win.h",
"debug/leak_annotations.h", "debug/leak_annotations.h",
"debug/leak_tracker.h", "debug/leak_tracker.h",
"debug/proc_maps_linux.cc", "debug/proc_maps_linux.cc",
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/debug/invalid_access_win.h"
#include <stdlib.h>
#include <windows.h>
#include "base/logging.h"
#include "base/win/windows_version.h"
namespace base {
namespace debug {
namespace win {
namespace {
void CreateSyntheticHeapCorruption() {
EXCEPTION_RECORD record = {};
record.ExceptionCode = STATUS_HEAP_CORRUPTION;
RaiseFailFastException(&record, nullptr,
FAIL_FAST_GENERATE_EXCEPTION_ADDRESS);
}
} // namespace
void TerminateWithHeapCorruption() {
__try {
// Pre-Windows 10, it's hard to trigger a heap corruption fast fail, so
// artificially create one instead.
if (base::win::GetVersion() < base::win::VERSION_WIN10)
CreateSyntheticHeapCorruption();
HANDLE heap = ::HeapCreate(0, 0, 0);
CHECK(heap);
CHECK(HeapSetInformation(heap, HeapEnableTerminationOnCorruption, nullptr,
0));
void* addr = ::HeapAlloc(heap, 0, 0x1000);
CHECK(addr);
// Corrupt heap header.
char* addr_mutable = reinterpret_cast<char*>(addr);
memset(addr_mutable - sizeof(addr), 0xCC, sizeof(addr));
HeapFree(heap, 0, addr);
HeapDestroy(heap);
} __except (EXCEPTION_EXECUTE_HANDLER) {
// Heap corruption exception should never be caught.
CHECK(false);
}
// Should never reach here.
abort();
}
} // namespace win
} // namespace debug
} // namespace base
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_DEBUG_INVALID_ACCESS_WIN_H_
#define BASE_DEBUG_INVALID_ACCESS_WIN_H_
#include "base/base_export.h"
namespace base {
namespace debug {
namespace win {
// Creates a synthetic heap corruption that causes the current process to
// terminate immediately with a fast fail exception.
[[noreturn]] BASE_EXPORT void TerminateWithHeapCorruption();
} // namespace win
} // namespace debug
} // namespace base
#endif // BASE_DEBUG_INVALID_ACCESS_WIN_H_
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <utility> #include <utility>
#include "base/at_exit.h" #include "base/at_exit.h"
#include "base/debug/invalid_access_win.h"
#include "base/process/kill.h" #include "base/process/kill.h"
#include "base/test/multiprocess_test.h" #include "base/test/multiprocess_test.h"
#include "base/test/test_timeouts.h" #include "base/test/test_timeouts.h"
...@@ -299,6 +300,13 @@ TEST_F(ProcessTest, PredefinedProcessIsRunning) { ...@@ -299,6 +300,13 @@ TEST_F(ProcessTest, PredefinedProcessIsRunning) {
} }
#endif #endif
#if defined(OS_WIN)
TEST_F(ProcessTest, HeapCorruption) {
EXPECT_EXIT(base::debug::win::TerminateWithHeapCorruption(),
::testing::ExitedWithCode(STATUS_HEAP_CORRUPTION), "");
}
#endif
TEST_F(ProcessTest, ChildProcessIsRunning) { TEST_F(ProcessTest, ChildProcessIsRunning) {
Process process(SpawnChild("SleepyChildProcess")); Process process(SpawnChild("SleepyChildProcess"));
EXPECT_FALSE(process.WaitForExitWithTimeout( EXPECT_FALSE(process.WaitForExitWithTimeout(
......
...@@ -179,6 +179,27 @@ IN_PROC_BROWSER_TEST_F(MetricsServiceBrowserTest, MAYBE_CrashRenderers) { ...@@ -179,6 +179,27 @@ IN_PROC_BROWSER_TEST_F(MetricsServiceBrowserTest, MAYBE_CrashRenderers) {
histogram_tester.ExpectUniqueSample("Tabs.SadTab.CrashCreated", 1, 1); histogram_tester.ExpectUniqueSample("Tabs.SadTab.CrashCreated", 1, 1);
} }
#if defined(OS_WIN)
IN_PROC_BROWSER_TEST_F(MetricsServiceBrowserTest, HeapCorruptionInRenderer) {
base::HistogramTester histogram_tester;
OpenTabsAndNavigateToCrashyUrl(content::kChromeUIHeapCorruptionCrashURL);
// Verify that the expected stability metrics were recorded.
const PrefService* prefs = g_browser_process->local_state();
EXPECT_EQ(1, prefs->GetInteger(metrics::prefs::kStabilityLaunchCount));
// The three tabs from OpenTabs() and the one tab to open chrome://crash/.
EXPECT_EQ(4, prefs->GetInteger(metrics::prefs::kStabilityPageLoadCount));
EXPECT_EQ(1, prefs->GetInteger(metrics::prefs::kStabilityRendererCrashCount));
histogram_tester.ExpectUniqueSample(
"CrashExitCodes.Renderer",
std::abs(static_cast<int32_t>(STATUS_HEAP_CORRUPTION)), 1);
histogram_tester.ExpectUniqueSample("Tabs.SadTab.CrashCreated", 1, 1);
LOG(INFO) << histogram_tester.GetAllHistogramsRecorded();
}
#endif // OS_WIN
IN_PROC_BROWSER_TEST_F(MetricsServiceBrowserTest, MAYBE_CheckCrashRenderers) { IN_PROC_BROWSER_TEST_F(MetricsServiceBrowserTest, MAYBE_CheckCrashRenderers) {
base::HistogramTester histogram_tester; base::HistogramTester histogram_tester;
......
...@@ -425,25 +425,30 @@ const char* const kChromeHostURLs[] = { ...@@ -425,25 +425,30 @@ const char* const kChromeHostURLs[] = {
}; };
const size_t kNumberOfChromeHostURLs = arraysize(kChromeHostURLs); const size_t kNumberOfChromeHostURLs = arraysize(kChromeHostURLs);
const char* const kChromeDebugURLs[] = {content::kChromeUIBadCastCrashURL, const char* const kChromeDebugURLs[] = {
content::kChromeUIBrowserCrashURL, content::kChromeUIBadCastCrashURL,
content::kChromeUICrashURL, content::kChromeUIBrowserCrashURL,
content::kChromeUIDumpURL, content::kChromeUICrashURL,
content::kChromeUIKillURL, content::kChromeUIDumpURL,
content::kChromeUIHangURL, content::kChromeUIKillURL,
content::kChromeUIShorthangURL, content::kChromeUIHangURL,
content::kChromeUIGpuCleanURL, content::kChromeUIShorthangURL,
content::kChromeUIGpuCrashURL, content::kChromeUIGpuCleanURL,
content::kChromeUIGpuHangURL, content::kChromeUIGpuCrashURL,
content::kChromeUIMemoryExhaustURL, content::kChromeUIGpuHangURL,
content::kChromeUIPpapiFlashCrashURL, content::kChromeUIMemoryExhaustURL,
content::kChromeUIPpapiFlashHangURL, content::kChromeUIPpapiFlashCrashURL,
content::kChromeUIPpapiFlashHangURL,
#if defined(OS_WIN)
content::kChromeUIBrowserHeapCorruptionURL,
content::kChromeUIHeapCorruptionCrashURL,
#endif
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
content::kChromeUIGpuJavaCrashURL, content::kChromeUIGpuJavaCrashURL,
kChromeUIJavaCrashURL, kChromeUIJavaCrashURL,
#endif #endif
kChromeUIQuitURL, kChromeUIQuitURL,
kChromeUIRestartURL}; kChromeUIRestartURL};
const size_t kNumberOfChromeDebugURLs = arraysize(kChromeDebugURLs); const size_t kNumberOfChromeDebugURLs = arraysize(kChromeDebugURLs);
} // namespace chrome } // namespace chrome
...@@ -26,6 +26,10 @@ ...@@ -26,6 +26,10 @@
#include "ppapi/proxy/ppapi_messages.h" // nogncheck #include "ppapi/proxy/ppapi_messages.h" // nogncheck
#endif #endif
#if defined(OS_WIN)
#include "base/debug/invalid_access_win.h"
#endif
namespace content { namespace content {
class ScopedAllowWaitForDebugURL { class ScopedAllowWaitForDebugURL {
...@@ -142,6 +146,14 @@ bool HandleDebugURL(const GURL& url, ui::PageTransition transition) { ...@@ -142,6 +146,14 @@ bool HandleDebugURL(const GURL& url, ui::PageTransition transition) {
return true; return true;
} }
#if defined(OS_WIN)
if (url == kChromeUIBrowserHeapCorruptionURL) {
// Induce an intentional heap corruption in the browser process.
base::debug::win::TerminateWithHeapCorruption();
return true;
}
#endif
if (url == kChromeUIBrowserUIHang) { if (url == kChromeUIBrowserUIHang) {
HangCurrentThread(); HangCurrentThread();
return true; return true;
......
...@@ -58,6 +58,11 @@ const char kChromeUIProcessInternalsURL[] = "chrome://process-internals"; ...@@ -58,6 +58,11 @@ const char kChromeUIProcessInternalsURL[] = "chrome://process-internals";
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
const char kChromeUIGpuJavaCrashURL[] = "chrome://gpu-java-crash/"; const char kChromeUIGpuJavaCrashURL[] = "chrome://gpu-java-crash/";
#endif #endif
#if defined(OS_WIN)
const char kChromeUIBrowserHeapCorruptionURL[] =
"chrome://inducebrowserheapcorruption/";
const char kChromeUIHeapCorruptionCrashURL[] = "chrome://heapcorruptioncrash/";
#endif
#if defined(ADDRESS_SANITIZER) #if defined(ADDRESS_SANITIZER)
const char kChromeUICrashHeapOverflowURL[] = "chrome://crash/heap-overflow"; const char kChromeUICrashHeapOverflowURL[] = "chrome://crash/heap-overflow";
const char kChromeUICrashHeapUnderflowURL[] = "chrome://crash/heap-underflow"; const char kChromeUICrashHeapUnderflowURL[] = "chrome://crash/heap-underflow";
......
...@@ -69,6 +69,10 @@ CONTENT_EXPORT extern const char kChromeUIProcessInternalsURL[]; ...@@ -69,6 +69,10 @@ CONTENT_EXPORT extern const char kChromeUIProcessInternalsURL[];
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
CONTENT_EXPORT extern const char kChromeUIGpuJavaCrashURL[]; CONTENT_EXPORT extern const char kChromeUIGpuJavaCrashURL[];
#endif #endif
#if defined(OS_WIN)
CONTENT_EXPORT extern const char kChromeUIBrowserHeapCorruptionURL[];
CONTENT_EXPORT extern const char kChromeUIHeapCorruptionCrashURL[];
#endif
#if defined(ADDRESS_SANITIZER) #if defined(ADDRESS_SANITIZER)
CONTENT_EXPORT extern const char kChromeUICrashHeapOverflowURL[]; CONTENT_EXPORT extern const char kChromeUICrashHeapOverflowURL[];
CONTENT_EXPORT extern const char kChromeUICrashHeapUnderflowURL[]; CONTENT_EXPORT extern const char kChromeUICrashHeapUnderflowURL[];
......
...@@ -90,6 +90,11 @@ bool IsRendererDebugURL(const GURL& url) { ...@@ -90,6 +90,11 @@ bool IsRendererDebugURL(const GURL& url) {
} }
#endif #endif
#if defined(OS_WIN)
if (url == kChromeUIHeapCorruptionCrashURL)
return true;
#endif
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
if (url == kChromeUICrashDcheckURL) if (url == kChromeUICrashDcheckURL)
return true; return true;
......
...@@ -239,6 +239,7 @@ ...@@ -239,6 +239,7 @@
#endif #endif
#if defined(OS_WIN) #if defined(OS_WIN)
#include "base/debug/invalid_access_win.h"
#include "base/process/kill.h" #include "base/process/kill.h"
#elif defined(OS_POSIX) #elif defined(OS_POSIX)
#include <signal.h> #include <signal.h>
...@@ -1063,6 +1064,15 @@ void HandleChromeDebugURL(const GURL& url) { ...@@ -1063,6 +1064,15 @@ void HandleChromeDebugURL(const GURL& url) {
CHECK(false); CHECK(false);
} }
#if defined(OS_WIN)
if (url == kChromeUIHeapCorruptionCrashURL) {
LOG(ERROR)
<< "Intentionally causing heap corruption because user navigated to "
<< url.spec();
base::debug::win::TerminateWithHeapCorruption();
}
#endif
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
if (url == kChromeUICrashDcheckURL) { if (url == kChromeUICrashDcheckURL) {
LOG(ERROR) << "Intentionally causing DCHECK because user navigated to " LOG(ERROR) << "Intentionally causing DCHECK because user navigated to "
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment