فهرست منبع

Merge pull request #1716 from silvergasp/master

fuzz: Add support for fuzzing
Ha Thach 3 سال پیش
والد
کامیت
d4620d99d3
36فایلهای تغییر یافته به همراه2727 افزوده شده و 57 حذف شده
  1. 8 8
      .github/workflows/build_aarch64.yml
  2. 8 8
      .github/workflows/build_arm.yml
  3. 8 8
      .github/workflows/build_esp.yml
  4. 8 8
      .github/workflows/build_msp430.yml
  5. 8 8
      .github/workflows/build_renesas.yml
  6. 8 8
      .github/workflows/build_riscv.yml
  7. 10 1
      .github/workflows/pre-commit.yml
  8. 8 8
      .github/workflows/test_hardware.yml
  9. 1 0
      src/class/cdc/cdc_device.c
  10. 208 0
      test/fuzz/dcd_fuzz.cc
  11. 29 0
      test/fuzz/device/cdc/CMakeLists.txt
  12. 12 0
      test/fuzz/device/cdc/Makefile
  13. 174 0
      test/fuzz/device/cdc/src/fuzz.cc
  14. 114 0
      test/fuzz/device/cdc/src/tusb_config.h
  15. 229 0
      test/fuzz/device/cdc/src/usb_descriptors.cc
  16. 29 0
      test/fuzz/device/msc/CMakeLists.txt
  17. 12 0
      test/fuzz/device/msc/Makefile
  18. 62 0
      test/fuzz/device/msc/src/fuzz.cc
  19. 114 0
      test/fuzz/device/msc/src/tusb_config.h
  20. 224 0
      test/fuzz/device/msc/src/usb_descriptors.cc
  21. 29 0
      test/fuzz/device/net/CMakeLists.txt
  22. 71 0
      test/fuzz/device/net/Makefile
  23. 75 0
      test/fuzz/device/net/src/arch/cc.h
  24. 99 0
      test/fuzz/device/net/src/fuzz.cc
  25. 71 0
      test/fuzz/device/net/src/lwipopts.h
  26. 122 0
      test/fuzz/device/net/src/tusb_config.h
  27. 229 0
      test/fuzz/device/net/src/usb_descriptors.cc
  28. 74 0
      test/fuzz/dicts/cdc.dict
  29. 34 0
      test/fuzz/fuzz.cc
  30. 37 0
      test/fuzz/fuzz.h
  31. 30 0
      test/fuzz/fuzz_private.h
  32. 104 0
      test/fuzz/make.mk
  33. 162 0
      test/fuzz/msc_fuzz.cc
  34. 82 0
      test/fuzz/net_fuzz.cc
  35. 161 0
      test/fuzz/rules.mk
  36. 73 0
      test/fuzz/usbd_fuzz.cc

+ 8 - 8
.github/workflows/build_aarch64.yml

@@ -3,17 +3,17 @@ name: Build AArch64
 on:
   push:
     paths:
-      - 'src'
-      - 'examples'
-      - 'lib'
-      - 'hw'
+      - 'src/**'
+      - 'examples/**'
+      - 'lib/**'
+      - 'hw/**'
   pull_request:
     branches: [ master ]
     paths:
-      - 'src'
-      - 'examples'
-      - 'lib'
-      - 'hw'
+      - 'src/**'
+      - 'examples/**'
+      - 'lib/**'
+      - 'hw/**'
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}

+ 8 - 8
.github/workflows/build_arm.yml

@@ -3,17 +3,17 @@ name: Build ARM
 on:
   push:
     paths:
-      - 'src'
-      - 'examples'
-      - 'lib'
-      - 'hw'
+      - 'src/**'
+      - 'examples/**'
+      - 'lib/**'
+      - 'hw/**'
   pull_request:
     branches: [ master ]
     paths:
-      - 'src'
-      - 'examples'
-      - 'lib'
-      - 'hw'
+      - 'src/**'
+      - 'examples/**'
+      - 'lib/**'
+      - 'hw/**'
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}

+ 8 - 8
.github/workflows/build_esp.yml

@@ -3,17 +3,17 @@ name: Build ESP
 on:
   push:
     paths:
-      - 'src'
-      - 'examples'
-      - 'lib'
-      - 'hw'
+      - 'src/**'
+      - 'examples/**'
+      - 'lib/**'
+      - 'hw/**'
   pull_request:
     branches: [ master ]
     paths:
-      - 'src'
-      - 'examples'
-      - 'lib'
-      - 'hw'
+      - 'src/**'
+      - 'examples/**'
+      - 'lib/**'
+      - 'hw/**'
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}

+ 8 - 8
.github/workflows/build_msp430.yml

@@ -3,17 +3,17 @@ name: Build MSP430
 on:
   push:
     paths:
-      - 'src'
-      - 'examples'
-      - 'lib'
-      - 'hw'
+      - 'src/**'
+      - 'examples/**'
+      - 'lib/**'
+      - 'hw/**'
   pull_request:
     branches: [ master ]
     paths:
-      - 'src'
-      - 'examples'
-      - 'lib'
-      - 'hw'
+      - 'src/**'
+      - 'examples/**'
+      - 'lib/**'
+      - 'hw/**'
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}

+ 8 - 8
.github/workflows/build_renesas.yml

@@ -3,17 +3,17 @@ name: Build Renesas
 on:
   push:
     paths:
-      - 'src'
-      - 'examples'
-      - 'lib'
-      - 'hw'
+      - 'src/**'
+      - 'examples/**'
+      - 'lib/**'
+      - 'hw/**'
   pull_request:
     branches: [ master ]
     paths:
-      - 'src'
-      - 'examples'
-      - 'lib'
-      - 'hw'
+      - 'src/**'
+      - 'examples/**'
+      - 'lib/**'
+      - 'hw/**'
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}

+ 8 - 8
.github/workflows/build_riscv.yml

@@ -3,17 +3,17 @@ name: Build RISC-V
 on:
   push:
     paths:
-      - 'src'
-      - 'examples'
-      - 'lib'
-      - 'hw'
+      - 'src/**'
+      - 'examples/**'
+      - 'lib/**'
+      - 'hw/**'
   pull_request:
     branches: [ master ]
     paths:
-      - 'src'
-      - 'examples'
-      - 'lib'
-      - 'hw'
+      - 'src/**'
+      - 'examples/**'
+      - 'lib/**'
+      - 'hw/**'
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}

+ 10 - 1
.github/workflows/pre-commit.yml

@@ -34,4 +34,13 @@ jobs:
         # Install Ceedling
         gem install ceedling
         cd test/unit-test
