1// Copyright 2019 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 "components/exo/wayland/fuzzer/harness.h"
6
7{% for protocol in protocol_names %}
8  {% if protocol == 'wayland' %}
9    #include <wayland-client-core.h>
10    #include <wayland-client-protocol.h>
11  {% else %}
12    #include <{{protocol | replace('_','-')}}-client-protocol.h>
13  {% endif %}
14{% endfor %}
15
16#include <cstring>
17#include <functional>
18
19#include "base/check.h"
20#include "components/exo/wayland/fuzzer/actions.pb.h"
21
22namespace exo {
23namespace wayland_fuzzer {
24
25{% for interface in interfaces if interface.has_listener and interface.name != 'wl_display' %}
26  namespace {{interface.name}} {
27  {% for event in interface.events %}
28    void {{event.name}}(
29      void* data,
30      {{interface.cpp_type}} receiver
31      {% for arg in event.args %}
32        , {{arg.cpp_type}} {{arg.name}}
33      {% endfor %}
34    );
35  {% endfor %}
36  static const struct {{interface.name}}_listener kListener = {
37    {% for event in interface.events %}
38      {{event.name}},
39    {% endfor %}
40  };
41  }  // namespace {{interface.name}}
42{% endfor %}
43
44
45{% for interface in interfaces if interface.name != 'wl_registry' %}
46  namespace {{interface.name}} {
47  {% for event in interface.events %}
48    void {{event.name}}(
49      void* data,
50      {{interface.cpp_type}} receiver
51      {% for arg in event.args %}
52        , {{arg.cpp_type}} {{arg.name}}
53      {% endfor %}
54    ){
55      {% if event.is_constructor %}
56        Harness* harness = static_cast<Harness*>(data);
57        {% for arg in event.args if arg.type == 'new_id' %}
58          {{arg.cpp_type}} new_object = {{arg.name}};
59        {% endfor %}
60        {% if event.constructed_has_listener %}
61          {{event.constructed}}_add_listener(new_object, &{{event.constructed}}::kListener, harness);
62        {% endif %}
63        harness->add_{{event.constructed}}(new_object);
64      {% endif %}
65      {% for arg in event.args if arg.type == 'fd' %}
66        FILE* _f = fdopen({{arg.name}}, "w");
67	CHECK(_f);
68	fwrite(".", 1, 1, _f);
69        fclose(_f);
70      {% endfor %}
71    }
72  {% endfor %}
73  {% for request in interface.requests %}
74    void {{request.name}}(Harness* harness,
75        const actions::{{interface.name}}_{{request.name}}& action) {
76      {{interface.cpp_type}} receiver = harness->get_{{interface.name}}(action.receiver());
77      if (!receiver)
78        return;
79      {% for arg in request.args %}
80        {% if arg.type == 'object' %}
81          {{arg.cpp_type}} {{arg.name}} = harness->get_{{arg.interface}}(action.{{arg.name}}());
82          {% if not arg.nullable %}
83            if (!{{arg.name}})
84              return;
85          {% endif %}
86        {% elif arg.type == 'fd' %}
87          int {{arg.name}} = harness->GetFileDescriptor(action.{{arg.name}}());
88        {% elif arg.type == 'array' %}
89          wl_array {{arg.name}}{
90            /*size=*/action.{{arg.name}}().size(),
91            /*alloc=*/action.{{arg.name}}().capacity(),
92            /*data=*/const_cast<char*>(action.{{arg.name}}().data())
93          };
94        {% endif %}
95      {% endfor %}
96
97      {% if request.is_constructor %}
98        struct {{request.constructed}}* new_object =
99      {% endif %}
100      // Invoke the wayland method.  We need ::method_name in order to
101      // disambiguate methods which might collide with
102      // interface/namespace names.
103      ::{{interface.name}}_{{request.name}}(receiver
104        {% for arg in request.args %}
105          {% if arg.type == 'object' or arg.type == 'fd' %}
106            , {{arg.name}}
107          {% elif arg.type == 'array' %}
108            , &{{arg.name}}
109          {% elif arg.type != 'new_id' %}
110            , action.{{arg.name}}(){% if arg.type == 'string' %}.c_str(){% endif %}
111          {% endif %}
112        {% endfor %}
113      );
114      {% if request.is_constructor %}
115        {% if request.constructed_has_listener %}
116          {{request.constructed}}_add_listener(new_object, &{{request.constructed}}::kListener, harness);
117        {% endif %}
118        harness->add_{{request.constructed}}(new_object);
119      {% elif request.is_destructor %}
120        harness->remove_{{interface.name}}(action.receiver());
121      {% endif %}
122    }
123  {% endfor %}
124  }  // namespace {{interface.name}}
125{% endfor %}
126
127namespace wl_registry {
128
129void bind(Harness* harness, const actions::wl_registry_bind& action) {
130  struct wl_registry* receiver = harness->get_wl_registry(action.receiver());
131  if (!receiver)
132    return;
133  switch (action.global()) {
134    {% for interface in interfaces if interface.is_global %}
135      case actions::global::{{interface.name}}: {
136        if (harness->{{interface.name}}_globals_.empty())
137          return;
138        void* new_object = wl_registry_bind(
139            receiver, harness->{{interface.name}}_globals_[0].first,
140            &{{interface.name}}_interface, harness->{{interface.name}}_globals_[0].second);
141        {% if interface.has_listener and interface.name != 'wl_display' %}
142          {{interface.name}}_add_listener(static_cast<::{{interface.name}}*>(new_object), &{{interface.name}}::kListener, harness);
143        {% endif %}
144        harness->add_{{interface.name}}(
145            static_cast<::{{interface.name}}*>(new_object));
146        break;
147      }
148    {% endfor %}
149    case actions::global::global_INT_MIN_SENTINEL_DO_NOT_USE_:
150    case actions::global::global_INT_MAX_SENTINEL_DO_NOT_USE_:
151    case actions::global::GLOBAL_UNSPECIFIED:
152      break;
153  }
154}
155
156void global(void* data,
157            struct wl_registry* registry,
158            uint32_t name,
159            const char* interface,
160            uint32_t version) {
161  Harness* harness = static_cast<Harness*>(data);
162  {% for interface in interfaces if interface.is_global %}
163    if (strcmp(interface, "{{interface.name}}") == 0) {
164      harness->{{interface.name}}_globals_.emplace_back(name, version);
165      return;
166    }
167  {% endfor %}
168}
169
170}  // namespace wl_registry
171
172void wl_registry::global_remove(void* data, struct wl_registry* registry, uint32_t name) {}
173
174Harness::Harness() {
175  wl_display_list_.emplace_back(wl_display_connect(nullptr));
176  DCHECK(wl_display_list_.front());
177}
178
179Harness::~Harness() {
180  {% for interface in interfaces %}
181    for (auto ifc : {{interface.name}}_list_) {
182      if (ifc)
183        {% if interface.name == "wl_display" %}
184          wl_display_disconnect(ifc);
185        {% else %}
186          free(ifc);
187        {% endif %}
188    }
189  {% endfor %}
190}
191
192void Harness::Run(const actions::actions& all_steps) {
193  for (const actions::action& current : all_steps.acts())
194    Run(current);
195}
196
197void Harness::Run(const actions::action& current_step) {
198  switch (current_step.act_case()) {
199    case actions::action::ActCase::ACT_NOT_SET:
200      wl_display_roundtrip(wl_display_list_.front());
201      break;
202    {% for interface in interfaces %}
203      {% for request in interface.requests %}
204        case actions::action::ActCase::kAct{{(interface.name + "_" + request.name) | replace('_', ' ') | title | replace(' ', '')}}:
205          {{interface.name}}::{{request.name}}(this, current_step.act_{{interface.name}}_{{request.name}}());
206          break;
207      {% endfor %}
208    {% endfor %}
209  }
210}
211
212int Harness::GetFileDescriptor(int id) {
213  if (shared_memory_map_.count(id) == 0) {
214    base::UnsafeSharedMemoryRegion region =
215        base::UnsafeSharedMemoryRegion::Create(1);
216    shared_memory_map_.emplace(id, std::move(region));
217  }
218  base::subtle::ScopedFDPair fd_pair =
219      base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
220          shared_memory_map_[id].Duplicate()).PassPlatformHandle();
221  return fd_pair.fd.release();
222}
223
224}  // namespace wayland_fuzzer
225}  // namespace exo
226