Re: USB fuzzing with syzbot

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Apr 19, 2019 at 10:35 AM Greg Kroah-Hartman
<gregkh@xxxxxxxxxxxxxxxxxxx> wrote:
>
> On Wed, Apr 17, 2019 at 06:33:39PM +0200, Andrey Konovalov wrote:
> > Hi,
> >
> > As you might have noticed, syzbot has started reporting bugs in the
> > USB subsystem that can be triggered externally by a malicious USB
> > device. Right now the fuzzing is done via a GadgetFS-like interface to
> > emulate USB devices through the USB Gadget subsystem and the Dummy
> > HCD/UDC module to "loopback" connect those devices to the running
> > kernel. There are more details in my OffensiveCon talk [1], [2].
> >
> > A few questions/comments:
> >
> > 1. Which tree should we use for testing?
> >
> > Right now we're targeting the upstream tree, but we can switch to some
> > USB development tree, where the fixes are likely to end up earlier.
>
> USB fixes land in the usb.git tree on git.kernel.org in the usb-testing
> branch (for the next release), and in the usb-linus branch (for this
> release).

OK, I've switched to the usb-linus branch of the usb.git tree, since I
see that all Alan's fixes went in that one.

>
> So you can just merge those two branches together if you like to be sure
> you have all of the latest fixes.
>
> > 2. Is there an easy way to figure out which config options enable
> > drivers reachable over USB?
>
> Looking for all options that depend on USB is a good start.
>
> > Right now our kernel config is based on one of the Debian kernel
> > configs, that supposedly enables enough relevant USB drivers. At the
> > same time it enables a lot of other unnecessary stuff, which makes the
> > kernel big and long to compile. Ideally, we would to have a way to
> > auto-generate a kernel config that enables all the relevant (enabled
> > by at least one of the distros) USB drivers. I've looked at whether
> > it's possible to figure out which particular options in some kernel
> > config are related to USB, but it seems that neither the option names,
> > nor the way they are grouped in the config file, are representative
> > enough.
>
> Yeah, it's hard to just carve out this type of configuration, but here's
> what I have done in the past to try to be sure I enabled all USB drivers
> in my kernel configuration.
>
> First, start with a "minimally working configuration" by running:
>         make localmodconfig
> on a working system, with the needed modules for booting and operating
> properly already loaded.
>
> That gives you a .config file that should take only minutes to build,
> compared to much longer for the normal distro configuration (also be
> sure to disable some debugging options so you don't spend extra time
> building and stripping symbols).
>
> Boot and make sure that configuration works.
>
> Then, take that .config and do:
>         - disable USB from the configuration by deleting the:
>                 CONFIG_USB_SUPPORT=y
>           option from your .config
>         - run 'make oldconfig' to disable all USB drivers
>         - turn USB back on by setting CONFIG_USB_SUPPORT=y back on in
>           your .config
>         - run 'make oldconfig' and answer 'y' or 'm' to all of the
>           driver options you are presented with.
>
> That usually catches almost all of them.  Sometimes you need to make
> sure you have some other subsystem enabled (like SCSI), but odds are, if
> you start with a "normally stripped down" configuration that works, you
> should be fine.

I suspect that make localmodconfig (+ switching CONFIG_USB_SUPPORT off
and on) would likely include a lot of stuff that we don't need (there
are many options that are =y, but not related to USB at all), but it
definitely sounds better than what I have right now (converting almost
all =m into =y). I'll give it a shot, thanks!

>
> > 3. Regarding that GadgetFS-like interface.
> >
> > Initially I was using GadgetFS (together with the Dummy HCD/UDC
> > module) to perform emulation of USB devices for fuzzing, but later
> > switched to a custom written interface. This interface is essentially
> > implemented in the following patch [3]. An example that emulates a USB
> > keyboard through this interface can be found here [4]. And the
> > syzkaller parts responsible for USB fuzzing are here [5], [6]. The
> > incentive to implement a different interface was to provide a somewhat
> > raw and direct access to the USB Gadget layer for the userspace, where
> > every USB request is passed to the userspace to get a response.
> >
> > The main differences between this interface (referred to as usb-fuzzer
> > for now) and GadgetFS are:
> >
> > 1) GadgetFS does some sanity checks on the provided USB descriptors,
> > which is something we don't want for fuzzing. We want the descriptors
> > to be as corrupted as they can.
> >
> > 2) GadgetFS handles some of the USB requests internally based on the
> > provided device descriptor, which is also something we don't want. For
> > example we may want to be able to provide differently corrupted
> > responses to the same request.
> >
> > 3) usb-fuzzer has ioctl-based interface instead of a filesystem-based
> > one. I wouldn't say it's that big of a deal, but it makes it somewhat
> > easier to incorporate into a fuzzer.
> >
> > 4) Somewhat related to the previous point: usb-fuzzer uses predictable
> > endpoint names across different UDCs.
> >
> > Right now each UDC driver defines endpoint names via EP_INFO() as it
> > pleases. And GadgetFS uses those names to create file entries for each
> > of the endpoints. As a result, endpoint names for different UDCs will
> > be different and it requires more work to write a portable userspace
> > gadget. The usb-fuzzer interface auto selects and assigns an endpoint
> > based on the required features like the transfer type.
> >
> > 5) GadgetFS binds to the first available UDC, usb-fuzzer provides a
> > way to select a UDC to bind to.
> >
> > Since the fuzzing happens in multiple processes each of which has its
> > own Dummy UDC assigned, we want to have control over which UDC we bind
> > to. This part is a bit confusing, but what I found out is that a UDC
> > is selected based on two different identifying names. I call the first
> > one "udc_device_name" and the second one "udc_driver_name".
> > "udc_device_name" has to be assigned to usb_gadget_driver->udc_name
> > when usb_gadget_probe_driver() is called, and "udc_driver_name" is
> > what we have to compare usb_gadget->name with inside of the
> > usb_gadget_driver->bind() callback. For example, Dummy UDC has
> > "dummy_udc" as its "udc_driver_name" and "dummy_udc.N" as its
> > "udc_device_name". At the same time the dwc2 driver that is used on
> > Raspberry Pi Zero, has "20980000.usb" as both "udc_driver_name" and
> > "udc_device_name".
> >
> > Overall, the usb-fuzzer interface implementation has a similar
> > structure to that of GadgetFS, but looks way simpler (although that
> > might be because I've missed to implement some functionality :).
> >
> > We'd like to get this upstreamed, but I'm not sure whether this should
> > be a separate interface (which we can rebrand as a raw usb gadget
> > interface or something like that) or we should try to make it a
> > special mode of GadgetFS. I like the former approach more, as GadgetFS
> > looks quite complicated from my point of view and making fundamental
> > changes to it doesn't seem like an easy task. This is where we'd like
> > to get your input.
>
> I'll leave the gadgetfs questions to others that know that api better
> than I do :)
>
> thanks,
>
> greg k-h



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux