Version 1.33.10.
[nbdkit.git] / server / fuzzer.c
blob6c57e0f6893f6e8c0498697a7fd48631d6e463cc
1 /* nbdkit
2 * Copyright (C) 2013-2020 Red Hat Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdint.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <poll.h>
41 #include <errno.h>
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <sys/wait.h>
46 #include "array-size.h"
48 #include "internal.h"
50 #ifndef ENABLE_LIBFUZZER
51 #error "This file should only be compiled when libFuzzer is enabled"
52 #endif
54 /* When we're compiled with --enable-libfuzzer, the normal main()
55 * function is renamed to fuzzer_main. We call it with particular
56 * parameters to make it use the memory plugin.
58 extern int fuzzer_main (int argc, char *argv[]);
60 static void server (int sock);
61 static void client (const uint8_t *data, size_t size, int sock);
63 /* This is the entry point called by libFuzzer. */
64 int
65 LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
67 pid_t pid;
68 int sv[2], r, status;
70 /* Create a connected socket. */
71 if (socketpair (AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sv) == -1) {
72 perror ("socketpair");
73 exit (EXIT_FAILURE);
76 /* Fork: The parent will be the nbdkit process (server). The child
77 * will be the phony NBD client.
79 pid = fork ();
80 if (pid == -1) {
81 perror ("fork");
82 exit (EXIT_FAILURE);
85 if (pid > 0) {
86 /* Parent: nbdkit server. */
87 close (sv[1]);
89 server (sv[0]);
91 close (sv[0]);
93 again:
94 r = wait (&status);
95 if (r == -1) {
96 if (errno == EINTR)
97 goto again;
98 perror ("wait");
99 exit (EXIT_FAILURE);
101 if (!WIFEXITED (status) || WEXITSTATUS (status) != 0)
102 fprintf (stderr, "bad exit status %d\n", status);
104 return 0;
107 /* Child: phony NBD client. */
108 close (sv[0]);
110 client (data, size, sv[1]);
112 close (sv[1]);
114 _exit (EXIT_SUCCESS);
117 static void
118 server (int sock)
120 char *argv[] = {
121 "nbdkit",
122 "-s", /* take input from stdin/stdout */
123 "--log=null", /* discard error messages */
124 "plugins/memory/.libs/nbdkit-memory-plugin." SOEXT, "1M",
125 NULL
127 const int argc = ARRAY_SIZE (argv) - 1;
128 int saved_stdin, saved_stdout;
130 /* Make the socket appear as stdin and stdout of the process, saving
131 * the existing stdin/stdout.
133 saved_stdin = dup (0);
134 saved_stdout = dup (1);
135 dup2 (sock, 0);
136 dup2 (sock, 1);
138 /* Call nbdkit's normal main() function. */
139 fuzzer_main (argc, argv);
141 /* Restore stdin/stdout. */
142 dup2 (saved_stdin, 0);
143 dup2 (saved_stdout, 1);
144 close (saved_stdin);
145 close (saved_stdout);
148 static void
149 client (const uint8_t *data, size_t size, int sock)
151 struct pollfd pfds[1];
152 char rbuf[512];
153 ssize_t r;
155 if (size == 0)
156 shutdown (sock, SHUT_WR);
158 for (;;) {
159 pfds[0].fd = sock;
160 pfds[0].events = POLLIN;
161 if (size > 0) pfds[0].events |= POLLOUT;
162 pfds[0].revents = 0;
164 if (poll (pfds, 1, -1) == -1) {
165 if (errno == EINTR)
166 continue;
167 perror ("poll");
168 /* This is not an error. */
169 return;
172 /* We can read from the server socket. Just throw away anything sent. */
173 if ((pfds[0].revents & POLLIN) != 0) {
174 r = read (sock, rbuf, sizeof rbuf);
175 if (r == -1 && errno != EINTR) {
176 //perror ("read");
177 return;
179 else if (r == 0) /* end of input from the server */
180 return;
183 /* We can write to the server socket. */
184 if ((pfds[0].revents & POLLOUT) != 0) {
185 if (size > 0) {
186 r = write (sock, data, size);
187 if (r == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
188 perror ("write");
189 return;
191 else if (r > 0) {
192 data += r;
193 size -= r;
195 if (size == 0)
196 shutdown (sock, SHUT_WR);
200 } /* for (;;) */