Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions executor/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ NORETURN void doexit_thread(int status)
#endif
#endif

#if SYZ_EXECUTOR || SYZ_MULTI_PROC || SYZ_REPEAT && SYZ_CGROUPS || \
SYZ_NET_DEVICES || __NR_syz_mount_image || __NR_syz_read_part_table || \
__NR_syz_usb_connect || __NR_syz_usb_connect_ath9k || __NR_syz_usbip_server_init || \
#if SYZ_EXECUTOR || SYZ_MULTI_PROC || SYZ_REPEAT && SYZ_CGROUPS || \
SYZ_NET_DEVICES || __NR_syz_mount_image || __NR_syz_read_part_table || \
__NR_syz_usb_connect || __NR_syz_usbip_server_init || \
(GOOS_freebsd || GOOS_darwin || GOOS_openbsd || GOOS_netbsd) && SYZ_NET_INJECTION
static unsigned long long procid;
#endif
Expand Down Expand Up @@ -178,7 +178,7 @@ static void kill_and_wait(int pid, int* status)

#if !GOOS_windows
#if SYZ_EXECUTOR || SYZ_THREADED || SYZ_REPEAT && SYZ_EXECUTOR_USES_FORK_SERVER || \
__NR_syz_usb_connect || __NR_syz_usb_connect_ath9k || __NR_syz_sleep_ms || \
__NR_syz_usb_connect || __NR_syz_usb_finish_probe || __NR_syz_sleep_ms || \
__NR_syz_usb_control_io || __NR_syz_usb_ep_read || __NR_syz_usb_ep_write || \
__NR_syz_usb_disconnect
static void sleep_ms(uint64 ms)
Expand Down
6 changes: 3 additions & 3 deletions executor/common_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ static int event_timedwait(event_t* ev, uint64 timeout)
#if SYZ_EXECUTOR || SYZ_REPEAT || SYZ_NET_INJECTION || SYZ_FAULT || SYZ_SANDBOX_NONE || \
SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID || \
SYZ_FAULT || SYZ_LEAK || SYZ_BINFMT_MISC || SYZ_SYSCTL || \
((__NR_syz_usb_connect || __NR_syz_usb_connect_ath9k) && USB_DEBUG) || \
(__NR_syz_usb_connect && USB_DEBUG) || \
__NR_syz_usbip_server_init
#include <errno.h>
#include <fcntl.h>
Expand Down Expand Up @@ -2376,11 +2376,11 @@ static long syz_extract_tcp_res(volatile long a0, volatile long a1, volatile lon
}
#endif

#if SYZ_EXECUTOR || SYZ_CLOSE_FDS || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k
#if SYZ_EXECUTOR || SYZ_CLOSE_FDS || __NR_syz_usb_connect
#define MAX_FDS 30
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k || \
#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_finish_probe || \
__NR_syz_usb_ep_write || __NR_syz_usb_ep_read || __NR_syz_usb_control_io || \
__NR_syz_usb_disconnect
#include <errno.h>
Expand Down
186 changes: 107 additions & 79 deletions executor/common_usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ struct usb_info {
struct usb_device_index index;
};

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k || \
#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_finish_probe || \
__NR_syz_usb_control_io || __NR_syz_usb_ep_read || __NR_syz_usb_ep_write
static struct usb_info usb_devices[USB_MAX_FDS];

Expand All @@ -61,7 +61,7 @@ static struct usb_device_index* lookup_usb_index(int fd)
}
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k
#if SYZ_EXECUTOR || __NR_syz_usb_connect
static int usb_devices_num;

static bool parse_usb_descriptor(const char* buffer, size_t length, struct usb_device_index* index)
Expand Down Expand Up @@ -128,7 +128,7 @@ static struct usb_device_index* add_usb_index(int fd, const char* dev, size_t de
return &usb_devices[i].index;
}

#endif // #if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k
#endif // #if SYZ_EXECUTOR || __NR_syz_usb_connect

#if USB_DEBUG

