inputflinger: Add touchpad stack fuzzer
Heavily inspired by MultiTouchInputFuzzer, this one works similarly but
has additional code to fuzz touchpad setting values and device-specific
configuration. The evdev axis info is also fuzzed, since unspecified
resolution values have caused bugs in the Gestures library before.
(Other fuzzers only fuzz the status_t return value from
getAbsoluteAxisInfo, not the axis info struct itself.)
Bug: 264582512
Test: build with SANITIZE_TARGET=hwaddress, run for a while on a device
Change-Id: Ic22ac0f29d433fdf3c17331df620a39937ebd7eb
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index ee03d94..f749b0e 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -243,6 +243,7 @@
"inputflinger_keyboard_input_fuzzer",
"inputflinger_multitouch_input_fuzzer",
"inputflinger_switch_input_fuzzer",
+ "inputflinger_touchpad_input_fuzzer",
"inputflinger_input_reader_fuzzer",
"inputflinger_blocking_queue_fuzzer",
"inputflinger_input_classifier_fuzzer",
diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp
index 47b0824..d7980f5 100644
--- a/services/inputflinger/tests/fuzzers/Android.bp
+++ b/services/inputflinger/tests/fuzzers/Android.bp
@@ -100,6 +100,22 @@
}
cc_fuzz {
+ name: "inputflinger_touchpad_input_fuzzer",
+ defaults: [
+ "inputflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "TouchpadInputFuzzer.cpp",
+ ],
+ static_libs: [
+ "libchrome-gestures",
+ ],
+ header_libs: [
+ "libchrome-gestures_headers",
+ ],
+}
+
+cc_fuzz {
name: "inputflinger_input_reader_fuzzer",
defaults: [
"inputflinger_fuzz_defaults",
diff --git a/services/inputflinger/tests/fuzzers/FuzzContainer.h b/services/inputflinger/tests/fuzzers/FuzzContainer.h
index fd14e02..0869b9f 100644
--- a/services/inputflinger/tests/fuzzers/FuzzContainer.h
+++ b/services/inputflinger/tests/fuzzers/FuzzContainer.h
@@ -73,6 +73,10 @@
InputReaderConfiguration& getPolicyConfig() { return mPolicyConfig; }
+ void setAbsoluteAxisInfo(int axis, const RawAbsoluteAxisInfo& axisInfo) {
+ mFuzzEventHub->setAbsoluteAxisInfo(mFuzzDevice->getId(), axis, axisInfo);
+ }
+
template <class T, typename... Args>
T& getMapper(Args... args) {
int32_t eventhubId = mFdp->ConsumeIntegral<int32_t>();
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index 4a2c98c..5039d1a 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -15,6 +15,9 @@
*/
#pragma once
+#include <map>
+
+#include <EventHub.h>
#include <InputDevice.h>
#include <InputMapper.h>
#include <InputReader.h>
@@ -92,6 +95,7 @@
InputDeviceIdentifier mIdentifier;
std::vector<TouchVideoFrame> mVideoFrames;
PropertyMap mFuzzConfig;
+ std::map<int32_t /* deviceId */, std::map<int /* axis */, RawAbsoluteAxisInfo>> mAxes;
std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp;
public:
@@ -111,8 +115,18 @@
std::optional<PropertyMap> getConfiguration(int32_t deviceId) const override {
return mFuzzConfig;
}
+ void setAbsoluteAxisInfo(int32_t deviceId, int axis, const RawAbsoluteAxisInfo& axisInfo) {
+ mAxes[deviceId][axis] = axisInfo;
+ }
status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const override {
+ if (auto deviceAxesIt = mAxes.find(deviceId); deviceAxesIt != mAxes.end()) {
+ const std::map<int, RawAbsoluteAxisInfo>& deviceAxes = deviceAxesIt->second;
+ if (auto axisInfoIt = deviceAxes.find(axis); axisInfoIt != deviceAxes.end()) {
+ *outAxisInfo = axisInfoIt->second;
+ return OK;
+ }
+ }
return mFdp->ConsumeIntegral<status_t>();
}
bool hasRelativeAxis(int32_t deviceId, int axis) const override { return mFdp->ConsumeBool(); }
diff --git a/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp
new file mode 100644
index 0000000..ef9663a
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2023 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 <limits>
+#include <string>
+#include <vector>
+
+#include <linux/input-event-codes.h>
+
+#include <FuzzContainer.h>
+#include <MapperHelpers.h>
+#include <TouchpadInputMapper.h>
+
+namespace android {
+
+namespace {
+
+void setAxisInfo(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer, int axis) {
+ if (fdp.ConsumeBool()) {
+ fuzzer.setAbsoluteAxisInfo(axis,
+ RawAbsoluteAxisInfo{
+ .valid = fdp.ConsumeBool(),
+ .minValue = fdp.ConsumeIntegral<int32_t>(),
+ .maxValue = fdp.ConsumeIntegral<int32_t>(),
+ .flat = fdp.ConsumeIntegral<int32_t>(),
+ .fuzz = fdp.ConsumeIntegral<int32_t>(),
+ .resolution = fdp.ConsumeIntegral<int32_t>(),
+ });
+ }
+}
+
+void setAxisInfos(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer) {
+ setAxisInfo(fdp, fuzzer, ABS_MT_SLOT);
+ setAxisInfo(fdp, fuzzer, ABS_MT_POSITION_X);
+ setAxisInfo(fdp, fuzzer, ABS_MT_POSITION_Y);
+ setAxisInfo(fdp, fuzzer, ABS_MT_PRESSURE);
+ setAxisInfo(fdp, fuzzer, ABS_MT_ORIENTATION);
+ setAxisInfo(fdp, fuzzer, ABS_MT_TOUCH_MAJOR);
+ setAxisInfo(fdp, fuzzer, ABS_MT_TOUCH_MINOR);
+ setAxisInfo(fdp, fuzzer, ABS_MT_WIDTH_MAJOR);
+ setAxisInfo(fdp, fuzzer, ABS_MT_WIDTH_MINOR);
+}
+
+const std::vector<std::string> boolPropertiesToFuzz = {
+ "gestureProp.Compute_Surface_Area_from_Pressure",
+ "gestureProp.Drumroll_Suppression_Enable",
+ "gestureProp.Fling_Buffer_Suppress_Zero_Length_Scrolls",
+ "gestureProp.Stationary_Wiggle_Filter_Enabled",
+};
+const std::vector<std::string> doublePropertiesToFuzz = {
+ "gestureProp.Fake_Timestamp_Delta",
+ "gestureProp.Finger_Moving_Energy",
+ "gestureProp.Finger_Moving_Hysteresis",
+ "gestureProp.IIR_a1",
+ "gestureProp.IIR_a2",
+ "gestureProp.IIR_b0",
+ "gestureProp.IIR_b1",
+ "gestureProp.IIR_b2",
+ "gestureProp.IIR_b3",
+ "gestureProp.Max_Allowed_Pressure_Change_Per_Sec",
+ "gestureProp.Max_Hysteresis_Pressure_Per_Sec",
+ "gestureProp.Max_Stationary_Move_Speed",
+ "gestureProp.Max_Stationary_Move_Speed_Hysteresis",
+ "gestureProp.Max_Stationary_Move_Suppress_Distance",
+ "gestureProp.Multiple_Palm_Width",
+ "gestureProp.Palm_Edge_Zone_Width",
+ "gestureProp.Palm_Eval_Timeout",
+ "gestureProp.Palm_Pressure",
+ "gestureProp.Palm_Width",
+ "gestureProp.Pressure_Calibration_Offset",
+ "gestureProp.Pressure_Calibration_Slope",
+ "gestureProp.Tap_Exclusion_Border_Width",
+ "gestureProp.Touchpad_Device_Output_Bias_on_X-Axis",
+ "gestureProp.Touchpad_Device_Output_Bias_on_Y-Axis",
+ "gestureProp.Two_Finger_Vertical_Close_Distance_Thresh",
+};
+
+void setDeviceSpecificConfig(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer) {
+ // There are a great many gesture properties offered by the Gestures library, all of which could
+ // potentially be set in Input Device Configuration files. Maintaining a complete list is
+ // impractical, so instead we only fuzz properties which are used in at least one IDC file, or
+ // which are likely to be used in future (e.g. ones for controlling palm rejection).
+
+ if (fdp.ConsumeBool()) {
+ fuzzer.addProperty("gestureProp.Touchpad_Stack_Version",
+ std::to_string(fdp.ConsumeIntegral<int>()));
+ }
+
+ for (auto& propertyName : boolPropertiesToFuzz) {
+ if (fdp.ConsumeBool()) {
+ fuzzer.addProperty(propertyName, fdp.ConsumeBool() ? "1" : "0");
+ }
+ }
+
+ for (auto& propertyName : doublePropertiesToFuzz) {
+ if (fdp.ConsumeBool()) {
+ fuzzer.addProperty(propertyName, std::to_string(fdp.ConsumeFloatingPoint<double>()));
+ }
+ }
+
+ if (fdp.ConsumeBool()) {
+ fuzzer.addProperty("gestureProp." + fdp.ConsumeRandomLengthString(),
+ std::to_string(fdp.ConsumeIntegral<int>()));
+ }
+}
+
+void setTouchpadSettings(ThreadSafeFuzzedDataProvider& fdp, InputReaderConfiguration& config) {
+ config.touchpadPointerSpeed = fdp.ConsumeIntegralInRange(-7, 7);
+ config.touchpadNaturalScrollingEnabled = fdp.ConsumeBool();
+ config.touchpadTapToClickEnabled = fdp.ConsumeBool();
+ config.touchpadRightClickZoneEnabled = fdp.ConsumeBool();
+}
+
+} // namespace
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
+ std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp =
+ std::make_shared<ThreadSafeFuzzedDataProvider>(data, size);
+ FuzzContainer fuzzer(fdp);
+ setAxisInfos(*fdp, fuzzer);
+ setDeviceSpecificConfig(*fdp, fuzzer);
+
+ auto policyConfig = fuzzer.getPolicyConfig();
+ // Some settings are fuzzed here, as well as in the main loop, to provide randomized data to the
+ // TouchpadInputMapper constructor.
+ setTouchpadSettings(*fdp, policyConfig);
+ policyConfig.pointerCaptureRequest.enable = fdp->ConsumeBool();
+ TouchpadInputMapper& mapper = fuzzer.getMapper<TouchpadInputMapper>(policyConfig);
+
+ // 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 {
+ InputDeviceInfo info;
+ mapper.populateDeviceInfo(info);
+ },
+ [&]() -> void { mapper.getSources(); },
+ [&]() -> void {
+ setTouchpadSettings(*fdp, policyConfig);
+ policyConfig.pointerCaptureRequest.enable = fdp->ConsumeBool();
+ std::list<NotifyArgs> unused =
+ mapper.reconfigure(fdp->ConsumeIntegral<nsecs_t>(), policyConfig,
+ InputReaderConfiguration::Change(
+ fdp->ConsumeIntegral<uint32_t>()));
+ },
+ [&]() -> void {
+ std::list<NotifyArgs> unused = mapper.reset(fdp->ConsumeIntegral<nsecs_t>());
+ },
+ [&]() -> void {
+ RawEvent event = getFuzzedRawEvent(*fdp);
+ std::list<NotifyArgs> unused = mapper.process(&event);
+ },
+ })();
+ }
+
+ return 0;
+}
+
+} // namespace android