fuzzing: introduce automated IPC fuzzing
This CL introduces a fuzzer that automatically detects renderer process exposed IPC interfaces and fuzzes them. The design of this fuzzer has been described at https://docs.google.com/document/d/1Y5yy8YTJRLPQUPHzPO-KhmT-gZoBkLjWp2eRaJbBpq4/edit?usp=sharing. Because GN does not support dynamic dependencies, this patch needs to introduce a gni file at `chrome/browser_exposed_mojom_targets.gni` which lists all the targets of browser exposed mojom interfaces on Linux. Please, check this doc to read about pros and cons about the different considered solutions: https://docs.google.com/document/d/1BSgrxtXVKGEtVU5KoKZbvZfQOxIZb2fqYcAX4FXYw8E. Thanks to this automated IPC fuzzer, any new browser-exposed IPC endpoint will be fuzzed as soon as it gets in the codebase. Doing this, we aim at detecting potential issues as soon as possible. Bug: 40282115 Cq-Include-Trybots: luci.chromium.try:linux-centipede-asan-rel Change-Id: I1f097b871d53c4f2a34c62c43bbede1fd23d760a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5490095 Reviewed-by: Adrian Taylor <adetaylor@chromium.org> Reviewed-by: Daniel Cheng <dcheng@chromium.org> Commit-Queue: Paul Semel <paulsemel@chromium.org> Cr-Commit-Position: refs/heads/main@{#1310532}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
11a700e804
commit
90ef9055a5
345
chrome/browser_exposed_mojom_targets.gni
Normal file
345
chrome/browser_exposed_mojom_targets.gni
Normal file
@ -0,0 +1,345 @@
|
||||
# Copyright 2024 The Chromium Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
#
|
||||
|
||||
# This file represents global knowledge about all the mojom targets building
|
||||
# browser-to-renderer exposed mojom interfaces. Developers are responsible for
|
||||
# maintaining this file to match addition and removal of newly exposed targets.
|
||||
# This is part of our automated fuzzing of the browser/renderer interface that
|
||||
# lives at `//chrome/test/fuzzing/renderer_fuzzing/ipc_fuzzing`.
|
||||
# As for now, we are only listing those targets for interfaces exposed on
|
||||
# Linux.
|
||||
|
||||
browser_exposed_mojom_targets = [
|
||||
"//cc/mojom:layer_type",
|
||||
"//cc/mojom:mojom",
|
||||
"//chrome/browser/cart:mojo_bindings",
|
||||
"//chrome/browser/companion/core/mojom:mojo_bindings",
|
||||
"//chrome/browser/lens/core/mojom:mojo_bindings",
|
||||
"//chrome/browser/media:mojo_bindings",
|
||||
"//chrome/browser/new_tab_page/modules/feed:mojo_bindings",
|
||||
"//chrome/browser/new_tab_page/modules/file_suggestion:mojo_bindings",
|
||||
"//chrome/browser/new_tab_page/modules/history_clusters:mojo_bindings",
|
||||
"//chrome/browser/new_tab_page/modules/history_clusters/cart:mojo_bindings",
|
||||
"//chrome/browser/new_tab_page/modules/history_clusters/discount:mojo_bindings",
|
||||
"//chrome/browser/new_tab_page/modules/photos:mojo_bindings",
|
||||
"//chrome/browser/new_tab_page/modules/recipes:mojo_bindings",
|
||||
"//chrome/browser/new_tab_page/modules/safe_browsing:mojo_bindings",
|
||||
"//chrome/browser/new_tab_page/modules/v2/calendar:mojo_bindings",
|
||||
"//chrome/browser/new_tab_page/modules/v2/history_clusters:mojo_bindings",
|
||||
"//chrome/browser/new_tab_page/modules/v2/most_relevant_tab_resumption:mojo_bindings",
|
||||
"//chrome/browser/new_tab_page/modules/v2/tab_resumption:mojo_bindings",
|
||||
"//chrome/browser/resource_coordinator:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/access_code_cast:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/app_home:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/app_service_internals:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/bluetooth_internals:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/connectors_internals:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/data_sharing_internals:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/discards:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/downloads:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/hats:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/internals/user_education:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/location_internals:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/new_tab_page_third_party:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/new_tab_page:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/new_tab_page/foo:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/omnibox:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/on_device_internals:mojom",
|
||||
"//chrome/browser/ui/webui/privacy_sandbox:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/reset_password:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/search_engine_choice:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/segmentation_internals:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/side_panel/bookmarks:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/side_panel/customize_chrome:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/side_panel/performance_controls:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/side_panel/reading_list:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/suggest_internals:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/tab_search:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/tab_strip:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/tabs:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/usb_internals:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/web_app_internals:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/whats_new:mojo_bindings",
|
||||
"//chrome/browser/web_applications/mojom:mojom_web_apps_enum",
|
||||
"//chrome/common:available_offline_content_mojom",
|
||||
"//chrome/common:mojo_bindings",
|
||||
"//chrome/common:offline_page_auto_fetcher_mojom",
|
||||
"//chrome/common:supervised_user_commands_mojom",
|
||||
"//chrome/common/accessibility:mojo_bindings",
|
||||
"//chrome/common/cart:mojo_bindings",
|
||||
"//chrome/common/companion:mojo_bindings",
|
||||
"//chrome/common/compose:mojo_bindings",
|
||||
"//chrome/common/importer:interfaces",
|
||||
"//chrome/common/search:mojo_bindings",
|
||||
"//chrome/services/file_util/public/mojom:mojom",
|
||||
"//chrome/services/media_gallery_util/public/mojom:mojom",
|
||||
"//chrome/services/on_device_translation/public/mojom:mojom",
|
||||
"//chrome/services/printing/public/mojom:mojom",
|
||||
"//chrome/services/removable_storage_writer/public/mojom:mojom",
|
||||
"//components/attribution_reporting:mojom",
|
||||
"//components/attribution_reporting:registration_header_error_mojom",
|
||||
"//components/attribution_reporting:registration_mojom",
|
||||
"//components/attribution_reporting:source_type_mojom",
|
||||
"//components/autofill/content/common/mojom:mojom",
|
||||
"//components/autofill/core/common/mojom:mojo_types",
|
||||
"//components/browsing_topics/mojom:mojo_bindings",
|
||||
"//components/commerce/core/internals/mojom:mojo_bindings",
|
||||
"//components/commerce/core/mojom:mojo_bindings",
|
||||
"//components/compose/core/browser:mojo_bindings",
|
||||
"//components/content_capture/common:mojo_interfaces",
|
||||
"//components/content_capture/common:mojo_types",
|
||||
"//components/content_settings/common:mojom",
|
||||
"//components/content_settings/core/common:content_settings_enums",
|
||||
"//components/content_settings/core/common:content_settings_types",
|
||||
"//components/content_settings/core/common:mojo_bindings",
|
||||
"//components/continuous_search/common/public/mojom:mojom",
|
||||
"//components/device_signals/core/common/mojom:mojom",
|
||||
"//components/digital_goods/mojom:mojom",
|
||||
"//components/discardable_memory/public/mojom:mojom",
|
||||
"//components/dom_distiller/content/common/mojom:mojom",
|
||||
"//components/dom_distiller/core/mojom:mojom",
|
||||
"//components/download/public/common:interfaces",
|
||||
"//components/facilitated_payments/core/mojom:facilitated_payments_agent_mojom",
|
||||
"//components/facilitated_payments/core/mojom:pix_code_validator_mojom",
|
||||
"//components/feed/mojom:mojo_bindings",
|
||||
"//components/global_media_controls/public/mojom:device_service",
|
||||
"//components/guest_view/common:mojom",
|
||||
"//components/heap_profiling/in_process:mojom",
|
||||
"//components/history_clusters/history_clusters_internals/webui:mojo_bindings",
|
||||
"//components/history_clusters/public/mojom:mojo_bindings",
|
||||
"//components/history/core/browser/mojom:mojo_bindings",
|
||||
"//components/lens:lens_mojo",
|
||||
"//components/media_router/common/mojom:debugger",
|
||||
"//components/media_router/common/mojom:logger",
|
||||
"//components/media_router/common/mojom:media_controller",
|
||||
"//components/media_router/common/mojom:media_route_provider_id",
|
||||
"//components/media_router/common/mojom:media_router",
|
||||
"//components/media_router/common/mojom:route_request_result_code",
|
||||
"//components/metrics/public/mojom:call_stack_mojo_bindings",
|
||||
"//components/metrics/public/mojom:histogram_fetcher_mojo_bindings",
|
||||
"//components/metrics/public/mojom:single_sample_metrics_mojo_bindings",
|
||||
"//components/metrics/structured/mojom:mojom",
|
||||
"//components/mirroring/mojom:common",
|
||||
"//components/mirroring/mojom:service",
|
||||
"//components/ml/mojom:mojom",
|
||||
"//components/ml/webnn:features",
|
||||
"//components/network_hints/common:mojo_bindings",
|
||||
"//components/no_state_prefetch/common:mojo_bindings",
|
||||
"//components/omnibox/browser:mojo_bindings",
|
||||
"//components/optimization_guide/content/mojom:mojo_interfaces",
|
||||
"//components/optimization_guide/core:interfaces",
|
||||
"//components/optimization_guide/optimization_guide_internals/webui:mojo_bindings",
|
||||
"//components/os_crypt/async/common:algorithm_mojom",
|
||||
"//components/os_crypt/async/common:common_mojom",
|
||||
"//components/page_image_service/mojom:mojo_bindings",
|
||||
"//components/page_load_metrics/common:page_load_metrics_mojom",
|
||||
"//components/paint_preview/common/mojom:mojom",
|
||||
"//components/password_manager/services/csv_password/public/mojom:mojom",
|
||||
"//components/payments/mojom:mojom",
|
||||
"//components/performance_manager/public/mojom:mojom",
|
||||
"//components/printing/common:mojo_interfaces",
|
||||
"//components/safe_browsing/content/common:interfaces",
|
||||
"//components/safe_browsing/core/common:interfaces",
|
||||
"//components/schema_org/common:improved_mojom",
|
||||
"//components/schema_org/common:mojom",
|
||||
"//components/security_interstitials/core/common/mojom:mojom",
|
||||
"//components/services/filesystem/public/mojom:mojom",
|
||||
"//components/services/font/public/mojom:mojom",
|
||||
"//components/services/heap_profiling/public/mojom:mojom",
|
||||
"//components/services/language_detection/public/mojom:mojom",
|
||||
"//components/services/paint_preview_compositor/public/mojom:mojom",
|
||||
"//components/services/patch/public/mojom:mojom",
|
||||
"//components/services/print_compositor/public/mojom:mojom",
|
||||
"//components/services/quarantine/public/mojom:mojom",
|
||||
"//components/services/storage/privileged/mojom:mojom_bucket",
|
||||
"//components/services/storage/privileged/mojom:mojom",
|
||||
"//components/services/storage/public/mojom:mojom",
|
||||
"//components/services/storage/public/mojom/buckets:buckets",
|
||||
"//components/services/storage/public/mojom/filesystem:filesystem",
|
||||
"//components/services/unzip/public/mojom:mojom",
|
||||
"//components/site_engagement/core/mojom:mojo_bindings",
|
||||
"//components/spellcheck/common:interfaces",
|
||||
"//components/subresource_filter/content/mojom:mojom",
|
||||
"//components/subresource_filter/core/mojom:mojom",
|
||||
"//components/tab_groups/public/mojom:mojo_bindings",
|
||||
"//components/translate/content/common:common",
|
||||
"//components/variations:variations_mojom",
|
||||
"//components/visitedlink/common:interfaces",
|
||||
"//components/viz/service/debugger/mojom:mojom",
|
||||
"//components/web_cache/public/mojom:mojom",
|
||||
"//components/web_package/mojom:mojom",
|
||||
"//components/webapps/common:mojo_bindings",
|
||||
"//components/webapps/services/web_app_origin_association/public/mojom:mojom",
|
||||
"//content/browser/attribution_reporting:internals_mojo_bindings",
|
||||
"//content/browser/attribution_reporting:mojo_bindings",
|
||||
"//content/browser/attribution_reporting:registration_result_mojom",
|
||||
"//content/browser/indexed_db:internals_mojo_bindings",
|
||||
"//content/browser/private_aggregation:mojo_bindings",
|
||||
"//content/browser/process_internals:mojo_bindings",
|
||||
"//content/browser/tracing/trace_report:mojo_bindings",
|
||||
"//content/browser/xr/webxr_internals/mojom:mojo_bindings",
|
||||
"//content/common:mojo_bindings",
|
||||
"//content/public/common:interfaces",
|
||||
"//content/public/common:renderer_type",
|
||||
"//device/bluetooth/public/mojom:deprecated_experimental_interfaces",
|
||||
"//device/bluetooth/public/mojom:mojom",
|
||||
"//device/gamepad/public/mojom:mojom",
|
||||
"//device/vr/public/mojom:isolated_xr_service",
|
||||
"//device/vr/public/mojom:test_mojom",
|
||||
"//device/vr/public/mojom:vr_service",
|
||||
"//device/vr/public/mojom:xr_common",
|
||||
"//extensions/common:mojom",
|
||||
"//extensions/common/api:mojom",
|
||||
"//gpu/ipc/common:gmb_interface",
|
||||
"//gpu/ipc/common:gpu_channel_mojom",
|
||||
"//gpu/ipc/common:gpu_preferences_interface",
|
||||
"//gpu/ipc/common:interfaces",
|
||||
"//gpu/ipc/common:surface_handle",
|
||||
"//gpu/ipc/common:vulkan_interface",
|
||||
"//ipc:mojom_constants",
|
||||
"//ipc:mojom",
|
||||
"//media/capture/mojom:image_capture",
|
||||
"//media/capture/mojom:video_capture_buffer",
|
||||
"//media/capture/mojom:video_capture_types",
|
||||
"//media/capture/mojom:video_capture",
|
||||
"//media/capture/mojom:video_effects_manager",
|
||||
"//media/learning/mojo/public/mojom:mojom",
|
||||
"//media/midi:mojo",
|
||||
"//media/mojo/mojom:audio_data",
|
||||
"//media/mojo/mojom:encryption_pattern",
|
||||
"//media/mojo/mojom:mojom",
|
||||
"//media/mojo/mojom:remoting_common",
|
||||
"//media/mojo/mojom:remoting",
|
||||
"//media/mojo/mojom:speech_recognition_audio_forwarder",
|
||||
"//media/mojo/mojom:speech_recognition",
|
||||
"//media/mojo/mojom:web_speech_recognition",
|
||||
"//media/mojo/mojom/stable:native_pixmap_handle",
|
||||
"//media/mojo/mojom/stable:stable_video_decoder",
|
||||
"//mojo/public/interfaces/bindings:bindings",
|
||||
"//mojo/public/mojom/base:base",
|
||||
"//mojo/public/mojom/base:protobuf_support",
|
||||
"//pdf/mojom:mojom",
|
||||
"//printing/backend/mojom:mojom",
|
||||
"//printing/mojom:mojom",
|
||||
"//printing/mojom:printing_context",
|
||||
"//sandbox/policy/mojom:mojom",
|
||||
"//services/accessibility/public/mojom:automation_client",
|
||||
"//services/accessibility/public/mojom:automation",
|
||||
"//services/accessibility/public/mojom:mojom",
|
||||
"//services/audio/public/mojom:mojom",
|
||||
"//services/cert_verifier/public/mojom:mojom",
|
||||
"//services/data_decoder/public/mojom:mojom_xml_parser",
|
||||
"//services/data_decoder/public/mojom:mojom",
|
||||
"//services/device/public/mojom:device_service",
|
||||
"//services/device/public/mojom:generic_sensor",
|
||||
"//services/device/public/mojom:geolocation_internals",
|
||||
"//services/device/public/mojom:geoposition",
|
||||
"//services/device/public/mojom:mojom",
|
||||
"//services/device/public/mojom:usb_test",
|
||||
"//services/device/public/mojom:usb",
|
||||
"//services/image_annotation/public/mojom:mojom",
|
||||
"//services/media_session/public/mojom:mojom",
|
||||
"//services/metrics/public/mojom:mojom",
|
||||
"//services/network/public/mojom:cookies_mojom",
|
||||
"//services/network/public/mojom:mojom_attribution",
|
||||
"//services/network/public/mojom:mojom_first_party_sets",
|
||||
"//services/network/public/mojom:mojom_host_resolver",
|
||||
"//services/network/public/mojom:mojom_ip_address",
|
||||
"//services/network/public/mojom:mojom_network_anonymization_key",
|
||||
"//services/network/public/mojom:mojom_network_isolation_key",
|
||||
"//services/network/public/mojom:mojom_network_param",
|
||||
"//services/network/public/mojom:mojom_proxy_config",
|
||||
"//services/network/public/mojom:mojom_schemeful_site",
|
||||
"//services/network/public/mojom:mojom_shared_dictionary",
|
||||
"//services/network/public/mojom:mojom_structured_headers",
|
||||
"//services/network/public/mojom:mojom",
|
||||
"//services/network/public/mojom:url_loader_base",
|
||||
"//services/network/public/mojom:websocket_mojom",
|
||||
"//services/on_device_model/public/mojom:mojom",
|
||||
"//services/passage_embeddings/public/mojom:mojom",
|
||||
"//services/preferences/public/mojom:mojom",
|
||||
"//services/proxy_resolver/public/mojom:mojom",
|
||||
"//services/resource_coordinator/public/mojom:mojom",
|
||||
"//services/screen_ai/public/mojom:factory",
|
||||
"//services/screen_ai/public/mojom:mojom",
|
||||
"//services/service_manager/public/mojom:constants",
|
||||
"//services/service_manager/public/mojom:mojom",
|
||||
"//services/shape_detection/public/mojom:mojom",
|
||||
"//services/tracing/public/mojom:mojom",
|
||||
"//services/video_capture/public/mojom:constants",
|
||||
"//services/video_capture/public/mojom:mojom",
|
||||
"//services/video_effects/public/mojom:mojom",
|
||||
"//services/viz/privileged/mojom:mojom",
|
||||
"//services/viz/privileged/mojom/compositing:compositing",
|
||||
"//services/viz/privileged/mojom/gl:gl",
|
||||
"//services/viz/public/mojom:mojom",
|
||||
"//services/viz/public/mojom:shared_image_format",
|
||||
"//services/viz/public/mojom:singleplanar_format",
|
||||
"//services/webnn/public/mojom:mojom",
|
||||
"//skia/public/mojom:mojom",
|
||||
"//storage/browser/quota:mojo_bindings",
|
||||
"//third_party/blink/public/mojom:android_mojo_bindings",
|
||||
"//third_party/blink/public/mojom:authenticator_test_mojo_bindings",
|
||||
"//third_party/blink/public/mojom:color_scheme_mojo_bindings",
|
||||
"//third_party/blink/public/mojom:embedded_frame_sink_mojo_bindings",
|
||||
"//third_party/blink/public/mojom:memory_usage_monitor_linux_mojo_bindings",
|
||||
"//third_party/blink/public/mojom:mojom_core",
|
||||
"//third_party/blink/public/mojom:mojom_mhtml_load_result",
|
||||
"//third_party/blink/public/mojom:mojom_modules",
|
||||
"//third_party/blink/public/mojom:mojom_platform",
|
||||
"//third_party/blink/public/mojom:script_type_mojo_bindings",
|
||||
"//third_party/blink/public/mojom:web_bluetooth_mojo_bindings",
|
||||
"//third_party/blink/public/mojom:web_feature_mojo_bindings",
|
||||
"//third_party/blink/public/mojom/gpu:gpu",
|
||||
"//third_party/blink/public/mojom/origin_trial_feature:origin_trial_feature",
|
||||
"//third_party/blink/public/mojom/origin_trial_state:origin_trial_state",
|
||||
"//third_party/blink/public/mojom/private_network_device:private_network_device",
|
||||
"//third_party/blink/public/mojom/quota:quota",
|
||||
"//third_party/blink/public/mojom/runtime_feature_state:runtime_feature_state",
|
||||
"//third_party/blink/public/mojom/service_worker:storage",
|
||||
"//third_party/blink/public/mojom/storage_key:storage_key",
|
||||
"//third_party/blink/public/mojom/tokens:tokens",
|
||||
"//third_party/blink/public/mojom/usb:usb",
|
||||
"//ui/accessibility:ax_constants_mojo",
|
||||
"//ui/accessibility:ax_enums_mojo",
|
||||
"//ui/accessibility:ax_features_mojo",
|
||||
"//ui/accessibility/mojom:mojom",
|
||||
"//ui/base/cursor/mojom:cursor_type",
|
||||
"//ui/base/cursor/mojom:mojom",
|
||||
"//ui/base/dragdrop/mojom:mojom",
|
||||
"//ui/base/ime/mojom:mojom",
|
||||
"//ui/base/mojom:mojom",
|
||||
"//ui/color:mojom",
|
||||
"//ui/display/mojom:mojom",
|
||||
"//ui/events/mojom:event_latency_metadata_mojom",
|
||||
"//ui/events/mojom:mojom",
|
||||
"//ui/gfx/geometry/mojom:mojom",
|
||||
"//ui/gfx/image/mojom:mojom",
|
||||
"//ui/gfx/mojom:hdr_metadata",
|
||||
"//ui/gfx/mojom:mojom",
|
||||
"//ui/gfx/mojom:native_handle_types",
|
||||
"//ui/gfx/range/mojom:mojom",
|
||||
"//ui/gl/mojom:mojom",
|
||||
"//ui/latency/mojom:mojom",
|
||||
"//ui/ozone/platform/wayland/mojom:mojom",
|
||||
"//ui/ozone/public/mojom:gesture_properties_service",
|
||||
"//ui/webui/resources/cr_components/app_management:mojo_bindings",
|
||||
"//ui/webui/resources/cr_components/certificate_manager:mojom",
|
||||
"//ui/webui/resources/cr_components/color_change_listener:mojom",
|
||||
"//ui/webui/resources/cr_components/commerce:mojo_bindings",
|
||||
"//ui/webui/resources/cr_components/customize_color_scheme_mode:mojom",
|
||||
"//ui/webui/resources/cr_components/customize_themes:mojom",
|
||||
"//ui/webui/resources/cr_components/help_bubble:mojo_bindings",
|
||||
"//ui/webui/resources/cr_components/history_clusters:mojo_bindings",
|
||||
"//ui/webui/resources/cr_components/history_embeddings:mojo_bindings",
|
||||
"//ui/webui/resources/cr_components/most_visited:mojom",
|
||||
"//ui/webui/resources/cr_components/searchbox:mojo_bindings",
|
||||
"//ui/webui/resources/cr_components/theme_color_picker:mojom",
|
||||
"//ui/webui/resources/js/browser_command:mojo_bindings",
|
||||
"//ui/webui/resources/js/metrics_reporter:mojo_bindings",
|
||||
"//url/mojom:url_mojom_gurl",
|
||||
"//url/mojom:url_mojom_origin",
|
||||
"//url/mojom:url_mojom_scheme_host_port",
|
||||
]
|
@ -2,15 +2,22 @@
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//chrome/browser_exposed_mojom_targets.gni")
|
||||
import("//chrome/test/fuzzing/in_process_fuzzer.gni")
|
||||
import("//chrome/test/fuzzing/renderer_fuzzing/in_process_renderer_fuzzing.gni")
|
||||
import(
|
||||
"//chrome/test/fuzzing/renderer_fuzzing/ipc_fuzzing/mojom_interfaces.gni")
|
||||
|
||||
group("test") {
|
||||
testonly = true
|
||||
}
|
||||
|
||||
# We want to make sure to only enable this fuzzer on platforms that have a CQ
|
||||
# bot so that the mojom target list is maintained up-to-date.
|
||||
# Similarly, if something goes wrong with those targets, this will "only" break
|
||||
# fuzzer CQ bots, so we this allows for damage control.
|
||||
# crbug.com/343669713: enable this on Windows once the Linux version sticks in.
|
||||
renderer_ipc_fuzzing_enabled =
|
||||
fuzzing_engine_supports_custom_main && is_linux && enable_mojom_fuzzer
|
||||
|
||||
if (fuzzing_engine_supports_custom_main) {
|
||||
source_set("renderer_in_process_fuzzer_runner") {
|
||||
testonly = true
|
||||
@ -25,164 +32,77 @@ if (fuzzing_engine_supports_custom_main) {
|
||||
}
|
||||
}
|
||||
|
||||
# As for now, we cannot compile this fuzzer when `dcheck_always_on=true`,
|
||||
# because InProcessFuzzer aren't running properly. See crbug.com/40949031.
|
||||
# Relatedly, we are also checking for `fuzzing_engine_supports_custom_main`
|
||||
# because this is a necessary condition to most of the in_process_fuzzer
|
||||
# dependencies, which we are heavily relying upon here.
|
||||
if (!is_android && !dcheck_always_on && fuzzing_engine_supports_custom_main) {
|
||||
if (renderer_ipc_fuzzing_enabled) {
|
||||
_mojolpm_deps = []
|
||||
foreach(target, browser_exposed_mojom_targets) {
|
||||
_mojolpm_deps += [ "${target}_mojolpm" ]
|
||||
}
|
||||
|
||||
# This tool aims at replicating an environment similar to how
|
||||
# in_process_fuzzer are running, so that we can fetch a list of mojom
|
||||
# interfaces that make sense for `renderer_in_process_mojolpm_fuzzer`.
|
||||
executable("ipc_interfaces_dumper") {
|
||||
testonly = true
|
||||
sources = [
|
||||
# We include those files so that we take into consideration the exact
|
||||
# same setup as in_process_fuzzer, including the runtime flags. This is
|
||||
# important because this can have an effect on which interfaces are
|
||||
# being exposed.
|
||||
"../in_process_fuzzer.cc",
|
||||
"../in_process_fuzzer.h",
|
||||
"ipc_fuzzing/ipc_interfaces_dumper.cc",
|
||||
]
|
||||
defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
|
||||
sources = [ "ipc_fuzzing/ipc_interfaces_dumper.cc" ]
|
||||
deps = [
|
||||
"//chrome/test:chrome_test_launcher",
|
||||
"//base",
|
||||
"//chrome/test:browser_tests_runner",
|
||||
"//chrome/test:test_support",
|
||||
"//chrome/test/fuzzing:in_process_fuzzer_buildflags",
|
||||
"//content/test:test_support",
|
||||
|
||||
# This is so that in_process_fuzzer internals work, but
|
||||
# `ipc_interfaces_dumper` is not recognized as an actual fuzzer.
|
||||
"//testing/libfuzzer:fuzzing_engine_no_main_core",
|
||||
]
|
||||
}
|
||||
action("renderer_in_process_mojolpm_fuzzer_generator") {
|
||||
testonly = true
|
||||
deps = [ ":ipc_interfaces_dumper" ]
|
||||
depfile = "$target_out_dir/$target_name.d"
|
||||
inputs = []
|
||||
foreach(target, browser_exposed_mojom_targets) {
|
||||
inputs += [ get_label_info(target, "target_gen_dir") + "/" +
|
||||
get_label_info(target, "name") + ".build_metadata" ]
|
||||
}
|
||||
|
||||
# We cannot use the GN `metadata` mechanism here, because our initial
|
||||
# deps could depend on other mojom targets which would also generate some
|
||||
# metadata, but we would actually not depend on their `mojolpm` variant.
|
||||
# Doing things the current way allows for ensuring that we are only listing
|
||||
# meta files for mojolpm targets we directly depend upon.
|
||||
_metafiles = []
|
||||
foreach(file, inputs) {
|
||||
_metafiles += [ rebase_path(file, root_build_dir) ]
|
||||
}
|
||||
write_file("$target_gen_dir/metadata", _metafiles)
|
||||
|
||||
script = "//chrome/test/fuzzing/renderer_fuzzing/ipc_fuzzing/generate_testcase.py"
|
||||
args = [
|
||||
"-n",
|
||||
"renderer_in_process_mojolpm_fuzzer",
|
||||
"-p",
|
||||
rebase_path("${root_build_dir}/ipc_interfaces_dumper", root_build_dir),
|
||||
"-i",
|
||||
rebase_path("${target_gen_dir}/interfaces.json", root_build_dir),
|
||||
"-r",
|
||||
rebase_path(root_gen_dir, root_build_dir),
|
||||
"-m",
|
||||
rebase_path("$target_gen_dir/metadata", root_build_dir),
|
||||
"-t",
|
||||
rebase_path("${target_gen_dir}/testcase.h", root_build_dir),
|
||||
"-d",
|
||||
rebase_path("${target_gen_dir}/", root_gen_dir),
|
||||
"-o",
|
||||
rebase_path("${target_gen_dir}/testcase.h", root_build_dir),
|
||||
"-c",
|
||||
"-n",
|
||||
"renderer_in_process_mojolpm_fuzzer",
|
||||
"-f",
|
||||
rebase_path(depfile, root_build_dir),
|
||||
]
|
||||
foreach(interface, context_browser_exposed_interfaces) {
|
||||
args += [ interface[1] ]
|
||||
}
|
||||
args += [ "-p" ]
|
||||
foreach(interface, process_browser_exposed_interfaces) {
|
||||
args += [ interface[1] ]
|
||||
}
|
||||
outputs = [ "${target_gen_dir}/testcase.h" ]
|
||||
outputs = [
|
||||
"${target_gen_dir}/interfaces.json",
|
||||
"${target_gen_dir}/testcase.h",
|
||||
]
|
||||
deps += _mojolpm_deps
|
||||
}
|
||||
in_process_renderer_mojolpm_generated_fuzzer(
|
||||
"renderer_in_process_mojolpm_fuzzer") {
|
||||
sources = [ "renderer_in_process_mojolpm_fuzzer.cc" ]
|
||||
|
||||
interfaces = context_browser_exposed_interfaces
|
||||
interfaces += process_browser_exposed_interfaces
|
||||
|
||||
_interfaces_deps = [
|
||||
"//chrome/browser/lens/core/mojom:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/media:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/new_tab_page/modules/file_suggestion:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/new_tab_page/modules/photos:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/new_tab_page/modules/v2/history_clusters:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/new_tab_page/modules/v2/tab_resumption:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/access_code_cast:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/app_home:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/app_service_internals:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/bluetooth_internals:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/connectors_internals:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/discards:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/downloads:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/internals/user_education:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/location_internals:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/new_tab_page:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/new_tab_page/foo:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/new_tab_page_third_party:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/omnibox:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/privacy_sandbox:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/reset_password:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/search_engine_choice:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/segmentation_internals:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/side_panel/bookmarks:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/side_panel/customize_chrome:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/side_panel/reading_list:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/suggest_internals:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/tab_search:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/tab_strip:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/usb_internals:mojo_bindings_mojolpm",
|
||||
"//chrome/browser/ui/webui/web_app_internals:mojo_bindings_mojolpm",
|
||||
"//chrome/common:mojo_bindings_mojolpm",
|
||||
"//chrome/common/accessibility:mojo_bindings_mojolpm",
|
||||
"//chrome/common/cart:mojo_bindings_mojolpm",
|
||||
"//components/browsing_topics/mojom:mojo_bindings_mojolpm",
|
||||
"//components/commerce/core/internals/mojom:mojo_bindings_mojolpm",
|
||||
"//components/dom_distiller/content/common/mojom:mojom_mojolpm",
|
||||
"//components/history_clusters/history_clusters_internals/webui:mojo_bindings_mojolpm",
|
||||
"//components/metrics/public/mojom:call_stack_mojo_bindings_mojolpm",
|
||||
"//components/metrics/public/mojom:single_sample_metrics_mojo_bindings_mojolpm",
|
||||
"//components/network_hints/common:mojo_bindings_mojolpm",
|
||||
"//components/no_state_prefetch/common:mojo_bindings_mojolpm",
|
||||
"//components/optimization_guide/optimization_guide_internals/webui:mojo_bindings_mojolpm",
|
||||
"//components/page_image_service/mojom:mojo_bindings_mojolpm",
|
||||
"//components/performance_manager/public/mojom:mojom_mojolpm",
|
||||
"//components/safe_browsing/content/common:interfaces_mojolpm",
|
||||
"//components/site_engagement/core/mojom:mojo_bindings_mojolpm",
|
||||
"//components/spellcheck/common:interfaces_mojolpm",
|
||||
"//components/translate/content/common:common_mojolpm",
|
||||
"//content/browser/attribution_reporting:internals_mojo_bindings_mojolpm",
|
||||
"//content/browser/indexed_db:internals_mojo_bindings_mojolpm",
|
||||
"//content/browser/private_aggregation:mojo_bindings_mojolpm",
|
||||
"//content/browser/process_internals:mojo_bindings_mojolpm",
|
||||
"//content/browser/tracing/trace_report:mojo_bindings_mojolpm",
|
||||
"//content/browser/xr/webxr_internals/mojom:mojo_bindings_mojolpm",
|
||||
"//content/common:mojo_bindings_mojolpm",
|
||||
"//device/gamepad/public/mojom:mojom_mojolpm",
|
||||
"//device/vr/public/mojom:vr_service_mojolpm",
|
||||
"//extensions/common/api:mojom_mojolpm",
|
||||
"//media/capture/mojom:image_capture_mojolpm",
|
||||
"//media/capture/mojom:video_capture_mojolpm",
|
||||
"//media/midi:mojo_mojolpm",
|
||||
"//media/mojo/mojom:mojom_mojolpm",
|
||||
"//media/mojo/mojom:remoting_mojolpm",
|
||||
"//media/mojo/mojom:speech_recognition_mojolpm",
|
||||
"//media/mojo/mojom:web_speech_recognition_mojolpm",
|
||||
"//services/device/public/mojom:mojom_mojolpm",
|
||||
"//services/image_annotation/public/mojom:mojom_mojolpm",
|
||||
"//services/network/public/mojom:cookies_mojom_mojolpm",
|
||||
"//services/network/public/mojom:mojom_mojolpm",
|
||||
"//services/network/public/mojom:url_loader_base_mojolpm",
|
||||
"//services/resource_coordinator/public/mojom:mojom_mojolpm",
|
||||
"//services/screen_ai/public/mojom:mojom_mojolpm",
|
||||
"//services/shape_detection/public/mojom:mojom_mojolpm",
|
||||
"//services/viz/public/mojom:mojom_mojolpm",
|
||||
"//storage/browser/quota:mojo_bindings_mojolpm",
|
||||
"//third_party/blink/public/mojom:android_mojo_bindings_mojolpm",
|
||||
"//third_party/blink/public/mojom:authenticator_test_mojo_bindings_mojolpm",
|
||||
"//third_party/blink/public/mojom:embedded_frame_sink_mojo_bindings_mojolpm",
|
||||
"//third_party/blink/public/mojom:mojom_core_mojolpm",
|
||||
"//third_party/blink/public/mojom:mojom_modules_mojolpm",
|
||||
"//third_party/blink/public/mojom:mojom_platform_mojolpm",
|
||||
"//third_party/blink/public/mojom:web_bluetooth_mojo_bindings_mojolpm",
|
||||
"//third_party/blink/public/mojom/gpu:gpu_mojolpm",
|
||||
"//third_party/blink/public/mojom/origin_trial_state:origin_trial_state_mojolpm",
|
||||
"//third_party/blink/public/mojom/quota:quota_mojolpm",
|
||||
"//third_party/blink/public/mojom/usb:usb_mojolpm",
|
||||
"//ui/webui/resources/cr_components/app_management:mojo_bindings_mojolpm",
|
||||
"//ui/webui/resources/cr_components/certificate_manager:mojom_mojolpm",
|
||||
"//ui/webui/resources/cr_components/color_change_listener:mojom_mojolpm",
|
||||
"//ui/webui/resources/cr_components/commerce:mojo_bindings_mojolpm",
|
||||
"//ui/webui/resources/cr_components/customize_color_scheme_mode:mojom_mojolpm",
|
||||
"//ui/webui/resources/cr_components/customize_themes:mojom_mojolpm",
|
||||
"//ui/webui/resources/cr_components/help_bubble:mojo_bindings_mojolpm",
|
||||
"//ui/webui/resources/cr_components/history_clusters:mojo_bindings_mojolpm",
|
||||
"//ui/webui/resources/cr_components/most_visited:mojom_mojolpm",
|
||||
"//ui/webui/resources/cr_components/searchbox:mojo_bindings_mojolpm",
|
||||
"//ui/webui/resources/cr_components/theme_color_picker:mojom_mojolpm",
|
||||
"//ui/webui/resources/js/browser_command:mojo_bindings_mojolpm",
|
||||
"//ui/webui/resources/js/metrics_reporter:mojo_bindings_mojolpm",
|
||||
]
|
||||
interface_file = "${target_gen_dir}/interfaces.json"
|
||||
|
||||
deps = [
|
||||
":renderer_in_process_mojolpm_fuzzer_generator",
|
||||
@ -193,8 +113,10 @@ if (!is_android && !dcheck_always_on && fuzzing_engine_supports_custom_main) {
|
||||
"//testing/libfuzzer/proto:url_proto_converter",
|
||||
"//third_party/blink/public/common:storage_key_proto_converter",
|
||||
]
|
||||
deps += _interfaces_deps
|
||||
|
||||
proto_deps = _interfaces_deps
|
||||
deps += _mojolpm_deps
|
||||
|
||||
proto_deps = [ ":renderer_in_process_mojolpm_fuzzer_generator" ]
|
||||
proto_deps += _mojolpm_deps
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,40 @@
|
||||
|
||||
This script must be used with MojoLPMGenerator and a RendererFuzzer. It
|
||||
generates code to handle interface creation requested by MojoLPM by using the
|
||||
interface brokers provided by the internal RendererFuzzer mechanism.
|
||||
`ipc_interfaces_dumper` binary. It then formats a JSON file that
|
||||
MojoLPMGenerator will understand.
|
||||
|
||||
JSON Format:
|
||||
{
|
||||
# Those are the context (frame, document...) bound interfaces.
|
||||
"context_interfaces": [
|
||||
[
|
||||
"//path/to/mojom.mojom",
|
||||
"qualified.interface.name",
|
||||
"{Associated,}Remote",
|
||||
],
|
||||
...
|
||||
],
|
||||
# Those are the process bound interfaces.
|
||||
"process_interfaces": [
|
||||
{
|
||||
"//path/to/mojom.mojom",
|
||||
"qualified.interface.name",
|
||||
"{Associated,}Remote",
|
||||
},
|
||||
...
|
||||
],
|
||||
# Those are the format MojoLPMGenerator undertands.
|
||||
# This groups all interfaces together.
|
||||
"interfaces": [
|
||||
{
|
||||
"gen/path/to/generator/file.mojom-module",
|
||||
"qualified.interface.name",
|
||||
"{Associated,}Remote",
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
|
||||
This script uses the jinja2 and the `testcase.h.tmpl` template to generate C++
|
||||
code. A class named `RendererTestcase` will be created.
|
||||
@ -15,45 +48,270 @@ code. A class named `RendererTestcase` will be created.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import abc
|
||||
import argparse
|
||||
import dataclasses
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import tempfile
|
||||
import typing
|
||||
import enum
|
||||
|
||||
# Copied from //mojo/public/tools/mojom/mojom/fileutil.py.
|
||||
def AddLocalRepoThirdPartyDirToModulePath():
|
||||
"""Helper function to find the top-level directory of this script's repository
|
||||
assuming the script falls somewhere within a 'chrome' directory, and insert
|
||||
the top-level 'third_party' directory early in the module search path. Used to
|
||||
ensure that third-party dependencies provided within the repository itself
|
||||
(e.g. Chromium sources include snapshots of jinja2 and ply) are preferred over
|
||||
locally installed system library packages."""
|
||||
def _GetDirAbove(dirname: str):
|
||||
"""Returns the directory "above" this file containing |dirname| (which must
|
||||
also be "above" this file)."""
|
||||
path = os.path.abspath(__file__)
|
||||
while True:
|
||||
path, tail = os.path.split(path)
|
||||
if not tail:
|
||||
return None
|
||||
if tail == dirname:
|
||||
return path
|
||||
|
||||
toplevel_dir = _GetDirAbove('chrome')
|
||||
if toplevel_dir:
|
||||
sys.path.insert(1, os.path.join(toplevel_dir, 'third_party'))
|
||||
def _GetDirAbove(dirname: str):
|
||||
"""Returns the directory "above" this file containing |dirname| (which must
|
||||
also be "above" this file)."""
|
||||
path = os.path.abspath(__file__)
|
||||
while True:
|
||||
path, tail = os.path.split(path)
|
||||
if not tail:
|
||||
return None
|
||||
if tail == dirname:
|
||||
return path
|
||||
|
||||
# This is needed in order to be able to import jinja2.
|
||||
AddLocalRepoThirdPartyDirToModulePath()
|
||||
|
||||
SOURCE_DIR = _GetDirAbove('chrome')
|
||||
|
||||
sys.path.insert(1, os.path.join(SOURCE_DIR, 'third_party'))
|
||||
sys.path.append(os.path.join(SOURCE_DIR, 'build'))
|
||||
sys.path.append(os.path.join(SOURCE_DIR, 'mojo/public/tools/mojom/'))
|
||||
|
||||
from mojom.parse import parser as mojom_parser, ast
|
||||
import action_helpers
|
||||
import jinja2
|
||||
|
||||
XVFB_PATH = os.path.join(SOURCE_DIR, 'testing/xvfb.py')
|
||||
|
||||
|
||||
def strip_end(text: str, suffix: str) -> str:
|
||||
"""Similar to python 3.9 `removesuffix` function.
|
||||
|
||||
Args:
|
||||
text: input text.
|
||||
suffix: the suffix to remove if present.
|
||||
|
||||
Returns:
|
||||
the input string with suffix removed if present.
|
||||
"""
|
||||
if suffix and text.endswith(suffix):
|
||||
return text[:-len(suffix)]
|
||||
return text
|
||||
|
||||
|
||||
def get_all_interfaces(metadata_file: str) -> typing.List[str]:
|
||||
"""Returns the list of every mojo interfaces in src_dir. Recurses through
|
||||
subdirectories.
|
||||
|
||||
Args:
|
||||
src_dir: the chromium source directory.
|
||||
|
||||
Returns:
|
||||
the list of paths to mojom interfaces.
|
||||
"""
|
||||
res = []
|
||||
with open(metadata_file, 'r', encoding='utf-8') as file:
|
||||
lines = [line.rstrip() for line in file]
|
||||
for line in lines:
|
||||
with open(line, 'r') as metadata:
|
||||
data = json.load(metadata)
|
||||
for mojom_file in data['sources']:
|
||||
if mojom_file.endswith('.mojom'):
|
||||
path = os.path.join(os.path.dirname(line), mojom_file)
|
||||
path = os.path.abspath(path)
|
||||
res.append(path)
|
||||
return res
|
||||
|
||||
|
||||
def is_defined_in_module(qualified_name: str, interface: ast.Mojom) -> bool:
|
||||
namespace = ".".join(qualified_name.split('.')[:-1])
|
||||
name = qualified_name.split('.')[-1]
|
||||
if not interface.module:
|
||||
return False
|
||||
m_namespace = str(interface.module.mojom_namespace)
|
||||
if m_namespace != namespace:
|
||||
return False
|
||||
|
||||
if not interface.definition_list:
|
||||
return False
|
||||
for definition in interface.definition_list:
|
||||
if (isinstance(definition, ast.Interface) and
|
||||
str(definition.mojom_name) == name):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def find_matching_interface(qualified_name: str,
|
||||
modules: typing.List[ast.Mojom]) -> str:
|
||||
"""Finds the correct mojom file for the given interface. The interface name
|
||||
must be qualified.
|
||||
|
||||
Args:
|
||||
qualified_name: the qualified interface name (e.g.
|
||||
'blink.mojom.BlobRegistry').
|
||||
modules: the list of parsed mojom modules.
|
||||
|
||||
Returns:
|
||||
the path to the mojom file corresponding to the input interface.
|
||||
"""
|
||||
for module in modules:
|
||||
if is_defined_in_module(qualified_name, module):
|
||||
return module.module.filename
|
||||
return None
|
||||
|
||||
|
||||
def ensure_interface_deps_complete(interfaces: typing.List[str],
|
||||
modules: typing.List[ast.Mojom],
|
||||
build_dir: str):
|
||||
"""Ensures that all the interfaces can be fetched from the parsed mojom
|
||||
modules.
|
||||
|
||||
Args:
|
||||
interfaces: the list of interfaces (qualified names).
|
||||
modules: the list of mojom modules to search into.
|
||||
|
||||
Raises:
|
||||
Exception: if at least one interface could not be found.
|
||||
"""
|
||||
missing_interfaces = []
|
||||
for interface in interfaces:
|
||||
res = find_matching_interface(interface, modules)
|
||||
if not res:
|
||||
missing_interfaces.append(interface)
|
||||
if len(missing_interfaces) != 0:
|
||||
raise Exception('Missing browser exposed targets for the following '
|
||||
'interfaces:\n'
|
||||
f'{missing_interfaces}\n'
|
||||
'Please add the corresponding targets to '
|
||||
'`//chrome/browser_exposed_mojom_targets.gni`.')
|
||||
|
||||
|
||||
def handle_interfaces(interfaces,
|
||||
mojom_files: typing.List[ast.Mojom],
|
||||
source_path: str,
|
||||
output):
|
||||
"""Finds the mojom files for the given interfaces and append the formatted
|
||||
result to the output list.
|
||||
|
||||
Args:
|
||||
interfaces: the interfaces to handle.
|
||||
mojom_files: the list of parsed mojom files to look into.
|
||||
source_path: the path to chromium's root source directory.
|
||||
output: the output list.
|
||||
"""
|
||||
for interface in interfaces:
|
||||
qualified_name = interface['qualified_name']
|
||||
interface_type = interface['type']
|
||||
path = pathlib.Path(find_matching_interface(qualified_name, mojom_files))
|
||||
path = path.relative_to(source_path)
|
||||
output.append([
|
||||
f"//{path}", qualified_name, interface_type
|
||||
])
|
||||
|
||||
|
||||
def filter_data(data):
|
||||
"""Filters the JSON data. As for now, we filter out:
|
||||
- AssociatedRemote
|
||||
- Duplicate interfaces for context and process interfaces.
|
||||
|
||||
Args:
|
||||
data: the JSON data.
|
||||
"""
|
||||
data_filter = lambda x : x['type'] != 'AssociatedRemote'
|
||||
data['context_interfaces'] = list(filter(data_filter,
|
||||
data['context_interfaces']))
|
||||
data['process_interfaces'] = list(filter(data_filter,
|
||||
data['process_interfaces']))
|
||||
ctx_interfaces = [s['qualified_name'] for s in data['context_interfaces']]
|
||||
data_filter = lambda x: x['qualified_name'] not in ctx_interfaces
|
||||
data['process_interfaces'] = list(filter(data_filter,
|
||||
data['process_interfaces']))
|
||||
|
||||
|
||||
def run_ipc_dumper(dumper_path: str, out_file: str):
|
||||
"""This runs the ipc_dumper executable at `dumper_path` and redirects its
|
||||
output to `out_file` so that this tool can use it to generate the list of
|
||||
interfaces.
|
||||
|
||||
Args:
|
||||
dumper_path: path to the `ipc_interfaces_dumper` executable.
|
||||
out_file: the file to which we'll dump the interfaces.
|
||||
"""
|
||||
env = os.environ.copy()
|
||||
env["IPC_DUMP_PATH"] = out_file
|
||||
# Since we're running these at compile time, we need to make sure this will
|
||||
# run regardless of the building flags being used.
|
||||
# When enabling ASAN, we have a `detect_ord_violation` issue when running
|
||||
# this tool.
|
||||
env["ASAN_OPTIONS"] = 'detect_odr_violation=0'
|
||||
args = [XVFB_PATH, os.path.abspath(dumper_path)]
|
||||
subprocess.run(args, capture_output=True, env=env, check=True)
|
||||
|
||||
|
||||
def generate_interfaces(ipc_interfaces_dumper: str,
|
||||
interfaces_f: str,
|
||||
gen_dir: str,
|
||||
metadata_file: str,
|
||||
depfile: str):
|
||||
"""Generates the appropriate interfaces file given the output of the
|
||||
`ipc_interfaces_dumper`.
|
||||
|
||||
Args:
|
||||
ipc_interfaces_dumper: the path to the `ipc_interfaces_dumper` binary.
|
||||
interfaces_f: the output path to the JSON interfaces file.
|
||||
gen_dir: the path to the root gen directory.
|
||||
metadata_file: the path to the mojo metadata file.
|
||||
depfile: the depfile to write to.
|
||||
"""
|
||||
interfaces = get_all_interfaces(metadata_file)
|
||||
parsed_interfaces = []
|
||||
for interface in interfaces:
|
||||
with open(interface, 'r', encoding="utf-8") as f:
|
||||
parsed_interfaces.append(mojom_parser.Parse(f.read(), interface))
|
||||
output = {"context_interfaces": [], "process_interfaces": []}
|
||||
with tempfile.NamedTemporaryFile() as input_file:
|
||||
run_ipc_dumper(ipc_interfaces_dumper, input_file.name)
|
||||
with open(input_file.name, 'r') as in_f:
|
||||
data = json.load(in_f)
|
||||
filter_data(data)
|
||||
all_interfaces = data['context_interfaces'] + data['process_interfaces']
|
||||
qualified_names = [e['qualified_name'] for e in all_interfaces]
|
||||
ensure_interface_deps_complete(qualified_names,
|
||||
parsed_interfaces,
|
||||
os.path.join(gen_dir, os.pardir))
|
||||
handle_interfaces(data['context_interfaces'],
|
||||
parsed_interfaces,
|
||||
SOURCE_DIR,
|
||||
output['context_interfaces'])
|
||||
handle_interfaces(data['process_interfaces'],
|
||||
parsed_interfaces,
|
||||
SOURCE_DIR,
|
||||
output['process_interfaces'])
|
||||
|
||||
# MojoLPMGenerator expects a particular format for generating MojoLPM
|
||||
# boilerplate. This part will generate the expected format and rebase the
|
||||
# mojom module paths in order for MojoLPMGenerator to be able to find them.
|
||||
output['interfaces'] = []
|
||||
for interface in output['context_interfaces'] + output['process_interfaces']:
|
||||
path = interface[0]
|
||||
path = os.path.join(gen_dir, path.lstrip('/')) + '-module'
|
||||
output['interfaces'].append([
|
||||
path, interface[1], interface[2]
|
||||
])
|
||||
with action_helpers.atomic_output(interfaces_f, mode="w") as f:
|
||||
json.dump(output, f)
|
||||
|
||||
# Now, we want to write the depfile so that ninja knows that we're depending
|
||||
# on the mojom files. If one gets modified, we want to re-run this action.
|
||||
all_interfaces = output['context_interfaces'] + output['process_interfaces']
|
||||
paths = [i[0].lstrip('//') for i in all_interfaces]
|
||||
paths = [pathlib.Path(os.path.join(SOURCE_DIR, p)) for p in paths]
|
||||
action_helpers.write_depfile(depfile,
|
||||
interfaces_f,
|
||||
[os.path.relpath(p) for p in paths])
|
||||
|
||||
|
||||
def split_interface_name(interface: str):
|
||||
"""Helper that splits a qualified mojo interface name into a dictionary
|
||||
containing the key 'name' that contains the name of the interface, and the
|
||||
@ -106,23 +364,50 @@ def camel_to_snake_case(name: str) -> str:
|
||||
# character but only add the '_'.
|
||||
return re.sub(r"(?<!^)(?=[A-Z])", "_", name).lower()
|
||||
|
||||
|
||||
def generate_testcase(interfaces_f: str,
|
||||
fuzzer_dir: str,
|
||||
fuzzer_name: str,
|
||||
testcase_f: str):
|
||||
"""Generates the testcase file given the interface list and the
|
||||
MojoLPMGenerator fuzzer name.
|
||||
|
||||
Args:
|
||||
interfaces_f: the path to the JSON interface file.
|
||||
fuzzer_dir: the path to the fuzzer directory.
|
||||
fuzzer_name: the name of the MojoLPM fuzzer.
|
||||
testcase_f: the output path to the testcase .h file.
|
||||
"""
|
||||
template_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
environment = jinja2.Environment(loader=jinja2.FileSystemLoader(
|
||||
template_dir))
|
||||
template = environment.get_template('testcase.h.tmpl')
|
||||
fuzzer_path = os.path.join(fuzzer_dir, fuzzer_name)
|
||||
fuzzer_name = snake_to_camel_case(fuzzer_name)
|
||||
mojolpm_classname = f"mojolpmgenerator::{fuzzer_name}Testcase"
|
||||
with open(interfaces_f, 'r') as f:
|
||||
data = json.load(f)
|
||||
context = [c[1] for c in data['context_interfaces']]
|
||||
process = [p[1] for p in data['process_interfaces']]
|
||||
context = {
|
||||
"filename": testcase_f,
|
||||
"mojolpm_generator_filepath": f"{fuzzer_path}.h",
|
||||
"mojolpm_generator_classname": mojolpm_classname,
|
||||
"process_interfaces": [split_interface_name(p) for p in process],
|
||||
"context_interfaces": [split_interface_name(c) for c in context],
|
||||
}
|
||||
with action_helpers.atomic_output(testcase_f, mode="w") as f:
|
||||
f.write(template.render(context))
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Generate an IPC fuzzer based on MojoLPM Generator.')
|
||||
parser.add_argument(
|
||||
'-c',
|
||||
'--context',
|
||||
default=[],
|
||||
nargs='+',
|
||||
required=True,
|
||||
help="Context bound interfaces to fuzz.")
|
||||
parser.add_argument(
|
||||
'-p',
|
||||
'--process',
|
||||
default=[],
|
||||
nargs='+',
|
||||
'--path',
|
||||
required=True,
|
||||
help="Process bound interfaces to fuzz.")
|
||||
help="The path to ipc_interfaces_dumper binary.")
|
||||
parser.add_argument(
|
||||
'-d',
|
||||
'--fuzzer_dir',
|
||||
@ -135,28 +420,42 @@ def main():
|
||||
help="""The name of the MojoLPMGenerator fuzzing target.
|
||||
This will used to deduce the name of the generated MojoLPM testcase.""")
|
||||
parser.add_argument(
|
||||
'-o',
|
||||
'--output',
|
||||
'-t',
|
||||
'--testcase-output-path',
|
||||
required=True,
|
||||
help="Output file name.")
|
||||
help="The path where the testcase file will be written to.")
|
||||
parser.add_argument(
|
||||
'-i',
|
||||
'--interface-output-path',
|
||||
required=True,
|
||||
help="The path where the interface file will be written to.")
|
||||
parser.add_argument(
|
||||
'-r',
|
||||
'--root-gen-dir',
|
||||
required=True,
|
||||
help="The path to the root gen dir.")
|
||||
parser.add_argument(
|
||||
'-m',
|
||||
'--metadata-file',
|
||||
required=True,
|
||||
help="Path to the metadata file.")
|
||||
parser.add_argument(
|
||||
'-f',
|
||||
'--depfile',
|
||||
required=True,
|
||||
help="The path to the depfile.")
|
||||
|
||||
args = parser.parse_args()
|
||||
template_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
environment = jinja2.Environment(loader=jinja2.FileSystemLoader(
|
||||
template_dir))
|
||||
template = environment.get_template('testcase.h.tmpl')
|
||||
fuzzer_path = os.path.join(args.fuzzer_dir, args.name)
|
||||
fuzzer_name = snake_to_camel_case(args.name)
|
||||
mojolpm_classname = f"mojolpmgenerator::{fuzzer_name}Testcase"
|
||||
context = {
|
||||
"filename": args.output,
|
||||
"mojolpm_generator_filepath": f"{fuzzer_path}.h",
|
||||
"mojolpm_generator_classname": mojolpm_classname,
|
||||
"process_interfaces": [split_interface_name(p) for p in args.process],
|
||||
"context_interfaces": [split_interface_name(c) for c in args.context],
|
||||
}
|
||||
with pathlib.Path(args.output).open(mode="w") as f:
|
||||
f.write(template.render(context))
|
||||
generate_interfaces(args.path,
|
||||
args.interface_output_path,
|
||||
args.root_gen_dir,
|
||||
args.metadata_file,
|
||||
args.depfile)
|
||||
generate_testcase(args.interface_output_path,
|
||||
args.fuzzer_dir,
|
||||
args.name,
|
||||
args.testcase_output_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@ -14,12 +14,14 @@
|
||||
#include "base/strings/escape.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/test/bind.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/values.h"
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
#include "chrome/test/base/in_process_browser_test.h"
|
||||
#include "chrome/test/base/ui_test_utils.h"
|
||||
#include "chrome/test/fuzzing/in_process_fuzzer.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/test/browser_test.h"
|
||||
|
||||
// Format for the outputted JSON:
|
||||
// {
|
||||
@ -41,19 +43,6 @@
|
||||
// ]
|
||||
// }
|
||||
|
||||
class IPCInterfaceDumper : public InProcessFuzzer {
|
||||
public:
|
||||
IPCInterfaceDumper() = default;
|
||||
void RunTestOnMainThread() override;
|
||||
|
||||
int Fuzz(const uint8_t* data, size_t size) override { return 0; }
|
||||
};
|
||||
|
||||
// We register this tool as an in_process_fuzzer so that it has the exact same
|
||||
// setup as an in_process_fuzzer. Indeed, this is important because this can
|
||||
// have an effect on which interfaces are being exposed.
|
||||
REGISTER_IN_PROCESS_FUZZER(IPCInterfaceDumper)
|
||||
|
||||
namespace {
|
||||
|
||||
void RegisterInterfaces(const std::vector<std::string>& interfaces,
|
||||
@ -72,7 +61,12 @@ void RegisterInterfaces(const std::vector<std::string>& interfaces,
|
||||
|
||||
} // namespace
|
||||
|
||||
void IPCInterfaceDumper::RunTestOnMainThread() {
|
||||
class IPCInterfacesDumper : public InProcessBrowserTest {
|
||||
public:
|
||||
IPCInterfacesDumper() = default;
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(IPCInterfacesDumper, DumperTest) {
|
||||
auto env = base::Environment::Create();
|
||||
if (!env->HasVar("IPC_DUMP_PATH")) {
|
||||
LOG(ERROR) << "IPC_DUMP_PATH not set. Nothing will be done.";
|
||||
@ -107,6 +101,8 @@ void IPCInterfaceDumper::RunTestOnMainThread() {
|
||||
// Write the JSON to a file in the IPC_DUMP_PATH directory.
|
||||
std::string file_path;
|
||||
env->GetVar("IPC_DUMP_PATH", &file_path);
|
||||
|
||||
base::ScopedAllowBlockingForTesting allow_blocking;
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
base::FilePath filepath = base::FilePath(base::UTF8ToWide(file_path));
|
||||
#else
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -196,6 +196,17 @@ template("mojolpm_fuzzer_test") {
|
||||
# lists.
|
||||
# The remote type must be either "Remote" or "AssociatedRemote".
|
||||
#
|
||||
# interface_file
|
||||
# JSON file containing the list of interfaces to generate.
|
||||
# Format:
|
||||
# {
|
||||
# "interfaces": {
|
||||
# ["InterfaceName", "//path/to/interface.mojom", "Remote"],
|
||||
# ["AnotherInterface", "//path/to/another.mojom", "AssociatedRemote" ],
|
||||
# ...
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# deps
|
||||
# List of dependencies to compile this target.
|
||||
#
|
||||
@ -236,19 +247,22 @@ template("mojolpm_fuzzer_test") {
|
||||
template("mojolpm_generated_fuzzer") {
|
||||
assert(defined(invoker.sources),
|
||||
"\"sources\" must be defined for $target_name")
|
||||
assert(defined(invoker.interfaces),
|
||||
"\"interfaces\" must be defined for $target_name")
|
||||
assert(
|
||||
defined(invoker.interfaces) || defined(invoker.interface_file),
|
||||
"\"interfaces\" or \"interface_file\" must be defined for $target_name")
|
||||
|
||||
if (enable_mojom_fuzzer) {
|
||||
_target_name = target_name
|
||||
_generate_target_name = _target_name + "_mojolpm_generator_generate"
|
||||
|
||||
# Generates the correct argument format give invoker.interfaces.
|
||||
_script_inputs = []
|
||||
foreach(elt, invoker.interfaces) {
|
||||
_script_inputs +=
|
||||
[ rebase_path("$root_gen_dir/" + elt[0] + "-module", root_build_dir) +
|
||||
":" + elt[1] + ":" + elt[2] ]
|
||||
if (defined(invoker.interfaces)) {
|
||||
# Generates the correct argument format give invoker.interfaces.
|
||||
_script_inputs = []
|
||||
foreach(elt, invoker.interfaces) {
|
||||
_script_inputs +=
|
||||
[ rebase_path("$root_gen_dir/" + elt[0] + "-module",
|
||||
root_build_dir) + ":" + elt[1] + ":" + elt[2] ]
|
||||
}
|
||||
}
|
||||
|
||||
action(_generate_target_name) {
|
||||
@ -261,8 +275,16 @@ template("mojolpm_generated_fuzzer") {
|
||||
deps += invoker.proto_deps
|
||||
}
|
||||
|
||||
args = [ "--input" ]
|
||||
args += _script_inputs
|
||||
args = []
|
||||
if (defined(invoker.interfaces)) {
|
||||
args += [ "--input" ]
|
||||
args += _script_inputs
|
||||
} else if (defined(invoker.interface_file)) {
|
||||
args += [
|
||||
"-f",
|
||||
rebase_path(invoker.interface_file, root_build_dir),
|
||||
]
|
||||
}
|
||||
args += [
|
||||
"--output_file_format",
|
||||
rebase_path("${target_gen_dir}/${_target_name}", root_build_dir),
|
||||
|
@ -45,6 +45,7 @@ from __future__ import annotations
|
||||
import abc
|
||||
import argparse
|
||||
import dataclasses
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
@ -62,6 +63,7 @@ from mojom import fileutil
|
||||
from mojom.generate import module
|
||||
|
||||
fileutil.AddLocalRepoThirdPartyDirToModulePath()
|
||||
CHROME_SRC_DIR = fileutil._GetDirAbove('mojo')
|
||||
|
||||
import jinja2
|
||||
|
||||
@ -654,17 +656,48 @@ def build(interface: module.Interface,
|
||||
return actions
|
||||
|
||||
|
||||
def get_interface_list_from_file(
|
||||
file_path: str) -> typing.List[typing.List[str]]:
|
||||
"""Reads the JSON input file and returns the interfaces list that it
|
||||
contains.
|
||||
|
||||
Args:
|
||||
file_path: the path to the input file.
|
||||
|
||||
Returns:
|
||||
the list of interfaces.
|
||||
"""
|
||||
with open(file_path, 'r') as f:
|
||||
data = json.load(f)
|
||||
return data['interfaces']
|
||||
|
||||
|
||||
def get_interface_list_from_input(
|
||||
interfaces: typing.List[str]) -> typing.List[typing.List[str]]:
|
||||
"""Parses the input list of interfaces and returns a list of list that
|
||||
matches the expected format.
|
||||
|
||||
Args:
|
||||
interfaces: the list of strings listing the interfaces.
|
||||
|
||||
Returns:
|
||||
the list of interfaces.
|
||||
"""
|
||||
return [interface.split(':') for interface in interfaces]
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Generate MojoLPM proto and cpp/h files.')
|
||||
parser.add_argument(
|
||||
group = parser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument(
|
||||
'-i',
|
||||
'--input',
|
||||
default=[],
|
||||
nargs='+',
|
||||
required=True,
|
||||
help="input(s) with format: "
|
||||
"path/to/interface.mojom-module:InterfaceName:{Remote|AssociatedRemote}")
|
||||
group.add_argument('-f', '--file', help="")
|
||||
parser.add_argument('--output_file_format',
|
||||
required=True,
|
||||
help="output file format. Files with extensions '.h' and"
|
||||
@ -677,11 +710,11 @@ def main():
|
||||
[MojoLPMProtoGenerator(output_file),
|
||||
MojoLPMCppGenerator(output_file)])
|
||||
actions = MojoLPMActionSet()
|
||||
for file_interface in args.input:
|
||||
custom_format = file_interface.split(':')
|
||||
if len(custom_format) != 3:
|
||||
print(f"Wrong format: {file_interface}. See help for usage.")
|
||||
return
|
||||
if args.file:
|
||||
interfaces = get_interface_list_from_file(args.file)
|
||||
else:
|
||||
interfaces = get_interface_list_from_input(args.input)
|
||||
for custom_format in interfaces:
|
||||
(file, interface_name, remote_type_str) = custom_format
|
||||
if remote_type_str == 'Remote':
|
||||
remote_type = MojoLPMActionType.REMOTE_ACTION
|
||||
|
Reference in New Issue
Block a user