Add initial batch of inputFlinger fuzzers
This batch of fuzzers is focused on the input Mappers. These fuzzers are
not host_supported, and must be run on-device. Followup CLs containing
additional inputflinger fuzzers will rely on the FuzzContainer.h and
MapperHelpers.h header files.
Fuzzers included:
- CursorInputFuzzer
- KeyboardInputFuzzer
- MultiTouchInputFuzzer
- SwitchInputFuzzer
Test: Tested on a pixel 3a with HWASAN. Accurate % coverage information is
not available due to the large number of shared libraries included
in runs built with hwasan interfering with PC Count information
(increasing the total PC count to ~682,000).
Summary of updates:
Coverage improvements: 75% to 82%
Design changes:
[1] Refactored
- CursorInputFuzzer
- KeyboardInputFuzzer
- MultiTouchInputFuzzer
- SwitchInputFuzzer
in order to generate event as a combination of valid and invalid input.
[2] Used FuzzedDataProvider to generate values for events.
Signed-off-by: Michael Ensing <michael.ensing@leviathansecurity.com>
Change-Id: Id39205c691f54c516f8a452293cb098382019335
diff --git a/libs/input/PropertyMap.cpp b/libs/input/PropertyMap.cpp
index 662e568..16ffa10 100644
--- a/libs/input/PropertyMap.cpp
+++ b/libs/input/PropertyMap.cpp
@@ -75,7 +75,7 @@
}
char* end;
- int value = strtol(stringValue.c_str(), &end, 10);
+ int32_t value = static_cast<int32_t>(strtol(stringValue.c_str(), &end, 10));
if (*end != '\0') {
ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.c_str(),
stringValue.c_str());
diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp
index 455a1e2..a53db00 100644
--- a/services/inputflinger/tests/fuzzers/Android.bp
+++ b/services/inputflinger/tests/fuzzers/Android.bp
@@ -46,3 +46,74 @@
cc: ["android-framework-input@google.com"],
},
}
+
+cc_defaults {
+ name: "inputflinger_fuzz_defaults",
+ defaults: [
+ "inputflinger_defaults",
+ ],
+ include_dirs: [
+ "frameworks/native/services/inputflinger",
+ ],
+ shared_libs: [
+ "android.hardware.input.classifier@1.0",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "liblog",
+ "libutils",
+ "libui",
+ "libinput",
+ "libinputflinger",
+ "libinputreader",
+ "libinputflinger_base",
+ "libstatslog",
+ ],
+ header_libs: [
+ "libbatteryservice_headers",
+ "libinputreader_headers",
+ ],
+ fuzz_config: {
+ cc: ["android-framework-input@google.com"],
+ },
+}
+
+cc_fuzz {
+ name: "inputflinger_cursor_input_fuzzer",
+ defaults: [
+ "inputflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "CursorInputFuzzer.cpp",
+ ],
+}
+
+cc_fuzz {
+ name: "inputflinger_keyboard_input_fuzzer",
+ defaults: [
+ "inputflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "KeyboardInputFuzzer.cpp",
+ ],
+}
+
+cc_fuzz {
+ name: "inputflinger_multitouch_input_fuzzer",
+ defaults: [
+ "inputflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "MultiTouchInputFuzzer.cpp",
+ ],
+}
+
+cc_fuzz {
+ name: "inputflinger_switch_input_fuzzer",
+ defaults: [
+ "inputflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "SwitchInputFuzzer.cpp",
+ ],
+}
diff --git a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
new file mode 100644
index 0000000..4b542aa
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#include <CursorInputMapper.h>
+#include <FuzzContainer.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+
+static void addProperty(FuzzContainer& fuzzer, std::shared_ptr<FuzzedDataProvider> fdp) {
+ // Pick a random property to set for the mapper to have set.
+ fdp->PickValueInArray<std::function<void()>>(
+ {[&]() -> void { fuzzer.addProperty("cursor.mode", "pointer"); },
+ [&]() -> void { fuzzer.addProperty("cursor.mode", "navigation"); },
+ [&]() -> void {
+ fuzzer.addProperty("cursor.mode", fdp->ConsumeRandomLengthString(100).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("cursor.orientationAware",
+ fdp->ConsumeRandomLengthString(100).data());
+ }})();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
+ std::shared_ptr<FuzzedDataProvider> fdp = std::make_shared<FuzzedDataProvider>(data, size);
+ FuzzContainer fuzzer(fdp);
+
+ CursorInputMapper& mapper = fuzzer.getMapper<CursorInputMapper>();
+ auto policyConfig = fuzzer.getPolicyConfig();
+
+ // Loop through mapper operations until randomness is exhausted.
+ while (fdp->remaining_bytes() > 0) {
+ fdp->PickValueInArray<std::function<void()>>({
+ [&]() -> void { addProperty(fuzzer, fdp); },
+ [&]() -> void {
+ std::string dump;
+ mapper.dump(dump);
+ },
+ [&]() -> void { mapper.getSources(); },
+ [&]() -> void {
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig,
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ // Need to reconfigure with 0 or you risk a NPE.
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, 0);
+ InputDeviceInfo info;
+ mapper.populateDeviceInfo(&info);
+ },
+ [&]() -> void {
+ int32_t type, code;
+ type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes)
+ : fdp->ConsumeIntegral<int32_t>();
+ code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes)
+ : fdp->ConsumeIntegral<int32_t>();
+
+ // Need to reconfigure with 0 or you risk a NPE.
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, 0);
+ RawEvent rawEvent{fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<int32_t>(),
+ type,
+ code,
+ fdp->ConsumeIntegral<int32_t>()};
+ mapper.process(&rawEvent);
+ },
+ [&]() -> void { mapper.reset(fdp->ConsumeIntegral<nsecs_t>()); },
+ [&]() -> void {
+ mapper.getScanCodeState(fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ // Need to reconfigure with 0 or you risk a NPE.
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, 0);
+ mapper.getAssociatedDisplayId();
+ },
+ })();
+ }
+
+ return 0;
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/FuzzContainer.h b/services/inputflinger/tests/fuzzers/FuzzContainer.h
new file mode 100644
index 0000000..62615d0
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/FuzzContainer.h
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <InputDevice.h>
+#include <InputMapper.h>
+#include <InputReader.h>
+#include <MapperHelpers.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+
+class FuzzContainer {
+ std::shared_ptr<FuzzEventHub> mFuzzEventHub;
+ sp<FuzzInputReaderPolicy> mFuzzPolicy;
+ std::unique_ptr<FuzzInputListener> mFuzzListener;
+ std::unique_ptr<FuzzInputReaderContext> mFuzzContext;
+ std::unique_ptr<InputDevice> mFuzzDevice;
+ InputReaderConfiguration mPolicyConfig;
+ std::shared_ptr<FuzzedDataProvider> mFdp;
+
+public:
+ FuzzContainer(std::shared_ptr<FuzzedDataProvider> fdp) : mFdp(fdp) {
+ // Setup parameters.
+ std::string deviceName = mFdp->ConsumeRandomLengthString(16);
+ std::string deviceLocation = mFdp->ConsumeRandomLengthString(12);
+ int32_t deviceID = mFdp->ConsumeIntegralInRange<int32_t>(0, 5);
+ int32_t deviceGeneration = mFdp->ConsumeIntegralInRange<int32_t>(/*from*/ 0, /*to*/ 5);
+
+ // Create mocked objects.
+ mFuzzEventHub = std::make_shared<FuzzEventHub>(mFdp);
+ mFuzzPolicy = sp<FuzzInputReaderPolicy>::make(mFdp);
+ mFuzzListener = std::make_unique<FuzzInputListener>();
+ mFuzzContext = std::make_unique<FuzzInputReaderContext>(mFuzzEventHub, mFuzzPolicy,
+ *mFuzzListener, mFdp);
+
+ InputDeviceIdentifier identifier;
+ identifier.name = deviceName;
+ identifier.location = deviceLocation;
+ mFuzzDevice = std::make_unique<InputDevice>(mFuzzContext.get(), deviceID, deviceGeneration,
+ identifier);
+ mFuzzPolicy->getReaderConfiguration(&mPolicyConfig);
+ }
+
+ ~FuzzContainer() {}
+
+ void configureDevice() {
+ nsecs_t arbitraryTime = mFdp->ConsumeIntegral<nsecs_t>();
+ mFuzzDevice->configure(arbitraryTime, &mPolicyConfig, 0);
+ mFuzzDevice->reset(arbitraryTime);
+ }
+
+ void addProperty(std::string key, std::string value) {
+ mFuzzEventHub->addProperty(key, value);
+ configureDevice();
+ }
+
+ InputReaderConfiguration& getPolicyConfig() { return mPolicyConfig; }
+
+ template <class T, typename... Args>
+ T& getMapper(Args... args) {
+ T& mapper = mFuzzDevice->addMapper<T>(mFdp->ConsumeIntegral<int32_t>(), args...);
+ configureDevice();
+ return mapper;
+ }
+};
+
+} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
new file mode 100644
index 0000000..c48a099
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#include <FuzzContainer.h>
+#include <KeyboardInputMapper.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+
+const int32_t kMaxKeycodes = 100;
+
+static void addProperty(FuzzContainer& fuzzer, std::shared_ptr<FuzzedDataProvider> fdp) {
+ // Pick a random property to set for the mapper to have set.
+ fdp->PickValueInArray<std::function<void()>>(
+ {[&]() -> void { fuzzer.addProperty("keyboard.orientationAware", "1"); },
+ [&]() -> void {
+ fuzzer.addProperty("keyboard.orientationAware",
+ fdp->ConsumeRandomLengthString(100).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("keyboard.doNotWakeByDefault",
+ fdp->ConsumeRandomLengthString(100).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("keyboard.handlesKeyRepeat",
+ fdp->ConsumeRandomLengthString(100).data());
+ }})();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
+ std::shared_ptr<FuzzedDataProvider> fdp = std::make_shared<FuzzedDataProvider>(data, size);
+ FuzzContainer fuzzer(fdp);
+
+ KeyboardInputMapper& mapper =
+ fuzzer.getMapper<KeyboardInputMapper>(fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ auto policyConfig = fuzzer.getPolicyConfig();
+
+ // Loop through mapper operations until randomness is exhausted.
+ while (fdp->remaining_bytes() > 0) {
+ fdp->PickValueInArray<std::function<void()>>({
+ [&]() -> void { addProperty(fuzzer, fdp); },
+ [&]() -> void {
+ std::string dump;
+ mapper.dump(dump);
+ },
+ [&]() -> void {
+ InputDeviceInfo info;
+ mapper.populateDeviceInfo(&info);
+ },
+ [&]() -> void { mapper.getSources(); },
+ [&]() -> void {
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig,
+ fdp->ConsumeIntegral<uint32_t>());
+ },
+ [&]() -> void { mapper.reset(fdp->ConsumeIntegral<nsecs_t>()); },
+ [&]() -> void {
+ int32_t type, code;
+ type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes)
+ : fdp->ConsumeIntegral<int32_t>();
+ code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes)
+ : fdp->ConsumeIntegral<int32_t>();
+ RawEvent rawEvent{fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<int32_t>(),
+ type,
+ code,
+ fdp->ConsumeIntegral<int32_t>()};
+ mapper.process(&rawEvent);
+ },
+ [&]() -> void {
+ mapper.getKeyCodeState(fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ mapper.getScanCodeState(fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ std::vector<int32_t> keyCodes;
+ int32_t numBytes = fdp->ConsumeIntegralInRange<int32_t>(0, kMaxKeycodes);
+ for (int32_t i = 0; i < numBytes; ++i) {
+ keyCodes.push_back(fdp->ConsumeIntegral<int32_t>());
+ }
+ mapper.markSupportedKeyCodes(fdp->ConsumeIntegral<uint32_t>(), keyCodes,
+ nullptr);
+ },
+ [&]() -> void { mapper.getMetaState(); },
+ [&]() -> void { mapper.updateMetaState(fdp->ConsumeIntegral<int32_t>()); },
+ [&]() -> void { mapper.getAssociatedDisplayId(); },
+ })();
+ }
+
+ return 0;
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
new file mode 100644
index 0000000..53a7b16
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -0,0 +1,372 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <InputDevice.h>
+#include <InputMapper.h>
+#include <InputReader.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include "android/hardware/input/InputDeviceCountryCode.h"
+
+using android::hardware::input::InputDeviceCountryCode;
+
+constexpr size_t kValidTypes[] = {EV_SW,
+ EV_SYN,
+ SYN_REPORT,
+ EV_ABS,
+ EV_KEY,
+ EV_MSC,
+ EV_REL,
+ android::EventHubInterface::DEVICE_ADDED,
+ android::EventHubInterface::DEVICE_REMOVED,
+ android::EventHubInterface::FINISHED_DEVICE_SCAN};
+
+constexpr size_t kValidCodes[] = {
+ SYN_REPORT,
+ ABS_MT_SLOT,
+ SYN_MT_REPORT,
+ ABS_MT_POSITION_X,
+ ABS_MT_POSITION_Y,
+ ABS_MT_TOUCH_MAJOR,
+ ABS_MT_TOUCH_MINOR,
+ ABS_MT_WIDTH_MAJOR,
+ ABS_MT_WIDTH_MINOR,
+ ABS_MT_ORIENTATION,
+ ABS_MT_TRACKING_ID,
+ ABS_MT_PRESSURE,
+ ABS_MT_DISTANCE,
+ ABS_MT_TOOL_TYPE,
+ SYN_MT_REPORT,
+ MSC_SCAN,
+ REL_X,
+ REL_Y,
+ REL_WHEEL,
+ REL_HWHEEL,
+ BTN_LEFT,
+ BTN_RIGHT,
+ BTN_MIDDLE,
+ BTN_BACK,
+ BTN_SIDE,
+ BTN_FORWARD,
+ BTN_EXTRA,
+ BTN_TASK,
+};
+
+constexpr InputDeviceCountryCode kCountryCodes[] = {
+ InputDeviceCountryCode::INVALID,
+ InputDeviceCountryCode::NOT_SUPPORTED,
+ InputDeviceCountryCode::ARABIC,
+ InputDeviceCountryCode::BELGIAN,
+ InputDeviceCountryCode::CANADIAN_BILINGUAL,
+ InputDeviceCountryCode::CANADIAN_FRENCH,
+ InputDeviceCountryCode::CZECH_REPUBLIC,
+ InputDeviceCountryCode::DANISH,
+ InputDeviceCountryCode::FINNISH,
+ InputDeviceCountryCode::FRENCH,
+ InputDeviceCountryCode::GERMAN,
+ InputDeviceCountryCode::GREEK,
+ InputDeviceCountryCode::HEBREW,
+ InputDeviceCountryCode::HUNGARY,
+ InputDeviceCountryCode::INTERNATIONAL,
+ InputDeviceCountryCode::ITALIAN,
+ InputDeviceCountryCode::JAPAN,
+ InputDeviceCountryCode::KOREAN,
+ InputDeviceCountryCode::LATIN_AMERICAN,
+ InputDeviceCountryCode::DUTCH,
+ InputDeviceCountryCode::NORWEGIAN,
+ InputDeviceCountryCode::PERSIAN,
+ InputDeviceCountryCode::POLAND,
+ InputDeviceCountryCode::PORTUGUESE,
+ InputDeviceCountryCode::RUSSIA,
+ InputDeviceCountryCode::SLOVAKIA,
+ InputDeviceCountryCode::SPANISH,
+ InputDeviceCountryCode::SWEDISH,
+ InputDeviceCountryCode::SWISS_FRENCH,
+ InputDeviceCountryCode::SWISS_GERMAN,
+ InputDeviceCountryCode::SWITZERLAND,
+ InputDeviceCountryCode::TAIWAN,
+ InputDeviceCountryCode::TURKISH_Q,
+ InputDeviceCountryCode::UK,
+ InputDeviceCountryCode::US,
+ InputDeviceCountryCode::YUGOSLAVIA,
+ InputDeviceCountryCode::TURKISH_F,
+};
+
+constexpr size_t kMaxSize = 256;
+
+namespace android {
+
+class FuzzEventHub : public EventHubInterface {
+ InputDeviceIdentifier mIdentifier;
+ std::vector<TouchVideoFrame> mVideoFrames;
+ PropertyMap mFuzzConfig;
+ size_t mCount = 0;
+ std::array<RawEvent, kMaxSize> mBuf;
+ std::shared_ptr<FuzzedDataProvider> mFdp;
+
+public:
+ FuzzEventHub(std::shared_ptr<FuzzedDataProvider> fdp) : mFdp(std::move(fdp)) {}
+ ~FuzzEventHub() {}
+ void addProperty(std::string key, std::string value) { mFuzzConfig.addProperty(key, value); }
+ void addEvents(std::shared_ptr<FuzzedDataProvider> fdp) {
+ mCount = fdp->ConsumeIntegralInRange<size_t>(0, kMaxSize);
+
+ for (size_t i = 0; i < mCount; ++i) {
+ int32_t type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes)
+ : fdp->ConsumeIntegral<int32_t>();
+ int32_t code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes)
+ : fdp->ConsumeIntegral<int32_t>();
+ mBuf[i] = {fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<int32_t>(),
+ type,
+ code,
+ fdp->ConsumeIntegral<int32_t>()};
+ }
+ }
+
+ ftl::Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override {
+ return ftl::Flags<InputDeviceClass>(mFdp->ConsumeIntegral<uint32_t>());
+ }
+ InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override {
+ return mIdentifier;
+ }
+ int32_t getDeviceControllerNumber(int32_t deviceId) const override {
+ return mFdp->ConsumeIntegral<int32_t>();
+ }
+ void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const override {
+ *outConfiguration = mFuzzConfig;
+ }
+ status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
+ RawAbsoluteAxisInfo* outAxisInfo) const override {
+ return mFdp->ConsumeIntegral<status_t>();
+ }
+ bool hasRelativeAxis(int32_t deviceId, int axis) const override { return mFdp->ConsumeBool(); }
+ bool hasInputProperty(int32_t deviceId, int property) const override {
+ return mFdp->ConsumeBool();
+ }
+ bool hasMscEvent(int32_t deviceId, int mscEvent) const override { return mFdp->ConsumeBool(); }
+ status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState,
+ int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const override {
+ return mFdp->ConsumeIntegral<status_t>();
+ }
+ status_t mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const override {
+ return mFdp->ConsumeIntegral<status_t>();
+ }
+ void setExcludedDevices(const std::vector<std::string>& devices) override {}
+ size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) override {
+ for (size_t i = 0; i < mCount; ++i) buffer[i] = mBuf[i];
+
+ return mCount;
+ }
+ std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override { return mVideoFrames; }
+
+ base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(
+ int32_t deviceId, int32_t absCode) const override {
+ return base::ResultError("Fuzzer", UNKNOWN_ERROR);
+ };
+ // Raw batteries are sysfs power_supply nodes we found from the EventHub device sysfs node,
+ // containing the raw info of the sysfs node structure.
+ std::vector<int32_t> getRawBatteryIds(int32_t deviceId) const override { return {}; }
+ std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId,
+ int32_t BatteryId) const override {
+ return std::nullopt;
+ };
+
+ std::vector<int32_t> getRawLightIds(int32_t deviceId) const override { return {}; };
+ std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) const override {
+ return std::nullopt;
+ };
+ std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) const override {
+ return std::nullopt;
+ };
+ void setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) override{};
+ std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities(
+ int32_t deviceId, int32_t lightId) const override {
+ return std::nullopt;
+ };
+ void setLightIntensities(int32_t deviceId, int32_t lightId,
+ std::unordered_map<LightColor, int32_t> intensities) override{};
+
+ InputDeviceCountryCode getCountryCode(int32_t deviceId) const override {
+ return mFdp->PickValueInArray<InputDeviceCountryCode>(kCountryCodes);
+ };
+
+ int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override {
+ return mFdp->ConsumeIntegral<int32_t>();
+ }
+ int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override {
+ return mFdp->ConsumeIntegral<int32_t>();
+ }
+ int32_t getSwitchState(int32_t deviceId, int32_t sw) const override {
+ return mFdp->ConsumeIntegral<int32_t>();
+ }
+ int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const override {
+ return mFdp->ConsumeIntegral<int32_t>();
+ }
+ status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
+ int32_t* outValue) const override {
+ return mFdp->ConsumeIntegral<status_t>();
+ }
+ bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes,
+ uint8_t* outFlags) const override {
+ return mFdp->ConsumeBool();
+ }
+ bool hasScanCode(int32_t deviceId, int32_t scanCode) const override {
+ return mFdp->ConsumeBool();
+ }
+ bool hasKeyCode(int32_t deviceId, int32_t keyCode) const override {
+ return mFdp->ConsumeBool();
+ }
+ bool hasLed(int32_t deviceId, int32_t led) const override { return mFdp->ConsumeBool(); }
+ void setLedState(int32_t deviceId, int32_t led, bool on) override {}
+ void getVirtualKeyDefinitions(
+ int32_t deviceId, std::vector<VirtualKeyDefinition>& outVirtualKeys) const override {}
+ const std::shared_ptr<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const override {
+ return nullptr;
+ }
+ bool setKeyboardLayoutOverlay(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map) override {
+ return mFdp->ConsumeBool();
+ }
+ void vibrate(int32_t deviceId, const VibrationElement& effect) override {}
+ void cancelVibrate(int32_t deviceId) override {}
+
+ std::vector<int32_t> getVibratorIds(int32_t deviceId) const override { return {}; };
+
+ /* Query battery level. */
+ std::optional<int32_t> getBatteryCapacity(int32_t deviceId, int32_t batteryId) const override {
+ return std::nullopt;
+ };
+
+ /* Query battery status. */
+ std::optional<int32_t> getBatteryStatus(int32_t deviceId, int32_t batteryId) const override {
+ return std::nullopt;
+ };
+
+ void requestReopenDevices() override {}
+ void wake() override {}
+ void dump(std::string& dump) const override {}
+ void monitor() const override {}
+ bool isDeviceEnabled(int32_t deviceId) const override { return mFdp->ConsumeBool(); }
+ status_t enableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); }
+ status_t disableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); }
+};
+
+class FuzzPointerController : public PointerControllerInterface {
+ std::shared_ptr<FuzzedDataProvider> mFdp;
+
+public:
+ FuzzPointerController(std::shared_ptr<FuzzedDataProvider> mFdp) : mFdp(mFdp) {}
+ ~FuzzPointerController() {}
+ bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const override {
+ return mFdp->ConsumeBool();
+ }
+ void move(float deltaX, float deltaY) override {}
+ void setButtonState(int32_t buttonState) override {}
+ int32_t getButtonState() const override { return mFdp->ConsumeIntegral<int32_t>(); }
+ void setPosition(float x, float y) override {}
+ void getPosition(float* outX, float* outY) const override {}
+ void fade(Transition transition) override {}
+ void unfade(Transition transition) override {}
+ void setPresentation(Presentation presentation) override {}
+ void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
+ BitSet32 spotIdBits, int32_t displayId) override {}
+ void clearSpots() override {}
+ int32_t getDisplayId() const override { return mFdp->ConsumeIntegral<int32_t>(); }
+ void setDisplayViewport(const DisplayViewport& displayViewport) override {}
+};
+
+class FuzzInputReaderPolicy : public InputReaderPolicyInterface {
+ TouchAffineTransformation mTransform;
+ std::shared_ptr<FuzzPointerController> mPointerController;
+ std::shared_ptr<FuzzedDataProvider> mFdp;
+
+protected:
+ ~FuzzInputReaderPolicy() {}
+
+public:
+ FuzzInputReaderPolicy(std::shared_ptr<FuzzedDataProvider> mFdp) : mFdp(mFdp) {
+ mPointerController = std::make_shared<FuzzPointerController>(mFdp);
+ }
+ void getReaderConfiguration(InputReaderConfiguration* outConfig) override {}
+ std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId) override {
+ return mPointerController;
+ }
+ void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override {}
+ std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
+ const InputDeviceIdentifier& identifier) override {
+ return nullptr;
+ }
+ std::string getDeviceAlias(const InputDeviceIdentifier& identifier) {
+ return mFdp->ConsumeRandomLengthString(32);
+ }
+ TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor,
+ int32_t surfaceRotation) override {
+ return mTransform;
+ }
+ void setTouchAffineTransformation(const TouchAffineTransformation t) { mTransform = t; }
+};
+
+class FuzzInputListener : public virtual InputListenerInterface {
+public:
+ void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override {}
+ void notifyKey(const NotifyKeyArgs* args) override {}
+ void notifyMotion(const NotifyMotionArgs* args) override {}
+ void notifySwitch(const NotifySwitchArgs* args) override {}
+ void notifySensor(const NotifySensorArgs* args) override{};
+ void notifyVibratorState(const NotifyVibratorStateArgs* args) override{};
+ void notifyDeviceReset(const NotifyDeviceResetArgs* args) override {}
+ void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override{};
+};
+
+class FuzzInputReaderContext : public InputReaderContext {
+ std::shared_ptr<EventHubInterface> mEventHub;
+ sp<InputReaderPolicyInterface> mPolicy;
+ InputListenerInterface& mListener;
+ std::shared_ptr<FuzzedDataProvider> mFdp;
+
+public:
+ FuzzInputReaderContext(std::shared_ptr<EventHubInterface> eventHub,
+ const sp<InputReaderPolicyInterface>& policy,
+ InputListenerInterface& listener,
+ std::shared_ptr<FuzzedDataProvider> mFdp)
+ : mEventHub(eventHub), mPolicy(policy), mListener(listener), mFdp(mFdp) {}
+ ~FuzzInputReaderContext() {}
+ void updateGlobalMetaState() override {}
+ int32_t getGlobalMetaState() { return mFdp->ConsumeIntegral<int32_t>(); }
+ void disableVirtualKeysUntil(nsecs_t time) override {}
+ bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) override {
+ return mFdp->ConsumeBool();
+ }
+ void fadePointer() override {}
+ std::shared_ptr<PointerControllerInterface> getPointerController(int32_t deviceId) override {
+ return mPolicy->obtainPointerController(0);
+ }
+ void requestTimeoutAtTime(nsecs_t when) override {}
+ int32_t bumpGeneration() override { return mFdp->ConsumeIntegral<int32_t>(); }
+ void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) override {}
+ void dispatchExternalStylusState(const StylusState& outState) override {}
+ InputReaderPolicyInterface* getPolicy() override { return mPolicy.get(); }
+ InputListenerInterface& getListener() override { return mListener; }
+ EventHubInterface* getEventHub() override { return mEventHub.get(); }
+ int32_t getNextId() override { return mFdp->ConsumeIntegral<int32_t>(); }
+
+ void updateLedMetaState(int32_t metaState) override{};
+ int32_t getLedMetaState() override { return mFdp->ConsumeIntegral<int32_t>(); };
+};
+
+} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
new file mode 100644
index 0000000..59b0642
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#include <FuzzContainer.h>
+#include <MultiTouchInputMapper.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+
+const int32_t kMaxKeycodes = 100;
+
+static void addProperty(FuzzContainer& fuzzer, std::shared_ptr<FuzzedDataProvider> fdp) {
+ // Pick a random property to set for the mapper to have set.
+ fdp->PickValueInArray<std::function<void()>>(
+ {[&]() -> void { fuzzer.addProperty("touch.deviceType", "touchScreen"); },
+ [&]() -> void {
+ fuzzer.addProperty("touch.deviceType", fdp->ConsumeRandomLengthString(8).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("touch.size.scale", fdp->ConsumeRandomLengthString(8).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("touch.size.bias", fdp->ConsumeRandomLengthString(8).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("touch.size.isSummed",
+ fdp->ConsumeRandomLengthString(8).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("touch.size.calibration",
+ fdp->ConsumeRandomLengthString(8).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("touch.pressure.scale",
+ fdp->ConsumeRandomLengthString(8).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("touch.size.calibration",
+ fdp->ConsumeBool() ? "diameter" : "area");
+ },
+ [&]() -> void {
+ fuzzer.addProperty("touch.pressure.calibration",
+ fdp->ConsumeRandomLengthString(8).data());
+ }})();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
+ std::shared_ptr<FuzzedDataProvider> fdp = std::make_shared<FuzzedDataProvider>(data, size);
+ FuzzContainer fuzzer(fdp);
+
+ MultiTouchInputMapper& mapper = fuzzer.getMapper<MultiTouchInputMapper>();
+ auto policyConfig = fuzzer.getPolicyConfig();
+
+ // Loop through mapper operations until randomness is exhausted.
+ while (fdp->remaining_bytes() > 0) {
+ fdp->PickValueInArray<std::function<void()>>({
+ [&]() -> void { addProperty(fuzzer, fdp); },
+ [&]() -> void {
+ std::string dump;
+ mapper.dump(dump);
+ },
+ [&]() -> void {
+ InputDeviceInfo info;
+ mapper.populateDeviceInfo(&info);
+ },
+ [&]() -> void { mapper.getSources(); },
+ [&]() -> void {
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig,
+ fdp->ConsumeIntegral<uint32_t>());
+ },
+ [&]() -> void { mapper.reset(fdp->ConsumeIntegral<nsecs_t>()); },
+ [&]() -> void {
+ int32_t type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes)
+ : fdp->ConsumeIntegral<int32_t>();
+ int32_t code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes)
+ : fdp->ConsumeIntegral<int32_t>();
+ RawEvent rawEvent{fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<int32_t>(),
+ type,
+ code,
+ fdp->ConsumeIntegral<int32_t>()};
+ mapper.process(&rawEvent);
+ },
+ [&]() -> void {
+ mapper.getKeyCodeState(fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ mapper.getScanCodeState(fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ std::vector<int32_t> keyCodes;
+ int32_t numBytes = fdp->ConsumeIntegralInRange<int32_t>(0, kMaxKeycodes);
+ for (int32_t i = 0; i < numBytes; ++i) {
+ keyCodes.push_back(fdp->ConsumeIntegral<int32_t>());
+ }
+ mapper.markSupportedKeyCodes(fdp->ConsumeIntegral<uint32_t>(), keyCodes,
+ nullptr);
+ },
+ [&]() -> void {
+ mapper.cancelTouch(fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<nsecs_t>());
+ },
+ [&]() -> void { mapper.timeoutExpired(fdp->ConsumeIntegral<nsecs_t>()); },
+ [&]() -> void {
+ StylusState state{fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeFloatingPoint<float>(),
+ fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>()};
+ mapper.updateExternalStylusState(state);
+ },
+ [&]() -> void { mapper.getAssociatedDisplayId(); },
+ })();
+ }
+
+ return 0;
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp
new file mode 100644
index 0000000..e76bd72
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#include <FuzzContainer.h>
+#include <SwitchInputMapper.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
+ std::shared_ptr<FuzzedDataProvider> fdp = std::make_shared<FuzzedDataProvider>(data, size);
+ FuzzContainer fuzzer(fdp);
+
+ SwitchInputMapper& mapper = fuzzer.getMapper<SwitchInputMapper>();
+ auto policyConfig = fuzzer.getPolicyConfig();
+
+ // Loop through mapper operations until randomness is exhausted.
+ while (fdp->remaining_bytes() > 0) {
+ fdp->PickValueInArray<std::function<void()>>({
+ [&]() -> void {
+ std::string dump;
+ mapper.dump(dump);
+ },
+ [&]() -> void { mapper.getSources(); },
+ [&]() -> void {
+ int32_t type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes)
+ : fdp->ConsumeIntegral<int32_t>();
+ int32_t code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes)
+ : fdp->ConsumeIntegral<int32_t>();
+ RawEvent rawEvent{fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<int32_t>(),
+ type,
+ code,
+ fdp->ConsumeIntegral<int32_t>()};
+ mapper.process(&rawEvent);
+ },
+ [&]() -> void {
+ mapper.getSwitchState(fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ })();
+ }
+
+ return 0;
+}
+
+} // namespace android