• 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, 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