Friendly ping. On Mon, Oct 13, 2025 at 5:30 PM Navid Emamdoost <[email protected]> wrote: > > Add a new generic fuzz target for the QEMU VNC server. This target > exercises both the standard VNC protocol and the VNC-over-WebSocket > transport layer, increasing coverage of a primary remote attack surface. > > To support parallel fuzzing (e.g., with oss-fuzz), the VNC unix > socket paths are generated dynamically. The fuzzer harness inspects the > command line for placeholders and replaces them with unique paths > created by mkstemp() before execution. > > --- > > This new target increases code coverage in the VNC subsystem > and related networking and I/O code. > The baseline coverage below was generated by running all existing fuzz > targets with the oss-fuzz corpus. The new target shows significant gains: > > ---------------------------------------------------------------------------- > File New Target Baseline Change > ---------------------------------------------------------------------------- > vnc.c 339/3212 (10.6%) 3/3212 (0.1%) +336 > keymaps.c 91/184 (49.5%) 0/184 (0.0%) +91 > net-listener.c 76/198 (38.4%) 3/198 (1.5%) +73 > channel-socket.c 73/575 (12.7%) 19/575 (3.3%) +54 > qemu-sockets.c 44/1019 (4.3%) 0/1019 (0.0%) +44 > vnc-jobs.c 41/219 (18.7%) 0/219 (0.0%) +41 > dns-resolver.c 28/145 (19.3%) 3/145 (2.1%) +25 > > Signed-off-by: Navid Emamdoost <[email protected]> > --- > tests/qtest/fuzz/fuzz.c | 65 +++++++++++++++++++++++++ > tests/qtest/fuzz/generic_fuzz_configs.h | 5 ++ > 2 files changed, 70 insertions(+) > > diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c > index ca248a51a6..b77c3ceb2b 100644 > --- a/tests/qtest/fuzz/fuzz.c > +++ b/tests/qtest/fuzz/fuzz.c > @@ -126,6 +126,46 @@ static FuzzTarget *fuzz_get_target(char* name) > return NULL; > } > > +/* > + * Global variables to hold the unique socket paths for cleanup. > + */ > +static char g_vnc_socket_path[sizeof("/tmp/qemu-vnc.XXXXXX")]; > +static char g_vnc_ws_socket_path[sizeof("/tmp/qemu-vnc-ws.XXXXXX")]; > + > +/* > + * atexit() handler to clean up both socket files. > + */ > +static void cleanup_vnc_sockets(void) > +{ > + if (g_vnc_socket_path[0] != '\0') { > + unlink(g_vnc_socket_path); > + } > + if (g_vnc_ws_socket_path[0] != '\0') { > + unlink(g_vnc_ws_socket_path); > + } > +} > + > +/* Helper function to find and replace a placeholder in a GString */ > +static bool replace_socket_placeholder(GString *cmd_line, const char > *placeholder, > + const char *path_template, char > *global_path_out) > +{ > + char *placeholder_ptr = strstr(cmd_line->str, placeholder); > + if (placeholder_ptr) { > + int fd; > + strcpy(global_path_out, path_template); > + fd = mkstemp(global_path_out); > + if (fd == -1) { > + perror("mkstemp failed"); > + return false; > + } > + close(fd); > + > + gssize pos = placeholder_ptr - cmd_line->str; > + g_string_erase(cmd_line, pos, strlen(placeholder)); > + g_string_insert(cmd_line, pos, global_path_out); > + } > + return true; > +} > > /* Sometimes called by libfuzzer to mutate two inputs into one */ > size_t LLVMFuzzerCustomCrossOver(const uint8_t *data1, size_t size1, > @@ -213,6 +253,31 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char > ***envp) > g_string_append_printf(cmd_line, " %s -qtest /dev/null ", > getenv("QTEST_LOG") ? "" : "-qtest-log none"); > > + /* > + * For the VNC fuzzer, we replace placeholders for both the standard > + * and WebSocket VNC listeners with unique socket paths. > + */ > + if (strcmp(fuzz_target->name, "generic-fuzz-vnc") == 0) { > + bool success = true; > + success &= replace_socket_placeholder(cmd_line, "VNC_SOCKET_PATH", > + "/tmp/qemu-vnc.XXXXXX", > g_vnc_socket_path); > + success &= replace_socket_placeholder(cmd_line, "VNC_WS_SOCKET_PATH", > + "/tmp/qemu-vnc-ws.XXXXXX", > g_vnc_ws_socket_path); > + > + if (!success) { > + exit(1); > + } > + > + /* Check that placeholders were actually found and replaced */ > + if (g_vnc_socket_path[0] == '\0' || g_vnc_ws_socket_path[0] == '\0') > { > + fprintf(stderr, "ERROR: VNC fuzzer is missing a socket > placeholder\n"); > + exit(1); > + } > + > + /* Register a single cleanup handler for both sockets */ > + atexit(cleanup_vnc_sockets); > + } > + > /* Split the runcmd into an argv and argc */ > wordexp_t result; > wordexp(cmd_line->str, &result, 0); > diff --git a/tests/qtest/fuzz/generic_fuzz_configs.h > b/tests/qtest/fuzz/generic_fuzz_configs.h > index ef0ad95712..bd2d875dd8 100644 > --- a/tests/qtest/fuzz/generic_fuzz_configs.h > +++ b/tests/qtest/fuzz/generic_fuzz_configs.h > @@ -247,6 +247,11 @@ const generic_fuzz_config predefined_configs[] = { > .args = "-machine q35 -nodefaults " > "-parallel file:/dev/null", > .objects = "parallel*", > + },{ > + .name = "vnc", > + .args = "-machine q35 -nodefaults " > + "-vnc > vnc=unix:VNC_SOCKET_PATH,websocket=unix:VNC_WS_SOCKET_PATH", > + .objects = "*", > } > }; > > -- > 2.51.0.760.g7b8bcc2412-goog >
-- Thank you, Navid.