Expand Down Expand Up @@ -567,7 +567,39 @@ struct vusb_connect_descriptors {
struct vusb_connect_string_descriptor strs[0];
} __attribute__((packed));

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k
#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_control_io || __NR_syz_usb_finish_probe

struct vusb_descriptor {
uint8 req_type;
uint8 desc_type;
uint32 len;
char data[0];
} __attribute__((packed));

struct vusb_descriptors {
uint32 len;
struct vusb_descriptor* generic;
struct vusb_descriptor* descs[0];
} __attribute__((packed));

struct vusb_response {
uint8 type;
uint8 req;
uint32 len;
// Number of times this request *should* be processed. 0 by default.
uint32 expected;
char data[0];
} __attribute__((packed));

struct vusb_responses {
uint32 len;
struct vusb_response* generic;
struct vusb_response* resps[0];
} __attribute__((packed));

#endif // SYZ_EXECUTOR || __NR_syz_usb_control_io || __NR_syz_usb_finish_probe

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_finish_probe

static const char default_string[] = {
8, USB_DT_STRING,
Expand All @@ -580,24 +612,32 @@ static const char default_lang_id[] = {
};

// lookup_connect_response_in() is a helper function that returns a response to a USB IN request
// based on syzkaller-generated arguments provided to syz_usb_connect* pseudo-syscalls. The data
// and its length to be used as a response are returned in *response_data and *response_length.
// The return value of this function lookup_connect_response_inindicates whether the request is known to syzkaller.
// based on syzkaller-generated arguments provided to syz_usb_connect* and syz_usb_finish_probe*
// pseudo-syscalls. The data and its length to be used as a response are returned in *response_data
// and *response_length. The return value of this function lookup_connect_response_in indicates
// whether the request is known to syzkaller.

// Use *done counter (for instance, in syz_usb_finish_probe variants) to keep track of requests
// which remain to be processed.

static bool lookup_connect_response_in(int fd, const struct vusb_connect_descriptors* descs,
const struct vusb_responses* resps,
const struct usb_ctrlrequest* ctrl,
struct usb_qualifier_descriptor* qual,
char** response_data, uint32* response_length)
char** response_data, uint32* response_length, int* done)
{
struct usb_device_index* index = lookup_usb_index(fd);
uint8 str_idx;
int resps_num = 0;
uint8 req = ctrl->bRequest;
uint8 req_type = ctrl->bRequestType;

if (!index)
return false;

switch (ctrl->bRequestType & USB_TYPE_MASK) {
switch (req_type & USB_TYPE_MASK) {
case USB_TYPE_STANDARD:
switch (ctrl->bRequest) {
switch (req) {
case USB_REQ_GET_DESCRIPTOR:
switch (ctrl->wValue >> 8) {
case USB_DT_DEVICE:
Expand Down Expand Up @@ -655,107 +695,95 @@ static bool lookup_connect_response_in(int fd, const struct vusb_connect_descrip
}
break;
default:
break;
}
if (!resps || !done)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this part of code belongs to a new function, named e.g. lookup_probe_response_in. The code above does not use resps or done in any way.

And then in syz_usb_connect you just call lookup_connect_response_in like before, and in syz_usb_finish_probe you call both sequentially (but do you actually need the lookup_connect_response_in part in syz_usb_finish_probe? why?).

break;

debug("lookup_connect_response_in: unknown request");
return false;
}
resps_num = (resps->len - offsetof(struct vusb_responses, resps)) / sizeof(resps->resps[0]);

#endif // #if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k
int i;
for (i = 0; i < resps_num; i++) {
struct vusb_response* resp = resps->resps[i];
if (!resp)
continue;

// lookup_connect_response_out() functions process a USB OUT request and return in *done
// whether this is the last request that must be handled by syz_usb_connect* pseudo-syscalls.
if (resp->type == req_type && resp->req == req) {
*response_length = resp->len;

typedef bool (*lookup_connect_out_response_t)(int fd, const struct vusb_connect_descriptors* descs,
const struct usb_ctrlrequest* ctrl, bool* done);
if (*response_length != 0)
*response_data = &resp->data[0];
else
*response_data = NULL;

#if SYZ_EXECUTOR || __NR_syz_usb_connect
static bool lookup_connect_response_out_generic(int fd, const struct vusb_connect_descriptors* descs,
const struct usb_ctrlrequest* ctrl, bool* done)
{
switch (ctrl->bRequestType & USB_TYPE_MASK) {
case USB_TYPE_STANDARD:
switch (ctrl->bRequest) {
case USB_REQ_SET_CONFIGURATION:
*done = true;
if (resp->expected != 0)
*done -= 1;

return true;
}
}

if (resps->generic) {
*response_data = &resps->generic->data[0];
*response_length = resps->generic->len;
return true;
default:
break;
}
break;
}

debug("lookup_connect_response_out: unknown request");
debug("lookup_connect_response_in: unknown request");
return false;
}
#endif // SYZ_EXECUTOR || __NR_syz_usb_connect

#if GOOS_linux && (SYZ_EXECUTOR || __NR_syz_usb_connect_ath9k)

// drivers/net/wireless/ath/ath9k/hif_usb.h
#define ATH9K_FIRMWARE_DOWNLOAD 0x30
#define ATH9K_FIRMWARE_DOWNLOAD_COMP 0x31
// lookup_connect_response_out() functions process a USB OUT request and return in *done
// whether the number of requests left to be handled by syz_usb_connect* or syz_usb_finish_probe*
// pseudo-syscalls.

static bool lookup_connect_response_out_ath9k(int fd, const struct vusb_connect_descriptors* descs,
const struct usb_ctrlrequest* ctrl, bool* done)
static bool lookup_connect_response_out(int fd, const struct vusb_connect_descriptors* descs,
const struct vusb_responses* resps, const struct usb_ctrlrequest* ctrl, int* done)
{
switch (ctrl->bRequestType & USB_TYPE_MASK) {
uint8 req = ctrl->bRequest;
uint8 req_type = ctrl->bRequestType;
int resps_num = 0;

switch (req_type & USB_TYPE_MASK) {
case USB_TYPE_STANDARD:
switch (ctrl->bRequest) {
switch (req) {
case USB_REQ_SET_CONFIGURATION:
*done -= 1;
return true;
default:
break;
}
break;
case USB_TYPE_VENDOR:
switch (ctrl->bRequest) {
case ATH9K_FIRMWARE_DOWNLOAD:
return true;
case ATH9K_FIRMWARE_DOWNLOAD_COMP:
*done = true;
return true;
default:

default:
if (!resps)
break;

resps_num = (resps->len - offsetof(struct vusb_responses, resps)) / sizeof(resps->resps[0]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, put this part into lookup_probe_response_out.


int i;
for (i = 0; i < resps_num; i++) {
struct vusb_response* resp = resps->resps[i];
if (!resp)
continue;

if (resp->type == req_type && resp->req == req) {
if (resp->expected != 0)
*done -= 1;

return true;
}
}
break;
}

debug("lookup_connect_response_out_ath9k: unknown request");
debug("lookup_connect_response_out: unknown request");
return false;
}

#endif // SYZ_EXECUTOR || __NR_syz_usb_connect_ath9k
#endif // #if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_finish_probe

#if GOOS_linux && (SYZ_EXECUTOR || __NR_syz_usb_control_io)

struct vusb_descriptor {
uint8 req_type;
uint8 desc_type;
uint32 len;
char data[0];
} __attribute__((packed));

struct vusb_descriptors {
uint32 len;
struct vusb_descriptor* generic;
struct vusb_descriptor* descs[0];
} __attribute__((packed));

struct vusb_response {
uint8 type;
uint8 req;
uint32 len;
char data[0];
} __attribute__((packed));

struct vusb_responses {
uint32 len;
struct vusb_response* generic;
struct vusb_response* resps[0];
} __attribute__((packed));

// lookup_control_response() is a helper function that returns a response to a USB IN request based
// on syzkaller-generated arguments provided to syz_usb_control_io* pseudo-syscalls. The data and its
// length to be used as a response are returned in *response_data and *response_length. The return
Expand Down
Loading