forked from hathach/tinyusb
-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmsc_fuzz.cc
162 lines (140 loc) · 5.11 KB
/
msc_fuzz.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
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
#include "fuzz/fuzz_private.h"
#include "tusb.h"
#include <cassert>
#include <array>
#include <limits>
#if CFG_TUD_MSC==1
// Whether host does safe eject.
// tud_msc_get_maxlun_cb returns a uint8_t so the max logical units that are
// allowed is 255, so we need to keep track of 255 fuzzed logical units.
static std::array<bool, std::numeric_limits<uint8_t>::max()> ejected = {false};
extern "C" {
// Invoked when received SCSI_CMD_INQUIRY
// Application fill vendor id, product id and revision with string up to 8, 16,
// 4 characters respectively
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8],
uint8_t product_id[16], uint8_t product_rev[4]) {
(void)lun;
assert(_fuzz_data_provider.has_value());
std::string vid = _fuzz_data_provider->ConsumeBytesAsString(8);
std::string pid = _fuzz_data_provider->ConsumeBytesAsString(16);
std::string rev = _fuzz_data_provider->ConsumeBytesAsString(4);
memcpy(vendor_id, vid.c_str(), strlen(vid.c_str()));
memcpy(product_id, pid.c_str(), strlen(pid.c_str()));
memcpy(product_rev, rev.c_str(), strlen(rev.c_str()));
}
// Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted
bool tud_msc_test_unit_ready_cb(uint8_t lun) {
// RAM disk is ready until ejected
if (ejected[lun]) {
// Additional Sense 3A-00 is NOT_FOUND
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00);
return false;
}
return _fuzz_data_provider->ConsumeBool();
}
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and
// SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size Application update
// block count and block size
void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count,
uint16_t *block_size) {
(void)lun;
*block_count = _fuzz_data_provider->ConsumeIntegral<uint32_t>();
*block_size = _fuzz_data_provider->ConsumeIntegral<uint16_t>();
}
// Invoked when received Start Stop Unit command
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start,
bool load_eject) {
(void)power_condition;
assert(_fuzz_data_provider.has_value());
if (load_eject) {
if (start) {
// load disk storage
} else {
// unload disk storage
ejected[lun] = true;
}
}
return _fuzz_data_provider->ConsumeBool();
}
// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset,
void *buffer, uint32_t bufsize) {
assert(_fuzz_data_provider.has_value());
(void)lun;
(void)lba;
(void)offset;
std::vector<uint8_t> consumed_buffer = _fuzz_data_provider->ConsumeBytes<uint8_t>(
_fuzz_data_provider->ConsumeIntegralInRange<uint32_t>(0, bufsize));
memcpy(buffer, consumed_buffer.data(), consumed_buffer.size());
// Sometimes return an error code;
if (_fuzz_data_provider->ConsumeBool()) {
return _fuzz_data_provider->ConsumeIntegralInRange(
std::numeric_limits<int32_t>::min(), -1);
}
return consumed_buffer.size();
}
bool tud_msc_is_writable_cb(uint8_t lun) {
assert(_fuzz_data_provider.has_value());
(void)lun;
return _fuzz_data_provider->ConsumeBool();
}
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and return number of written bytes
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset,
uint8_t *buffer, uint32_t bufsize) {
// Ignore these as they are outputs and don't affect the return value.
(void)lun;
(void)lba;
(void)offset;
(void)buffer;
assert(_fuzz_data_provider.has_value());
// -ve error codes -> bufsize.
return _fuzz_data_provider->ConsumeIntegralInRange<int32_t>(
std::numeric_limits<int32_t>::min(), bufsize);
}
// Callback invoked when received an SCSI command not in built-in list below
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
// - READ10 and WRITE10 has their own callbacks
int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer,
uint16_t bufsize) {
(void)buffer;
(void)bufsize;
assert(_fuzz_data_provider.has_value());
switch (scsi_cmd[0]) {
case SCSI_CMD_TEST_UNIT_READY:
break;
case SCSI_CMD_INQUIRY:
break;
case SCSI_CMD_MODE_SELECT_6:
break;
case SCSI_CMD_MODE_SENSE_6:
break;
case SCSI_CMD_START_STOP_UNIT:
break;
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
break;
case SCSI_CMD_READ_CAPACITY_10:
break;
case SCSI_CMD_REQUEST_SENSE:
break;
case SCSI_CMD_READ_FORMAT_CAPACITY:
break;
case SCSI_CMD_READ_10:
break;
case SCSI_CMD_WRITE_10:
break;
default:
// Set Sense = Invalid Command Operation
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
return _fuzz_data_provider->ConsumeIntegralInRange<int32_t>(
std::numeric_limits<int32_t>::min(), -1);
}
return 0;
}
}
#endif