Skip to content

Commit

Permalink
docs: rewrite reproducing_crashes.md
Browse files Browse the repository at this point in the history
Let's list all the possible ways of reproducing syzkaller crashes
locally and keep the instructions of how to manually craft a reproducer
at the bottom.

Add information about the ktest tooling - now it also automates the
reproduction of syzbot bugs. See the discussion at:
https://groups.google.com/g/syzkaller/c/UTPrWcJfS8Q/m/K1YXz-f1AQAJ
  • Loading branch information
a-nogikh committed Nov 22, 2024
1 parent 68da6d9 commit a86430d
Showing 1 changed file with 166 additions and 25 deletions.
191 changes: 166 additions & 25 deletions docs/reproducing_crashes.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,184 @@
# How to reproduce crashes
# How to reproduce syzkaller crashes

The process of creating reproducer programs for syzkaller bugs is automated,
however it's not perfect, so syzkaller provides a few tools for executing and
reproducing programs manually.
## Using a C reproducer

If the bug was reported by syzbot, you first need to build the kernel used by
the tool. Syzbot provides the necessary information in its report:

```
Hello,
syzbot found the following issue on:
HEAD commit: ae58226b89ac Add linux-next specific files for 20241118
git tree: linux-next
console+strace: https://syzkaller.appspot.com/x/log.txt?x=14a67378580000
kernel config: https://syzkaller.appspot.com/x/.config?x=45719eec4c74e6ba
dashboard link: https://syzkaller.appspot.com/bug?extid=2159cbb522b02847c053
compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=137beac0580000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=177beac0580000
```