-        ceedling test:all
+        ceedling test:all
+
+    - name: Build Fuzzer
+      run: |
+        fuzz_harness=$(ls -d test/fuzz/device/*/)
+        for h in $fuzz_harness
+        do
+          make -C $h get-deps
+          make -C $h all
+        done

+ 8 - 8
.github/workflows/test_hardware.yml

@@ -3,17 +3,17 @@ name: Hardware Test
 on:
   push:
     paths:
-      - 'src'
-      - 'examples'
-      - 'lib'
-      - 'hw'
+      - 'src/**'
+      - 'examples/**'
+      - 'lib/**'
+      - 'hw/**'
   pull_request:
     branches: [ master ]
     paths:
-      - 'src'
-      - 'examples'
-      - 'lib'
-      - 'hw'
+      - 'src/**'
+      - 'examples/**'
+      - 'lib/**'
+      - 'hw/**'
 
 # Hardware in the loop (HIL)
 # Current self-hosted instance is running on an EPYC 7232 server hosted by HiFiPhile user

+ 1 - 0
src/class/cdc/cdc_device.c

@@ -171,6 +171,7 @@ uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize)
   uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) bufsize);
 
   // flush if queue more than packet size
+  // may need to suppress -Wunreachable-code since most of the time CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE
   if ( (tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE) || ((CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE) && tu_fifo_full(&p_cdc->tx_ff)) )
   {
     tud_cdc_n_write_flush(itf);

+ 208 - 0
test/fuzz/dcd_fuzz.cc

@@ -0,0 +1,208 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Nathaniel Brough
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+#include "device/dcd.h"
+#include "fuzz/fuzz_private.h"
+#include <assert.h>
+#include <cstdint>
+#include <limits>
+
+#define UNUSED(x) (void)(x)
+
+//--------------------------------------------------------------------+
+// State tracker
+//--------------------------------------------------------------------+
+struct State {
+  bool interrupts_enabled;
+  bool sof_enabled;
+  uint8_t address;
+};
+
+static State state = {false, 0, 0};
+
+//--------------------------------------------------------------------+
+// Controller API
+// All no-ops as we are fuzzing.
+//--------------------------------------------------------------------+
+extern "C" {
+void dcd_init(uint8_t rhport) {
+  UNUSED(rhport);
+  return;
+}
+
+void dcd_int_handler(uint8_t rhport) {
+  assert(_fuzz_data_provider.has_value());
+
+  if (!state.interrupts_enabled) {
+    return;
+  }
+
+  // Choose if we want to generate a signal based on the fuzzed data.
+  if (_fuzz_data_provider->ConsumeBool()) {
+    dcd_event_bus_signal(
+        rhport,
+        // Choose a random event based on the fuzz data.
+        (dcd_eventid_t)_fuzz_data_provider->ConsumeIntegralInRange<uint8_t>(
+            DCD_EVENT_INVALID + 1, DCD_EVENT_COUNT - 1),
+        // Identify trigger as either an interrupt or a syncrhonous call
+        // depending on fuzz data.
+        _fuzz_data_provider->ConsumeBool());
+  }
+
+  if (_fuzz_data_provider->ConsumeBool()) {
+    constexpr size_t kSetupFrameLength = 8;
+    std::vector<uint8_t> setup =
+        _fuzz_data_provider->ConsumeBytes<uint8_t>(kSetupFrameLength);
+    // Fuzz consumer may return less than requested. If this is the case
+    // we want to make sure that at least that length is allocated and available
+    // to the signal handler.
+    if (setup.size() != kSetupFrameLength) {
+      setup.resize(kSetupFrameLength);
+    }
+    dcd_event_setup_received(rhport, setup.data(),
+                             // Identify trigger as either an interrupt or a
+                             // syncrhonous call depending on fuzz data.
+                             _fuzz_data_provider->ConsumeBool());
+  }
+}
+
+void dcd_int_enable(uint8_t rhport) {
+  state.interrupts_enabled = true;
+  UNUSED(rhport);
+  return;
+}
+
+void dcd_int_disable(uint8_t rhport) {
+  state.interrupts_enabled = false;
+  UNUSED(rhport);
+  return;
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
+  UNUSED(rhport);
+  state.address = dev_addr;
+  // Respond with status.
+  dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+  return;
+}
+
+void dcd_remote_wakeup(uint8_t rhport) {
+  UNUSED(rhport);
+  return;
+}
+
+void dcd_connect(uint8_t rhport) {
+  UNUSED(rhport);
+  return;
+}
+
+void dcd_disconnect(uint8_t rhport) {
+  UNUSED(rhport);
+  return;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en) {
+  state.sof_enabled = en;
+  UNUSED(rhport);
+  return;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+// Configure endpoint's registers according to descriptor
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) {
+  UNUSED(rhport);
+  UNUSED(desc_ep);
+  return _fuzz_data_provider->ConsumeBool();
+}
+
+// Close all non-control endpoints, cancel all pending transfers if any.
+// Invoked when switching from a non-zero Configuration by SET_CONFIGURE
+// therefore required for multiple configuration support.
+void dcd_edpt_close_all(uint8_t rhport) {
+  UNUSED(rhport);
+  return;
+}
+
+// Close an endpoint.
+// Since it is weak, caller must TU_ASSERT this function's existence before
+// calling it.
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
+  UNUSED(rhport);
+  UNUSED(ep_addr);
+  return;
+}
+
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to
+// notify the stack
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer,
+                   uint16_t total_bytes) {
+  UNUSED(rhport);
+  UNUSED(buffer);
+  UNUSED(total_bytes);
+
+  uint8_t const dir = tu_edpt_dir(ep_addr);
+
+  if (dir == TUSB_DIR_IN) {
+    std::vector<uint8_t> temp =
+        _fuzz_data_provider->ConsumeBytes<uint8_t>(total_bytes);
+    std::copy(temp.begin(), temp.end(), buffer);
+  }
+  // Ignore output data as it's not useful for fuzzing without a more
+  // complex fuzzed backend. But we need to make sure it's not
+  // optimised out.
+  volatile uint8_t *dont_optimise0 = buffer;
+  volatile uint16_t dont_optimise1 = total_bytes;
+  UNUSED(dont_optimise0);
+  UNUSED(dont_optimise1);
+
+
+  return _fuzz_data_provider->ConsumeBool();
+}
+
+/* TODO: implement a fuzzed version of this.
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff,
+                        uint16_t total_bytes) {} 
+*/
+
+// Stall endpoint, any queuing transfer should be removed from endpoint
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
+
+  UNUSED(rhport);
+  UNUSED(ep_addr);
+  return;
+}
+
+// clear stall, data toggle is also reset to DATA0
+// This API never calls with control endpoints, since it is auto cleared when
+// receiving setup packet
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
+
+  UNUSED(rhport);
+  UNUSED(ep_addr);
+  return;
+}
+}

+ 29 - 0
test/fuzz/device/cdc/CMakeLists.txt

@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.5)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
+
+# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
+family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
+
+project(${PROJECT})
+
+# Checks this example is valid for the family and initializes the project
+family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+        )
+
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+        ${CMAKE_CURRENT_SOURCE_DIR}/src
+        )
+
+# Configure compilation flags and libraries for the example... see the corresponding function
+# in hw/bsp/FAMILY/family.cmake for details.
+family_configure_device_example(${PROJECT})

+ 12 - 0
test/fuzz/device/cdc/Makefile

