Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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