-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathseq_handler_fuzzer.cc
118 lines (99 loc) · 3.57 KB
/
seq_handler_fuzzer.cc
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
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "midis/seq_handler.h"
#include <string>
#include <base/bind.h>
#include <base/logging.h>
#include "midis/device.h"
namespace {
const int kFakeOutputPort = 0;
}
namespace midis {
// We don't have a real device whose callbacks we can run, so instead,
// we just create FakeCallbacks which contains stubs.
class FakeCallbacks {
public:
void AddDevice(std::unique_ptr<Device> device) {}
void RemoveDevice(uint32_t card_num, uint32_t device_num) {}
void HandleReceiveData(uint32_t card_id,
uint32_t device_id,
uint32_t port_id,
const char* buffer,
size_t buf_len) {}
bool IsDevicePresent(uint32_t card_num, uint32_t device_num) {
// Unused in the fuzzer, so doesn't matter.
return true;
}
bool IsPortPresent(uint32_t card_num, uint32_t device_num, uint32_t port_id) {
// Unused in the fuzzer, so doesn't matter.
return true;
}
};
// Running a fuzz test on the SeqHandler requires us to set certain
// private variables inside SeqHandler. To allow this to happen,
// we encapsulate the SeqHandler inside a FuzzerRunner class,
// and make FuzzerRunner a friend of SeqHandler.
class SeqHandlerFuzzer {
public:
void SetUpSeqHandler() {
seq_handler_ = std::make_unique<SeqHandler>(
base::Bind(&FakeCallbacks::AddDevice, base::Unretained(&callbacks_)),
base::Bind(&FakeCallbacks::RemoveDevice, base::Unretained(&callbacks_)),
base::Bind(&FakeCallbacks::HandleReceiveData,
base::Unretained(&callbacks_)),
base::Bind(&FakeCallbacks::IsDevicePresent,
base::Unretained(&callbacks_)),
base::Bind(&FakeCallbacks::IsPortPresent,
base::Unretained(&callbacks_)));
seq_handler_->decoder_ = midis::SeqHandler::CreateMidiEvent(0);
}
bool SetUpOutputPort() {
snd_seq_t* tmp_seq = nullptr;
int err = snd_seq_open(&tmp_seq, "hw", SND_SEQ_OPEN_OUTPUT, 0);
if (err != 0) {
LOG(ERROR) << "snd_seq_open fails: " << snd_strerror(err);
return false;
}
SeqHandler::ScopedSeqPtr out_client(tmp_seq);
tmp_seq = nullptr;
seq_handler_->out_client_ = std::move(out_client);
seq_handler_->out_client_id_ =
snd_seq_client_id(seq_handler_->out_client_.get());
return true;
}
// Send arbitrary data to ProcessMidiEvent() and see what happens.
void ProcessMidiEvent(const uint8_t* data, size_t size) {
snd_seq_event_t event;
size_t bytes_to_copy = sizeof(snd_seq_event_t);
if (size < bytes_to_copy) {
bytes_to_copy = size;
}
memcpy(&event, data, bytes_to_copy);
seq_handler_->ProcessMidiEvent(&event);
}
void SendMidiData(const uint8_t* data, size_t size) {
// We don't have a real output port, so we just supply a value.
// This ALSA seq interface should fail gracefully.
seq_handler_->SendMidiData(kFakeOutputPort, data, size);
}
private:
std::unique_ptr<SeqHandler> seq_handler_;
FakeCallbacks callbacks_;
};
struct Environment {
Environment() { logging::SetMinLogLevel(logging::LOGGING_ERROR); }
};
Environment* env = new Environment();
} // namespace midis
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
midis::SeqHandlerFuzzer fuzzer;
fuzzer.SetUpSeqHandler();
if (!fuzzer.SetUpOutputPort()) {
abort();
}
fuzzer.ProcessMidiEvent(data, size);
fuzzer.SendMidiData(data, size);
return 0;
}