@@ -0,0 +1,12 @@
+include ../../../../tools/top.mk
+include ../../make.mk
+
+INC += \
+	src \
+	$(TOP)/hw \
+
+# Example source
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(wildcard src/*.c))
+SRC_CXX += $(addprefix $(CURRENT_PATH)/, $(wildcard src/*.cc))
+
+include ../../rules.mk

+ 174 - 0
test/fuzz/device/cdc/src/fuzz.cc

@@ -0,0 +1,174 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Nathaniel Brough
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include <cassert>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "class/cdc/cdc_device.h"
+#include "fuzz/fuzz.h"
+#include "tusb.h"
+#include <cstdint>
+#include <string>
+#include <vector>
+
+extern "C" {
+
+#define FUZZ_ITERATIONS 500
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTYPES
+//--------------------------------------------------------------------+
+
+void cdc_task(FuzzedDataProvider *provider);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+  FuzzedDataProvider provider(Data, Size);
+  std::vector<uint8_t> callback_data = provider.ConsumeBytes<uint8_t>(
+      provider.ConsumeIntegralInRange<size_t>(0, Size));
+  fuzz_init(callback_data.data(), callback_data.size());
+  // init device stack on configured roothub port
+  tud_init(BOARD_TUD_RHPORT);
+
+  for (int i = 0; i < FUZZ_ITERATIONS; i++) {
+    if (provider.remaining_bytes() == 0) {
+      return 0;
+    }
+    tud_int_handler(provider.ConsumeIntegral<uint8_t>());
+    tud_task(); // tinyusb device task
+    cdc_task(&provider);
+  }
+
+  return 0;
+}
+
+//--------------------------------------------------------------------+
+// USB CDC
+//--------------------------------------------------------------------+
+enum CdcApiFuncs {
+  kCdcNConnected,
+  kCdcNGetLineState,
+  kCdcNGetLineCoding,
+  kCdcNSetWantedChar,
+  kCdcNAvailable,
+  kCdcNRead,
+  kCdcNReadChar,
+  kCdcNReadFlush,
+  kCdcNPeek,
+  kCdcNWrite,
+  kCdcNWriteChar,
+  kCdcNWriteStr,
+  kCdcNWriteFlush,
+  kCdcNWriteAvailable,
+  kCdcNWriteClear,
+  // We don't need to fuzz tud_cdc_<not n>* as they are just wrappers
+  // calling with n==0.
+  kMaxValue,
+};
+
+void cdc_task(FuzzedDataProvider *provider) {
+
+  assert(provider != NULL);
+  const int kMaxBufferSize = 4096;
+  switch (provider->ConsumeEnum<CdcApiFuncs>()) {
+  case kCdcNConnected:
+    // TODO: Fuzz interface number
+    (void)tud_cdc_n_connected(0);
+    break;
+  case kCdcNGetLineState:
+    // TODO: Fuzz interface number
+    (void)tud_cdc_n_get_line_state(0);
+    break;
+  case kCdcNGetLineCoding: {
+    cdc_line_coding_t coding;
+    // TODO: Fuzz interface number
+    (void)tud_cdc_n_get_line_coding(0, &coding);
+  } break;
+  case kCdcNSetWantedChar:
+    // TODO: Fuzz interface number
+    (void)tud_cdc_n_set_wanted_char(0, provider->ConsumeIntegral<char>());
+    break;
+  case kCdcNAvailable:
+    // TODO: Fuzz interface number
+    (void)tud_cdc_n_available(0);
+    break;
+  case kCdcNRead: {
+    std::vector<uint8_t> buffer;
+    buffer.resize(provider->ConsumeIntegralInRange<size_t>(0, kMaxBufferSize));
+    // TODO: Fuzz interface number
+    (void)tud_cdc_n_read(0, buffer.data(), buffer.size());
+    break;
+  }
+  case kCdcNReadChar:
+    // TODO: Fuzz interface number
+    tud_cdc_n_read_char(0);
+    break;
+  case kCdcNReadFlush:
+    // TODO: Fuzz interface number
+    tud_cdc_n_read_flush(0);
+    break;
+  case kCdcNPeek: {
+    uint8_t peak = 0;
+    tud_cdc_n_peek(0, &peak);
+    break;
+  }
+  case kCdcNWrite: {
+    std::vector<uint8_t> buffer = provider->ConsumeBytes<uint8_t>(
+        provider->ConsumeIntegralInRange<size_t>(0, kMaxBufferSize));
+
+    // TODO: Fuzz interface number
+    (void)tud_cdc_n_write(0, buffer.data(), buffer.size());
+  } break;
+  
+case kCdcNWriteChar:
+  // TODO: Fuzz interface number
+  (void)tud_cdc_n_write_char(0, provider->ConsumeIntegral<char>());
+  break;
+case kCdcNWriteStr: {
+  std::string str = provider->ConsumeRandomLengthString(kMaxBufferSize);
+  // TODO: Fuzz interface number
+  (void)tud_cdc_n_write_str(0, str.c_str());
+  break;
+}
+case kCdcNWriteFlush:
+  // TODO: Fuzz interface number
+  (void)tud_cdc_n_write_flush(0);
+  break;
+case kCdcNWriteAvailable:
+  // TODO: Fuzz interface number
+  (void)tud_cdc_n_write_available(0);
+  break;
+case kCdcNWriteClear:
+  // TODO: Fuzz interface number
+  (void)tud_cdc_n_write_clear(0);
+  break;
+case kMaxValue:
+  // Noop.
+  break;
+}
+}
+}

+ 114 - 0
test/fuzz/device/cdc/src/tusb_config.h

@@ -0,0 +1,114 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Nathaniel Brough
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Board Specific Configuration
+//--------------------------------------------------------------------+
+
+// RHPort number used for device can be defined by board.mk, default to port 0
+#ifndef BOARD_TUD_RHPORT
+#define BOARD_TUD_RHPORT      0
+#endif
+
+// RHPort max operational speed can defined by board.mk
+#ifndef BOARD_TUD_MAX_SPEED
+#define BOARD_TUD_MAX_SPEED   OPT_MODE_DEFAULT_SPEED
+#endif
+
+//--------------------------------------------------------------------
+// Common Configuration
+//--------------------------------------------------------------------
+
+// defined by compiler flags for flexibility
+#ifndef CFG_TUSB_MCU
+#error CFG_TUSB_MCU must be defined
+#endif
+
+#ifndef CFG_TUSB_OS
+#define CFG_TUSB_OS           OPT_OS_NONE
+#endif
+
+#ifndef CFG_TUSB_DEBUG
+#define CFG_TUSB_DEBUG        0
+#endif
+
+// Enable Device stack
+#define CFG_TUD_ENABLED       1
+
+// Default is max speed that hardware controller could support with on-chip PHY
+#define CFG_TUD_MAX_SPEED     BOARD_TUD_MAX_SPEED
+
+/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
+ * Tinyusb use follows macros to declare transferring memory so that they can be put
+ * into those specific section.
+ * e.g
+ * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
+ * - CFG_TUSB_MEM_ALIGN   : __attribute__ ((aligned(4)))
+ */
+#ifndef CFG_TUSB_MEM_SECTION
+#define CFG_TUSB_MEM_SECTION
+#endif
+
+#ifndef CFG_TUSB_MEM_ALIGN
+#define CFG_TUSB_MEM_ALIGN    __attribute__ ((aligned(4)))
+#endif
+
+//--------------------------------------------------------------------
+// DEVICE CONFIGURATION
+//--------------------------------------------------------------------
+
+#ifndef CFG_TUD_ENDPOINT0_SIZE
+#define CFG_TUD_ENDPOINT0_SIZE    64
+#endif
+
+//------------- CLASS -------------//
+#define CFG_TUD_CDC              1
+#define CFG_TUD_MSC              0
+#define CFG_TUD_HID              0
+#define CFG_TUD_MIDI             0
+#define CFG_TUD_VENDOR           0
+
+// CDC FIFO size of TX and RX
+#define CFG_TUD_CDC_RX_BUFSIZE   (TUD_OPT_HIGH_SPEED ? 512 : 64)
+#define CFG_TUD_CDC_TX_BUFSIZE   (TUD_OPT_HIGH_SPEED ? 512 : 64)
+
+// CDC Endpoint transfer buffer size, more is faster
+#define CFG_TUD_CDC_EP_BUFSIZE   (TUD_OPT_HIGH_SPEED ? 512 : 64)
+
+// MSC Buffer size of Device Mass storage
+#define CFG_TUD_MSC_EP_BUFSIZE   512
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */

+ 229 - 0
test/fuzz/device/cdc/src/usb_descriptors.cc

@@ -0,0 +1,229 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Nathaniel Brough
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "tusb.h"
+
+/* A combination of interfaces must have a unique product id, since PC will save
+ * device driver after the first plug.
+ * Auto ProductID layout's Bitmap:
+ *   [MSB]         HID | CDC          [LSB]
+ */
+#define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n))
+#define USB_PID                                                                \
+  (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(HID, 2) | _PID_MAP(MIDI, 3) |          \
+   _PID_MAP(VENDOR, 4))
+
+#define USB_VID 0xCafe
+#define USB_BCD 0x0200
+
+//--------------------------------------------------------------------+
+// Device Descriptors
+//--------------------------------------------------------------------+
+
+// Invoked when received GET DEVICE DESCRIPTOR
+// Application return pointer to descriptor
+uint8_t const *tud_descriptor_device_cb(void) {
+  static tusb_desc_device_t const desc_device = {
+      .bLength = sizeof(tusb_desc_device_t),
+      .bDescriptorType = TUSB_DESC_DEVICE,
+      .bcdUSB = USB_BCD,
+
+      // Use Interface Association Descriptor (IAD) for CDC
+      // As required by USB Specs IAD's subclass must be common class (2) and
+      // protocol must be IAD (1)
+      .bDeviceClass = TUSB_CLASS_MISC,
+      .bDeviceSubClass = MISC_SUBCLASS_COMMON,
+      .bDeviceProtocol = MISC_PROTOCOL_IAD,
+
+      .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+
+      .idVendor = USB_VID,
+      .idProduct = USB_PID,
+      .bcdDevice = 0x0100,
+
+      .iManufacturer = 0x01,
+      .iProduct = 0x02,
+      .iSerialNumber = 0x03,
+
+      .bNumConfigurations = 0x01};
+
+  return (uint8_t const *)&desc_device;
+}
+
+//--------------------------------------------------------------------+
+// Configuration Descriptor
+//--------------------------------------------------------------------+
+
+enum { ITF_NUM_CDC = 0, ITF_NUM_CDC_DATA, ITF_NUM_TOTAL };
+
+#define EPNUM_CDC_NOTIF 0x81
+#define EPNUM_CDC_OUT 0x02
+#define EPNUM_CDC_IN 0x82
+
+#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
+
+// full speed configuration
+uint8_t const desc_fs_configuration[] = {
+    // Config number, interface count, string index, total length, attribute,
+    // power in mA
+    TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
+
+    // Interface number, string index, EP notification address and size, EP data
+    // address (out, in) and size.
+    TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT,
+                       EPNUM_CDC_IN, 64),
+};
+
+#if TUD_OPT_HIGH_SPEED
+// Per USB specs: high speed capable device must report device_qualifier and
+// other_speed_configuration
+
+// high speed configuration
+uint8_t const desc_hs_configuration[] = {
+    // Config number, interface count, string index, total length, attribute,
+    // power in mA
+    TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
+
+    // Interface number, string index, EP notification address and size, EP data
+    // address (out, in) and size.
+    TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT,
+                       EPNUM_CDC_IN, 512),
+};
+
+// other speed configuration
+uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN];
+
+// device qualifier is mostly similar to device descriptor since we don't change
+// configuration based on speed
+tusb_desc_device_qualifier_t const desc_device_qualifier = {
+    .bLength = sizeof(tusb_desc_device_qualifier_t),
+    .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
+    .bcdUSB = USB_BCD,
+
+    .bDeviceClass = TUSB_CLASS_MISC,
+    .bDeviceSubClass = MISC_SUBCLASS_COMMON,
+    .bDeviceProtocol = MISC_PROTOCOL_IAD,
+
+    .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+    .bNumConfigurations = 0x01,
+    .bReserved = 0x00};
+
+// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long
+// enough for transfer to complete. device_qualifier descriptor describes
+// information about a high-speed capable device that would change if the device
+// were operating at the other speed. If not highspeed capable stall this
+// request.
+uint8_t const *tud_descriptor_device_qualifier_cb(void) {
+  return (uint8_t const *)&desc_device_qualifier;
+}
+
+// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long
+// enough for transfer to complete Configuration descriptor in the other speed
+// e.g if high speed then this is for full speed and vice versa
+uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
+  (void)index; // for multiple configurations
+
+  // if link speed is high return fullspeed config, and vice versa
+  // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
+  memcpy(desc_other_speed_config,
+         (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration
+                                              : desc_hs_configuration,
+         CONFIG_TOTAL_LEN);
+
+  desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
+
+  return desc_other_speed_config;
+}
+
+#endif // highspeed
+
+// Invoked when received GET CONFIGURATION DESCRIPTOR
+// Application return pointer to descriptor
+// Descriptor contents must exist long enough for transfer to complete
+uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
+  (void)index; // for multiple configurations
+
+#if TUD_OPT_HIGH_SPEED
+  // Although we are highspeed, host may be fullspeed.
+  return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration
+                                              : desc_fs_configuration;
+#else
+  return desc_fs_configuration;
+#endif
+}
+
+//--------------------------------------------------------------------+
+// String Descriptors
+//--------------------------------------------------------------------+
+
+// array of pointer to string descriptors
+char const *string_desc_arr[] = {
+    (const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
+    "TinyUSB",                  // 1: Manufacturer
+    "TinyUSB Device",           // 2: Product
+    "123456789012",             // 3: Serials, should use chip ID
+    "TinyUSB CDC",              // 4: CDC Interface
+};
+
+static uint16_t _desc_str[32];
+
+// Invoked when received GET STRING DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long
+// enough for transfer to complete
+uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
+  (void)langid;
+
+  uint8_t chr_count;
+
+  if (index == 0) {
+    memcpy(&_desc_str[1], string_desc_arr[0], 2);
+    chr_count = 1;
+  } else {
+    // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
+    // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
+
+    if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])))
+      return NULL;
+
+    const char *str = string_desc_arr[index];
+
+    // Cap at max char
+    chr_count = (uint8_t)strlen(str);
+    if (chr_count > 31)
+      chr_count = 31;
+
+    // Convert ASCII string into UTF-16
+    for (uint8_t i = 0; i < chr_count; i++) {
+      _desc_str[1 + i] = str[i];
+    }
+  }
+
+  // first byte is length (including header), second byte is string type
+  _desc_str[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
+
+  return _desc_str;
+}

+ 29 - 0
test/fuzz/device/msc/CMakeLists.txt

@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.5)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
+
+# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
+family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
+
+project(${PROJECT})
+
+# Checks this example is valid for the family and initializes the project
+family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+        )
+
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+        ${CMAKE_CURRENT_SOURCE_DIR}/src
+        )
+
+# Configure compilation flags and libraries for the example... see the corresponding function
+# in hw/bsp/FAMILY/family.cmake for details.
+family_configure_device_example(${PROJECT})

+ 12 - 0
test/fuzz/device/msc/Makefile

