summaryrefslogtreecommitdiff
path: root/test/fuzz/msc_fuzz.cc
diff options
context:
space:
mode:
authorHiFiPhile <[email protected]>2024-04-01 12:35:57 +0200
committerHiFiPhile <[email protected]>2024-04-01 12:35:57 +0200
commita1f01fcbe0fecb8d1783a105d7f22cba032dfced (patch)
treec8174923ef0bdd1016f55ed731df4c2df3257940 /test/fuzz/msc_fuzz.cc
parentdd0350f5499de586a3405fdcec632f059fd7534e (diff)
parent82dfe95655c7b7564363a2d5cb2f5e32d431b223 (diff)
Merge remote-tracking branch 'upstream/master' into pr/1702
Diffstat (limited to 'test/fuzz/msc_fuzz.cc')
-rw-r--r--test/fuzz/msc_fuzz.cc162
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