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 <android-base/stringprintf.h>
18 #include <fuzzer/FuzzedDataProvider.h>
19 #include "../FakeApplicationHandle.h"
20 #include "../FakeInputDispatcherPolicy.h"
21 #include "../FakeWindows.h"
22 #include "FuzzedInputStream.h"
23 #include "dispatcher/InputDispatcher.h"
24 #include "input/InputVerifier.h"
25
26 namespace android {
27
28 using android::base::Result;
29 using android::gui::WindowInfo;
30
31 namespace inputdispatcher {
32
33 namespace {
34
35 static constexpr int32_t MAX_RANDOM_DISPLAYS = 4;
36 static constexpr int32_t MAX_RANDOM_WINDOWS = 4;
37
38 /**
39 * Provide a valid motion stream, to make the fuzzer more effective.
40 */
41 class NotifyStreamProvider {
42 public:
NotifyStreamProvider(FuzzedDataProvider & fdp)43 NotifyStreamProvider(FuzzedDataProvider& fdp)
44 : mFdp(fdp), mIdGenerator(IdGenerator::Source::OTHER) {}
45
nextMotion()46 std::optional<NotifyMotionArgs> nextMotion() {
47 NotifyMotionArgs args = generateFuzzedMotionArgs(mIdGenerator, mFdp, MAX_RANDOM_DISPLAYS);
48 auto [it, _] = mVerifiers.emplace(args.displayId, "Fuzz Verifier");
49 InputVerifier& verifier = it->second;
50 const Result<void> result =
51 verifier.processMovement(args.deviceId, args.source, args.action, args.actionButton,
52 args.getPointerCount(), args.pointerProperties.data(),
53 args.pointerCoords.data(), args.flags, args.buttonState);
54 if (result.ok()) {
55 return args;
56 }
57 return {};
58 }
59
60 private:
61 FuzzedDataProvider& mFdp;
62
63 IdGenerator mIdGenerator;
64
65 std::map<int32_t /*displayId*/, InputVerifier> mVerifiers;
66 };
67
scrambleWindow(FuzzedDataProvider & fdp,FakeWindowHandle & window)68 void scrambleWindow(FuzzedDataProvider& fdp, FakeWindowHandle& window) {
69 const int32_t left = fdp.ConsumeIntegralInRange<int32_t>(0, 100);
70 const int32_t top = fdp.ConsumeIntegralInRange<int32_t>(0, 100);
71 const int32_t width = fdp.ConsumeIntegralInRange<int32_t>(0, 100);
72 const int32_t height = fdp.ConsumeIntegralInRange<int32_t>(0, 100);
73
74 window.setFrame(Rect(left, top, left + width, top + height));
75 window.setSlippery(fdp.ConsumeBool());
76 window.setDupTouchToWallpaper(fdp.ConsumeBool());
77 window.setIsWallpaper(fdp.ConsumeBool());
78 window.setVisible(fdp.ConsumeBool());
79 const bool isTrustedOverlay = fdp.ConsumeBool();
80 window.setTrustedOverlay(isTrustedOverlay);
81 if (isTrustedOverlay) {
82 window.setSpy(fdp.ConsumeBool());
83 } else {
84 window.setSpy(false);
85 }
86 }
87
88 } // namespace
89
generateFuzzedWindow(FuzzedDataProvider & fdp,std::unique_ptr<InputDispatcher> & dispatcher,ui::LogicalDisplayId displayId)90 sp<FakeWindowHandle> generateFuzzedWindow(FuzzedDataProvider& fdp,
91 std::unique_ptr<InputDispatcher>& dispatcher,
92 ui::LogicalDisplayId displayId) {
93 static size_t windowNumber = 0;
94 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
95 std::string windowName = android::base::StringPrintf("Win") + std::to_string(windowNumber++);
96 sp<FakeWindowHandle> window =
97 sp<FakeWindowHandle>::make(application, dispatcher, windowName, displayId);
98
99 scrambleWindow(fdp, *window);
100 return window;
101 }
102
randomizeWindows(std::unordered_map<ui::LogicalDisplayId,std::vector<sp<FakeWindowHandle>>> & windowsPerDisplay,FuzzedDataProvider & fdp,std::unique_ptr<InputDispatcher> & dispatcher)103 void randomizeWindows(std::unordered_map<ui::LogicalDisplayId, std::vector<sp<FakeWindowHandle>>>&
104 windowsPerDisplay,
105 FuzzedDataProvider& fdp, std::unique_ptr<InputDispatcher>& dispatcher) {
106 const ui::LogicalDisplayId displayId{
107 fdp.ConsumeIntegralInRange<int32_t>(0, MAX_RANDOM_DISPLAYS - 1)};
108 std::vector<sp<FakeWindowHandle>>& windows = windowsPerDisplay[displayId];
109
110 fdp.PickValueInArray<std::function<void()>>({
111 // Add a new window
112 [&]() -> void {
113 if (windows.size() < MAX_RANDOM_WINDOWS) {
114 windows.push_back(generateFuzzedWindow(fdp, dispatcher, displayId));
115 }
116 },
117 // Remove a window
118 [&]() -> void {
119 if (windows.empty()) {
120 return;
121 }
122 const int32_t erasedPosition =
123 fdp.ConsumeIntegralInRange<int32_t>(0, windows.size() - 1);
124
125 windows.erase(windows.begin() + erasedPosition);
126 if (windows.empty()) {
127 windowsPerDisplay.erase(displayId);
128 }
129 },
130 // Change flags or move some of the existing windows
131 [&]() -> void {
132 for (auto& window : windows) {
133 if (fdp.ConsumeBool()) {
134 scrambleWindow(fdp, *window);
135 }
136 }
137 },
138 })();
139 }
140
LLVMFuzzerTestOneInput(uint8_t * data,size_t size)141 extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
142 FuzzedDataProvider fdp(data, size);
143 NotifyStreamProvider streamProvider(fdp);
144
145 FakeInputDispatcherPolicy fakePolicy;
146 auto dispatcher = std::make_unique<InputDispatcher>(fakePolicy);
147 dispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false);
148 // Start InputDispatcher thread
149 dispatcher->start();
150
151 std::unordered_map<ui::LogicalDisplayId, std::vector<sp<FakeWindowHandle>>> windowsPerDisplay;
152
153 // Randomly invoke InputDispatcher api's until randomness is exhausted.
154 while (fdp.remaining_bytes() > 0) {
155 fdp.PickValueInArray<std::function<void()>>({
156 [&]() -> void {
157 std::optional<NotifyMotionArgs> motion = streamProvider.nextMotion();
158 if (motion) {
159 dispatcher->notifyMotion(*motion);
160 }
161 },
162 [&]() -> void {
163 // Scramble the windows we currently have
164 randomizeWindows(/*byref*/ windowsPerDisplay, fdp, dispatcher);
165
166 std::vector<WindowInfo> windowInfos;
167 for (const auto& [displayId, windows] : windowsPerDisplay) {
168 for (const sp<FakeWindowHandle>& window : windows) {
169 windowInfos.emplace_back(*window->getInfo());
170 }
171 }
172
173 dispatcher->onWindowInfosChanged(
174 {windowInfos, {}, /*vsyncId=*/0, /*timestamp=*/0});
175 },
176 // Consume on all the windows
177 [&]() -> void {
178 for (const auto& [_, windows] : windowsPerDisplay) {
179 for (const sp<FakeWindowHandle>& window : windows) {
180 // To speed up the fuzzing, don't wait for consumption. If there's an
181 // event pending, this can be consumed on the next call instead.
182 // We also don't care about whether consumption succeeds here, or what
183 // kind of event is returned.
184 window->consume(0ms);
185 }
186 }
187 },
188 })();
189 }
190
191 dispatcher->stop();
192
193 return 0;
194 }
195
196 } // namespace inputdispatcher
197
198 } // namespace android