• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,
52                                          args.getPointerCount(), args.pointerProperties.data(),
53                                          args.pointerCoords.data(), args.flags);
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     window.setPreventSplitting(fdp.ConsumeBool());
80     const bool isTrustedOverlay = fdp.ConsumeBool();
81     window.setTrustedOverlay(isTrustedOverlay);
82     if (isTrustedOverlay) {
83         window.setSpy(fdp.ConsumeBool());
84     } else {
85         window.setSpy(false);
86     }
87 }
88 
89 } // namespace
90 
generateFuzzedWindow(FuzzedDataProvider & fdp,std::unique_ptr<InputDispatcher> & dispatcher,ui::LogicalDisplayId displayId)91 sp<FakeWindowHandle> generateFuzzedWindow(FuzzedDataProvider& fdp,
92                                           std::unique_ptr<InputDispatcher>& dispatcher,
93                                           ui::LogicalDisplayId displayId) {
94     static size_t windowNumber = 0;
95     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
96     std::string windowName = android::base::StringPrintf("Win") + std::to_string(windowNumber++);
97     sp<FakeWindowHandle> window =
98             sp<FakeWindowHandle>::make(application, dispatcher, windowName, displayId);
99 
100     scrambleWindow(fdp, *window);
101     return window;
102 }
103 
randomizeWindows(std::unordered_map<ui::LogicalDisplayId,std::vector<sp<FakeWindowHandle>>> & windowsPerDisplay,FuzzedDataProvider & fdp,std::unique_ptr<InputDispatcher> & dispatcher)104 void randomizeWindows(std::unordered_map<ui::LogicalDisplayId, std::vector<sp<FakeWindowHandle>>>&
105                               windowsPerDisplay,
106                       FuzzedDataProvider& fdp, std::unique_ptr<InputDispatcher>& dispatcher) {
107     const ui::LogicalDisplayId displayId{
108             fdp.ConsumeIntegralInRange<int32_t>(0, MAX_RANDOM_DISPLAYS - 1)};
109     std::vector<sp<FakeWindowHandle>>& windows = windowsPerDisplay[displayId];
110 
111     fdp.PickValueInArray<std::function<void()>>({
112             // Add a new window
113             [&]() -> void {
114                 if (windows.size() < MAX_RANDOM_WINDOWS) {
115                     windows.push_back(generateFuzzedWindow(fdp, dispatcher, displayId));
116                 }
117             },
118             // Remove a window
119             [&]() -> void {
120                 if (windows.empty()) {
121                     return;
122                 }
123                 const int32_t erasedPosition =
124                         fdp.ConsumeIntegralInRange<int32_t>(0, windows.size() - 1);
125 
126                 windows.erase(windows.begin() + erasedPosition);
127                 if (windows.empty()) {
128                     windowsPerDisplay.erase(displayId);
129                 }
130             },
131             // Change flags or move some of the existing windows
132             [&]() -> void {
133                 for (auto& window : windows) {
134                     if (fdp.ConsumeBool()) {
135                         scrambleWindow(fdp, *window);
136                     }
137                 }
138             },
139     })();
140 }
141 
LLVMFuzzerTestOneInput(uint8_t * data,size_t size)142 extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
143     FuzzedDataProvider fdp(data, size);
144     NotifyStreamProvider streamProvider(fdp);
145 
146     FakeInputDispatcherPolicy fakePolicy;
147     auto dispatcher = std::make_unique<InputDispatcher>(fakePolicy);
148     dispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false);
149     // Start InputDispatcher thread
150     dispatcher->start();
151 
152     std::unordered_map<ui::LogicalDisplayId, std::vector<sp<FakeWindowHandle>>> windowsPerDisplay;
153 
154     // Randomly invoke InputDispatcher api's until randomness is exhausted.
155     while (fdp.remaining_bytes() > 0) {
156         fdp.PickValueInArray<std::function<void()>>({
157                 [&]() -> void {
158                     std::optional<NotifyMotionArgs> motion = streamProvider.nextMotion();
159                     if (motion) {
160                         dispatcher->notifyMotion(*motion);
161                     }
162                 },
163                 [&]() -> void {
164                     // Scramble the windows we currently have
165                     randomizeWindows(/*byref*/ windowsPerDisplay, fdp, dispatcher);
166 
167                     std::vector<WindowInfo> windowInfos;
168                     for (const auto& [displayId, windows] : windowsPerDisplay) {
169                         for (const sp<FakeWindowHandle>& window : windows) {
170                             windowInfos.emplace_back(*window->getInfo());
171                         }
172                     }
173 
174                     dispatcher->onWindowInfosChanged(
175                             {windowInfos, {}, /*vsyncId=*/0, /*timestamp=*/0});
176                 },
177                 // Consume on all the windows
178                 [&]() -> void {
179                     for (const auto& [_, windows] : windowsPerDisplay) {
180                         for (const sp<FakeWindowHandle>& window : windows) {
181                             // To speed up the fuzzing, don't wait for consumption. If there's an
182                             // event pending, this can be consumed on the next call instead.
183                             // We also don't care about whether consumption succeeds here, or what
184                             // kind of event is returned.
185                             window->consume(0ms);
186                         }
187                     }
188                 },
189         })();
190     }
191 
192     dispatcher->stop();
193 
194     return 0;
195 }
196 
197 } // namespace inputdispatcher
198 
199 } // namespace android