File: zeroconf_printer_detector_fuzzer.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (196 lines) | stat: -rw-r--r-- 7,774 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <fuzzer/FuzzedDataProvider.h>

#include <cstddef>
#include <cstdint>
#include <map>
#include <string>
#include <vector>

#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/task_environment.h"
#include "chrome/browser/ash/printing/zeroconf_printer_detector.h"
#include "chrome/browser/local_discovery/service_discovery_device_lister.h"

namespace {

// Describes a single call to ZeroconfDetector.
struct CallToDelegate {
  // method to call
  enum CallType {
    kOnDeviceChanged = 0,
    kOnDeviceRemoved = 1,
    kOnDeviceCacheFlushed = 2,
    kMaxValue = 2
  } call_type;
  // parameters (depends on |call_type|)
  bool added;
  local_discovery::ServiceDescription description;
};

// Shortcut for a map of unique_ptr<ServiceDiscoveryDeviceLister>.
// The key is a name of a service type.
using MapOfListers =
    std::map<std::string,
             std::unique_ptr<local_discovery::ServiceDiscoveryDeviceLister>>;

// Objects of this class fuzzes ZeroconfDetector by calling methods from
// local_discovery::ServiceDiscoveryDeviceLister::Delegate interface.
class FuzzDeviceLister : public local_discovery::ServiceDiscoveryDeviceLister {
 public:
  // |calls| contains definition of calls to made in reverse order.
  FuzzDeviceLister(const std::string& service_type,
                   const std::vector<CallToDelegate>& calls)
      : service_type_(service_type), calls_(calls) {}

  ~FuzzDeviceLister() override = default;

  // Sets a pointer to ZeroconfDetector object and starts fuzzing it.
  void SetDelegate(
      local_discovery::ServiceDiscoveryDeviceLister::Delegate* delegate) {
    delegate_ = delegate;
    base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE, base::BindOnce(&FuzzDeviceLister::CallDelegate,
                                  base::Unretained(this)));
  }

  void Start() override {}
  void DiscoverNewDevices() override {}
  const std::string& service_type() const override { return service_type_; }

 private:
  // Executes single call to
  // local_discovery::ServiceDiscoveryDeviceLister::Delegate interface.
  // This method schedules for execution last call from calls_, removes it from
  // calls_ and at the end schedules itself for execution. It does nothing
  // when calls_ is empty.
  void CallDelegate() {
    if (calls_.empty())
      return;
    const CallToDelegate call = calls_.back();
    calls_.pop_back();
    switch (call.call_type) {
      case CallToDelegate::kOnDeviceChanged:
        base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
            FROM_HERE,
            base::BindOnce(&local_discovery::ServiceDiscoveryDeviceLister::
                               Delegate::OnDeviceChanged,
                           base::Unretained(delegate_), service_type_,
                           call.added, call.description));
        break;
      case CallToDelegate::kOnDeviceRemoved:
        base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
            FROM_HERE,
            base::BindOnce(&local_discovery::ServiceDiscoveryDeviceLister::
                               Delegate::OnDeviceRemoved,
                           base::Unretained(delegate_), service_type_,
                           call.description.service_name));
        break;
      case CallToDelegate::kOnDeviceCacheFlushed:
        base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
            FROM_HERE,
            base::BindOnce(&local_discovery::ServiceDiscoveryDeviceLister::
                               Delegate::OnDeviceCacheFlushed,
                           base::Unretained(delegate_), service_type_));
        break;
    }
    base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE, base::BindOnce(&FuzzDeviceLister::CallDelegate,
                                  base::Unretained(this)));
  }

  raw_ptr<local_discovery::ServiceDiscoveryDeviceLister::Delegate> delegate_ =
      nullptr;
  std::string service_type_;
  std::vector<CallToDelegate> calls_;
};

// Helper for creating a lister.
void CreateLister(const std::string& service_type,
                  const std::vector<CallToDelegate>& calls,
                  MapOfListers* listers) {
  std::unique_ptr<FuzzDeviceLister> fuzz_lister =
      std::make_unique<FuzzDeviceLister>(service_type, std::move(calls));
  listers->emplace(service_type, std::move(fuzz_lister));
}

// Helper for creating a vector of (fuzzing) calls to make.
std::vector<CallToDelegate> CreateFuzzCalls(FuzzedDataProvider* fuzz_data) {
  // local function to generate random int
  auto RandInt = [fuzz_data](int min, int max) -> int {
    return fuzz_data->ConsumeIntegralInRange(min, max);
  };
  // local function to generate random string with random length
  auto RandStr = [fuzz_data](size_t max_length) -> std::string {
    return fuzz_data->ConsumeRandomLengthString(max_length);
  };
  // fuzzing parameters
  constexpr size_t kMaxNumberOfCalls = 100;
  constexpr size_t kMaxNameLength = 1000;
  constexpr size_t kMaxMetadataEntriesCount = 1000;
  constexpr size_t kMaxMetadataEntryLength = 1000;
  // an array of fuzzing calls
  std::vector<CallToDelegate> calls(RandInt(0, kMaxNumberOfCalls));
  // in this array we store names of created services
  std::vector<std::string> names_history;
  names_history.reserve(calls.size() / 2);
  // generates random fuzzing calls
  for (auto& call : calls) {
    call.call_type = static_cast<CallToDelegate::CallType>(
        RandInt(0, CallToDelegate::CallType::kMaxValue));
    switch (call.call_type) {
      case CallToDelegate::kOnDeviceChanged:
        call.description.service_name = RandStr(kMaxNameLength);
        call.description.metadata.resize(RandInt(0, kMaxMetadataEntriesCount));
        for (auto& text : call.description.metadata)
          text = RandStr(kMaxMetadataEntryLength);
        names_history.push_back(call.description.service_name);
        break;
      case CallToDelegate::kOnDeviceRemoved:
        // in 10% of cases random string is used as service name, in the rest
        // 90% one of the name is picked from names_history
        if (names_history.empty() || RandInt(0, 9) == 0) {
          call.description.service_name = RandStr(kMaxNameLength);
        } else {
          const int n = names_history.size();
          call.description.service_name = names_history[RandInt(0, n - 1)];
        }
        break;
      case CallToDelegate::kOnDeviceCacheFlushed:
        break;
    }
  }
  return calls;
}

}  // namespace

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  base::test::TaskEnvironment task_environment;
  FuzzedDataProvider fuzz_data(data, size);
  // Creating listers in similar way as in "standard" constructor of
  // ZeroconfPrinterDetector.
  MapOfListers listers;
  std::vector<CallToDelegate> calls = CreateFuzzCalls(&fuzz_data);
  CreateLister(ash::ZeroconfPrinterDetector::kIppServiceName, calls, &listers);
  CreateLister(ash::ZeroconfPrinterDetector::kIppsServiceName, calls, &listers);
  CreateLister(ash::ZeroconfPrinterDetector::kIppEverywhereServiceName, calls,
               &listers);
  CreateLister(ash::ZeroconfPrinterDetector::kIppsEverywhereServiceName, calls,
               &listers);
  // Creating an object of ZeroconfPrinterDetector to fuzz.
  auto detector = ash::ZeroconfPrinterDetector::CreateForTesting(
      &listers, /*ipp_reject_list=*/{});
  for (auto& lf : listers) {
    static_cast<FuzzDeviceLister*>(lf.second.get())
        ->SetDelegate(detector.get());
  }
  // Fuzzing.
  task_environment.RunUntilIdle();
  return 0;
}