@@ -0,0 +1,12 @@
+include ../../../../tools/top.mk
+include ../../make.mk
+
+INC += \
+	src \
+	$(TOP)/hw \
+
+# Example source
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(wildcard src/*.c))
+SRC_CXX += $(addprefix $(CURRENT_PATH)/, $(wildcard src/*.cc))
+
+include ../../rules.mk

+ 62 - 0
test/fuzz/device/msc/src/fuzz.cc

@@ -0,0 +1,62 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Nathaniel Brough
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include <cassert>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "class/cdc/cdc_device.h"
+#include "fuzz/fuzz.h"
+#include "tusb.h"
+#include <cstdint>
+#include <string>
+#include <vector>
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTYPES
+//--------------------------------------------------------------------+
+#define FUZZ_ITERATIONS 500
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+  FuzzedDataProvider provider(Data, Size);
+  std::vector<uint8_t> callback_data = provider.ConsumeBytes<uint8_t>(
+      provider.ConsumeIntegralInRange<size_t>(0, Size));
+  fuzz_init(callback_data.data(), callback_data.size());
+  // init device stack on configured roothub port
+  tud_init(BOARD_TUD_RHPORT);
+
+  for (int i = 0; i < FUZZ_ITERATIONS; i++) {
+    if (provider.remaining_bytes() == 0) {
+      return 0;
+    }
+    tud_int_handler(provider.ConsumeIntegral<uint8_t>());
+    tud_task(); // tinyusb device task
+  }
+
+  return 0;
+}
+

+ 114 - 0
test/fuzz/device/msc/src/tusb_config.h

@@ -0,0 +1,114 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Nathaniel Brough
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Board Specific Configuration
+//--------------------------------------------------------------------+
+
+// RHPort number used for device can be defined by board.mk, default to port 0
+#ifndef BOARD_TUD_RHPORT
+#define BOARD_TUD_RHPORT      0
+#endif
+
+// RHPort max operational speed can defined by board.mk
+#ifndef BOARD_TUD_MAX_SPEED
+#define BOARD_TUD_MAX_SPEED   OPT_MODE_DEFAULT_SPEED
+#endif
+
+//--------------------------------------------------------------------
+// Common Configuration
+//--------------------------------------------------------------------
+
+// defined by compiler flags for flexibility
+#ifndef CFG_TUSB_MCU
+#error CFG_TUSB_MCU must be defined
+#endif
+
+#ifndef CFG_TUSB_OS
+#define CFG_TUSB_OS           OPT_OS_NONE
+#endif
+
+#ifndef CFG_TUSB_DEBUG
+#define CFG_TUSB_DEBUG        0
+#endif
+
+// Enable Device stack
+#define CFG_TUD_ENABLED       1
+
+// Default is max speed that hardware controller could support with on-chip PHY
+#define CFG_TUD_MAX_SPEED     BOARD_TUD_MAX_SPEED
+
+/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
+ * Tinyusb use follows macros to declare transferring memory so that they can be put
+ * into those specific section.
+ * e.g
+ * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
+ * - CFG_TUSB_MEM_ALIGN   : __attribute__ ((aligned(4)))
+ */
+#ifndef CFG_TUSB_MEM_SECTION
+#define CFG_TUSB_MEM_SECTION
+#endif
+
+#ifndef CFG_TUSB_MEM_ALIGN
+#define CFG_TUSB_MEM_ALIGN    __attribute__ ((aligned(4)))
+#endif
+
+//--------------------------------------------------------------------
+// DEVICE CONFIGURATION
+//--------------------------------------------------------------------
+
+#ifndef CFG_TUD_ENDPOINT0_SIZE
+#define CFG_TUD_ENDPOINT0_SIZE    64
+#endif
+
+//------------- CLASS -------------//
+#define CFG_TUD_CDC              0
+#define CFG_TUD_MSC              1
+#define CFG_TUD_HID              0
+#define CFG_TUD_MIDI             0
+#define CFG_TUD_VENDOR           0
+
+// CDC FIFO size of TX and RX
+#define CFG_TUD_CDC_RX_BUFSIZE   (TUD_OPT_HIGH_SPEED ? 512 : 64)
+#define CFG_TUD_CDC_TX_BUFSIZE   (TUD_OPT_HIGH_SPEED ? 512 : 64)
+
+// CDC Endpoint transfer buffer size, more is faster
+#define CFG_TUD_CDC_EP_BUFSIZE   (TUD_OPT_HIGH_SPEED ? 512 : 64)
+
+// MSC Buffer size of Device Mass storage
+#define CFG_TUD_MSC_EP_BUFSIZE   512
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */

+ 224 - 0
test/fuzz/device/msc/src/usb_descriptors.cc

@@ -0,0 +1,224 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Nathaniel Brough
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "tusb.h"
+
+/* A combination of interfaces must have a unique product id, since PC will save
+ * device driver after the first plug.
+ * Auto ProductID layout's Bitmap:
+ *   [MSB]         HID | MSC | CDC          [LSB]
+ */
+#define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n))
+#define USB_PID                                                                \
+  (0x4000 | _PID_MAP(MSC, 0) | _PID_MAP(HID, 1) | _PID_MAP(MIDI, 2) |          \
+   _PID_MAP(VENDOR, 3))
+#define USB_VID 0xCafe
+#define USB_BCD 0x0200
+
+//--------------------------------------------------------------------+
+// Device Descriptors
+//--------------------------------------------------------------------+
+
+// Invoked when received GET DEVICE DESCRIPTOR
+// Application return pointer to descriptor
+uint8_t const *tud_descriptor_device_cb(void) {
+  static tusb_desc_device_t const desc_device = {
+      .bLength = sizeof(tusb_desc_device_t),
+      .bDescriptorType = TUSB_DESC_DEVICE,
+      .bcdUSB = USB_BCD,
+
+      // Use Interface Association Descriptor (IAD) for CDC
+      // As required by USB Specs IAD's subclass must be common class (2) and
+      // protocol must be IAD (1)
+      .bDeviceClass = TUSB_CLASS_MISC,
+      .bDeviceSubClass = MISC_SUBCLASS_COMMON,
+      .bDeviceProtocol = MISC_PROTOCOL_IAD,
+
+      .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+
+      .idVendor = USB_VID,
+      .idProduct = USB_PID,
+      .bcdDevice = 0x0100,
+
+      .iManufacturer = 0x01,
+      .iProduct = 0x02,
+      .iSerialNumber = 0x03,
+
+      .bNumConfigurations = 0x01};
+
+  return (uint8_t const *)&desc_device;
+}
+
+//--------------------------------------------------------------------+
+// Configuration Descriptor
+//--------------------------------------------------------------------+
+
+enum { ITF_NUM_MSC = 0, ITF_NUM_TOTAL };
+
+#define EPNUM_MSC_OUT 0x05
+#define EPNUM_MSC_IN 0x85
+
+#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN)
+
+// full speed configuration
+uint8_t const desc_fs_configuration[] = {
+    // Config number, interface count, string index, total length, attribute,
+    // power in mA
+    TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
+
+    // Interface number, string index, EP Out & EP In address, EP size
+    TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 4, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64),
+};
+
+#if TUD_OPT_HIGH_SPEED
+// Per USB specs: high speed capable device must report device_qualifier and
+// other_speed_configuration
+
+// high speed configuration
+uint8_t const desc_hs_configuration[] = {
+    // Config number, interface count, string index, total length, attribute,
+    // power in mA
+    TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
+
+    // Interface number, string index, EP Out & EP In address, EP size
+    TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 4, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512),
+};
+
+// other speed configuration
+uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN];
+
+// device qualifier is mostly similar to device descriptor since we don't change
+// configuration based on speed
+tusb_desc_device_qualifier_t const desc_device_qualifier = {
+    .bLength = sizeof(tusb_desc_device_qualifier_t),
+    .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
+    .bcdUSB = USB_BCD,
+
+    .bDeviceClass = TUSB_CLASS_MISC,
+    .bDeviceSubClass = MISC_SUBCLASS_COMMON,
+    .bDeviceProtocol = MISC_PROTOCOL_IAD,
+
+    .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+    .bNumConfigurations = 0x01,
+    .bReserved = 0x00};
+
+// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long
+// enough for transfer to complete. device_qualifier descriptor describes
+// information about a high-speed capable device that would change if the device
+// were operating at the other speed. If not highspeed capable stall this
+// request.
+uint8_t const *tud_descriptor_device_qualifier_cb(void) {
+  return (uint8_t const *)&desc_device_qualifier;
+}
+
+// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long
+// enough for transfer to complete Configuration descriptor in the other speed
+// e.g if high speed then this is for full speed and vice versa
+uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
+  (void)index; // for multiple configurations
+
+  // if link speed is high return fullspeed config, and vice versa
+  // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
+  memcpy(desc_other_speed_config,
+         (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration
+                                              : desc_hs_configuration,
+         CONFIG_TOTAL_LEN);
+
+  desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
+
+  return desc_other_speed_config;
+}
+
+#endif // highspeed
+
+// Invoked when received GET CONFIGURATION DESCRIPTOR
+// Application return pointer to descriptor
+// Descriptor contents must exist long enough for transfer to complete
+uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
+  (void)index; // for multiple configurations
+
+#if TUD_OPT_HIGH_SPEED
+  // Although we are highspeed, host may be fullspeed.
+  return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration
+                                              : desc_fs_configuration;
+#else
+  return desc_fs_configuration;
+#endif
+}
+
+//--------------------------------------------------------------------+
+// String Descriptors
+//--------------------------------------------------------------------+
+
+// array of pointer to string descriptors
+char const *string_desc_arr[] = {
+    (const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
+    "TinyUSB",                  // 1: Manufacturer
+    "TinyUSB Device",           // 2: Product
+    "123456789012",             // 3: Serials, should use chip ID
+    "TinyUSB MSC",              // 4: MSC Interface
+
+};
+
+static uint16_t _desc_str[32];
+
+// Invoked when received GET STRING DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long
+// enough for transfer to complete
+uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
+  (void)langid;
+
+  uint8_t chr_count;
+
+  if (index == 0) {
+    memcpy(&_desc_str[1], string_desc_arr[0], 2);
+    chr_count = 1;
+  } else {
+    // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
+    // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
+
+    if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])))
+      return NULL;
+
+    const char *str = string_desc_arr[index];
+
+    // Cap at max char
+    chr_count = (uint8_t)strlen(str);
+    if (chr_count > 31)
+      chr_count = 31;
+
+    // Convert ASCII string into UTF-16
+    for (uint8_t i = 0; i < chr_count; i++) {
+      _desc_str[1 + i] = str[i];
+    }
+  }
+
+  // first byte is length (including header), second byte is string type
+  _desc_str[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
+
+  return _desc_str;
+}

