Add fuzzing infrastructure

Though text formats aren't exactly fuzzer's strong suit, fuzzers can
catch many surface-level bugs.

The fuzz/ directory contains target programs, testcases and dictionaries
to drive the afl fuzzer.

This commit adds a fuzzer for the XKB keymap text format and the Compose
text format. On my slow machine, using a single core, a full cycle of
the XKB fuzzer takes 5 hours. For Compose, it takes a few minutes.

Fuzzing for the other file formats (rules files mostly) will be added
later.

To do some fuzzing, run `./fuzz/fuzz.sh`.

Signed-off-by: Ran Benita <ran234@gmail.com>
master
Ran Benita 2018-03-11 00:04:05 +02:00
parent a54cfe087a
commit 2cb5c2a3f3
9 changed files with 300 additions and 0 deletions

1
fuzz/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
findings/

8
fuzz/compose/dict Normal file
View File

@ -0,0 +1,8 @@
"Ctrl"
"Lock"
"Caps"
"Shift"
"Alt"
"Meta"
"None"
"acute"

45
fuzz/compose/target.c Normal file
View File

@ -0,0 +1,45 @@
/*
* A target program for fuzzing the Compose text format.
*
* Currently, just parses an input file, and hopefully doesn't crash or hang.
*/
#include <assert.h>
#include "xkbcommon/xkbcommon.h"
#include "xkbcommon/xkbcommon-compose.h"
int
main(int argc, char *argv[])
{
struct xkb_context *ctx;
FILE *file;
struct xkb_compose_table *table;
if (argc != 2) {
fprintf(stderr, "usage: %s <file>\n", argv[0]);
return 1;
}
ctx = xkb_context_new(XKB_CONTEXT_NO_DEFAULT_INCLUDES | XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
assert(ctx);
#ifdef __AFL_HAVE_MANUAL_CONTROL
__AFL_INIT();
while (__AFL_LOOP(1000))
#endif
{
file = fopen(argv[1], "r");
assert(file);
table = xkb_compose_table_new_from_file(ctx, file,
"en_US.UTF-8",
XKB_COMPOSE_FORMAT_TEXT_V1,
XKB_COMPOSE_COMPILE_NO_FLAGS);
xkb_compose_table_unref(table);
fclose(file);
}
puts(table ? "OK" : "FAIL");
xkb_context_unref(ctx);
}

View File

@ -0,0 +1,2 @@
<dead_tilde> <space> : "~" asciitilde # X
Meta <Multi_key> !Alt ~Shift <apostrophe> <apostrophe> : "\"\'\x43\123abc" acute # Y

17
fuzz/fuzz.sh Executable file
View File

@ -0,0 +1,17 @@
#!/bin/sh
set -e
case "$1" in
keymap|compose)
;;
*)
echo "usage: $0 keymap|compose" 1>&2
exit 1
;;
esac
export CC=afl-clang-fast
export AFL_HARDEN=1
test -d fuzz/build || meson setup -Db_lto=true fuzz/build
ninja -C fuzz/build
afl-fuzz -i fuzz/$1/testcases -x fuzz/$1/dict -o fuzz/$1/findings -t 200 -m 10 -- ./fuzz/build/fuzz-$1 @@

120
fuzz/keymap/dict Normal file
View File

@ -0,0 +1,120 @@
"Control"
"Group1"
"Group5"
"Lock"
"Mod1"
"Mod9"
"Shift"
"U1"
"0x1"
"Up"
"accel"
"action"
"actions"
"affect"
"alias"
"all"
"allowexplicit"
"allownone"
"alphanumeric_keys"
"alternate"
"alternate_group"
"any"
"augment"
"both"
"button"
"clearLocks"
"clearmods"
"controls"
"count"
"ctrls"
"data"
"default"
"dev"
"device"
"dfltbtn"
"driveskbd"
"false"
"foo"
"function_keys"
"genKeyEvent"
"group"
"groupname"
"groups"
"groupsclamp"
"groupsredirect"
"groupswrap"
"hidden"
"include"
"increment"
"index"
"indicator"
"indicatordriveskbd"
"interpret"
"kc"
"key"
"keycode"
"keypad_keys"
"keys"
"latchToLock"
"leddriveskbd"
"levelname"
"lock"
"locking"
"logo"
"map"
"mod_map"
"modifier_keys"
"modifier_map"
"modifiers"
"modmap"
"modmapmods"
"mods"
"name"
"neither"
"no"
"none"
"nosymbol"
"off"
"on"
"outline"
"overlay"
"override"
"partial"
"preserve"
"radiogroup"
"repeat"
"replace"
"report"
"row"
"same"
"sameServer"
"screen"
"section"
"shape"
"solid"
"symbols"
"text"
"true"
"type"
"unlock"
"usemodmap"
"value"
"virtual"
"virtual_modifiers"
"virtualmod"
"vmods"
"voidsymbol"
"whichgroupstate"
"whichmodstate"
"x"
"xkb_compat"
"xkb_geometry"
"xkb_keycodes"
"xkb_keymap"
"xkb_layout"
"xkb_semantics"
"xkb_symbols"
"xkb_types"
"y"
"yes"

