From 56f846cf74961eecd00242276dd566e1b6134e10 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 8 Dec 2022 10:39:54 +0700 Subject: move fuzz into test/fuzz --- test/fuzz/device/msc/CMakeLists.txt | 29 ++++ test/fuzz/device/msc/Makefile | 12 ++ test/fuzz/device/msc/src/fuzz.cc | 62 ++++++++ test/fuzz/device/msc/src/tusb_config.h | 114 ++++++++++++++ test/fuzz/device/msc/src/usb_descriptors.cc | 224 ++++++++++++++++++++++++++++ 5 files changed, 441 insertions(+) create mode 100644 test/fuzz/device/msc/CMakeLists.txt create mode 100644 test/fuzz/device/msc/Makefile create mode 100644 test/fuzz/device/msc/src/fuzz.cc create mode 100644 test/fuzz/device/msc/src/tusb_config.h create mode 100644 test/fuzz/device/msc/src/usb_descriptors.cc (limited to 'test/fuzz/device/msc') diff --git a/test/fuzz/device/msc/CMakeLists.txt b/test/fuzz/device/msc/CMakeLists.txt new file mode 100644 index 000000000..fa6e83b7e --- /dev/null +++ b/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. -) +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}) \ No newline at end of file diff --git a/test/fuzz/device/msc/Makefile b/test/fuzz/device/msc/Makefile new file mode 100644 index 000000000..ee51936b5 --- /dev/null +++ b/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 diff --git a/test/fuzz/device/msc/src/fuzz.cc b/test/fuzz/device/msc/src/fuzz.cc new file mode 100644 index 000000000..568900452 --- /dev/null +++ b/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 +#include +#include +#include +#include + +#include "class/cdc/cdc_device.h" +#include "fuzz/fuzz.h" +#include "tusb.h" +#include +#include +#include + +//--------------------------------------------------------------------+ +// 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 callback_data = provider.ConsumeBytes( + provider.ConsumeIntegralInRange(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()); + tud_task(); // tinyusb device task + } + + return 0; +} + diff --git a/test/fuzz/device/msc/src/tusb_config.h b/test/fuzz/device/msc/src/tusb_config.h new file mode 100644 index 000000000..ca39c6b0a --- /dev/null +++ b/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_ */ diff --git a/test/fuzz/device/msc/src/usb_descriptors.cc b/test/fuzz/device/msc/src/usb_descriptors.cc new file mode 100644 index 000000000..ded401fc9 --- /dev/null +++ b/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; +} -- cgit v1.3.1 From 02f1f0569723611d591b8bdd72b12a084a4f39d0 Mon Sep 17 00:00:00 2001 From: Nathaniel Brough Date: Sun, 29 Jan 2023 09:38:05 -0800 Subject: feat(fuzz): Adds seed corpus for cdc and msc classes --- test/fuzz/device/cdc/cdc_seed_corpus.zip | Bin 0 -> 50127 bytes test/fuzz/device/msc/msc_seed_corpus.zip | Bin 0 -> 50127 bytes tools/pcapng_to_corpus.py | 46 +++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 test/fuzz/device/cdc/cdc_seed_corpus.zip create mode 100644 test/fuzz/device/msc/msc_seed_corpus.zip create mode 100755 tools/pcapng_to_corpus.py (limited to 'test/fuzz/device/msc') diff --git a/test/fuzz/device/cdc/cdc_seed_corpus.zip b/test/fuzz/device/cdc/cdc_seed_corpus.zip new file mode 100644 index 000000000..81bc2240d Binary files /dev/null and b/test/fuzz/device/cdc/cdc_seed_corpus.zip differ diff --git a/test/fuzz/device/msc/msc_seed_corpus.zip b/test/fuzz/device/msc/msc_seed_corpus.zip new file mode 100644 index 000000000..81bc2240d Binary files /dev/null and b/test/fuzz/device/msc/msc_seed_corpus.zip differ diff --git a/tools/pcapng_to_corpus.py b/tools/pcapng_to_corpus.py new file mode 100755 index 000000000..78b1f77a2 --- /dev/null +++ b/tools/pcapng_to_corpus.py @@ -0,0 +1,46 @@ +#!/bin/python3 +import argparse +import pcapng +import zipfile +import hashlib + +def extract_packets(pcap_file): + """Reads a wireshark packet capture and extracts the binary packets""" + packets = [] + with open(pcap_file, 'rb') as fp: + scanner = pcapng.FileScanner(fp) + for block in scanner: + if isinstance(block, pcapng.blocks.EnhancedPacket): + packets.append(block.packet_data) + return packets + +def build_corpus_zip(zip_file_output, packets): + """Builds a zip file with a file per packet + + The structure of this zip corpus is a simple content addressable storage + i.e. seed_file_name == sha256_digest(packet). + """ + with zipfile.ZipFile(zip_file_output, 'a') as out: + for packet in packets: + hash = hashlib.sha256(packet).hexdigest() + if hash not in out.namelist(): + out.writestr(hash, packet) + + +def main(pcap_file, output_zip_file): + packets = extract_packets(pcap_file) + build_corpus_zip(output_zip_file, packets) + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + prog = "pcapng_to_corpus.py", + description="""Converts a wireshark capture to a zip of binary packet + files suitable for an oss-fuzz corpus. In the case the + zip corpus already exists, this script will modify + the zip file in place adding seed entries.""") + parser.add_argument('pcapng_capture_file') + parser.add_argument('oss_fuzz_corpus_zip') + args = parser.parse_args() + main(args.pcapng_capture_file, args.oss_fuzz_corpus_zip) + + -- cgit v1.3.1