+ 29 - 0
test/fuzz/device/net/CMakeLists.txt

@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.5)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
+
+# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
+family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
+
+project(${PROJECT})
+
+# Checks this example is valid for the family and initializes the project
+family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+        )
+
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+        ${CMAKE_CURRENT_SOURCE_DIR}/src
+        )
+
+# Configure compilation flags and libraries for the example... see the corresponding function
+# in hw/bsp/FAMILY/family.cmake for details.
+family_configure_device_example(${PROJECT})

+ 71 - 0
test/fuzz/device/net/Makefile

@@ -0,0 +1,71 @@
+DEPS_SUBMODULES += lib/lwip
+
+include ../../../../tools/top.mk
+include ../../make.mk
+
+# suppress warning caused by lwip
+CFLAGS += \
+  -Wno-error=null-dereference \
+  -Wno-error=unused-parameter \
+  -Wno-error=unused-variable
+
+INC += \
+  src \
+  $(TOP)/hw \
+  $(TOP)/lib/lwip/src/include \
+  $(TOP)/lib/lwip/src/include/ipv4 \
+  $(TOP)/lib/lwip/src/include/lwip/apps \
+  $(TOP)/lib/networking
+
+# Example source
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(wildcard src/*.c))
+SRC_CXX += $(addprefix $(CURRENT_PATH)/, $(wildcard src/*.cc))
+
+# lwip sources
+SRC_C += \
+  lib/lwip/src/core/altcp.c \
+  lib/lwip/src/core/altcp_alloc.c \
+  lib/lwip/src/core/altcp_tcp.c \
+  lib/lwip/src/core/def.c \
+  lib/lwip/src/core/dns.c \
+  lib/lwip/src/core/inet_chksum.c \
+  lib/lwip/src/core/init.c \
+  lib/lwip/src/core/ip.c \
+  lib/lwip/src/core/mem.c \
+  lib/lwip/src/core/memp.c \
+  lib/lwip/src/core/netif.c \
+  lib/lwip/src/core/pbuf.c \
+  lib/lwip/src/core/raw.c \
+  lib/lwip/src/core/stats.c \
+  lib/lwip/src/core/sys.c \
+  lib/lwip/src/core/tcp.c \
+  lib/lwip/src/core/tcp_in.c \
+  lib/lwip/src/core/tcp_out.c \
+  lib/lwip/src/core/timeouts.c \
+  lib/lwip/src/core/udp.c \
+  lib/lwip/src/core/ipv4/autoip.c \
+  lib/lwip/src/core/ipv4/dhcp.c \
+  lib/lwip/src/core/ipv4/etharp.c \
+  lib/lwip/src/core/ipv4/icmp.c \
+  lib/lwip/src/core/ipv4/igmp.c \
+  lib/lwip/src/core/ipv4/ip4.c \
+  lib/lwip/src/core/ipv4/ip4_addr.c \
+  lib/lwip/src/core/ipv4/ip4_frag.c \
+  lib/lwip/src/core/ipv6/dhcp6.c \
+  lib/lwip/src/core/ipv6/ethip6.c \
+  lib/lwip/src/core/ipv6/icmp6.c \
+  lib/lwip/src/core/ipv6/inet6.c \
+  lib/lwip/src/core/ipv6/ip6.c \
+  lib/lwip/src/core/ipv6/ip6_addr.c \
+  lib/lwip/src/core/ipv6/ip6_frag.c \
+  lib/lwip/src/core/ipv6/mld6.c \
+  lib/lwip/src/core/ipv6/nd6.c \
+  lib/lwip/src/netif/ethernet.c \
+  lib/lwip/src/netif/slipif.c \
+  lib/lwip/src/apps/http/httpd.c \
+  lib/lwip/src/apps/http/fs.c \
+  lib/networking/dhserver.c \
+  lib/networking/dnserver.c \
+  lib/networking/rndis_reports.c
+
+include ../../rules.mk

+ 75 - 0
test/fuzz/device/net/src/arch/cc.h

@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * All rights reserved. 
+ * 
+ * Redistribution and use in source and binary forms, with or without modification, 
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+#ifndef __CC_H__
+#define __CC_H__
+
+//#include "cpu.h"
+
+typedef int sys_prot_t;
+
+
+
+/* define compiler specific symbols */
+#if defined (__ICCARM__)
+
+#define PACK_STRUCT_BEGIN
+#define PACK_STRUCT_STRUCT 
+#define PACK_STRUCT_END
+#define PACK_STRUCT_FIELD(x) x
+#define PACK_STRUCT_USE_INCLUDES
+
+#elif defined (__CC_ARM)
+
+#define PACK_STRUCT_BEGIN __packed
+#define PACK_STRUCT_STRUCT 
+#define PACK_STRUCT_END
+#define PACK_STRUCT_FIELD(x) x
+
+#elif defined (__GNUC__)
+
+#define PACK_STRUCT_BEGIN
+#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
+#define PACK_STRUCT_END
+#define PACK_STRUCT_FIELD(x) x
+
+#elif defined (__TASKING__)
+
+#define PACK_STRUCT_BEGIN
+#define PACK_STRUCT_STRUCT
+#define PACK_STRUCT_END
+#define PACK_STRUCT_FIELD(x) x
+
+#endif
+
+#define LWIP_PLATFORM_ASSERT(x) do { if(!(x)) while(1); } while(0)
+
+#endif /* __CC_H__ */

+ 99 - 0
test/fuzz/device/net/src/fuzz.cc

@@ -0,0 +1,99 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Nathaniel Brough
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include <cassert>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "class/cdc/cdc_device.h"
+#include "class/net/net_device.h"
+#include "fuzz/fuzz.h"
+#include "tusb.h"
+#include <cstdint>
+#include <string>
+#include <vector>
+
+extern "C" {
+
+#define FUZZ_ITERATIONS 500
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTYPES
+//--------------------------------------------------------------------+
+
+void net_task(FuzzedDataProvider *provider);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+  FuzzedDataProvider provider(Data, Size);
+  std::vector<uint8_t> callback_data = provider.ConsumeBytes<uint8_t>(
+      provider.ConsumeIntegralInRange<size_t>(0, Size));
+  fuzz_init(callback_data.data(), callback_data.size());
+  // init device stack on configured roothub port
+  tud_init(BOARD_TUD_RHPORT);
+
+  for (int i = 0; i < FUZZ_ITERATIONS; i++) {
+    if (provider.remaining_bytes() == 0) {
+      return 0;
+    }
+    tud_int_handler(provider.ConsumeIntegral<uint8_t>());
+    tud_task(); // tinyusb device task
+    net_task(&provider);
+  }
+
+  return 0;
+}
+
+//--------------------------------------------------------------------+
+// USB CDC
+//--------------------------------------------------------------------+
+enum NetApiFuncs {
+  kNetworkRecvRenew,
+  kNetworkCanXmit,
+  kNetworkXmit,
+  kMaxValue,
+};
+
+void net_task(FuzzedDataProvider *provider) {
+
+  assert(provider != NULL);
+  switch (provider->ConsumeEnum<NetApiFuncs>()) {
+  
+  case kNetworkRecvRenew:
+    tud_network_recv_renew();
+    break;
+  case kNetworkCanXmit:
+ (void)tud_network_can_xmit(provider->ConsumeIntegral<uint16_t>());
+  case kNetworkXmit:
+    // TODO: Actually pass real values here later.
+    tud_network_xmit(NULL, 0);
+
+  case kMaxValue:
+    // Noop.
+    break;
+  }
+}
+}

+ 71 - 0
test/fuzz/device/net/src/lwipopts.h

@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * All rights reserved. 
+ * 
+ * Redistribution and use in source and binary forms, with or without modification, 
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Simon Goldschmidt
+ *
+ */
+#ifndef __LWIPOPTS_H__
+#define __LWIPOPTS_H__
+
+/* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */
+#define NO_SYS                          1
+#define MEM_ALIGNMENT                   4
+#define LWIP_RAW                        0
+#define LWIP_NETCONN                    0
+#define LWIP_SOCKET                     0
+#define LWIP_DHCP                       0
+#define LWIP_ICMP                       1
+#define LWIP_UDP                        1
+#define LWIP_TCP                        1
+#define LWIP_IPV4                       1
+#define LWIP_IPV6                       0
+#define ETH_PAD_SIZE                    0
+#define LWIP_IP_ACCEPT_UDP_PORT(p)      ((p) == PP_NTOHS(67))
+
+#define TCP_MSS                         (1500 /*mtu*/ - 20 /*iphdr*/ - 20 /*tcphhr*/)
+#define TCP_SND_BUF                     (2 * TCP_MSS)
+#define TCP_WND                         (TCP_MSS)
+
+#define ETHARP_SUPPORT_STATIC_ENTRIES   1
+
+#define LWIP_HTTPD_CGI                  0
+#define LWIP_HTTPD_SSI                  0
+#define LWIP_HTTPD_SSI_INCLUDE_TAG      0
+
+#define LWIP_SINGLE_NETIF               1
+
+#define PBUF_POOL_SIZE                  2
+
+#define HTTPD_USE_CUSTOM_FSDATA         0
+
+#define LWIP_MULTICAST_PING             1
+#define LWIP_BROADCAST_PING             1
+#define LWIP_IPV6_MLD                   0
+#define LWIP_IPV6_SEND_ROUTER_SOLICIT   0
+
+#endif /* __LWIPOPTS_H__ */

