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