From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by passt.top (Postfix) with ESMTP id 2B3275A026A for ; Thu, 17 Nov 2022 13:26:25 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668687984; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=C/ZaznXo2uuGKuzIIMcgRlNU37yd0iN+JV/irti6Utg=; b=b2dyV8lRqzwUwRgzr+hHHSink/KqkzKbgvbcodpHf5oePefkSWAnRMeXa3NJWbJ/2wV24m hS+SwsBYWtoWx0u988rAVVjwrT+cSdVeR9PvnZU31LJVcpLkETuwKXYtPh4dPQ/L2bwvga sDkIqLfEjHv99j8QW5DNkko098MO4B8= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-335-pTQ7r6BwOB6ONlBErzIdJA-1; Thu, 17 Nov 2022 07:26:22 -0500 X-MC-Unique: pTQ7r6BwOB6ONlBErzIdJA-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.rdu2.redhat.com [10.11.54.8]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 47EE32999B51 for ; Thu, 17 Nov 2022 12:26:22 +0000 (UTC) Received: from pick.home.annexia.org (unknown [10.39.193.198]) by smtp.corp.redhat.com (Postfix) with ESMTP id CA00AC158CF; Thu, 17 Nov 2022 12:26:21 +0000 (UTC) From: "Richard W.M. Jones" To: sbrivio@redhat.com Subject: [PATCH passt 5/5] Import fuzzing wrapper from libnbd Date: Thu, 17 Nov 2022 12:26:14 +0000 Message-Id: <20221117122614.1269214-6-rjones@redhat.com> In-Reply-To: <20221117122614.1269214-1-rjones@redhat.com> References: <20221117122614.1269214-1-rjones@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.8 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="US-ASCII"; x-default=true X-MailFrom: rjones@redhat.com X-Mailman-Rule-Hits: nonmember-moderation X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation Message-ID-Hash: DXP3NGRVYRCOLNIFWC3MB3JHFD5EPE3Z X-Message-ID-Hash: DXP3NGRVYRCOLNIFWC3MB3JHFD5EPE3Z X-Mailman-Approved-At: Thu, 17 Nov 2022 13:28:25 +0100 CC: passt-dev@passt.top X-Mailman-Version: 3.3.3 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: And adjust it so it can be used to fuzz passt. Follow the instructions in README.fuzzing.md Signed-off-by: Richard W.M. Jones --- .gitignore | 2 + fuzzing/Makefile | 15 +++ fuzzing/README.fuzzing.md | 36 +++++++ fuzzing/fuzz-wrapper.c | 173 +++++++++++++++++++++++++++++++++ fuzzing/testcase_dir/empty_tap | Bin 0 -> 4 bytes 5 files changed, 226 insertions(+) diff --git a/.gitignore b/.gitignore index d3d0e2c..2d001da 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ *~ +/fuzzing/fuzz-wrapper +/fuzzing/sync_dir /passt /passt.avx2 /pasta diff --git a/fuzzing/Makefile b/fuzzing/Makefile new file mode 100644 index 0000000..ae5ecd8 --- /dev/null +++ b/fuzzing/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio +# Author: Richard W.M. Jones + +all: fuzz-wrapper + +CFLAGS := -g -O2 + +fuzz-wrapper: fuzz-wrapper.c + $(CC) $(FLAGS) $(CFLAGS) $^ -o $@ $(LDFLAGS) + +.PHONY: clean +clean: + rm -f fuzz-wrapper *~ *.o diff --git a/fuzzing/README.fuzzing.md b/fuzzing/README.fuzzing.md new file mode 100644 index 0000000..4d86b2f --- /dev/null +++ b/fuzzing/README.fuzzing.md @@ -0,0 +1,36 @@ +## Fuzzing with AFL++ (https://aflplus.plus/) + +1. In the top directory rebuild passt with AFL instrumentation, Clang + and ASAN: + +``` +make clean +AFL_USE_ASAN=1 make CC=/usr/bin/afl-clang-lto passt +``` + +2. In the fuzzing/ subdirectory, build the fuzzing wrapper *without* + instrumentation: + +``` +make fuzz-wrapper +``` + +3. Run AFL++ + +Create `fuzzing/sync_dir` and run multiple copies of afl-fuzz. +Usually you should run 1 master (-M) and as many slaves (-S) as you +can. + +Master: + +``` +mkdir -p sync_dir +afl-fuzz -i testcase_dir -o sync_dir -M fuzz01 ./fuzz-wrapper @@ +``` + +Slaves: + +``` +# replace fuzzNN with fuzz02, fuzz03, etc. +afl-fuzz -i testcase_dir -o sync_dir -S fuzzNN ./fuzz-wrapper @@ +``` diff --git a/fuzzing/fuzz-wrapper.c b/fuzzing/fuzz-wrapper.c new file mode 100644 index 0000000..9b5f0d8 --- /dev/null +++ b/fuzzing/fuzz-wrapper.c @@ -0,0 +1,173 @@ +/* Fuzzing wrapper + * Derived from libnbd fuzzing wrapper + * Copyright (C) 2013-2022 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static void passt (int s); +static void qemu (int fd, int s); + +int +main (int argc, char *argv[]) +{ + int fd; + pid_t pid; + int sv[2]; + + if (argc == 2) { + /* Open the test case before we fork so we know the file exists. */ + fd = open (argv[1], O_RDONLY); + if (fd == -1) { + fprintf (stderr, "fuzz-wrapper: "); + perror (argv[1]); + exit (EXIT_FAILURE); + } + } + else { + fprintf (stderr, "fuzz-wrapper testcase\n"); + exit (EXIT_FAILURE); + } + + /* Create a connected socket. */ + if (socketpair (AF_UNIX, SOCK_STREAM, 0, sv) == -1) { + perror ("fuzz-wrapper: socketpair"); + exit (EXIT_FAILURE); + } + + /* Fork: The parent will be the passt process. The child will be + * the phony qemu. + */ + pid = fork (); + if (pid == -1) { + perror ("fuzz-wrapper: fork"); + exit (EXIT_FAILURE); + } + + if (pid > 0) { + /* Parent: passt. */ + close (sv[1]); + close (fd); + + passt (sv[0]); + } + + /* Child: qemu. */ + close (sv[0]); + + qemu (fd, sv[1]); + + close (sv[1]); + + _exit (EXIT_SUCCESS); +} + +/* This is the parent process running passt. */ +static void +passt (int sock) +{ + char sock_str[32]; + + snprintf (sock_str, sizeof sock_str, "%d", sock); + /* XXX Assumes passt is compiled in the top directory: */ + execlp ("../passt", "passt", "-f", "-e", "-1", "--fd", sock_str, NULL); + perror ("fuzz-wrapper: execlp"); + _exit (EXIT_FAILURE); +} + +/* This is the child process acting like qemu. */ +static void +qemu (int fd, int sock) +{ + struct pollfd pfds[1]; + char rbuf[512], wbuf[512]; + size_t wsize = 0; + ssize_t r; + + for (;;) { + pfds[0].fd = sock; + pfds[0].events = POLLIN; + if (wsize > 0 || fd >= 0) pfds[0].events |= POLLOUT; + pfds[0].revents = 0; + + if (poll (pfds, 1, -1) == -1) { + if (errno == EINTR) + continue; + perror ("fuzz-wrapper: poll"); + /* This is not an error. */ + return; + } + + /* We can read from the passt socket. Just throw away anything sent. */ + if ((pfds[0].revents & POLLIN) != 0) { + r = read (sock, rbuf, sizeof rbuf); + if (r == -1 && errno != EINTR) { + perror ("fuzz-wrapper: read"); + return; + } + else if (r == 0) /* end of input from the server */ + return; + } + + /* We can write to the passt socket. */ + if ((pfds[0].revents & POLLOUT) != 0) { + /* Write more data from the wbuf. */ + if (wsize > 0) { + morewrite: + r = write (sock, wbuf, wsize); + if (r == -1 && errno != EAGAIN && errno != EWOULDBLOCK) { + perror ("fuzz-wrapper: write"); + return; + } + else if (r > 0) { + memmove (wbuf, &wbuf[r], wsize-r); + wsize -= r; + } + } + /* Write more data from the file. */ + else if (fd >= 0) { + r = read (fd, wbuf, sizeof wbuf); + if (r == -1) { + perror ("fuzz-wrapper: read"); + _exit (EXIT_FAILURE); + } + else if (r == 0) { + fd = -1; /* ignore the file from now on */ + shutdown (sock, SHUT_WR); + } + else { + wsize = r; + goto morewrite; + } + } + } + } /* for (;;) */ +} diff --git a/fuzzing/testcase_dir/empty_tap b/fuzzing/testcase_dir/empty_tap new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 -- 2.37.0.rc2