+ 122 - 0
test/fuzz/device/net/src/tusb_config.h

@@ -0,0 +1,122 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Nathaniel Brough
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Board Specific Configuration
+//--------------------------------------------------------------------+
+
+// RHPort number used for device can be defined by board.mk, default to port 0
+#ifndef BOARD_TUD_RHPORT
+#define BOARD_TUD_RHPORT      0
+#endif
+
+// RHPort max operational speed can defined by board.mk
+#ifndef BOARD_TUD_MAX_SPEED
+#define BOARD_TUD_MAX_SPEED   OPT_MODE_DEFAULT_SPEED
+#endif
+
+//--------------------------------------------------------------------
+// Common Configuration
+//--------------------------------------------------------------------
+
+// defined by compiler flags for flexibility
+#ifndef CFG_TUSB_MCU
+#error CFG_TUSB_MCU must be defined
+#endif
+
+#ifndef CFG_TUSB_OS
+#define CFG_TUSB_OS           OPT_OS_NONE
+#endif
+
+#ifndef CFG_TUSB_DEBUG
+#define CFG_TUSB_DEBUG        0
+#endif
+
+// Enable Device stack
+#define CFG_TUD_ENABLED       1
+
+// Default is max speed that hardware controller could support with on-chip PHY
+#define CFG_TUD_MAX_SPEED     BOARD_TUD_MAX_SPEED
+
+/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
+ * Tinyusb use follows macros to declare transferring memory so that they can be put
+ * into those specific section.
+ * e.g
+ * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
+ * - CFG_TUSB_MEM_ALIGN   : __attribute__ ((aligned(4)))
+ */
+#ifndef CFG_TUSB_MEM_SECTION
+#define CFG_TUSB_MEM_SECTION
+#endif
+
+#ifndef CFG_TUSB_MEM_ALIGN
+#define CFG_TUSB_MEM_ALIGN    __attribute__ ((aligned(4)))
+#endif
+
+//--------------------------------------------------------------------
+// DEVICE CONFIGURATION
+//--------------------------------------------------------------------
+
+#ifndef CFG_TUD_ENDPOINT0_SIZE
+#define CFG_TUD_ENDPOINT0_SIZE    64
+#endif
+
+//------------- CLASS -------------//
+#define CFG_TUD_CDC              1
+#define CFG_TUD_MSC              0
+#define CFG_TUD_HID              0
+#define CFG_TUD_MIDI             0
+#define CFG_TUD_VENDOR           0
+
+// Network class has 2 drivers: ECM/RNDIS and NCM.
+// Only one of the drivers can be enabled
+#define CFG_TUD_ECM_RNDIS     1
+#define CFG_TUD_NCM           (1-CFG_TUD_ECM_RNDIS)
+
+// CDC FIFO size of TX and RX
+#define CFG_TUD_CDC_RX_BUFSIZE   (TUD_OPT_HIGH_SPEED ? 512 : 64)
+#define CFG_TUD_CDC_TX_BUFSIZE   (TUD_OPT_HIGH_SPEED ? 512 : 64)
+
+// CDC Endpoint transfer buffer size, more is faster
+#define CFG_TUD_CDC_EP_BUFSIZE   (TUD_OPT_HIGH_SPEED ? 512 : 64)
+
+// MSC Buffer size of Device Mass storage
+#define CFG_TUD_MSC_EP_BUFSIZE   512
+
+
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */

+ 229 - 0
test/fuzz/device/net/src/usb_descriptors.cc

@@ -0,0 +1,229 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "tusb.h"
+
+/* A combination of interfaces must have a unique product id, since PC will save
+ * device driver after the first plug.
+ * Auto ProductID layout's Bitmap:
+ *   [MSB]         HID | CDC          [LSB]
+ */
+#define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n))
+#define USB_PID                                                                \
+  (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(HID, 2) | _PID_MAP(MIDI, 3) |          \
+   _PID_MAP(VENDOR, 4))
+
+#define USB_VID 0xCafe
+#define USB_BCD 0x0200
+
+//--------------------------------------------------------------------+
+// Device Descriptors
+//--------------------------------------------------------------------+
+
+// Invoked when received GET DEVICE DESCRIPTOR
+// Application return pointer to descriptor
+uint8_t const *tud_descriptor_device_cb(void) {
+  static tusb_desc_device_t const desc_device = {
+      .bLength = sizeof(tusb_desc_device_t),
+      .bDescriptorType = TUSB_DESC_DEVICE,
+      .bcdUSB = USB_BCD,
+
+      // Use Interface Association Descriptor (IAD) for CDC
+      // As required by USB Specs IAD's subclass must be common class (2) and
+      // protocol must be IAD (1)
+      .bDeviceClass = TUSB_CLASS_MISC,
+      .bDeviceSubClass = MISC_SUBCLASS_COMMON,
+      .bDeviceProtocol = MISC_PROTOCOL_IAD,
+
+      .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+
+      .idVendor = USB_VID,
+      .idProduct = USB_PID,
+      .bcdDevice = 0x0100,
+
+      .iManufacturer = 0x01,
+      .iProduct = 0x02,
+      .iSerialNumber = 0x03,
+
+      .bNumConfigurations = 0x01};
+
+  return (uint8_t const *)&desc_device;
+}
+
+//--------------------------------------------------------------------+
+// Configuration Descriptor
+//--------------------------------------------------------------------+
+
+enum { ITF_NUM_CDC = 0, ITF_NUM_CDC_DATA, ITF_NUM_TOTAL };
+
+#define EPNUM_CDC_NOTIF 0x81
+#define EPNUM_CDC_OUT 0x02
+#define EPNUM_CDC_IN 0x82
+
+#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
+
+// full speed configuration
+uint8_t const desc_fs_configuration[] = {
+    // Config number, interface count, string index, total length, attribute,
+    // power in mA
+    TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
+
+    // Interface number, string index, EP notification address and size, EP data
+    // address (out, in) and size.
+    TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT,
+                       EPNUM_CDC_IN, 64),
+};
+
+#if TUD_OPT_HIGH_SPEED
+// Per USB specs: high speed capable device must report device_qualifier and
+// other_speed_configuration
+
+// high speed configuration
+uint8_t const desc_hs_configuration[] = {
+    // Config number, interface count, string index, total length, attribute,
+    // power in mA
+    TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
+
+    // Interface number, string index, EP notification address and size, EP data
+    // address (out, in) and size.
+    TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT,
+                       EPNUM_CDC_IN, 512),
+};
+
+// other speed configuration
+uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN];
+
+// device qualifier is mostly similar to device descriptor since we don't change
+// configuration based on speed
+tusb_desc_device_qualifier_t const desc_device_qualifier = {
+    .bLength = sizeof(tusb_desc_device_qualifier_t),
+    .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
+    .bcdUSB = USB_BCD,
+
+    .bDeviceClass = TUSB_CLASS_MISC,
+    .bDeviceSubClass = MISC_SUBCLASS_COMMON,
+    .bDeviceProtocol = MISC_PROTOCOL_IAD,
+
+    .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+    .bNumConfigurations = 0x01,
+    .bReserved = 0x00};
+
+// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long
+// enough for transfer to complete. device_qualifier descriptor describes
+// information about a high-speed capable device that would change if the device
+// were operating at the other speed. If not highspeed capable stall this
+// request.
+uint8_t const *tud_descriptor_device_qualifier_cb(void) {
+  return (uint8_t const *)&desc_device_qualifier;
+}
+
+// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long
+// enough for transfer to complete Configuration descriptor in the other speed
+// e.g if high speed then this is for full speed and vice versa
+uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
+  (void)index; // for multiple configurations
+
+  // if link speed is high return fullspeed config, and vice versa
+  // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
+  memcpy(desc_other_speed_config,
+         (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration
+                                              : desc_hs_configuration,
+         CONFIG_TOTAL_LEN);
+
+  desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
+
+  return desc_other_speed_config;
+}
+
+#endif // highspeed
+
+// Invoked when received GET CONFIGURATION DESCRIPTOR
+// Application return pointer to descriptor
+// Descriptor contents must exist long enough for transfer to complete
+uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
+  (void)index; // for multiple configurations
+
+#if TUD_OPT_HIGH_SPEED
+  // Although we are highspeed, host may be fullspeed.
+  return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration
+                                              : desc_fs_configuration;
+#else
+  return desc_fs_configuration;
+#endif
+}
+
+//--------------------------------------------------------------------+
+// String Descriptors
+//--------------------------------------------------------------------+
+
+// array of pointer to string descriptors
+char const *string_desc_arr[] = {
+    (const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
+    "TinyUSB",                  // 1: Manufacturer
+    "TinyUSB Device",           // 2: Product
+    "123456789012",             // 3: Serials, should use chip ID
+    "TinyUSB CDC",              // 4: CDC Interface
+};
+
+static uint16_t _desc_str[32];
+
+// Invoked when received GET STRING DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long
+// enough for transfer to complete
+uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
+  (void)langid;
+
+  uint8_t chr_count;
+
+  if (index == 0) {
+    memcpy(&_desc_str[1], string_desc_arr[0], 2);
+    chr_count = 1;
+  } else {
+    // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
+    // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
+
+    if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])))
+      return NULL;
+
+    const char *str = string_desc_arr[index];
+
+    // Cap at max char
+    chr_count = (uint8_t)strlen(str);
+    if (chr_count > 31)
+      chr_count = 31;
+
+    // Convert ASCII string into UTF-16
+    for (uint8_t i = 0; i < chr_count; i++) {
+      _desc_str[1 + i] = str[i];
+    }
+  }
+
+  // first byte is length (including header), second byte is string type
+  _desc_str[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
+
+  return _desc_str;
+}

