plugins: Wire up rust plugin support for NBD_INFO_INIT_STATE
[nbdkit/ericb.git] / server / fuzzer.c
blob94078904db320c4719ca9d62e6783a6f8bb8afb5
1 /* nbdkit
2 * Copyright (C) 2013-2019 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 "internal.h"
48 #ifndef ENABLE_LIBFUZZER
49 #error "This file should only be compiled when libFuzzer is enabled"
50 #endif
52 /* When we're compiled with --enable-libfuzzer, the normal main()
53 * function is renamed to fuzzer_main. We call it with particular
54 * parameters to make it use the memory plugin.
56 extern int fuzzer_main (int argc, char *argv[]);
58 static void server (int sock);
59 static void client (const uint8_t *data, size_t size, int sock);
61 /* This is the entry point called by libFuzzer. */
62 int
63 LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
65 pid_t pid;
66 int sv[2], r, status;
68 /* Create a connected socket. */
69 if (socketpair (AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sv) == -1) {
70 perror ("socketpair");
71 exit (EXIT_FAILURE);
74 /* Fork: The parent will be the nbdkit process (server). The child
75 * will be the phony NBD client.
77 pid = fork ();
78 if (pid == -1) {
79 perror ("fork");
80 exit (EXIT_FAILURE);
83 if (pid > 0) {
84 /* Parent: nbdkit server. */
85 close (sv[1]);
87 server (sv[0]);
89 close (sv[0]);
91 again:
92 r = wait (&status);
93 if (r == -1) {
94 if (errno == EINTR)
95 goto again;
96 perror ("wait");
97 exit (EXIT_FAILURE);
99 if (!WIFEXITED (status) || WEXITSTATUS (status) != 0)
100 fprintf (stderr, "bad exit status %d\n", status);
102 return 0;
105 /* Child: phony NBD client. */
106 close (sv[0]);
108 client (data, size, sv[1]);
110 close (sv[1]);
112 _exit (EXIT_SUCCESS);
115 static void
116 server (int sock)
118 char *argv[] = {
119 "nbdkit",
120 "-s", /* take input from stdin/stdout */
121 "--log=null", /* discard error messages */
122 "plugins/memory/.libs/nbdkit-memory-plugin.so", "1M",
123 NULL
125 const int argc = sizeof argv / sizeof argv[0] - 1;
126 int saved_stdin, saved_stdout;
128 /* Make the socket appear as stdin and stdout of the process, saving
129 * the existing stdin/stdout.
131 saved_stdin = dup (0);
132 saved_stdout = dup (1);
133 dup2 (sock, 0);
134 dup2 (sock, 1);
136 /* Call nbdkit's normal main() function. */
137 fuzzer_main (argc, argv);
139 /* Restore stdin/stdout. */
140 dup2 (saved_stdin, 0);
141 dup2 (saved_stdout, 1);
142 close (saved_stdin);
143 close (saved_stdout);
146 static void
147 client (const uint8_t *data, size_t size, int sock)
149 struct pollfd pfds[1];
150 char rbuf[512];
151 ssize_t r;
153 if (size == 0)
154 shutdown (sock, SHUT_WR);
156 for (;;) {
157 pfds[0].fd = sock;
158 pfds[0].events = POLLIN;
159 if (size > 0) pfds[0].events |= POLLOUT;
160 pfds[0].revents = 0;
162 if (poll (pfds, 1, -1) == -1) {
163 if (errno == EINTR)
164 continue;
165 perror ("poll");
166 /* This is not an error. */
167 return;
170 /* We can read from the server socket. Just throw away anything sent. */
171 if ((pfds[0].revents & POLLIN) != 0) {
172 r = read (sock, rbuf, sizeof rbuf);
173 if (r == -1 && errno != EINTR) {
174 //perror ("read");
175 return;
177 else if (r == 0) /* end of input from the server */
178 return;
181 /* We can write to the server socket. */
182 if ((pfds[0].revents & POLLOUT) != 0) {
183 if (size > 0) {
184 r = write (sock, data, size);
185 if (r == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
186 perror ("write");
187 return;
189 else if (r > 0) {
190 data += r;
191 size -= r;
193 if (size == 0)
194 shutdown (sock, SHUT_WR);
198 } /* for (;;) */