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