+ 74 - 0
test/fuzz/dicts/cdc.dict

@@ -0,0 +1,74 @@
+# List of supported OIDs
+RNDIS_OID_GEN_SUPPORTED_LIST="\x00\x01\x01\x01"
+# Hardware status
+RNDIS_OID_GEN_HARDWARE_STATUS="\x00\x01\x01\x02"
+# Media types supported (encoded)
+RNDIS_OID_GEN_MEDIA_SUPPORTED="\x00\x01\x01\x03"
+# Media types in use (encoded)
+RNDIS_OID_GEN_MEDIA_IN_USE="\x00\x01\x01\x04"
+RNDIS_OID_GEN_MAXIMUM_LOOKAHEAD="\x00\x01\x01\x05"
+# Maximum frame size in bytes
+RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE="\x00\x01\x01\x06"
+# Link speed in units of 100 bps
+RNDIS_OID_GEN_LINK_SPEED="\x00\x01\x01\x07"
+# Transmit buffer space
+RNDIS_OID_GEN_TRANSMIT_BUFFER_SPACE="\x00\x01\x01\x08"
+# Receive buffer space
+RNDIS_OID_GEN_RECEIVE_BUFFER_SPACE="\x00\x01\x01\x09"
+# NDIS version number used by the driver
+RNDIS_OID_GEN_DRIVER_VERSION="\x00\x01\x01\x10"
+# Maximum total packet length in bytes
+RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE="\x00\x01\x01\x11"
+# Optional protocol flags (encoded)
+RNDIS_OID_GEN_PROTOCOL_OPTIONS="\x00\x01\x01\x12"
+# Optional NIC flags (encoded)
+RNDIS_OID_GEN_MAC_OPTIONS="\x00\x01\x01\x13"
+# Whether the NIC is connected to the network
+RNDIS_OID_GEN_MEDIA_CONNECT_STATUS="\x00\x01\x01\x14"
+# The maximum number of send packets the driver can accept per call to its MiniportSendPacketsfunction
+RNDIS_OID_GEN_MAXIMUM_SEND_PACKETS="\x00\x01\x01\x15"
+# Vendor-assigned version number of the driver
+RNDIS_OID_GEN_VENDOR_DRIVER_VERSION="\x00\x01\x01\x16"
+# The custom GUIDs (Globally Unique Identifier) supported by the miniport driver
+RNDIS_OID_GEN_SUPPORTED_GUIDS="\x00\x01\x01\x17"
+# List of network-layer addresses associated with the binding between a transport and the driver
+RNDIS_OID_GEN_NETWORK_LAYER_ADDRESSES="\x00\x01\x01\x18"
+# Size of packets' additional headers
+RNDIS_OID_GEN_TRANSPORT_HEADER_OFFSET="\x00\x01\x01\x19"
+RNDIS_OID_GEN_MEDIA_CAPABILITIES="\x00\x01\x02\x01"
+# Physical media supported by the miniport driver (encoded)
+RNDIS_OID_GEN_PHYSICAL_MEDIUM="\x00\x01\x02\x02"
+# Permanent station address
+RNDIS_OID_802_3_PERMANENT_ADDRESS="\x01\x01\x01\x01"
+# Current station address
+RNDIS_OID_802_3_CURRENT_ADDRESS="\x01\x01\x01\x02"
+# Current multicast address list
+RNDIS_OID_802_3_MULTICAST_LIST="\x01\x01\x01\x03"
+# Maximum size of multicast address list
+RNDIS_OID_802_3_MAXIMUM_LIST_SIZE="\x01\x01\x01\x04"
+# Directed packets. Directed packets contain a destination address equal to the station address of the NIC.
+RNDIS_PACKET_TYPE_DIRECTED="\x00\x00\x00\x01"
+# Multicast address packets sent to addresses in the multicast address list.
+RNDIS_PACKET_TYPE_MULTICAST="\x00\x00\x00\x02"
+# All multicast address packets, not just the ones enumerated in the multicast address list.
+RNDIS_PACKET_TYPE_ALL_MULTICAST="\x00\x00\x00\x04"
+# Broadcast packets.
+RNDIS_PACKET_TYPE_BROADCAST="\x00\x00\x00\x08"
+# All source routing packets. If the protocol driver sets this bit, the NDIS library attempts to act as a source routing bridge.
+RNDIS_PACKET_TYPE_SOURCE_ROUTING="\x00\x00\x00\x10"
+# Specifies all packets regardless of whether VLAN filtering is enabled or not and whether the VLAN identifier matches or not.
+RNDIS_PACKET_TYPE_PROMISCUOUS="\x00\x00\x00\x20"
+# SMT packets that an FDDI NIC receives.
+RNDIS_PACKET_TYPE_SMT="\x00\x00\x00\x40"
+# All packets sent by installed protocols and all packets indicated by the NIC that is identified by a given NdisBindingHandle.
+RNDIS_PACKET_TYPE_ALL_LOCAL="\x00\x00\x00\x80"
+# Packets sent to the current group address.
+RNDIS_PACKET_TYPE_GROUP="\x00\x00\x10\x00"
+# All functional address packets, not just the ones in the current functional address.
+RNDIS_PACKET_TYPE_ALL_FUNCTIONAL="\x00\x00\x20\x00"
+# Functional address packets sent to addresses included in the current functional address.
+RNDIS_PACKET_TYPE_FUNCTIONAL="\x00\x00\x40\x00"
+# NIC driver frames that a Token Ring NIC receives.
+RNDIS_PACKET_TYPE_MAC_FRAME="\x00\x00\x80\x00"
+RNDIS_PACKET_TYPE_NO_LOCAL="\x00\x01\x00\x00"
+

+ 34 - 0
test/fuzz/fuzz.cc

@@ -0,0 +1,34 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Nathaniel Brough
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include <optional>
+
+std::optional<FuzzedDataProvider> _fuzz_data_provider;
+
+extern "C" int fuzz_init(const uint8_t *data, size_t size) {
+  _fuzz_data_provider.emplace(data, size);
+  return 0;
+}

+ 37 - 0
test/fuzz/fuzz.h

@@ -0,0 +1,37 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Nathaniel Brough
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#pragma once
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int fuzz_init(const uint8_t *data, size_t size);
+
+#ifdef __cplusplus
+}
+#endif

+ 30 - 0
test/fuzz/fuzz_private.h

@@ -0,0 +1,30 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Nathaniel Brough
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#pragma once
+#include "fuzzer/FuzzedDataProvider.h"
+#include <optional>
+
+extern std::optional<FuzzedDataProvider> _fuzz_data_provider;

+ 104 - 0
test/fuzz/make.mk

@@ -0,0 +1,104 @@
+# ---------------------------------------
+# Common make definition for all examples
+# ---------------------------------------
+
+# Build directory
+BUILD := _build
+PROJECT := $(notdir $(CURDIR))
+
+# Handy check parameter function
+check_defined = \
+    $(strip $(foreach 1,$1, \
+    $(call __check_defined,$1,$(strip $(value 2)))))
+__check_defined = \
+    $(if $(value $1),, \
+    $(error Undefined make flag: $1$(if $2, ($2))))
+
+#-------------- Fuzz harness compiler  ------------
+
+CC = clang
+CXX = clang++
+GDB = gdb
+OBJCOPY = objcopy
+SIZE = size
+MKDIR = mkdir
+
+ifeq ($(CMDEXE),1)
+  CP = copy
+  RM = del
+  PYTHON = python
+else
+  SED = sed
+  CP = cp
+  RM = rm
+  PYTHON = python3
+endif
+
+#-------------- Source files and compiler flags --------------
+
+
+INC += $(TOP)/test
+
+# Compiler Flags
+CFLAGS += \
+  -ggdb \
+  -fsanitize=fuzzer \
+  -fsanitize=address \
+  -fsanitize=undefined \
+  -fdata-sections \
+  -ffunction-sections \
+  -fno-strict-aliasing \
+  -Wall \
+  -Wextra \
+  -Werror \
+  -Wfatal-errors \
+  -Wdouble-promotion \
+  -Wstrict-prototypes \
+  -Wstrict-overflow \
+  -Werror-implicit-function-declaration \
+  -Wfloat-equal \
+  -Wundef \
+  -Wshadow \
+  -Wwrite-strings \
+  -Wsign-compare \
+  -Wmissing-format-attribute \
+  -Wunreachable-code \
+  -Wcast-align \
+  -Wcast-qual \
+  -Wnull-dereference \
+  -Wuninitialized \
+  -Wunused \
+  -Wredundant-decls \
+  -O1
+
+CFLAGS += \
+	-Wno-error=unreachable-code \
+  -DOPT_MCU_FUZZ=1 \
+  -DCFG_TUSB_MCU=OPT_MCU_FUZZ 
+
+CXXFLAGS += \
+  -xc++ \
+  -Wno-c++11-narrowing \
+  -fno-implicit-templates
+
+# conversion is too strict for most mcu driver, may be disable sign/int/arith-conversion
+#  -Wconversion
+  
+# Debugging/Optimization
+ifeq ($(DEBUG), 1)
+  CFLAGS += -Og
+else
+  CFLAGS += $(CFLAGS_OPTIMIZED)
+endif
+
+# Log level is mapped to TUSB DEBUG option
+ifneq ($(LOG),)
+  CMAKE_DEFSYM +=	-DLOG=$(LOG)
+  CFLAGS += -DCFG_TUSB_DEBUG=$(LOG)
+endif
+
+# Logger: default is uart, can be set to rtt or swo
+ifneq ($(LOGGER),)
+	CMAKE_DEFSYM +=	-DLOGGER=$(LOGGER)
+endif
+

