mirror of
https://github.com/reactos/syzkaller.git
synced 2025-03-03 17:17:39 +00:00
executor: add support for USB fuzzing on NetBSD
This commit is contained in:
parent
8f2ad84be9
commit
67fa1f59b8
@ -11,6 +11,17 @@
|
||||
#include <string.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#if GOOS_netbsd
|
||||
#if SYZ_EXECUTOR || __NR_syz_usb_connect
|
||||
#include "common_usb_netbsd.h"
|
||||
static void setup_usb(void)
|
||||
{
|
||||
if (chmod("/dev/vhci", 0666))
|
||||
fail("failed to chmod /dev/vhci");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if GOOS_openbsd
|
||||
|
||||
#define __syscall syscall
|
||||
|
@ -1463,7 +1463,7 @@ static long syz_extract_tcp_res(volatile long a0, volatile long a1, volatile lon
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "common_usb.h"
|
||||
#include "common_usb_linux.h"
|
||||
#endif
|
||||
|
||||
#if SYZ_EXECUTOR || __NR_syz_open_dev
|
||||
|
@ -684,7 +684,7 @@ static bool lookup_connect_response_out_generic(int fd, const struct vusb_connec
|
||||
}
|
||||
#endif // SYZ_EXECUTOR || __NR_syz_usb_connect
|
||||
|
||||
#if SYZ_EXECUTOR || __NR_syz_usb_connect_ath9k
|
||||
#if GOOS_linux && (SYZ_EXECUTOR || __NR_syz_usb_connect_ath9k)
|
||||
|
||||
// drivers/net/wireless/ath/ath9k/hif_usb.h
|
||||
#define ATH9K_FIRMWARE_DOWNLOAD 0x30
|
||||
@ -721,7 +721,7 @@ static bool lookup_connect_response_out_ath9k(int fd, const struct vusb_connect_
|
||||
|
||||
#endif // SYZ_EXECUTOR || __NR_syz_usb_connect_ath9k
|
||||
|
||||
#if SYZ_EXECUTOR || __NR_syz_usb_control_io
|
||||
#if GOOS_linux && (SYZ_EXECUTOR || __NR_syz_usb_control_io)
|
||||
|
||||
struct vusb_descriptor {
|
||||
uint8 req_type;
|
||||
@ -820,9 +820,3 @@ static bool lookup_control_response(const struct vusb_descriptors* descs, const
|
||||
}
|
||||
|
||||
#endif // SYZ_EXECUTOR || __NR_syz_usb_control_io
|
||||
|
||||
#if GOOS_linux
|
||||
#include "common_usb_linux.h"
|
||||
#else
|
||||
#error "unknown OS"
|
||||
#endif // GOOS_linux
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
// Linux-specific implementation of syz_usb_* pseudo-syscalls.
|
||||
|
||||
#include "common_usb.h"
|
||||
|
||||
#define UDC_NAME_LENGTH_MAX 128
|
||||
|
||||
struct usb_raw_init {
|
||||
|
379
executor/common_usb_netbsd.h
Normal file
379
executor/common_usb_netbsd.h
Normal file
@ -0,0 +1,379 @@
|
||||
// Copyright 2020 syzkaller project authors. All rights reserved.
|
||||
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
||||
|
||||
// This file is shared between executor and csource package.
|
||||
|
||||
// NetBSD-specific implementation of syz_usb_* pseudo-syscalls.
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbhid.h>
|
||||
#include <dev/usb/vhci.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Redefinitions to match the linux types used in common_usb.h.
|
||||
*/
|
||||
|
||||
struct usb_endpoint_descriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bEndpointAddress;
|
||||
uint8_t bmAttributes;
|
||||
uint16_t wMaxPacketSize;
|
||||
uint8_t bInterval;
|
||||
uint8_t bRefresh;
|
||||
uint8_t bSynchAddress;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct usb_device_descriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t bcdUSB;
|
||||
uint8_t bDeviceClass;
|
||||
uint8_t bDeviceSubClass;
|
||||
uint8_t bDeviceProtocol;
|
||||
uint8_t bMaxPacketSize0;
|
||||
uint16_t idVendor;
|
||||
uint16_t idProduct;
|
||||
uint16_t bcdDevice;
|
||||
uint8_t iManufacturer;
|
||||
uint8_t iProduct;
|
||||
uint8_t iSerialNumber;
|
||||
uint8_t bNumConfigurations;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct usb_config_descriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
|
||||
uint16_t wTotalLength;
|
||||
uint8_t bNumInterfaces;
|
||||
uint8_t bConfigurationValue;
|
||||
uint8_t iConfiguration;
|
||||
uint8_t bmAttributes;
|
||||
uint8_t bMaxPower;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct usb_interface_descriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bInterfaceNumber;
|
||||
uint8_t bAlternateSetting;
|
||||
uint8_t bNumEndpoints;
|
||||
uint8_t bInterfaceClass;
|
||||
uint8_t bInterfaceSubClass;
|
||||
uint8_t bInterfaceProtocol;
|
||||
uint8_t iInterface;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct usb_ctrlrequest {
|
||||
uint8_t bRequestType;
|
||||
uint8_t bRequest;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct usb_qualifier_descriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t bcdUSB;
|
||||
uint8_t bDeviceClass;
|
||||
uint8_t bDeviceSubClass;
|
||||
uint8_t bDeviceProtocol;
|
||||
uint8_t bMaxPacketSize0;
|
||||
uint8_t bNumConfigurations;
|
||||
uint8_t bRESERVED;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define USB_TYPE_MASK (0x03 << 5)
|
||||
#define USB_TYPE_STANDARD (0x00 << 5)
|
||||
#define USB_TYPE_CLASS (0x01 << 5)
|
||||
#define USB_TYPE_VENDOR (0x02 << 5)
|
||||
#define USB_TYPE_RESERVED (0x03 << 5)
|
||||
|
||||
#define USB_DT_DEVICE 0x01
|
||||
#define USB_DT_CONFIG 0x02
|
||||
#define USB_DT_STRING 0x03
|
||||
#define USB_DT_INTERFACE 0x04
|
||||
#define USB_DT_ENDPOINT 0x05
|
||||
#define USB_DT_DEVICE_QUALIFIER 0x06
|
||||
#define USB_DT_OTHER_SPEED_CONFIG 0x07
|
||||
#define USB_DT_INTERFACE_POWER 0x08
|
||||
#define USB_DT_OTG 0x09
|
||||
#define USB_DT_DEBUG 0x0a
|
||||
#define USB_DT_INTERFACE_ASSOCIATION 0x0b
|
||||
#define USB_DT_SECURITY 0x0c
|
||||
#define USB_DT_KEY 0x0d
|
||||
#define USB_DT_ENCRYPTION_TYPE 0x0e
|
||||
#define USB_DT_BOS 0x0f
|
||||
#define USB_DT_DEVICE_CAPABILITY 0x10
|
||||
#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11
|
||||
#define USB_DT_WIRE_ADAPTER 0x21
|
||||
#define USB_DT_RPIPE 0x22
|
||||
#define USB_DT_CS_RADIO_CONTROL 0x23
|
||||
#define USB_DT_PIPE_USAGE 0x24
|
||||
#define USB_DT_SS_ENDPOINT_COMP 0x30
|
||||
#define USB_DT_SSP_ISOC_ENDPOINT_COMP 0x31
|
||||
|
||||
#define USB_REQ_GET_STATUS 0x00
|
||||
#define USB_REQ_CLEAR_FEATURE 0x01
|
||||
#define USB_REQ_SET_FEATURE 0x03
|
||||
#define USB_REQ_SET_ADDRESS 0x05
|
||||
#define USB_REQ_GET_DESCRIPTOR 0x06
|
||||
#define USB_REQ_SET_DESCRIPTOR 0x07
|
||||
#define USB_REQ_GET_CONFIGURATION 0x08
|
||||
#define USB_REQ_SET_CONFIGURATION 0x09
|
||||
#define USB_REQ_GET_INTERFACE 0x0A
|
||||
#define USB_REQ_SET_INTERFACE 0x0B
|
||||
#define USB_REQ_SYNCH_FRAME 0x0C
|
||||
#define USB_REQ_SET_SEL 0x30
|
||||
#define USB_REQ_SET_ISOCH_DELAY 0x31
|
||||
|
||||
#define USB_REQ_SET_ENCRYPTION 0x0D
|
||||
#define USB_REQ_GET_ENCRYPTION 0x0E
|
||||
#define USB_REQ_RPIPE_ABORT 0x0E
|
||||
#define USB_REQ_SET_HANDSHAKE 0x0F
|
||||
#define USB_REQ_RPIPE_RESET 0x0F
|
||||
#define USB_REQ_GET_HANDSHAKE 0x10
|
||||
#define USB_REQ_SET_CONNECTION 0x11
|
||||
#define USB_REQ_SET_SECURITY_DATA 0x12
|
||||
#define USB_REQ_GET_SECURITY_DATA 0x13
|
||||
#define USB_REQ_SET_WUSB_DATA 0x14
|
||||
#define USB_REQ_LOOPBACK_DATA_WRITE 0x15
|
||||
#define USB_REQ_LOOPBACK_DATA_READ 0x16
|
||||
#define USB_REQ_SET_INTERFACE_DS 0x17
|
||||
|
||||
#define USB_REQ_GET_PARTNER_PDO 20
|
||||
#define USB_REQ_GET_BATTERY_STATUS 21
|
||||
#define USB_REQ_SET_PDO 22
|
||||
#define USB_REQ_GET_VDM 23
|
||||
#define USB_REQ_SEND_VDM 24
|
||||
|
||||
#include "common_usb.h"
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static int vhci_open(void)
|
||||
{
|
||||
return open("/dev/vhci", O_RDWR);
|
||||
}
|
||||
|
||||
static int vhci_setport(int fd, u_int port)
|
||||
{
|
||||
struct vhci_ioc_set_port args;
|
||||
|
||||
args.port = port;
|
||||
return ioctl(fd, VHCI_IOC_SET_PORT, &args);
|
||||
}
|
||||
|
||||
static int vhci_usb_attach(int fd)
|
||||
{
|
||||
return ioctl(fd, VHCI_IOC_USB_ATTACH, NULL);
|
||||
}
|
||||
|
||||
static int vhci_usb_recv(int fd, void* buf, size_t size)
|
||||
{
|
||||
uint8_t* ptr = (uint8_t*)buf;
|
||||
ssize_t done;
|
||||
|
||||
while (1) {
|
||||
done = read(fd, ptr, size);
|
||||
if (done < 0)
|
||||
return -1;
|
||||
if ((size_t)done == size)
|
||||
return 0;
|
||||
size -= done;
|
||||
ptr += done;
|
||||
}
|
||||
}
|
||||
|
||||
static int vhci_usb_send(int fd, void* buf, size_t size)
|
||||
{
|
||||
uint8_t* ptr = (uint8_t*)buf;
|
||||
ssize_t done;
|
||||
|
||||
while (1) {
|
||||
done = write(fd, ptr, size);
|
||||
if (done <= 0)
|
||||
return -1;
|
||||
if ((size_t)done == size)
|
||||
return 0;
|
||||
size -= done;
|
||||
ptr += done;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static volatile long syz_usb_connect_impl(uint64 speed, uint64 dev_len,
|
||||
const char* dev, const struct vusb_connect_descriptors* descs,
|
||||
lookup_connect_out_response_t lookup_connect_response_out)
|
||||
{
|
||||
struct usb_device_index* index;
|
||||
int portnum, fd, rv;
|
||||
bool done;
|
||||
|
||||
portnum = procid + 1;
|
||||
|
||||
debug("syz_usb_connect: dev: %p\n", dev);
|
||||
if (!dev) {
|
||||
debug("syz_usb_connect: dev is null\n");
|
||||
return -1;
|
||||
}
|
||||
if (portnum != 1) {
|
||||
/* For now, we support only one proc. */
|
||||
debug("syz_usb_connect: not proc1 %d\n", (int)procid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug("syz_usb_connect: device data:\n");
|
||||
debug_dump_data(dev, dev_len);
|
||||
|
||||
fd = vhci_open();
|
||||
if (fd < 0) {
|
||||
debug("syz_usb_connect: vhci_open failed with %d\n", fd);
|
||||
return -1;
|
||||
}
|
||||
debug("syz_usb_connect: vhci_open success\n");
|
||||
|
||||
index = add_usb_index(fd, dev, dev_len);
|
||||
if (!index) {
|
||||
debug("syz_usb_connect: add_usb_index failed\n");
|
||||
goto err;
|
||||
}
|
||||
debug("syz_usb_connect: add_usb_index success\n");
|
||||
|
||||
#if USB_DEBUG
|
||||
NONFAILING(analyze_usb_device(index));
|
||||
#endif
|
||||
|
||||
rv = vhci_setport(fd, portnum);
|
||||
if (rv != 0) {
|
||||
debug("syz_usb_connect: vhci_setport failed with %d\n", rv);
|
||||
goto err;
|
||||
}
|
||||
debug("syz_usb_connect: vhci_setport success\n");
|
||||
|
||||
rv = vhci_usb_attach(fd);
|
||||
if (rv != 0) {
|
||||
debug("syz_usb_connect: vhci_usb_attach failed with %d\n", rv);
|
||||
goto err;
|
||||
}
|
||||
debug("syz_usb_connect: vhci_usb_attach success\n");
|
||||
|
||||
done = false;
|
||||
while (!done) {
|
||||
vhci_request_t req;
|
||||
|
||||
rv = vhci_usb_recv(fd, &req, sizeof(req));
|
||||
if (rv != 0) {
|
||||
debug("syz_usb_connect: vhci_usb_recv failed with %d\n", errno);
|
||||
goto err;
|
||||
}
|
||||
if (req.type != VHCI_REQ_CTRL) {
|
||||
debug("syz_usb_connect: received non-control transfer\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
debug("syz_usb_connect: bReqType: 0x%x (%s), bReq: 0x%x, wVal: 0x%x, wIdx: 0x%x, wLen: %d\n",
|
||||
req.u.ctrl.bmRequestType, (req.u.ctrl.bmRequestType & UE_DIR_IN) ? "IN" : "OUT",
|
||||
req.u.ctrl.bRequest, UGETW(req.u.ctrl.wValue), UGETW(req.u.ctrl.wIndex), UGETW(req.u.ctrl.wLength));
|
||||
|
||||
#if USB_DEBUG
|
||||
analyze_control_request(fd, &req.u.ctrl);
|
||||
#endif
|
||||
|
||||
char* response_data = NULL;
|
||||
uint32 response_length = 0;
|
||||
char data[4096];
|
||||
|
||||
if (req.u.ctrl.bmRequestType & UE_DIR_IN) {
|
||||
bool response_found = false;
|
||||
NONFAILING(response_found = lookup_connect_response_in(fd, descs, (const usb_ctrlrequest*)&req.u.ctrl, &response_data, &response_length));
|
||||
if (!response_found) {
|
||||
debug("syz_usb_connect: unknown control IN request\n");
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
if (!lookup_connect_response_out(fd, descs, (const usb_ctrlrequest*)&req.u.ctrl, &done)) {
|
||||
debug("syz_usb_connect: unknown control OUT request\n");
|
||||
goto err;
|
||||
}
|
||||
response_data = NULL;
|
||||
response_length = UGETW(req.u.ctrl.wLength);
|
||||
}
|
||||
|
||||
if ((req.u.ctrl.bmRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD &&
|
||||
req.u.ctrl.bRequest == USB_REQ_SET_CONFIGURATION) {
|
||||
/* TODO: possibly revisit */
|
||||
}
|
||||
|
||||
if (response_length > sizeof(data))
|
||||
response_length = 0;
|
||||
if ((uint32_t)UGETW(req.u.ctrl.wLength) < response_length)
|
||||
response_length = UGETW(req.u.ctrl.wLength);
|
||||
|
||||
if (response_data)
|
||||
memcpy(data, response_data, response_length);
|
||||
else
|
||||
memset(data, 0, response_length);
|
||||
|
||||
if (req.u.ctrl.bmRequestType & UE_DIR_IN) {
|
||||
debug("syz_usb_connect: writing %d bytes\n", response_length);
|
||||
if (response_length > 0) {
|
||||
vhci_response_t res;
|
||||
res.size = response_length;
|
||||
rv = vhci_usb_send(fd, &res, sizeof(res));
|
||||
if (rv == 0)
|
||||
rv = vhci_usb_send(fd, data, response_length);
|
||||
}
|
||||
} else {
|
||||
rv = vhci_usb_recv(fd, data, response_length);
|
||||
debug("syz_usb_connect: read %d bytes\n", response_length);
|
||||
debug_dump_data(&data[0], response_length);
|
||||
}
|
||||
if (rv < 0) {
|
||||
debug("syz_usb_connect: usb_raw_ep0_read/write failed with %d\n", rv);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
sleep_ms(200);
|
||||
debug("syz_usb_connect: configured\n");
|
||||
return fd;
|
||||
|
||||
err:
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if SYZ_EXECUTOR || __NR_syz_usb_connect
|
||||
static volatile long syz_usb_connect(volatile long a0, volatile long a1,
|
||||
volatile long a2, volatile long a3)
|
||||
{
|
||||
uint64 speed = a0;
|
||||
uint64 dev_len = a1;
|
||||
const char* dev = (const char*)a2;
|
||||
const struct vusb_connect_descriptors* descs = (const struct vusb_connect_descriptors*)a3;
|
||||
|
||||
return syz_usb_connect_impl(speed, dev_len, dev, descs,
|
||||
&lookup_connect_response_out_generic);
|
||||
}
|
||||
#endif // SYZ_EXECUTOR || __NR_syz_usb_connect
|
||||
|
||||
#if SYZ_EXECUTOR || __NR_syz_usb_disconnect
|
||||
static volatile long syz_usb_disconnect(volatile long a0)
|
||||
{
|
||||
int fd = a0;
|
||||
|
||||
int rv = close(fd);
|
||||
|
||||
sleep_ms(200);
|
||||
|
||||
return rv;
|
||||
}
|
||||
#endif // SYZ_EXECUTOR || __NR_syz_usb_disconnect
|
@ -156,3 +156,15 @@ static bool cover_check(uint64 pc)
|
||||
#else
|
||||
#include "nocover.h"
|
||||
#endif
|
||||
|
||||
#if GOOS_netbsd
|
||||
#define SYZ_HAVE_FEATURES 1
|
||||
static feature_t features[] = {
|
||||
{"usb", setup_usb},
|
||||
};
|
||||
|
||||
static void setup_machine(void)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
#endif
|
||||
|
@ -32,8 +32,9 @@ func main() {
|
||||
"common_test.h",
|
||||
"common_kvm_amd64.h",
|
||||
"common_kvm_arm64.h",
|
||||
"common_usb.h",
|
||||
"common_usb_linux.h",
|
||||
"common_usb_netbsd.h",
|
||||
"common_usb.h",
|
||||
"android/android_seccomp.h",
|
||||
"kvm.h",
|
||||
"kvm.S.h",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,14 +4,29 @@
|
||||
package host
|
||||
|
||||
import (
|
||||
"github.com/google/syzkaller/pkg/osutil"
|
||||
"github.com/google/syzkaller/prog"
|
||||
)
|
||||
|
||||
func isSupported(c *prog.Syscall, target *prog.Target, sandbox string) (bool, string) {
|
||||
return true, ""
|
||||
switch c.CallName {
|
||||
case "syz_usb_connect", "syz_usb_disconnect":
|
||||
reason := checkUSBEmulation()
|
||||
return reason == "", reason
|
||||
default:
|
||||
return true, ""
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
checkFeature[FeatureCoverage] = unconditionallyEnabled
|
||||
checkFeature[FeatureComparisons] = unconditionallyEnabled
|
||||
checkFeature[FeatureUSBEmulation] = checkUSBEmulation
|
||||
}
|
||||
|
||||
func checkUSBEmulation() string {
|
||||
if err := osutil.IsAccessible("/dev/vhci"); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
11
sys/netbsd/vusb.txt
Normal file
11
sys/netbsd/vusb.txt
Normal file
@ -0,0 +1,11 @@
|
||||
# Copyright 2020 syzkaller project authors. All rights reserved.
|
||||
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
||||
|
||||
# This is a special fd for USB fuzzing and should only be used with syz_usb_* pseudo-syscalls.
|
||||
# We don't inherit it from the fd resource, to discourage syzkaller calling raw ioctls on it.
|
||||
resource fd_usb[int32]: -1
|
||||
|
||||
# These are generic pseudo-syscalls for emulating arbitrary USB devices.
|
||||
# They are mostly targeted to cover the enumeration process.
|
||||
syz_usb_connect(speed intptr, dev_len len[dev], dev buffer[in], conn_descs buffer[in]) fd_usb (timeout[3000], prog_timeout[3000])
|
||||
syz_usb_disconnect(fd fd_usb) (timeout[300])
|
Loading…
x
Reference in New Issue
Block a user