xref: /aosp_15_r20/external/virglrenderer/vtest/vtest_fuzzer.c (revision bbecb9d118dfdb95f99bd754f8fa9be01f189df3)
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 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    NULL, /* VCMD_RESOURCE_BUSY_WAIT is determined by VTEST_FUZZER_FENCES */
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 wait_fences)89 static void vtest_fuzzer_run_renderer(int out_fd, struct vtest_input *input,
90                                       int ctx_flags, bool wait_fences)
91 {
92    struct vtest_context *context = NULL;
93    int ret;
94    uint32_t header[VTEST_HDR_SIZE];
95 
96    vtest_commands[VCMD_RESOURCE_BUSY_WAIT] = wait_fences ?
97       vtest_resource_busy_wait : vtest_resource_busy_wait_nop;
98 
99    do {
100       ret = input->read(input, &header, sizeof(header));
101       if (ret < 0 || (size_t)ret < sizeof(header)) {
102          break;
103       }
104 
105       if (!context) {
106          /* The first command MUST be VCMD_CREATE_RENDERER */
107          if (header[1] != VCMD_CREATE_RENDERER) {
108             break;
109          }
110 
111          ret = vtest_init_renderer(false, ctx_flags, NULL);
112          if (ret >= 0) {
113             ret = vtest_create_context(input, out_fd, header[0], &context);
114          }
115          if (ret >= 0) {
116             ret = vtest_lazy_init_context(context);
117          }
118          if (ret < 0) {
119             break;
120          }
121          vtest_set_current_context(context);
122          vtest_poll_resource_busy_wait();
123          continue;
124       }
125 
126       vtest_poll_resource_busy_wait();
127       if (header[1] <= 0 || header[1] >= ARRAY_SIZE(vtest_commands)) {
128          break;
129       }
130 
131       if (vtest_commands[header[1]] == NULL) {
132          break;
133       }
134 
135       ret = vtest_commands[header[1]](header[0]);
136       if (ret < 0) {
137          break;
138       }
139    } while (1);
140 
141    if (context) {
142       vtest_destroy_context(context);
143    }
144    vtest_cleanup_renderer();
145 }
146 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)147 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
148 {
149    /* Limit unbounded allocations under fuzzer default limits. */
150    vtest_set_max_length(256 * 1024 * 1024);
151 
152    int out_fd = open("/dev/null", O_WRONLY);
153 
154    struct vtest_buffer buffer;
155    buffer.buffer = (char *)data;
156    buffer.size = size;
157    struct vtest_input input;
158    input.data.buffer = &buffer;
159    input.read = vtest_buf_read;
160 
161    vtest_fuzzer_run_renderer(out_fd, &input,
162                              VIRGL_RENDERER_USE_EGL |
163                              VIRGL_RENDERER_USE_SURFACELESS |
164                              (getenv("VTEST_FUZZER_USE_GL") != NULL ?
165                               0 : VIRGL_RENDERER_USE_GLES),
166                              getenv("VTEST_FUZZER_FENCES") != NULL);
167 
168    close(out_fd);
169 
170    return 0;
171 }
172