sepolicy : Recommend fuzzers for new services
Adding soong module and tool to check if there is fuzzer present
for every service in private/service_contexts. Whenever a service is
added, its is recommended to update
$ANDROID_BUILD_TOP/system/sepolicy/soong/build/service_fuzzer_bindings.go
with service name and its corresponding fuzzer.
Test: m
Bug: 242104782
Change-Id: Id9bc45f50bebf464de7c91c7469d4bb6ff153ebd
diff --git a/Android.mk b/Android.mk
index c3728fd..8f0b37c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -324,6 +324,7 @@
plat_service_contexts_test \
plat_hwservice_contexts \
plat_hwservice_contexts_test \
+ fuzzer_bindings_test \
plat_bug_map \
searchpolicy \
diff --git a/build/soong/Android.bp b/build/soong/Android.bp
index 99dd662..83b31b4 100644
--- a/build/soong/Android.bp
+++ b/build/soong/Android.bp
@@ -43,6 +43,8 @@
"sepolicy_neverallow.go",
"sepolicy_vers.go",
"versioned_policy.go",
+ "service_fuzzer_bindings.go",
+ "validate_bindings.go",
],
pluginFor: ["soong_build"],
}
diff --git a/build/soong/service_fuzzer_bindings.go b/build/soong/service_fuzzer_bindings.go
new file mode 100644
index 0000000..7a7f61f
--- /dev/null
+++ b/build/soong/service_fuzzer_bindings.go
@@ -0,0 +1,406 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package selinux
+
+var (
+ ServiceFuzzerBindings = map[string][]string{
+ "android.hardware.audio.core.IConfig/default": []string{},
+ "android.hardware.audio.core.IModule/default": []string{},
+ "android.hardware.audio.effect.IFactory/default": []string{},
+ "android.hardware.authsecret.IAuthSecret/default": []string{},
+ "android.hardware.automotive.evs.IEvsEnumerator/hw/0": []string{},
+ "android.hardware.boot.IBootControl/default": []string{},
+ "android.hardware.automotive.evs.IEvsEnumerator/hw/1": []string{},
+ "android.hardware.automotive.vehicle.IVehicle/default": []string{},
+ "android.hardware.automotive.audiocontrol.IAudioControl/default": []string{},
+ "android.hardware.biometrics.face.IFace/default": []string{},
+ "android.hardware.biometrics.fingerprint.IFingerprint/default": []string{},
+ "android.hardware.biometrics.fingerprint.IFingerprint/virtual": []string{},
+ "android.hardware.bluetooth.audio.IBluetoothAudioProviderFactory/default": []string{},
+ "android.hardware.camera.provider.ICameraProvider/internal/0": []string{},
+ "android.hardware.contexthub.IContextHub/default": []string{},
+ "android.hardware.drm.IDrmFactory/clearkey": []string{},
+ "android.hardware.drm.ICryptoFactory/clearkey": []string{},
+ "android.hardware.dumpstate.IDumpstateDevice/default": []string{},
+ "android.hardware.gnss.IGnss/default": []string{},
+ "android.hardware.graphics.allocator.IAllocator/default": []string{},
+ "android.hardware.graphics.composer3.IComposer/default": []string{},
+ "android.hardware.health.storage.IStorage/default": []string{},
+ "android.hardware.health.IHealth/default": []string{},
+ "android.hardware.identity.IIdentityCredentialStore/default": []string{},
+ "android.hardware.input.processor.IInputProcessor/default": []string{},
+ "android.hardware.ir.IConsumerIr/default": []string{},
+ "android.hardware.light.ILights/default": []string{},
+ "android.hardware.memtrack.IMemtrack/default": []string{},
+ "android.hardware.net.nlinterceptor.IInterceptor/default": []string{},
+ "android.hardware.nfc.INfc/default": []string{},
+ "android.hardware.oemlock.IOemLock/default": []string{},
+ "android.hardware.power.IPower/default": []string{},
+ "android.hardware.power.stats.IPowerStats/default": []string{},
+ "android.hardware.radio.config.IRadioConfig/default": []string{},
+ "android.hardware.radio.data.IRadioData/slot1": []string{},
+ "android.hardware.radio.data.IRadioData/slot2": []string{},
+ "android.hardware.radio.data.IRadioData/slot3": []string{},
+ "android.hardware.radio.messaging.IRadioMessaging/slot1": []string{},
+ "android.hardware.radio.messaging.IRadioMessaging/slot2": []string{},
+ "android.hardware.radio.messaging.IRadioMessaging/slot3": []string{},
+ "android.hardware.radio.modem.IRadioModem/slot1": []string{},
+ "android.hardware.radio.modem.IRadioModem/slot2": []string{},
+ "android.hardware.radio.modem.IRadioModem/slot3": []string{},
+ "android.hardware.radio.network.IRadioNetwork/slot1": []string{},
+ "android.hardware.radio.network.IRadioNetwork/slot2": []string{},
+ "android.hardware.radio.network.IRadioNetwork/slot3": []string{},
+ "android.hardware.radio.sim.IRadioSim/slot1": []string{},
+ "android.hardware.radio.sim.IRadioSim/slot2": []string{},
+ "android.hardware.radio.sim.IRadioSim/slot3": []string{},
+ "android.hardware.radio.voice.IRadioVoice/slot1": []string{},
+ "android.hardware.radio.voice.IRadioVoice/slot2": []string{},
+ "android.hardware.radio.voice.IRadioVoice/slot3": []string{},
+ "android.hardware.rebootescrow.IRebootEscrow/default": []string{},
+ "android.hardware.security.dice.IDiceDevice/default": []string{},
+ "android.hardware.security.keymint.IKeyMintDevice/default": []string{},
+ "android.hardware.security.keymint.IRemotelyProvisionedComponent/default": []string{},
+ "android.hardware.security.secureclock.ISecureClock/default": []string{},
+ "android.hardware.security.sharedsecret.ISharedSecret/default": []string{},
+ "android.hardware.sensors.ISensors/default": []string{},
+ "android.hardware.soundtrigger3.ISoundTriggerHw/default": []string{},
+ "android.hardware.tv.input.ITvInput/default": []string{},
+ "android.hardware.tv.tuner.ITuner/default": []string{},
+ "android.hardware.usb.IUsb/default": []string{},
+ "android.hardware.uwb.IUwb/default": []string{},
+ "android.hardware.vibrator.IVibrator/default": []string{},
+ "android.hardware.vibrator.IVibratorManager/default": []string{},
+ "android.hardware.weaver.IWeaver/default": []string{},
+ "android.hardware.wifi.hostapd.IHostapd/default": []string{},
+ "android.hardware.wifi.supplicant.ISupplicant/default": []string{},
+ "android.frameworks.stats.IStats/default": []string{},
+ "android.se.omapi.ISecureElementService/default": []string{},
+ "android.system.keystore2.IKeystoreService/default": []string{},
+ "android.system.net.netd.INetd/default": []string{},
+ "android.system.suspend.ISystemSuspend/default": []string{},
+ "accessibility": []string{},
+ "account": []string{},
+ "activity": []string{},
+ "activity_task": []string{},
+ "adb": []string{},
+ "adservices_manager": []string{},
+ "aidl_lazy_test_1": []string{},
+ "aidl_lazy_test_2": []string{},
+ "aidl_lazy_cb_test": []string{},
+ "alarm": []string{},
+ "android.hardware.automotive.evs.IEvsEnumerator/default": []string{},
+ "android.os.UpdateEngineService": []string{},
+ "android.os.UpdateEngineStableService": []string{},
+ "android.frameworks.automotive.display.ICarDisplayProxy/default": []string{},
+ "android.security.apc": []string{},
+ "android.security.authorization": []string{},
+ "android.security.compat": []string{},
+ "android.security.dice.IDiceMaintenance": []string{},
+ "android.security.dice.IDiceNode": []string{},
+ "android.security.identity": []string{},
+ "android.security.keystore": []string{},
+ "android.security.legacykeystore": []string{},
+ "android.security.maintenance": []string{},
+ "android.security.metrics": []string{},
+ "android.security.remoteprovisioning": []string{},
+ "android.security.remoteprovisioning.IRemotelyProvisionedKeyPool": []string{},
+ "android.service.gatekeeper.IGateKeeperService": []string{},
+ "android.system.composd": []string{},
+ "android.system.virtualizationservice": []string{},
+ "ambient_context": []string{},
+ "app_binding": []string{},
+ "app_hibernation": []string{},
+ "app_integrity": []string{},
+ "app_prediction": []string{},
+ "app_search": []string{},
+ "apexservice": []string{},
+ "attestation_verification": []string{},
+ "blob_store": []string{},
+ "gsiservice": []string{},
+ "appops": []string{},
+ "appwidget": []string{},
+ "artd": []string{},
+ "assetatlas": []string{},
+ "attention": []string{},
+ "audio": []string{},
+ "auth": []string{},
+ "autofill": []string{},
+ "backup": []string{},
+ "batteryproperties": []string{},
+ "batterystats": []string{},
+ "battery": []string{},
+ "binder_calls_stats": []string{},
+ "biometric": []string{},
+ "bluetooth_manager": []string{},
+ "bluetooth": []string{},
+ "broadcastradio": []string{},
+ "bugreport": []string{},
+ "cacheinfo": []string{},
+ "carrier_config": []string{},
+ "clipboard": []string{},
+ "cloudsearch": []string{},
+ "cloudsearch_service": []string{},
+ "com.android.net.IProxyService": []string{},
+ "companiondevice": []string{},
+ "communal": []string{},
+ "platform_compat": []string{},
+ "platform_compat_native": []string{},
+ "connectivity": []string{},
+ "connectivity_native": []string{},
+ "connmetrics": []string{},
+ "consumer_ir": []string{},
+ "content": []string{},
+ "content_capture": []string{},
+ "content_suggestions": []string{},
+ "contexthub": []string{},
+ "country_detector": []string{},
+ "coverage": []string{},
+ "cpuinfo": []string{},
+ "crossprofileapps": []string{},
+ "dataloader_manager": []string{},
+ "dbinfo": []string{},
+ "device_config": []string{},
+ "device_policy": []string{},
+ "device_identifiers": []string{},
+ "deviceidle": []string{},
+ "device_state": []string{},
+ "devicestoragemonitor": []string{},
+ "diskstats": []string{},
+ "display": []string{},
+ "dnsresolver": []string{},
+ "domain_verification": []string{},
+ "color_display": []string{},
+ "netd_listener": []string{},
+ "network_watchlist": []string{},
+ "DockObserver": []string{},
+ "dreams": []string{},
+ "drm.drmManager": []string{},
+ "dropbox": []string{},
+ "dumpstate": []string{},
+ "dynamic_system": []string{},
+ "econtroller": []string{},
+ "emergency_affordance": []string{},
+ "euicc_card_controller": []string{},
+ "external_vibrator_service": []string{},
+ "ethernet": []string{},
+ "face": []string{},
+ "file_integrity": []string{},
+ "fingerprint": []string{},
+ "font": []string{},
+ "android.hardware.fingerprint.IFingerprintDaemon": []string{},
+ "game": []string{},
+ "gfxinfo": []string{},
+ "gnss_time_update_service": []string{},
+ "graphicsstats": []string{},
+ "gpu": []string{},
+ "hardware": []string{},
+ "hardware_properties": []string{},
+ "hdmi_control": []string{},
+ "ions": []string{},
+ "idmap": []string{},
+ "incident": []string{},
+ "incidentcompanion": []string{},
+ "inputflinger": []string{},
+ "input_method": []string{},
+ "input": []string{},
+ "installd": []string{},
+ "iphonesubinfo_msim": []string{},
+ "iphonesubinfo2": []string{},
+ "iphonesubinfo": []string{},
+ "ims": []string{},
+ "imms": []string{},
+ "incremental": []string{},
+ "ipsec": []string{},
+ "ircsmessage": []string{},
+ "iris": []string{},
+ "isms_msim": []string{},
+ "isms2": []string{},
+ "isms": []string{},
+ "isub": []string{},
+ "jobscheduler": []string{},
+ "launcherapps": []string{},
+ "legacy_permission": []string{},
+ "lights": []string{},
+ "locale": []string{},
+ "location": []string{},
+ "location_time_zone_manager": []string{},
+ "lock_settings": []string{},
+ "logcat": []string{},
+ "logd": []string{},
+ "looper_stats": []string{},
+ "lpdump_service": []string{},
+ "mdns": []string{},
+ "media.aaudio": []string{},
+ "media.audio_flinger": []string{},
+ "media.audio_policy": []string{},
+ "media.camera": []string{},
+ "media.camera.proxy": []string{},
+ "media.log": []string{},
+ "media.player": []string{},
+ "media.metrics": []string{},
+ "media.extractor": []string{},
+ "media.transcoding": []string{},
+ "media.resource_manager": []string{},
+ "media.resource_observer": []string{},
+ "media.sound_trigger_hw": []string{},
+ "media.drm": []string{},
+ "media.tuner": []string{},
+ "media_communication": []string{},
+ "media_metrics": []string{},
+ "media_projection": []string{},
+ "media_resource_monitor": []string{},
+ "media_router": []string{},
+ "media_session": []string{},
+ "meminfo": []string{},
+ "memtrack.proxy": []string{},
+ "midi": []string{},
+ "mount": []string{},
+ "music_recognition": []string{},
+ "nearby": []string{},
+ "netd": []string{},
+ "netpolicy": []string{},
+ "netstats": []string{},
+ "network_stack": []string{},
+ "network_management": []string{},
+ "network_score": []string{},
+ "network_time_update_service": []string{},
+ "nfc": []string{},
+ "notification": []string{},
+ "oem_lock": []string{},
+ "otadexopt": []string{},
+ "overlay": []string{},
+ "pac_proxy": []string{},
+ "package": []string{},
+ "package_native": []string{},
+ "people": []string{},
+ "performance_hint": []string{},
+ "permission": []string{},
+ "permissionmgr": []string{},
+ "permission_checker": []string{},
+ "persistent_data_block": []string{},
+ "phone_msim": []string{},
+ "phone1": []string{},
+ "phone2": []string{},
+ "phone": []string{},
+ "pinner": []string{},
+ "powerstats": []string{},
+ "power": []string{},
+ "print": []string{},
+ "processinfo": []string{},
+ "procstats": []string{},
+ "profcollectd": []string{},
+ "radio.phonesubinfo": []string{},
+ "radio.phone": []string{},
+ "radio.sms": []string{},
+ "rcs": []string{},
+ "reboot_readiness": []string{},
+ "recovery": []string{},
+ "resolver": []string{},
+ "resources": []string{},
+ "restrictions": []string{},
+ "role": []string{},
+ "rollback": []string{},
+ "rttmanager": []string{},
+ "runtime": []string{},
+ "safety_center": []string{},
+ "samplingprofiler": []string{},
+ "scheduling_policy": []string{},
+ "search": []string{},
+ "search_ui": []string{},
+ "secure_element": []string{},
+ "sec_key_att_app_id_provider": []string{},
+ "selection_toolbar": []string{},
+ "sensorservice": []string{},
+ "sensor_privacy": []string{},
+ "serial": []string{},
+ "servicediscovery": []string{},
+ "manager": []string{},
+ "settings": []string{},
+ "shortcut": []string{},
+ "simphonebook_msim": []string{},
+ "simphonebook2": []string{},
+ "simphonebook": []string{},
+ "sip": []string{},
+ "slice": []string{},
+ "smartspace": []string{},
+ "speech_recognition": []string{},
+ "stats": []string{},
+ "statsbootstrap": []string{},
+ "statscompanion": []string{},
+ "statsmanager": []string{},
+ "soundtrigger": []string{},
+ "soundtrigger_middleware": []string{},
+ "statusbar": []string{},
+ "storaged": []string{},
+ "storaged_pri": []string{},
+ "storagestats": []string{},
+ "sdk_sandbox": []string{},
+ "SurfaceFlinger": []string{},
+ "SurfaceFlingerAIDL": []string{},
+ "suspend_control": []string{},
+ "suspend_control_internal": []string{},
+ "system_config": []string{},
+ "system_server_dumper": []string{},
+ "system_update": []string{},
+ "tare": []string{},
+ "task": []string{},
+ "telecom": []string{},
+ "telephony.registry": []string{},
+ "telephony_ims": []string{},
+ "testharness": []string{},
+ "tethering": []string{},
+ "textclassification": []string{},
+ "textservices": []string{},
+ "texttospeech": []string{},
+ "time_detector": []string{},
+ "time_zone_detector": []string{},
+ "thermalservice": []string{},
+ "tracing.proxy": []string{},
+ "translation": []string{},
+ "transparency": []string{},
+ "trust": []string{},
+ "tv_interactive_app": []string{},
+ "tv_input": []string{},
+ "tv_tuner_resource_mgr": []string{},
+ "uce": []string{},
+ "uimode": []string{},
+ "updatelock": []string{},
+ "uri_grants": []string{},
+ "usagestats": []string{},
+ "usb": []string{},
+ "user": []string{},
+ "uwb": []string{},
+ "vcn_management": []string{},
+ "vibrator": []string{},
+ "vibrator_manager": []string{},
+ "virtualdevice": []string{},
+ "virtual_touchpad": []string{},
+ "voiceinteraction": []string{},
+ "vold": []string{},
+ "vpn_management": []string{},
+ "vrmanager": []string{},
+ "wallpaper": []string{},
+ "wallpaper_effects_generation": []string{},
+ "webviewupdate": []string{},
+ "wifip2p": []string{},
+ "wifiscanner": []string{},
+ "wifi": []string{},
+ "wifinl80211": []string{},
+ "wifiaware": []string{},
+ "wifirtt": []string{},
+ "window": []string{},
+ "*": []string{},
+ }
+)
diff --git a/build/soong/validate_bindings.go b/build/soong/validate_bindings.go
new file mode 100644
index 0000000..3132453
--- /dev/null
+++ b/build/soong/validate_bindings.go
@@ -0,0 +1,109 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package selinux
+
+import (
+ "encoding/json"
+ "fmt"
+
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterModuleType("fuzzer_bindings_test", fuzzerBindingsTestFactory)
+ android.PreArchMutators(registerFuzzerMutators)
+}
+
+func registerFuzzerMutators(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("addFuzzerConfigDeps", addFuzzerConfigDeps).Parallel()
+}
+
+func addFuzzerConfigDeps(ctx android.BottomUpMutatorContext) {
+ if _, ok := ctx.Module().(*fuzzerBindingsTestModule); ok {
+ for _, fuzzers := range ServiceFuzzerBindings {
+ for _, fuzzer := range fuzzers {
+ if !ctx.OtherModuleExists(fuzzer) {
+ panic(fmt.Errorf("Fuzzer doesn't exist : %s", fuzzer))
+ }
+ }
+ }
+ }
+}
+
+type bindingsTestProperties struct {
+ // Contexts files to be tested.
+ Srcs []string `android:"path"`
+}
+
+type fuzzerBindingsTestModule struct {
+ android.ModuleBase
+ tool string
+ properties bindingsTestProperties
+ testTimestamp android.ModuleOutPath
+}
+
+// fuzzer_bindings_test checks if a fuzzer is implemented for every service in service_contexts
+func fuzzerBindingsTestFactory() android.Module {
+ m := &fuzzerBindingsTestModule{tool: "fuzzer_bindings_check"}
+ m.AddProperties(&m.properties)
+ android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
+ return m
+}
+
+func (m *fuzzerBindingsTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ tool := m.tool
+ if tool != "fuzzer_bindings_check" {
+ panic(fmt.Errorf("%q: unknown tool name: %q", ctx.ModuleName(), tool))
+ }
+
+ if len(m.properties.Srcs) == 0 {
+ ctx.PropertyErrorf("srcs", "can't be empty")
+ return
+ }
+
+ // Generate a json file which contains existing bindings
+ rootPath := android.PathForIntermediates(ctx, "bindings.json")
+ jsonString, parseError := json.Marshal(ServiceFuzzerBindings)
+ if parseError != nil {
+ panic(fmt.Errorf("Error while marshalling ServiceFuzzerBindings dict. Check Format"))
+ }
+ android.WriteFileRule(ctx, rootPath, string(jsonString))
+
+ //input module json, service context and binding files here
+ srcs := android.PathsForModuleSrc(ctx, m.properties.Srcs)
+ rule := android.NewRuleBuilder(pctx, ctx)
+
+ rule.Command().BuiltTool(tool).Flag("-s").Inputs(srcs).Flag("-b").Input(rootPath)
+
+ // Every Soong module needs to generate an output even if it doesn't require it
+ m.testTimestamp = android.PathForModuleOut(ctx, "timestamp")
+ rule.Command().Text("touch").Output(m.testTimestamp)
+ rule.Build("fuzzer_bindings_test", "running service:fuzzer bindings test: "+ctx.ModuleName())
+}
+
+func (m *fuzzerBindingsTestModule) AndroidMkEntries() []android.AndroidMkEntries {
+ return []android.AndroidMkEntries{android.AndroidMkEntries{
+ Class: "FAKE",
+ // OutputFile is needed, even though BUILD_PHONY_PACKAGE doesn't use it.
+ // Without OutputFile this module won't be exported to Makefile.
+ OutputFile: android.OptionalPathForPath(m.testTimestamp),
+ Include: "$(BUILD_PHONY_PACKAGE)",
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", m.testTimestamp.String())
+ },
+ },
+ }}
+}
diff --git a/contexts/Android.bp b/contexts/Android.bp
index 04a0c11..82f42ba 100644
--- a/contexts/Android.bp
+++ b/contexts/Android.bp
@@ -520,3 +520,8 @@
srcs: [":vndservice_contexts"],
sepolicy: ":precompiled_sepolicy",
}
+
+fuzzer_bindings_test {
+ name: "fuzzer_bindings_test",
+ srcs: [":plat_service_contexts"],
+}
diff --git a/tools/Android.bp b/tools/Android.bp
index 8e40575..057b073 100644
--- a/tools/Android.bp
+++ b/tools/Android.bp
@@ -77,3 +77,8 @@
libs: ["mini_cil_parser", "pysepolwrap"],
data: [":libsepolwrap"],
}
+
+python_binary_host {
+ name: "fuzzer_bindings_check",
+ srcs: ["fuzzer_bindings_check.py"],
+}
diff --git a/tools/README b/tools/README
index 5e340a0..8976c68 100644
--- a/tools/README
+++ b/tools/README
@@ -70,3 +70,15 @@
sepolicy-analyze
A tool for performing various kinds of analysis on a sepolicy
file.
+
+fuzzer_bindings_check
+ Tool to check if fuzzer is added for new services. it is used by fuzzer_bindings_test soong module internally.
+ Error will be generated if there is no fuzzer binding present for service added in service_contexts in
+ system/sepolicy/soong/build/service_fuzzer_bindings.go
+
+ Usage:
+ fuzzer_bindings_check.py -s [SRCs...] -b /path/to/binding.json
+
+ -s [SRCs...] list of service_contexts files. Tool will check if there is fuzzer for every service
+ in the context file.
+ -b /path/to/binding.json Path to json file containing "service":[fuzzers...] bindings.
diff --git a/tools/fuzzer_bindings_check.py b/tools/fuzzer_bindings_check.py
new file mode 100644
index 0000000..d2cc3ae
--- /dev/null
+++ b/tools/fuzzer_bindings_check.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging
+import json
+import sys
+import os
+import argparse
+
+def check_file_exists(file_name):
+ if not os.path.exists(file_name):
+ sys.exit("File doesn't exist : {0}".format(file_name))
+
+def read_bindings(binding_file):
+ check_file_exists(binding_file)
+ with open(binding_file) as jsonFile:
+ bindings = json.loads(jsonFile.read())
+ return bindings
+
+def check_fuzzer_exists(context_file, bindings):
+ with open(context_file) as file:
+ for line in file:
+ # Ignore empty lines and comments
+ line = line.strip()
+ if line.startswith("#"):
+ logging.debug("Found a comment..skipping")
+ continue
+
+ tokens = line.split()
+ if len(tokens) == 0:
+ logging.debug("Skipping empty lines in service_contexts")
+ continue
+
+ # For a valid service_context file, there will be only two tokens
+ # First will be service name and second will be its label.
+ service_name = tokens[0]
+ if service_name not in bindings:
+ sys.exit("\nerror: Service {0} is being added, but we have no fuzzer on file for it. "
+ "Fuzzers are listed at $ANDROID_BUILD_TOP/system/sepolicy/build/soong/service_fuzzer_bindings.go \n\n"
+ "NOTE: automatic service fuzzers are currently not supported in Java (b/232439254) "
+ "and Rust (b/164122727). In this case, please ignore this for now. \n\n"
+ "If you are writing a new service, it may be subject to attack from other "
+ "potentially malicious processes. A fuzzer can be written automatically "
+ "by adding these things: \n"
+ "- a cc_fuzz Android.bp entry \n"
+ "- a main file that constructs your service and calls 'fuzzService' \n\n"
+ "An example can be found here: \n "
+ "$ANDROID_BUILD_TOP/hardware/interfaces/vibrator/aidl/default/fuzzer.cpp \n\n"
+ "This is only ~30 lines of configuration. It requires dependency injection "
+ "for your service which is a good practice, and (in AOSP) you will get bugs "
+ "automatically filed on you. You will find out about issues without needing "
+ "to backport changes years later, and the system will automatically find ways "
+ "to reproduce difficult to solve issues for you. \n\n"
+ "- Android Fuzzing and Security teams".format(service_name))
+ return
+
+def validate_bindings(args):
+ bindings = read_bindings(args.bindings)
+ for file in args.srcs:
+ check_file_exists(file)
+ check_fuzzer_exists(file, bindings)
+ return
+
+def get_args():
+ parser = argparse.ArgumentParser(description="Tool to check if fuzzer is "
+ "added for new services")
+ parser.add_argument('-b', help='Path to json file containing '
+ '"service":[fuzzers...] bindings.',
+ required=True, dest='bindings')
+ parser.add_argument('-s', '--list', nargs='+',
+ help='list of service_contexts files. Tool will check if '
+ 'there is fuzzer for every service in the context '
+ 'file.', required=True, dest='srcs')
+ parsed_args = parser.parse_args()
+ return parsed_args
+
+if __name__ == "__main__":
+ args = get_args()
+ validate_bindings(args)