On Mon, 4 Jun 2018, Andrey Konovalov wrote: > Hi Greg and Alan! > > As you might know I've been working on adding external USB fuzzing > support to syzkaller. Yes. It's an ambitious goal. > At this point a have a prototype, which is able to emulate USB devices > from userspace via a custom written userspace interface for the gadget > subsystem and CONFIG_USB_DUMMY_HCD. The patches and some details are > here [1]. > > This is just a prototype and there are a few things we need to support > USB fuzzing properly. > > 1. A way to collect coverage from USB code. > > Syzkaller uses kcov (CONFIG_KCOV) to collect coverage from the kernel. > The issue is that kcov collects coverage in a process context (from > the kernel task that corresponds to the userspace process that created > the kcov device). But AFAIU USB uses a kernel worker to process USB > hub events. That's right. And other parts of the USB stack do this too, not just the hub driver. Some drivers create their own helper threads, some rely on work queues, some rely on threaded interrupt handlers, and so on. Not to mention non-process stuff, like timer or softirq callbacks. > The approach I tried to deal with this is to change hub_event() to put > events into a global queue and wait instead of processing them right > away. Then I added an ioctl to the hub device that takes an event from > the queue and processes it the same way hub_event() used to. This > results in USB events being processed in a process context. The patch > is here [2]. > > Is there a less hacky way to make processing USB events synchronously > (by an ioctl call from userspace for example), if that's feasible at > all? Sounds exactly like what you have already done for the hub driver. It might be okay in that setting, and maybe in a few other drivers, but it isn't a general-purpose solution. In general, I don't think that kind of approach will work for all drivers. There are too many different asynchronous execution mechanisms in use. Not to mention execution pathways that originate completely outside the USB stack (Power Management callbacks). > The perfect solution would be to have something like /dev/tun for USB, > where you can write USB packets and the kernel would synchronously > process them. I'm not sure whether this is possible (highly > asynchronous USB core subsystem architecture + all communication is > initiated by the host). gadgetfs is a little like that already, except of course that the processing is not synchronous. Another aspect of this would be fuzzing USB host controller drivers. In theory you could start doing this now, although you would have to use a real UDC instead of dummy-hcd. However, this may create more complications that you want to deal with at the moment. > Another thing we could do is to teach kcov to collect coverage from > arbitrary kernel threads. In this case we could collect coverage from > the thread that processes the USB events. That seems like a more general solution, something which could be applied to other settings too. One difficulty you would face is telling the tool which threads to work on. This is particularly tricky when dealing with work queues, since a single work-queue thread can run code for many different drivers and purposes. Perhaps it would be better to collect coverage information based on the location of the code being executed rather than the thread ID. > However we would still need > some signal to understand whether the device finished initialization, > etc. (with the first approach we could tell that some stage of device > initialization is finished by seeing that hub_event() returned). Why initialization particularly? A device goes through a number of stages in its life cycle. I get the impression you would like to have a mechanism whereby you can send messages from arbitrary places in the kernel to your testing process. A little like the function tracer or perf, perhaps. > There's another issue with getting coverage after USB device has been > initialized. For example some device drivers create new threads that > communicate with that device. I don't see an easy way to collect > coverage from those threads. Right. This is the problem I mentioned above. > 2. A way to isolate independent test programs. > > Right now CONFIG_USB_DUMMY_HCD creates one global hub to which all > emulated USB devices connect. Would it be possible to create one > virtual hub per test (or at least one per test process) by say calling > some ioctl? What changes would that require? Are you planning to run multiple test processes concurrently? If you aren't then this isn't an issue. In fact, dummy-hcd is capable of creating more than one virtual root hub (see the "num" module parameter), so in theory you could run multiple tests at the same time. I don't think this capability has been tested very much. > Basically we need a way to run a test program (that connects a USB > device and works with it from userspace for example) and then destroy > all the accumulated state before running the next test. You can do that with dummy-hcd simply by removing the USB gadget (closing the gadgetfs files, for example). If you want to be extra thorough, unload the gadget driver and dummy-hcd modules after the end of the test, and then reload them before starting the next test. That should get rid of any important state. Alan Stern -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html