Index: skia/ext/bitmap_platform_device_win.cc |
diff --git a/skia/ext/bitmap_platform_device_win.cc b/skia/ext/bitmap_platform_device_win.cc |
index 63108209abc313b305256319246a06fa7d03424c..a692927eaa05ab02cd868c28571ea22c151d717c 100644 |
--- a/skia/ext/bitmap_platform_device_win.cc |
+++ b/skia/ext/bitmap_platform_device_win.cc |
@@ -6,6 +6,7 @@ |
#include <psapi.h> |
#include "base/debug/gdi_debug_util_win.h" |
+#include "base/lazy_instance.h" |
#include "base/logging.h" |
#include "skia/ext/bitmap_platform_device_win.h" |
#include "skia/ext/platform_canvas.h" |
@@ -16,6 +17,59 @@ |
namespace { |
+// This file contains an implementation of a Skia platform bitmap for drawing |
+// and compositing graphics. The original implementation uses Windows GDI |
+// to create the backing bitmap memory, however when using the sandbox security |
+// policy win32k lockdown it's not possible to use GDI for security reasons. |
+// Therefore this code also implements a fallback mechanism when a process is |
+// under this security policy to directly map the shared section as memory |
+// instead of using GDI. To catch new code which tries to explicitly rely on |
+// this code using GDI some additional DCHECKs have been added to catch that |
+// code during development. |
+typedef decltype(GetProcessMitigationPolicy)* GetProcessMitigationPolicyType; |
+ |
+// Get win32k lockdown policy using a lazy instance so it's only initialized |
+// once and is thread-safe. |
+class LazyIsWin32kLockdownEnabled { |
+ public: |
+ LazyIsWin32kLockdownEnabled() |
+ : value_(IsWin32kLockdownEnabled()) {} |
+ |
+ ~LazyIsWin32kLockdownEnabled() {} |
+ |
+ bool value() { return value_; } |
+ |
+ private: |
+ static bool IsWin32kLockdownEnabled() { |
+ GetProcessMitigationPolicyType get_process_mitigation_policy_func = |
+ reinterpret_cast<GetProcessMitigationPolicyType>( |
+ GetProcAddress( |
+ GetModuleHandle(L"kernel32.dll"), |
+ "GetProcessMitigationPolicy")); |
+ |
+ if (!get_process_mitigation_policy_func) |
+ return false; |
+ |
+ PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = {0}; |
+ if (get_process_mitigation_policy_func(GetCurrentProcess(), |
+ ProcessSystemCallDisablePolicy, |
+ &policy, |
+ sizeof(policy))) |
+ return policy.DisallowWin32kSystemCalls != 0; |
+ |
+ return false; |
+ } |
+ |
+ const bool value_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(LazyIsWin32kLockdownEnabled); |
+}; |
+ |
+bool IsWin32kLockdownEnabled() { |
+ static base::LazyInstance<LazyIsWin32kLockdownEnabled> win32k_lockdown; |
Will Harris
2015/09/10 17:34:45
I think this needs a LAZY_INSTANCE_INITIALIZER
|
+ return win32k_lockdown.Get().value(); |
+} |
+ |
HBITMAP CreateHBitmap(int width, int height, bool is_opaque, |
HANDLE shared_section, void** data) { |
// CreateDIBSection appears to get unhappy if we create an empty bitmap, so |
@@ -57,6 +111,7 @@ namespace skia { |
void DrawToNativeContext(SkCanvas* canvas, HDC hdc, int x, int y, |
const RECT* src_rect) { |
+ DCHECK(!IsWin32kLockdownEnabled()); |
PlatformDevice* platform_device = GetPlatformDevice(GetTopDevice(*canvas)); |
if (platform_device) |
platform_device->DrawToHDC(hdc, x, y, src_rect); |
@@ -65,6 +120,7 @@ void DrawToNativeContext(SkCanvas* canvas, HDC hdc, int x, int y, |
void PlatformDevice::DrawToHDC(HDC, int x, int y, const RECT* src_rect) {} |
HDC BitmapPlatformDevice::GetBitmapDC() { |
+ DCHECK(!IsWin32kLockdownEnabled()); |
if (!hdc_) { |
hdc_ = CreateCompatibleDC(NULL); |
InitializeDC(hdc_); |
@@ -76,11 +132,13 @@ HDC BitmapPlatformDevice::GetBitmapDC() { |
} |
void BitmapPlatformDevice::ReleaseBitmapDC() { |
- SkASSERT(hdc_); |
- SelectObject(hdc_, old_hbitmap_); |
- DeleteDC(hdc_); |
- hdc_ = NULL; |
- old_hbitmap_ = NULL; |
+ if (!IsWin32kLockdownEnabled()) { |
+ SkASSERT(hdc_); |
+ SelectObject(hdc_, old_hbitmap_); |
+ DeleteDC(hdc_); |
+ hdc_ = NULL; |
+ old_hbitmap_ = NULL; |
+ } |
} |
bool BitmapPlatformDevice::IsBitmapDCCreated() |
@@ -108,7 +166,12 @@ void BitmapPlatformDevice::LoadConfig() { |
} |
static void DeleteHBitmapCallback(void* addr, void* context) { |
- DeleteObject(static_cast<HBITMAP>(context)); |
+ // If context is not NULL then it's a valid HBITMAP to delete. |
+ // Otherwise we just unmap the pixel memory. |
+ if (context) |
+ DeleteObject(static_cast<HBITMAP>(context)); |
+ else |
+ UnmapViewOfFile(addr); |
} |
static bool InstallHBitmapPixels(SkBitmap* bitmap, int width, int height, |
@@ -133,10 +196,22 @@ BitmapPlatformDevice* BitmapPlatformDevice::Create( |
bool do_clear) { |
void* data; |
- HBITMAP hbitmap = CreateHBitmap(width, height, is_opaque, shared_section, |
+ |
+ HBITMAP hbitmap = NULL; |
+ |
+ if (IsWin32kLockdownEnabled()) { |
+ CHECK(shared_section != NULL); |
+ data = MapViewOfFile(shared_section, FILE_MAP_WRITE, |
+ 0, 0, width * height * 4); |
+ DCHECK(data != NULL); |
+ if (!data) |
+ return NULL; |
+ } else { |
+ hbitmap = CreateHBitmap(width, height, is_opaque, shared_section, |
&data); |
- if (!hbitmap) |
- return NULL; |
+ if (!hbitmap) |
+ return NULL; |
+ } |
SkBitmap bitmap; |
if (!InstallHBitmapPixels(&bitmap, width, height, is_opaque, data, hbitmap)) |
@@ -180,12 +255,14 @@ BitmapPlatformDevice::BitmapPlatformDevice( |
// The data object is already ref'ed for us by create(). |
SkDEBUGCODE(begin_paint_count_ = 0); |
SetPlatformDevice(this, this); |
- // Initialize the clip region to the entire bitmap. |
- BITMAP bitmap_data; |
- if (GetObject(hbitmap_, sizeof(BITMAP), &bitmap_data)) { |
- SkIRect rect; |
- rect.set(0, 0, bitmap_data.bmWidth, bitmap_data.bmHeight); |
- clip_region_ = SkRegion(rect); |
+ if (hbitmap) { |
+ // Initialize the clip region to the entire bitmap. |
+ BITMAP bitmap_data; |
+ if (GetObject(hbitmap_, sizeof(BITMAP), &bitmap_data)) { |
+ SkIRect rect; |
+ rect.set(0, 0, bitmap_data.bmWidth, bitmap_data.bmHeight); |
+ clip_region_ = SkRegion(rect); |
+ } |
} |
} |
@@ -213,6 +290,8 @@ void BitmapPlatformDevice::setMatrixClip(const SkMatrix& transform, |
void BitmapPlatformDevice::DrawToHDC(HDC dc, int x, int y, |
const RECT* src_rect) { |
+ DCHECK(!IsWin32kLockdownEnabled()); |
+ |
bool created_dc = !IsBitmapDCCreated(); |
HDC source_dc = BeginPlatformPaint(); |
@@ -305,6 +384,7 @@ PlatformBitmap::~PlatformBitmap() { |
} |
bool PlatformBitmap::Allocate(int width, int height, bool is_opaque) { |
+ DCHECK(!IsWin32kLockdownEnabled()); |
void* data; |
HBITMAP hbitmap = CreateHBitmap(width, height, is_opaque, 0, &data); |
if (!hbitmap) |