1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <limits>
18 #include <memory>
19 #include <string>
20 #include <vector>
21 
22 #include <linux/input-event-codes.h>
23 
24 #include <InputDevice.h>
25 #include <InputReaderBase.h>
26 #include <MapperHelpers.h>
27 #include <TouchpadInputMapper.h>
28 
29 namespace android {
30 
31 namespace {
32 
setAxisInfo(ThreadSafeFuzzedDataProvider & fdp,FuzzEventHub & eventHub,int32_t id,int axis)33 void setAxisInfo(ThreadSafeFuzzedDataProvider& fdp, FuzzEventHub& eventHub, int32_t id, int axis) {
34     if (fdp.ConsumeBool()) {
35         eventHub.setAbsoluteAxisInfo(id, axis,
36                                      RawAbsoluteAxisInfo{
37                                              .valid = fdp.ConsumeBool(),
38                                              .minValue = fdp.ConsumeIntegral<int32_t>(),
39                                              .maxValue = fdp.ConsumeIntegral<int32_t>(),
40                                              .flat = fdp.ConsumeIntegral<int32_t>(),
41                                              .fuzz = fdp.ConsumeIntegral<int32_t>(),
42                                              .resolution = fdp.ConsumeIntegral<int32_t>(),
43                                      });
44     }
45 }
46 
setAxisInfos(ThreadSafeFuzzedDataProvider & fdp,FuzzEventHub & eventHub,int32_t id)47 void setAxisInfos(ThreadSafeFuzzedDataProvider& fdp, FuzzEventHub& eventHub, int32_t id) {
48     setAxisInfo(fdp, eventHub, id, ABS_MT_SLOT);
49     setAxisInfo(fdp, eventHub, id, ABS_MT_POSITION_X);
50     setAxisInfo(fdp, eventHub, id, ABS_MT_POSITION_Y);
51     setAxisInfo(fdp, eventHub, id, ABS_MT_PRESSURE);
52     setAxisInfo(fdp, eventHub, id, ABS_MT_ORIENTATION);
53     setAxisInfo(fdp, eventHub, id, ABS_MT_TOUCH_MAJOR);
54     setAxisInfo(fdp, eventHub, id, ABS_MT_TOUCH_MINOR);
55     setAxisInfo(fdp, eventHub, id, ABS_MT_WIDTH_MAJOR);
56     setAxisInfo(fdp, eventHub, id, ABS_MT_WIDTH_MINOR);
57 }
58 
59 const std::vector<std::string> boolPropertiesToFuzz = {
60         "gestureProp.Compute_Surface_Area_from_Pressure",
61         "gestureProp.Drumroll_Suppression_Enable",
62         "gestureProp.Fling_Buffer_Suppress_Zero_Length_Scrolls",
63         "gestureProp.Stationary_Wiggle_Filter_Enabled",
64 };
65 const std::vector<std::string> doublePropertiesToFuzz = {
66         "gestureProp.Fake_Timestamp_Delta",
67         "gestureProp.Finger_Moving_Energy",
68         "gestureProp.Finger_Moving_Hysteresis",
69         "gestureProp.IIR_a1",
70         "gestureProp.IIR_a2",
71         "gestureProp.IIR_b0",
72         "gestureProp.IIR_b1",
73         "gestureProp.IIR_b2",
74         "gestureProp.IIR_b3",
75         "gestureProp.Max_Allowed_Pressure_Change_Per_Sec",
76         "gestureProp.Max_Hysteresis_Pressure_Per_Sec",
77         "gestureProp.Max_Stationary_Move_Speed",
78         "gestureProp.Max_Stationary_Move_Speed_Hysteresis",
79         "gestureProp.Max_Stationary_Move_Suppress_Distance",
80         "gestureProp.Multiple_Palm_Width",
81         "gestureProp.Palm_Edge_Zone_Width",
82         "gestureProp.Palm_Eval_Timeout",
83         "gestureProp.Palm_Pressure",
84         "gestureProp.Palm_Width",
85         "gestureProp.Pressure_Calibration_Offset",
86         "gestureProp.Pressure_Calibration_Slope",
87         "gestureProp.Tap_Exclusion_Border_Width",
88         "gestureProp.Touchpad_Device_Output_Bias_on_X-Axis",
89         "gestureProp.Touchpad_Device_Output_Bias_on_Y-Axis",
90         "gestureProp.Two_Finger_Vertical_Close_Distance_Thresh",
91 };
92 
setDeviceSpecificConfig(ThreadSafeFuzzedDataProvider & fdp,FuzzEventHub & eventHub)93 void setDeviceSpecificConfig(ThreadSafeFuzzedDataProvider& fdp, FuzzEventHub& eventHub) {
94     // There are a great many gesture properties offered by the Gestures library, all of which could
95     // potentially be set in Input Device Configuration files. Maintaining a complete list is
96     // impractical, so instead we only fuzz properties which are used in at least one IDC file, or
97     // which are likely to be used in future (e.g. ones for controlling palm rejection).
98 
99     if (fdp.ConsumeBool()) {
100         eventHub.addProperty("gestureProp.Touchpad_Stack_Version",
101                              std::to_string(fdp.ConsumeIntegral<int>()));
102     }
103 
104     for (auto& propertyName : boolPropertiesToFuzz) {
105         if (fdp.ConsumeBool()) {
106             eventHub.addProperty(propertyName, fdp.ConsumeBool() ? "1" : "0");
107         }
108     }
109 
110     for (auto& propertyName : doublePropertiesToFuzz) {
111         if (fdp.ConsumeBool()) {
112             eventHub.addProperty(propertyName, std::to_string(fdp.ConsumeFloatingPoint<double>()));
113         }
114     }
115 
116     if (fdp.ConsumeBool()) {
117         eventHub.addProperty("gestureProp." + fdp.ConsumeRandomLengthString(),
118                              std::to_string(fdp.ConsumeIntegral<int>()));
119     }
120 }
121 
setTouchpadSettings(ThreadSafeFuzzedDataProvider & fdp,InputReaderConfiguration & config)122 void setTouchpadSettings(ThreadSafeFuzzedDataProvider& fdp, InputReaderConfiguration& config) {
123     config.touchpadPointerSpeed = fdp.ConsumeIntegralInRange(-7, 7);
124     config.touchpadNaturalScrollingEnabled = fdp.ConsumeBool();
125     config.touchpadTapToClickEnabled = fdp.ConsumeBool();
126     config.touchpadTapDraggingEnabled = fdp.ConsumeBool();
127     config.touchpadRightClickZoneEnabled = fdp.ConsumeBool();
128 
129     config.pointerCaptureRequest.window = fdp.ConsumeBool() ? sp<BBinder>::make() : nullptr;
130     config.pointerCaptureRequest.seq = fdp.ConsumeIntegral<uint32_t>();
131 }
132 
133 } // namespace
134 
LLVMFuzzerTestOneInput(uint8_t * data,size_t size)135 extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
136     std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp =
137             std::make_shared<ThreadSafeFuzzedDataProvider>(data, size);
138 
139     // Create mocked objects to support the fuzzed input mapper.
140     std::shared_ptr<FuzzEventHub> eventHub = std::make_shared<FuzzEventHub>(fdp);
141     FuzzInputReaderContext context(eventHub, fdp);
142     InputDevice device = getFuzzedInputDevice(*fdp, &context);
143 
144     setAxisInfos(*fdp, *eventHub.get(), device.getId());
145     setDeviceSpecificConfig(*fdp, *eventHub.get());
146 
147     InputReaderConfiguration policyConfig;
148     // Some settings are fuzzed here, as well as in the main loop, to provide randomized data to the
149     // TouchpadInputMapper constructor.
150     setTouchpadSettings(*fdp, policyConfig);
151     TouchpadInputMapper& mapper =
152             getMapperForDevice<ThreadSafeFuzzedDataProvider, TouchpadInputMapper>(*fdp, device,
153                                                                                   policyConfig);
154 
155     // Loop through mapper operations until randomness is exhausted.
156     while (fdp->remaining_bytes() > 0) {
157         fdp->PickValueInArray<std::function<void()>>({
158                 [&]() -> void {
159                     std::string dump;
160                     mapper.dump(dump);
161                 },
162                 [&]() -> void {
163                     InputDeviceInfo info;
164                     mapper.populateDeviceInfo(info);
165                 },
166                 [&]() -> void { mapper.getSources(); },
167                 [&]() -> void {
168                     setTouchpadSettings(*fdp, policyConfig);
169                     std::list<NotifyArgs> unused =
170                             mapper.reconfigure(fdp->ConsumeIntegral<nsecs_t>(), policyConfig,
171                                                InputReaderConfiguration::Change(
172                                                        fdp->ConsumeIntegral<uint32_t>()));
173                 },
174                 [&]() -> void {
175                     std::list<NotifyArgs> unused = mapper.reset(fdp->ConsumeIntegral<nsecs_t>());
176                 },
177                 [&]() -> void {
178                     RawEvent event = getFuzzedRawEvent(*fdp);
179                     std::list<NotifyArgs> unused = mapper.process(event);
180                 },
181         })();
182     }
183 
184     return 0;
185 }
186 
187 } // namespace android
188