Chromium Code Reviews| 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) |