Linux-USB Archive on lore.kernel.org
 help / color / Atom feed
From: Andrey Konovalov <andreyknvl@google.com>
To: Alan Stern <stern@rowland.harvard.edu>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: "Gustavo A. R. Silva" <gustavo@embeddedor.com>,
	USB list <linux-usb@vger.kernel.org>,
	Dmitry Vyukov <dvyukov@google.com>,
	Kostya Serebryany <kcc@google.com>,
	Alexander Potapenko <glider@google.com>
Subject: USB fuzzing with syzbot
Date: Wed, 17 Apr 2019 18:33:39 +0200
Message-ID: <CAAeHK+z+d=Gh4j1VSsEtLuYUpd7-T3Cu1ww0-5otSE5kDTgMGA@mail.gmail.com> (raw)

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.

2. Is there an easy way to figure out which config options enable
drivers reachable over USB?

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.

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.

If you have any other questions or comments, please let us know.

Alan, thanks a lot for answering to lots of my USB related questions
while I was working on this, that helped tremendously!

Thanks!

[1] https://docs.google.com/presentation/d/1z-giB9kom17Lk21YEjmceiNUVYeI6yIaG5_gZ3vKC-M/edit#slide=id.g1925acbbf3_0_0

[2] https://www.youtube.com/watch?v=1MD5JV6LfxA

[3] https://github.com/google/kasan/commit/9a33b36996cb6138a806eab931ba43c63a836708

[4] https://github.com/google/syzkaller/blob/usb-fuzzer/tools/usb/keyboard.c

[5] https://github.com/google/syzkaller/blob/master/sys/linux/vusb.txt

[6] https://github.com/google/syzkaller/blob/master/executor/common_usb.h

             reply index

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-04-17 16:33 Andrey Konovalov [this message]
2019-04-19  8:35 ` Greg Kroah-Hartman
2019-04-19 14:39   ` Alan Stern
2019-04-24 16:09     ` Andrey Konovalov
2019-04-24 16:05   ` Andrey Konovalov
2019-04-25 12:44     ` Andrey Konovalov
2019-04-25 14:25       ` Greg Kroah-Hartman
2019-05-14 12:43         ` Andrey Konovalov
2019-08-13 13:06 ` Andrey Konovalov

Reply instructions:

You may reply publically to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAAeHK+z+d=Gh4j1VSsEtLuYUpd7-T3Cu1ww0-5otSE5kDTgMGA@mail.gmail.com' \
    --to=andreyknvl@google.com \
    --cc=dvyukov@google.com \
    --cc=glider@google.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=gustavo@embeddedor.com \
    --cc=kcc@google.com \
    --cc=linux-usb@vger.kernel.org \
    --cc=stern@rowland.harvard.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Linux-USB Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-usb/0 linux-usb/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-usb linux-usb/ https://lore.kernel.org/linux-usb \
		linux-usb@vger.kernel.org linux-usb@archiver.kernel.org
	public-inbox-index linux-usb


Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-usb


AGPL code for this site: git clone https://public-inbox.org/ public-inbox