In this case, you would run:
```
$ git checkout ae58226b89ac
$ wget -O '.config' 'https://syzkaller.appspot.com/x/.config?x=45719eec4c74e6ba`
$ make CC=clang LD=ld.lld olddefconfig
$ make CC=clang LD=ld.lld -j$(nproc)
```

You also need a bootable disk image. Syzbot currently uses small Buildroot-based
images that you can either [build locally](/tools/create-buildroot-image.sh) or
[download](https://storage.googleapis.com/syzkaller/images/buildroot_amd64_2024.09.gz).

Download and build the reproducer:
```
$ wget -O 'repro.c' 'https://syzkaller.appspot.com/x/repro.c?x=177beac0580000'
$ gcc repro.c -lpthread -static -o repro
```

Run the VM:
```
$ export DISK_IMAGE='buildroot_amd64_2024.09'
$ qemu-system-x86_64 -m 2G -smp 2,sockets=2,cores=1 -drive file=$DISK_IMAGE,format=raw -net nic,model=e1000 -net user,host=10.0.2.10,hostfwd=tcp::10022-:22 -enable-kvm -nographic -snapshot -machine pc-q35-7.1
```

Run the reproducer:
```
$ scp -P 10022 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes ./repro [email protected]:/root/
$ ssh -p 10022 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes [email protected] 'chmod +x ./repro && ./repro'
```


## Using a Syz reproducer

Syzkaller always generates a "Syz" reproducer first (in [Syzkaller
DSL](/docs/program_syntax.md)). Afterwards, syzkaller attempts to convert the
Syz reproducer into C code. The process does not always succeed due to the
differences between the `syz-executor` environment and the environment emulated
in the C reproducer. Therefore, in some cases, only the Syz version is
available.

To run a Syz reproducer locally, the required actions are mostly similar to
those in the previous section.

Download and
[build](https://github.com/google/syzkaller/blob/master/docs/linux/setup.md#go-and-syzkaller)

Check failure on line 67 in docs/reproducing_crashes.md

View workflow job for this annotation

GitHub Actions / aux

Replace absolute link with /docs/linux/setup.md#go-and-syzkaller.
syzkaller. If you have Docker installed, the instructions are simpler:
```
$ git clone https://github.com/google/syzkaller.git
$ ./tools/syz-env make
```

Build the kernel and boot the VM as described above.

Download and run the reproducer:
```
$ export SYZKALLER_PATH="~/syzkaller"
$ wget -O 'repro.syz' 'https://syzkaller.appspot.com/x/repro.syz?x=137beac0580000'
$ scp -P 10022 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes $SYZKALLER_PATH/bin/linux_amd64/* ./repro.syz [email protected]:/root/
$ ssh -p 10022 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes [email protected] './syz-execprog -enable=all -repeat=0 -procs=6 ./repro.syz'
```

## Using ktest

[ktest](https://evilpiepirate.org/git/ktest.git/tree/README.md) is a collection
of tests for Linux and an infrastructure that simplifies running them locally.

Ktest includes a special `syzbot-repro.ktest` test that automates building the
kernel, booting the VM, fetching syzbot bug report details and running the
reproducer.

**Installation instructions:**
```
$ git clone git://evilpiepirate.org/ktest.git
$ cd ktest
$ export KTEST_PATH=$(pwd)
$ sudo ./root_image init
$ sudo ./root_image create
$ sudo apt-get install capnproto
$ cargo install --path /tmp/ktest
```

**Instructions to reproduce a syzbot bug:**
```
$ cd ~/linux
$ git checkout <kernel-commit>
$ $KTEST_PATH/build-test-kernel -I $KTEST_PATH/tests/syzbot-repro.ktest <bug-id>
```

`<bug-id>` can be taken from syzbot bug reports:

```
dashboard link: https://syzkaller.appspot.com/bug?extid=2159cbb522b02847c053
```

In this case, `bug-id` is `2159cbb522b02847c053`.


## Using downloadable assets

See [the corresponding documentation](docs/syzbot_assets.md).

Check failure on line 122 in docs/reproducing_crashes.md

View workflow job for this annotation

GitHub Actions / aux

Broken link docs/syzbot_assets.md.

## From execution logs

The process of creating reproducer programs for syzkaller bugs is automated, but
it's not perfect. In some cases, the tool cannot narrow down the kernel crash to
a single program.

### Obtaining execution logs
* **A local syzkaller instance** \
Crash logs created in manager `workdir/crashes` dir contain programs executed
just before a crash. In parallel execution mode (when `procs` parameter in
manager config is set to value larger than 1), program that caused the crash
does not necessary immediately precedes it; the guilty program can be somewhere
before. There are two tools that can help you identify and minimize the program
that causes a crash: `tools/syz-execprog` and `tools/syz-prog2c`.
before.

* **Syzbot** shares execution logs in its reports:
```
console output: https://syzkaller.appspot.com/x/log.txt?x=148914c0580000
```

### Crafting reproducers manually

`tools/syz-execprog` executes a single syzkaller program or a set of programs in
There are two tools that can help you identify and minimize the program that
causes a crash: `syz-execprog` and `syz-prog2c`. You can build them with `make
execprog` and `make prog2c`, respectively.

`syz-execprog` executes a single syzkaller program or a set of programs in
various modes (once or loop indefinitely; in threaded/collide mode (see below),
with or without coverage collection). You can start by running all programs in
the crash log in a loop to check that at least one of them indeed crashes
kernel: `./syz-execprog -executor=./syz-executor -repeat=0 -procs=16 -cover=0
crash-log`. Then try to identify the single program that causes the crash, you
can test programs with `./syz-execprog -executor=./syz-executor -repeat=0
-procs=16 -cover=0 file-with-a-single-program`.

Note: `syz-execprog` executes programs locally. So you need to copy
with or without coverage collection).

You can start by running all programs in the crash log in a loop to check that
at least one of them indeed crashes kernel:

```
./syz-execprog -executor=./syz-executor -repeat=0 -procs=8 -cover=0 crash-log-file.txt
```
**Note: `syz-execprog` executes programs locally. So you need to copy
`syz-execprog` and `syz-executor` into a VM with the test kernel and run it
there.
there.** See the [Using a Syz reproducer](#Using-a-Syz-reproducer) section.

To identify the single program that causes the crash, you can cut out individual
programs from `crash-log-file.txt` and run `syz-execprog` separately.

Once you have a single program that causes the crash, you can try to minimize it by:
* Removing individual syscalls from the program (you can comment out single lines
with `#` at the beginning of line)
* By removing unnecessary data (e.g. replacing `&(0x7f0000001000)="73656c6600"`
syscall argument with `&(0x7f0000001000)=nil`).
* You can also try to coalesce all mmap calls into a single mmap call that maps
whole required area.

Once you have a single program that causes the crash, try to minimize it by
removing individual syscalls from the program (you can comment out single lines
with `#` at the beginning of line), and by removing unnecessary data
(e.g. replacing `&(0x7f0000001000)="73656c6600"` syscall argument with
`&(0x7f0000001000)=nil`). You can also try to coalesce all mmap calls into a
single mmap call that maps whole required area. Again, test minimization with
`syz-execprog` tool.
Don't forget to test minimization results with the `syz-execprog` tool.

Now that you have a minimized program, check if the crash still reproduces with
`./syz-execprog -threaded=0 -collide=0` flags. If not, then you will need to do
some additional work later.

Now, run `syz-prog2c` tool on the program. It will give you executable C
source. If the crash reproduces with `-threaded/collide=0` flags, then this C
Now, run the `syz-prog2c` tool on the program. It will give you an executable C
source code. If the crash reproduces with `-threaded/collide=0` flags, then this C
program should cause the crash as well.

If the crash is not reproducible with `-threaded/collide=0` flags, then you need
Expand Down

0 comments on commit a86430d

Please sign in to comment.