Coverage Report

Created: 2025-12-11 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tinyusb/test/fuzz/msc_fuzz.cc
Line
Count
Source
1
#include "fuzz/fuzz_private.h"
2
#include "tusb.h"
3
#include <cassert>
4
#include <array>
5
#include <limits>
6
7
#if CFG_TUD_MSC==1
8
9
// Whether host does safe eject.
10
// tud_msc_get_maxlun_cb returns a uint8_t so the max logical units that are
11
// allowed is 255, so we need to keep track of 255 fuzzed logical units.
12
static std::array<bool, std::numeric_limits<uint8_t>::max()> ejected = {false};
13
14
extern "C" {
15
// Invoked when received SCSI_CMD_INQUIRY
16
// Application fill vendor id, product id and revision with string up to 8, 16,
17
// 4 characters respectively
18
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8],
19
                        uint8_t product_id[16], uint8_t product_rev[4]) {
20
  (void)lun;
21
  assert(_fuzz_data_provider.has_value());
22
23
  std::string vid = _fuzz_data_provider->ConsumeBytesAsString(8);
24
  std::string pid = _fuzz_data_provider->ConsumeBytesAsString(16);
25
  std::string rev = _fuzz_data_provider->ConsumeBytesAsString(4);
26
27
  memcpy(vendor_id, vid.c_str(), strlen(vid.c_str()));
28
  memcpy(product_id, pid.c_str(), strlen(pid.c_str()));
29
  memcpy(product_rev, rev.c_str(), strlen(rev.c_str()));
30
}
31
32
// Invoked when received Test Unit Ready command.
33
// return true allowing host to read/write this LUN e.g SD card inserted
34
0
bool tud_msc_test_unit_ready_cb(uint8_t lun) {
35
  // RAM disk is ready until ejected
36
0
  if (ejected[lun]) {
37
    // Additional Sense 3A-00 is NOT_FOUND
38
0
    tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00);
39
0
    return false;
40
0
  }
41
42
0
  return _fuzz_data_provider->ConsumeBool();
43
0
}
44
45
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and
46
// SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size Application update
47
// block count and block size
48
void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count,
49
0
                         uint16_t *block_size) {
50
0
  (void)lun;
51
0
  *block_count = _fuzz_data_provider->ConsumeIntegral<uint32_t>();
52
0
  *block_size = _fuzz_data_provider->ConsumeIntegral<uint16_t>();
53
0
}
54
55
// Invoked when received Start Stop Unit command
56
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
57
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
58
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start,
59
                           bool load_eject) {
60
  (void)power_condition;
61
  assert(_fuzz_data_provider.has_value());
62
63
  if (load_eject) {
64
    if (start) {
65
      // load disk storage
66
    } else {
67
      // unload disk storage
68
      ejected[lun] = true;
69
    }
70
  }
71
72
  return _fuzz_data_provider->ConsumeBool();
73
}
74
75
// Callback invoked when received READ10 command.
76
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
77
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset,
78
0
                          void *buffer, uint32_t bufsize) {
79
0
  assert(_fuzz_data_provider.has_value());
80
0
  (void)lun;
81
0
  (void)lba;
82
0
  (void)offset;
83
84
0
  std::vector<uint8_t> consumed_buffer = _fuzz_data_provider->ConsumeBytes<uint8_t>(
85
0
      _fuzz_data_provider->ConsumeIntegralInRange<uint32_t>(0, bufsize));
86
0
  memcpy(buffer, consumed_buffer.data(), consumed_buffer.size());
87
88
  // Sometimes return an error code;
89
0
  if (_fuzz_data_provider->ConsumeBool()) {
90
0
    return _fuzz_data_provider->ConsumeIntegralInRange(
91
0
        std::numeric_limits<int32_t>::min(), -1);
92
0
  }
93
94
0
  return consumed_buffer.size();
95
0
}
96
97
bool tud_msc_is_writable_cb(uint8_t lun) {
98
  assert(_fuzz_data_provider.has_value());
99
  (void)lun;
100
  return _fuzz_data_provider->ConsumeBool();
101
}
102
103
// Callback invoked when received WRITE10 command.
104
// Process data in buffer to disk's storage and return number of written bytes
105
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset,
106
0
                           uint8_t *buffer, uint32_t bufsize) {
107
  // Ignore these as they are outputs and don't affect the return value.
108
0
  (void)lun;
109
0
  (void)lba;
110
0
  (void)offset;
111
0
  (void)buffer;
112
0
  assert(_fuzz_data_provider.has_value());
113
114
  // -ve error codes -> bufsize.
115
0
  return _fuzz_data_provider->ConsumeIntegralInRange<int32_t>(
116
0
      std::numeric_limits<int32_t>::min(), bufsize);
117
0
}
118
119
// Callback invoked when received an SCSI command not in built-in list below
120
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
121
// - READ10 and WRITE10 has their own callbacks
122
int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer,
123
0
                        uint16_t bufsize) {
124
0
  (void)buffer;
125
0
  (void)bufsize;
126
0
  assert(_fuzz_data_provider.has_value());
127
128
0
  switch (scsi_cmd[0]) {
129
0
  case SCSI_CMD_TEST_UNIT_READY:
130
0
    break;
131
0
  case SCSI_CMD_INQUIRY:
132
0
    break;
133
0
  case SCSI_CMD_MODE_SELECT_6:
134
0
    break;
135
0
  case SCSI_CMD_MODE_SENSE_6:
136
0
    break;
137
0
  case SCSI_CMD_START_STOP_UNIT:
138
0
    break;
139
0
  case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
140
0
    break;
141
0
  case SCSI_CMD_READ_CAPACITY_10:
142
0
    break;
143
0
  case SCSI_CMD_REQUEST_SENSE:
144
0
    break;
145
0
  case SCSI_CMD_READ_FORMAT_CAPACITY:
146
0
    break;
147
0
  case SCSI_CMD_READ_10:
148
0
    break;
149
0
  case SCSI_CMD_WRITE_10:
150
0
    break;
151
0
  default:
152
    // Set Sense = Invalid Command Operation
153
0
    tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
154
0
    return _fuzz_data_provider->ConsumeIntegralInRange<int32_t>(
155
0
        std::numeric_limits<int32_t>::min(), -1);
156
0
  }
157
158
0
  return 0;
159
0
}
160
}
161
162
#endif