Skip to content

Commit

Permalink
Add Heap corruption chrome URLs.
Browse files Browse the repository at this point in the history
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: Mark Mentovai <mark@chromium.org>
Reviewed-by: John Abd-El-Malek <jam@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577989}
  • Loading branch information
wfh-chromium authored and Commit Bot committed Jul 25, 2018
1 parent 4b7e257 commit eb4a6ff
Show file tree
Hide file tree
Showing 11 changed files with 167 additions and 17 deletions.
2 changes: 2 additions & 0 deletions base/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,8 @@ jumbo_component("base") {
"debug/dump_without_crashing.h",
"debug/gdi_debug_util_win.cc",
"debug/gdi_debug_util_win.h",
"debug/invalid_access_win.cc",
"debug/invalid_access_win.h",
"debug/leak_annotations.h",
"debug/leak_tracker.h",
"debug/proc_maps_linux.cc",
Expand Down
56 changes: 56 additions & 0 deletions base/debug/invalid_access_win.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// 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
22 changes: 22 additions & 0 deletions base/debug/invalid_access_win.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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_
8 changes: 8 additions & 0 deletions base/process/process_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <utility>

#include "base/at_exit.h"
#include "base/debug/invalid_access_win.h"
#include "base/process/kill.h"
#include "base/test/multiprocess_test.h"
#include "base/test/test_timeouts.h"
Expand Down Expand Up @@ -299,6 +300,13 @@ TEST_F(ProcessTest, PredefinedProcessIsRunning) {
}
#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) {
Process process(SpawnChild("SleepyChildProcess"));
EXPECT_FALSE(process.WaitForExitWithTimeout(
Expand Down
21 changes: 21 additions & 0 deletions chrome/browser/metrics/metrics_service_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,27 @@ IN_PROC_BROWSER_TEST_F(MetricsServiceBrowserTest, MAYBE_CrashRenderers) {
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) {
base::HistogramTester histogram_tester;

Expand Down
39 changes: 22 additions & 17 deletions chrome/common/webui_url_constants.cc
Original file line number Diff line number Diff line change
Expand Up @@ -425,25 +425,30 @@ const char* const kChromeHostURLs[] = {
};
const size_t kNumberOfChromeHostURLs = arraysize(kChromeHostURLs);

const char* const kChromeDebugURLs[] = {content::kChromeUIBadCastCrashURL,
content::kChromeUIBrowserCrashURL,
content::kChromeUICrashURL,
content::kChromeUIDumpURL,
content::kChromeUIKillURL,
content::kChromeUIHangURL,
content::kChromeUIShorthangURL,
content::kChromeUIGpuCleanURL,
content::kChromeUIGpuCrashURL,
content::kChromeUIGpuHangURL,
content::kChromeUIMemoryExhaustURL,
content::kChromeUIPpapiFlashCrashURL,
content::kChromeUIPpapiFlashHangURL,
const char* const kChromeDebugURLs[] = {
content::kChromeUIBadCastCrashURL,
content::kChromeUIBrowserCrashURL,
content::kChromeUICrashURL,
content::kChromeUIDumpURL,
content::kChromeUIKillURL,
content::kChromeUIHangURL,
content::kChromeUIShorthangURL,
content::kChromeUIGpuCleanURL,
content::kChromeUIGpuCrashURL,
content::kChromeUIGpuHangURL,
content::kChromeUIMemoryExhaustURL,
content::kChromeUIPpapiFlashCrashURL,
content::kChromeUIPpapiFlashHangURL,
#if defined(OS_WIN)
content::kChromeUIBrowserHeapCorruptionURL,
content::kChromeUIHeapCorruptionCrashURL,
#endif
#if defined(OS_ANDROID)
content::kChromeUIGpuJavaCrashURL,
kChromeUIJavaCrashURL,
content::kChromeUIGpuJavaCrashURL,
kChromeUIJavaCrashURL,
#endif
kChromeUIQuitURL,
kChromeUIRestartURL};
kChromeUIQuitURL,
kChromeUIRestartURL};
const size_t kNumberOfChromeDebugURLs = arraysize(kChromeDebugURLs);

} // namespace chrome
12 changes: 12 additions & 0 deletions content/browser/frame_host/debug_urls.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
#include "ppapi/proxy/ppapi_messages.h" // nogncheck
#endif

#if defined(OS_WIN)
#include "base/debug/invalid_access_win.h"
#endif

namespace content {

class ScopedAllowWaitForDebugURL {
Expand Down Expand Up @@ -142,6 +146,14 @@ bool HandleDebugURL(const GURL& url, ui::PageTransition transition) {
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) {
HangCurrentThread();
return true;
Expand Down
5 changes: 5 additions & 0 deletions content/public/common/url_constants.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ const char kChromeUIProcessInternalsURL[] = "chrome://process-internals";
#if defined(OS_ANDROID)
const char kChromeUIGpuJavaCrashURL[] = "chrome://gpu-java-crash/";
#endif
#if defined(OS_WIN)
const char kChromeUIBrowserHeapCorruptionURL[] =
"chrome://inducebrowserheapcorruption/";
const char kChromeUIHeapCorruptionCrashURL[] = "chrome://heapcorruptioncrash/";
#endif
#if defined(ADDRESS_SANITIZER)
const char kChromeUICrashHeapOverflowURL[] = "chrome://crash/heap-overflow";
const char kChromeUICrashHeapUnderflowURL[] = "chrome://crash/heap-underflow";
Expand Down
4 changes: 4 additions & 0 deletions content/public/common/url_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ CONTENT_EXPORT extern const char kChromeUIProcessInternalsURL[];
#if defined(OS_ANDROID)
CONTENT_EXPORT extern const char kChromeUIGpuJavaCrashURL[];
#endif
#if defined(OS_WIN)
CONTENT_EXPORT extern const char kChromeUIBrowserHeapCorruptionURL[];
CONTENT_EXPORT extern const char kChromeUIHeapCorruptionCrashURL[];
#endif
#if defined(ADDRESS_SANITIZER)
CONTENT_EXPORT extern const char kChromeUICrashHeapOverflowURL[];
CONTENT_EXPORT extern const char kChromeUICrashHeapUnderflowURL[];
Expand Down
5 changes: 5 additions & 0 deletions content/public/common/url_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ bool IsRendererDebugURL(const GURL& url) {
}
#endif

#if defined(OS_WIN)
if (url == kChromeUIHeapCorruptionCrashURL)
return true;
#endif

#if DCHECK_IS_ON()
if (url == kChromeUICrashDcheckURL)
return true;
Expand Down
10 changes: 10 additions & 0 deletions content/renderer/render_frame_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@
#endif

#if defined(OS_WIN)
#include "base/debug/invalid_access_win.h"
#include "base/process/kill.h"
#elif defined(OS_POSIX)
#include <signal.h>
Expand Down Expand Up @@ -1063,6 +1064,15 @@ void HandleChromeDebugURL(const GURL& url) {
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 (url == kChromeUICrashDcheckURL) {
LOG(ERROR) << "Intentionally causing DCHECK because user navigated to "
Expand Down

0 comments on commit eb4a6ff

Please sign in to comment.