mirror of
https://github.com/tmux/tmux.git
synced 2026-03-31 16:56:28 +00:00
Add new fuzzers for command parsing, formats and styles, from David Korczynski
in GitHub issue 4957.
This commit is contained in:
83
fuzz/cmd-parse-fuzzer.c
Normal file
83
fuzz/cmd-parse-fuzzer.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2026 David Korczynski <david@adalogics.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Fuzz the tmux command parser (cmd_parse_from_buffer).
|
||||
*
|
||||
* This exercises:
|
||||
* - cmd-parse.y (yacc grammar, lexer, command building)
|
||||
* - cmd.c (command lookup and validation)
|
||||
* - arguments.c (argument parsing and flag handling)
|
||||
* - cmd-find.c (target resolution)
|
||||
* - options.c (option name lookups during parsing)
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
struct event_base *libevent;
|
||||
|
||||
int
|
||||
LLVMFuzzerTestOneInput(const u_char *data, size_t size)
|
||||
{
|
||||
struct cmd_parse_input pi;
|
||||
struct cmd_parse_result *pr;
|
||||
|
||||
if (size > 2048 || size == 0)
|
||||
return 0;
|
||||
|
||||
memset(&pi, 0, sizeof pi);
|
||||
pi.flags = CMD_PARSE_QUIET;
|
||||
|
||||
pr = cmd_parse_from_buffer(data, size, &pi);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_SUCCESS:
|
||||
cmd_list_free(pr->cmdlist);
|
||||
break;
|
||||
case CMD_PARSE_ERROR:
|
||||
free(pr->error);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
LLVMFuzzerInitialize(__unused int *argc, __unused char ***argv)
|
||||
{
|
||||
const struct options_table_entry *oe;
|
||||
|
||||
global_environ = environ_create();
|
||||
global_options = options_create(NULL);
|
||||
global_s_options = options_create(NULL);
|
||||
global_w_options = options_create(NULL);
|
||||
for (oe = options_table; oe->name != NULL; oe++) {
|
||||
if (oe->scope & OPTIONS_TABLE_SERVER)
|
||||
options_default(global_options, oe);
|
||||
if (oe->scope & OPTIONS_TABLE_SESSION)
|
||||
options_default(global_s_options, oe);
|
||||
if (oe->scope & OPTIONS_TABLE_WINDOW)
|
||||
options_default(global_w_options, oe);
|
||||
}
|
||||
libevent = osdep_event_init();
|
||||
socket_path = xstrdup("dummy");
|
||||
|
||||
return 0;
|
||||
}
|
||||
133
fuzz/cmd-parse-fuzzer.dict
Normal file
133
fuzz/cmd-parse-fuzzer.dict
Normal file
@@ -0,0 +1,133 @@
|
||||
# tmux command names
|
||||
"set-option"
|
||||
"bind-key"
|
||||
"unbind-key"
|
||||
"send-keys"
|
||||
"new-session"
|
||||
"new-window"
|
||||
"split-window"
|
||||
"select-window"
|
||||
"select-pane"
|
||||
"kill-pane"
|
||||
"kill-window"
|
||||
"kill-session"
|
||||
"kill-server"
|
||||
"list-sessions"
|
||||
"list-windows"
|
||||
"list-panes"
|
||||
"list-keys"
|
||||
"list-buffers"
|
||||
"list-clients"
|
||||
"list-commands"
|
||||
"attach-session"
|
||||
"detach-client"
|
||||
"switch-client"
|
||||
"rename-session"
|
||||
"rename-window"
|
||||
"resize-pane"
|
||||
"resize-window"
|
||||
"display-message"
|
||||
"display-menu"
|
||||
"display-popup"
|
||||
"display-panes"
|
||||
"copy-mode"
|
||||
"paste-buffer"
|
||||
"capture-pane"
|
||||
"save-buffer"
|
||||
"load-buffer"
|
||||
"set-buffer"
|
||||
"delete-buffer"
|
||||
"show-buffer"
|
||||
"choose-buffer"
|
||||
"choose-tree"
|
||||
"choose-client"
|
||||
"if-shell"
|
||||
"run-shell"
|
||||
"source-file"
|
||||
"command-prompt"
|
||||
"confirm-before"
|
||||
"pipe-pane"
|
||||
"wait-for"
|
||||
"set-environment"
|
||||
"show-environment"
|
||||
"set-hook"
|
||||
"show-hooks"
|
||||
"show-messages"
|
||||
"show-options"
|
||||
"set-window-option"
|
||||
"show-window-options"
|
||||
"clear-history"
|
||||
"clock-mode"
|
||||
"find-window"
|
||||
"join-pane"
|
||||
"move-pane"
|
||||
"break-pane"
|
||||
"swap-pane"
|
||||
"swap-window"
|
||||
"move-window"
|
||||
"link-window"
|
||||
"unlink-window"
|
||||
"rotate-window"
|
||||
"next-window"
|
||||
"previous-window"
|
||||
"last-window"
|
||||
"last-pane"
|
||||
"next-layout"
|
||||
"previous-layout"
|
||||
"select-layout"
|
||||
"customize-mode"
|
||||
"refresh-client"
|
||||
"suspend-client"
|
||||
"lock-client"
|
||||
"lock-server"
|
||||
"lock-session"
|
||||
"respawn-pane"
|
||||
"respawn-window"
|
||||
"start-server"
|
||||
"server-access"
|
||||
"send-prefix"
|
||||
"clear-prompt-history"
|
||||
"show-prompt-history"
|
||||
|
||||
# Common flags and syntax
|
||||
"-t"
|
||||
"-s"
|
||||
"-g"
|
||||
"-w"
|
||||
"-p"
|
||||
"-a"
|
||||
"-o"
|
||||
"-q"
|
||||
"-u"
|
||||
"-F"
|
||||
"-f"
|
||||
"-b"
|
||||
"-d"
|
||||
"-e"
|
||||
"-n"
|
||||
"-r"
|
||||
|
||||
# Targets and option names
|
||||
"status"
|
||||
"default"
|
||||
"mouse"
|
||||
"on"
|
||||
"off"
|
||||
"vi"
|
||||
"emacs"
|
||||
"set -g"
|
||||
"set -s"
|
||||
"setw"
|
||||
"bind"
|
||||
"unbind"
|
||||
|
||||
# Syntax elements
|
||||
"{"
|
||||
"}"
|
||||
";"
|
||||
"#{"
|
||||
"%if"
|
||||
"%elif"
|
||||
"%else"
|
||||
"%endif"
|
||||
"%hidden"
|
||||
2
fuzz/cmd-parse-fuzzer.options
Normal file
2
fuzz/cmd-parse-fuzzer.options
Normal file
@@ -0,0 +1,2 @@
|
||||
[libfuzzer]
|
||||
max_len = 2048
|
||||
88
fuzz/format-fuzzer.c
Normal file
88
fuzz/format-fuzzer.c
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2026 David Korczynski <david@adalogics.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Fuzz the tmux format string expander (format_expand).
|
||||
*
|
||||
* This exercises:
|
||||
* - format.c (format parsing, modifier chains, conditionals, math, regex)
|
||||
* - colour.c (colour name and RGB parsing within formats)
|
||||
* - utf8.c (UTF-8 width calculations in format padding)
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
struct event_base *libevent;
|
||||
|
||||
int
|
||||
LLVMFuzzerTestOneInput(const u_char *data, size_t size)
|
||||
{
|
||||
struct format_tree *ft;
|
||||
char *buf, *expanded;
|
||||
|
||||
if (size > 2048 || size == 0)
|
||||
return 0;
|
||||
|
||||
/* Null-terminate the input for format_expand. */
|
||||
buf = malloc(size + 1);
|
||||
if (buf == NULL)
|
||||
return 0;
|
||||
memcpy(buf, data, size);
|
||||
buf[size] = '\0';
|
||||
|
||||
ft = format_create(NULL, NULL, 0, FORMAT_NOJOBS);
|
||||
format_add(ft, "session_name", "%s", "fuzz-session");
|
||||
format_add(ft, "window_index", "%d", 0);
|
||||
format_add(ft, "window_name", "%s", "fuzz-window");
|
||||
format_add(ft, "pane_index", "%d", 0);
|
||||
format_add(ft, "pane_id", "%s", "%%0");
|
||||
format_add(ft, "host", "%s", "fuzzhost");
|
||||
format_add(ft, "pane_width", "%d", 80);
|
||||
format_add(ft, "pane_height", "%d", 25);
|
||||
|
||||
expanded = format_expand(ft, buf);
|
||||
free(expanded);
|
||||
format_free(ft);
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
LLVMFuzzerInitialize(__unused int *argc, __unused char ***argv)
|
||||
{
|
||||
const struct options_table_entry *oe;
|
||||
|
||||
global_environ = environ_create();
|
||||
global_options = options_create(NULL);
|
||||
global_s_options = options_create(NULL);
|
||||
global_w_options = options_create(NULL);
|
||||
for (oe = options_table; oe->name != NULL; oe++) {
|
||||
if (oe->scope & OPTIONS_TABLE_SERVER)
|
||||
options_default(global_options, oe);
|
||||
if (oe->scope & OPTIONS_TABLE_SESSION)
|
||||
options_default(global_s_options, oe);
|
||||
if (oe->scope & OPTIONS_TABLE_WINDOW)
|
||||
options_default(global_w_options, oe);
|
||||
}
|
||||
libevent = osdep_event_init();
|
||||
socket_path = xstrdup("dummy");
|
||||
|
||||
return 0;
|
||||
}
|
||||
71
fuzz/format-fuzzer.dict
Normal file
71
fuzz/format-fuzzer.dict
Normal file
@@ -0,0 +1,71 @@
|
||||
# Format expansion syntax
|
||||
"#{"
|
||||
"}"
|
||||
"#{?"
|
||||
"#{=="
|
||||
"#{!="
|
||||
"#{<"
|
||||
"#{>"
|
||||
"#{m:"
|
||||
"#{C:"
|
||||
"#{s/"
|
||||
"#{t:"
|
||||
"#{T:"
|
||||
"#{E:"
|
||||
"#{S:"
|
||||
"#{W:"
|
||||
"#{P:"
|
||||
"##"
|
||||
|
||||
# Common format modifiers
|
||||
"b:"
|
||||
"d:"
|
||||
"q:"
|
||||
"l:"
|
||||
"e:"
|
||||
"t:"
|
||||
"p:"
|
||||
"w:"
|
||||
"n:"
|
||||
"a:"
|
||||
"=:"
|
||||
"||"
|
||||
"&&"
|
||||
","
|
||||
"#{e|"
|
||||
"#{p-1:"
|
||||
"#{=/10/...:"
|
||||
|
||||
# Format variables
|
||||
"session_name"
|
||||
"window_index"
|
||||
"window_name"
|
||||
"pane_index"
|
||||
"pane_id"
|
||||
"host"
|
||||
"pane_width"
|
||||
"pane_height"
|
||||
"pane_current_command"
|
||||
"pane_pid"
|
||||
"session_id"
|
||||
"window_id"
|
||||
"client_name"
|
||||
"version"
|
||||
"line"
|
||||
|
||||
# Conditionals
|
||||
"#{?pane_active,"
|
||||
",}"
|
||||
"#{?#{==:"
|
||||
|
||||
# Math and comparison
|
||||
"#{e|+:"
|
||||
"#{e|-:"
|
||||
"#{e|*:"
|
||||
"#{e|/:"
|
||||
"#{e|%:"
|
||||
|
||||
# Nested
|
||||
"#{="
|
||||
"#{"
|
||||
"#{l:"
|
||||
2
fuzz/format-fuzzer.options
Normal file
2
fuzz/format-fuzzer.options
Normal file
@@ -0,0 +1,2 @@
|
||||
[libfuzzer]
|
||||
max_len = 2048
|
||||
79
fuzz/style-fuzzer.c
Normal file
79
fuzz/style-fuzzer.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2026 David Korczynski <david@adalogics.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Fuzz the tmux style parser (style_parse).
|
||||
*
|
||||
* This exercises:
|
||||
* - style.c (style string parsing, alignment, ranges)
|
||||
* - colour.c (colour name, RGB, and indexed colour parsing)
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
struct event_base *libevent;
|
||||
|
||||
int
|
||||
LLVMFuzzerTestOneInput(const u_char *data, size_t size)
|
||||
{
|
||||
struct style sy;
|
||||
struct grid_cell gc;
|
||||
char *buf;
|
||||
|
||||
if (size > 512 || size == 0)
|
||||
return 0;
|
||||
|
||||
/* Null-terminate the input for style_parse. */
|
||||
buf = malloc(size + 1);
|
||||
if (buf == NULL)
|
||||
return 0;
|
||||
memcpy(buf, data, size);
|
||||
buf[size] = '\0';
|
||||
|
||||
memset(&gc, 0, sizeof gc);
|
||||
style_set(&sy, &gc);
|
||||
|
||||
style_parse(&sy, &gc, buf);
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
LLVMFuzzerInitialize(__unused int *argc, __unused char ***argv)
|
||||
{
|
||||
const struct options_table_entry *oe;
|
||||
|
||||
global_environ = environ_create();
|
||||
global_options = options_create(NULL);
|
||||
global_s_options = options_create(NULL);
|
||||
global_w_options = options_create(NULL);
|
||||
for (oe = options_table; oe->name != NULL; oe++) {
|
||||
if (oe->scope & OPTIONS_TABLE_SERVER)
|
||||
options_default(global_options, oe);
|
||||
if (oe->scope & OPTIONS_TABLE_SESSION)
|
||||
options_default(global_s_options, oe);
|
||||
if (oe->scope & OPTIONS_TABLE_WINDOW)
|
||||
options_default(global_w_options, oe);
|
||||
}
|
||||
libevent = osdep_event_init();
|
||||
socket_path = xstrdup("dummy");
|
||||
|
||||
return 0;
|
||||
}
|
||||
73
fuzz/style-fuzzer.dict
Normal file
73
fuzz/style-fuzzer.dict
Normal file
@@ -0,0 +1,73 @@
|
||||
# Style attributes
|
||||
"default"
|
||||
"ignore"
|
||||
"nodefaults"
|
||||
"bright"
|
||||
"bold"
|
||||
"dim"
|
||||
"underscore"
|
||||
"blink"
|
||||
"reverse"
|
||||
"hidden"
|
||||
"italics"
|
||||
"overline"
|
||||
"strikethrough"
|
||||
"double-underscore"
|
||||
"curly-underscore"
|
||||
"dotted-underscore"
|
||||
"dashed-underscore"
|
||||
"nobright"
|
||||
"nobold"
|
||||
"nodim"
|
||||
"nounderscore"
|
||||
"noblink"
|
||||
"noreverse"
|
||||
"nohidden"
|
||||
"noitalics"
|
||||
"nooverline"
|
||||
"nostrikethrough"
|
||||
|
||||
# Colours
|
||||
"fg="
|
||||
"bg="
|
||||
"us="
|
||||
"fill="
|
||||
"colour0"
|
||||
"colour255"
|
||||
"red"
|
||||
"green"
|
||||
"blue"
|
||||
"yellow"
|
||||
"cyan"
|
||||
"magenta"
|
||||
"white"
|
||||
"black"
|
||||
|
||||
# RGB and hex
|
||||
"#ff0000"
|
||||
"#00ff00"
|
||||
"#0000ff"
|
||||
|
||||
# Alignment and ranges
|
||||
"align=left"
|
||||
"align=centre"
|
||||
"align=right"
|
||||
"align=absolute-centre"
|
||||
"list=on"
|
||||
"list=focus"
|
||||
"list=left-marker"
|
||||
"list=right-marker"
|
||||
"range=left"
|
||||
"range=right"
|
||||
"range=pane"
|
||||
"range=window"
|
||||
"range=session"
|
||||
"range=user"
|
||||
|
||||
# Width and padding
|
||||
"width="
|
||||
"pad="
|
||||
|
||||
# Delimiters
|
||||
","
|
||||
" "
|
||||
2
fuzz/style-fuzzer.options
Normal file
2
fuzz/style-fuzzer.options
Normal file
@@ -0,0 +1,2 @@
|
||||
[libfuzzer]
|
||||
max_len = 512
|
||||
Reference in New Issue
Block a user