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
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
42 #include <sys/types.h>
43 #include <sys/socket.h>
48 #ifndef ENABLE_LIBFUZZER
49 #error "This file should only be compiled when libFuzzer is enabled"
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. */
63 LLVMFuzzerTestOneInput (const uint8_t *data
, size_t size
)
68 /* Create a connected socket. */
69 if (socketpair (AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
, 0, sv
) == -1) {
70 perror ("socketpair");
74 /* Fork: The parent will be the nbdkit process (server). The child
75 * will be the phony NBD client.
84 /* Parent: nbdkit server. */
99 if (!WIFEXITED (status
) || WEXITSTATUS (status
) != 0)
100 fprintf (stderr
, "bad exit status %d\n", status
);
105 /* Child: phony NBD client. */
108 client (data
, size
, sv
[1]);
112 _exit (EXIT_SUCCESS
);
120 "-s", /* take input from stdin/stdout */
121 "--log=null", /* discard error messages */
122 "plugins/memory/.libs/nbdkit-memory-plugin.so", "1M",
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);
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);
143 close (saved_stdout
);
147 client (const uint8_t *data
, size_t size
, int sock
)
149 struct pollfd pfds
[1];
154 shutdown (sock
, SHUT_WR
);
158 pfds
[0].events
= POLLIN
;
159 if (size
> 0) pfds
[0].events
|= POLLOUT
;
162 if (poll (pfds
, 1, -1) == -1) {
166 /* This is not an error. */
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
) {
177 else if (r
== 0) /* end of input from the server */
181 /* We can write to the server socket. */
182 if ((pfds
[0].revents
& POLLOUT
) != 0) {
184 r
= write (sock
, data
, size
);
185 if (r
== -1 && errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
) {
194 shutdown (sock
, SHUT_WR
);