Message ID | d7035335fdfe7493067fbf7d677db57807a42d5d.1606175031.git.andreyknvl@google.com |
---|---|
State | New |
Headers | show |
Series | [v5] kcov, usb: only collect coverage from __usb_hcd_giveback_urb in softirq | expand |
On Tue, Nov 24, 2020 at 12:47:25AM +0100, Andrey Konovalov wrote: > Currently there's a kcov remote coverage collection section in > __usb_hcd_giveback_urb(). Initially that section was added based on the > assumption that usb_hcd_giveback_urb() can only be called in interrupt > context as indicated by a comment before it. This is what happens when > syzkaller is fuzzing the USB stack via the dummy_hcd driver. > > As it turns out, it's actually valid to call usb_hcd_giveback_urb() in task > context, provided that the caller turned off the interrupts; USB/IP does > exactly that. This can lead to a nested KCOV remote coverage collection > sections both trying to collect coverage in task context. This isn't > supported by kcov, and leads to a WARNING. > > Change __usb_hcd_giveback_urb() to only call kcov_remote_*() callbacks > when it's being executed in a softirq. To avoid calling > in_serving_softirq() directly in the driver code, add a couple of new kcov > wrappers. > > As the result of this change, the coverage from USB/IP related > usb_hcd_giveback_urb() calls won't be collected, but the WARNING is fixed. > > A potential future improvement would be to support nested remote coverage > collection sections, but this patch doesn't address that. > > Signed-off-by: Andrey Konovalov <andreyknvl@google.com> > Acked-by: Marco Elver <elver@google.com> > --- > > Changes in v5: > - Don't call in_serving_softirq() in USB driver code directly, do that > via kcov wrappers. Does not apply to 5.11-rc1 :(
On Mon, Dec 28, 2020 at 3:51 PM Greg Kroah-Hartman <gregkh@linuxfoundation.org> wrote: > > On Tue, Nov 24, 2020 at 12:47:25AM +0100, Andrey Konovalov wrote: > > Currently there's a kcov remote coverage collection section in > > __usb_hcd_giveback_urb(). Initially that section was added based on the > > assumption that usb_hcd_giveback_urb() can only be called in interrupt > > context as indicated by a comment before it. This is what happens when > > syzkaller is fuzzing the USB stack via the dummy_hcd driver. > > > > As it turns out, it's actually valid to call usb_hcd_giveback_urb() in task > > context, provided that the caller turned off the interrupts; USB/IP does > > exactly that. This can lead to a nested KCOV remote coverage collection > > sections both trying to collect coverage in task context. This isn't > > supported by kcov, and leads to a WARNING. > > > > Change __usb_hcd_giveback_urb() to only call kcov_remote_*() callbacks > > when it's being executed in a softirq. To avoid calling > > in_serving_softirq() directly in the driver code, add a couple of new kcov > > wrappers. > > > > As the result of this change, the coverage from USB/IP related > > usb_hcd_giveback_urb() calls won't be collected, but the WARNING is fixed. > > > > A potential future improvement would be to support nested remote coverage > > collection sections, but this patch doesn't address that. > > > > Signed-off-by: Andrey Konovalov <andreyknvl@google.com> > > Acked-by: Marco Elver <elver@google.com> > > --- > > > > Changes in v5: > > - Don't call in_serving_softirq() in USB driver code directly, do that > > via kcov wrappers. > > Does not apply to 5.11-rc1 :( Hm, I see version 4 in 5.11-rc1. Let me send a fix up.
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 2c6b9578a7d3..7bafd01e05fb 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1646,9 +1646,14 @@ static void __usb_hcd_giveback_urb(struct urb *urb) /* pass ownership to the completion handler */ urb->status = status; - kcov_remote_start_usb((u64)urb->dev->bus->busnum); + /* + * This function can be called in task context inside another remote + * coverage collection section, but kcov doesn't support that kind of + * recursion yet. Only collect coverage in softirq context for now. + */ + kcov_remote_start_usb_softirq((u64)urb->dev->bus->busnum); urb->complete(urb); - kcov_remote_stop(); + kcov_remote_stop_softirq(); usb_anchor_resume_wakeups(anchor); atomic_dec(&urb->use_count); diff --git a/include/linux/kcov.h b/include/linux/kcov.h index a10e84707d82..4e3037dc1204 100644 --- a/include/linux/kcov.h +++ b/include/linux/kcov.h @@ -52,6 +52,25 @@ static inline void kcov_remote_start_usb(u64 id) kcov_remote_start(kcov_remote_handle(KCOV_SUBSYSTEM_USB, id)); } +/* + * The softirq flavor of kcov_remote_*() functions is introduced as a temporary + * work around for kcov's lack of nested remote coverage sections support in + * task context. Adding suport for nested sections is tracked in: + * https://bugzilla.kernel.org/show_bug.cgi?id=210337 + */ + +static inline void kcov_remote_start_usb_softirq(u64 id) +{ + if (in_serving_softirq()) + kcov_remote_start_usb(id); +} + +static inline void kcov_remote_stop_softirq(void) +{ + if (in_serving_softirq()) + kcov_remote_stop(); +} + #else static inline void kcov_task_init(struct task_struct *t) {} @@ -66,6 +85,8 @@ static inline u64 kcov_common_handle(void) } static inline void kcov_remote_start_common(u64 id) {} static inline void kcov_remote_start_usb(u64 id) {} +static inline void kcov_remote_start_usb_softirq(u64 id) {} +static inline void kcov_remote_stop_softirq(void) {} #endif /* CONFIG_KCOV */ #endif /* _LINUX_KCOV_H */