sys/linux, executor: add syz_usb_ep_read syzkall

syz_usb_ep_read reads data from USB endpoints other than #0.
This commit is contained in:
Andrey Konovalov 2019-06-26 18:28:06 +02:00 committed by Andrey Konovalov
parent df9270ba7f
commit 13c3a99962
5 changed files with 90 additions and 25 deletions

View File

@ -30,19 +30,21 @@ static bool parse_usb_descriptor(char* buffer, size_t length, struct usb_device_
size_t offset = 0;
while (true) {
if (offset == length)
if (offset + 1 >= length)
break;
if (offset + 1 < length)
uint8 desc_length = buffer[offset];
uint8 desc_type = buffer[offset + 1];
if (desc_length <= 2)
break;
uint8 length = buffer[offset];
uint8 type = buffer[offset + 1];
if (type == USB_DT_ENDPOINT) {
if (offset + desc_length > length)
break;
if (desc_type == USB_DT_ENDPOINT) {
index->eps[index->eps_num] = (struct usb_endpoint_descriptor*)(buffer + offset);
index->eps_num++;
}
if (index->eps_num == USB_MAX_EP_NUM)
break;
offset += length;
offset += desc_length;
}
return true;
@ -82,6 +84,7 @@ struct usb_fuzzer_ep_io {
#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 4, struct usb_endpoint_descriptor)
#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 6, struct usb_fuzzer_ep_io)
#define USB_FUZZER_IOCTL_EP_READ _IOWR('U', 7, struct usb_fuzzer_ep_io)
#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 8)
#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 9, uint32)
@ -119,6 +122,11 @@ int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
}
int usb_fuzzer_ep_read(int fd, struct usb_fuzzer_ep_io* io)
{
return ioctl(fd, USB_FUZZER_IOCTL_EP_READ, io);
}
int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
{
return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
@ -227,8 +235,10 @@ static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatil
struct vusb_connect_descriptors* descs = (struct vusb_connect_descriptors*)a3;
debug("syz_usb_connect: dev: %p\n", dev);
if (!dev)
if (!dev) {
debug("syz_usb_connect: dev is null\n");
return -1;
}
debug("syz_usb_connect: device data:\n");
debug_dump_data(dev, dev_len);
@ -241,7 +251,7 @@ static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatil
debug("syz_usb_connect: parse_usb_descriptor failed with %d\n", rv);
return rv;
}
debug("syz_usb_connect: parsed usb descriptor\n");
debug("syz_usb_connect: parsed usb descriptor, %d endpoints found\n", index.eps_num);
int fd = usb_fuzzer_open();
if (fd < 0) {
@ -306,8 +316,11 @@ static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatil
unsigned ep;
for (ep = 0; ep < index.eps_num; ep++) {
rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
if (rv < 0)
fail("syz_usb_connect: ep enable failed");
if (rv < 0) {
debug("syz_usb_connect: usb_fuzzer_ep_enable failed with %d\n", rv);
} else {
debug("syz_usb_connect: endpoint %d enabled\n", ep);
}
}
}
@ -491,16 +504,55 @@ static volatile long syz_usb_ep_write(volatile long a0, volatile long a1, volati
uint32 len = a2;
char* data = (char*)a3;
struct usb_fuzzer_ep_io_data response;
response.inner.ep = ep;
response.inner.flags = 0;
if (len > sizeof(response.data))
len = 0;
response.inner.length = len;
if (data)
memcpy(&response.data[0], data, len);
struct usb_fuzzer_ep_io_data io_data;
io_data.inner.ep = ep;
io_data.inner.flags = 0;
if (len > sizeof(io_data.data))
len = sizeof(io_data.data);
io_data.inner.length = len;
NONFAILING(memcpy(&io_data.data[0], data, len));
return usb_fuzzer_ep_write(fd, (struct usb_fuzzer_ep_io*)&response);
int rv = usb_fuzzer_ep_write(fd, (struct usb_fuzzer_ep_io*)&io_data);
if (rv < 0) {
debug("syz_usb_ep_write: usb_fuzzer_ep_write failed with %d\n", rv);
return rv;
}
sleep_ms(200);
return 0;
}
#endif
#if SYZ_EXECUTOR || __NR_syz_usb_ep_read
static volatile long syz_usb_ep_read(volatile long a0, volatile long a1, volatile long a2, volatile long a3)
{
int fd = a0;
uint16 ep = a1;
uint32 len = a2;
char* data = (char*)a3;
struct usb_fuzzer_ep_io_data io_data;
io_data.inner.ep = ep;
io_data.inner.flags = 0;
if (len > sizeof(io_data.data))
len = sizeof(io_data.data);
io_data.inner.length = len;
int rv = usb_fuzzer_ep_read(fd, (struct usb_fuzzer_ep_io*)&io_data);
if (rv < 0) {
debug("syz_usb_ep_read: usb_fuzzer_ep_read failed with %d\n", rv);
return rv;
}
NONFAILING(memcpy(&data[0], &io_data.data[0], io_data.inner.length));
debug("syz_usb_ep_read: received data:\n");
debug_dump_data(&io_data.data[0], io_data.inner.length);
sleep_ms(200);
return 0;
}
#endif

View File

@ -608,11 +608,19 @@ retry:
}
if (strncmp(syscalls[call_num].name, "syz_usb_control_io", strlen("syz_usb_control_io")) == 0) {
// Must match timeout in pkg/csource/csource.go.
call_extra_timeout = 200;
call_extra_timeout = 300;
}
if (strncmp(syscalls[call_num].name, "syz_usb_ep_write", strlen("syz_usb_ep_write")) == 0) {
// Must match timeout in pkg/csource/csource.go.
call_extra_timeout = 300;
}
if (strncmp(syscalls[call_num].name, "syz_usb_ep_read", strlen("syz_usb_ep_read")) == 0) {
// Must match timeout in pkg/csource/csource.go.
call_extra_timeout = 300;
}
if (strncmp(syscalls[call_num].name, "syz_usb_disconnect", strlen("syz_usb_disconnect")) == 0) {
// Must match timeout in pkg/csource/csource.go.
call_extra_timeout = 200;
call_extra_timeout = 300;
}
if (call_num == instr_copyin) {
char* addr = (char*)read_input(&input_pos);

View File

@ -76,8 +76,10 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) {
// Must match timeouts in executor/executor.cc.
specialCallTimeouts := map[string]int{
"syz_usb_connect": 2000,
"syz_usb_control_io": 200,
"syz_usb_disconnect": 200,
"syz_usb_control_io": 300,
"syz_usb_ep_write": 300,
"syz_usb_ep_read": 300,
"syz_usb_disconnect": 300,
}
timeoutExpr := "45"
for i, call := range p.Calls {

View File

@ -214,7 +214,7 @@ func isSupportedSyzkall(sandbox string, c *prog.Syscall) (bool, string) {
case "syz_emit_ethernet", "syz_extract_tcp_res":
reason := checkNetworkInjection()
return reason == "", reason
case "syz_usb_connect", "syz_usb_disconnect", "syz_usb_control_io", "syz_usb_ep_write":
case "syz_usb_connect", "syz_usb_disconnect", "syz_usb_control_io", "syz_usb_ep_write", "syz_usb_ep_read":
reason := checkUSBInjection()
return reason == "", reason
case "syz_kvm_setup_cpu":

View File

@ -20,6 +20,7 @@ resource fd_usb_hid[fd_usb]
syz_usb_connect(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb
syz_usb_control_io(fd fd_usb, descs ptr[in, vusb_descriptors], resps ptr[in, vusb_responses])
syz_usb_ep_write(fd fd_usb, ep int16[0:31], len len[data], data buffer[in])
syz_usb_ep_read(fd fd_usb, ep int16[0:31], len len[data], data buffer[out])
syz_usb_disconnect(fd fd_usb)
# These are syzcalls specifically targeted to the HID device class.
@ -87,14 +88,16 @@ type usb_interface_descriptor_t[CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] {
endpoints EPS
} [packed]
# TODO: Some endpoints have USB_DT_ENDPOINT_SIZE.
type usb_endpoint_descriptor_t[ADDR, ATTRS, EXTRA] {
bLength const[USB_DT_ENDPOINT_SIZE, int8]
bLength const[USB_DT_ENDPOINT_AUDIO_SIZE, int8]
bDescriptorType const[USB_DT_ENDPOINT, int8]
bEndpointAddress ADDR
bmAttributes ATTRS
wMaxPacketSize int16
bInterval int8
bRefresh int8
bSynchAddress int8