+ 162 - 0
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

+ 82 - 0
test/fuzz/net_fuzz.cc

@@ -0,0 +1,82 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Nathaniel Brough
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "tusb_config.h"
+#if defined(CFG_TUD_ECM_RNDIS) || defined(CFG_TUD_NCM)
+
+#include "class/net/net_device.h"
+#include "fuzz_private.h"
+#include <cassert>
+#include <cstdint>
+#include <vector>
+#include "lwip/sys.h"
+
+extern "C" {
+bool tud_network_recv_cb(const uint8_t *src, uint16_t size) {
+  assert(_fuzz_data_provider.has_value());
+  (void)src;
+  (void)size;
+  return _fuzz_data_provider->ConsumeBool();
+}
+
+// client must provide this: copy from network stack packet pointer to dst
+uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) {
+  (void)ref;
+  (void)arg;
+
+  assert(_fuzz_data_provider.has_value());
+
+  uint16_t size = _fuzz_data_provider->ConsumeIntegral<uint16_t>();
+  std::vector<uint8_t> temp = _fuzz_data_provider->ConsumeBytes<uint8_t>(size);
+  memcpy(dst, temp.data(), temp.size());
+  return size;
+}
+
+/* lwip has provision for using a mutex, when applicable */
+sys_prot_t sys_arch_protect(void) { return 0; }
+void sys_arch_unprotect(sys_prot_t pval) { (void)pval; }
+
+//------------- ECM/RNDIS -------------//
+
+// client must provide this: initialize any network state back to the beginning
+void tud_network_init_cb(void) {
+  // NoOp.
+}
+
+// client must provide this: 48-bit MAC address
+// TODO removed later since it is not part of tinyusb stack
+const uint8_t tud_network_mac_address[6] = {0};
+
+//------------- NCM -------------//
+
+// callback to client providing optional indication of internal state of network
+// driver
+void tud_network_link_state_cb(bool state) {
+  (void)state;
+  // NoOp.
+}
+}
+
+#endif

+ 161 - 0
test/fuzz/rules.mk

@@ -0,0 +1,161 @@
+# ---------------------------------------
+# Common make rules for all examples
+# ---------------------------------------
+
+# Set all as default goal
+.DEFAULT_GOAL := all
+
+# ---------------------------------------
+# Compiler Flags
+# ---------------------------------------
+
+LIBS_GCC ?=  -lm
+
+# libc
+LIBS += $(LIBS_GCC)
+
+ifneq ($(BOARD), spresense)
+LIBS += -lc -Wl,-Bstatic -lc++ -Wl,-Bdynamic
+endif
+
+# TinyUSB Stack source
+SRC_C += \
+	src/tusb.c \
+	src/common/tusb_fifo.c \
+	src/device/usbd.c \
+	src/device/usbd_control.c \
+	src/class/audio/audio_device.c \
+	src/class/cdc/cdc_device.c \
+	src/class/dfu/dfu_device.c \
+	src/class/dfu/dfu_rt_device.c \
+	src/class/hid/hid_device.c \
+	src/class/midi/midi_device.c \
+	src/class/msc/msc_device.c \
+	src/class/net/ecm_rndis_device.c \
+	src/class/net/ncm_device.c \
+	src/class/usbtmc/usbtmc_device.c \
+	src/class/video/video_device.c \
+	src/class/vendor/vendor_device.c
+
+
+# Fuzzers are c++
+SRC_CXX += \
+	test/fuzz/dcd_fuzz.cc \
+	test/fuzz/fuzz.cc \
+	test/fuzz/msc_fuzz.cc \
+	test/fuzz/net_fuzz.cc \
+	test/fuzz/usbd_fuzz.cc
+
+# TinyUSB stack include
+INC += $(TOP)/src
+
+CFLAGS += $(addprefix -I,$(INC))
+CXXFLAGS += -std=c++17
+
+# LTO makes it difficult to analyze map file for optimizing size purpose
+# We will run this option in ci
+ifeq ($(NO_LTO),1)
+CFLAGS := $(filter-out -flto,$(CFLAGS))
+endif
+
+ifneq ($(LD_FILE),)
+LDFLAGS_LD_FILE ?= -Wl,-T,$(TOP)/$(LD_FILE)
+endif
+
+LDFLAGS += $(CFLAGS) $(LDFLAGS_LD_FILE) -fuse-ld=lld -Wl,-Map=$@.map -Wl,--cref -Wl,-gc-sections
+ifneq ($(SKIP_NANOLIB), 1)
+endif
+
+ASFLAGS += $(CFLAGS)
+
+# Assembly files can be name with upper case .S, convert it to .s
+SRC_S := $(SRC_S:.S=.s)
+
+# Due to GCC LTO bug https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966
+# assembly file should be placed first in linking order
+# '_asm' suffix is added to object of assembly file
+OBJ += $(addprefix $(BUILD)/obj/, $(SRC_S:.s=_asm.o))
+OBJ += $(addprefix $(BUILD)/obj/, $(SRC_C:.c=.o))
+OBJ += $(addprefix $(BUILD)/obj/, $(SRC_CXX:.cc=_cxx.o))
+
+# Verbose mode
+ifeq ("$(V)","1")
+$(info CFLAGS  $(CFLAGS) ) $(info )
+$(info LDFLAGS $(LDFLAGS)) $(info )
+$(info ASFLAGS $(ASFLAGS)) $(info )
+endif
+
+# ---------------------------------------
+# Rules
+# ---------------------------------------
+
+all: $(BUILD)/$(PROJECT) 
+
+OBJ_DIRS = $(sort $(dir $(OBJ)))
+$(OBJ): | $(OBJ_DIRS)
+$(OBJ_DIRS):
+ifeq ($(CMDEXE),1)
+	@$(MKDIR) $(subst /,\,$@)
+else
+	@$(MKDIR) -p $@
+endif
+
+$(BUILD)/$(PROJECT): $(OBJ)
+	@echo LINK $@
+	@ $(CXX) -o $@  $(LIB_FUZZING_ENGINE) $^ $(LIBS) $(LDFLAGS)
+
+# We set vpath to point to the top of the tree so that the source files
+# can be located. By following this scheme, it allows a single build rule
+# to be used to compile all .c files.
+vpath %.c . $(TOP)
+$(BUILD)/obj/%.o: %.c
+	@echo CC $(notdir $@)
+	@$(CC) $(CFLAGS) -c -MD -o $@ $<
+	
+# All cpp srcs
+vpath %.cc . $(TOP)
+$(BUILD)/obj/%_cxx.o: %.cc
+	@echo CXX $(notdir $@)
+	@$(CXX) $(CFLAGS) $(CXXFLAGS) -c -MD -o $@ $<
+
+# ASM sources lower case .s
+vpath %.s . $(TOP)
+$(BUILD)/obj/%_asm.o: %.s
+	@echo AS $(notdir $@)
+	@$(CC) -x assembler-with-cpp $(ASFLAGS) -c -o $@ $<
+
+# ASM sources upper case .S
+vpath %.S . $(TOP)
+$(BUILD)/obj/%_asm.o: %.S
+	@echo AS $(notdir $@)
+	@$(CC) -x assembler-with-cpp $(ASFLAGS) -c -o $@ $<
+
+.PHONY: clean
+clean:
+ifeq ($(CMDEXE),1)
+	rd /S /Q $(subst /,\,$(BUILD))
+else
+	$(RM) -rf $(BUILD)
+endif
+# ---------------- GNU Make End -----------------------
+
+# get depenecies
+.PHONY: get-deps
+get-deps:
+  ifdef DEPS_SUBMODULES
+	git -C $(TOP) submodule update --init $(DEPS_SUBMODULES)
+  endif
+
+size: $(BUILD)/$(PROJECT)
+	-@echo ''
+	@$(SIZE) $<
+	-@echo ''
+
+# linkermap must be install previously at https://github.com/hathach/linkermap
+linkermap: $(BUILD)/$(PROJECT)
+	@linkermap -v $<.map
+
+# Print out the value of a make variable.
+# https://stackoverflow.com/questions/16467718/how-to-print-out-a-variable-in-makefile
+print-%:
+	@echo $* = $($*)

+ 73 - 0
test/fuzz/usbd_fuzz.cc

@@ -0,0 +1,73 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Nathaniel Brough
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "fuzz/fuzz_private.h"
+#include "tusb.h"
+// #include "usb_descriptors.h"
+
+#ifndef CFG_FUZZ_MAX_STRING_LEN
+#define CFG_FUZZ_MAX_STRING_LEN 1000
+#endif
+
+extern "C" {
+
+/* TODO: Implement a fuzzed version of this.
+uint8_t const *tud_descriptor_bos_cb(void) {  }
+*/
+
+/* TODO: Implement a fuzzed version of this.
+uint8_t const *tud_descriptor_device_qualifier_cb(void) {}
+*/
+
+/* TODO: Implement a fuzzed version of this.
+uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {}
+*/
+
+void tud_mount_cb(void) {
+  // NOOP
+}
+
+void tud_umount_cb(void) {
+  // NOOP
+}
+
+void tud_suspend_cb(bool remote_wakeup_en) {
+  (void)remote_wakeup_en;
+  // NOOP
+}
+
+void tud_resume_cb(void) {
+  // NOOP
+}
+
+/* TODO: Implement a fuzzed version of this.
+bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage,
+                                tusb_control_request_t const *request) {}
+*/
+
+/* TODO: Implement a fuzzed version of this.
+uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {}
+*/
+}