1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 // * Neither the name of Google Inc. nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 #include <stdio.h>
30 #include <signal.h>
31 #include <stdbool.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <sys/un.h>
38 #include <fcntl.h>
39 #include <getopt.h>
40 #include <string.h>
41
42 #include "util.h"
43 #include "util/u_memory.h"
44 #include "vtest.h"
45 #include "vtest_protocol.h"
46 #include "virglrenderer.h"
47
48 int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
49
50 #ifndef CLEANUP_EACH_INPUT
51 // eglInitialize leaks unless eglTeriminate is called (which only happens
52 // with CLEANUP_EACH_INPUT), so suppress leak detection on everything
53 // allocated by it.
54
55 #if !defined(__has_feature)
56 #define __has_feature(x) 0
57 #endif
58
59 #if __has_feature(address_sanitizer)
60 const char* __lsan_default_suppressions(void);
61
__lsan_default_suppressions()62 const char* __lsan_default_suppressions() {
63 return "leak:dri2_initialize_surfaceless\n";
64 }
65 #endif // __has_feature(address_sanitizer)
66
67 #endif // !CLEANUP_EACH_INPUT
68
69 typedef int (*vtest_cmd_fptr_t)(uint32_t);
70
71 static const vtest_cmd_fptr_t vtest_commands[] = {
72 NULL /* CMD ids starts at 1 */,
73 vtest_send_caps,
74 vtest_create_resource,
75 vtest_resource_unref,
76 vtest_transfer_get_nop,
77 vtest_transfer_put_nop,
78 vtest_submit_cmd,
79 vtest_resource_busy_wait,
80 NULL, /* VCMD_CREATE_RENDERER is a specific case */
81 vtest_send_caps2,
82 vtest_ping_protocol_version,
83 vtest_protocol_version,
84 vtest_create_resource2,
85 vtest_transfer_get2_nop,
86 vtest_transfer_put2_nop,
87 };
88
vtest_fuzzer_run_renderer(int out_fd,struct vtest_input * input,int ctx_flags,bool create_fences)89 static void vtest_fuzzer_run_renderer(int out_fd, struct vtest_input *input,
90 int ctx_flags, bool create_fences)
91 {
92 struct vtest_context *context = NULL;
93 int ret;
94 uint32_t header[VTEST_HDR_SIZE];
95
96 do {
97 ret = input->read(input, &header, sizeof(header));
98 if (ret < 0 || (size_t)ret < sizeof(header)) {
99 break;
100 }
101
102 if (!context) {
103 /* The first command MUST be VCMD_CREATE_RENDERER */
104 if (header[1] != VCMD_CREATE_RENDERER) {
105 break;
106 }
107
108 ret = vtest_init_renderer(ctx_flags, NULL);
109 if (ret >= 0) {
110 ret = vtest_create_context(input, out_fd, header[0], &context);
111 }
112 if (ret >= 0) {
113 ret = vtest_lazy_init_context(context);
114 }
115 if (ret < 0) {
116 break;
117 }
118 vtest_set_current_context(context);
119 vtest_poll();
120 continue;
121 }
122
123 vtest_poll();
124 if (header[1] <= 0 || header[1] >= ARRAY_SIZE(vtest_commands)) {
125 break;
126 }
127
128 if (vtest_commands[header[1]] == NULL) {
129 break;
130 }
131
132 ret = vtest_commands[header[1]](header[0]);
133 if (ret < 0) {
134 break;
135 }
136
137 /* GL draws are fenced, while possible fence creations are too */
138 if (create_fences &&
139 (header[1] == VCMD_SUBMIT_CMD || header[1] == VCMD_RESOURCE_CREATE ||
140 header[1] == VCMD_RESOURCE_CREATE2))
141 vtest_renderer_create_fence();
142 } while (1);
143
144 if (context) {
145 vtest_destroy_context(context);
146 }
147 vtest_cleanup_renderer();
148 }
149
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)150 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
151 {
152 /* Limit unbounded allocations under fuzzer default limits. */
153 vtest_set_max_length(256 * 1024 * 1024);
154
155 int out_fd = open("/dev/null", O_WRONLY);
156
157 struct vtest_buffer buffer;
158 buffer.buffer = data;
159 buffer.size = size;
160 struct vtest_input input;
161 input.data.buffer = &buffer;
162 input.read = vtest_buf_read;
163
164 vtest_fuzzer_run_renderer(out_fd, &input,
165 VIRGL_RENDERER_USE_EGL |
166 VIRGL_RENDERER_USE_SURFACELESS |
167 (getenv("VTEST_FUZZER_USE_GL") != NULL ?
168 0 : VIRGL_RENDERER_USE_GLES),
169 getenv("VTEST_FUZZER_FENCES") != NULL);
170
171 close(out_fd);
172
173 return 0;
174 }
175