// Copyright 2015 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 #include #include #include #include #include #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/memory/shared_memory_handle.h" #include "base/strings/string_util.h" #include "base/values.h" #include "build/build_config.h" #include "ipc/ipc_message.h" #include "ipc/ipc_message_utils.h" #include "ipc/ipc_sync_channel.h" #include "ipc/ipc_sync_message.h" #include "tools/ipc_fuzzer/fuzzer/fuzzer.h" #include "tools/ipc_fuzzer/fuzzer/rand_util.h" #include "tools/ipc_fuzzer/message_lib/message_cracker.h" #include "tools/ipc_fuzzer/message_lib/message_file.h" #if defined(OS_POSIX) #include #endif // First include of all message files to provide basic types. #include "tools/ipc_fuzzer/message_lib/all_messages.h" #include "tools/ipc_fuzzer/message_lib/all_message_null_macros.h" #if defined(COMPILER_GCC) #define PRETTY_FUNCTION __PRETTY_FUNCTION__ #elif defined(COMPILER_MSVC) #define PRETTY_FUNCTION __FUNCSIG__ #else #define PRETTY_FUNCTION __FUNCTION__ #endif namespace IPC { class Message; } // namespace IPC namespace { // For breaking deep recursion. int g_depth = 0; } // namespace namespace ipc_fuzzer { FuzzerFunctionVector g_function_vector; bool Fuzzer::ShouldGenerate() { return false; } // Partially-specialized class that knows how to handle a given type. template struct FuzzTraits { static bool Fuzz(P* p, Fuzzer *fuzzer) { // This is the catch-all for types we don't have enough information // to generate. std::cerr << "Can't handle " << PRETTY_FUNCTION << "\n"; return false; } }; // Template function to invoke partially-specialized class method. template static bool FuzzParam(P* p, Fuzzer* fuzzer) { return FuzzTraits

