diff mbox series

[1/2] Wrapper for Syzkaller reproducers

Message ID 20191107153458.16917-2-rpalethorpe@suse.com
State Superseded
Headers show
Series LTP wrapper for Syzkaller reproducers | expand

Commit Message

Richard Palethorpe Nov. 7, 2019, 3:34 p.m. UTC
Allows one to run the Syzkaller reproducers as part of the LTP.

Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
---
 .gitmodules                                  |   5 +
 configure.ac                                 |  11 ++
 include/mk/features.mk.default               |   2 +
 include/mk/features.mk.in                    |   2 +
 runtest/.gitignore                           |   1 +
 testcases/kernel/Makefile                    |   1 +
 testcases/kernel/syzkaller-repros/.gitignore |   1 +
 testcases/kernel/syzkaller-repros/Makefile   | 100 ++++++++++++++
 testcases/kernel/syzkaller-repros/README.md  |  45 +++++++
 testcases/kernel/syzkaller-repros/syzwrap.c  | 133 +++++++++++++++++++
 10 files changed, 301 insertions(+)
 create mode 100644 runtest/.gitignore
 create mode 100644 testcases/kernel/syzkaller-repros/.gitignore
 create mode 100644 testcases/kernel/syzkaller-repros/Makefile
 create mode 100644 testcases/kernel/syzkaller-repros/README.md
 create mode 100644 testcases/kernel/syzkaller-repros/syzwrap.c

Comments

