• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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