1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <stddef.h>
6 #include <stdint.h>
7 #include <string.h>
8 
9 #include <fuzzer/FuzzedDataProvider.h>
10 
11 #include <vector>
12 
13 #include "base/command_line.h"
14 #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
15 #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
16 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
17 #include "components/viz/service/hit_test/hit_test_aggregator.h"
18 #include "components/viz/service/hit_test/hit_test_manager.h"
19 #include "components/viz/test/compositor_frame_helpers.h"
20 #include "components/viz/test/test_latest_local_surface_id_lookup_delegate.h"
21 
22 namespace {
23 
24 constexpr uint32_t kMaxDepthAllowed = 255;
25 
GetNextUInt32NonZero(FuzzedDataProvider * fuzz)26 uint32_t GetNextUInt32NonZero(FuzzedDataProvider* fuzz) {
27   return fuzz->ConsumeIntegralInRange<uint32_t>(
28       1, std::numeric_limits<uint32_t>::max());
29 }
30 
GetNextTransform(FuzzedDataProvider * fuzz)31 gfx::Transform GetNextTransform(FuzzedDataProvider* fuzz) {
32   gfx::Transform transform;
33   if (fuzz->ConsumeBool() && fuzz->remaining_bytes() >= sizeof(transform)) {
34     std::vector<uint8_t> matrix_bytes =
35         fuzz->ConsumeBytes<uint8_t>(sizeof(gfx::Transform));
36     memcpy(&transform, matrix_bytes.data(), matrix_bytes.size());
37   }
38   return transform;
39 }
40 
41 void SubmitHitTestRegionList(
42     FuzzedDataProvider* fuzz,
43     viz::TestLatestLocalSurfaceIdLookupDelegate* delegate,
44     viz::FrameSinkManagerImpl* frame_sink_manager,
45     const viz::SurfaceId& surface_id,
46     bool support_is_root,
47     const uint32_t depth);
48 
AddHitTestRegion(FuzzedDataProvider * fuzz,std::vector<viz::HitTestRegion> * regions,uint32_t child_count,viz::TestLatestLocalSurfaceIdLookupDelegate * delegate,viz::FrameSinkManagerImpl * frame_sink_manager,const viz::SurfaceId & surface_id,const uint32_t depth)49 void AddHitTestRegion(FuzzedDataProvider* fuzz,
50                       std::vector<viz::HitTestRegion>* regions,
51                       uint32_t child_count,
52                       viz::TestLatestLocalSurfaceIdLookupDelegate* delegate,
53                       viz::FrameSinkManagerImpl* frame_sink_manager,
54                       const viz::SurfaceId& surface_id,
55                       const uint32_t depth) {
56   if (!child_count || depth > kMaxDepthAllowed)
57     return;
58 
59   // If there's not enough space left for a HitTestRegion, then skip.
60   if (fuzz->remaining_bytes() < sizeof(viz::HitTestRegion))
61     return;
62 
63   viz::HitTestRegion hit_test_region;
64   hit_test_region.flags = fuzz->ConsumeIntegral<uint32_t>();
65   hit_test_region.async_hit_test_reasons = fuzz->ConsumeIntegral<uint32_t>();
66   if (fuzz->ConsumeBool())
67     hit_test_region.flags |= viz::HitTestRegionFlags::kHitTestChildSurface;
68   hit_test_region.frame_sink_id = viz::FrameSinkId(
69       fuzz->ConsumeIntegral<uint32_t>(), fuzz->ConsumeIntegral<uint32_t>());
70   hit_test_region.rect =
71       gfx::Rect(fuzz->ConsumeIntegral<int>(), fuzz->ConsumeIntegral<int>(),
72                 fuzz->ConsumeIntegral<int>(), fuzz->ConsumeIntegral<int>());
73   hit_test_region.transform = GetNextTransform(fuzz);
74 
75   if (fuzz->ConsumeBool() &&
76       (hit_test_region.flags & viz::HitTestRegionFlags::kHitTestChildSurface)) {
77     // If there's not enough space left for a LocalSurfaceId, then skip.
78     if (fuzz->remaining_bytes() < sizeof(viz::LocalSurfaceId))
79       return;
80 
81     uint32_t last_frame_sink_id_client_id =
82         surface_id.frame_sink_id().client_id();
83     uint32_t last_frame_sink_id_sink_id = surface_id.frame_sink_id().sink_id();
84     viz::FrameSinkId frame_sink_id(last_frame_sink_id_client_id + 1,
85                                    last_frame_sink_id_sink_id + 1);
86     viz::LocalSurfaceId local_surface_id(GetNextUInt32NonZero(fuzz),
87                                          GetNextUInt32NonZero(fuzz),
88                                          base::UnguessableToken::Create());
89     SubmitHitTestRegionList(fuzz, delegate, frame_sink_manager,
90                             viz::SurfaceId(frame_sink_id, local_surface_id),
91                             false /* support_is_root */, depth + 1);
92   }
93 
94   regions->push_back(std::move(hit_test_region));
95   AddHitTestRegion(fuzz, regions, child_count - 1, delegate, frame_sink_manager,
96                    surface_id, depth + 1);
97 }
98 
SubmitHitTestRegionList(FuzzedDataProvider * fuzz,viz::TestLatestLocalSurfaceIdLookupDelegate * delegate,viz::FrameSinkManagerImpl * frame_sink_manager,const viz::SurfaceId & surface_id,bool support_is_root,const uint32_t depth)99 void SubmitHitTestRegionList(
100     FuzzedDataProvider* fuzz,
101     viz::TestLatestLocalSurfaceIdLookupDelegate* delegate,
102     viz::FrameSinkManagerImpl* frame_sink_manager,
103     const viz::SurfaceId& surface_id,
104     bool support_is_root,
105     const uint32_t depth) {
106   // If there's not enough space left for a HitTestRegionList, then skip.
107   if (fuzz->remaining_bytes() < sizeof(viz::HitTestRegionList) + sizeof(bool) ||
108       depth > kMaxDepthAllowed) {
109     return;
110   }
111 
112   base::Optional<viz::HitTestRegionList> hit_test_region_list;
113   if (fuzz->ConsumeBool()) {
114     hit_test_region_list.emplace();
115     hit_test_region_list->flags = fuzz->ConsumeIntegral<uint32_t>();
116     hit_test_region_list->async_hit_test_reasons =
117         fuzz->ConsumeIntegral<uint32_t>();
118     if (fuzz->ConsumeBool())
119       hit_test_region_list->flags |=
120           viz::HitTestRegionFlags::kHitTestChildSurface;
121     hit_test_region_list->bounds =
122         gfx::Rect(fuzz->ConsumeIntegral<int>(), fuzz->ConsumeIntegral<int>(),
123                   fuzz->ConsumeIntegral<int>(), fuzz->ConsumeIntegral<int>());
124     hit_test_region_list->transform = GetNextTransform(fuzz);
125 
126     uint32_t child_count = fuzz->ConsumeIntegral<uint32_t>();
127     AddHitTestRegion(fuzz, &hit_test_region_list->regions, child_count,
128                      delegate, frame_sink_manager, surface_id, depth + 1);
129   }
130 
131   delegate->SetSurfaceIdMap(surface_id);
132   viz::CompositorFrameSinkSupport support(
133       nullptr /* client */, frame_sink_manager, surface_id.frame_sink_id(),
134       support_is_root);
135   support.SubmitCompositorFrame(surface_id.local_surface_id(),
136                                 viz::MakeDefaultCompositorFrame(),
137                                 std::move(hit_test_region_list));
138 }
139 
140 }  // namespace
141 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t num_bytes)142 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t num_bytes) {
143   FuzzedDataProvider fuzz(data, num_bytes);
144   viz::ServerSharedBitmapManager shared_bitmap_manager;
145   viz::FrameSinkManagerImpl frame_sink_manager(&shared_bitmap_manager);
146   viz::TestLatestLocalSurfaceIdLookupDelegate delegate;
147   viz::TestLatestLocalSurfaceIdLookupDelegate* lsi_delegate =
148       fuzz.ConsumeBool() ? &delegate : nullptr;
149 
150   // If there's not enough space left for a LocalSurfaceId, then skip.
151   if (fuzz.remaining_bytes() < sizeof(viz::LocalSurfaceId))
152     return 0;
153 
154   constexpr uint32_t root_client_id = 1;
155   constexpr uint32_t root_sink_id = 1;
156   viz::FrameSinkId frame_sink_id(root_client_id, root_sink_id);
157   viz::LocalSurfaceId local_surface_id(GetNextUInt32NonZero(&fuzz),
158                                        GetNextUInt32NonZero(&fuzz),
159                                        base::UnguessableToken::Create());
160   viz::SurfaceId surface_id(frame_sink_id, local_surface_id);
161   viz::HitTestAggregator aggregator(
162       frame_sink_manager.hit_test_manager(), &frame_sink_manager, lsi_delegate,
163       frame_sink_id, 10 /* initial_region_size */, 100 /* max_region_size */);
164 
165   SubmitHitTestRegionList(&fuzz, &delegate, &frame_sink_manager, surface_id,
166                           true /* support_is_root */, 0 /* depth */);
167 
168   viz::SurfaceId aggregate_surface_id = surface_id;
169   if (fuzz.ConsumeBool() && fuzz.remaining_bytes() >= sizeof(viz::SurfaceId)) {
170     viz::FrameSinkId frame_sink_id(GetNextUInt32NonZero(&fuzz),
171                                    GetNextUInt32NonZero(&fuzz));
172     viz::LocalSurfaceId local_surface_id(GetNextUInt32NonZero(&fuzz),
173                                          GetNextUInt32NonZero(&fuzz),
174                                          base::UnguessableToken::Create());
175     aggregate_surface_id = viz::SurfaceId(frame_sink_id, local_surface_id);
176   }
177   aggregator.Aggregate(aggregate_surface_id);
178   viz::Surface* surface = frame_sink_manager.surface_manager()->GetSurfaceForId(
179       aggregate_surface_id);
180   if (surface)
181     frame_sink_manager.surface_manager()->SurfaceDestroyed(surface);
182 
183   return 0;
184 }
185