From 6ac4d771cbc03aec5239785daa8b405bda8f640e Mon Sep 17 00:00:00 2001 From: Alexander Dunaev Date: Wed, 16 Jan 2019 11:19:40 +0100 Subject: [PATCH] [ozone/wayland] fuzzer for wayland buffer manager is introduced Change-Id: I5d7944d1bcc9780f072f946387f414ecb0c7d96d --- ui/ozone/platform/wayland/BUILD.gn | 26 +++- ui/ozone/platform/wayland/test/mock_buffer.cc | 4 +- .../platform/wayland/wayland_buffer_fuzzer.cc | 133 ++++++++++++++++++ .../wayland/wayland_buffer_manager.cc | 8 +- .../platform/wayland/wayland_connection.cc | 7 +- 5 files changed, 167 insertions(+), 11 deletions(-) create mode 100644 ui/ozone/platform/wayland/wayland_buffer_fuzzer.cc diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn index e19abd74731ca..f12737378ecc5 100644 --- a/ui/ozone/platform/wayland/BUILD.gn +++ b/ui/ozone/platform/wayland/BUILD.gn @@ -5,6 +5,7 @@ visibility = [ "//ui/ozone/*" ] import("//build/config/linux/pkg_config.gni") +import("//testing/libfuzzer/fuzzer_test.gni") import("//ui/ozone/platform/wayland/wayland.gni") pkg_config("wayland-egl") { @@ -204,6 +205,7 @@ source_set("test_support") { "test/test_zwp_text_input_manager.h", ] + defines = [ "WL_HIDE_DEPRECATED" ] deps = [ "//base:base", "//skia", @@ -256,9 +258,25 @@ source_set("wayland_unittests") { if (use_xkbcommon) { deps += [ "//ui/events/keycodes:xkb" ] } +} - defines = [ "WL_HIDE_DEPRECATED" ] - if (use_wayland_gbm) { - defines += [ "WAYLAND_GBM" ] - } +fuzzer_test("wayland_buffer_fuzzer") { + sources = [ + "wayland_buffer_fuzzer.cc" + ] + deps = [ + ":wayland", + ":test_support", + "//base/test:test_support", + "//build/config/linux/libdrm", + "//testing/gmock", + "//third_party/wayland:wayland_server", + "//third_party/wayland-protocols:linux_dmabuf_protocol", + "//third_party/wayland-protocols:text_input_protocol", + "//third_party/wayland-protocols:xdg_shell_protocol", + "//ui/gfx:test_support", + "//ui/ozone/common/linux:drm", + "//ui/ozone:platform", + ] } + diff --git a/ui/ozone/platform/wayland/test/mock_buffer.cc b/ui/ozone/platform/wayland/test/mock_buffer.cc index b31f9283d7728..d2b504e9eefde 100644 --- a/ui/ozone/platform/wayland/test/mock_buffer.cc +++ b/ui/ozone/platform/wayland/test/mock_buffer.cc @@ -12,10 +12,8 @@ MockBuffer::MockBuffer(wl_resource* resource, std::vector&& fds) : ServerObject(resource), fds_(std::move(fds)) {} MockBuffer::~MockBuffer() { - for (auto& fd : fds_) { - LOG(WARNING) << "Will close FD: " << fd.get(); + for (auto& fd : fds_) fd.reset(); - } } } // namespace wl diff --git a/ui/ozone/platform/wayland/wayland_buffer_fuzzer.cc b/ui/ozone/platform/wayland/wayland_buffer_fuzzer.cc new file mode 100644 index 0000000000000..033cb1029f462 --- /dev/null +++ b/ui/ozone/platform/wayland/wayland_buffer_fuzzer.cc @@ -0,0 +1,133 @@ +// 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. + +// This fuzzer tests browser-side implementation of +// ozone::mojom::WaylandConnection. + +#include +#include + +#include +#include +#include + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "base/test/fuzzed_data_provider.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/ozone/common/linux/drm_util_linux.h" +#include "ui/ozone/platform/wayland/fake_server.h" +#include "ui/ozone/platform/wayland/wayland_connection.h" +#include "ui/ozone/platform/wayland/wayland_window.h" +#include "ui/platform_window/platform_window_delegate.h" +#include "ui/platform_window/platform_window_init_properties.h" + +namespace { + +// Off-class equivalent of WaylandTest::Sync. +void Sync(wl::FakeServer* server) { + DCHECK(server); + + server->Resume(); + base::RunLoop().RunUntilIdle(); + server->Pause(); +} + +// Copied from ui/ozone/test/mock_platform_window_delegate.h to avoid +// dependency from the whole library (it causes link problems). +class MockPlatformWindowDelegate : public ui::PlatformWindowDelegate { + public: + MockPlatformWindowDelegate() = default; + ~MockPlatformWindowDelegate() = default; + + MOCK_METHOD1(OnBoundsChanged, void(const gfx::Rect& new_bounds)); + MOCK_METHOD1(OnDamageRect, void(const gfx::Rect& damaged_region)); + MOCK_METHOD1(DispatchEvent, void(ui::Event* event)); + MOCK_METHOD0(OnCloseRequest, void()); + MOCK_METHOD0(OnClosed, void()); + MOCK_METHOD1(OnWindowStateChanged, void(ui::PlatformWindowState new_state)); + MOCK_METHOD0(OnLostCapture, void()); + MOCK_METHOD1(OnAcceleratedWidgetAvailable, + void(gfx::AcceleratedWidget widget)); + MOCK_METHOD0(OnAcceleratedWidgetDestroyed, void()); + MOCK_METHOD1(OnActivationChanged, void(bool active)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockPlatformWindowDelegate); +}; + +} // namespace + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + base::FuzzedDataProvider data_provider(data, size); + + std::vector known_fourccs{ + DRM_FORMAT_R8, DRM_FORMAT_GR88, DRM_FORMAT_ABGR8888, + DRM_FORMAT_XBGR8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, + DRM_FORMAT_XRGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_RGB565, + DRM_FORMAT_UYVY, DRM_FORMAT_NV12, DRM_FORMAT_YVU420}; + + base::MessageLoopForUI message_loop; + + MockPlatformWindowDelegate delegate; + std::unique_ptr connection = + std::make_unique(); + std::unique_ptr window = + std::make_unique(&delegate, connection.get()); + gfx::AcceleratedWidget widget = gfx::kNullAcceleratedWidget; + + wl::FakeServer server; + CHECK(server.Start(6)); + CHECK(connection->Initialize()); + + EXPECT_CALL(delegate, OnAcceleratedWidgetAvailable(testing::_)) + .WillOnce(testing::SaveArg<0>(&widget)); + ui::PlatformWindowInitProperties properties; + properties.bounds = gfx::Rect(0, 0, 800, 600); + properties.type = ui::PlatformWindowType::kWindow; + CHECK(window->Initialize(std::move(properties))); + CHECK_NE(widget, gfx::kNullAcceleratedWidget); + + base::RunLoop().RunUntilIdle(); + server.Pause(); + + base::FilePath temp_path; + EXPECT_TRUE(base::CreateTemporaryFile(&temp_path)); + base::File temp(temp_path, + base::File::FLAG_WRITE | base::File::FLAG_CREATE_ALWAYS); + + uint32_t width = data_provider.ConsumeIntegralInRange(1U, 10000U); + uint32_t height = data_provider.ConsumeIntegralInRange(1U, 10000U); + uint32_t planes_count = data_provider.ConsumeIntegralInRange(1U, 10000U); + uint32_t format = known_fourccs[data_provider.ConsumeIntegralInRange( + 0UL, known_fourccs.size() - 1)]; + std::vector strides(planes_count); + std::vector offsets(planes_count); + std::vector modifiers(planes_count); + for (uint32_t i = 0; i < planes_count; ++i) { + strides[i] = data_provider.ConsumeIntegralInRange(1U, UINT_MAX); + offsets[i] = data_provider.ConsumeIntegralInRange(0U, UINT_MAX); + modifiers[i] = + data_provider.ConsumeIntegralInRange(uint64_t(0), UINT64_MAX); + } + + const uint32_t kBufferId = 1; + + connection->CreateZwpLinuxDmabuf(std::move(temp), width, height, strides, + offsets, format, modifiers, planes_count, + kBufferId); + + Sync(&server); + Sync(&server); + + connection->DestroyZwpLinuxDmabuf(kBufferId); + + Sync(&server); + Sync(&server); + + return 0; +} diff --git a/ui/ozone/platform/wayland/wayland_buffer_manager.cc b/ui/ozone/platform/wayland/wayland_buffer_manager.cc index 91b1a1e8eb010..078b9a0df5b84 100644 --- a/ui/ozone/platform/wayland/wayland_buffer_manager.cc +++ b/ui/ozone/platform/wayland/wayland_buffer_manager.cc @@ -53,15 +53,19 @@ WaylandBufferManager::WaylandBufferManager( zwp_linux_dmabuf_v1* zwp_linux_dmabuf, WaylandConnection* connection) : zwp_linux_dmabuf_(zwp_linux_dmabuf), connection_(connection) { + DCHECK(zwp_linux_dmabuf_); + DCHECK(connection_); + static const zwp_linux_dmabuf_v1_listener dmabuf_listener = { - &WaylandBufferManager::Format, &WaylandBufferManager::Modifiers, + &WaylandBufferManager::Format, + &WaylandBufferManager::Modifiers, }; zwp_linux_dmabuf_v1_add_listener(zwp_linux_dmabuf_.get(), &dmabuf_listener, this); // A roundtrip after binding guarantees that the client has received all // supported formats. - wl_display_roundtrip(connection->display()); + wl_display_roundtrip(connection_->display()); } WaylandBufferManager::~WaylandBufferManager() { diff --git a/ui/ozone/platform/wayland/wayland_connection.cc b/ui/ozone/platform/wayland/wayland_connection.cc index e963c49b02c74..e62a6f8056479 100644 --- a/ui/ozone/platform/wayland/wayland_connection.cc +++ b/ui/ozone/platform/wayland/wayland_connection.cc @@ -52,7 +52,8 @@ WaylandConnection::~WaylandConnection() = default; bool WaylandConnection::Initialize() { static const wl_registry_listener registry_listener = { - &WaylandConnection::Global, &WaylandConnection::GlobalRemove, + &WaylandConnection::Global, + &WaylandConnection::GlobalRemove, }; display_.reset(wl_display_connect(nullptr)); @@ -193,6 +194,7 @@ void WaylandConnection::CreateZwpLinuxDmabuf( uint32_t planes_count, uint32_t buffer_id) { DCHECK(base::MessageLoopCurrentForUI::IsSet()); + DCHECK(buffer_manager_); if (!buffer_manager_->CreateBuffer(std::move(file), width, height, strides, offsets, format, modifiers, planes_count, buffer_id)) { @@ -364,7 +366,8 @@ void WaylandConnection::Global(void* data, const char* interface, uint32_t version) { static const wl_seat_listener seat_listener = { - &WaylandConnection::Capabilities, &WaylandConnection::Name, + &WaylandConnection::Capabilities, + &WaylandConnection::Name, }; static const xdg_shell_listener shell_listener = { &WaylandConnection::Ping,