From 2cb5c2a3f3a74fb7478648a7811ca2b6e6272311 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Sun, 11 Mar 2018 00:04:05 +0200 Subject: 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 --- fuzz/.gitignore | 1 + fuzz/compose/dict | 8 +++ fuzz/compose/target.c | 45 +++++++++++++++ fuzz/compose/testcases/Compose | 2 + fuzz/fuzz.sh | 17 ++++++ fuzz/keymap/dict | 120 ++++++++++++++++++++++++++++++++++++++++ fuzz/keymap/target.c | 43 ++++++++++++++ fuzz/keymap/testcases/input.xkb | 59 ++++++++++++++++++++ meson.build | 5 ++ 9 files changed, 300 insertions(+) create mode 100644 fuzz/.gitignore create mode 100644 fuzz/compose/dict create mode 100644 fuzz/compose/target.c create mode 100644 fuzz/compose/testcases/Compose create mode 100755 fuzz/fuzz.sh create mode 100644 fuzz/keymap/dict create mode 100644 fuzz/keymap/target.c create mode 100644 fuzz/keymap/testcases/input.xkb diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000..413910a --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1 @@ +findings/ diff --git a/fuzz/compose/dict b/fuzz/compose/dict new file mode 100644 index 0000000..38dfe3a --- /dev/null +++ b/fuzz/compose/dict @@ -0,0 +1,8 @@ +"Ctrl" +"Lock" +"Caps" +"Shift" +"Alt" +"Meta" +"None" +"acute" diff --git a/fuzz/compose/target.c b/fuzz/compose/target.c new file mode 100644 index 0000000..69b434e --- /dev/null +++ b/fuzz/compose/target.c @@ -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 + +#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 \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); +} diff --git a/fuzz/compose/testcases/Compose b/fuzz/compose/testcases/Compose new file mode 100644 index 0000000..a62727d --- /dev/null +++ b/fuzz/compose/testcases/Compose @@ -0,0 +1,2 @@ + : "~" asciitilde # X +Meta !Alt ~Shift : "\"\'\x43\123abc" acute # Y diff --git a/fuzz/fuzz.sh b/fuzz/fuzz.sh new file mode 100755 index 0000000..65aab9c --- /dev/null +++ b/fuzz/fuzz.sh @@ -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 @@ diff --git a/fuzz/keymap/dict b/fuzz/keymap/dict new file mode 100644 index 0000000..2a7ac69 --- /dev/null +++ b/fuzz/keymap/dict @@ -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" diff --git a/fuzz/keymap/target.c b/fuzz/keymap/target.c new file mode 100644 index 0000000..3c5e5f7 --- /dev/null +++ b/fuzz/keymap/target.c @@ -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 + +#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 \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); +} diff --git a/fuzz/keymap/testcases/input.xkb b/fuzz/keymap/testcases/input.xkb new file mode 100644 index 0000000..64ea6a3 --- /dev/null +++ b/fuzz/keymap/testcases/input.xkb @@ -0,0 +1,59 @@ +xkb_keymap{ +xkb_keycodes"0"{ +minimum=0; +maximum=500; +=0; +indicator 1="X"; +alias=; +}; +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{type[group2]="X",symbols[Group1]=[0,exclam],symbols[Group2]=[0xff,U00],symbols[Group3]=[z]}; +modifier_map Control{}; +}; +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{{,color="X"},{,00.0},,,};};}; +alias=; +}; +}; diff --git a/meson.build b/meson.build index 360958b..9adfb5c 100644 --- a/meson.build +++ b/meson.build @@ -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) -- cgit v1.2.1