::Fuzz(p, fuzzer); } template static bool FuzzParamArray(P* p, size_t length, Fuzzer* fuzzer) { for (size_t i = 0; i < length; i++, p++) { if (!FuzzTraits

::Fuzz(p, fuzzer)) return false; } return true; } // Specializations to generate primitive types. template <> struct FuzzTraits { static bool Fuzz(bool* p, Fuzzer* fuzzer) { fuzzer->FuzzBool(p); return true; } }; template <> struct FuzzTraits { static bool Fuzz(int* p, Fuzzer* fuzzer) { fuzzer->FuzzInt(p); return true; } }; template <> struct FuzzTraits { static bool Fuzz(unsigned int* p, Fuzzer* fuzzer) { fuzzer->FuzzInt(reinterpret_cast(p)); return true; } }; template <> struct FuzzTraits { static bool Fuzz(long* p, Fuzzer* fuzzer) { fuzzer->FuzzLong(p); return true; } }; template <> struct FuzzTraits { static bool Fuzz(unsigned long* p, Fuzzer* fuzzer) { fuzzer->FuzzLong(reinterpret_cast(p)); return true; } }; template <> struct FuzzTraits { static bool Fuzz(long long* p, Fuzzer* fuzzer) { fuzzer->FuzzInt64(reinterpret_cast(p)); return true; } }; template <> struct FuzzTraits { static bool Fuzz(unsigned long long* p, Fuzzer* fuzzer) { fuzzer->FuzzInt64(reinterpret_cast(p)); return true; } }; template <> struct FuzzTraits { static bool Fuzz(short* p, Fuzzer* fuzzer) { fuzzer->FuzzUInt16(reinterpret_cast(p)); return true; } }; template <> struct FuzzTraits { static bool Fuzz(unsigned short* p, Fuzzer* fuzzer) { fuzzer->FuzzUInt16(reinterpret_cast(p)); return true; } }; template <> struct FuzzTraits { static bool Fuzz(signed char* p, Fuzzer* fuzzer) { fuzzer->FuzzUChar(reinterpret_cast(p)); return true; } }; template <> struct FuzzTraits { static bool Fuzz(unsigned char* p, Fuzzer* fuzzer) { fuzzer->FuzzUChar(p); return true; } }; template <> struct FuzzTraits { static bool Fuzz(wchar_t* p, Fuzzer* fuzzer) { fuzzer->FuzzWChar(p); return true; } }; template <> struct FuzzTraits { static bool Fuzz(float* p, Fuzzer* fuzzer) { fuzzer->FuzzFloat(p); return true; } }; template <> struct FuzzTraits { static bool Fuzz(double* p, Fuzzer* fuzzer) { fuzzer->FuzzDouble(p); return true; } }; template <> struct FuzzTraits { static bool Fuzz(std::string* p, Fuzzer* fuzzer) { fuzzer->FuzzString(p); return true; } }; template <> struct FuzzTraits { static bool Fuzz(base::string16* p, Fuzzer* fuzzer) { fuzzer->FuzzString16(p); return true; } }; // Specializations for tuples. template <> struct FuzzTraits> { static bool Fuzz(std::tuple<>* p, Fuzzer* fuzzer) { return true; } }; template struct FuzzTraits> { static bool Fuzz(std::tuple* p, Fuzzer* fuzzer) { return FuzzParam(&std::get<0>(*p), fuzzer); } }; template struct FuzzTraits> { static bool Fuzz(std::tuple* p, Fuzzer* fuzzer) { return FuzzParam(&std::get<0>(*p), fuzzer) && FuzzParam(&std::get<1>(*p), fuzzer); } }; template struct FuzzTraits> { static bool Fuzz(std::tuple* p, Fuzzer* fuzzer) { return FuzzParam(&std::get<0>(*p), fuzzer) && FuzzParam(&std::get<1>(*p), fuzzer) && FuzzParam(&std::get<2>(*p), fuzzer); } }; template struct FuzzTraits> { static bool Fuzz(std::tuple* p, Fuzzer* fuzzer) { return FuzzParam(&std::get<0>(*p), fuzzer) && FuzzParam(&std::get<1>(*p), fuzzer) && FuzzParam(&std::get<2>(*p), fuzzer) && FuzzParam(&std::get<3>(*p), fuzzer); } }; template struct FuzzTraits> { static bool Fuzz(std::tuple* p, Fuzzer* fuzzer) { return FuzzParam(&std::get<0>(*p), fuzzer) && FuzzParam(&std::get<1>(*p), fuzzer) && FuzzParam(&std::get<2>(*p), fuzzer) && FuzzParam(&std::get<3>(*p), fuzzer) && FuzzParam(&std::get<4>(*p), fuzzer); } }; // Specializations for containers. template struct FuzzTraits > { static bool Fuzz(std::vector* p, Fuzzer* fuzzer) { ++g_depth; size_t count = p->size(); if (fuzzer->ShouldGenerate()) { count = g_depth > 3 ? 0 : RandElementCount(); p->resize(count); } for (size_t i = 0; i < count; ++i) { if (!FuzzParam(&p->at(i), fuzzer)) { --g_depth; return false; } } --g_depth; return true; } }; template struct FuzzTraits > { static bool Fuzz(std::set* p, Fuzzer* fuzzer) { if (!fuzzer->ShouldGenerate()) { std::set result; typename std::set::iterator it; for (it = p->begin(); it != p->end(); ++it) { A item = *it; if (!FuzzParam(&item, fuzzer)) return false; result.insert(item); } *p = result; return true; } static int g_depth = 0; size_t count = ++g_depth > 3 ? 0 : RandElementCount(); A a; for (size_t i = 0; i < count; ++i) { if (!FuzzParam(&a, fuzzer)) { --g_depth; return false; } p->insert(a); } --g_depth; return true; } }; template struct FuzzTraits > { static bool Fuzz(std::map* p, Fuzzer* fuzzer) { if (!fuzzer->ShouldGenerate()) { typename std::map::iterator it; for (it = p->begin(); it != p->end(); ++it) { if (!FuzzParam(&it->second, fuzzer)) return false; } return true; } static int g_depth = 0; size_t count = ++g_depth > 3 ? 0 : RandElementCount(); std::pair place_holder; for (size_t i = 0; i < count; ++i) { if (!FuzzParam(&place_holder, fuzzer)) { --g_depth; return false; } p->insert(place_holder); } --g_depth; return true; } }; template struct FuzzTraits> { static bool Fuzz(std::map* p, Fuzzer* fuzzer) { if (!fuzzer->ShouldGenerate()) { typename std::map::iterator it; for (it = p->begin(); it != p->end(); ++it) { if (!FuzzParam(&it->second, fuzzer)) return false; } return true; } static int g_depth = 0; size_t count = ++g_depth > 3 ? 0 : RandElementCount(); std::pair place_holder; for (size_t i = 0; i < count; ++i) { if (!FuzzParam(&place_holder, fuzzer)) { --g_depth; return false; } p->insert(place_holder); } --g_depth; return true; } }; template struct FuzzTraits > { static bool Fuzz(std::pair* p, Fuzzer* fuzzer) { return FuzzParam(&p->first, fuzzer) && FuzzParam(&p->second, fuzzer); } }; // Specializations for hand-coded types. template <> struct FuzzTraits { static bool Fuzz(base::FilePath* p, Fuzzer* fuzzer) { if (!fuzzer->ShouldGenerate()) { base::FilePath::StringType path = p->value(); if(!FuzzParam(&path, fuzzer)) return false; *p = base::FilePath(path); return true; } const char path_chars[] = "ACz0/.~:"; size_t count = RandInRange(60); base::FilePath::StringType random_path; for (size_t i = 0; i < count; ++i) random_path += path_chars[RandInRange(sizeof(path_chars) - 1)]; *p = base::FilePath(random_path); return true; } }; template <> struct FuzzTraits { static bool Fuzz(base::File::Error* p, Fuzzer* fuzzer) { int value = static_cast(*p); if (!FuzzParam(&value, fuzzer)) return false; *p = static_cast(value); return true; } }; template <> struct FuzzTraits { static bool Fuzz(base::File::Info* p, Fuzzer* fuzzer) { double last_modified = p->last_modified.ToDoubleT(); double last_accessed = p->last_accessed.ToDoubleT(); double creation_time = p->creation_time.ToDoubleT(); if (!FuzzParam(&p->size, fuzzer)) return false; if (!FuzzParam(&p->is_directory, fuzzer)) return false; if (!FuzzParam(&last_modified, fuzzer)) return false; if (!FuzzParam(&last_accessed, fuzzer)) return false; if (!FuzzParam(&creation_time, fuzzer)) return false; p->last_modified = base::Time::FromDoubleT(last_modified); p->last_accessed = base::Time::FromDoubleT(last_accessed); p->creation_time = base::Time::FromDoubleT(creation_time); return true; } }; template <> struct FuzzTraits { static bool Fuzz(base::NullableString16* p, Fuzzer* fuzzer) { base::string16 string = p->string(); bool is_null = p->is_null(); if (!FuzzParam(&string, fuzzer)) return false; if (!FuzzParam(&is_null, fuzzer)) return false; *p = base::NullableString16(string, is_null); return true; } }; #if defined(OS_WIN) || defined(OS_MACOSX) template <> struct FuzzTraits { static bool Fuzz(base::SharedMemoryHandle* p, Fuzzer* fuzzer) { // This generates an invalid SharedMemoryHandle. Generating a valid // SharedMemoryHandle requires setting/knowing state in both the sending and // receiving process, which is not currently possible. return true; } }; #endif // defined(OS_WIN) || defined(OS_MACOSX) template <> struct FuzzTraits { static bool Fuzz(base::Time* p, Fuzzer* fuzzer) { int64_t internal_value = p->ToInternalValue(); if (!FuzzParam(&internal_value, fuzzer)) return false; *p = base::Time::FromInternalValue(internal_value); return true; } }; template <> struct FuzzTraits { static bool Fuzz(base::TimeDelta* p, Fuzzer* fuzzer) { int64_t internal_value = p->ToInternalValue(); if (!FuzzParam(&internal_value, fuzzer)) return false; *p = base::TimeDelta::FromInternalValue(internal_value); return true; } }; template <> struct FuzzTraits { static bool Fuzz(base::TimeTicks* p, Fuzzer* fuzzer) { int64_t internal_value = p->ToInternalValue(); if (!FuzzParam(&internal_value, fuzzer)) return false; *p = base::TimeTicks::FromInternalValue(internal_value); return true; } }; template <> struct FuzzTraits { static bool Fuzz(base::ListValue* p, Fuzzer* fuzzer) { // TODO(mbarbella): Support mutation. if (!fuzzer->ShouldGenerate()) return true; ++g_depth; size_t list_length = p->GetSize(); if (fuzzer->ShouldGenerate()) list_length = g_depth > 3 ? 0 : RandInRange(8); for (size_t index = 0; index < list_length; ++index) { switch (static_cast(RandInRange(8))) { case base::Value::Type::BOOLEAN: { bool tmp; p->GetBoolean(index, &tmp); fuzzer->FuzzBool(&tmp); p->Set(index, std::make_unique(tmp)); break; } case base::Value::Type::INTEGER: { int tmp; p->GetInteger(index, &tmp); fuzzer->FuzzInt(&tmp); p->Set(index, std::make_unique(tmp)); break; } case base::Value::Type::DOUBLE: { double tmp; p->GetDouble(index, &tmp); fuzzer->FuzzDouble(&tmp); p->Set(index, std::make_unique(tmp)); break; } case base::Value::Type::STRING: { std::string tmp; p->GetString(index, &tmp); fuzzer->FuzzString(&tmp); p->Set(index, std::make_unique(tmp)); break; } case base::Value::Type::BINARY: { char tmp[200]; size_t bin_length = RandInRange(sizeof(tmp)); fuzzer->FuzzData(tmp, bin_length); p->Set(index, base::Value::CreateWithCopiedBuffer(tmp, bin_length)); break; } case base::Value::Type::DICTIONARY: { base::DictionaryValue* dict_weak = nullptr; if (p->GetDictionary(index, &dict_weak)) { FuzzParam(dict_weak, fuzzer); } else { auto dict = std::make_unique(); FuzzParam(dict.get(), fuzzer); p->Set(index, std::move(dict)); } break; } case base::Value::Type::LIST: { base::ListValue* list_weak = nullptr; if (p->GetList(index, &list_weak)) { FuzzParam(list_weak, fuzzer); } else { auto list = std::make_unique(); FuzzParam(list.get(), fuzzer); p->Set(index, std::move(list)); } break; } case base::Value::Type::NONE: default: break; } } --g_depth; return true; } }; template <> struct FuzzTraits { static bool Fuzz(base::DictionaryValue* p, Fuzzer* fuzzer) { // TODO(mbarbella): Support mutation. if (!fuzzer->ShouldGenerate()) return true; ++g_depth; size_t dict_length = g_depth > 3 ? 0 : RandInRange(8); for (size_t index = 0; index < dict_length; ++index) { std::string property; fuzzer->FuzzString(&property); switch (static_cast(RandInRange(8))) { case base::Value::Type::BOOLEAN: { bool tmp; fuzzer->FuzzBool(&tmp); p->SetKey(property, base::Value(tmp)); break; } case base::Value::Type::INTEGER: { int tmp; fuzzer->FuzzInt(&tmp); p->SetKey(property, base::Value(tmp)); break; } case base::Value::Type::DOUBLE: { double tmp; fuzzer->FuzzDouble(&tmp); p->SetKey(property, base::Value(tmp)); break; } case base::Value::Type::STRING: { std::string tmp; fuzzer->FuzzString(&tmp); p->SetKey(property, base::Value(tmp)); break; } case base::Value::Type::BINARY: { char tmp[200]; size_t bin_length = RandInRange(sizeof(tmp)); fuzzer->FuzzData(tmp, bin_length); p->SetWithoutPathExpansion( property, base::Value::CreateWithCopiedBuffer(tmp, bin_length)); break; } case base::Value::Type::DICTIONARY: { auto tmp = std::make_unique(); FuzzParam(tmp.get(), fuzzer); p->SetWithoutPathExpansion(property, std::move(tmp)); break; } case base::Value::Type::LIST: { auto tmp = std::make_unique(); FuzzParam(tmp.get(), fuzzer); p->SetWithoutPathExpansion(property, std::move(tmp)); break; } case base::Value::Type::NONE: default: break; } } --g_depth; return true; } }; template <> struct FuzzTraits { static bool Fuzz(viz::CompositorFrame* p, Fuzzer* fuzzer) { // TODO(mbarbella): Support mutation. if (!fuzzer->ShouldGenerate()) return true; if (!FuzzParam(&p->metadata, fuzzer)) return false; switch (RandInRange(2)) { case 0: { if (!FuzzParam(&p->resource_list, fuzzer)) return false; if (!FuzzParam(&p->render_pass_list, fuzzer)) return false; return true; } default: // Fuzz nothing to handle the no frame case. return true; } } }; template struct FuzzTraits> { static bool Fuzz(cc::ListContainer* p, Fuzzer* fuzzer) { // TODO(mbarbella): This should actually do something. return true; } }; template <> struct FuzzTraits { static bool Fuzz(viz::QuadList* p, Fuzzer* fuzzer) { // TODO(mbarbella): This should actually do something. return true; } }; template <> struct FuzzTraits { static bool Fuzz(viz::RenderPass* p, Fuzzer* fuzzer) { if (!FuzzParam(&p->id, fuzzer)) return false; if (!FuzzParam(&p->output_rect, fuzzer)) return false; if (!FuzzParam(&p->damage_rect, fuzzer)) return false; if (!FuzzParam(&p->transform_to_root_target, fuzzer)) return false; if (!FuzzParam(&p->has_transparent_background, fuzzer)) return false; if (!FuzzParam(&p->quad_list, fuzzer)) return false; if (!FuzzParam(&p->shared_quad_state_list, fuzzer)) return false; // Omitting |copy_requests| as it is not sent over IPC. return true; } }; template <> struct FuzzTraits { static bool Fuzz(viz::RenderPassList* p, Fuzzer* fuzzer) { if (!fuzzer->ShouldGenerate()) { for (size_t i = 0; i < p->size(); ++i) { if (!FuzzParam(p->at(i).get(), fuzzer)) return false; } return true; } size_t count = RandElementCount(); for (size_t i = 0; i < count; ++i) { std::unique_ptr render_pass = viz::RenderPass::Create(); if (!FuzzParam(render_pass.get(), fuzzer)) return false; p->push_back(std::move(render_pass)); } return true; } }; template <> struct FuzzTraits { static bool Fuzz(content::PageState* p, Fuzzer* fuzzer) { std::string data = p->ToEncodedData(); if (!FuzzParam(&data, fuzzer)) return false; *p = content::PageState::CreateFromEncodedData(data); return true; } }; template <> struct FuzzTraits { static bool Fuzz(content::WebCursor* p, Fuzzer* fuzzer) { content::CursorInfo info; p->GetCursorInfo(&info); // |type| enum is not validated on de-serialization, so pick random value. if (!FuzzParam(reinterpret_cast(&info.type), fuzzer)) return false; if (!FuzzParam(&info.hotspot, fuzzer)) return false; if (!FuzzParam(&info.image_scale_factor, fuzzer)) return false; if (!FuzzParam(&info.custom_image, fuzzer)) return false; // Omitting |externalHandle| since it is not serialized. // Scale factor is expected to be greater than 0, otherwise we hit // a check failure. info.image_scale_factor = fabs(info.image_scale_factor); if (!(info.image_scale_factor > 0.0)) info.image_scale_factor = 1; *p = content::WebCursor(); p->InitFromCursorInfo(info); return true; } }; template <> struct FuzzTraits { static bool Fuzz(ContentSettingsPattern* p, Fuzzer* fuzzer) { // TODO(mbarbella): This can crash if a pattern is generated from a random // string. We could carefully generate a pattern or fix pattern generation. return true; } }; template <> struct FuzzTraits { static bool Fuzz(ExtensionMsg_PermissionSetStruct* p, Fuzzer* fuzzer) { // TODO(mbarbella): This should actually do something. return true; } }; template <> struct FuzzTraits { static bool Fuzz(extensions::URLPatternSet* p, Fuzzer* fuzzer) { std::set patterns = p->patterns(); if (!FuzzParam(&patterns, fuzzer)) return false; *p = extensions::URLPatternSet(patterns); return true; } }; template <> struct FuzzTraits { static bool Fuzz(gfx::Point* p, Fuzzer* fuzzer) { int x = p->x(); int y = p->y(); if (!FuzzParam(&x, fuzzer)) return false; if (!FuzzParam(&y, fuzzer)) return false; p->SetPoint(x, y); return true; } }; template <> struct FuzzTraits { static bool Fuzz(gfx::PointF* p, Fuzzer* fuzzer) { float x = p->x(); float y = p->y(); if (!FuzzParam(&x, fuzzer)) return false; if (!FuzzParam(&y, fuzzer)) return false; p->SetPoint(x, y); return true; } }; template <> struct FuzzTraits { static bool Fuzz(gfx::Rect* p, Fuzzer* fuzzer) { gfx::Point origin = p->origin(); gfx::Size size = p->size(); if (!FuzzParam(&origin, fuzzer)) return false; if (!FuzzParam(&size, fuzzer)) return false; p->set_origin(origin); p->set_size(size); return true; } }; template <> struct FuzzTraits { static bool Fuzz(gfx::RectF* p, Fuzzer* fuzzer) { gfx::PointF origin = p->origin(); gfx::SizeF size = p->size(); if (!FuzzParam(&origin, fuzzer)) return false; if (!FuzzParam(&size, fuzzer)) return false; p->set_origin(origin); p->set_size(size); return true; } }; template <> struct FuzzTraits { static bool Fuzz(gfx::Range* p, Fuzzer* fuzzer) { size_t start = p->start(); size_t end = p->end(); if (!FuzzParam(&start, fuzzer)) return false; if (!FuzzParam(&end, fuzzer)) return false; *p = gfx::Range(start, end); return true; } }; template <> struct FuzzTraits { static bool Fuzz(gfx::Size* p, Fuzzer* fuzzer) { int width = p->width(); int height = p->height(); if (!FuzzParam(&width, fuzzer)) return false; if (!FuzzParam(&height, fuzzer)) return false; p->SetSize(width, height); return true; } }; template <> struct FuzzTraits { static bool Fuzz(gfx::SizeF* p, Fuzzer* fuzzer) { float w; float h; if (!FuzzParam(&w, fuzzer)) return false; if (!FuzzParam(&h, fuzzer)) return false; p->SetSize(w, h); return true; } }; template <> struct FuzzTraits { static bool Fuzz(gfx::Transform* p, Fuzzer* fuzzer) { SkMScalar matrix[16]; for (size_t i = 0; i < arraysize(matrix); i++) { matrix[i] = p->matrix().get(i / 4, i % 4); } if (!FuzzParamArray(&matrix[0], arraysize(matrix), fuzzer)) return false; *p = gfx::Transform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6], matrix[7], matrix[8], matrix[9], matrix[10], matrix[11], matrix[12], matrix[13], matrix[14], matrix[15]); return true; } }; template <> struct FuzzTraits { static bool Fuzz(gfx::Vector2d* p, Fuzzer* fuzzer) { int x = p->x(); int y = p->y(); if (!FuzzParam(&x, fuzzer)) return false; if (!FuzzParam(&y, fuzzer)) return false; *p = gfx::Vector2d(x, y); return true; } }; template <> struct FuzzTraits { static bool Fuzz(gfx::Vector2dF* p, Fuzzer* fuzzer) { float x = p->x(); float y = p->y(); if (!FuzzParam(&x, fuzzer)) return false; if (!FuzzParam(&y, fuzzer)) return false; *p = gfx::Vector2dF(x, y); return true; } }; template struct FuzzTraits> { using param_type = gpu::IdType; static bool Fuzz(param_type* id, Fuzzer* fuzzer) { WrappedType raw_value = id->GetUnsafeValue(); if (!FuzzParam(&raw_value, fuzzer)) return false; *id = param_type::FromUnsafeValue(raw_value); return true; } }; template <> struct FuzzTraits { static bool Fuzz(gpu::Mailbox* p, Fuzzer* fuzzer) { fuzzer->FuzzBytes(p->name, sizeof(p->name)); return true; } }; template <> struct FuzzTraits { static bool Fuzz(gpu::SyncToken* p, Fuzzer* fuzzer) { bool verified_flush = false; gpu::CommandBufferNamespace namespace_id = gpu::CommandBufferNamespace::INVALID; gpu::CommandBufferId command_buffer_id; uint64_t release_count = 0; if (!FuzzParam(&verified_flush, fuzzer)) return false; if (!FuzzParam(&namespace_id, fuzzer)) return false; if (!FuzzParam(&command_buffer_id, fuzzer)) return false; if (!FuzzParam(&release_count, fuzzer)) return false; p->Clear(); p->Set(namespace_id, command_buffer_id, release_count); if (verified_flush) p->SetVerifyFlush(); return true; } }; template <> struct FuzzTraits { static bool Fuzz(gpu::MailboxHolder* p, Fuzzer* fuzzer) { if (!FuzzParam(&p->mailbox, fuzzer)) return false; if (!FuzzParam(&p->sync_token, fuzzer)) return false; if (!FuzzParam(&p->texture_target, fuzzer)) return false; return true; } }; template <> struct FuzzTraits { static bool Fuzz(GURL* p, Fuzzer* fuzzer) { if (!fuzzer->ShouldGenerate()) { std::string spec = p->possibly_invalid_spec(); if (!FuzzParam(&spec, fuzzer)) return false; if (spec != p->possibly_invalid_spec()) *p = GURL(spec); return true; } const char url_chars[] = "Ahtp0:/.?+\\%&#"; size_t count = RandInRange(100); std::string random_url; for (size_t i = 0; i < count; ++i) random_url += url_chars[RandInRange(sizeof(url_chars) - 1)]; int selector = RandInRange(10); if (selector == 0) random_url = std::string("http://") + random_url; else if (selector == 1) random_url = std::string("file://") + random_url; else if (selector == 2) random_url = std::string("javascript:") + random_url; else if (selector == 2) random_url = std::string("data:") + random_url; *p = GURL(random_url); return true; } }; template <> struct FuzzTraits { static bool Fuzz(HostID* p, Fuzzer* fuzzer) { HostID::HostType type = p->type(); std::string id = p->id(); if (!FuzzParam(&type, fuzzer)) return false; if (!FuzzParam(&id, fuzzer)) return false; *p = HostID(type, id); return true; } }; #if defined(OS_WIN) template <> struct FuzzTraits { static bool Fuzz(HWND* p, Fuzzer* fuzzer) { // TODO(aarya): This should actually do something. return true; } }; #endif template <> struct FuzzTraits> { static bool Fuzz(std::unique_ptr* p, Fuzzer* fuzzer) { // TODO(mbarbella): Support mutation. if (!fuzzer->ShouldGenerate()) return true; if (g_function_vector.empty()) return false; size_t index = RandInRange(g_function_vector.size()); std::unique_ptr ipc_message = (*g_function_vector[index])(nullptr, fuzzer); if (!ipc_message) return false; *p = std::move(ipc_message); return true; } }; #if !defined(OS_WIN) // PlatformfileForTransit is just SharedMemoryHandle on Windows, which already // has a trait, see ipc/ipc_platform_file.h template <> struct FuzzTraits { static bool Fuzz(IPC::PlatformFileForTransit* p, Fuzzer* fuzzer) { // TODO(inferno): I don't think we can generate real ones due to check on // construct. return true; } }; #endif template <> struct FuzzTraits { static bool Fuzz(IPC::ChannelHandle* p, Fuzzer* fuzzer) { // TODO(mbarbella): Support mutation. if (!fuzzer->ShouldGenerate()) return true; return FuzzParam(&p->mojo_handle, fuzzer); } }; #if defined(OS_WIN) template <> struct FuzzTraits { static bool Fuzz(LOGFONT* p, Fuzzer* fuzzer) { // TODO(aarya): This should actually do something. return true; } }; #endif template <> struct FuzzTraits { static bool Fuzz(media::AudioParameters* p, Fuzzer* fuzzer) { int channel_layout = p->channel_layout(); int format = p->format(); int sample_rate = p->sample_rate(); int bits_per_sample = p->bits_per_sample(); int frames_per_buffer = p->frames_per_buffer(); int channels = p->channels(); int effects = p->effects(); // TODO(mbarbella): Support ChannelLayout mutation and invalid values. if (fuzzer->ShouldGenerate()) { channel_layout = RandInRange(media::ChannelLayout::CHANNEL_LAYOUT_MAX + 1); } if (!FuzzParam(&format, fuzzer)) return false; if (!FuzzParam(&sample_rate, fuzzer)) return false; if (!FuzzParam(&bits_per_sample, fuzzer)) return false; if (!FuzzParam(&frames_per_buffer, fuzzer)) return false; if (!FuzzParam(&channels, fuzzer)) return false; if (!FuzzParam(&effects, fuzzer)) return false; media::AudioParameters params( static_cast(format), static_cast(channel_layout), sample_rate, bits_per_sample, frames_per_buffer); params.set_channels_for_discrete(channels); params.set_effects(effects); *p = params; return true; } }; template <> struct FuzzTraits { static bool Fuzz(media::cast::RtpTimeTicks* p, Fuzzer* fuzzer) { base::TimeDelta delta; int base; if (!FuzzParam(&delta, fuzzer)) return false; if (!FuzzParam(&base, fuzzer)) return false; *p = media::cast::RtpTimeTicks::FromTimeDelta(delta, base); return true; } }; template <> struct FuzzTraits { static bool Fuzz(media::VideoCaptureFormat* p, Fuzzer* fuzzer) { if (!FuzzParam(&p->frame_size, fuzzer)) return false; if (!FuzzParam(&p->frame_rate, fuzzer)) return false; if (!FuzzParam(reinterpret_cast(&p->pixel_format), fuzzer)) return false; return true; } }; template <> struct FuzzTraits { static bool Fuzz(net::LoadTimingInfo* p, Fuzzer* fuzzer) { return FuzzParam(&p->socket_log_id, fuzzer) && FuzzParam(&p->socket_reused, fuzzer) && FuzzParam(&p->request_start_time, fuzzer) && FuzzParam(&p->request_start, fuzzer) && FuzzParam(&p->proxy_resolve_start, fuzzer) && FuzzParam(&p->proxy_resolve_end, fuzzer) && FuzzParam(&p->connect_timing.dns_start, fuzzer) && FuzzParam(&p->connect_timing.dns_end, fuzzer) && FuzzParam(&p->connect_timing.connect_start, fuzzer) && FuzzParam(&p->connect_timing.connect_end, fuzzer) && FuzzParam(&p->connect_timing.ssl_start, fuzzer) && FuzzParam(&p->connect_timing.ssl_end, fuzzer) && FuzzParam(&p->send_start, fuzzer) && FuzzParam(&p->send_end, fuzzer) && FuzzParam(&p->receive_headers_end, fuzzer); } }; template <> struct FuzzTraits { static bool Fuzz(net::HostPortPair* p, Fuzzer* fuzzer) { std::string host = p->host(); uint16_t port = p->port(); if (!FuzzParam(&host, fuzzer)) return false; if (!FuzzParam(&port, fuzzer)) return false; p->set_host(host); p->set_port(port); return true; } }; template <> struct FuzzTraits { static bool Fuzz(net::IPAddress* p, Fuzzer* fuzzer) { std::vector bytes = p->CopyBytesToVector(); if (!FuzzParam(&bytes, fuzzer)) return false; net::IPAddress ip_address(bytes.data(), bytes.size()); *p = ip_address; return true; } }; template <> struct FuzzTraits { static bool Fuzz(net::IPEndPoint* p, Fuzzer* fuzzer) { net::IPAddress ip_address = p->address(); int port = p->port(); if (!FuzzParam(&ip_address, fuzzer)) return false; if (!FuzzParam(&port, fuzzer)) return false; net::IPEndPoint ip_endpoint(ip_address, port); *p = ip_endpoint; return true; } }; template <> struct FuzzTraits { static bool Fuzz(network_hints::LookupRequest* p, Fuzzer* fuzzer) { if (!FuzzParam(&p->hostname_list, fuzzer)) return false; return true; } }; // PP_ traits. template <> struct FuzzTraits { static bool Fuzz(PP_Bool* p, Fuzzer* fuzzer) { bool tmp = PP_ToBool(*p); if (!FuzzParam(&tmp, fuzzer)) return false; *p = PP_FromBool(tmp); return true; } }; template <> struct FuzzTraits { static bool Fuzz(PP_NetAddress_Private* p, Fuzzer* fuzzer) { p->size = RandInRange(sizeof(p->data) + 1); fuzzer->FuzzBytes(&p->data, p->size); return true; } }; template <> struct FuzzTraits { static bool Fuzz(ppapi::PPB_X509Certificate_Fields* p, Fuzzer* fuzzer) { // TODO(mbarbella): This should actually do something. return true; } }; template <> struct FuzzTraits { static bool Fuzz(ppapi::proxy::PPBFlash_DrawGlyphs_Params* p, Fuzzer* fuzzer) { // TODO(mbarbella): This should actually do something. return true; } }; template <> struct FuzzTraits { static bool Fuzz( ppapi::proxy::ResourceMessageCallParams* p, Fuzzer* fuzzer) { // TODO(mbarbella): Support mutation. if (!fuzzer->ShouldGenerate()) return true; PP_Resource resource; int32_t sequence; bool has_callback; if (!FuzzParam(&resource, fuzzer)) return false; if (!FuzzParam(&sequence, fuzzer)) return false; if (!FuzzParam(&has_callback, fuzzer)) return false; *p = ppapi::proxy::ResourceMessageCallParams(resource, sequence); if (has_callback) p->set_has_callback(); return true; } }; template <> struct FuzzTraits { static bool Fuzz( ppapi::proxy::ResourceMessageReplyParams* p, Fuzzer* fuzzer) { // TODO(mbarbella): Support mutation. if (!fuzzer->ShouldGenerate()) return true; PP_Resource resource; int32_t sequence; int32_t result; if (!FuzzParam(&resource, fuzzer)) return false; if (!FuzzParam(&sequence, fuzzer)) return false; if (!FuzzParam(&result, fuzzer)) return false; *p = ppapi::proxy::ResourceMessageReplyParams(resource, sequence); p->set_result(result); return true; } }; template <> struct FuzzTraits { static bool Fuzz(ppapi::proxy::SerializedHandle* p, Fuzzer* fuzzer) { // TODO(mbarbella): This should actually do something. return true; } }; template <> struct FuzzTraits { static bool Fuzz(ppapi::proxy::SerializedFontDescription* p, Fuzzer* fuzzer) { // TODO(mbarbella): This should actually do something. return true; } }; template <> struct FuzzTraits { static bool Fuzz(ppapi::proxy::SerializedTrueTypeFontDesc* p, Fuzzer* fuzzer) { // TODO(mbarbella): This should actually do something. return true; } }; template <> struct FuzzTraits { static bool Fuzz(ppapi::proxy::SerializedVar* p, Fuzzer* fuzzer) { // TODO(mbarbella): This should actually do something. return true; } }; template <> struct FuzzTraits { static bool Fuzz(ppapi::HostResource* p, Fuzzer* fuzzer) { // TODO(mbarbella): Support mutation. if (!fuzzer->ShouldGenerate()) return true; PP_Instance instance; PP_Resource resource; if (!FuzzParam(&instance, fuzzer)) return false; if (!FuzzParam(&resource, fuzzer)) return false; p->SetHostResource(instance, resource); return true; } }; template <> struct FuzzTraits { static bool Fuzz(ppapi::PepperFilePath *p, Fuzzer* fuzzer) { // TODO(mbarbella): Support mutation. if (!fuzzer->ShouldGenerate()) return true; unsigned domain = RandInRange(ppapi::PepperFilePath::DOMAIN_MAX_VALID+1); base::FilePath path; if (!FuzzParam(&path, fuzzer)) return false; *p = ppapi::PepperFilePath( static_cast(domain), path); return true; } }; template <> struct FuzzTraits { static bool Fuzz(ppapi::PpapiPermissions* p, Fuzzer* fuzzer) { uint32_t bits = p->GetBits(); if (!FuzzParam(&bits, fuzzer)) return false; *p = ppapi::PpapiPermissions(bits); return true; } }; template <> struct FuzzTraits { static bool Fuzz(ppapi::SocketOptionData* p, Fuzzer* fuzzer) { // TODO(mbarbella): This can be improved. int32_t tmp; p->GetInt32(&tmp); if (!FuzzParam(&tmp, fuzzer)) return false; p->SetInt32(tmp); return true; } }; template <> struct FuzzTraits { static bool Fuzz(SkBitmap* p, Fuzzer* fuzzer) { // TODO(mbarbella): This should actually do something. return true; } }; template <> struct FuzzTraits { static bool Fuzz(network::DataElement* p, Fuzzer* fuzzer) { // TODO(mbarbella): Support mutation. if (!fuzzer->ShouldGenerate()) return true; switch (RandInRange(3)) { case 0: { // network::DataElement::Type::TYPE_BYTES if (RandEvent(2)) { p->SetToEmptyBytes(); } else { char data[256]; int data_len = RandInRange(sizeof(data)); fuzzer->FuzzBytes(&data[0], data_len); p->SetToBytes(&data[0], data_len); } return true; } case 1: { // network::DataElement::Type::TYPE_FILE base::FilePath path; uint64_t offset; uint64_t length; base::Time modification_time; if (!FuzzParam(&path, fuzzer)) return false; if (!FuzzParam(&offset, fuzzer)) return false; if (!FuzzParam(&length, fuzzer)) return false; if (!FuzzParam(&modification_time, fuzzer)) return false; p->SetToFilePathRange(path, offset, length, modification_time); return true; } case 2: { // network::DataElement::Type::TYPE_BLOB std::string uuid; uint64_t offset; uint64_t length; if (!FuzzParam(&uuid, fuzzer)) return false; if (!FuzzParam(&offset, fuzzer)) return false; if (!FuzzParam(&length, fuzzer)) return false; p->SetToBlobRange(uuid, offset, length); return true; } default: { NOTREACHED(); return false; } } } }; template <> struct FuzzTraits { static bool Fuzz(ui::LatencyInfo* p, Fuzzer* fuzzer) { // TODO(inferno): Add param traits for |latency_components|. int64_t trace_id = p->trace_id(); bool terminated = p->terminated(); if (!FuzzParam(&trace_id, fuzzer)) return false; if (!FuzzParam(&terminated, fuzzer)) return false; ui::LatencyInfo latency(trace_id, terminated); *p = latency; return true; } }; template <> struct FuzzTraits { static bool Fuzz(url::Origin* p, Fuzzer* fuzzer) { std::string scheme = p->scheme(); std::string host = p->host(); uint16_t port = p->port(); if (!FuzzParam(&scheme, fuzzer)) return false; if (!FuzzParam(&host, fuzzer)) return false; if (!FuzzParam(&port, fuzzer)) return false; *p = url::Origin::UnsafelyCreateOriginWithoutNormalization(scheme, host, port); // Force a unique origin 1% of the time: if (RandInRange(100) == 1) *p = url::Origin(); return true; } }; template <> struct FuzzTraits { static bool Fuzz(URLPattern* p, Fuzzer* fuzzer) { int valid_schemes = p->valid_schemes(); std::string host = p->host(); std::string port = p->port(); std::string path = p->path(); if (!FuzzParam(&valid_schemes, fuzzer)) return false; if (!FuzzParam(&host, fuzzer)) return false; if (!FuzzParam(&port, fuzzer)) return false; if (!FuzzParam(&path, fuzzer)) return false; *p = URLPattern(valid_schemes); p->SetHost(host); p->SetPort(port); p->SetPath(path); return true; } }; // Redefine macros to generate generating from traits declarations. // STRUCT declarations cause corresponding STRUCT_TRAITS declarations to occur. #undef IPC_STRUCT_BEGIN #undef IPC_STRUCT_BEGIN_WITH_PARENT #undef IPC_STRUCT_MEMBER #undef IPC_STRUCT_END #define IPC_STRUCT_BEGIN_WITH_PARENT(struct_name, parent) \ IPC_STRUCT_BEGIN(struct_name) #define IPC_STRUCT_BEGIN(struct_name) IPC_STRUCT_TRAITS_BEGIN(struct_name) #define IPC_STRUCT_MEMBER(type, name, ...) IPC_STRUCT_TRAITS_MEMBER(name) #define IPC_STRUCT_END() IPC_STRUCT_TRAITS_END() // Set up so next include will generate generate trait classes. #undef IPC_STRUCT_TRAITS_BEGIN #undef IPC_STRUCT_TRAITS_MEMBER #undef IPC_STRUCT_TRAITS_PARENT #undef IPC_STRUCT_TRAITS_END #define IPC_STRUCT_TRAITS_BEGIN(struct_name) \ template <> \ struct FuzzTraits { \ static bool Fuzz(struct_name *p, Fuzzer* fuzzer) { #define IPC_STRUCT_TRAITS_MEMBER(name) \ if (!FuzzParam(&p->name, fuzzer)) \ return false; #define IPC_STRUCT_TRAITS_PARENT(type) \ if (!FuzzParam(static_cast(p), fuzzer)) \ return false; #define IPC_STRUCT_TRAITS_END() \ return true; \ } \ }; // If |condition| isn't met, the messsge will fail to serialize. Try // increasingly smaller ranges until we find one that happens to meet // the condition, or fail trying. // TODO(mbarbella): Attempt to validate even in the mutation case. #undef IPC_ENUM_TRAITS_VALIDATE #define IPC_ENUM_TRAITS_VALIDATE(enum_name, condition) \ template <> \ struct FuzzTraits { \ static bool Fuzz(enum_name* p, Fuzzer* fuzzer) { \ if (!fuzzer->ShouldGenerate()) { \ return FuzzParam(reinterpret_cast(p), fuzzer); \ } \ for (int shift = 30; shift; --shift) { \ for (int tries = 0; tries < 2; ++tries) { \ int value = RandInRange(1 << shift); \ if (condition) { \ *reinterpret_cast(p) = value; \ return true; \ } \ } \ } \ std::cerr << "failed to satisfy " << #condition << "\n"; \ return false; \ } \ }; // Bring them into existence. #include "tools/ipc_fuzzer/message_lib/all_messages.h" #include "tools/ipc_fuzzer/message_lib/all_message_null_macros.h" #define MAX_FAKE_ROUTING_ID 15 // MessageFactory abstracts away constructing control/routed messages by // providing an additional random routing ID argument when necessary. template class MessageFactory; template class MessageFactory { public: template static std::unique_ptr New(const Args&... args) { return std::make_unique(args...); } }; template class MessageFactory { public: template static std::unique_ptr New(const Args&... args) { return std::make_unique(RandInRange(MAX_FAKE_ROUTING_ID), args...); } }; template class FuzzerHelper; template class FuzzerHelper, void>> { public: using Message = IPC::MessageT, void>; static std::unique_ptr Fuzz(IPC::Message* msg, Fuzzer* fuzzer) { return FuzzImpl(msg, fuzzer, std::index_sequence_for()); } private: template static std::unique_ptr FuzzImpl(IPC::Message* msg, Fuzzer* fuzzer, std::index_sequence) { typename Message::Param p; if (msg) { Message::Read(static_cast(msg), &p); } if (FuzzParam(&p, fuzzer)) { return MessageFactory::New(std::get(p)...); } std::cerr << "Don't know how to handle " << Meta::kName << "\n"; return nullptr; } }; template class FuzzerHelper< IPC::MessageT, std::tuple>> { public: using Message = IPC::MessageT, std::tuple>; static std::unique_ptr Fuzz(IPC::Message* msg, Fuzzer* fuzzer) { return FuzzImpl(msg, fuzzer, std::index_sequence_for()); } private: template static std::unique_ptr FuzzImpl(IPC::Message* msg, Fuzzer* fuzzer, std::index_sequence) { typename Message::SendParam p; Message* real_msg = static_cast(msg); std::unique_ptr new_msg; if (real_msg) { Message::ReadSendParam(real_msg, &p); } if (FuzzParam(&p, fuzzer)) { new_msg = MessageFactory::New( std::get(p)..., static_cast(nullptr)...); } if (real_msg && new_msg) { MessageCracker::CopyMessageID(new_msg.get(), real_msg); } else if (!new_msg) { std::cerr << "Don't know how to handle " << Meta::kName << "\n"; } return new_msg; } }; #include "tools/ipc_fuzzer/message_lib/all_message_null_macros.h" void PopulateFuzzerFunctionVector( FuzzerFunctionVector* function_vector) { #undef IPC_MESSAGE_DECL #define IPC_MESSAGE_DECL(name, ...) \ function_vector->push_back(FuzzerHelper::Fuzz); #include "tools/ipc_fuzzer/message_lib/all_messages.h" } // Redefine macros to register fuzzing functions into map. #include "tools/ipc_fuzzer/message_lib/all_message_null_macros.h" #undef IPC_MESSAGE_DECL #define IPC_MESSAGE_DECL(name, ...) \ (*map)[static_cast(name::ID)] = FuzzerHelper::Fuzz; void PopulateFuzzerFunctionMap(FuzzerFunctionMap* map) { #include "tools/ipc_fuzzer/message_lib/all_messages.h" } } // namespace ipc_fuzzer