diff options
Diffstat (limited to 'test/fuzz/msc_fuzz.cc')
| -rw-r--r-- | test/fuzz/msc_fuzz.cc | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/test/fuzz/msc_fuzz.cc b/test/fuzz/msc_fuzz.cc new file mode 100644 index 000000000..6e838a682 --- /dev/null +++ b/test/fuzz/msc_fuzz.cc @@ -0,0 +1,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 |
