diff options
Diffstat (limited to 'app/clipboard/clipboard.cc')
-rw-r--r-- | app/clipboard/clipboard.cc | 108 |
1 files changed, 104 insertions, 4 deletions
diff --git a/app/clipboard/clipboard.cc b/app/clipboard/clipboard.cc index a2050a0..54a7d90 100644 --- a/app/clipboard/clipboard.cc +++ b/app/clipboard/clipboard.cc @@ -6,11 +6,22 @@ #include "base/gfx/size.h" #include "base/logging.h" +#include "base/scoped_ptr.h" namespace { // A compromised renderer could send us bad data, so validate it. -bool IsBitmapSafe(const Clipboard::ObjectMapParams& params) { +// This function only checks that the size parameter makes sense, the caller +// is responsible for further validating the bitmap buffer against +// |bitmap_bytes|. +// +// |params| - Clipboard bitmap contents to validate. +// |bitmap_bytes| - On return contains the number of bytes needed to store +// the bitmap data or -1 if the data is invalid. +// returns: true if the bitmap size is valid, false otherwise. +bool IsBitmapSafe(const Clipboard::ObjectMapParams& params, + size_t* bitmap_bytes) { + *bitmap_bytes = -1; if (params[1].size() != sizeof(gfx::Size)) return false; const gfx::Size* size = @@ -23,7 +34,40 @@ bool IsBitmapSafe(const Clipboard::ObjectMapParams& params) { if (INT_MAX / total_size <= 4) return false; total_size *= 4; - return params[0].size() == total_size; + *bitmap_bytes = total_size; + return true; +} + +// Validates a plain bitmap on the clipboard. +// Returns true if the clipboard data makes sense and it's safe to access the +// bitmap. +bool ValidatePlainBitmap(const Clipboard::ObjectMapParams& params) { + size_t bitmap_bytes = -1; + if (!IsBitmapSafe(params, &bitmap_bytes)) + return false; + if (bitmap_bytes != params[0].size()) + return false; + return true; +} + +// Valides a shared bitmap on the clipboard. +// Returns true if the clipboard data makes sense and it's safe to access the +// bitmap. +bool ValidateAndMapSharedBitmap(const Clipboard::ObjectMapParams& params, + base::SharedMemory* bitmap_data) { + using base::SharedMemory; + size_t bitmap_bytes = -1; + if (!IsBitmapSafe(params, &bitmap_bytes)) + return false; + + if (!bitmap_data || !SharedMemory::IsHandleValid(bitmap_data->handle())) + return false; + + if (!bitmap_data->Map(bitmap_bytes)) { + PLOG(ERROR) << "Failed to map bitmap memory"; + return false; + } + return true; } } // namespace @@ -33,7 +77,8 @@ void Clipboard::DispatchObject(ObjectType type, const ObjectMapParams& params) { if (type != CBF_WEBKIT && (params.empty() || params[0].empty())) return; // Some other types need a non-empty 2nd param. - if ((type == CBF_BOOKMARK || type == CBF_BITMAP || type == CBF_DATA) && + if ((type == CBF_BOOKMARK || type == CBF_BITMAP || + type == CBF_SMBITMAP || type == CBF_DATA) && (params.size() != 2 || params[1].empty())) return; switch (type) { @@ -62,11 +107,34 @@ void Clipboard::DispatchObject(ObjectType type, const ObjectMapParams& params) { break; case CBF_BITMAP: - if (!IsBitmapSafe(params)) + if (!ValidatePlainBitmap(params)) return; + WriteBitmap(&(params[0].front()), &(params[1].front())); break; + case CBF_SMBITMAP: { + using base::SharedMemory; + using base::SharedMemoryHandle; + + if (params[0].size() != sizeof(SharedMemory*)) + return; + + // It's OK to cast away constness here since we map the handle as + // read-only. + const char* raw_bitmap_data_const = + reinterpret_cast<const char*>(&(params[0].front())); + char* raw_bitmap_data = const_cast<char*>(raw_bitmap_data_const); + scoped_ptr<SharedMemory> bitmap_data( + *reinterpret_cast<SharedMemory**>(raw_bitmap_data)); + + if (!ValidateAndMapSharedBitmap(params, bitmap_data.get())) + return; + WriteBitmap(static_cast<const char*>(bitmap_data->memory()), + &(params[1].front())); + break; + } + #if !defined(OS_MACOSX) case CBF_DATA: WriteData(&(params[0].front()), params[0].size(), @@ -78,3 +146,35 @@ void Clipboard::DispatchObject(ObjectType type, const ObjectMapParams& params) { NOTREACHED(); } } + +// static +void Clipboard::ReplaceSharedMemHandle(ObjectMap* objects, + base::SharedMemoryHandle bitmap_handle, + base::ProcessHandle process) { + using base::SharedMemory; + bool has_shared_bitmap = false; + + for (ObjectMap::iterator iter = objects->begin(); iter != objects->end(); + ++iter) { + if (iter->first == CBF_SMBITMAP) { + // The code currently only accepts sending a single bitmap over this way. + // Fail hard if we ever encounter more than one shared bitmap structure to + // fill. + CHECK(!has_shared_bitmap); + +#if defined(OS_WIN) + SharedMemory* bitmap = new SharedMemory(bitmap_handle, true, process); +#else + SharedMemory* bitmap = new SharedMemory(bitmap_handle, true); +#endif + + // We store the shared memory object pointer so it can be retrieved by the + // UI thread (see DispatchObject()). + iter->second[0].clear(); + for (size_t i = 0; i < sizeof(SharedMemory*); ++i) + iter->second[0].push_back(reinterpret_cast<char*>(&bitmap)[i]); + has_shared_bitmap = true; + } + } +} + |