[PATCH RFC 2/2] HID: usbhid: kcov: add annotations for coverage collection

From: Andrey Konovalov
Date: Thu Dec 12 2019 - 12:15:59 EST


This patch adds kcov_remote_start/stop() callbacks into usbhid code that
is executed in interrupt context. As the result, kcov can be used to
collect coverage from those parts of the code, which is used to facilitate
coverage-guided fuzzing with syzkaller.

Signed-off-by: Andrey Konovalov <andreyknvl@xxxxxxxxxx>
---
drivers/hid/usbhid/hid-core.c | 25 ++++++++++++++++++++-----
drivers/hid/usbhid/usbkbd.c | 15 ++++++++++++---
drivers/hid/usbhid/usbmouse.c | 7 ++++++-
3 files changed, 38 insertions(+), 9 deletions(-)

diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index c7bc9db5b192..3e825f27d882 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -274,6 +274,8 @@ static void hid_irq_in(struct urb *urb)
struct usbhid_device *usbhid = hid->driver_data;
int status;

+ kcov_remote_start_usb((u64)urb->dev->bus->busnum);
+
switch (urb->status) {
case 0: /* success */
usbhid->retry_delay = 0;
@@ -300,12 +302,12 @@ static void hid_irq_in(struct urb *urb)
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
set_bit(HID_CLEAR_HALT, &usbhid->iofl);
schedule_work(&usbhid->reset_work);
- return;
+ goto out;
case -ECONNRESET: /* unlink */
case -ENOENT:
case -ESHUTDOWN: /* unplug */
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
- return;
+ goto out;
case -EILSEQ: /* protocol error or unplug */
case -EPROTO: /* protocol error or unplug */
case -ETIME: /* protocol error or unplug */
@@ -313,7 +315,7 @@ static void hid_irq_in(struct urb *urb)
usbhid_mark_busy(usbhid);
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
hid_io_error(hid);
- return;
+ goto out;
default: /* error */
hid_warn(urb->dev, "input irq status %d received\n",
urb->status);
@@ -330,6 +332,9 @@ static void hid_irq_in(struct urb *urb)
hid_io_error(hid);
}
}
+
+out:
+ kcov_remote_stop();
}

static int hid_submit_out(struct hid_device *hid)
@@ -433,6 +438,8 @@ static void hid_irq_out(struct urb *urb)
unsigned long flags;
int unplug = 0;

+ kcov_remote_start_usb((u64)urb->dev->bus->busnum);
+
switch (urb->status) {
case 0: /* success */
break;
@@ -459,7 +466,7 @@ static void hid_irq_out(struct urb *urb)
hid_submit_out(hid) == 0) {
/* Successfully submitted next urb in queue */
spin_unlock_irqrestore(&usbhid->lock, flags);
- return;
+ goto out;
}
}

@@ -467,6 +474,9 @@ static void hid_irq_out(struct urb *urb)
spin_unlock_irqrestore(&usbhid->lock, flags);
usb_autopm_put_interface_async(usbhid->intf);
wake_up(&usbhid->wait);
+
+out:
+ kcov_remote_stop();
}

/*
@@ -480,6 +490,8 @@ static void hid_ctrl(struct urb *urb)
unsigned long flags;
int unplug = 0, status = urb->status;

+ kcov_remote_start_usb((u64)urb->dev->bus->busnum);
+
switch (status) {
case 0: /* success */
if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
@@ -510,7 +522,7 @@ static void hid_ctrl(struct urb *urb)
hid_submit_ctrl(hid) == 0) {
/* Successfully submitted next urb in queue */
spin_unlock_irqrestore(&usbhid->lock, flags);
- return;
+ goto out;
}
}

@@ -518,6 +530,9 @@ static void hid_ctrl(struct urb *urb)
spin_unlock_irqrestore(&usbhid->lock, flags);
usb_autopm_put_interface_async(usbhid->intf);
wake_up(&usbhid->wait);
+
+out:
+ kcov_remote_stop();
}

static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *report,
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
index d5b7a696a68c..eae46e51ca6a 100644
--- a/drivers/hid/usbhid/usbkbd.c
+++ b/drivers/hid/usbhid/usbkbd.c
@@ -102,13 +102,15 @@ static void usb_kbd_irq(struct urb *urb)
struct usb_kbd *kbd = urb->context;
int i;

+ kcov_remote_start_usb((u64)urb->dev->bus->busnum);
+
switch (urb->status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
case -ENOENT:
case -ESHUTDOWN:
- return;
+ goto out;
/* -EPIPE: should clear the halt */
default: /* error */
goto resubmit;
@@ -148,6 +150,9 @@ static void usb_kbd_irq(struct urb *urb)
hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d",
kbd->usbdev->bus->bus_name,
kbd->usbdev->devpath, i);
+
+out:
+ kcov_remote_stop();
}

static int usb_kbd_event(struct input_dev *dev, unsigned int type,
@@ -192,6 +197,8 @@ static void usb_kbd_led(struct urb *urb)
unsigned long flags;
struct usb_kbd *kbd = urb->context;

+ kcov_remote_start_usb((u64)urb->dev->bus->busnum);
+
if (urb->status)
hid_warn(urb->dev, "led urb status %d received\n",
urb->status);
@@ -201,7 +208,7 @@ static void usb_kbd_led(struct urb *urb)
if (*(kbd->leds) == kbd->newleds){
kbd->led_urb_submitted = false;
spin_unlock_irqrestore(&kbd->leds_lock, flags);
- return;
+ goto out;
}

*(kbd->leds) = kbd->newleds;
@@ -212,7 +219,9 @@ static void usb_kbd_led(struct urb *urb)
kbd->led_urb_submitted = false;
}
spin_unlock_irqrestore(&kbd->leds_lock, flags);
-
+
+out:
+ kcov_remote_stop();
}

static int usb_kbd_open(struct input_dev *dev)
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
index 073127e65ac1..f470ffa8fa87 100644
--- a/drivers/hid/usbhid/usbmouse.c
+++ b/drivers/hid/usbhid/usbmouse.c
@@ -53,13 +53,15 @@ static void usb_mouse_irq(struct urb *urb)
struct input_dev *dev = mouse->dev;
int status;

+ kcov_remote_start_usb((u64)urb->dev->bus->busnum);
+
switch (urb->status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
case -ENOENT:
case -ESHUTDOWN:
- return;
+ goto out;
/* -EPIPE: should clear the halt */
default: /* error */
goto resubmit;
@@ -83,6 +85,9 @@ static void usb_mouse_irq(struct urb *urb)
"can't resubmit intr, %s-%s/input0, status %d\n",
mouse->usbdev->bus->bus_name,
mouse->usbdev->devpath, status);
+
+out:
+ kcov_remote_stop();
}

static int usb_mouse_open(struct input_dev *dev)
--
2.24.1.735.g03f4e72817-goog