43
fuzz/keymap/target.c Normal file
View File

@ -0,0 +1,43 @@
/*
* A target program for fuzzing the XKB keymap text format.
*
* Currently, just parses an input file, and hopefully doesn't crash or hang.
*/
#include <assert.h>
#include "xkbcommon/xkbcommon.h"
int
main(int argc, char *argv[])
{
struct xkb_context *ctx;
FILE *file;
struct xkb_keymap *keymap;
if (argc != 2) {
fprintf(stderr, "usage: %s <file>\n", argv[0]);
return 1;
}
ctx = xkb_context_new(XKB_CONTEXT_NO_DEFAULT_INCLUDES | XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
assert(ctx);
#ifdef __AFL_HAVE_MANUAL_CONTROL
__AFL_INIT();
while (__AFL_LOOP(1000))
#endif
{
file = fopen(argv[1], "r");
assert(file);
keymap = xkb_keymap_new_from_file(ctx, file,
XKB_KEYMAP_FORMAT_TEXT_V1,
XKB_KEYMAP_COMPILE_NO_FLAGS);
xkb_keymap_unref(keymap);
fclose(file);
}
puts(keymap ? "OK" : "FAIL");
xkb_context_unref(ctx);
}

View File

@ -0,0 +1,59 @@
xkb_keymap{
xkb_keycodes"0"{
minimum=0;
maximum=500;
<a>=0;
indicator 1="X";
alias<X>=<Y>;
};
xkb_types"X"{
virtual_modifiers NumLock;
type"X"{
modifiers=Shift;
map[Shift]=Level2;
level_name[Level1]="X";
preserve[Shift]=Shift;
};
};
partial xkb_compat{
virtual_modifiers Alt;
interpret.useModMapMods=AnyLevel;
interpret.repeat=False;
interpret.locking=False;
interpret ISO_Level2_Latch+Exactly(Shift){
repeat=True;
virtualModifier=NumLock;
useModMapMods=level1;
action=LatchMods(modifiers=Shift,clearLocks,latchToLock);
action=MovePtr(x=+0,y=-0);
action=SwitchScreen(screen=00,!same);
action=Private(type=0x80,data[0]=0x00);
};
indicator"X"{whichModState=locked;modifiers=Lock;};
};
xkb_symbols{
name[group1]="X";
key<Y>{type[group2]="X",symbols[Group1]=[0,exclam],symbols[Group2]=[0xff,U00],symbols[Group3]=[z]};
modifier_map Control{<a>};
};
default xkb_geometry"X"{
description="X";
width=470;
shape.cornerRadius=1;
shape"NORM"{cornerRadius=0,{[0.0,0]},{[0,0],[0,0.0]}};
solid"X"{shape="X";top=00;left=00;color="X";};
indicator.onColor="X";
indicator.top=00.0;
indicator.shape="X";
indicator"X"{left=0;};
text.top=00;
text.color="X";
text"X"{left=0;text="X";};
section.left=00;
row.left=0;
key.shape="X";
key.gap=1;
section"X"{top=22;row{top=1;keys{{<X>,color="X"},{<X>,00.0},<X>,<X>,<X>};};};
alias<AC00>=<CAPS>;
};
};

View File

@ -383,6 +383,11 @@ if get_option('enable-x11')
endif
# Fuzzing target programs.
executable('fuzz-keymap', 'fuzz/keymap/target.c', dependencies: test_dep)
executable('fuzz-compose', 'fuzz/compose/target.c', dependencies: test_dep)
# Demo programs.
executable('rmlvo-to-kccgst', 'test/rmlvo-to-kccgst.c', dependencies: test_dep)
executable('print-compiled-keymap', 'test/print-compiled-keymap.c', dependencies: test_dep)