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
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>
46 #include "array-size.h"
50 #ifndef ENABLE_LIBFUZZER
51 #error "This file should only be compiled when libFuzzer is enabled"
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. */
65 LLVMFuzzerTestOneInput (const uint8_t *data
, size_t size
)
70 /* Create a connected socket. */
71 if (socketpair (AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
, 0, sv
) == -1) {
72 perror ("socketpair");
76 /* Fork: The parent will be the nbdkit process (server). The child
77 * will be the phony NBD client.
86 /* Parent: nbdkit server. */
101 if (!WIFEXITED (status
) || WEXITSTATUS (status
) != 0)
102 fprintf (stderr
, "bad exit status %d\n", status
);
107 /* Child: phony NBD client. */
110 client (data
, size
, sv
[1]);
114 _exit (EXIT_SUCCESS
);
122 "-s", /* take input from stdin/stdout */
123 "--log=null", /* discard error messages */
124 "plugins/memory/.libs/nbdkit-memory-plugin." SOEXT
, "1M",
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);
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);
145 close (saved_stdout
);
149 client (const uint8_t *data
, size_t size
, int sock
)
151 struct pollfd pfds
[1];
156 shutdown (sock
, SHUT_WR
);
160 pfds
[0].events
= POLLIN
;
161 if (size
> 0) pfds
[0].events
|= POLLOUT
;
164 if (poll (pfds
, 1, -1) == -1) {
168 /* This is not an error. */
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
) {
179 else if (r
== 0) /* end of input from the server */
183 /* We can write to the server socket. */
184 if ((pfds
[0].revents
& POLLOUT
) != 0) {
186 r
= write (sock
, data
, size
);
187 if (r
== -1 && errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
) {
196 shutdown (sock
, SHUT_WR
);