Samasth via ltp Nov. 7, 2019, 3:43 p.m. UTC | #1
On Thu, Nov 7, 2019 at 4:35 PM Richard Palethorpe <rpalethorpe@suse.com> wrote:
>
> Allows one to run the Syzkaller reproducers as part of the LTP.
>
> Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
> ---
>  .gitmodules                                  |   5 +
>  configure.ac                                 |  11 ++
>  include/mk/features.mk.default               |   2 +
>  include/mk/features.mk.in                    |   2 +
>  runtest/.gitignore                           |   1 +
>  testcases/kernel/Makefile                    |   1 +
>  testcases/kernel/syzkaller-repros/.gitignore |   1 +
>  testcases/kernel/syzkaller-repros/Makefile   | 100 ++++++++++++++
>  testcases/kernel/syzkaller-repros/README.md  |  45 +++++++
>  testcases/kernel/syzkaller-repros/syzwrap.c  | 133 +++++++++++++++++++
>  10 files changed, 301 insertions(+)
>  create mode 100644 runtest/.gitignore
>  create mode 100644 testcases/kernel/syzkaller-repros/.gitignore
>  create mode 100644 testcases/kernel/syzkaller-repros/Makefile
>  create mode 100644 testcases/kernel/syzkaller-repros/README.md
>  create mode 100644 testcases/kernel/syzkaller-repros/syzwrap.c
>
> diff --git a/.gitmodules b/.gitmodules
> index 1c9e9c38a..6a2d31f51 100644
> --- a/.gitmodules
> +++ b/.gitmodules
> @@ -1,3 +1,8 @@
>  [submodule "testcases/kernel/mce-test"]
>         path = testcases/kernel/mce-test
>         url = git://git.kernel.org/pub/scm/linux/kernel/git/gong.chen/mce-test.git
> +[submodule "testcases/linux-arts"]
> +       path = testcases/linux-arts
> +       url = https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-arts.git
> +       shallow = true
> +       ignore = all
> diff --git a/configure.ac b/configure.ac
> index 3785dff63..ec4cae483 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -184,6 +184,17 @@ else
>      AC_SUBST([WITH_OPEN_POSIX_TESTSUITE],["no"])
>  fi
>
> +AC_ARG_WITH([syzkaller-repros],
> +  [AC_HELP_STRING([--with-syzkaller-repros],
> +    [compile and install Syzkaller reproducers (default=no)])],
> +  [with_syzkaller_repros=$withval]
> +)
> +if test "x$with_syzkaller_repros" = xyes; then
> +    AC_SUBST([WITH_SYZKALLER_REPROS],["yes"])
> +else
> +    AC_SUBST([WITH_SYZKALLER_REPROS],["no"])
> +fi
> +
>  # testcases/realtime requires bash and python.
>  if test "x$with_bash" = xyes && test "x$with_python" = xyes; then
>      AC_ARG_WITH([realtime-testsuite],
> diff --git a/include/mk/features.mk.default b/include/mk/features.mk.default
> index 3a6cc5176..71fb48c60 100644
> --- a/include/mk/features.mk.default
> +++ b/include/mk/features.mk.default
> @@ -47,3 +47,5 @@ WITH_REALTIME_TESTSUITE               := no
>  else
>  WITH_REALTIME_TESTSUITE                := no
>  endif
> +
> +WITH_SYZKALLER_REPROS          := no
> diff --git a/include/mk/features.mk.in b/include/mk/features.mk.in
> index 8e561b738..3ab7f4721 100644
> --- a/include/mk/features.mk.in
> +++ b/include/mk/features.mk.in
> @@ -47,3 +47,5 @@ WITH_REALTIME_TESTSUITE               := no
>  else
>  WITH_REALTIME_TESTSUITE                := @WITH_REALTIME_TESTSUITE@
>  endif
> +
> +WITH_SYZKALLER_REPROS          := @WITH_SYZKALLER_REPROS@
> diff --git a/runtest/.gitignore b/runtest/.gitignore
> new file mode 100644
> index 000000000..2ae05bfac
> --- /dev/null
> +++ b/runtest/.gitignore
> @@ -0,0 +1 @@
> +syzkaller*
> diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile
> index 3319b3163..0150cfb4f 100644
> --- a/testcases/kernel/Makefile
> +++ b/testcases/kernel/Makefile
> @@ -53,6 +53,7 @@ SUBDIRS                       += connectors \
>                            sched \
>                            security \
>                            sound \
> +                          syzkaller-repros \
>                            tracing \
>                            uevents \
>
> diff --git a/testcases/kernel/syzkaller-repros/.gitignore b/testcases/kernel/syzkaller-repros/.gitignore
> new file mode 100644
> index 000000000..dbda1c71f
> --- /dev/null
> +++ b/testcases/kernel/syzkaller-repros/.gitignore
> @@ -0,0 +1 @@
> +syzwrap
> diff --git a/testcases/kernel/syzkaller-repros/Makefile b/testcases/kernel/syzkaller-repros/Makefile
> new file mode 100644
> index 000000000..d40d61ac1
> --- /dev/null
> +++ b/testcases/kernel/syzkaller-repros/Makefile
> @@ -0,0 +1,100 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# Copyright (c) 2019 Linux Test Project
> +
> +top_srcdir             ?= ../../..
> +
> +include $(top_srcdir)/include/mk/testcases.mk
> +
> +CFLAGS                 += -D_GNU_SOURCE
> +
> +ifeq ($(WITH_SYZKALLER_REPROS),yes)
> +
> +# The number of reproducers in each runtest file
> +SYZKALLER_RUNFILES_SIZE ?= 100
> +
> +# Extra arguments to pass to syzwrap. Uncomment the below to add some
> +# sandboxing.
> +# SYZWRAP_ARGS ?= -s
> +
> +# Location where reproducers are installed
> +SYZKALLER_INSTALL_DIR ?= $(abspath $(DESTDIR)/$(prefix)/testcases/bin)
> +
> +# If the reproducers directory is missing then we automatically clone the repo.
> +# We then have to call make recursively to revaluate the targets
> +SYZKALLER_REPROS_DIR ?= $(abs_top_srcdir)/testcases/linux-arts/syzkaller-repros/linux
> +$(SYZKALLER_REPROS_DIR):
> +       git submodule update --init $(abs_top_srcdir)/testcases/linux-arts
> +       $(MAKE) syzkaller_runfiles
> +
> +SYZKALLER_REPROS_SRCS = $(wildcard $(SYZKALLER_REPROS_DIR)/*.c)
> +
> +# Some useful compiler flags for the LTP will cause problems with the
> +# syzkaller repros so the repros have seperate flags
> +SYZKALLER_CFLAGS ?= -pthread
> +SYZKALLER_REPROS = $(subst $(abs_top_srcdir),$(abs_top_builddir),$(SYZKALLER_REPROS_SRCS:.c=))
> +$(SYZKALLER_REPROS): %: %.c
> +       -@if grep -q "__NR_mmap2" $^; then \
> +               M32="-m32"; \
> +       fi; \
> +       $(CC) $(SYZKALLER_CFLAGS) $$M32 $(SYZKALLER_LDFLAGS) $^ -o $@; \
> +       echo $(CC) $(SYZKALLER_CFLAGS) $$M32 $(SYZKALLER_LDFLAGS) $^ -o $@;
> +
> +# Generate the names of the runtest files. This uses Shell arithmetic to
> +# calculate how many runtest files there will be.
> +define SYZKALLER_RUNFILES !=
> +       n=$(words $(SYZKALLER_REPROS));
> +       m=$(SYZKALLER_RUNFILES_SIZE);
> +       i=$$(( $$n / $$m + ($$n % $$m > 0) ));
> +       while test $$i -gt 0;
> +       do
> +               echo $(top_srcdir)/runtest/syzkaller$$i;
> +               i=$$(($$i - 1));
> +       done
> +endef
> +
> +# Get the index part of a runtest files name
> +syz_n = $(subst $(top_srcdir)/runtest/syzkaller,,$(1))
> +syz_m = $(SYZKALLER_RUNFILES_SIZE)
> +# Gives the index of the first reproducer in a runtest file
> +syz_i = $(shell echo $$((($(call syz_n,$(1)) - 1) * $(2) + 1)))
> +# Gives the index of the last reproducer in a runtest file
> +syz_j = $(shell echo $$(( $(call syz_i,$(1),$(2)) + $(2) - 1 )))
> +# Gvien a runtest file name, get the reproducers it should contain
> +syz_wordlist = $(wordlist $(call syz_i,$(1),$(syz_m)),$(call syz_j,$(1),$(syz_m)),$(SYZKALLER_REPROS))
> +
> +define syz_runfile_line
> +$(notdir $(exe)) syzwrap $(SYZWRAP_ARGS) -d $(SYZKALLER_INSTALL_DIR) -n $(notdir $(exe))
> +
> +endef
> +
> +# Generate the runtest files based on the reproducer names and batch size.
> +$(SYZKALLER_RUNFILES): $(SYZKALLER_REPROS)
> +       @echo "Writing $@"
> +       $(file >$@)
> +       $(foreach exe,$(call syz_wordlist,$@),$(file >>$@,$(syz_runfile_line)))
> +
> +.PHONY: syzkaller_runfiles
> +syzkaller_runfiles: $(SYZKALLER_RUNFILES) | $(SYZKALLER_REPROS_DIR)
> +
> +all: $(SYZKALLER_RUNFILES) | $(SYZKALLER_REPROS_DIR)
> +
> +# There are too many reproducers to pass all at once to rm, so we just pass
> +# one at a time
> +syzkaller_clean:
> +       $(foreach f, $(SYZKALLER_REPROS), $(RM) $(f))
> +CLEAN_DEPS += syzkaller_clean
> +CLEAN_TARGETS += $(SYZKALLER_RUNFILES)
> +
> +INSTALL_MODE ?= 0775
> +
> +# For some reason part of the path is missing if we just try to install these
> +# by adding them to INSTALL_FILES
> +SYZKALLER_REPROS_INSTALLED := $(subst $(SYZKALLER_REPROS_DIR),$(SYZKALLER_INSTALL_DIR),$(SYZKALLER_REPROS))
> +$(SYZKALLER_REPROS_INSTALLED): $(SYZKALLER_INSTALL_DIR)/%: $(SYZKALLER_REPROS_DIR)/%
> +       install -m $(INSTALL_MODE) -T $< $@
> +
> +install: $(SYZKALLER_REPROS_INSTALLED)
> +
> +endif
> +
> +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> diff --git a/testcases/kernel/syzkaller-repros/README.md b/testcases/kernel/syzkaller-repros/README.md
> new file mode 100644
> index 000000000..2c88efd01
> --- /dev/null
> +++ b/testcases/kernel/syzkaller-repros/README.md
> @@ -0,0 +1,45 @@
> +# LTP wrapper for Syzkaller reproducers
> +
> +This allows you to run the autogenerated C bug reproducers from the Syzkaller
> +fuzzer within the LTP framework. Meaning that you may use an existing test
> +runner compatible with the LTP (with some constraints, see below).
> +
> +## Instructions
> +
> +1. Run `ltp/configure` with `--with-syzkaller-repros`.
> +2. Build and install the LTP as normal.
> +3. Run one or more of syzkallerN runtest files where N is a number.
> +
> +Make will automatically download the reproducers into `testcases/linux-arts`
> +using git-submodule if necessary.
> +
> +By default each runtest file contains 100 reproducers. You may change this by
> +overriding `SYZKALLER_RUNFILES_SIZE`.
> +
> +Extra parameters can be sent to syzwrap using `SYZWRAP_ARGS`. See `syzwrap
> +-h`.
> +
> +## Kernel Requirements
> +
> +It is strongly recommended that you use KASAN and other debugging kernel
> +features. See the Syzkaller documentation for the configuration you should
> +use.
> +
> +## Test Runner Requirements
> +
> +Unlike most LTP tests these reproducers can leave your system in a broken
> +state even if no bug is triggered.
> +
> +You will need to:
> +
> +A) Reboot the SUT
> +B) Reset at least the root filesystem to a known good state
> +
> +Every time syzwrap fails.
> +
> +If syzwrap fails with TBROK or fails to run at all, then you probably need to
> +reset the system and rerun that test. If a test fails with TFAIL, you may also
> +want to run it once again with a clean state.
> +
> +It might be the case that some reproducers write to random devices or do other
> +things which can effect the outside world.
> diff --git a/testcases/kernel/syzkaller-repros/syzwrap.c b/testcases/kernel/syzkaller-repros/syzwrap.c
> new file mode 100644
> index 000000000..9f5d16078
> --- /dev/null
> +++ b/testcases/kernel/syzkaller-repros/syzwrap.c
> @@ -0,0 +1,133 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2019 Richard Palethorpe <rpalethorpe@suse.com>
> + *
> + * Run a single reproducer generated by the Syzkaller fuzzer.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/wait.h>
> +#include <sys/prctl.h>
> +#include <sched.h>
> +#include <signal.h>
> +#include <stdio.h>
> +#include <pwd.h>
> +
> +#include "tst_test.h"
> +#include "tst_taint.h"
> +#include "tst_safe_stdio.h"
> +
> +#define SANDBOX_HELP "\n"\
> +       "-s\t Add some sandboxing around the reproducer. This will prevent some\n"\
> +       "\t reproducers from creating network devices and thus prevent them from\n"\
> +       "\t working. However it will also prevent some reproducers from trashing\n"\
> +       "\t the system using root privileges. Note that you may generate the\n"\
> +       "\t reproducers with various types of sandboxing built in using\n"\
> +       "\t syz-reprolist"
> +
> +static char *dir;
> +static char *name;
> +static char *path;
> +
> +static char *sandbox;
> +
> +static struct tst_option options[] = {
> +       {"d:", &dir, "\n-d PATH\t Mandatory directory containing reproducers"},
> +       {"n:", &name, "-n NAME\t Mandatory executable name of reproducer"},
> +       {"s", &sandbox, SANDBOX_HELP},
> +       {NULL, NULL, NULL}
> +};
> +
> +static void become_nobody(void)
> +{
> +       struct passwd *pw;
> +       int gid, uid;
> +
> +       setgroups(0, NULL);
> +
> +       pw = getpwnam("nobody");
> +       if (pw) {
> +               gid = pw->pw_gid;
> +               uid = pw->pw_uid;
> +       } else {
> +               gid = 65534;
> +               uid = 65534;
> +       }
> +
> +       SAFE_SETREGID(gid, gid);
> +       SAFE_SETREUID(uid, uid);
> +}
> +
> +static void setup(void)
> +{
> +       tst_taint_init(TST_TAINT_W | TST_TAINT_D | TST_TAINT_L);
> +
> +       if (!dir)
> +               tst_brk(TBROK, "No reproducer directory specified");
> +
> +       if (!name)
> +               tst_brk(TBROK, "No reproducer name specified");
> +
> +       tst_res(TINFO, "https://syzkaller.appspot.com/bug?id=%s", name);
> +
> +       SAFE_ASPRINTF(&path, "%s/%s", dir, name);
> +       tst_res(TINFO, "%s", path);
> +}
> +
> +static void run(void)
> +{
> +       unsigned int backoff = 100;
> +       int rem, status, sent_kill = 0;
> +       float exec_time_start = (float)tst_timeout_remaining();
> +       int pid;
> +
> +       if (sandbox)
> +               SAFE_UNSHARE(CLONE_NEWPID);
> +
> +       pid = SAFE_FORK();
> +       if (!pid) {
> +               if (sandbox) {
> +                       SAFE_UNSHARE(CLONE_NEWNET);
> +                       become_nobody();
> +               }
> +
> +               if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)) {
> +                       tst_res(TWARN | TERRNO,
> +                               "Failed to set dumpable; won't be able to open /proc/self/*");
> +               }
> +
> +               execl(path, name, NULL);
> +               tst_brk(TBROK | TERRNO, "Failed to exec reproducer");
> +       }
> +
> +       while (!waitpid(pid, &status, WNOHANG)) {
> +               rem = tst_timeout_remaining();
> +
> +               if (!sent_kill && rem / exec_time_start < 0.5) {
> +                       tst_res(TINFO, "Timeout; killing reproducer");
> +
> +                       TEST(kill(pid, SIGKILL));
> +                       if (TST_RET == -1)
> +                               tst_res(TWARN | TTERRNO, "kill() failed");
> +                       else
> +                               sent_kill = 1;
> +               }
> +
> +               usleep(backoff);
> +               backoff = MIN(2 * backoff, 1000000);
> +       }
> +
> +       if (tst_taint_check()) {
> +               tst_res(TFAIL, "Kernel is tainted");
> +       } else {
> +               tst_res(TPASS, "Kernel is not tainted");
> +       }
> +}
> +
> +static struct tst_test test = {
> +       .setup = setup,
> +       .test_all = run,
> +       .options = options,
> +       .needs_tmpdir = 1,
> +       .forks_child = 1
> +};
> --
> 2.23.0
>

+syzkaller mailing list FTR
Li Wang Nov. 12, 2019, 12:38 p.m. UTC | #2
On Thu, Nov 7, 2019 at 11:44 PM Dmitry Vyukov via ltp <ltp@lists.linux.it>
wrote:

> On Thu, Nov 7, 2019 at 4:35 PM Richard Palethorpe <rpalethorpe@suse.com>
> wrote:
> >
> > Allows one to run the Syzkaller reproducers as part of the LTP.
> >
> > Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
> > ---
> >  .gitmodules                                  |   5 +
> >  configure.ac                                 |  11 ++
> >  include/mk/features.mk.default               |   2 +
> >  include/mk/features.mk.in                    |   2 +
> >  runtest/.gitignore                           |   1 +
> >  testcases/kernel/Makefile                    |   1 +
> >  testcases/kernel/syzkaller-repros/.gitignore |   1 +
> >  testcases/kernel/syzkaller-repros/Makefile   | 100 ++++++++++++++
> >  testcases/kernel/syzkaller-repros/README.md  |  45 +++++++
> >  testcases/kernel/syzkaller-repros/syzwrap.c  | 133 +++++++++++++++++++
> >  10 files changed, 301 insertions(+)
> >  create mode 100644 runtest/.gitignore
> >  create mode 100644 testcases/kernel/syzkaller-repros/.gitignore
> >  create mode 100644 testcases/kernel/syzkaller-repros/Makefile
> >  create mode 100644 testcases/kernel/syzkaller-repros/README.md
> >  create mode 100644 testcases/kernel/syzkaller-repros/syzwrap.c
> >
> > diff --git a/.gitmodules b/.gitmodules
> > index 1c9e9c38a..6a2d31f51 100644
> > --- a/.gitmodules
> > +++ b/.gitmodules
> > @@ -1,3 +1,8 @@
> >  [submodule "testcases/kernel/mce-test"]
> >         path = testcases/kernel/mce-test
> >         url = git://
> git.kernel.org/pub/scm/linux/kernel/git/gong.chen/mce-test.git
> > +[submodule "testcases/linux-arts"]
> > +       path = testcases/linux-arts
> > +       url =
> https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-arts.git
> > +       shallow = true
> > +       ignore = all
> > diff --git a/configure.ac b/configure.ac
> > index 3785dff63..ec4cae483 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -184,6 +184,17 @@ else
> >      AC_SUBST([WITH_OPEN_POSIX_TESTSUITE],["no"])
> >  fi
> >
> > +AC_ARG_WITH([syzkaller-repros],
> > +  [AC_HELP_STRING([--with-syzkaller-repros],
> > +    [compile and install Syzkaller reproducers (default=no)])],
> > +  [with_syzkaller_repros=$withval]
> > +)
> > +if test "x$with_syzkaller_repros" = xyes; then
> > +    AC_SUBST([WITH_SYZKALLER_REPROS],["yes"])
> > +else
> > +    AC_SUBST([WITH_SYZKALLER_REPROS],["no"])
> > +fi
> > +
> >  # testcases/realtime requires bash and python.
> >  if test "x$with_bash" = xyes && test "x$with_python" = xyes; then
> >      AC_ARG_WITH([realtime-testsuite],
> > diff --git a/include/mk/features.mk.default b/include/mk/features.mk
> .default
> > index 3a6cc5176..71fb48c60 100644
> > --- a/include/mk/features.mk.default
> > +++ b/include/mk/features.mk.default
> > @@ -47,3 +47,5 @@ WITH_REALTIME_TESTSUITE               := no
> >  else
> >  WITH_REALTIME_TESTSUITE                := no
> >  endif
> > +
> > +WITH_SYZKALLER_REPROS          := no
> > diff --git a/include/mk/features.mk.in b/include/mk/features.mk.in
> > index 8e561b738..3ab7f4721 100644
> > --- a/include/mk/features.mk.in
> > +++ b/include/mk/features.mk.in
> > @@ -47,3 +47,5 @@ WITH_REALTIME_TESTSUITE               := no
> >  else
> >  WITH_REALTIME_TESTSUITE                := @WITH_REALTIME_TESTSUITE@
> >  endif
> > +
> > +WITH_SYZKALLER_REPROS          := @WITH_SYZKALLER_REPROS@
> > diff --git a/runtest/.gitignore b/runtest/.gitignore
> > new file mode 100644
> > index 000000000..2ae05bfac
> > --- /dev/null
> > +++ b/runtest/.gitignore
> > @@ -0,0 +1 @@
> > +syzkaller*
> > diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile
> > index 3319b3163..0150cfb4f 100644
> > --- a/testcases/kernel/Makefile
> > +++ b/testcases/kernel/Makefile
> > @@ -53,6 +53,7 @@ SUBDIRS                       += connectors \
> >                            sched \
> >                            security \
> >                            sound \
> > +                          syzkaller-repros \
> >                            tracing \
> >                            uevents \
> >
> > diff --git a/testcases/kernel/syzkaller-repros/.gitignore
> b/testcases/kernel/syzkaller-repros/.gitignore
> > new file mode 100644
> > index 000000000..dbda1c71f
> > --- /dev/null
> > +++ b/testcases/kernel/syzkaller-repros/.gitignore
> > @@ -0,0 +1 @@
> > +syzwrap
> > diff --git a/testcases/kernel/syzkaller-repros/Makefile
> b/testcases/kernel/syzkaller-repros/Makefile
> > new file mode 100644
> > index 000000000..d40d61ac1
> > --- /dev/null
> > +++ b/testcases/kernel/syzkaller-repros/Makefile
> > @@ -0,0 +1,100 @@
> > +# SPDX-License-Identifier: GPL-2.0-or-later
> > +# Copyright (c) 2019 Linux Test Project
> > +
> > +top_srcdir             ?= ../../..
> > +
> > +include $(top_srcdir)/include/mk/testcases.mk
> > +
> > +CFLAGS                 += -D_GNU_SOURCE
> > +
> > +ifeq ($(WITH_SYZKALLER_REPROS),yes)
> > +
> > +# The number of reproducers in each runtest file
> > +SYZKALLER_RUNFILES_SIZE ?= 100
> > +
> > +# Extra arguments to pass to syzwrap. Uncomment the below to add some
> > +# sandboxing.
> > +# SYZWRAP_ARGS ?= -s
> > +
> > +# Location where reproducers are installed
> > +SYZKALLER_INSTALL_DIR ?= $(abspath $(DESTDIR)/$(prefix)/testcases/bin)
> > +
> > +# If the reproducers directory is missing then we automatically clone
> the repo.
> > +# We then have to call make recursively to revaluate the targets
> > +SYZKALLER_REPROS_DIR ?=
> $(abs_top_srcdir)/testcases/linux-arts/syzkaller-repros/linux
> > +$(SYZKALLER_REPROS_DIR):
> > +       git submodule update --init
> $(abs_top_srcdir)/testcases/linux-arts
>


Just to try build it in LTP and hit errors:

# cd ltp-new/
# make autotools
# ./configure --with-syzkaller-repros
# make -j32
...
error: pathspec '/root/ltp-new/testcases/linux-arts' did not match any
file(s) known to git
make[3]: *** [/root/ltp-new/testcases/kernel/syzkaller-repros/Makefile:26:
/root/ltp-new/testcases/linux-arts/syzkaller-repros/linux] Error 1
make[3]: Leaving directory '/root/ltp-new/testcases/kernel/syzkaller-repros'
make[2]: *** [../../include/mk/generic_trunk_target.inc:93: all] Error 2
make[2]: Leaving directory '/root/ltp-new/testcases/kernel'
make[1]: *** [../include/mk/generic_trunk_target.inc:93: all] Error 2
make[1]: Leaving directory '/root/ltp-new/testcases'
make: *** [Makefile:108: testcases-all] Error 2



> > +       $(MAKE) syzkaller_runfiles
> > +
> > +SYZKALLER_REPROS_SRCS = $(wildcard $(SYZKALLER_REPROS_DIR)/*.c)
> > +
> > +# Some useful compiler flags for the LTP will cause problems with the
> > +# syzkaller repros so the repros have seperate flags
> > +SYZKALLER_CFLAGS ?= -pthread
> > +SYZKALLER_REPROS = $(subst
> $(abs_top_srcdir),$(abs_top_builddir),$(SYZKALLER_REPROS_SRCS:.c=))
> > +$(SYZKALLER_REPROS): %: %.c
> > +       -@if grep -q "__NR_mmap2" $^; then \
> > +               M32="-m32"; \
> > +       fi; \
> > +       $(CC) $(SYZKALLER_CFLAGS) $$M32 $(SYZKALLER_LDFLAGS) $^ -o $@; \
> > +       echo $(CC) $(SYZKALLER_CFLAGS) $$M32 $(SYZKALLER_LDFLAGS) $^ -o
> $@;
> > +
> > +# Generate the names of the runtest files. This uses Shell arithmetic to
> > +# calculate how many runtest files there will be.
> > +define SYZKALLER_RUNFILES !=
> > +       n=$(words $(SYZKALLER_REPROS));
> > +       m=$(SYZKALLER_RUNFILES_SIZE);
> > +       i=$$(( $$n / $$m + ($$n % $$m > 0) ));
> > +       while test $$i -gt 0;
> > +       do
> > +               echo $(top_srcdir)/runtest/syzkaller$$i;
> > +               i=$$(($$i - 1));
> > +       done
> > +endef
> > +
> > +# Get the index part of a runtest files name
> > +syz_n = $(subst $(top_srcdir)/runtest/syzkaller,,$(1))
> > +syz_m = $(SYZKALLER_RUNFILES_SIZE)
> > +# Gives the index of the first reproducer in a runtest file
> > +syz_i = $(shell echo $$((($(call syz_n,$(1)) - 1) * $(2) + 1)))
> > +# Gives the index of the last reproducer in a runtest file
> > +syz_j = $(shell echo $$(( $(call syz_i,$(1),$(2)) + $(2) - 1 )))
> > +# Gvien a runtest file name, get the reproducers it should contain
> > +syz_wordlist = $(wordlist $(call syz_i,$(1),$(syz_m)),$(call
> syz_j,$(1),$(syz_m)),$(SYZKALLER_REPROS))
> > +
> > +define syz_runfile_line
> > +$(notdir $(exe)) syzwrap $(SYZWRAP_ARGS) -d $(SYZKALLER_INSTALL_DIR) -n
> $(notdir $(exe))
> > +
> > +endef
> > +
> > +# Generate the runtest files based on the reproducer names and batch
> size.
> > +$(SYZKALLER_RUNFILES): $(SYZKALLER_REPROS)
> > +       @echo "Writing $@"
> > +       $(file >$@)
> > +       $(foreach exe,$(call syz_wordlist,$@),$(file
> >>$@,$(syz_runfile_line)))
> > +
> > +.PHONY: syzkaller_runfiles
> > +syzkaller_runfiles: $(SYZKALLER_RUNFILES) | $(SYZKALLER_REPROS_DIR)
> > +
> > +all: $(SYZKALLER_RUNFILES) | $(SYZKALLER_REPROS_DIR)
> > +
> > +# There are too many reproducers to pass all at once to rm, so we just
> pass
> > +# one at a time
> > +syzkaller_clean:
> > +       $(foreach f, $(SYZKALLER_REPROS), $(RM) $(f))
> > +CLEAN_DEPS += syzkaller_clean
> > +CLEAN_TARGETS += $(SYZKALLER_RUNFILES)
> > +
> > +INSTALL_MODE ?= 0775
> > +
> > +# For some reason part of the path is missing if we just try to install
> these
> > +# by adding them to INSTALL_FILES
> > +SYZKALLER_REPROS_INSTALLED := $(subst
> $(SYZKALLER_REPROS_DIR),$(SYZKALLER_INSTALL_DIR),$(SYZKALLER_REPROS))
> > +$(SYZKALLER_REPROS_INSTALLED): $(SYZKALLER_INSTALL_DIR)/%:
> $(SYZKALLER_REPROS_DIR)/%
> > +       install -m $(INSTALL_MODE) -T $< $@
> > +
> > +install: $(SYZKALLER_REPROS_INSTALLED)
> > +
> > +endif
> > +
> > +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> > diff --git a/testcases/kernel/syzkaller-repros/README.md
> b/testcases/kernel/syzkaller-repros/README.md
> > new file mode 100644
> > index 000000000..2c88efd01
> > --- /dev/null
> > +++ b/testcases/kernel/syzkaller-repros/README.md
> > @@ -0,0 +1,45 @@
> > +# LTP wrapper for Syzkaller reproducers
> > +
> > +This allows you to run the autogenerated C bug reproducers from the
> Syzkaller
> > +fuzzer within the LTP framework. Meaning that you may use an existing
> test
> > +runner compatible with the LTP (with some constraints, see below).
> > +
> > +## Instructions
> > +
> > +1. Run `ltp/configure` with `--with-syzkaller-repros`.
> > +2. Build and install the LTP as normal.
> > +3. Run one or more of syzkallerN runtest files where N is a number.
> > +
> > +Make will automatically download the reproducers into
> `testcases/linux-arts`
> > +using git-submodule if necessary.
> > +
> > +By default each runtest file contains 100 reproducers. You may change
> this by
> > +overriding `SYZKALLER_RUNFILES_SIZE`.
> > +
> > +Extra parameters can be sent to syzwrap using `SYZWRAP_ARGS`. See
> `syzwrap
> > +-h`.
> > +
> > +## Kernel Requirements
> > +
> > +It is strongly recommended that you use KASAN and other debugging kernel
> > +features. See the Syzkaller documentation for the configuration you
> should
> > +use.
> > +
> > +## Test Runner Requirements
> > +
> > +Unlike most LTP tests these reproducers can leave your system in a
> broken
> > +state even if no bug is triggered.
> > +
> > +You will need to:
> > +
> > +A) Reboot the SUT
> > +B) Reset at least the root filesystem to a known good state
> > +
> > +Every time syzwrap fails.
> > +
> > +If syzwrap fails with TBROK or fails to run at all, then you probably
> need to
> > +reset the system and rerun that test. If a test fails with TFAIL, you
> may also
> > +want to run it once again with a clean state.
> > +
> > +It might be the case that some reproducers write to random devices or
> do other
> > +things which can effect the outside world.
> > diff --git a/testcases/kernel/syzkaller-repros/syzwrap.c
> b/testcases/kernel/syzkaller-repros/syzwrap.c
> > new file mode 100644
> > index 000000000..9f5d16078
> > --- /dev/null
> > +++ b/testcases/kernel/syzkaller-repros/syzwrap.c
> > @@ -0,0 +1,133 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Copyright (c) 2019 Richard Palethorpe <rpalethorpe@suse.com>
> > + *
> > + * Run a single reproducer generated by the Syzkaller fuzzer.
> > + */
> > +
> > +#include <sys/types.h>
> > +#include <sys/wait.h>
> > +#include <sys/prctl.h>
> > +#include <sched.h>
> > +#include <signal.h>
> > +#include <stdio.h>
> > +#include <pwd.h>
> > +
> > +#include "tst_test.h"
> > +#include "tst_taint.h"
> > +#include "tst_safe_stdio.h"
> > +
> > +#define SANDBOX_HELP "\n"\
> > +       "-s\t Add some sandboxing around the reproducer. This will
> prevent some\n"\
> > +       "\t reproducers from creating network devices and thus prevent
> them from\n"\
> > +       "\t working. However it will also prevent some reproducers from
> trashing\n"\
> > +       "\t the system using root privileges. Note that you may generate
> the\n"\
> > +       "\t reproducers with various types of sandboxing built in
> using\n"\
> > +       "\t syz-reprolist"
> > +
> > +static char *dir;
> > +static char *name;
> > +static char *path;
> > +
> > +static char *sandbox;
> > +
> > +static struct tst_option options[] = {
> > +       {"d:", &dir, "\n-d PATH\t Mandatory directory containing
> reproducers"},
> > +       {"n:", &name, "-n NAME\t Mandatory executable name of
> reproducer"},
> > +       {"s", &sandbox, SANDBOX_HELP},
> > +       {NULL, NULL, NULL}
> > +};
> > +
> > +static void become_nobody(void)
> > +{
> > +       struct passwd *pw;
> > +       int gid, uid;
> > +
> > +       setgroups(0, NULL);
> > +
> > +       pw = getpwnam("nobody");
> > +       if (pw) {
> > +               gid = pw->pw_gid;
> > +               uid = pw->pw_uid;
> > +       } else {
> > +               gid = 65534;
> > +               uid = 65534;
> > +       }
> > +
> > +       SAFE_SETREGID(gid, gid);
> > +       SAFE_SETREUID(uid, uid);
> > +}
> > +
> > +static void setup(void)
> > +{
> > +       tst_taint_init(TST_TAINT_W | TST_TAINT_D | TST_TAINT_L);
> > +
> > +       if (!dir)
> > +               tst_brk(TBROK, "No reproducer directory specified");
> > +
> > +       if (!name)
> > +               tst_brk(TBROK, "No reproducer name specified");
> > +
> > +       tst_res(TINFO, "https://syzkaller.appspot.com/bug?id=%s", name);
> > +
> > +       SAFE_ASPRINTF(&path, "%s/%s", dir, name);
> > +       tst_res(TINFO, "%s", path);
> > +}
> > +
> > +static void run(void)
> > +{
> > +       unsigned int backoff = 100;
> > +       int rem, status, sent_kill = 0;
> > +       float exec_time_start = (float)tst_timeout_remaining();
> > +       int pid;
> > +
> > +       if (sandbox)
> > +               SAFE_UNSHARE(CLONE_NEWPID);
> > +
> > +       pid = SAFE_FORK();
> > +       if (!pid) {
> > +               if (sandbox) {
> > +                       SAFE_UNSHARE(CLONE_NEWNET);
> > +                       become_nobody();
> > +               }
> > +
> > +               if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)) {
> > +                       tst_res(TWARN | TERRNO,
> > +                               "Failed to set dumpable; won't be able
> to open /proc/self/*");
> > +               }
> > +
> > +               execl(path, name, NULL);
> > +               tst_brk(TBROK | TERRNO, "Failed to exec reproducer");
> > +       }
> > +
> > +       while (!waitpid(pid, &status, WNOHANG)) {
> > +               rem = tst_timeout_remaining();
> > +
> > +               if (!sent_kill && rem / exec_time_start < 0.5) {
> > +                       tst_res(TINFO, "Timeout; killing reproducer");
> > +
> > +                       TEST(kill(pid, SIGKILL));
> > +                       if (TST_RET == -1)
> > +                               tst_res(TWARN | TTERRNO, "kill()
> failed");
> > +                       else
> > +                               sent_kill = 1;
> > +               }
> > +
> > +               usleep(backoff);
> > +               backoff = MIN(2 * backoff, 1000000);
> > +       }
> > +
> > +       if (tst_taint_check()) {
> > +               tst_res(TFAIL, "Kernel is tainted");
> > +       } else {
> > +               tst_res(TPASS, "Kernel is not tainted");
> > +       }
> > +}
> > +
> > +static struct tst_test test = {
> > +       .setup = setup,
> > +       .test_all = run,
> > +       .options = options,
> > +       .needs_tmpdir = 1,
> > +       .forks_child = 1
> > +};
> > --
> > 2.23.0
> >
>
> +syzkaller mailing list FTR
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
>
Richard Palethorpe Nov. 12, 2019, 2 p.m. UTC | #3
Hello,

Li Wang <liwang@redhat.com> writes:

>
>
> Just to try build it in LTP and hit errors:
>
> # cd ltp-new/
> # make autotools
> # ./configure --with-syzkaller-repros
> # make -j32
> ...
> error: pathspec '/root/ltp-new/testcases/linux-arts' did not match any
> file(s) known to git
> make[3]: *** [/root/ltp-new/testcases/kernel/syzkaller-repros/Makefile:26:
> /root/ltp-new/testcases/linux-arts/syzkaller-repros/linux] Error 1
> make[3]: Leaving directory '/root/ltp-new/testcases/kernel/syzkaller-repros'
> make[2]: *** [../../include/mk/generic_trunk_target.inc:93: all] Error 2
> make[2]: Leaving directory '/root/ltp-new/testcases/kernel'
> make[1]: *** [../include/mk/generic_trunk_target.inc:93: all] Error 2
> make[1]: Leaving directory '/root/ltp-new/testcases'
> make: *** [Makefile:108: testcases-all] Error 2
>
>

What happens if you try to pull the git submodule manually?

i.e. do git submodule update --init testcases/linux-arts

It looks like it failed on the line where it gets the submodule, so I am
wondering if you have an old git version?
Li Wang Nov. 12, 2019, 2:10 p.m. UTC | #4
On Tue, Nov 12, 2019 at 10:00 PM Richard Palethorpe <rpalethorpe@suse.de>
wrote:

> Hello,
>
> Li Wang <liwang@redhat.com> writes:
>
> >
> >
> > Just to try build it in LTP and hit errors:
> >
> > # cd ltp-new/
> > # make autotools
> > # ./configure --with-syzkaller-repros
> > # make -j32
> > ...
> > error: pathspec '/root/ltp-new/testcases/linux-arts' did not match any
> > file(s) known to git
> > make[3]: ***
> [/root/ltp-new/testcases/kernel/syzkaller-repros/Makefile:26:
> > /root/ltp-new/testcases/linux-arts/syzkaller-repros/linux] Error 1
> > make[3]: Leaving directory
> '/root/ltp-new/testcases/kernel/syzkaller-repros'
> > make[2]: *** [../../include/mk/generic_trunk_target.inc:93: all] Error 2
> > make[2]: Leaving directory '/root/ltp-new/testcases/kernel'
> > make[1]: *** [../include/mk/generic_trunk_target.inc:93: all] Error 2
> > make[1]: Leaving directory '/root/ltp-new/testcases'
> > make: *** [Makefile:108: testcases-all] Error 2
> >
> >
>
> What happens if you try to pull the git submodule manually?
>
# pwd
/root/ltp-new

# git submodule update --init testcases/linux-arts
error: pathspec 'testcases/linux-arts' did not match any file(s) known to
git


>
> i.e. do git submodule update --init testcases/linux-arts
>
> It looks like it failed on the line where it gets the submodule, so I am
> wondering if you have an old git version?


Not sure if that related to git-version, I'm trying to look into it.

# git --version
git version 2.23.0

# uname -r
5.3.8-300.fc31.x86_64
Li Wang Nov. 13, 2019, 6:27 a.m. UTC | #5
Hi Richard,

On Tue, Nov 12, 2019 at 10:10 PM Li Wang <liwang@redhat.com> wrote:

>
>
> On Tue, Nov 12, 2019 at 10:00 PM Richard Palethorpe <rpalethorpe@suse.de>
> wrote:
>
>> Hello,
>>
>> Li Wang <liwang@redhat.com> writes:
>>
>> >
>> >
>> > Just to try build it in LTP and hit errors:
>> >
>> > # cd ltp-new/
>> > # make autotools
>> > # ./configure --with-syzkaller-repros
>> > # make -j32
>> > ...
>> > error: pathspec '/root/ltp-new/testcases/linux-arts' did not match any
>> > file(s) known to git
>> > make[3]: ***
>> [/root/ltp-new/testcases/kernel/syzkaller-repros/Makefile:26:
>> > /root/ltp-new/testcases/linux-arts/syzkaller-repros/linux] Error 1
>> > make[3]: Leaving directory
>> '/root/ltp-new/testcases/kernel/syzkaller-repros'
>> > make[2]: *** [../../include/mk/generic_trunk_target.inc:93: all] Error 2
>> > make[2]: Leaving directory '/root/ltp-new/testcases/kernel'
>> > make[1]: *** [../include/mk/generic_trunk_target.inc:93: all] Error 2
>> > make[1]: Leaving directory '/root/ltp-new/testcases'
>> > make: *** [Makefile:108: testcases-all] Error 2
>> >
>> >
>>
>> What happens if you try to pull the git submodule manually?
>>
> # pwd
> /root/ltp-new
>
> # git submodule update --init testcases/linux-arts
> error: pathspec 'testcases/linux-arts' did not match any file(s) known to
> git
>
>
>>
>> i.e. do git submodule update --init testcases/linux-arts
>>
>> It looks like it failed on the line where it gets the submodule, so I am
>> wondering if you have an old git version?
>
>
> Not sure if that related to git-version, I'm trying to look into it.
>

I have tried many times with different systems but still not working.

My question is did you add the submodule via 'git-submodule add' commands?
or just modify the .gitmodules file by hand?

i.e: `git submodule add
https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-arts.git
testcases/linux-arts`

I don't understand why I can't see the subproject commit-id in your patch.
I have to perform git-submodule-add locally again then it could compile for
me.

i.e:
diff --git a/testcases/linux-arts b/testcases/linux-arts
new file mode 160000
index 0000000..07759b8
--- /dev/null
+++ b/testcases/linux-arts
@@ -0,0 +1 @@
+Subproject commit 07759b820a9cbf01333d861d8eb2613b20d1ede4

Or did I missing anything?
Richard Palethorpe Nov. 13, 2019, 9:34 a.m. UTC | #6
Hello,

Li Wang <liwang@redhat.com> writes:

> Hi Richard,
>
> On Tue, Nov 12, 2019 at 10:10 PM Li Wang <liwang@redhat.com> wrote:
>
>>
>>
>> On Tue, Nov 12, 2019 at 10:00 PM Richard Palethorpe <rpalethorpe@suse.de>
>> wrote:
>>
>>> Hello,
>>>
>>> Li Wang <liwang@redhat.com> writes:
>>>
>>> >
>>> >
>>> > Just to try build it in LTP and hit errors:
>>> >
>>> > # cd ltp-new/
>>> > # make autotools
>>> > # ./configure --with-syzkaller-repros
>>> > # make -j32
>>> > ...
>>> > error: pathspec '/root/ltp-new/testcases/linux-arts' did not match any
>>> > file(s) known to git
>>> > make[3]: ***
>>> [/root/ltp-new/testcases/kernel/syzkaller-repros/Makefile:26:
>>> > /root/ltp-new/testcases/linux-arts/syzkaller-repros/linux] Error 1
>>> > make[3]: Leaving directory
>>> '/root/ltp-new/testcases/kernel/syzkaller-repros'
>>> > make[2]: *** [../../include/mk/generic_trunk_target.inc:93: all] Error 2
>>> > make[2]: Leaving directory '/root/ltp-new/testcases/kernel'
>>> > make[1]: *** [../include/mk/generic_trunk_target.inc:93: all] Error 2
>>> > make[1]: Leaving directory '/root/ltp-new/testcases'
>>> > make: *** [Makefile:108: testcases-all] Error 2
>>> >
>>> >
>>>
>>> What happens if you try to pull the git submodule manually?
>>>
>> # pwd
>> /root/ltp-new
>>
>> # git submodule update --init testcases/linux-arts
>> error: pathspec 'testcases/linux-arts' did not match any file(s) known to
>> git
>>
>>
>>>
>>> i.e. do git submodule update --init testcases/linux-arts
>>>
>>> It looks like it failed on the line where it gets the submodule, so I am
>>> wondering if you have an old git version?
>>
>>
>> Not sure if that related to git-version, I'm trying to look into it.
>>
>
> I have tried many times with different systems but still not working.
>
> My question is did you add the submodule via 'git-submodule add' commands?
> or just modify the .gitmodules file by hand?
>
> i.e: `git submodule add
> https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-arts.git
> testcases/linux-arts`
>
> I don't understand why I can't see the subproject commit-id in your patch.
> I have to perform git-submodule-add locally again then it could compile for
> me.
>
> i.e:
> diff --git a/testcases/linux-arts b/testcases/linux-arts
> new file mode 160000
> index 0000000..07759b8
> --- /dev/null
> +++ b/testcases/linux-arts
> @@ -0,0 +1 @@
> +Subproject commit 07759b820a9cbf01333d861d8eb2613b20d1ede4
>
> Or did I missing anything?

Sorry, I think it is probably my fault. I added the submodule properly,
but I set 'ignore = all' to .gitmodules which prevents the commit-id
from being added to the patchset.

I set ignore=all because I thought it would probably be best to always
get the HEAD of linux-arts, at least to begin with. Otherwise we have to
remember to update it.

--
Thank you,
Richard.
Li Wang Nov. 26, 2019, 8:18 a.m. UTC | #7
Hi Richard,

Some more queries below.

On Thu, Nov 7, 2019 at 11:36 PM Richard Palethorpe <rpalethorpe@suse.com>
wrote:

> Allows one to run the Syzkaller reproducers as part of the LTP.
>
> ...
>
> +AC_ARG_WITH([syzkaller-repros],
> +  [AC_HELP_STRING([--with-syzkaller-repros],
> +    [compile and install Syzkaller reproducers (default=no)])],
> +  [with_syzkaller_repros=$withval]
>

To strictly, the [action-if-not-given] should be added too?


> +)
> +if test "x$with_syzkaller_repros" = xyes; then
> +    AC_SUBST([WITH_SYZKALLER_REPROS],["yes"])
> +else
> +    AC_SUBST([WITH_SYZKALLER_REPROS],["no"])
> +fi
> ...
> diff --git a/runtest/.gitignore b/runtest/.gitignore
> new file mode 100644
> index 000000000..2ae05bfac
> --- /dev/null
> +++ b/runtest/.gitignore
> @@ -0,0 +1 @@
> +syzkaller*
>

Why adding syzkaller* in here?


> diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile
> index 3319b3163..0150cfb4f 100644
> --- a/testcases/kernel/Makefile
> +++ b/testcases/kernel/Makefile
> @@ -53,6 +53,7 @@ SUBDIRS                       += connectors \
>                            sched \
>                            security \
>                            sound \
> +                          syzkaller-repros \
>                            tracing \
>                            uevents \
>
> diff --git a/testcases/kernel/syzkaller-repros/.gitignore
> b/testcases/kernel/syzkaller-repros/.gitignore
> new file mode 100644
> index 000000000..dbda1c71f
> --- /dev/null
> +++ b/testcases/kernel/syzkaller-repros/.gitignore
> @@ -0,0 +1 @@
> +syzwrap
> diff --git a/testcases/kernel/syzkaller-repros/Makefile
> b/testcases/kernel/syzkaller-repros/Makefile
> new file mode 100644
> ...
> +# Some useful compiler flags for the LTP will cause problems with the
> +# syzkaller repros so the repros have seperate flags
> +SYZKALLER_CFLAGS ?= -pthread
> +SYZKALLER_REPROS = $(subst
> $(abs_top_srcdir),$(abs_top_builddir),$(SYZKALLER_REPROS_SRCS:.c=))
> +$(SYZKALLER_REPROS): %: %.c
> +       -@if grep -q "__NR_mmap2" $^; then \
> +               M32="-m32"; \
>

I got compiling errors on s390x:
  gcc: error: unrecognized command line option ‘-m32’; did you mean ‘-m31’?

My other concern is syzkaller (I guess maybe) have some package
dependencies, and that will break the compiler phase on the embedded system.


> ....
> +       while (!waitpid(pid, &status, WNOHANG)) {
> +               rem = tst_timeout_remaining();
> +
> +               if (!sent_kill && rem / exec_time_start < 0.5) {
> +                       tst_res(TINFO, "Timeout; killing reproducer");
> +
> +                       TEST(kill(pid, SIGKILL));
> +                       if (TST_RET == -1)
> +                               tst_res(TWARN | TTERRNO, "kill() failed");
> +                       else
> +                               sent_kill = 1;
> +               }
> +
> +               usleep(backoff);
> +               backoff = MIN(2 * backoff, 1000000);
> +       }
>

Force to kill a timeout test process is fine, but one thing makes me
worried is that we don't do any cleanup work(e.g. release hugepage, devices
or other resources) for the children, that very probably causes many
additional issues in the next testing and not easy to reproduce it in a new
run.


> +
> +       if (tst_taint_check()) {
> +               tst_res(TFAIL, "Kernel is tainted");
> +       } else {
> +               tst_res(TPASS, "Kernel is not tainted");
> +       }


If this is the only condition to judge if all tests pass or not, we may
miss some test failure logs after running, unless we don't care about that.

Btw, I can't even finish one round for the test then system panic there.
Richard Palethorpe Nov. 26, 2019, 10:32 a.m. UTC | #8
Hello,

Li Wang <liwang@redhat.com> writes:

> Hi Richard,
>
> Some more queries below.
>
> On Thu, Nov 7, 2019 at 11:36 PM Richard Palethorpe <rpalethorpe@suse.com>
> wrote:
>
>> Allows one to run the Syzkaller reproducers as part of the LTP.
>>
>> ...
>>
>> +AC_ARG_WITH([syzkaller-repros],
>> +  [AC_HELP_STRING([--with-syzkaller-repros],
>> +    [compile and install Syzkaller reproducers (default=no)])],
>> +  [with_syzkaller_repros=$withval]
>>
>
> To strictly, the [action-if-not-given] should be added too?

Were the other 'with' options updated recently to have that? I just
copied this from the other options.

>
>
>> +)
>> +if test "x$with_syzkaller_repros" = xyes; then
>> +    AC_SUBST([WITH_SYZKALLER_REPROS],["yes"])
>> +else
>> +    AC_SUBST([WITH_SYZKALLER_REPROS],["no"])
>> +fi
>> ...
>> diff --git a/runtest/.gitignore b/runtest/.gitignore
>> new file mode 100644
>> index 000000000..2ae05bfac
>> --- /dev/null
>> +++ b/runtest/.gitignore
>> @@ -0,0 +1 @@
>> +syzkaller*
>>
>
> Why adding syzkaller* in here?

The runtest files are automatically generated.

>
>
>> diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile
>> index 3319b3163..0150cfb4f 100644
>> --- a/testcases/kernel/Makefile
>> +++ b/testcases/kernel/Makefile
>> @@ -53,6 +53,7 @@ SUBDIRS                       += connectors \
>>                            sched \
>>                            security \
>>                            sound \
>> +                          syzkaller-repros \
>>                            tracing \
>>                            uevents \
>>
>> diff --git a/testcases/kernel/syzkaller-repros/.gitignore
>> b/testcases/kernel/syzkaller-repros/.gitignore
>> new file mode 100644
>> index 000000000..dbda1c71f
>> --- /dev/null
>> +++ b/testcases/kernel/syzkaller-repros/.gitignore
>> @@ -0,0 +1 @@
>> +syzwrap
>> diff --git a/testcases/kernel/syzkaller-repros/Makefile
>> b/testcases/kernel/syzkaller-repros/Makefile
>> new file mode 100644
>> ...
>> +# Some useful compiler flags for the LTP will cause problems with the
>> +# syzkaller repros so the repros have seperate flags
>> +SYZKALLER_CFLAGS ?= -pthread
>> +SYZKALLER_REPROS = $(subst
>> $(abs_top_srcdir),$(abs_top_builddir),$(SYZKALLER_REPROS_SRCS:.c=))
>> +$(SYZKALLER_REPROS): %: %.c
>> +       -@if grep -q "__NR_mmap2" $^; then \
>> +               M32="-m32"; \
>>
>
> I got compiling errors on s390x:
>   gcc: error: unrecognized command line option ‘-m32’; did you mean
> ‘-m31’?

I have only tried these on x86_64 so far and I think that is all we can
support to begin with.

>
> My other concern is syzkaller (I guess maybe) have some package
> dependencies, and that will break the compiler phase on the embedded
> system.

This is true, the reproducers do have dependencies and it seems to vary
(randomly view some of the C files). However this is one of the reasons
why they are only installed if --with-syzkaller-repros is set.

>
>
>> ....
>> +       while (!waitpid(pid, &status, WNOHANG)) {
>> +               rem = tst_timeout_remaining();
>> +
>> +               if (!sent_kill && rem / exec_time_start < 0.5) {
>> +                       tst_res(TINFO, "Timeout; killing reproducer");
>> +
>> +                       TEST(kill(pid, SIGKILL));
>> +                       if (TST_RET == -1)
>> +                               tst_res(TWARN | TTERRNO, "kill() failed");
>> +                       else
>> +                               sent_kill = 1;
>> +               }
>> +
>> +               usleep(backoff);
>> +               backoff = MIN(2 * backoff, 1000000);
>> +       }
>>
>
> Force to kill a timeout test process is fine, but one thing makes me
> worried is that we don't do any cleanup work(e.g. release hugepage, devices
> or other resources) for the children, that very probably causes many
> additional issues in the next testing and not easy to reproduce it in a new
> run.

The reproducer itself should clear up some of this. It is also possible
to regenerate the reproducers with more sandboxing AFAICT. However the
sandboxing itself has some requirements.

I don't know how we could possibly cleanup after every reproducer,
except by taking a complete snapshot of the system and reverting to
it. Which is what I recommend doing in the README.

This is another reason for the --with-syzkaller-repros flag. The test
runner must do extra work compared to normal LTP tests. I'm also not
sure it would be safe to run these on baremetal unless you regenerate
them with the extra sandboxing.

>
>
>> +
>> +       if (tst_taint_check()) {
>> +               tst_res(TFAIL, "Kernel is tainted");
>> +       } else {
>> +               tst_res(TPASS, "Kernel is not tainted");
>> +       }
>
>
> If this is the only condition to judge if all tests pass or not, we may
> miss some test failure logs after running, unless we don't care about
> that.

They produce a lot of output, some of it might be useful for returning
TCONF (like when sandboxing is enabled in syzwrap and this stops network
devices from being created). However I think it is more important to
provide some basic functionality than work on stuff like this.

>
> Btw, I can't even finish one round for the test then system panic there.

Same. There are a lot of reproducers for unsolved bugs, plus some of
them probably shouldn't be run as root without the extra sandboxing. So
they will crash the system just by randomly deleting or overwriting
stuff.

--
Thank you,
Richard.
Petr Vorel Nov. 26, 2019, 12:42 p.m. UTC | #9
Hi,

> >> +AC_ARG_WITH([syzkaller-repros],
> >> +  [AC_HELP_STRING([--with-syzkaller-repros],
> >> +    [compile and install Syzkaller reproducers (default=no)])],
> >> +  [with_syzkaller_repros=$withval]


> > To strictly, the [action-if-not-given] should be added too?

> Were the other 'with' options updated recently to have that? I just
> copied this from the other options.
Yep, you'll just add
[with_syzkaller_repros=no]
(looking at the default off, probably safer for the start)

> >> diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile
> >> index 3319b3163..0150cfb4f 100644
> >> --- a/testcases/kernel/Makefile
> >> +++ b/testcases/kernel/Makefile
> >> @@ -53,6 +53,7 @@ SUBDIRS                       += connectors \
> >>                            sched \
> >>                            security \
> >>                            sound \
> >> +                          syzkaller-repros \
> >>                            tracing \
> >>                            uevents \

> >> +# Some useful compiler flags for the LTP will cause problems with the
> >> +# syzkaller repros so the repros have seperate flags
> >> +SYZKALLER_CFLAGS ?= -pthread
> >> +SYZKALLER_REPROS = $(subst
> >> $(abs_top_srcdir),$(abs_top_builddir),$(SYZKALLER_REPROS_SRCS:.c=))
> >> +$(SYZKALLER_REPROS): %: %.c
> >> +       -@if grep -q "__NR_mmap2" $^; then \
> >> +               M32="-m32"; \


> > I got compiling errors on s390x:
> >   gcc: error: unrecognized command line option ‘-m32’; did you mean
> > ‘-m31’?

> I have only tried these on x86_64 so far and I think that is all we can
> support to begin with.

Maybe filter it out in testcases/kernel/Makefile with something like this:
ifneq (,$(filter $(HOST_CPU),x86 x86_64))
FILTER_OUT_DIRS += syzkaller-repros
endif

> > My other concern is syzkaller (I guess maybe) have some package
> > dependencies, and that will break the compiler phase on the embedded
> > system.

> This is true, the reproducers do have dependencies and it seems to vary
> (randomly view some of the C files). However this is one of the reasons
> why they are only installed if --with-syzkaller-repros is set.
Maybe later we manage to generate autotools config based on pkg-config.

Kind regards,
Petr
Petr Vorel Nov. 26, 2019, 12:59 p.m. UTC | #10
Hi,

...
> +++ b/testcases/kernel/syzkaller-repros/Makefile
...
> +# If the reproducers directory is missing then we automatically clone the repo.
> +# We then have to call make recursively to revaluate the targets
> +SYZKALLER_REPROS_DIR ?= $(abs_top_srcdir)/testcases/linux-arts/syzkaller-repros/linux
> +$(SYZKALLER_REPROS_DIR):
> +	git submodule update --init $(abs_top_srcdir)/testcases/linux-arts
Hm, that does not get submodule code.
Reproduced locally and also on travis:
https://travis-ci.org/pevik/ltp/builds/617186693

https://api.travis-ci.org/v3/job/617186701/log.txt
fatal: Not a git repository (or any of the parent directories): .git

or

https://api.travis-ci.org/v3/job/617186700/log.txt
error: pathspec '/usr/src/ltp/testcases/linux-arts' did not match any file(s) known to git

Maybe it's due the fact I already run locally (and the same did travis):
git submodule update --init --recursive

Kind regards,
Petr
diff mbox series

Patch

diff --git a/.gitmodules b/.gitmodules
index 1c9e9c38a..6a2d31f51 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,8 @@ 
 [submodule "testcases/kernel/mce-test"]
 	path = testcases/kernel/mce-test
 	url = git://git.kernel.org/pub/scm/linux/kernel/git/gong.chen/mce-test.git
+[submodule "testcases/linux-arts"]
+	path = testcases/linux-arts
+	url = https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-arts.git
+	shallow = true
+	ignore = all
diff --git a/configure.ac b/configure.ac
index 3785dff63..ec4cae483 100644
--- a/configure.ac
+++ b/configure.ac
@@ -184,6 +184,17 @@  else
     AC_SUBST([WITH_OPEN_POSIX_TESTSUITE],["no"])
 fi
 
+AC_ARG_WITH([syzkaller-repros],
+  [AC_HELP_STRING([--with-syzkaller-repros],
+    [compile and install Syzkaller reproducers (default=no)])],
+  [with_syzkaller_repros=$withval]
+)
+if test "x$with_syzkaller_repros" = xyes; then
+    AC_SUBST([WITH_SYZKALLER_REPROS],["yes"])
+else
+    AC_SUBST([WITH_SYZKALLER_REPROS],["no"])
+fi
+
 # testcases/realtime requires bash and python.
 if test "x$with_bash" = xyes && test "x$with_python" = xyes; then
     AC_ARG_WITH([realtime-testsuite],
diff --git a/include/mk/features.mk.default b/include/mk/features.mk.default
index 3a6cc5176..71fb48c60 100644
--- a/include/mk/features.mk.default
+++ b/include/mk/features.mk.default
@@ -47,3 +47,5 @@  WITH_REALTIME_TESTSUITE		:= no
 else
 WITH_REALTIME_TESTSUITE		:= no
 endif
+
+WITH_SYZKALLER_REPROS		:= no
diff --git a/include/mk/features.mk.in b/include/mk/features.mk.in
index 8e561b738..3ab7f4721 100644
--- a/include/mk/features.mk.in
+++ b/include/mk/features.mk.in
@@ -47,3 +47,5 @@  WITH_REALTIME_TESTSUITE		:= no
 else
 WITH_REALTIME_TESTSUITE		:= @WITH_REALTIME_TESTSUITE@
 endif
+
+WITH_SYZKALLER_REPROS		:= @WITH_SYZKALLER_REPROS@
diff --git a/runtest/.gitignore b/runtest/.gitignore
new file mode 100644
index 000000000..2ae05bfac
--- /dev/null
+++ b/runtest/.gitignore
@@ -0,0 +1 @@ 
+syzkaller*
diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile
index 3319b3163..0150cfb4f 100644
--- a/testcases/kernel/Makefile
+++ b/testcases/kernel/Makefile
@@ -53,6 +53,7 @@  SUBDIRS			+= connectors \
 			   sched \
 			   security \
 			   sound \
+			   syzkaller-repros \
 			   tracing \
 			   uevents \
 
diff --git a/testcases/kernel/syzkaller-repros/.gitignore b/testcases/kernel/syzkaller-repros/.gitignore
new file mode 100644
index 000000000..dbda1c71f
--- /dev/null
+++ b/testcases/kernel/syzkaller-repros/.gitignore
@@ -0,0 +1 @@ 
+syzwrap
diff --git a/testcases/kernel/syzkaller-repros/Makefile b/testcases/kernel/syzkaller-repros/Makefile
new file mode 100644
index 000000000..d40d61ac1
--- /dev/null
+++ b/testcases/kernel/syzkaller-repros/Makefile
@@ -0,0 +1,100 @@ 
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2019 Linux Test Project
+
+top_srcdir		?= ../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+CFLAGS			+= -D_GNU_SOURCE
+
+ifeq ($(WITH_SYZKALLER_REPROS),yes)
+
+# The number of reproducers in each runtest file
+SYZKALLER_RUNFILES_SIZE ?= 100
+
+# Extra arguments to pass to syzwrap. Uncomment the below to add some
+# sandboxing.
+# SYZWRAP_ARGS ?= -s
+
+# Location where reproducers are installed
+SYZKALLER_INSTALL_DIR ?= $(abspath $(DESTDIR)/$(prefix)/testcases/bin)
+
+# If the reproducers directory is missing then we automatically clone the repo.
+# We then have to call make recursively to revaluate the targets
+SYZKALLER_REPROS_DIR ?= $(abs_top_srcdir)/testcases/linux-arts/syzkaller-repros/linux
+$(SYZKALLER_REPROS_DIR):
+	git submodule update --init $(abs_top_srcdir)/testcases/linux-arts
+	$(MAKE) syzkaller_runfiles
+
+SYZKALLER_REPROS_SRCS = $(wildcard $(SYZKALLER_REPROS_DIR)/*.c)
+
+# Some useful compiler flags for the LTP will cause problems with the
+# syzkaller repros so the repros have seperate flags
+SYZKALLER_CFLAGS ?= -pthread
+SYZKALLER_REPROS = $(subst $(abs_top_srcdir),$(abs_top_builddir),$(SYZKALLER_REPROS_SRCS:.c=))
+$(SYZKALLER_REPROS): %: %.c
+	-@if grep -q "__NR_mmap2" $^; then \
+		M32="-m32"; \
+	fi; \
+	$(CC) $(SYZKALLER_CFLAGS) $$M32 $(SYZKALLER_LDFLAGS) $^ -o $@; \
+	echo $(CC) $(SYZKALLER_CFLAGS) $$M32 $(SYZKALLER_LDFLAGS) $^ -o $@;
+
+# Generate the names of the runtest files. This uses Shell arithmetic to
+# calculate how many runtest files there will be.
+define SYZKALLER_RUNFILES !=
+	n=$(words $(SYZKALLER_REPROS));
+	m=$(SYZKALLER_RUNFILES_SIZE);
+	i=$$(( $$n / $$m + ($$n % $$m > 0) ));
+	while test $$i -gt 0;
+	do
+		echo $(top_srcdir)/runtest/syzkaller$$i;
+		i=$$(($$i - 1));
+	done
+endef
+
+# Get the index part of a runtest files name
+syz_n = $(subst $(top_srcdir)/runtest/syzkaller,,$(1))
+syz_m = $(SYZKALLER_RUNFILES_SIZE)
+# Gives the index of the first reproducer in a runtest file
+syz_i = $(shell echo $$((($(call syz_n,$(1)) - 1) * $(2) + 1)))
+# Gives the index of the last reproducer in a runtest file
+syz_j = $(shell echo $$(( $(call syz_i,$(1),$(2)) + $(2) - 1 )))
+# Gvien a runtest file name, get the reproducers it should contain
+syz_wordlist = $(wordlist $(call syz_i,$(1),$(syz_m)),$(call syz_j,$(1),$(syz_m)),$(SYZKALLER_REPROS))
+
+define syz_runfile_line
+$(notdir $(exe)) syzwrap $(SYZWRAP_ARGS) -d $(SYZKALLER_INSTALL_DIR) -n $(notdir $(exe))
+
+endef
+
+# Generate the runtest files based on the reproducer names and batch size.
+$(SYZKALLER_RUNFILES): $(SYZKALLER_REPROS)
+	@echo "Writing $@"
+	$(file >$@)
+	$(foreach exe,$(call syz_wordlist,$@),$(file >>$@,$(syz_runfile_line)))
+
+.PHONY: syzkaller_runfiles
+syzkaller_runfiles: $(SYZKALLER_RUNFILES) | $(SYZKALLER_REPROS_DIR)
+
+all: $(SYZKALLER_RUNFILES) | $(SYZKALLER_REPROS_DIR)
+
+# There are too many reproducers to pass all at once to rm, so we just pass
+# one at a time
+syzkaller_clean:
+	$(foreach f, $(SYZKALLER_REPROS), $(RM) $(f))
+CLEAN_DEPS += syzkaller_clean
+CLEAN_TARGETS += $(SYZKALLER_RUNFILES)
+
+INSTALL_MODE ?= 0775
+
+# For some reason part of the path is missing if we just try to install these
+# by adding them to INSTALL_FILES
+SYZKALLER_REPROS_INSTALLED := $(subst $(SYZKALLER_REPROS_DIR),$(SYZKALLER_INSTALL_DIR),$(SYZKALLER_REPROS))
+$(SYZKALLER_REPROS_INSTALLED): $(SYZKALLER_INSTALL_DIR)/%: $(SYZKALLER_REPROS_DIR)/%
+	install -m $(INSTALL_MODE) -T $< $@
+
+install: $(SYZKALLER_REPROS_INSTALLED)
+
+endif
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/syzkaller-repros/README.md b/testcases/kernel/syzkaller-repros/README.md
new file mode 100644
index 000000000..2c88efd01
--- /dev/null
+++ b/testcases/kernel/syzkaller-repros/README.md
@@ -0,0 +1,45 @@ 
+# LTP wrapper for Syzkaller reproducers
+
+This allows you to run the autogenerated C bug reproducers from the Syzkaller
+fuzzer within the LTP framework. Meaning that you may use an existing test
+runner compatible with the LTP (with some constraints, see below).
+
+## Instructions
+
+1. Run `ltp/configure` with `--with-syzkaller-repros`.
+2. Build and install the LTP as normal.
+3. Run one or more of syzkallerN runtest files where N is a number.
+
+Make will automatically download the reproducers into `testcases/linux-arts`
+using git-submodule if necessary.
+
+By default each runtest file contains 100 reproducers. You may change this by
+overriding `SYZKALLER_RUNFILES_SIZE`.
+
+Extra parameters can be sent to syzwrap using `SYZWRAP_ARGS`. See `syzwrap
+-h`.
+
+## Kernel Requirements
+
+It is strongly recommended that you use KASAN and other debugging kernel
+features. See the Syzkaller documentation for the configuration you should
+use.
+
+## Test Runner Requirements
+
+Unlike most LTP tests these reproducers can leave your system in a broken
+state even if no bug is triggered.
+
+You will need to:
+
+A) Reboot the SUT
+B) Reset at least the root filesystem to a known good state
+
+Every time syzwrap fails. 
+
+If syzwrap fails with TBROK or fails to run at all, then you probably need to
+reset the system and rerun that test. If a test fails with TFAIL, you may also
+want to run it once again with a clean state.
+
+It might be the case that some reproducers write to random devices or do other
+things which can effect the outside world.
diff --git a/testcases/kernel/syzkaller-repros/syzwrap.c b/testcases/kernel/syzkaller-repros/syzwrap.c
new file mode 100644
index 000000000..9f5d16078
--- /dev/null
+++ b/testcases/kernel/syzkaller-repros/syzwrap.c
@@ -0,0 +1,133 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Richard Palethorpe <rpalethorpe@suse.com>
+ *
+ * Run a single reproducer generated by the Syzkaller fuzzer.
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/prctl.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdio.h>
+#include <pwd.h>
+
+#include "tst_test.h"
+#include "tst_taint.h"
+#include "tst_safe_stdio.h"
+
+#define SANDBOX_HELP "\n"\
+	"-s\t Add some sandboxing around the reproducer. This will prevent some\n"\
+	"\t reproducers from creating network devices and thus prevent them from\n"\
+	"\t working. However it will also prevent some reproducers from trashing\n"\
+	"\t the system using root privileges. Note that you may generate the\n"\
+	"\t reproducers with various types of sandboxing built in using\n"\
+	"\t syz-reprolist"
+
+static char *dir;
+static char *name;
+static char *path;
+
+static char *sandbox;
+
+static struct tst_option options[] = {
+	{"d:", &dir, "\n-d PATH\t Mandatory directory containing reproducers"},
+	{"n:", &name, "-n NAME\t Mandatory executable name of reproducer"},
+	{"s", &sandbox, SANDBOX_HELP},
+	{NULL, NULL, NULL}
+};
+
+static void become_nobody(void)
+{
+	struct passwd *pw;
+	int gid, uid;
+
+	setgroups(0, NULL);
+
+	pw = getpwnam("nobody");
+	if (pw) {
+		gid = pw->pw_gid;
+		uid = pw->pw_uid;
+	} else {
+		gid = 65534;
+		uid = 65534;
+	}
+
+	SAFE_SETREGID(gid, gid);
+	SAFE_SETREUID(uid, uid);
+}
+
+static void setup(void)
+{
+	tst_taint_init(TST_TAINT_W | TST_TAINT_D | TST_TAINT_L);
+
+	if (!dir)
+		tst_brk(TBROK, "No reproducer directory specified");
+
+	if (!name)
+		tst_brk(TBROK, "No reproducer name specified");
+
+	tst_res(TINFO, "https://syzkaller.appspot.com/bug?id=%s", name);
+
+	SAFE_ASPRINTF(&path, "%s/%s", dir, name);
+	tst_res(TINFO, "%s", path);
+}
+
+static void run(void)
+{
+	unsigned int backoff = 100;
+	int rem, status, sent_kill = 0;
+	float exec_time_start = (float)tst_timeout_remaining();
+	int pid;
+
+	if (sandbox)
+		SAFE_UNSHARE(CLONE_NEWPID);
+
+	pid = SAFE_FORK();
+	if (!pid) {
+		if (sandbox) {
+			SAFE_UNSHARE(CLONE_NEWNET);
+			become_nobody();
+		}
+
+		if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)) {
+			tst_res(TWARN | TERRNO,
+				"Failed to set dumpable; won't be able to open /proc/self/*");
+		}
+
+		execl(path, name, NULL);
+		tst_brk(TBROK | TERRNO, "Failed to exec reproducer");
+	}
+
+	while (!waitpid(pid, &status, WNOHANG)) {
+		rem = tst_timeout_remaining();
+
+		if (!sent_kill && rem / exec_time_start < 0.5) {
+			tst_res(TINFO, "Timeout; killing reproducer");
+
+			TEST(kill(pid, SIGKILL));
+			if (TST_RET == -1)
+				tst_res(TWARN | TTERRNO, "kill() failed");
+			else
+				sent_kill = 1;
+		}
+
+		usleep(backoff);
+		backoff = MIN(2 * backoff, 1000000);
+	}
+
+	if (tst_taint_check()) {
+		tst_res(TFAIL, "Kernel is tainted");
+	} else {
+		tst_res(TPASS, "Kernel is not tainted");
+	}
+}
+
+static struct tst_test test = {
+	.setup = setup,
+	.test_all = run,
+	.options = options,
+	.needs_tmpdir = 1,
+	.forks_child = 1
+};